App-Phoebe

 view release on metacpan or  search on metacpan

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

# -*- mode: perl -*-
# Copyright (C) 2017–2021  Alex Schroeder <alex@gnu.org>

# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.

=encoding utf8

=head1 NAME

App::Phoebe::Gopher - serving a Phoebe wiki via the Gopher protocol

=head1 DESCRIPTION

This extension serves your Gemini pages via Gopher and generates a few automatic
pages for you, such as the main page.

To configure, you need to specify the Gopher port(s) in your Phoebe F<config> file.
The default port is 70. This is a priviledge port. Thus, you either need to
grant Perl the permission to listen on a priviledged port, or you need to run
Phoebe as a super user. Both are potential security risk, but the first option
is much less of a problem, I think.

If you want to try this, run the following as root:

    setcap 'cap_net_bind_service=+ep' $(which perl)

Verify it:

    getcap $(which perl)

If you want to undo this:

    setcap -r $(which perl)

The alternative is to use a port number above 1024.

If you don't do any of the above, you'll get a permission error on startup:
"Mojo::Reactor::Poll: Timer failed: Can't create listen socket: Permission
denied…"

If you are virtual hosting note that the Gopher protocol is incapable of doing
that: the server does not know what hostname the client used to look up the IP
number it eventually contacted. This works for HTTP and Gemini because HTTP/1.0
and later added a Host header to pass this information along, and because Gemini
uses a URL including a hostname in its request. It does not work for Gopher.
This is why you need to specify the hostname via C<$gopher_host>.

You can set the normal Gopher via C<$gopher_port> and the encrypted Gopher ports
via C<$gophers_port> (note the extra s). The values either be a single port, or
an array of ports. See the example below.

In this example we first switch to the package namespace, set some variables,
and then we I<use> the package. At this point the ports are specified and the
server processes it starts go up, one for ever IP number serving the hostname.

    package App::Phoebe::Gopher;
    our $gopher_host = "alexschroeder.ch";
    our $gopher_port = [70,79]; # listen on the finger port as well
    our $gophers_port = 7443; # listen on port 7443 using TLS
    our $gopher_main_page = "Gopher_Welcome";
    use App::Phoebe::Gopher;

Note the C<finger> port in the example. This works, but it's awkward since you
have to finger C<page/alex> instead of C<alex>. In order to make that work, we
need some more code.

    package App::Phoebe::Gopher;
    use App::Phoebe qw(@extensions port $log);
    use Modern::Perl;
    our $gopher_host = "alexschroeder.ch";
    our $gopher_port = [70,79]; # listen on the finger port as well
    our $gophers_port = 7443; # listen on port 7443 using TLS
    our $gopher_main_page = "Gopher_Welcome";
    our @extensions;
    push(@extensions, \&finger);
    sub finger {
      my $stream = shift;
      my $selector = shift;
      my $port = port($stream);
      if ($port == 79 and $selector =~ m!^[^/]+$!) {
	$log->debug("Serving $selector via finger");
	gopher_serve_page($stream, $gopher_host, undef, decode_utf8(uri_unescape($selector)));
	return 1;
      }
      return 0;



( run in 1.691 second using v1.01-cache-2.11-cpan-2398b32b56e )