From c5812663583131d438647fe8e57914e6f8eeb541 Mon Sep 17 00:00:00 2001 From: dsgnr Date: Tue, 5 Nov 2024 18:57:07 +0000 Subject: [PATCH] Improve documentation --- README.md | 125 ++++++++++++++++++++++++----------- backend/api/app/routes/v1.py | 33 +++++---- backend/api/app/routes/v2.py | 58 ++++++++++------ backend/api/main.py | 7 +- 4 files changed, 150 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index b20e7c3..d0fc71b 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,115 @@ -

Welcome to portchecker.io 👋

+

portchecker.io

-[![CodeQL](https://github.com/dsgnr/portchecker.io/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/dsgnr/portchecker.io/actions/workflows/codeql-analysis.yml) +[portchecker.io](https://portchecker.io) is an open-source API for checking port availability on specified hostnames or IP addresses. Ideal for developers and network admins, it helps troubleshoot network setups, validate firewall rules, and assess potential access points. -This project aims to be a simple, go-to place for querying the port status for a provided hostname or IP address. +## Table of contents: -### 🏠 [Homepage](https://portchecker.io) +- [Getting Started](#getting-started) +- [Documentation](#documentation) +- [Development](#development) + - [Standalone](#standalone) + - [Docker](#docker) +- [Production](#production) +- [Environment Variables](#environment-variables) +- [Contributing](#contributing) -### ✨ [Demo](https://portchecker.io) +## Getting Started +The project consists of two containers. The front-end is a static HTML file sat behind Nginx. The back-end is a simple API built using [Litestar](https://litestar.dev/). -### API Specs -The API documentation is automatically generated by FastAPI. -Routes and specification can be found at [https://portchecker.io/docs](https://portchecker.io/docs) +The project aims to be super simple, with low overhead and also the least amount of dependencies as possible. -## Author +The project contains both production and development stacks. The production stack utilises `gunicorn` as the API's process manager with `uvicorn` workers. Development utilises `uvicorn` with the `--reload` parameter. -👤 **Dan Hand** +## Documentation +API routes and specification can be found at [portchecker.io/docs](https://portchecker.io/docs) -* Website: https://danielhand.io -* Github: [@dsgnr](https://github.com/dsgnr) -### Getting Started -The project consists of two containers. The front-end is a static HTML file sat behind Nginx. The back-end is a simple API built using FastAPI. +## Development -The project aims to be super simple, with low overhead and also the least amount of dependencies as possible. +### Standalone -The project contains both production and development stacks. The production stack utilises Gunicorn as the API's gateway interface, whereas development utilises `uvicorn`. +#### Web +> [!NOTE] +> Uses [Node](https://nodejs.org/) version 23 and newer. Requires [Yarn](https://classic.yarnpkg.com/en/) -Bringing up the development stack: +Bringing up the UI outside of Docker; ~~~ -$ docker-compose -f docker-compose-dev.yml up --build +$ cd frontend/web +$ yarn install +$ yarn dev ~~~ -Bringing up the API outside of Docker; +portchecker.io front-end be running at [http://0.0.0.0:8080](http://0.0.0.0:8080). + +#### API +> [!NOTE] +> Uses Python 3.12. The Python environment uses [Poetry](https://pypi.org/project/poetry/) for package management. This must be installed. + ~~~ -$ cd backend/api; uvicorn main:app --host 0.0.0.0 --port 8000 --reload +$ cd backend/api +$ poetry install +$ uvicorn main:app --host 0.0.0.0 --port 8000 --reload ~~~ -Bringing up the UI outside of Docker; +portchecker.io API be running at [http://0.0.0.0:8000](http://0.0.0.0:8000). + + +### Docker ~~~ -$ cd frontend/web; yarn install; yarn dev +$ docker-compose -f docker-compose-dev.yml up --build ~~~ -The port checker API will be running at [http://0.0.0.0:8000](http://0.0.0.0:8000) and the front-end will be running at [http://0.0.0.0:8080](http://0.0.0.0:8080). +portchecker.io front-end will be running at [http://0.0.0.0:8080](http://0.0.0.0:8080) and the API will be running at [http://0.0.0.0:8000](http://0.0.0.0:8000). -## Configuration -The following configuration options are available. These would be set within the Docker compose files. +## Production +### Docker +> [!NOTE] +> Uses [ghcr.io/dsgnr/portcheckerio-web:latest](https://github.com/dsgnr/portchecker.io/pkgs/container/portcheckerio-web) and [ghcr.io/dsgnr/portcheckerio-api:latest](https://github.com/dsgnr/portchecker.io/pkgs/container/portcheckerio-api). -### API: -- ALLOW_PRIVATE (boolean, default false) +~~~ +$ docker-compose up +~~~ -### UI: -- DEFAULT_PORT (integer, default 443) +portchecker.io front-end will be running at [http://0.0.0.0:8080](http://0.0.0.0:8080) and the API will be running at [http://0.0.0.0:8000](http://0.0.0.0:8000). -## 🤝 Contributing +## Environment Variables +The following configuration options are available. These would be set within the Docker compose files, or in your environment if you're using portchecker standalone. -Contributions, issues and feature requests are welcome.
-Feel free to check [issues page](https://github.com/dsgnr/portchecker.io/issues) if you want to contribute.
+### Web +| Name | Required? | Default | Notes | +|------------------|-----------|---------|------------------------------------------------------------| +| DEFAULT_PORT | No | | Allows a default port number to be prefilled in the UI | +| GOOGLE_ANALYTICS | No | | Allows for a Google Analytics tracking code to be provided | +### API +| Name | Required? | Default | Notes | +|---------------|-----------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ALLOW_PRIVATE | No | 443 | Allows private IP addresses in [ IANA IPv4 Special Registry ]( https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml ) ranges to be checked | + +## Contributing + +I'm thrilled that you’re interested in contributing to this project! Here’s how you can get involved: + +### How to Contribute + +1. **Submit Issues**: + - If you encounter any bugs or have suggestions for improvements, please submit an issue on our [GitHub Issues](https://github.com/dsgnr/portchecker.io/issues) page. + - Provide as much detail as possible, including steps to reproduce and screenshots if applicable. + +2. **Propose Features**: + - Have a great idea for a new feature? Open a feature request issue in the same [GitHub Issues](https://github.com/dsgnr/portchecker.io/issues) page. + - Describe the feature in detail and explain how it will benefit the project. + +3. **Submit Pull Requests**: + - Fork the repository and create a new branch for your changes. + - Make your modifications and test thoroughly. + - Open a pull request against the `devel` branch of the original repository. Include a clear description of your changes and any relevant context. + +## Author + +* Website: https://danielhand.io +* Github: [@dsgnr](https://github.com/dsgnr) ## Show your support @@ -71,12 +123,9 @@ The site is located on Digital Ocean. You can use the following referral link to [![DigitalOcean Referral Badge](https://web-platforms.sfo2.digitaloceanspaces.com/WWW/Badge%203.svg)](https://www.digitalocean.com/?refcode=b54817e033c8&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge) -## 📝 License +## License + +See the [LICENSE](LICENSE) file for more details on terms and conditions. -Copyright [Dan Hand](https://github.com/dsgnr).
-This project is [GNU General Public License v3.0](https://github.com/dsgnr/portchecker.io/blob/devel/LICENSE) licensed. ---- -*** -_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_ diff --git a/backend/api/app/routes/v1.py b/backend/api/app/routes/v1.py index 4175b81..2831363 100644 --- a/backend/api/app/routes/v1.py +++ b/backend/api/app/routes/v1.py @@ -5,33 +5,42 @@ # Standard Library from typing import Annotated -from litestar import post -from litestar.params import Body -from litestar.status_codes import HTTP_200_OK - # Third Party from app.helpers.query import query_ipv4 from app.schemas.api import APIResponseSchema, APISchema +from litestar import MediaType, post +from litestar.params import Body +from litestar.status_codes import HTTP_200_OK -@post("/api/v1/query", status_code=HTTP_200_OK, sync_to_thread=False, deprecated=True) +@post( + "/api/v1/query", + media_type=MediaType.JSON, + status_code=HTTP_200_OK, + sync_to_thread=False, + deprecated=True, +) def v1_query_post( data: Annotated[ APISchema, - Body(title="Query a hostname or IP", description="Query a hostname or IP"), + Body( + title="Query a resolvable hostname or IPv4 address", + description="Query a resolvable hostname or IPv4 address", + ), ], ) -> APIResponseSchema: """ - A `POST` endpoint to query a range of ports for a hostname or IP address. - - This endpoint will accept an IPv4 IP address or resolveable hostname, - and iterate an array of port numbers provided. + A `POST` endpoint to query the status of multiple ports on a given hostname + or IP address. - The port check will timeout after 1 second. + This endpoint accepts a JSON payload containing either an IPv4 address + or a resolvable hostname, along with an array of port numbers to be checked. + For each port in the array, the endpoint performs a connectivity check with a + timeout of 1 second per port. **NOTE:** The request body for this endpoint is not logged. ~~~ - "POST / HTTP/1.1" 200 OK + "POST /api/query HTTP/1.1" 200 OK ~~~ """ return APIResponseSchema( diff --git a/backend/api/app/routes/v2.py b/backend/api/app/routes/v2.py index 77291bd..2ffab88 100644 --- a/backend/api/app/routes/v2.py +++ b/backend/api/app/routes/v2.py @@ -5,21 +5,27 @@ # Standard Library from typing import Annotated +# Third Party +from app.helpers.query import get_requester, query_ipv4 +from app.schemas.api import APIResponseSchema, APISchema from litestar import MediaType, Request, get, post from litestar.openapi.spec import Example from litestar.params import Body, Parameter from litestar.status_codes import HTTP_200_OK -# Third Party -from app.helpers.query import get_requester, query_ipv4 -from app.schemas.api import APIResponseSchema, APISchema - @get("/api/me", media_type=MediaType.TEXT, sync_to_thread=False) def my_ip(request: Request) -> str: """ - Returns the requester IP back to the user via the following request headers; - `cf-connecting-ip`, `do-connecting-ip`, `x-real-ip`. + Returns the requester IP. + + Auto-detects the requester IP address using the following headers: + - `cf-connecting-ip` + - `do-connecting-ip` + - `x-real-ip` + + These headers are typically added by the application ingress router (ie, Nginx) + and so does not need to be explicitly provided. The live production environment version of this app lives on DigitalOceans App Platform, and so the `do-connecting-ip` will be leveraged. @@ -36,28 +42,32 @@ def get_port_check( port: int = Parameter(examples=[Example(value=443)]), ) -> str: """ - A `GET` endpoint to query a port for a hostname or IP address. + A `GET` endpoint to check the status of a specific port on a given + resolvable hostname or IPv4 address. - Autodetection of the requesters address is available by providing the host as `me`. - If `me` is provided as the host, we will check the request headers for the following - parameters; `cf-connecting-ip`, `do-connecting-ip`, `x-real-ip`. - These headers would be automatically passed to the API via its ingress. + Use `me` as the host to auto-detect the requester IP address based + on the following headers: + - `cf-connecting-ip` + - `do-connecting-ip` + - `x-real-ip` + + These headers are typically added by the application ingress router (ie, Nginx) + and so does not need to be explicitly provided. **Note:** Whilst the results of this endpoints port check are not logged, - if a host is explicitly passed, the URL will be logged to STDOUT. + if a host is explicitly passed, the URL will be logged to `STDOUT`. For example; ~~~ "GET /foo.com/443 HTTP/1.1" 200 OK ~~~ - If `me` is provided as the host, requester autodetection will be used via + If `me` is provided as the host, requester auto-detection will be used using the above headers. However, the requester will not be logged. For example; ~~~ "GET /me/443 HTTP/1.1" 200 OK ~~~ - Application logs are not collected, forwarded or permanently stored. - + Application logs are not forwarded or permanently stored. """ host = get_requester(request) if host == "me" else host APISchema(host=host, ports=[port]) @@ -73,20 +83,24 @@ def get_port_check( def query_post( data: Annotated[ APISchema, - Body(title="Query a hostname or IP", description="Query a hostname or IP"), + Body( + title="Query a resolvable hostname or IPv4 address", + description="Query a resolvable hostname or IPv4 address", + ), ], ) -> APIResponseSchema: """ - A `POST` endpoint to query a range of ports for a hostname or IP address. - - This endpoint will accept an IPv4 IP address or resolveable hostname, - and iterate an array of port numbers provided. + A `POST` endpoint to query the status of multiple ports on a given hostname + or IP address. - The port check will timeout after 1 second. + This endpoint accepts a JSON payload containing either an IPv4 address + or a resolvable hostname, along with an array of port numbers to be checked. + For each port in the array, the endpoint performs a connectivity check with a + timeout of 1 second per port. **NOTE:** The request body for this endpoint is not logged. ~~~ - "POST / HTTP/1.1" 200 OK + "POST /api/query HTTP/1.1" 200 OK ~~~ """ return APIResponseSchema( diff --git a/backend/api/main.py b/backend/api/main.py index f709e4a..80773d4 100644 --- a/backend/api/main.py +++ b/backend/api/main.py @@ -12,7 +12,12 @@ route_handlers=[my_ip, query_post, get_port_check, v1_query_post, health], openapi_config=OpenAPIConfig( title="portchecker.io", - description="Documentation for portchecker.io", + description=( + "portchecker.io is an open-source API for checking port \ + availability on specified hostnames or IP addresses. \ + Ideal for developers and network admins, it helps troubleshoot network \ + setups, validate firewall rules, and assess potential access points." + ), version="3.0.0", render_plugins=[ScalarRenderPlugin()], path="/docs",