135 lines
5.3 KiB
Markdown
135 lines
5.3 KiB
Markdown
# Jetforce
|
|
|
|
An experimental TCP server for the new, under development Gemini Protocol.
|
|
Learn more about Project Gemini
|
|
[here](https://gopher.commons.host/gopher://zaibatsu.circumlunar.space/1/~solderpunk/gemini).
|
|
|
|
![Rocket Launch](resources/rocket.jpg)
|
|
|
|
## Features
|
|
|
|
- A built-in static file server with support for gemini directories and
|
|
CGI scripts.
|
|
- Lightweight, single-file framework with zero external dependencies.
|
|
- Modern python codebase with type hinting and black style formatting.
|
|
- Supports concurrent connections using an asynchronous event loop.
|
|
- Extendable components that loosely implement the [WSGI](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface)
|
|
server/application pattern.
|
|
|
|
## Installation
|
|
|
|
Requires Python 3.7+
|
|
|
|
The latest release can be installed from [PyPI](https://pypi.org/project/Jetforce/):
|
|
|
|
```bash
|
|
$ pip install jetforce
|
|
```
|
|
|
|
Or, clone the repository and run the script directly:
|
|
|
|
```bash
|
|
$ git clone https://github.com/michael-lazar/jetforce
|
|
$ cd jetforce
|
|
$ python3 jetforce.py
|
|
```
|
|
|
|
## Usage
|
|
|
|
Use the ``--help`` flag to view command-line options:
|
|
|
|
```bash
|
|
$ jetforce --help
|
|
usage: jetforce [-h] [--host HOST] [--port PORT] [--tls-certfile FILE]
|
|
[--tls-keyfile FILE] [--hostname HOSTNAME] [--dir DIR]
|
|
[--cgi-dir DIR] [--index-file FILE]
|
|
|
|
An Experimental Gemini Protocol Server
|
|
|
|
optional arguments:
|
|
-h, --help show this help message and exit
|
|
--host HOST Server address to bind to (default: 127.0.0.1)
|
|
--port PORT Server port to bind to (default: 1965)
|
|
--tls-certfile FILE Server TLS certificate file (default: None)
|
|
--tls-keyfile FILE Server TLS private key file (default: None)
|
|
--hostname HOSTNAME Server hostname (default: localhost)
|
|
--dir DIR Local directory to serve (default: /var/gemini)
|
|
--cgi-dir DIR CGI script directory, relative to the server's root
|
|
directory (default: cgi-bin)
|
|
--index-file FILE If a directory contains a file with this name, that
|
|
file will be served instead of auto-generating an index
|
|
page (default: index.gmi)
|
|
|
|
If the TLS cert/keyfile is not provided, a self-signed certificate will
|
|
automatically be generated and saved to your temporary directory.
|
|
```
|
|
|
|
### TLS Certificates
|
|
|
|
The gemini specification *requires* that all connections be sent over TLS.
|
|
Before you deploy jetforce, you should either generate your own self-signed
|
|
certificate, or obtain one from a Certificate Authority like
|
|
[Let's Encrypt](https://letsencrypt.org).
|
|
|
|
In order to make local development easier, if you do not specify the certificate
|
|
arguments, jetforce will automatically generate a temporary ad-hoc TLS certificate
|
|
to use. Here's the OpenSSL command that jetforce uses internally:
|
|
|
|
|
|
```
|
|
$ openssl req -newkey rsa:2048 -nodes -keyout {hostname}.key \
|
|
-nodes -x509 -out {hostname}.crt -subj "/CN={hostname}"
|
|
```
|
|
|
|
There are currently no plans to support transient self-signed client certificates.
|
|
This is due to a techinical limitation of the python standard library's ``ssl``
|
|
module, which is described in detail
|
|
[here](https://portal.mozz.us/?url=gemini%3A%2F%2Fmozz.us%2Fjournal%2F2019-08-21.txt).
|
|
|
|
Support for verified client certificates will be added in a future version.
|
|
|
|
### Hostname
|
|
|
|
Because the gemini protocol sends the *whole* URL in the request, it's required
|
|
that you declare the hostname that your server is expecting to receive traffic
|
|
under. Jetforce will reject any request that doesn't match your hostname with a
|
|
status of ``Proxy Request Refused``.
|
|
|
|
Using python, you can modify this behavior to do fancy things like building a
|
|
proxy server for HTTP requests. See [http_proxy.py](examples/http_proxy.py) for
|
|
an example of how this is done.
|
|
|
|
### Serving Files
|
|
|
|
Jetforce serves files from the ``/var/gemini/`` directory by default:
|
|
|
|
- Files with the **.gmi** extension will be interpreted as *text/gemini*.
|
|
- Other files will have their *mimetype* guessed based on their file extension.
|
|
- Directories will look for a file with the name **index.gmi**.
|
|
- If an index file does not exist, a directory listing will be generated.
|
|
|
|
### CGI Scripts
|
|
|
|
Jetforce implements a slightly modified version of the official CGI
|
|
specification. Because Gemini is a less complex than HTTP, the CGI interface is
|
|
also inherently easier and more straightforward to use.
|
|
|
|
The main difference in this implementation is that the CGI script is expected
|
|
to write the entire gemini response *verbetim* to stdout:
|
|
|
|
1. The status code and meta on the first line
|
|
2. Any additional response body on subsequent lines
|
|
|
|
Unlike HTTP's CGI, there are no request/response headers or other special
|
|
fields to perform actions like redirects.
|
|
|
|
## License
|
|
|
|
This project is licensed under the [Floodgap Free Software License](https://www.floodgap.com/software/ffsl/license.html).
|
|
|
|
> The Floodgap Free Software License (FFSL) has one overriding mandate: that software
|
|
> using it, or derivative works based on software that uses it, must be free. By free
|
|
> we mean simply "free as in beer" -- you may put your work into open or closed source
|
|
> packages as you see fit, whether or not you choose to release your changes or updates
|
|
> publicly, but you must not ask any fee for it.
|