App-phoebe
view release on metacpan or search on metacpan
Manual install:
perl Makefile.PL
make
make install
## Dependencies
If you are not using `cpan` or `cpanm` to install Phoebe, you'll need to
install the following dependencies:
- [Algorithm::Diff](https://metacpan.org/pod/Algorithm%3A%3ADiff), or `libalgorithm-diff-xs-perl`
- [File::ReadBackwards](https://metacpan.org/pod/File%3A%3AReadBackwards), or `libfile-readbackwards-perl`
- [File::Slurper](https://metacpan.org/pod/File%3A%3ASlurper), or `libfile-slurper-perl`
- [Mojolicious](https://metacpan.org/pod/Mojolicious), or `libmojolicious-perl`
- [IO::Socket::SSL](https://metacpan.org/pod/IO%3A%3ASocket%3A%3ASSL), or `libio-socket-ssl-perl`
- [Modern::Perl](https://metacpan.org/pod/Modern%3A%3APerl), or `libmodern-perl-perl`
- [URI::Escape](https://metacpan.org/pod/URI%3A%3AEscape), or `liburi-escape-xs-perl`
- [Net::IDN::Encode](https://metacpan.org/pod/Net%3A%3AIDN%3A%3AEncode), or `libnet-idn-encode-perl`
- [Encode::Locale](https://metacpan.org/pod/Encode%3A%3ALocale), or `libencode-locale-perl`
I'm going to be using `curl` and `openssl` in the ["Quickstart"](#quickstart) instructions,
so you'll need those tools as well. And finally, when people download their
data, the code calls `tar` (available from packages with the same name on
Debian derived systems).
The `update-readme.pl` script I use to generate `README.md` also requires some
libraries:
- [Pod::Markdown](https://metacpan.org/pod/Pod%3A%3AMarkdown), or `libpod-markdown-perl`
- [Text::Slugify](https://metacpan.org/pod/Text%3A%3ASlugify), which has no Debian package, apparently ð
## Quickstart
I'm going to assume that you're going to create a new user just to be safe.
sudo adduser --disabled-login --disabled-password phoebe
sudo su phoebe --shell=/bin/bash
cd
Now you're in your home directory, `/home/phoebe`. We're going to install
things right here.
cpan App::phoebe
Start Phoebe. It's going to prompt you for a hostname and create certificates
for you. If in doubt, answer `localhost`. The certificate and a private key are
stored in the `cert.pem` and `key.pem` files, using elliptic curves, valid for
five years, without password protection.
perl5/bin/phoebe
This starts the server in the foreground. If it aborts, see the
["Troubleshooting"](#troubleshooting) section below. If it runs, open a second terminal and test
it:
perl5/bin/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
perl5/bin/titan --url=titan://localhost/raw/Welcome --token=hello test.txt
You should get a nice redirect message, with an appropriate date.
30 gemini://localhost:1965/page/Welcome
You can check the page, now (replacing the appropriate date):
perl5/bin/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
## Image uploads
OK, how do image uploads work? First, we need to specify which MIME types Phoebe
accepts. The files are going to be served back with that MIME type, so even if
somebody uploads an executable and claim it's an image, other people's clients
will treat it as an image instead of executing it (one hopes!) â so let's start
with a list of common MIME types.
- `image/jpeg` is for photos (usually with the `jpg` extension)
- `image/png` is for graphics (usually with the `png` extension)
- `audio/mpeg` is for sound (usually with the `mp3` extension)
Let's continue using the setup we used for the ["Quickstart"](#quickstart) section. Restart
the server and allow photos:
perl5/bin/phoebe --wiki_mime_type=image/jpeg
Upload the image using the `titan` script:
perl5/bin/titan --url=titan://localhost:1965/jupiter.jpg \
--token=hello Pictures/Planets/Juno.jpg
You should get back a redirect to the uploaded image:
30 gemini://localhost:1965/file/jupiter.jpg
How did the `titan` script know the MIME-type to use for the upload? If you
don't specify a MIME-type using `--mime`, the `file` utility is called to
guess the MIME type of the file.
Test it:
file --mime-type --brief Pictures/Planets/Juno.jpg
The result is the MIME-type we enabled for our wiki:
image/jpeg
Here's what happens when you're trying to upload an unsupported MIME-type:
titan --url=titan://localhost:1965/earth.png \
--token=hello Pictures/Planets/Earth.png
What you get back explains the problem:
59 This wiki does not allow image/png
In order to allow such graphics as well, you need to restart Phoebe:
phoebe --wiki_mime_type=image/jpeg --wiki_mime_type=image/png
`@main_menu` adds more lines to the main menu, possibly links that aren't
simply links to existing pages.
`@footer` is a list of code references allowing you to add things like licenses
or contact information to every page; each code reference gets called with
$stream ([Mojo::IOLoop::Stream](https://metacpan.org/pod/Mojo%3A%3AIOLoop%3A%3AStream)), $host, $space, $id, $revision, and $format
('gemini' or 'html') used to serve the page; return a gemtext string to append
at the end; the alternative is to overwrite the `footer` or `html_footer` subs
â the default implementation for Gemini adds History, Raw text and HTML link,
and `@footer` to the bottom of every page; the default implementation for HTTP
just adds `@footer` to the bottom of every page.
If you do hook into Phoebe's code, you probably want to make use of the
following variables:
`$server` stores the command line options provided by the user.
`$log` is how you log things.
A very simple example to add a contact mail at the bottom of every page; this
works for both Gemini and the web:
# tested by t/example-footer.t
use App::Phoebe::Web;
use App::Phoebe qw(@footer);
push(@footer, sub { '=> mailto:alex@alexschroeder.ch Mail' });
This prints a very simply footer instead of the usual footer for Gemini, as the
`footer` function is redefined. At the same time, the `@footer` array is still
used for the web:
# tested by t/example-footer2.t
package App::Phoebe;
use App::Phoebe::Web;
use Modern::Perl;
our (@footer); # HTML only
push(@footer, sub { '=> https://alexschroeder.ch/wiki/Contact Contact' });
# footer sub is Gemini only
no warnings qw(redefine);
sub footer {
return "\n" . 'â' x 10 . "\n" . '=> mailto:alex@alexschroeder.ch Mail';
}
This example shows you how to add a new route (a new path served by the wiki).
Instead of just writing "Test" to the page, you could of course run arbitrary
Perl code.
# tested by t/example-route.t
our @config = (<<'EOT');
use App::Phoebe qw(@extensions @main_menu port host_regex success);
use Modern::Perl;
push(@main_menu, "=> /do/test Test");
push(@extensions, \&serve_test);
sub serve_test {
my $stream = shift;
my $url = shift;
my $hosts = host_regex();
my $port = port($stream);
if ($url =~ m!^gemini://($hosts):$port/do/test$!) {
success($stream, 'text/plain; charset=UTF-8');
$stream->write("Test\n");
return 1;
}
return;
}
EOT
This example also shows how to redefine existing code in your config file
without the warning "Subroutine ⦠redefined".
Here's a more elaborate example to add a new action the main menu and a handler
for it, for Gemini only:
# tested by t/example-new-action.t
package App::Phoebe;
use Modern::Perl;
our (@extensions, @main_menu);
push(@main_menu, "=> gemini://localhost/do/test Test");
push(@extensions, \&serve_test);
sub serve_test {
my $stream = shift;
my $url = shift;
my $headers = shift;
my $host = host_regex();
my $port = port($stream);
if ($url =~ m!^gemini://($host)(?::$port)?/do/test$!) {
result($stream, "20", "text/plain");
$stream->write("Test\n");
return 1;
}
return;
}
1;
# App::Phoebe::BlockFediverse
This extension blocks the Fediverse user agent from your website (Mastodon,
Friendica, Pleroma). The reason is this: when these sites federate a status
linking to your site, each instance will fetch a preview, so your site will get
hit by hundreds of requests from all over the Internet. Blocking them helps us
weather the storm.
There is no configuration. Simply add it to your `config` file:
use App::Phoebe::BlockFediverse;
Sure, we could also think of better caching and all that. I hate the fact that
other developers are forcing us to build âsoftware that scalesâ â I hate how
they think that I have nothing better to do than think about blocking and
caching. Phoebe is software for the Smolnet, not for people that keep thinking
about scaling.
The solution implemented is this: if the user agent of a HTTP request matches
the regular expression, quit immediatly. The result:
$ curl --header "User-Agent: Pleroma" https://transjovian.org:1965/
Blocking Fediverse previews
Yeah, we could respond with a error, but fediverse developers arenât interested
in a new architecture for this problem. They think the issue has been solved.
( run in 2.169 seconds using v1.01-cache-2.11-cpan-75ffa21a3d4 )