App-Phoebe

 view release on metacpan or  search on metacpan

lib/App/Phoebe/RegisteredEditorsOnly.pm  view on Meta::CPAN

above. Add it, and restart Phoebe.

If a visitor uses a fingerprint that Phoebe doesn’t know, the fingerprint is
printed in the log (if your log level is set to “info” or more), so you can get
it from there in case the user can’t send you their client certificate, or tell
you what the fingerprint is.

You should also have a login link somewhere such that people can login
immediately. If they don’t, and they try to save, their client is going to ask
them for a certificate and their edits may or may not be lost. It depends. 😅

    => /login Login

This code works by intercepting all C<titan:> links, and all web edit requests.
If you allow editing via the web using L<App::Phoebe::WebEdit>, then those also
require a valid client certificate – and setting these up in a web browser are
not easy. Be prepared to explain how to do this to your users!

This code does I<not> prevent simple comments using L<App::Phoebe::Comments> or
L<App::Phoebe::WebComments>. People can still leave comments, if you use these
modules. This can be a problem: if only registered users can edit the site, you
probably don’t want a token; if anonymous users can comment, you probably want a
token. There is currently no solution for this. Choose one or the other. If you
choose both, registered users might have to provide a token, which might annoy
them.

Here’s an example config that allows reading and editing via the web, but only
for users with known fingerprints, with no comments and no tokens:

    # tested by t/example-registered-editors-only.t
    package App::Phoebe;
    use App::Phoebe::Web;
    use App::Phoebe::WebEdit;
    use App::Phoebe::RegisteredEditorsOnly;
    our @known_fingerprints = qw(
      sha256$0ba6ba61da1385890f611439590f2f0758760708d1375859b2184dcd8f855a00);
    our $server->{wiki_token} = []; # no tokens
    1;

At the time of this writing, here’s a way to do provide a client certificate for
Firefox users. First, we need a file in the C<PKCS12> format. On the command
line, create this file from the F<cert.pem> and F<key.pem> files you have.
Provide no password when you run the command.

    openssl pkcs12 -export -inkey key.pem -in cert.pem -out cert.p12

In Firefox, go to “Preferences” → “Privacy & Security” → “Certificates”; under
“When a server requests your personal certificate” check the option “Select one
automatically”; click on the “View Certificates” button, switch to the “Your
Certificates” tab, click on “Import…” and pick the F<cert.p12> file you just
created.

Once you have done this and you visit the Phoebe site, it’ll use the client
certificate you provided or it’ll ask you what client certificate to use.

=cut

package App::Phoebe::RegisteredEditorsOnly;
use App::Phoebe qw(@request_handlers @extensions @known_fingerprints $log
		   port host_regex space_regex handle_titan result);
use Modern::Perl;

unshift(@request_handlers, '^titan://' => \&protected_titan);

sub protected_titan {
  my $stream = shift;
  my $data = shift;
  my $hosts = host_regex();
  my $spaces = space_regex();
  my $port = port($stream);
  my $fingerprint = $stream->handle->get_fingerprint();
  if ($fingerprint and grep { $_ eq $fingerprint} @known_fingerprints) {
    $log->info("Successfully identified client certificate");
    return handle_titan($stream, $data);
  } elsif ($fingerprint) {
    $log->info("Unknown client certificate $fingerprint");
    result($stream, "61", "Your client certificate is not authorized for editing");
  } else {
    $log->info("Requested client certificate");
    result($stream, "60", "You need a client certificate to edit this wiki");
  }
  $stream->close_gracefully();
}

# for App::Phoebe::WebEdit
unshift(@extensions, \&protect_edit_requests);

sub protect_edit_requests {
  my ($stream, $request, $headers, $buffer) = @_;
  my $host_regex = host_regex();
  my $spaces = space_regex();
  my $port = port($stream);
  if ($request =~ m!^GET (?:/($spaces))?/do/edit/([^/#?]+) HTTP/1\.[01]$!
      or $request =~ m!^POST (?:/($spaces))?/do/edit/([^/#?]+) HTTP/1\.[01]$!) {
    # we don’t check $space and $host like we do in App::Phoebe::WebEdit!
    my $fingerprint = $stream->handle->get_fingerprint();
    if ($fingerprint and grep { $_ eq $fingerprint} @known_fingerprints) {
      $log->info("Successfully identified client certificate via the web");
      return 0; # let it be handled by process_edit_request in App::Phoebe::WebEdit!
    } elsif ($fingerprint) {
      $log->info("Unknown client certificate $fingerprint via the web");
      $stream->write("HTTP/1.1 403 Not authorized\r\n");
      $stream->write("Content-Type: text/plain\r\n");
      $stream->write("\r\n");
      $stream->write("Your client certificate is not authorized for editing\n");
      return 1; # we handled it, no further action required
    } else {
      $log->info("Requested client certificate via the web");
      $stream->write("HTTP/1.1 403 Not authorized\r\n");
      $stream->write("Content-Type: text/plain\r\n");
      $stream->write("\r\n");
      $stream->write("You need a client certificate to edit this wiki");
      return 1; # we handled it, no further action required
    }
  }
  return 0;
}

push(@extensions, \&registered_editor_login);

sub registered_editor_login {



( run in 0.637 second using v1.01-cache-2.11-cpan-a1f116cd669 )