App-Phoebe

 view release on metacpan or  search on metacpan

script/phoebe  view on Meta::CPAN

favourite text editor to write them.

A text line is a paragraph of text.

    This is a paragraph.
    This is another paragraph.

A link line starts with "=>", a space, a URL, optionally followed by whitespace
and some text; the URL can be absolute or relative.

    => http://transjovian.org/ The Transjovian Council on the web
    => Welcome                 Welcome to The Transjovian Council

A line starting with "```" toggles preformatting on and off.

    Here is an example:
    ```
    The tapping calms me:
    Constant mindless murmuring
    Rain drops against glass
    ```

A line starting with "#", "##", or "###", followed by a space and some text is a
heading.

    ## License
    The GNU Affero General Public License.

A line starting with "*", followed by a space and some text is a list item.

    * one item
    * another item

A line starting with ">", followed by a space and some text is a quote.

    The monologue at the end is fantastic, with the city lights and the rain.
    > I have seen things you people would not believe.

=head1 SECURITY

It might be best if you had a separate user for Phoebe:

    sudo adduser --disabled-login --disabled-password phoebe
    sudo su phoebe --shell=/bin/bash
    cd

Now you're in the new home directory, F</home/phoebe>. If you start C<phoebe>
here, your wiki directory will be F</home/phoebe/wiki>. If you haven't installed
L<App::Phoebe> for all your users, you will have to install it again.

    cpan App::Phoebe

The Perl files are stored in F</home/phoebe/perl5>.

=head1 QUICKSTART

Start Phoebe.

    phoebe

When you run it for the first time, Phoebe is going to prompt you for a hostname
and create certificates for you. If in doubt, answer C<localhost>. The
certificate and a private key are stored in the F<cert.pem> and F<key.pem>
files, using elliptic curves, valid for five years, without password protection.

    Do you want to create them right now?
    The certificate uses eliptic curves and is valid for five years.
    If so, please provide your hostname (e.g. localhost).
    If not, just press Enter.
    localhost
    openssl req -new -x509 -newkey ec -subj "/CN=localhost" -pkeyopt ec_paramgen_curve:prime256v1 -days 1825 -nodes -out cert.pem -keyout key.pem
    Generating an EC private key
    writing new private key to 'key.pem'
    -----

If it aborts, see the L</Troubleshooting> section below. If it runs, open a
second terminal and test it:

    gemini gemini://localhost/

You should see a Gemini page starting with the following:

    20 text/gemini; charset=UTF-8
    Welcome to Phoebe!

Success!! 😀 🚀🚀

Let's create a new page using the Titan protocol, from the command line:

    echo "Welcome to the wiki!" > test.txt
    echo "Please be kind." >> test.txt
    titan --url=titan://localhost/raw/Welcome --token=hello test.txt

You should get a nice redirect message.

    30 gemini://localhost:1965/page/Welcome

You can check the page:

    gemini gemini://localhost:1965/page/Welcome

You should get back a page that starts as follows:

    20 text/gemini; charset=UTF-8
    Welcome to the wiki!
    Please be kind.

Yay! 😁🎉 🚀🚀

If you have a bunch of Gemtext files in a directory, you can upload them all in
one go:

    titan --url=titan://localhost/ --token=hello *.gmi

=head1 CERTIFICATES

If you want to generate your own certificates, here's how you would generate a
certificate for two domains (you can add as many as you need), and a common name
of "Phoebe" (use whatever you want).

    openssl req -new -x509 -newkey ec \

script/phoebe  view on Meta::CPAN

	  $server->{key_file}->{"$host:$port"} = $key_file;
	}
      }
      $cert_file = $key_file = undef;
      @host = @port = ();
    }
  }

  # if, at the end, there is a left-over
  if ($cert_file or $key_file) {
    die "I must have both --key_file and --cert_file\n";
  }

  push @port, 1965 unless @port;

  # let's see if we need to generate certificates
  my $default_certs = 0;

  # if, at the end, we have some hosts but no certs and keys
  for my $host (@host) {
    $default_certs = 1;
    $server->{host}->{$host} = 1;
    push(@{$server->{port}->{$host}}, @port);
    for my $port (@port) {
      $server->{cert_file}->{"$host:$port"} = 'cert.pem';
      $server->{key_file}->{"$host:$port"} = 'key.pem';
    }
  }

  # if, at the end, we had no hosts at all, the default still needs cert and key
  if (not keys %{$server->{host}}) {
    $default_certs = 1;
    $server->{host}->{localhost} = 1;
    push(@{$server->{port}->{localhost}}, @port);
    for my $port (@port) {
      $server->{cert_file}->{"localhost:$port"} = 'cert.pem';
      $server->{key_file}->{"localhost:$port"} = 'key.pem';
    }
  }

  # use Data::Dumper;
  # warn Dumper($server);

  # if the certs don't exist, generate them
  if ($default_certs
      and (not -f 'cert.pem'
	   or not -f 'key.pem')) {
    generate_certificates();
  }
}

sub generate_certificates {
  say "The default certificate (and key) files are missing.";
  say "Do you want to create them right now?";
  say "The certificate uses eliptic curves and is valid for five years.";
  say "If so, please provide your hostname (e.g. localhost).";
  say "If not, just press Enter.";
  local $SIG{'ALRM'} = sub {
    die "Timed out!\n";
  };
  alarm(30); # timeout for the following prompt
  my $hostname = <STDIN>;
  alarm(0);  # done, no more alarm
  chomp $hostname;
  die "The hostname may not contain any whitespace\n" if $hostname =~ /\s/;
  my $cmd = qq(openssl req -new -x509 -newkey ec -subj "/CN=$hostname" )
      . qq(-pkeyopt ec_paramgen_curve:prime256v1 -days 1825 -nodes -out cert.pem -keyout key.pem);
  if ($hostname) {
    say $cmd;
    system($cmd) == 0
      or die "openssl failed: $?";
  }
}

sub help {
  my $parser = Pod::Text->new();
  $parser->parse_file($0);
  exit;
}

sub verify_fingerprint {
  my ($ok, $ctx_store, $certname, $error, $cert, $depth) = @_;
  return 1;
}

# defaults
$server->{wiki_token} ||= ['hello'];
$server->{wiki_space} ||= [];
$server->{wiki_mime_type} ||= [];
$server->{wiki_dir} ||= $ENV{PHOEBE_DATA_DIR} || './wiki';
$server->{wiki_page} ||= [];
$server->{wiki_main_page} ||= '';
$server->{wiki_page_size_limit} ||= 100000;

configure();

# Reconfigure if we get SIGHUP (via kill -s SIGHUP $pid, for example)
$SIG{HUP} = sub { Mojo::IOLoop->next_tick(\&configure) };

start_servers();

sub configure {
  # config file with extra code; restart server if you change it
  my $dir = $server->{wiki_dir};
  my @config;
  push(@config, map { "$dir/conf.d/$_" } grep(/\.p[lm]$/, read_dir("$dir/conf.d"))) if -d "$dir/conf.d";
  # allow override of config files in conf.d
  push(@config, "$dir/config") if -f "$dir/config";
  for my $config (@config) {
    $log->info("Running $config");
    $log->error("$config cannot be read") unless -r $config;
    $log->warn("$config did not return a true value") unless do $config;
    $log->error("$@") if $@;
    $log->error("$!") if $!;
  }
  # summarize config results
  $log->info("PID: $$");
  $log->info("Space: @{$server->{wiki_space}}");
  if (keys %{$server->{host}} > 1) {
    my $hosts = host_regex();
    for (grep(!/^$hosts\//, @{$server->{wiki_space}})) {



( run in 0.803 second using v1.01-cache-2.11-cpan-6aa56a78535 )