{ "info": { "author": "Michael Lazar", "author_email": "lazar.michael22@gmail.com", "bugtrack_url": null, "classifiers": [ "Environment :: Web Environment", "Intended Audience :: Developers", "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# Jetforce\n\nAn experimental TCP server for the new, under development Gemini Protocol.\nLearn more [here](https://gopher.commons.host/gopher://zaibatsu.circumlunar.space/1/~solderpunk/gemini).\n\n![Rocket Launch](resources/rocket.jpg)\n\n## Features\n\n- A built-in static file server with support for gemini directories and\n CGI scripts.\n- Lightweight, single-file framework with zero external dependencies. \n- Modern python codebase with type hinting and black style formatting.\n- Supports concurrent connections using an asynchronous event loop.\n- Extendable components that loosely implement the [WSGI](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface)\n server/application pattern.\n\n## Installation\n\nRequires Python 3.7+\n\nThe latest release can be installed from [PyPI](https://pypi.org/project/Jetforce/):\n\n```bash\n$ pip install jetforce\n```\n\nOr, clone the repository and run the script directly:\n\n```bash\n$ git clone https://github.com/michael-lazar/jetforce\n$ cd jetforce\n$ python3 jetforce.py\n```\n\n## Usage\n\nUse the ``--help`` flag to view command-line options:\n\n```bash\n$ jetforce --help\nusage: jetforce [-h] [--host HOST] [--port PORT] [--hostname HOSTNAME]\n [--tls-certfile FILE] [--tls-keyfile FILE] [--tls-cafile FILE]\n [--tls-capath DIR] [--dir DIR] [--cgi-dir DIR]\n [--index-file FILE]\n\nAn Experimental Gemini Protocol Server\n\noptional arguments:\n -h, --help show this help message and exit\n --host HOST Server address to bind to (default: 127.0.0.1)\n --port PORT Server port to bind to (default: 1965)\n --hostname HOSTNAME Server hostname (default: localhost)\n --tls-certfile FILE Server TLS certificate file (default: None)\n --tls-keyfile FILE Server TLS private key file (default: None)\n --tls-cafile FILE A CA file to use for validating clients (default: None)\n --tls-capath DIR A directory containing CA files for validating clients\n (default: None)\n --dir DIR Root directory on the filesystem to serve (default:\n /var/gemini)\n --cgi-dir DIR CGI script directory, relative to the server's root\n directory (default: cgi-bin)\n --index-file FILE If a directory contains a file with this name, that\n file will be served instead of auto-generating an index\n page (default: index.gmi)\n```\n\n### Hostname\n\nBecause the gemini protocol sends the whole URL in the request, it's necessary\nto declare the hostname that your server is expecting to receive traffic under.\nJetforce will reject any request that doesn't match your hostname with a status\nof ``Proxy Request Refused``.\n\n### TLS Certificates\n\nThe gemini specification *requires* that all connections be sent over TLS.\n\nIf you do not provide a TLS certificate file using the ``--tls-certfile`` flag,\njetforce will automatically generate a temporary cert for you to use. This is\ngreat for making development easier, but before you expose your server to the\npublic internet you should configure something more permanent. You can generate\nyour own self-signed server certificate, or obtain one from a Certificate\nAuthority like [Let's Encrypt](https://letsencrypt.org).\n\nHere's the OpenSSL command that jetforce uses to generate a self-signed cert:\n\n```\n$ openssl req -newkey rsa:2048 -nodes -keyout {hostname}.key \\\n -nodes -x509 -out {hostname}.crt -subj \"/CN={hostname}\"\n```\n\nJetforce also supports verified client TLS certificates. You can specify your\nclient CA with the ``--tls-cafile`` or ``--tls-capath`` flags. Verified\nconnections will have the ``REMOTE_USER`` variable added to their environment,\nwhich contains the client certificate's CN attribute. Instructions on how to\ngenerate TLS client certificates are outside of the scope of this readme, but\nyou can find many helpful tutorials\n[online](https://portal.mozz.us/?url=gemini%3A%2F%2Fmozz.us%2Fjournal%2F2019-08-21.txt).\n\nThere are currently no plans to support unverified (transient) client\ncertificates. This is due to a technical limitation of the python standard\nlibrary's ``ssl`` module, which is described in detail \n[here](https://portal.mozz.us/?url=gemini%3A%2F%2Fmozz.us%2Fjournal%2F2019-08-21.txt).\n\n### Static Files\n\nJetforce will serve static files in the ``/var/gemini/`` directory:\n\n- Files ending with **.gmi** will be interpreted as the *text/gemini* type\n- If a directory is requested, jetforce will look for a file in that directory\n with the name of **index.gmi**\n - If it exists, the index file will be returned\n - Otherwise, jetforce will generate a directory listing\n\n### CGI Scripts\n\nJetforce implements a slightly modified version of the official CGI\nspecification. Because Gemini is a less complex than HTTP, the CGI interface is\nalso inherently easier and more straightforward to use.\n\nThe main difference in jetforce's implementation is that the CGI script is\nexpected to write the entire gemini response *verbatim* to stdout:\n\n1. The status code and meta on the first line\n2. The optional response body on subsequent lines\n\nThe script is not allowed to respond with HTTP headers like ``Content-Type``,\nor any other special CGI headers like internal file redirects.\n\nSome of the HTTP specific environment variables like ``REQUEST_METHOD`` are not\nused, because they don't make sense in the context of a Gemini request.\n\n## License\n\nThis project is licensed under the [Floodgap Free Software License](https://www.floodgap.com/software/ffsl/license.html).\n\n> The Floodgap Free Software License (FFSL) has one overriding mandate: that software\n> using it, or derivative works based on software that uses it, must be free. By free\n> we mean simply \"free as in beer\" -- you may put your work into open or closed source\n> packages as you see fit, whether or not you choose to release your changes or updates\n> publicly, but you must not ask any fee for it.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/michael-lazar/jetforce", "keywords": "gemini server tcp gopher asyncio", "license": "Other/Proprietary License", "maintainer": "", "maintainer_email": "", "name": "Jetforce", "package_url": "https://pypi.org/project/Jetforce/", "platform": "", "project_url": "https://pypi.org/project/Jetforce/", "project_urls": { "Homepage": "https://github.com/michael-lazar/jetforce" }, "release_url": "https://pypi.org/project/Jetforce/0.1.0/", "requires_dist": null, "requires_python": ">=3.7", "summary": "An Experimental Gemini Server", "version": "0.1.0" }, "last_serial": 5871130, "releases": { "0.0.1": [ { "comment_text": "", "digests": { "md5": "a8b54a80f030953f5a8f86494370537c", "sha256": "bdf98279cc50a648c9a1b6ace5e0d41883e5f98c32ae0e5e09fe6ebadd5c4e16" }, "downloads": -1, "filename": "Jetforce-0.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "a8b54a80f030953f5a8f86494370537c", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 17572, "upload_time": "2019-08-05T02:04:31", "url": "https://files.pythonhosted.org/packages/41/c9/ded8139f5fda997fbe4453c9b06a8780d2e8de47f81245e38e252a35d940/Jetforce-0.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "407ecef40e3faa12f5944b4070c328aa", "sha256": "e529bd6ba916afba740ac2efb6ba7dd27c91718350a338d5c6ea7c70ea0d7c9d" }, "downloads": -1, "filename": "Jetforce-0.0.1.tar.gz", "has_sig": false, "md5_digest": "407ecef40e3faa12f5944b4070c328aa", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 4712, "upload_time": "2019-08-05T02:04:34", "url": "https://files.pythonhosted.org/packages/12/9c/82c9de56eb07adc500c1eac5c6a2a8b2a943d344bf70e3cb1da1f3c27e43/Jetforce-0.0.1.tar.gz" } ], "0.0.2": [ { "comment_text": "", "digests": { "md5": "04ea432fdc363dfdf1b08c7a451c698b", "sha256": "35afb0ba3ee2daf801228525cba3b17ad30133523fe442cf21856e572728be24" }, "downloads": -1, "filename": "Jetforce-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "04ea432fdc363dfdf1b08c7a451c698b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 18316, "upload_time": "2019-08-06T02:23:38", "url": "https://files.pythonhosted.org/packages/c8/75/8ace0e9341860f8712b70190b75f0e3a9b2da5467dbe8ddb1c135dd6ffdc/Jetforce-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "685f0e5139a1752ee046154e9173fc53", "sha256": "4a6cc310d8c75fa6cdf82d4d29353e780764c2d5a53aa259f952384d3c5b6d90" }, "downloads": -1, "filename": "Jetforce-0.0.2.tar.gz", "has_sig": false, "md5_digest": "685f0e5139a1752ee046154e9173fc53", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 5521, "upload_time": "2019-08-06T02:23:40", "url": "https://files.pythonhosted.org/packages/4f/99/a1f172f89121df1d306a4de40604f16a863b5bbbad7631b1a51bd2e9c17b/Jetforce-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "0a6d619ccdd25a99b12c645e17a14563", "sha256": "4039f71163cf7fd6f642f5be4d15604377293b245735dcc92bd708693229da01" }, "downloads": -1, "filename": "Jetforce-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "0a6d619ccdd25a99b12c645e17a14563", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 18745, "upload_time": "2019-08-06T03:16:09", "url": "https://files.pythonhosted.org/packages/6e/e3/0174217748a9fdc9a8570b465afd708c1fef4992d340139b2d34f98156d7/Jetforce-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9d2a038d660a27d98a57716df68ca20d", "sha256": "2d28a9ea6f3e740defb857d18c4147da568b8b69d5aa861dd87af75707949dcf" }, "downloads": -1, "filename": "Jetforce-0.0.3.tar.gz", "has_sig": false, "md5_digest": "9d2a038d660a27d98a57716df68ca20d", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 5999, "upload_time": "2019-08-06T03:16:11", "url": "https://files.pythonhosted.org/packages/5d/ad/da25a9cb4ba8b0eea09011c209bf76227acd32a09fc1508728d993a4ebf9/Jetforce-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "b2be39b3c0be25b735aac2f772701c40", "sha256": "52152fec3e2498d65d8c296f819737c6a69c4dd2b049cd7600480b1b956dc02d" }, "downloads": -1, "filename": "Jetforce-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "b2be39b3c0be25b735aac2f772701c40", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 18801, "upload_time": "2019-08-09T01:35:13", "url": "https://files.pythonhosted.org/packages/b3/ea/b1f3ceb82fbf2c94355dd35ec2b2bc9e1d9beff108431c827711d5f6059c/Jetforce-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "08c6f778bff46a0e156af1136c1fd28e", "sha256": "c9da17663b1291278e3dc44771a3cb56bb2ec1e65f8aae8d3cfc2c41b0db8a9f" }, "downloads": -1, "filename": "Jetforce-0.0.4.tar.gz", "has_sig": false, "md5_digest": "08c6f778bff46a0e156af1136c1fd28e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 6054, "upload_time": "2019-08-09T01:35:14", "url": "https://files.pythonhosted.org/packages/43/16/976634c58b949665a9542f428f8ce35c60f88bf650e8aedce8200209971b/Jetforce-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "bab8ae58974df27ec480eb6d58ba4dfb", "sha256": "c7f230b15bbaa0e7f4ee39984c3bc4f22d5d71e7461aebf5449aa7ef622a7e65" }, "downloads": -1, "filename": "Jetforce-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "bab8ae58974df27ec480eb6d58ba4dfb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 20519, "upload_time": "2019-08-13T01:46:27", "url": "https://files.pythonhosted.org/packages/b8/ce/0066f0a8439dc43f235c38701a95dfff05da52bfee3823739ed68152af8f/Jetforce-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "017c55f2401682ab7294fb11bb433000", "sha256": "50a561069dc1d8c1b52147f3fa6b639a9bf62fd90553870b3cb248a674ad53c0" }, "downloads": -1, "filename": "Jetforce-0.0.5.tar.gz", "has_sig": false, "md5_digest": "017c55f2401682ab7294fb11bb433000", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 7493, "upload_time": "2019-08-13T01:46:29", "url": "https://files.pythonhosted.org/packages/79/84/2f9efc179fbb988ef4a6ed12d17397359c73441fb07cdb0c3b7a5df2f5a4/Jetforce-0.0.5.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "402924062749abe4b8bb2fd68e78149d", "sha256": "c23230f8d3098e384a793071245e622c31988a232b6f1d8e05e917012d1a66f7" }, "downloads": -1, "filename": "Jetforce-0.0.6-py2-none-any.whl", "has_sig": false, "md5_digest": "402924062749abe4b8bb2fd68e78149d", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": ">=3.7", "size": 13825, "upload_time": "2019-08-22T23:52:51", "url": "https://files.pythonhosted.org/packages/e1/4c/180690ccdc56c468beac667a0c8797aa19902902c50a05297d612945c8b8/Jetforce-0.0.6-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6748c4fadf213e64933070d66546d895", "sha256": "562183b12420d17bf014fd64ac16faa9b760072f12748323b34f90aaaf11ed56" }, "downloads": -1, "filename": "Jetforce-0.0.6.tar.gz", "has_sig": false, "md5_digest": "6748c4fadf213e64933070d66546d895", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 8125, "upload_time": "2019-08-22T23:52:54", "url": "https://files.pythonhosted.org/packages/93/b5/6bae628d169a8d39e77998f075142c881fa4f05c24197d92a0f50acc0555/Jetforce-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "399819db84d3c41a7fc092eaebdd7e29", "sha256": "7513e6160dd3f8e26c3d8adef38a5853154096e11c75a56dfed21efd3db168d2" }, "downloads": -1, "filename": "Jetforce-0.0.7-py2-none-any.whl", "has_sig": false, "md5_digest": "399819db84d3c41a7fc092eaebdd7e29", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": ">=3.7", "size": 17027, "upload_time": "2019-08-30T03:51:56", "url": "https://files.pythonhosted.org/packages/64/25/0dbc81723d4f4aeeeaa599d869fc5c64ae817246365aed735ca893517e26/Jetforce-0.0.7-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3fa6d75be9935f23416822f7bb951be4", "sha256": "a96ab2799967a8f13b8735024db26bb73cd60c62044cb6f6a45db9f62f9d1b43" }, "downloads": -1, "filename": "Jetforce-0.0.7.tar.gz", "has_sig": false, "md5_digest": "3fa6d75be9935f23416822f7bb951be4", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 13464, "upload_time": "2019-08-30T03:51:57", "url": "https://files.pythonhosted.org/packages/fa/41/6720e2f0fbcfe0591c6715fb643bcd084f77f8c526d29e4920db8b92c90b/Jetforce-0.0.7.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "5febaeaff6a62b7e2c7b2896aaada35a", "sha256": "d8280b2699bd420525227e69863a81d0d0b375fbd774084ae462081243c395dd" }, "downloads": -1, "filename": "Jetforce-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "5febaeaff6a62b7e2c7b2896aaada35a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 17157, "upload_time": "2019-09-23T02:13:57", "url": "https://files.pythonhosted.org/packages/96/84/ea46c9c3e1a891249e72e78b2c12a444448276eced446f0057dca4d1bb7d/Jetforce-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "37cbe552d3c92745d3781e9dd12ed766", "sha256": "0b5a6a89a47b05892f59c1a2cb7155b67c5e9ca035cfa2d80cd586c98b87b736" }, "downloads": -1, "filename": "Jetforce-0.1.0.tar.gz", "has_sig": false, "md5_digest": "37cbe552d3c92745d3781e9dd12ed766", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 11646, "upload_time": "2019-09-23T02:13:59", "url": "https://files.pythonhosted.org/packages/dc/b6/75a9a2209f577dd35c168a3250478a22391f718d4f1ff69c20cecb37d4a7/Jetforce-0.1.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "5febaeaff6a62b7e2c7b2896aaada35a", "sha256": "d8280b2699bd420525227e69863a81d0d0b375fbd774084ae462081243c395dd" }, "downloads": -1, "filename": "Jetforce-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "5febaeaff6a62b7e2c7b2896aaada35a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7", "size": 17157, "upload_time": "2019-09-23T02:13:57", "url": "https://files.pythonhosted.org/packages/96/84/ea46c9c3e1a891249e72e78b2c12a444448276eced446f0057dca4d1bb7d/Jetforce-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "37cbe552d3c92745d3781e9dd12ed766", "sha256": "0b5a6a89a47b05892f59c1a2cb7155b67c5e9ca035cfa2d80cd586c98b87b736" }, "downloads": -1, "filename": "Jetforce-0.1.0.tar.gz", "has_sig": false, "md5_digest": "37cbe552d3c92745d3781e9dd12ed766", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7", "size": 11646, "upload_time": "2019-09-23T02:13:59", "url": "https://files.pythonhosted.org/packages/dc/b6/75a9a2209f577dd35c168a3250478a22391f718d4f1ff69c20cecb37d4a7/Jetforce-0.1.0.tar.gz" } ] }