From 017ab86591c4d033827f4332659a519b0559935d Mon Sep 17 00:00:00 2001 From: clowzed Date: Mon, 24 Jun 2024 12:58:04 +0300 Subject: [PATCH 1/9] actions-fix: update toolchain to nightly for cargo fmt to use crate imports granularity --- .github/workflows/test.yml | 2 +- Cargo.toml | 2 +- openapi.json | 2434 ++++++++++++++++++------------------ 3 files changed, 1219 insertions(+), 1219 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5556be5..287ab55 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -77,7 +77,7 @@ jobs: - uses: "actions-rs/toolchain@v1" with: profile: "minimal" - toolchain: "stable" + toolchain: "nightly" override: true - run: "rustup component add rustfmt" diff --git a/Cargo.toml b/Cargo.toml index c5bf411..8d82c3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.1" +version = "0.2.2" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" diff --git a/openapi.json b/openapi.json index c933fec..20c27d1 100644 --- a/openapi.json +++ b/openapi.json @@ -1,1219 +1,1219 @@ { - "openapi": "3.0.3", - "info": { - "title": "sero", - "description": "Muiltidomain static site hosting", - "contact": { - "name": "clowzed", - "email": "clowzed.work@gmail.com" - }, - "license": { - "name": "MIT" - }, - "version": "0.2.1" - }, - "paths": { - "/api/auth/login": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Login user and receive JWT token.", - "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", - "operationId": "Login", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully authenticated.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Login was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/auth/registration": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Register new user for sero server.", - "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", - "operationId": "Registration", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "409": { - "description": "Login has already been registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/origin": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Origins were successfully retrieved for subdomain.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListOriginsResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Create origin", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginRequest" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "The origin was successfully added.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Origins were successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/origin/{id}": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to retrieve", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "Origin was successfully retrieved.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Origin was successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The origin is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site": { - "get": { - "tags": [ - "Actions" - ], - "summary": "Download site of the specified subdomain.", - "description": "Returns a zip file which was uploaded by user (last)", - "operationId": "Download site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Site was successfully downloaded", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Actions" - ], - "summary": "Uploads site for a specified subdomain.", - "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", - "operationId": "Upload site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadData" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Site was successfully uploaded" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Actions" - ], - "summary": "Removes a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", - "operationId": "Teardown site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully removed." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/disable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Disables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", - "operationId": "Disable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully disabled." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/enable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Enables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", - "operationId": "Enable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully enabled" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - } - }, - "components": { - "schemas": { - "AddOriginRequest": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "type": "string", - "description": "Origin to be added" - } - }, - "example": { - "origin": "https://example.com/" - } - }, - "AddOriginResponse": { - "type": "object", - "required": [ - "id", - "origin" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Automatically generated id for new origin\nThis can be used for further management" - }, - "origin": { - "type": "string", - "description": "This duplicates origin from response payload\nto match REST specification" - } - }, - "example": { - "id": "42", - "origin": "https://example.com/" - } - }, - "Details": { - "type": "object", - "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", - "required": [ - "reason" - ], - "properties": { - "reason": { - "type": "string", - "description": "This field will contain error information" - } - } - }, - "GetOriginResponse": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "$ref": "#/components/schemas/OriginModel" - } - }, - "example": { - "origin": { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - } - }, - "ListOriginsResponse": { - "type": "object", - "required": [ - "origins" - ], - "properties": { - "origins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OriginModel" - }, - "description": "List of retrieved origins" - } - }, - "example": { - "origins": [ - { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - ] - } - }, - "LoginRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "LoginResponse": { - "type": "object", - "description": "The JWT token generated for authentication purposes.", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "Token in JWT format" - } - }, - "example": { - "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" - } - }, - "OriginModel": { - "type": "object", - "required": [ - "id", - "subdomain_id", - "value" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "subdomain_id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "string" - } - } - }, - "RegistrationRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "RegistrationResponse": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Auto generated id of a registered user" - } - }, - "example": { - "id": 1293983717 - } - }, - "UploadData": { - "type": "object", - "required": [ - "archive" - ], - "properties": { - "archive": { - "type": "string", - "format": "binary" - } - } - } - }, - "securitySchemes": { - "Bearer-JWT": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } + "openapi": "3.0.3", + "info": { + "title": "sero", + "description": "Muiltidomain static site hosting", + "contact": { + "name": "clowzed", + "email": "clowzed.work@gmail.com" + }, + "license": { + "name": "MIT" + }, + "version": "0.2.2" + }, + "paths": { + "/api/auth/login": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Login user and receive JWT token.", + "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", + "operationId": "Login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Login was not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/auth/registration": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Register new user for sero server.", + "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", + "operationId": "Registration", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "409": { + "description": "Login has already been registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/origin": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Origins were successfully retrieved for subdomain.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOriginsResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Create origin", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The origin was successfully added.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Origins were successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/origin/{id}": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to retrieve", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Origin was successfully retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Origin was successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The origin is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site": { + "get": { + "tags": [ + "Actions" + ], + "summary": "Download site of the specified subdomain.", + "description": "Returns a zip file which was uploaded by user (last)", + "operationId": "Download site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Site was successfully downloaded", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Actions" + ], + "summary": "Uploads site for a specified subdomain.", + "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", + "operationId": "Upload site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadData" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Site was successfully uploaded" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Actions" + ], + "summary": "Removes a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", + "operationId": "Teardown site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully removed." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/disable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Disables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", + "operationId": "Disable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully disabled." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/enable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Enables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", + "operationId": "Enable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully enabled" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + } + }, + "components": { + "schemas": { + "AddOriginRequest": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "Origin to be added" + } + }, + "example": { + "origin": "https://example.com/" + } + }, + "AddOriginResponse": { + "type": "object", + "required": [ + "id", + "origin" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Automatically generated id for new origin\nThis can be used for further management" + }, + "origin": { + "type": "string", + "description": "This duplicates origin from response payload\nto match REST specification" + } + }, + "example": { + "id": "42", + "origin": "https://example.com/" + } + }, + "Details": { + "type": "object", + "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "description": "This field will contain error information" + } + } + }, + "GetOriginResponse": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "$ref": "#/components/schemas/OriginModel" + } + }, + "example": { + "origin": { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + } + }, + "ListOriginsResponse": { + "type": "object", + "required": [ + "origins" + ], + "properties": { + "origins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OriginModel" + }, + "description": "List of retrieved origins" + } + }, + "example": { + "origins": [ + { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + ] + } + }, + "LoginRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "LoginResponse": { + "type": "object", + "description": "The JWT token generated for authentication purposes.", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "Token in JWT format" + } + }, + "example": { + "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" + } + }, + "OriginModel": { + "type": "object", + "required": [ + "id", + "subdomain_id", + "value" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "subdomain_id": { + "type": "integer", + "format": "int64" + }, + "value": { + "type": "string" + } + } + }, + "RegistrationRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "RegistrationResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Auto generated id of a registered user" + } + }, + "example": { + "id": 1293983717 + } + }, + "UploadData": { + "type": "object", + "required": [ + "archive" + ], + "properties": { + "archive": { + "type": "string", + "format": "binary" + } + } + } + }, + "securitySchemes": { + "Bearer-JWT": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } } From aa27492f6f3f636b6db05ee9fa5f2fc56a2a8ef9 Mon Sep 17 00:00:00 2001 From: clowzed Date: Mon, 24 Jun 2024 13:03:05 +0300 Subject: [PATCH 2/9] actions-fix: update toolchain to nightly for cargo fmt to use crate imports granularity part 2. remove +nightly --- .github/workflows/test.yml | 2 +- Cargo.toml | 2 +- openapi.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 287ab55..894068a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -84,7 +84,7 @@ jobs: - uses: "actions-rs/cargo@v1" with: - command: "+nightly fmt" + command: "fmt" args: "--all -- --check" clippy: diff --git a/Cargo.toml b/Cargo.toml index 8d82c3c..e0cb270 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.2" +version = "0.2.3" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" diff --git a/openapi.json b/openapi.json index 20c27d1..795d731 100644 --- a/openapi.json +++ b/openapi.json @@ -10,7 +10,7 @@ "license": { "name": "MIT" }, - "version": "0.2.2" + "version": "0.2.3" }, "paths": { "/api/auth/login": { From 6eb836ee19afc01f1d8fe12c6d8d58b8ae45bee1 Mon Sep 17 00:00:00 2001 From: clowzed Date: Mon, 24 Jun 2024 13:08:25 +0300 Subject: [PATCH 3/9] version-update for: toolchane update in fmt test. Add optimized build in profile. --- Cargo.toml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e0cb270..00edba1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,5 +77,11 @@ members = [".", "entity", "migration"] [dev-dependencies] - axum-test = "15.2.0" + + +[profile.release] +lto = true +strip = true +opt-level = 3 +codegen-units = 1 From ac8bcf4e2ad04b83e4e1d16818470e2841c197d3 Mon Sep 17 00:00:00 2001 From: clowzed Date: Fri, 28 Jun 2024 14:03:14 +0300 Subject: [PATCH 4/9] fix: donotstart profile removed from docker-compose.yml. Obsolete files will be removed from database too. Try cors check return allowed if x-subdomain missing. This should not be desired behaviour and needs to be resolved using placement of layers in router. --- Cargo.toml | 2 +- docker-compose.yml | 7 +- nginx-templates/default.conf.template | 12 +- openapi.json | 2434 ++++++++++++------------- src/lib.rs | 18 +- 5 files changed, 1238 insertions(+), 1235 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 00edba1..4a75a03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.3" +version = "0.2.4" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" diff --git a/docker-compose.yml b/docker-compose.yml index f7727d8..995d255 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,6 @@ services: database: image: postgres:16 user: postgres - restart: always environment: - POSTGRES_USER=postgres - POSTGRES_DB=sero @@ -21,7 +20,6 @@ services: proxy: image: nginx:alpine3.18-slim - restart: always environment: - DOLLAR=$ - SERVER_PORT=8080 @@ -37,12 +35,9 @@ services: - 80:80 links: - server - profiles: - - donotstart server: image: clowzed/sero - restart: always build: . depends_on: database: @@ -60,8 +55,8 @@ services: - MAX_SITES_PER_USER=100 - MAX_BODY_LIMIT_SIZE=10000000 # 10mb - RUST_LOG=none,sero=trace - # end of section - JWT_SECRET=mysuperstrongjwtscret + # end of section - JWT_TTL_SECONDS=120 - SQLX_LOGGING=true - UPLOAD_FOLDER=./sites-uploads diff --git a/nginx-templates/default.conf.template b/nginx-templates/default.conf.template index d0f5380..ad452bb 100644 --- a/nginx-templates/default.conf.template +++ b/nginx-templates/default.conf.template @@ -1,18 +1,10 @@ server { - - - # We check if $subdomain is not empty and if the X-subdomain header is not present in the request - # ($http_x_subdomain = ""). - # If both conditions are met, we set the X-subdomain header using proxy_set_header. - # Otherwise, we do nothing, and the existing X-subdomain header (if any) will be preserved. - listen 80; server_name ~^(?\w*)\.${DOMAIN}.${ZONE}${DOLLAR}; location / { - if ($subdomain != "" && $http_x_subdomain = "") { - proxy_set_header x-subdomain $subdomain; - } + # Always set the X-subdomain header with the value from the subdomain in the URL + proxy_set_header x-subdomain $subdomain; proxy_pass http://${SERVER}:${SERVER_PORT}/; } } diff --git a/openapi.json b/openapi.json index 795d731..8a614f4 100644 --- a/openapi.json +++ b/openapi.json @@ -1,1219 +1,1219 @@ { - "openapi": "3.0.3", - "info": { - "title": "sero", - "description": "Muiltidomain static site hosting", - "contact": { - "name": "clowzed", - "email": "clowzed.work@gmail.com" - }, - "license": { - "name": "MIT" - }, - "version": "0.2.3" - }, - "paths": { - "/api/auth/login": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Login user and receive JWT token.", - "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", - "operationId": "Login", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully authenticated.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Login was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/auth/registration": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Register new user for sero server.", - "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", - "operationId": "Registration", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "409": { - "description": "Login has already been registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/origin": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Origins were successfully retrieved for subdomain.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListOriginsResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Create origin", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginRequest" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "The origin was successfully added.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Origins were successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/origin/{id}": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to retrieve", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "Origin was successfully retrieved.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Origin was successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The origin is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site": { - "get": { - "tags": [ - "Actions" - ], - "summary": "Download site of the specified subdomain.", - "description": "Returns a zip file which was uploaded by user (last)", - "operationId": "Download site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Site was successfully downloaded", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Actions" - ], - "summary": "Uploads site for a specified subdomain.", - "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", - "operationId": "Upload site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadData" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Site was successfully uploaded" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Actions" - ], - "summary": "Removes a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", - "operationId": "Teardown site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully removed." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/disable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Disables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", - "operationId": "Disable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully disabled." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/enable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Enables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", - "operationId": "Enable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully enabled" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - } - }, - "components": { - "schemas": { - "AddOriginRequest": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "type": "string", - "description": "Origin to be added" - } - }, - "example": { - "origin": "https://example.com/" - } - }, - "AddOriginResponse": { - "type": "object", - "required": [ - "id", - "origin" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Automatically generated id for new origin\nThis can be used for further management" - }, - "origin": { - "type": "string", - "description": "This duplicates origin from response payload\nto match REST specification" - } - }, - "example": { - "id": "42", - "origin": "https://example.com/" - } - }, - "Details": { - "type": "object", - "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", - "required": [ - "reason" - ], - "properties": { - "reason": { - "type": "string", - "description": "This field will contain error information" - } - } - }, - "GetOriginResponse": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "$ref": "#/components/schemas/OriginModel" - } - }, - "example": { - "origin": { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - } - }, - "ListOriginsResponse": { - "type": "object", - "required": [ - "origins" - ], - "properties": { - "origins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OriginModel" - }, - "description": "List of retrieved origins" - } - }, - "example": { - "origins": [ - { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - ] - } - }, - "LoginRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "LoginResponse": { - "type": "object", - "description": "The JWT token generated for authentication purposes.", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "Token in JWT format" - } - }, - "example": { - "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" - } - }, - "OriginModel": { - "type": "object", - "required": [ - "id", - "subdomain_id", - "value" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "subdomain_id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "string" - } - } - }, - "RegistrationRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "RegistrationResponse": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Auto generated id of a registered user" - } - }, - "example": { - "id": 1293983717 - } - }, - "UploadData": { - "type": "object", - "required": [ - "archive" - ], - "properties": { - "archive": { - "type": "string", - "format": "binary" - } - } - } - }, - "securitySchemes": { - "Bearer-JWT": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } + "openapi": "3.0.3", + "info": { + "title": "sero", + "description": "Muiltidomain static site hosting", + "contact": { + "name": "clowzed", + "email": "clowzed.work@gmail.com" + }, + "license": { + "name": "MIT" + }, + "version": "0.2.4" + }, + "paths": { + "/api/auth/login": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Login user and receive JWT token.", + "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", + "operationId": "Login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Login was not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/auth/registration": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Register new user for sero server.", + "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", + "operationId": "Registration", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "409": { + "description": "Login has already been registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/origin": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Origins were successfully retrieved for subdomain.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOriginsResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Create origin", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The origin was successfully added.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Origins were successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/origin/{id}": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to retrieve", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Origin was successfully retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Origin was successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The origin is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site": { + "get": { + "tags": [ + "Actions" + ], + "summary": "Download site of the specified subdomain.", + "description": "Returns a zip file which was uploaded by user (last)", + "operationId": "Download site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Site was successfully downloaded", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Actions" + ], + "summary": "Uploads site for a specified subdomain.", + "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", + "operationId": "Upload site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadData" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Site was successfully uploaded" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Actions" + ], + "summary": "Removes a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", + "operationId": "Teardown site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully removed." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/disable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Disables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", + "operationId": "Disable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully disabled." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/enable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Enables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", + "operationId": "Enable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully enabled" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + } + }, + "components": { + "schemas": { + "AddOriginRequest": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "Origin to be added" + } + }, + "example": { + "origin": "https://example.com/" + } + }, + "AddOriginResponse": { + "type": "object", + "required": [ + "id", + "origin" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Automatically generated id for new origin\nThis can be used for further management" + }, + "origin": { + "type": "string", + "description": "This duplicates origin from response payload\nto match REST specification" + } + }, + "example": { + "id": "42", + "origin": "https://example.com/" + } + }, + "Details": { + "type": "object", + "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "description": "This field will contain error information" + } + } + }, + "GetOriginResponse": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "$ref": "#/components/schemas/OriginModel" + } + }, + "example": { + "origin": { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + } + }, + "ListOriginsResponse": { + "type": "object", + "required": [ + "origins" + ], + "properties": { + "origins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OriginModel" + }, + "description": "List of retrieved origins" + } + }, + "example": { + "origins": [ + { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + ] + } + }, + "LoginRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "LoginResponse": { + "type": "object", + "description": "The JWT token generated for authentication purposes.", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "Token in JWT format" + } + }, + "example": { + "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" + } + }, + "OriginModel": { + "type": "object", + "required": [ + "id", + "subdomain_id", + "value" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "subdomain_id": { + "type": "integer", + "format": "int64" + }, + "value": { + "type": "string" + } + } + }, + "RegistrationRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "RegistrationResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Auto generated id of a registered user" + } + }, + "example": { + "id": 1293983717 + } + }, + "UploadData": { + "type": "object", + "required": [ + "archive" + ], + "properties": { + "archive": { + "type": "string", + "format": "binary" + } + } + } + }, + "securitySchemes": { + "Bearer-JWT": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index f58974a..13c2ebb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,8 @@ use configuration::{reader::ConfigurationReader, *}; use futures::StreamExt; use migration::{Migrator, MigratorTrait}; use origin::service::Service as CorsService; -use sea_orm::{ConnectOptions, Database, DbErr}; +use sea_orm::ActiveModelTrait; +use sea_orm::{ConnectOptions, Database, DbErr, IntoActiveModel}; use serde::{Deserialize, Serialize}; use services::*; use site::service::Service as SiteService; @@ -165,6 +166,15 @@ pub async fn app() -> Result<(Router, Arc), AppCreationError> { |cause| tracing::warn!(%cause, "Failed to remove file with path : {}", file.real_path), ) .ok(); + + let file_id = file.id; + file.into_active_model() + .delete(state_for_file_deletion_task.connection()) + .await + .inspect_err( + |cause| tracing::warn!(%cause, %file_id, "Failed to remove file from database"), + ) + .ok(); } } } @@ -197,6 +207,12 @@ pub async fn app() -> Result<(Router, Arc), AppCreationError> { }; async move { + //? If header was not provided + //? Allow as it probably management tool + if task.subdomain.is_empty() { + return true; + } + if cors_task_sender .send(task) .await From b22e8817e1912905bc14c16b7e1c18efb922315b Mon Sep 17 00:00:00 2001 From: clowzed Date: Fri, 28 Jun 2024 14:08:57 +0300 Subject: [PATCH 5/9] fix: fmt --- Cargo.toml | 2 +- openapi.json | 2434 +++++++++++++++++++++++++------------------------- src/lib.rs | 3 +- 3 files changed, 1219 insertions(+), 1220 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4a75a03..9e04864 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.4" +version = "0.2.5" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" diff --git a/openapi.json b/openapi.json index 8a614f4..cd00ae7 100644 --- a/openapi.json +++ b/openapi.json @@ -1,1219 +1,1219 @@ { - "openapi": "3.0.3", - "info": { - "title": "sero", - "description": "Muiltidomain static site hosting", - "contact": { - "name": "clowzed", - "email": "clowzed.work@gmail.com" - }, - "license": { - "name": "MIT" - }, - "version": "0.2.4" - }, - "paths": { - "/api/auth/login": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Login user and receive JWT token.", - "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", - "operationId": "Login", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully authenticated.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Login was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/auth/registration": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Register new user for sero server.", - "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", - "operationId": "Registration", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "409": { - "description": "Login has already been registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/origin": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Origins were successfully retrieved for subdomain.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListOriginsResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Create origin", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginRequest" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "The origin was successfully added.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Origins were successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/origin/{id}": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to retrieve", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "Origin was successfully retrieved.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Origin was successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The origin is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site": { - "get": { - "tags": [ - "Actions" - ], - "summary": "Download site of the specified subdomain.", - "description": "Returns a zip file which was uploaded by user (last)", - "operationId": "Download site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Site was successfully downloaded", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Actions" - ], - "summary": "Uploads site for a specified subdomain.", - "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", - "operationId": "Upload site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadData" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Site was successfully uploaded" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Actions" - ], - "summary": "Removes a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", - "operationId": "Teardown site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully removed." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/disable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Disables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", - "operationId": "Disable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully disabled." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/enable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Enables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", - "operationId": "Enable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully enabled" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - } - }, - "components": { - "schemas": { - "AddOriginRequest": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "type": "string", - "description": "Origin to be added" - } - }, - "example": { - "origin": "https://example.com/" - } - }, - "AddOriginResponse": { - "type": "object", - "required": [ - "id", - "origin" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Automatically generated id for new origin\nThis can be used for further management" - }, - "origin": { - "type": "string", - "description": "This duplicates origin from response payload\nto match REST specification" - } - }, - "example": { - "id": "42", - "origin": "https://example.com/" - } - }, - "Details": { - "type": "object", - "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", - "required": [ - "reason" - ], - "properties": { - "reason": { - "type": "string", - "description": "This field will contain error information" - } - } - }, - "GetOriginResponse": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "$ref": "#/components/schemas/OriginModel" - } - }, - "example": { - "origin": { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - } - }, - "ListOriginsResponse": { - "type": "object", - "required": [ - "origins" - ], - "properties": { - "origins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OriginModel" - }, - "description": "List of retrieved origins" - } - }, - "example": { - "origins": [ - { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - ] - } - }, - "LoginRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "LoginResponse": { - "type": "object", - "description": "The JWT token generated for authentication purposes.", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "Token in JWT format" - } - }, - "example": { - "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" - } - }, - "OriginModel": { - "type": "object", - "required": [ - "id", - "subdomain_id", - "value" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "subdomain_id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "string" - } - } - }, - "RegistrationRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "RegistrationResponse": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Auto generated id of a registered user" - } - }, - "example": { - "id": 1293983717 - } - }, - "UploadData": { - "type": "object", - "required": [ - "archive" - ], - "properties": { - "archive": { - "type": "string", - "format": "binary" - } - } - } - }, - "securitySchemes": { - "Bearer-JWT": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } + "openapi": "3.0.3", + "info": { + "title": "sero", + "description": "Muiltidomain static site hosting", + "contact": { + "name": "clowzed", + "email": "clowzed.work@gmail.com" + }, + "license": { + "name": "MIT" + }, + "version": "0.2.5" + }, + "paths": { + "/api/auth/login": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Login user and receive JWT token.", + "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", + "operationId": "Login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Login was not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/auth/registration": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Register new user for sero server.", + "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", + "operationId": "Registration", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "409": { + "description": "Login has already been registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/origin": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Origins were successfully retrieved for subdomain.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOriginsResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Create origin", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The origin was successfully added.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Origins were successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/origin/{id}": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to retrieve", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Origin was successfully retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Origin was successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The origin is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site": { + "get": { + "tags": [ + "Actions" + ], + "summary": "Download site of the specified subdomain.", + "description": "Returns a zip file which was uploaded by user (last)", + "operationId": "Download site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Site was successfully downloaded", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Actions" + ], + "summary": "Uploads site for a specified subdomain.", + "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", + "operationId": "Upload site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadData" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Site was successfully uploaded" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Actions" + ], + "summary": "Removes a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", + "operationId": "Teardown site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully removed." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/disable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Disables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", + "operationId": "Disable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully disabled." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/enable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Enables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", + "operationId": "Enable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully enabled" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + } + }, + "components": { + "schemas": { + "AddOriginRequest": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "Origin to be added" + } + }, + "example": { + "origin": "https://example.com/" + } + }, + "AddOriginResponse": { + "type": "object", + "required": [ + "id", + "origin" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Automatically generated id for new origin\nThis can be used for further management" + }, + "origin": { + "type": "string", + "description": "This duplicates origin from response payload\nto match REST specification" + } + }, + "example": { + "id": "42", + "origin": "https://example.com/" + } + }, + "Details": { + "type": "object", + "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "description": "This field will contain error information" + } + } + }, + "GetOriginResponse": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "$ref": "#/components/schemas/OriginModel" + } + }, + "example": { + "origin": { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + } + }, + "ListOriginsResponse": { + "type": "object", + "required": [ + "origins" + ], + "properties": { + "origins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OriginModel" + }, + "description": "List of retrieved origins" + } + }, + "example": { + "origins": [ + { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + ] + } + }, + "LoginRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "LoginResponse": { + "type": "object", + "description": "The JWT token generated for authentication purposes.", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "Token in JWT format" + } + }, + "example": { + "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" + } + }, + "OriginModel": { + "type": "object", + "required": [ + "id", + "subdomain_id", + "value" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "subdomain_id": { + "type": "integer", + "format": "int64" + }, + "value": { + "type": "string" + } + } + }, + "RegistrationRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "RegistrationResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Auto generated id of a registered user" + } + }, + "example": { + "id": 1293983717 + } + }, + "UploadData": { + "type": "object", + "required": [ + "archive" + ], + "properties": { + "archive": { + "type": "string", + "format": "binary" + } + } + } + }, + "securitySchemes": { + "Bearer-JWT": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index 13c2ebb..da97b0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,8 +11,7 @@ use configuration::{reader::ConfigurationReader, *}; use futures::StreamExt; use migration::{Migrator, MigratorTrait}; use origin::service::Service as CorsService; -use sea_orm::ActiveModelTrait; -use sea_orm::{ConnectOptions, Database, DbErr, IntoActiveModel}; +use sea_orm::{ActiveModelTrait, ConnectOptions, Database, DbErr, IntoActiveModel}; use serde::{Deserialize, Serialize}; use services::*; use site::service::Service as SiteService; From a86f6ba0e72e018bbc7ee9d3ad40d7d94f0d9f6a Mon Sep 17 00:00:00 2001 From: Dmitry Miasnenko Date: Tue, 6 Aug 2024 00:12:03 +0300 Subject: [PATCH 6/9] Release 0.2.6 (#24) * Added docker-compose for dev. Added dev build build and push job for dockerhub * Moved cors layer to check if /api now is not guarded * Added logging for error in response * Removed too strict validation rules for credentials * fix: x-subdmain was overwritten on correct request. Updated nginx-template and nginx now waits for server * proxy-fix: New nginx config as the previous one failed with subdomain * archive-fix: Remove skipping first component in path of entry. Zip archive should not containt root folder. * assets-fix: Remove root folder inside zips to pass tests. The root dir is not skipped now due to previous commit * tests-fix: enable logging to see error message in gh actions. Lokal tests work fine * fmt: for tests * tests-fix: disable logging to see error message in gh actions. That was gh issue * fmt: remove unused import * openapi-client: add build and publih with gh actions * fix-deploy: nginx now waits for server in dev also * fix-deploy: publsh to pypi --- .github/workflows/dev.yml | 27 + .github/workflows/release.yml | 50 + Cargo.toml | 2 +- assets/zips/correct-1.zip | Bin 20548 -> 19938 bytes assets/zips/correct-2.zip | Bin 742 -> 228 bytes assets/zips/correct-3.zip | Bin 742 -> 228 bytes assets/zips/correct-with-404.html.zip | Bin 20742 -> 20036 bytes assets/zips/correct-with-503.html.zip | Bin 940 -> 330 bytes assets/zips/correct-without-404.html.zip | Bin 20548 -> 19938 bytes assets/zips/correct-without-503.html.zip | Bin 746 -> 232 bytes docker-compose.dev.yml | 69 + docker-compose.yml | 2 + nginx-templates/default.conf.template | 20 +- openapi.json | 2434 +++++++++++----------- src/api/auth/login/error.rs | 2 +- src/api/auth/login/request.rs | 60 +- src/api/auth/registration/error.rs | 1 + src/api/auth/registration/request.rs | 60 +- src/api/origin/create/error.rs | 1 + src/api/origin/delete/error.rs | 1 + src/api/origin/list/error.rs | 1 + src/api/origin/purge/error.rs | 1 + src/api/origin/retrieve/error.rs | 1 + src/api/site/disable/error.rs | 1 + src/api/site/download/error.rs | 1 + src/api/site/enable/error.rs | 1 + src/api/site/page/error.rs | 1 + src/api/site/teardown/error.rs | 1 + src/api/site/upload/error.rs | 1 + src/extractors/auth.rs | 1 + src/extractors/guards/upload.rs | 1 + src/extractors/subdomain.rs | 1 + src/extractors/subdomain_name.rs | 1 + src/extractors/subdomain_owned.rs | 1 + src/lib.rs | 2 +- src/services/archive/service.rs | 4 +- 36 files changed, 1411 insertions(+), 1338 deletions(-) create mode 100644 .github/workflows/dev.yml create mode 100644 docker-compose.dev.yml diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml new file mode 100644 index 0000000..7b64b15 --- /dev/null +++ b/.github/workflows/dev.yml @@ -0,0 +1,27 @@ +name: "Test" + +on: + push: + branches: + - "dev" # matches every branch + +jobs: + push-to-registry: + name: "Build and push Docker image to Docker Hub" + runs-on: "ubuntu-latest" + steps: + - name: "Check out the repo" + uses: actions/checkout@v3 + + - name: "Log in to Docker Hub" + uses: "docker/login-action@v2" + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_PASSWORD }} + + - name: "Build and push Docker image" + uses: "docker/build-push-action@v3" + with: + context: . + push: true + tags: clowzed/sero:dev-unstable diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e46b2cc..9d1eb30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -104,3 +104,53 @@ jobs: push: true tags: clowzed/sero:v${{ needs.get-tag.outputs.pkg-version }} labels: ${{ steps.meta.outputs.labels }} + upload-openapi-client: + needs: + - "push-to-registry" + name: "Build and upload openapi python client" + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: "16" + + - name: Install OpenAPI Generator CLI + run: | + npm install @openapitools/openapi-generator-cli -g + - name: Extract version from OpenAPI spec + id: extract_version + run: | + VERSION=$(jq -r '.info.version' openapi.json) + echo "VERSION=$VERSION" >> $GITHUB_ENV + + - name: Generate Python client from OpenAPI spec + run: | + openapi-generator-cli generate -i openapi.json -g python -o seroapi --additional-properties=packageName=seroapi,packageVersion=${{ env.VERSION }} + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.x" + + - name: Install Poetry + run: | + curl -sSL https://install.python-poetry.org | python3 - + + - name: Configure Poetry + run: | + poetry config virtualenvs.in-project true + + - name: Install dependencies + run: | + cd seroapi + poetry install + + - name: Publish to Test PyPI + run: | + cd seroapi + poetry publish -u __token__ -p ${{ secrets.PYPI_PASSWORD }} --build diff --git a/Cargo.toml b/Cargo.toml index 9e04864..0c740b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.5" +version = "0.2.6" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" diff --git a/assets/zips/correct-1.zip b/assets/zips/correct-1.zip index 6c82e27ad63c19a7f71a7166ea864dad562a92d8..784228859c5f3c126fa28ff4abb9ee6eee27f5aa 100644 GIT binary patch delta 336 zcmX@Ifbr36MvVY(W)=|!1_llWnabA@YbN;Y2~-1emkTj)0jbQql++5njFQ}(%|FzG z)k2Wf0;L(4Km-tQ0&#I_QNCVDer^sk18zh4K??J8Q}xkIu4iNtVaDwakR2efq!C0S z^agmN>I2Cly9vYxfhCQVKwrUKh^}qT1V@CwK~98$C5?+f`cNGl;LXYgQosy^Yk;(Z HFNg;K{Ub)} delta 957 zcmaDfoAJm3#`*wnW)=|!5O~p>906uP2@VDYhUEOBqSWLP{m>9z2KLh4C#i5;!Og(P z@`9Ox0Zc$l;b7ok(CIFeEN zV6)KN-m>{|YC8~vXf#tdpH~aUbTlKA2s7@Oga#wSTSpL!_;`hwiX5}h7^!CfMJ)_0 zX>>y}7E459kLLhyg!!O&MUDngyu!ee#^p%HgF~vGsAz^+05S+$Y{D#f>lmSq2o_@E swg#9^5RL~$FS6r7(F+4h8W*FRO?+Gjc(byB3}OYstBec`k$xZ^01Hq)$ diff --git a/assets/zips/correct-2.zip b/assets/zips/correct-2.zip index 939621c5fbc565b4c58d238d114266d1234630ce..f30aa57bc273ef3d48e20cda0743bdec1c88499d 100644 GIT binary patch literal 228 zcmWIWW@Zs#U|`^2kg0qf0c0>Rfe0Yr1mfb9D literal 742 zcmWIWW@Zs#0D;pvNfBTMl;B`cU`Wm{DoRZ*(GLybWniDj_&9Yw5QFH_3T_5QmKV$n z3}7MvYzhYh2ZMfZB8n-3NTw907Uk=e1{ns! zXoea;VgkE)!ulE?7NAie;{v=HnM9az2QE+v7`$}^QN#x|#8l+KhJ_L+uwh_HqZ^W` zLxqmjc0WGpDCVc@Ofav&4t=wjjm9^rD3(a2#13VIk=()bD8XyPLxz?+o~WDpAw NmNGIhL<2Dc0{~_Sp%4H7 diff --git a/assets/zips/correct-3.zip b/assets/zips/correct-3.zip index 0e9c53ce148084e4d44dc6fdfe4e85801746b052..2641e251f71e3944262913fe56092527fb42f8c2 100644 GIT binary patch literal 228 zcmWIWW@Zs#U|`^2kg0qf0c0>Rfe0Yr1mfb1{ns! zXoea;V*xqmjc0WGpDCVc@Ofav&4t=wjjm9^rD3(a2#13VIk=()bD8XyPLxz?+o~WDpAw NmNGIhL<2Dc0|2s|qZ9xD diff --git a/assets/zips/correct-with-404.html.zip b/assets/zips/correct-with-404.html.zip index 9b17c0b3ffdab9d866c485f7a27f984318706273..daec77bf55fc2256ecec87812b8721f8be5b1b29 100644 GIT binary patch delta 435 zcmZo$#CT*5qeg%?Gm8iV0|N(xOy%o{H4}XH1gZhK%Y_)YfK+B)N@|5(MoDhY<`|7& zwR&W=ll^BZvH{hwfORu4m>8IVRT>)_JY-@(H5aIafeAza0Vfa_rxxYwmE`Bb0)qhN9dunl v1?4Dy0qX&4TME<$_ZhlAbe|!#odan@@h8x!te~I;hAj)jBOvYL3*rF)1+rI0 delta 1146 zcmX>yhp}xDV|{=(Gm8iV2&`C;906uP2@VDYhUEOBqSWLP{m>9z2KKXSpQOTYX$3a} zBg+eB1_m$zF@=MH1H}{;ph*HqrkEI*=w+1T<{+6?4>1zWIAcSDhfE9s-s~Kc{bwq& z0gV9}g|I}wHxb3Df=HGWrxxYwmE=Qhk$U+s^?Lb})Z#x6Q_(D823Zix0rD*qhyVhF z4KI3;0%N%lgAkGpnRzLx6$p=%_C85%24WD6X2s^;YQbvt>>O(*`0NQ(16lwy2@&8c z`;t(6!HZ-^aei(pB-G<5^duETqZyBIu8t6@bH$O2(g&M`=IEBqk5k)$7(}C) zirvwSOd`y<(+N2AfW%uz5R3R!12GkrZjd6o9-MGs#x7}eLoyaiGQygQ0=yB%!%_?^ zra>tN29`9gLNXnae(H%xK*;8U(hG7dgVGBOENSFsL<9<2MBqq0^`NW;vjAiew!{Ln z;H~2xb%X^(CLKiBfD#X~+d+vZ8fNyAMs^J}v(bEjCn*JZvw|`&0~-(;1A~6AABYD4 DQ=}TI diff --git a/assets/zips/correct-with-503.html.zip b/assets/zips/correct-with-503.html.zip index 5a66f25d7fbc22ecb0e2b7992bcf6df89caef088..a6cf06f195d0d2fe5019d3487a4a9ac2434e8ea0 100644 GIT binary patch literal 330 zcmWIWW@Zs#U|`^2kg0qfVYn~l8XJ(u0v2IlFf}mN%P7gsF*Y@L#>5bSq86xxfeAza z0Vfa_rxxYwmE`BjKFky9&eyfhCPPKoagobZzKv1nU873k7LIb#Z_-$$v%e;%fy8OO{J;LXkfat9OC zF$fEGBRP`=C@X+ufvJJ9UPcMj{AQ?gK{T5A#-;|(n80=z?n}AG1~dg^62uOWg-ej^ z0P%T|>?qF9O@)Ljs_VI zic;i=07WSbENNVhWIVAE3^N^M3UUm9_@Kyyfwzv_jEEp1GHMaw0x}voCP0x314|mi a(2XWOssp@PK{3m~3WS$|#vBG>1_l6plgZcs diff --git a/assets/zips/correct-without-404.html.zip b/assets/zips/correct-without-404.html.zip index 8c9eb8be92320173fce80861c9e37fb0aab61a0b..784228859c5f3c126fa28ff4abb9ee6eee27f5aa 100644 GIT binary patch delta 336 zcmX@Ifbr36MvVY(W)=|!1_llWnabA@YbN;Y2~-1emkTj)0jbQql++5njFQ}(%|FzG z)k2Wf0;L(4Km-tQ0&#I_QNCVDer^sk18zh4K??J8Q}xkIu4iNtVaDwakR2efq!C0S z^agmN>I2Cly9vYxfhCQVKwrUKh^}qT1V@CwK~98$C5?+f`cNGl;LXYgQosy^Yk;(Z HFNg;K{Ub)} delta 957 zcmaDfoAJm3#`*wnW)=|!5O~p>906uP2@VDYhUEOBqSWLP{m>9z2KLh4C#i5;!Og(P z@`9Ox0Zc$l;b7ok(CI1 zEetGabVD*0OGIOj=Kybn`Ji}3js{S?!oZTo{` v7GmPI2AEC|jt50Avg1L~3j<3U7o(d^d|U^3v$BBRfe0Yr1mfb literal 746 zcmWIWW@Zs#0D;pvNfBTMl;B`cU`Wm{DoRZ*(GLybWniDj_&9Yw5QFH_3T_5QmKV$n z3}7MvYzhYh2ZMfZB8n-3NTw907Uk=ej%uDNumJz>-Ec zBvXkFeq=`@hY`qFP;kS*TgT-r#05UW[a-zA-Z0-9-]+)\.${DOMAIN}\.${ZONE}${DOLLAR} $subdomain; +} + server { listen 80; - server_name ~^(?\w*)\.${DOMAIN}.${ZONE}${DOLLAR}; + server_name ~^(?[a-zA-Z0-9-]+)\.${DOMAIN}\.${ZONE}${DOLLAR}; location / { - # Always set the X-subdomain header with the value from the subdomain in the URL - proxy_set_header x-subdomain $subdomain; - proxy_pass http://${SERVER}:${SERVER_PORT}/; + proxy_set_header X-Subdomain $subdomain; + proxy_pass http://${SERVER}:${SERVER_PORT}; + } +} + +server { + listen 80; + server_name ${DOMAIN}.${ZONE}; + + location / { + proxy_pass http://${SERVER}:${SERVER_PORT}; } } diff --git a/openapi.json b/openapi.json index cd00ae7..551cefd 100644 --- a/openapi.json +++ b/openapi.json @@ -1,1219 +1,1219 @@ { - "openapi": "3.0.3", - "info": { - "title": "sero", - "description": "Muiltidomain static site hosting", - "contact": { - "name": "clowzed", - "email": "clowzed.work@gmail.com" - }, - "license": { - "name": "MIT" - }, - "version": "0.2.5" - }, - "paths": { - "/api/auth/login": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Login user and receive JWT token.", - "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", - "operationId": "Login", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully authenticated.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Login was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/auth/registration": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Register new user for sero server.", - "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", - "operationId": "Registration", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "409": { - "description": "Login has already been registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/origin": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Origins were successfully retrieved for subdomain.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListOriginsResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Create origin", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginRequest" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "The origin was successfully added.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Origins were successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/origin/{id}": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to retrieve", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "Origin was successfully retrieved.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Origin was successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The origin is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site": { - "get": { - "tags": [ - "Actions" - ], - "summary": "Download site of the specified subdomain.", - "description": "Returns a zip file which was uploaded by user (last)", - "operationId": "Download site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Site was successfully downloaded", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Actions" - ], - "summary": "Uploads site for a specified subdomain.", - "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", - "operationId": "Upload site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadData" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Site was successfully uploaded" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Actions" - ], - "summary": "Removes a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", - "operationId": "Teardown site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully removed." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/disable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Disables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", - "operationId": "Disable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully disabled." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/enable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Enables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", - "operationId": "Enable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully enabled" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - } - }, - "components": { - "schemas": { - "AddOriginRequest": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "type": "string", - "description": "Origin to be added" - } - }, - "example": { - "origin": "https://example.com/" - } - }, - "AddOriginResponse": { - "type": "object", - "required": [ - "id", - "origin" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Automatically generated id for new origin\nThis can be used for further management" - }, - "origin": { - "type": "string", - "description": "This duplicates origin from response payload\nto match REST specification" - } - }, - "example": { - "id": "42", - "origin": "https://example.com/" - } - }, - "Details": { - "type": "object", - "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", - "required": [ - "reason" - ], - "properties": { - "reason": { - "type": "string", - "description": "This field will contain error information" - } - } - }, - "GetOriginResponse": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "$ref": "#/components/schemas/OriginModel" - } - }, - "example": { - "origin": { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - } - }, - "ListOriginsResponse": { - "type": "object", - "required": [ - "origins" - ], - "properties": { - "origins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OriginModel" - }, - "description": "List of retrieved origins" - } - }, - "example": { - "origins": [ - { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - ] - } - }, - "LoginRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "LoginResponse": { - "type": "object", - "description": "The JWT token generated for authentication purposes.", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "Token in JWT format" - } - }, - "example": { - "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" - } - }, - "OriginModel": { - "type": "object", - "required": [ - "id", - "subdomain_id", - "value" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "subdomain_id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "string" - } - } - }, - "RegistrationRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- It can contain letters (a-z), numbers (0-9), and periods (.).\n- It cannot contain any of the following characters: & = ' - + , < >\n- It cannot have multiple periods (.) consecutively.\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.\n- A combination of letters, numbers, and symbols.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "RegistrationResponse": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Auto generated id of a registered user" - } - }, - "example": { - "id": 1293983717 - } - }, - "UploadData": { - "type": "object", - "required": [ - "archive" - ], - "properties": { - "archive": { - "type": "string", - "format": "binary" - } - } - } - }, - "securitySchemes": { - "Bearer-JWT": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } + "openapi": "3.0.3", + "info": { + "title": "sero", + "description": "Muiltidomain static site hosting", + "contact": { + "name": "clowzed", + "email": "clowzed.work@gmail.com" + }, + "license": { + "name": "MIT" + }, + "version": "0.2.6" + }, + "paths": { + "/api/auth/login": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Login user and receive JWT token.", + "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", + "operationId": "Login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Login was not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/auth/registration": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Register new user for sero server.", + "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", + "operationId": "Registration", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "409": { + "description": "Login has already been registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/origin": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Origins were successfully retrieved for subdomain.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOriginsResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Create origin", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The origin was successfully added.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Origins were successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/origin/{id}": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to retrieve", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Origin was successfully retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Origin was successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The origin is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site": { + "get": { + "tags": [ + "Actions" + ], + "summary": "Download site of the specified subdomain.", + "description": "Returns a zip file which was uploaded by user (last)", + "operationId": "Download site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Site was successfully downloaded", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Actions" + ], + "summary": "Uploads site for a specified subdomain.", + "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", + "operationId": "Upload site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadData" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Site was successfully uploaded" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Actions" + ], + "summary": "Removes a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", + "operationId": "Teardown site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully removed." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/disable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Disables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", + "operationId": "Disable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully disabled." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/enable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Enables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", + "operationId": "Enable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully enabled" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + } + }, + "components": { + "schemas": { + "AddOriginRequest": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "Origin to be added" + } + }, + "example": { + "origin": "https://example.com/" + } + }, + "AddOriginResponse": { + "type": "object", + "required": [ + "id", + "origin" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Automatically generated id for new origin\nThis can be used for further management" + }, + "origin": { + "type": "string", + "description": "This duplicates origin from response payload\nto match REST specification" + } + }, + "example": { + "id": "42", + "origin": "https://example.com/" + } + }, + "Details": { + "type": "object", + "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "description": "This field will contain error information" + } + } + }, + "GetOriginResponse": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "$ref": "#/components/schemas/OriginModel" + } + }, + "example": { + "origin": { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + } + }, + "ListOriginsResponse": { + "type": "object", + "required": [ + "origins" + ], + "properties": { + "origins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OriginModel" + }, + "description": "List of retrieved origins" + } + }, + "example": { + "origins": [ + { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + ] + } + }, + "LoginRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "LoginResponse": { + "type": "object", + "description": "The JWT token generated for authentication purposes.", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "Token in JWT format" + } + }, + "example": { + "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" + } + }, + "OriginModel": { + "type": "object", + "required": [ + "id", + "subdomain_id", + "value" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "subdomain_id": { + "type": "integer", + "format": "int64" + }, + "value": { + "type": "string" + } + } + }, + "RegistrationRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "RegistrationResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Auto generated id of a registered user" + } + }, + "example": { + "id": 1293983717 + } + }, + "UploadData": { + "type": "object", + "required": [ + "archive" + ], + "properties": { + "archive": { + "type": "string", + "format": "binary" + } + } + } + }, + "securitySchemes": { + "Bearer-JWT": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } } diff --git a/src/api/auth/login/error.rs b/src/api/auth/login/error.rs index 28fb312..e638c8a 100644 --- a/src/api/auth/login/error.rs +++ b/src/api/auth/login/error.rs @@ -27,7 +27,7 @@ impl IntoResponse for LoginError { fn into_response(self) -> Response { let reason = self.to_string(); let status_code: StatusCode = self.into(); - + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/auth/login/request.rs b/src/api/auth/login/request.rs index 3e8064e..ea7e6da 100644 --- a/src/api/auth/login/request.rs +++ b/src/api/auth/login/request.rs @@ -1,25 +1,15 @@ -use std::fmt::{self, Debug}; - use serde::{Deserialize, Serialize}; +use std::fmt::{self, Debug}; use utoipa::{schema, ToSchema}; -use validator::{Validate, ValidationError}; +use validator::Validate; #[derive(Deserialize, Serialize, Validate, ToSchema)] pub struct LoginRequest { /// The username used for authentication. /// It must adhere to the following criteria: - /// - It can contain letters (a-z), numbers (0-9), and periods (.). - /// - It cannot contain any of the following characters: & = ' - + , < > - /// - It cannot have multiple periods (.) consecutively. /// - Minimum length of 5 characters. /// - Maximum length of 40 characters. - #[validate( - length(min = 5, max = 40), - custom( - function = validate_login, - message = "Login can contain letters (a-z), numbers (0-9), and periods (.), - and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)" - ))] + #[validate(length(min = 5, max = 40))] #[schema(min_length = 5, max_length = 40)] pub login: String, @@ -27,53 +17,11 @@ pub struct LoginRequest { /// It must meet the following requirements: /// - Minimum length of 12 characters. /// - Maximum length of 40 characters. - /// - A combination of letters, numbers, and symbols. - #[validate( - length(min = 12, max = 40), - custom(function = validate_password, - message = "Minimum length of 12 characters and maximum length of 40 characters and a combination of - letters, numbers, and symbols.") - )] + #[validate(length(min = 12, max = 40))] #[schema(min_length = 12, max_length = 40)] pub password: String, } -fn validate_login(login: &str) -> Result<(), ValidationError> { - let invalid_chars = "&='+,<>"; - let invalid_double_period = ".."; - - if login.chars().any(|c| invalid_chars.contains(c)) || login.contains(invalid_double_period) { - return Err(ValidationError::new( - "Rules for login: Login can contain letters (a-z), numbers (0-9), and periods (.), - and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)", - )); - } - - Ok(()) -} - -fn validate_password(password: &str) -> Result<(), ValidationError> { - let mut has_digit = false; - let mut has_special_char = false; - - for c in password.chars() { - if !has_digit && c.is_ascii_digit() { - has_digit = true; - } else if c.is_ascii_punctuation() || c.is_ascii_whitespace() { - has_special_char = true; - } - - if has_digit && has_special_char { - return Ok(()); - } - } - - Err(ValidationError::new( - "Rules for password: Minimum length of 12 characters and maximum length of 40 characters and a combination of - letters, numbers, and symbols.", - )) -} - impl Debug for LoginRequest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LoginRequest") diff --git a/src/api/auth/registration/error.rs b/src/api/auth/registration/error.rs index 4518139..f7d5ad9 100644 --- a/src/api/auth/registration/error.rs +++ b/src/api/auth/registration/error.rs @@ -32,6 +32,7 @@ impl IntoResponse for RegistrationError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/auth/registration/request.rs b/src/api/auth/registration/request.rs index a5ed8f2..e63ea53 100644 --- a/src/api/auth/registration/request.rs +++ b/src/api/auth/registration/request.rs @@ -1,25 +1,15 @@ -use std::fmt::{self, Debug}; - use serde::{Deserialize, Serialize}; +use std::fmt::{self, Debug}; use utoipa::{schema, ToSchema}; -use validator::{Validate, ValidationError}; +use validator::Validate; #[derive(Deserialize, Serialize, Validate, ToSchema)] pub struct RegistrationRequest { /// The username used for authentication. /// It must adhere to the following criteria: - /// - It can contain letters (a-z), numbers (0-9), and periods (.). - /// - It cannot contain any of the following characters: & = ' - + , < > - /// - It cannot have multiple periods (.) consecutively. /// - Minimum length of 5 characters. /// - Maximum length of 40 characters. - #[validate( - length(min = 5, max = 40), - custom( - function = validate_login, - message = "Login can contain letters (a-z), numbers (0-9), and periods (.), - and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)" - ))] + #[validate(length(min = 5, max = 40))] #[schema(min_length = 5, max_length = 40)] pub login: String, @@ -27,53 +17,11 @@ pub struct RegistrationRequest { /// It must meet the following requirements: /// - Minimum length of 12 characters. /// - Maximum length of 40 characters. - /// - A combination of letters, numbers, and symbols. - #[validate( - length(min = 12, max = 40), - custom(function = validate_password, - message = "Minimum length of 12 characters and maximum length of 40 characters and a combination of - letters, numbers, and symbols.") - )] + #[validate(length(min = 12, max = 40))] #[schema(min_length = 12, max_length = 40)] pub password: String, } -fn validate_login(login: &str) -> Result<(), ValidationError> { - let invalid_chars = "&='+,<>"; - let invalid_double_period = ".."; - - if login.chars().any(|c| invalid_chars.contains(c)) || login.contains(invalid_double_period) { - return Err(ValidationError::new( - "Rules for login: Login can contain letters (a-z), numbers (0-9), and periods (.), - and cannot contain any of the following characters: & = ' + , < > or multiple periods (.)", - )); - } - - Ok(()) -} - -fn validate_password(password: &str) -> Result<(), ValidationError> { - let mut has_digit = false; - let mut has_special_char = false; - - for c in password.chars() { - if !has_digit && c.is_ascii_digit() { - has_digit = true; - } else if c.is_ascii_punctuation() || c.is_ascii_whitespace() { - has_special_char = true; - } - - if has_digit && has_special_char { - return Ok(()); - } - } - - Err(ValidationError::new( - "Rules for password: Minimum length of 12 characters and maximum length of 40 characters and a combination of - letters, numbers, and symbols.", - )) -} - impl Debug for RegistrationRequest { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("RegistrationRequest") diff --git a/src/api/origin/create/error.rs b/src/api/origin/create/error.rs index 4c1654c..8d4ace7 100644 --- a/src/api/origin/create/error.rs +++ b/src/api/origin/create/error.rs @@ -24,6 +24,7 @@ impl IntoResponse for AddOriginError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/origin/delete/error.rs b/src/api/origin/delete/error.rs index e436ff3..24b1a7d 100644 --- a/src/api/origin/delete/error.rs +++ b/src/api/origin/delete/error.rs @@ -28,6 +28,7 @@ impl IntoResponse for DeleteOriginError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/origin/list/error.rs b/src/api/origin/list/error.rs index 8aedb45..850bf8b 100644 --- a/src/api/origin/list/error.rs +++ b/src/api/origin/list/error.rs @@ -24,6 +24,7 @@ impl IntoResponse for ListOriginsError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/origin/purge/error.rs b/src/api/origin/purge/error.rs index 6bd6f62..3d92d06 100644 --- a/src/api/origin/purge/error.rs +++ b/src/api/origin/purge/error.rs @@ -24,6 +24,7 @@ impl IntoResponse for DeleteOriginsError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/origin/retrieve/error.rs b/src/api/origin/retrieve/error.rs index 0a5d730..b807ef4 100644 --- a/src/api/origin/retrieve/error.rs +++ b/src/api/origin/retrieve/error.rs @@ -24,6 +24,7 @@ impl IntoResponse for GetOriginError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/site/disable/error.rs b/src/api/site/disable/error.rs index 058cd28..00b4d3b 100644 --- a/src/api/site/disable/error.rs +++ b/src/api/site/disable/error.rs @@ -27,6 +27,7 @@ impl IntoResponse for DisableError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/site/download/error.rs b/src/api/site/download/error.rs index 2acb2d6..68c03d2 100644 --- a/src/api/site/download/error.rs +++ b/src/api/site/download/error.rs @@ -32,6 +32,7 @@ impl IntoResponse for DownloadError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/site/enable/error.rs b/src/api/site/enable/error.rs index 4c32ed4..76b3f9d 100644 --- a/src/api/site/enable/error.rs +++ b/src/api/site/enable/error.rs @@ -28,6 +28,7 @@ impl IntoResponse for EnableError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/site/page/error.rs b/src/api/site/page/error.rs index e2dfa3e..9c491cf 100644 --- a/src/api/site/page/error.rs +++ b/src/api/site/page/error.rs @@ -28,6 +28,7 @@ impl IntoResponse for PageError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/site/teardown/error.rs b/src/api/site/teardown/error.rs index c754e8a..d55e5a3 100644 --- a/src/api/site/teardown/error.rs +++ b/src/api/site/teardown/error.rs @@ -28,6 +28,7 @@ impl IntoResponse for TeardownError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/api/site/upload/error.rs b/src/api/site/upload/error.rs index 62d9273..8feb853 100644 --- a/src/api/site/upload/error.rs +++ b/src/api/site/upload/error.rs @@ -34,6 +34,7 @@ impl IntoResponse for UploadError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/extractors/auth.rs b/src/extractors/auth.rs index 79d97c3..15184d0 100644 --- a/src/extractors/auth.rs +++ b/src/extractors/auth.rs @@ -61,6 +61,7 @@ impl IntoResponse for AuthError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/extractors/guards/upload.rs b/src/extractors/guards/upload.rs index b2dee44..364d8e1 100644 --- a/src/extractors/guards/upload.rs +++ b/src/extractors/guards/upload.rs @@ -49,6 +49,7 @@ impl IntoResponse for GuardError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/extractors/subdomain.rs b/src/extractors/subdomain.rs index 917cd2c..780876e 100644 --- a/src/extractors/subdomain.rs +++ b/src/extractors/subdomain.rs @@ -41,6 +41,7 @@ impl IntoResponse for SubdomainError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/extractors/subdomain_name.rs b/src/extractors/subdomain_name.rs index b3621c2..b17324d 100644 --- a/src/extractors/subdomain_name.rs +++ b/src/extractors/subdomain_name.rs @@ -32,6 +32,7 @@ impl IntoResponse for SubdomainNameError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/extractors/subdomain_owned.rs b/src/extractors/subdomain_owned.rs index f6889b8..f55d951 100644 --- a/src/extractors/subdomain_owned.rs +++ b/src/extractors/subdomain_owned.rs @@ -41,6 +41,7 @@ impl IntoResponse for SubdomainOwnedError { let reason = self.to_string(); let status_code: StatusCode = self.into(); + tracing::error!(%reason, %status_code, "Error occurred while trying to handle request!"); (status_code, Json(Details { reason })).into_response() } } diff --git a/src/lib.rs b/src/lib.rs index da97b0e..3120d51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,10 +247,10 @@ pub async fn app() -> Result<(Router, Arc), AppCreationError> { let mut app = Router::new() .merge(openapi) - .nest("/api", api::router()) .route("/*path", get(api::site::page::handler::implementation)) .route("/", get(api::site::page::handler::redirect::implementation)) .layer(cors_layer) + .nest("/api", api::router()) .layer(tracing_layer) .layer(TimeoutLayer::new(Duration::from_secs(10))) .with_state(state.clone()); diff --git a/src/services/archive/service.rs b/src/services/archive/service.rs index da255f1..70c8aa0 100644 --- a/src/services/archive/service.rs +++ b/src/services/archive/service.rs @@ -44,11 +44,11 @@ impl Service { .filename() .as_str() .inspect_err(|cause| tracing::warn!(%cause, "Failed to convert entry filepath to str"))?; - PathBuf::from(entry_filename).components().skip(1).collect::() + PathBuf::from(entry_filename) }; tracing::trace!(?path, "Entry filepath was successfully retrieved"); - //? Generating filename for entry + //? Generating filename for enty // Just random to prevent collisions let u1 = Uuid::new_v4(); let u2 = Uuid::new_v4(); From 7214330e5385fea5c2db03263423f2433a2304dc Mon Sep 17 00:00:00 2001 From: Dmitry Miasnenko Date: Tue, 6 Aug 2024 04:02:44 +0300 Subject: [PATCH 7/9] readme-fix: remove warning about cli tool. Update version in docker-compose.yml to match. (#25) --- Cargo.toml | 2 +- docker-compose.yml | 4 +--- openapi.json | 2 +- readme.md | 31 ++++++++++++------------------- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0c740b0..29a6dda 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.6" +version = "0.2.7" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" diff --git a/docker-compose.yml b/docker-compose.yml index 21cee03..8c1be93 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -39,15 +39,13 @@ services: - server server: - image: clowzed/sero + image: clowzed/sero:v0.2.7 build: . depends_on: database: condition: service_healthy volumes: - server-files:/app/sites-uploads - ports: - - 8080:8080 environment: - DATABASE_URL=postgresql://postgres:1234@database/sero - PORT=8080 diff --git a/openapi.json b/openapi.json index 551cefd..8c00c2b 100644 --- a/openapi.json +++ b/openapi.json @@ -10,7 +10,7 @@ "license": { "name": "MIT" }, - "version": "0.2.6" + "version": "0.2.7" }, "paths": { "/api/auth/login": { diff --git a/readme.md b/readme.md index 9c4ed94..dacf155 100644 --- a/readme.md +++ b/readme.md @@ -21,31 +21,24 @@

-# Warning - -> [!CAUTION] -> -> **_This project was in a huge rewrite and upload tool and docs are not updated! -> THis will be fixed very soon._** - ## 📖 Table Of Contents -- [Warning!](#warning) - - [📖 Table Of Contents](#-table-of-contents) - - [Docs](#docs) - - [🔧 Tools](#-tools) - - [❓ About The Project](#-about-the-project) - - [🚀 Features](#-features) - - [🔌 Built With](#-built-with) - - [📍 Roadmap](#-roadmap) - - [🧑‍🤝‍🧑 Contributing](#-contributing) +- [📖 Table Of Contents](#-table-of-contents) +- [Docs](#docs) +- [🔧 Tools](#-tools) +- [❓ About The Project](#-about-the-project) +- [🚀 Features](#-features) +- [🔌 Built With](#-built-with) +- [📍 Roadmap](#-roadmap) +- [🧑‍🤝‍🧑 Contributing](#-contributing) - [Creating A Pull Request](#creating-a-pull-request) - - [License](#license) - - [Authors](#authors) +- [License](#license) +- [Authors](#authors) ## Docs -Read [docs here]("http://sero-docs.clowzed.ru") for fast installation. +In progress... +~~Read [docs here]("http://sero-docs.clowzed.ru") for fast installation.~~ ## 🔧 Tools From 782d8e4b0524361b84d7a417af9c520dc72b287d Mon Sep 17 00:00:00 2001 From: Dmitry Miasnenko Date: Fri, 4 Oct 2024 15:59:59 +0300 Subject: [PATCH 8/9] Update readme. Remove openapi.json and adjust workflows. (#26) * readme-fix: remove warning about cli tool. Update version in docker-compose.yml to match. * Updated readme.md. Fully remove openapi.json. Remove version cmp beteen Cargo.toml and openapi.json. Added openapi.josn to gitignore. --- .github/workflows/dev.yml | 2 +- .github/workflows/test.yml | 18 - .gitignore | 1 + Cargo.toml | 38 +- openapi.json | 2434 ++++++++++++++++++------------------ readme.md | 4 +- 6 files changed, 1240 insertions(+), 1257 deletions(-) diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 7b64b15..af04248 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -3,7 +3,7 @@ name: "Test" on: push: branches: - - "dev" # matches every branch + - "dev" jobs: push-to-registry: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 894068a..2a2e902 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,24 +46,6 @@ jobs: steps: - uses: actions/checkout@v3 - - name: "Get version from Cargo.toml" - id: "get-cargo-version" - shell: "bash" - run: | - echo PKG_VERSION=$(awk -F ' = ' '$1 ~ /version/ { gsub(/["]/, "", $2); printf("%s",$2) }' Cargo.toml) >> $GITHUB_OUTPUT - - name: Get version from openapi.json - id: get-openapi-version - run: | - echo OAPI_VERSION=$(jq -r '.info.version' openapi.json) >> $GITHUB_OUTPUT - - - name: Compare versions - run: | - if [ "${{ steps.get-cargo-version.outputs.PKG_VERSION }}" != "${{ steps.get-openapi-version.outputs.OAPI_VERSION }}" ]; then - echo "Version mismatch between cargo.toml and generated OpenAPI JSON." - exit 1 - else - echo "Version matches between cargo.toml and generated OpenAPI JSON." - fi - name: Run tests (with database service) run: cargo test --verbose -- --test-threads=1 diff --git a/.gitignore b/.gitignore index 3337113..99dc2ec 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ sites-uploads logs test_upload_files .env +openapi.json diff --git a/Cargo.toml b/Cargo.toml index 29a6dda..80b0906 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sero" -version = "0.2.7" +version = "0.2.8" edition = "2021" authors = ["clowzed "] description = "Muiltidomain static site hosting" @@ -11,19 +11,19 @@ license = "MIT" [dependencies] envy = "0.4.2" sea-orm = { version = "0.12.3", features = [ - "sqlx-postgres", - "runtime-tokio-rustls", - "macros", + "sqlx-postgres", + "runtime-tokio-rustls", + "macros", ] } tokio = { version = "1.32.0", features = ["full"] } tokio-postgres = "0.7.10" tracing = { version = "0.1.37", features = ["async-await"] } tracing-subscriber = { version = "0.3.17", features = [ - "env-filter", - "fmt", - "ansi", - "std", - "json", + "env-filter", + "fmt", + "ansi", + "std", + "json", ] } entity = { path = "entity" } migration = { path = "migration" } @@ -41,9 +41,9 @@ mime = "0.3.17" mime_guess = "2.0.4" argon2 = { version = "0.5.3", features = ["std"] } utoipa = { version = "4.2.0", features = [ - "axum_extras", - "chrono", - "preserve_order", + "axum_extras", + "chrono", + "preserve_order", ] } dotenvy = "0.15.7" toml = "0.8.8" @@ -52,16 +52,16 @@ utoipa-rapidoc = { version = "4.0.0", features = ["axum"] } utoipa-redoc = { version = "4.0.0", features = ["axum"] } utoipa-swagger-ui = { version = "7.1.0", features = ["axum"] } axum = { version = "0.7.4", features = [ - "macros", - "tracing", - "json", - "multipart", + "macros", + "tracing", + "json", + "multipart", ] } axum_typed_multipart = "0.11.0" tower-http = { git = "https://github.com/tower-rs/tower-http.git", features = [ - "cors", - "trace", - "timeout", + "cors", + "trace", + "timeout", ] } tower = { version = "0.4.13", features = ["util"] } hyper = "0.14.28" diff --git a/openapi.json b/openapi.json index 8c00c2b..27f35d2 100644 --- a/openapi.json +++ b/openapi.json @@ -1,1219 +1,1219 @@ { - "openapi": "3.0.3", - "info": { - "title": "sero", - "description": "Muiltidomain static site hosting", - "contact": { - "name": "clowzed", - "email": "clowzed.work@gmail.com" - }, - "license": { - "name": "MIT" - }, - "version": "0.2.7" - }, - "paths": { - "/api/auth/login": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Login user and receive JWT token.", - "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", - "operationId": "Login", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully authenticated.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Login was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/auth/registration": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Register new user for sero server.", - "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", - "operationId": "Registration", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "409": { - "description": "Login has already been registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/origin": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Origins were successfully retrieved for subdomain.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListOriginsResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Create origin", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginRequest" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "The origin was successfully added.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Origins were successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/origin/{id}": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to retrieve", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "Origin was successfully retrieved.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Origin was successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The origin is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site": { - "get": { - "tags": [ - "Actions" - ], - "summary": "Download site of the specified subdomain.", - "description": "Returns a zip file which was uploaded by user (last)", - "operationId": "Download site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Site was successfully downloaded", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Actions" - ], - "summary": "Uploads site for a specified subdomain.", - "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", - "operationId": "Upload site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadData" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Site was successfully uploaded" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Actions" - ], - "summary": "Removes a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", - "operationId": "Teardown site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully removed." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/disable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Disables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", - "operationId": "Disable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully disabled." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/enable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Enables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", - "operationId": "Enable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully enabled" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - } - }, - "components": { - "schemas": { - "AddOriginRequest": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "type": "string", - "description": "Origin to be added" - } - }, - "example": { - "origin": "https://example.com/" - } - }, - "AddOriginResponse": { - "type": "object", - "required": [ - "id", - "origin" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Automatically generated id for new origin\nThis can be used for further management" - }, - "origin": { - "type": "string", - "description": "This duplicates origin from response payload\nto match REST specification" - } - }, - "example": { - "id": "42", - "origin": "https://example.com/" - } - }, - "Details": { - "type": "object", - "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", - "required": [ - "reason" - ], - "properties": { - "reason": { - "type": "string", - "description": "This field will contain error information" - } - } - }, - "GetOriginResponse": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "$ref": "#/components/schemas/OriginModel" - } - }, - "example": { - "origin": { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - } - }, - "ListOriginsResponse": { - "type": "object", - "required": [ - "origins" - ], - "properties": { - "origins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OriginModel" - }, - "description": "List of retrieved origins" - } - }, - "example": { - "origins": [ - { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - ] - } - }, - "LoginRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "LoginResponse": { - "type": "object", - "description": "The JWT token generated for authentication purposes.", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "Token in JWT format" - } - }, - "example": { - "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" - } - }, - "OriginModel": { - "type": "object", - "required": [ - "id", - "subdomain_id", - "value" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "subdomain_id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "string" - } - } - }, - "RegistrationRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "RegistrationResponse": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Auto generated id of a registered user" - } - }, - "example": { - "id": 1293983717 - } - }, - "UploadData": { - "type": "object", - "required": [ - "archive" - ], - "properties": { - "archive": { - "type": "string", - "format": "binary" - } - } - } - }, - "securitySchemes": { - "Bearer-JWT": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } + "openapi": "3.0.3", + "info": { + "title": "sero", + "description": "Muiltidomain static site hosting", + "contact": { + "name": "clowzed", + "email": "clowzed.work@gmail.com" + }, + "license": { + "name": "MIT" + }, + "version": "0.2.7" + }, + "paths": { + "/api/auth/login": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Login user and receive JWT token.", + "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", + "operationId": "Login", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully authenticated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Login was not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/auth/registration": { + "post": { + "tags": [ + "Account management" + ], + "summary": "Register new user for sero server.", + "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", + "operationId": "Registration", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User was successfully registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegistrationResponse" + } + } + } + }, + "400": { + "description": "Bad request or bad credentials. See details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "409": { + "description": "Login has already been registered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Some error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + } + } + }, + "/api/origin": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "201": { + "description": "Origins were successfully retrieved for subdomain.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListOriginsResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Create origin", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginRequest" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "The origin was successfully added.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete all origins", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Origins were successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/origin/{id}": { + "get": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Get origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to retrieve", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "Origin was successfully retrieved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetOriginResponse" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Origins Management and Dynamic Access Control" + ], + "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", + "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", + "operationId": "Delete origin by id", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "id", + "in": "path", + "description": "Id of the origin to delete", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "204": { + "description": "Origin was successfully deleted for subdomain." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The origin is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site": { + "get": { + "tags": [ + "Actions" + ], + "summary": "Download site of the specified subdomain.", + "description": "Returns a zip file which was uploaded by user (last)", + "operationId": "Download site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Site was successfully downloaded", + "content": { + "application/octet-stream": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "post": { + "tags": [ + "Actions" + ], + "summary": "Uploads site for a specified subdomain.", + "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", + "operationId": "Upload site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadData" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Site was successfully uploaded" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + }, + "delete": { + "tags": [ + "Actions" + ], + "summary": "Removes a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", + "operationId": "Teardown site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully removed." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/disable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Disables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", + "operationId": "Disable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully disabled." + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + }, + "/api/site/enable": { + "patch": { + "tags": [ + "Actions" + ], + "summary": "Enables a specific site identified by the `x-subdomain` header.", + "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", + "operationId": "Enable site", + "parameters": [ + { + "name": "x-subdomain", + "in": "header", + "description": "x-subdomain header represents name of subdomain to call action on", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Site was successfully enabled" + }, + "400": { + "description": "The 'x-subdomain' header is missing or contains invalid characters.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "401": { + "description": "Unauthorized: The JWT in the header is invalid or expired.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "403": { + "description": "Forbidden: The subdomain is owned by another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "404": { + "description": "Not Found: The login or subdomain was not found. See details for more information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + }, + "500": { + "description": "Internal Server Error: An error occurred on the server.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Details" + } + } + } + } + }, + "security": [ + { + "Bearer-JWT": [] + } + ] + } + } + }, + "components": { + "schemas": { + "AddOriginRequest": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "type": "string", + "description": "Origin to be added" + } + }, + "example": { + "origin": "https://example.com/" + } + }, + "AddOriginResponse": { + "type": "object", + "required": [ + "id", + "origin" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Automatically generated id for new origin\nThis can be used for further management" + }, + "origin": { + "type": "string", + "description": "This duplicates origin from response payload\nto match REST specification" + } + }, + "example": { + "id": "42", + "origin": "https://example.com/" + } + }, + "Details": { + "type": "object", + "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", + "required": [ + "reason" + ], + "properties": { + "reason": { + "type": "string", + "description": "This field will contain error information" + } + } + }, + "GetOriginResponse": { + "type": "object", + "required": [ + "origin" + ], + "properties": { + "origin": { + "$ref": "#/components/schemas/OriginModel" + } + }, + "example": { + "origin": { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + } + }, + "ListOriginsResponse": { + "type": "object", + "required": [ + "origins" + ], + "properties": { + "origins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OriginModel" + }, + "description": "List of retrieved origins" + } + }, + "example": { + "origins": [ + { + "id": 42, + "subdomain_id": 1, + "value": "https://example.com" + } + ] + } + }, + "LoginRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "LoginResponse": { + "type": "object", + "description": "The JWT token generated for authentication purposes.", + "required": [ + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "Token in JWT format" + } + }, + "example": { + "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" + } + }, + "OriginModel": { + "type": "object", + "required": [ + "id", + "subdomain_id", + "value" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "subdomain_id": { + "type": "integer", + "format": "int64" + }, + "value": { + "type": "string" + } + } + }, + "RegistrationRequest": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "type": "string", + "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 5 + }, + "password": { + "type": "string", + "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", + "maxLength": 40, + "minLength": 12 + } + } + }, + "RegistrationResponse": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "Auto generated id of a registered user" + } + }, + "example": { + "id": 1293983717 + } + }, + "UploadData": { + "type": "object", + "required": [ + "archive" + ], + "properties": { + "archive": { + "type": "string", + "format": "binary" + } + } + } + }, + "securitySchemes": { + "Bearer-JWT": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } } diff --git a/readme.md b/readme.md index dacf155..240f6b8 100644 --- a/readme.md +++ b/readme.md @@ -31,7 +31,7 @@ - [🔌 Built With](#-built-with) - [📍 Roadmap](#-roadmap) - [🧑‍🤝‍🧑 Contributing](#-contributing) - - [Creating A Pull Request](#creating-a-pull-request) + - [Creating A Pull Request](#creating-a-pull-request) - [License](#license) - [Authors](#authors) @@ -63,7 +63,7 @@ One key feature that it is self-hosted. This gives users more flexibility and co - Custom 503.html `new` `(on disabled site)` - Clean urls - Dynamic CORS Management -- `[WIP]` Server events with websocket +- `[WIP]` SSE ## 🔌 Built With From 466dd6b3f0f677c969f025f139d9e4e182b8e07d Mon Sep 17 00:00:00 2001 From: Dmitry Miasnenko Date: Fri, 4 Oct 2024 16:24:02 +0300 Subject: [PATCH 9/9] Fix 1 commit behind (#27) * readme-fix: remove warning about cli tool. Update version in docker-compose.yml to match. * Updated readme.md. Fully remove openapi.json. Remove version cmp beteen Cargo.toml and openapi.json. Added openapi.josn to gitignore. * Removed openapi.json * Update readme.md * Update readme.md --- openapi.json | 1219 -------------------------------------------------- readme.md | 3 +- 2 files changed, 1 insertion(+), 1221 deletions(-) delete mode 100644 openapi.json diff --git a/openapi.json b/openapi.json deleted file mode 100644 index 27f35d2..0000000 --- a/openapi.json +++ /dev/null @@ -1,1219 +0,0 @@ -{ - "openapi": "3.0.3", - "info": { - "title": "sero", - "description": "Muiltidomain static site hosting", - "contact": { - "name": "clowzed", - "email": "clowzed.work@gmail.com" - }, - "license": { - "name": "MIT" - }, - "version": "0.2.7" - }, - "paths": { - "/api/auth/login": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Login user and receive JWT token.", - "description": "This endpoint allows users to login to sero server. The TTL for token is set by\nthe owner of the server by `JWT_TTL` env.", - "operationId": "Login", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully authenticated.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Login was not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/auth/registration": { - "post": { - "tags": [ - "Account management" - ], - "summary": "Register new user for sero server.", - "description": "This endpoint creates new user for sero server. The amount of users is checked\nby [RegistrationGuard]. The amount of allowed users is determined by `MAX_USERS` env.", - "operationId": "Registration", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "User was successfully registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegistrationResponse" - } - } - } - }, - "400": { - "description": "Bad request or bad credentials. See details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "409": { - "description": "Login has already been registered.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Some error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - } - } - }, - "/api/origin": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "List all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to list all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "201": { - "description": "Origins were successfully retrieved for subdomain.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ListOriginsResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Adds a new origin to a specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to add origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Create origin", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginRequest" - } - } - }, - "required": true - }, - "responses": { - "201": { - "description": "The origin was successfully added.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete all origins for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete all origins that are permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete all origins", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Origins were successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/origin/{id}": { - "get": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Get specified origin [by id] for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to get specified origin by id that is permitted to access resources\non specified subdomain. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Get origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to retrieve", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "Origin was successfully retrieved.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/GetOriginResponse" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Origins Management and Dynamic Access Control" - ], - "summary": "Delete origin by id for specified subdomain for dynamic CORS (Cross-Origin Resource Sharing) management.", - "description": "This endpoint allows users to delete origin by id that is permitted to access resources\non their specified subdomains. The action is authenticated using a JWT, and the subdomain must\nbe owned by the user making the request. This will be checked by the server.", - "operationId": "Delete origin by id", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "'x-subdomain' header represents the name of the subdomain on which the action is to be performed.", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "id", - "in": "path", - "description": "Id of the origin to delete", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "204": { - "description": "Origin was successfully deleted for subdomain." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The origin is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain or origin was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site": { - "get": { - "tags": [ - "Actions" - ], - "summary": "Download site of the specified subdomain.", - "description": "Returns a zip file which was uploaded by user (last)", - "operationId": "Download site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Site was successfully downloaded", - "content": { - "application/octet-stream": { - "schema": { - "type": "string" - } - } - } - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "post": { - "tags": [ - "Actions" - ], - "summary": "Uploads site for a specified subdomain.", - "description": "Warning: Old files will be removed after successful upload.\nThe cleanup task is configured with `CLEAN_OBSOLETE_INTERVAL` env\nIf upload fails then old files will be preserved.\nIf upload fails on th stage of extracting zips then\nnew subdomain will be associated with user\n\nUpload guard checks amount of uploads available for user.\nThe guard is configured with `MAX_SITES_PER_USER` env.", - "operationId": "Upload site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadData" - } - } - }, - "required": true - }, - "responses": { - "204": { - "description": "Site was successfully uploaded" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - }, - "delete": { - "tags": [ - "Actions" - ], - "summary": "Removes a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to remove a site associated with the specified subdomain.\nThe subdomain to be removed is specified in the `x-subdomain` header.", - "operationId": "Teardown site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully removed." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/disable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Disables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to disable a site associated with the specified subdomain.", - "operationId": "Disable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully disabled." - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - }, - "/api/site/enable": { - "patch": { - "tags": [ - "Actions" - ], - "summary": "Enables a specific site identified by the `x-subdomain` header.", - "description": "This endpoint allows authenticated users to enable a site associated with the specified subdomain.", - "operationId": "Enable site", - "parameters": [ - { - "name": "x-subdomain", - "in": "header", - "description": "x-subdomain header represents name of subdomain to call action on", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "204": { - "description": "Site was successfully enabled" - }, - "400": { - "description": "The 'x-subdomain' header is missing or contains invalid characters.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "401": { - "description": "Unauthorized: The JWT in the header is invalid or expired.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "403": { - "description": "Forbidden: The subdomain is owned by another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "404": { - "description": "Not Found: The login or subdomain was not found. See details for more information.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - }, - "500": { - "description": "Internal Server Error: An error occurred on the server.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Details" - } - } - } - } - }, - "security": [ - { - "Bearer-JWT": [] - } - ] - } - } - }, - "components": { - "schemas": { - "AddOriginRequest": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "type": "string", - "description": "Origin to be added" - } - }, - "example": { - "origin": "https://example.com/" - } - }, - "AddOriginResponse": { - "type": "object", - "required": [ - "id", - "origin" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Automatically generated id for new origin\nThis can be used for further management" - }, - "origin": { - "type": "string", - "description": "This duplicates origin from response payload\nto match REST specification" - } - }, - "example": { - "id": "42", - "origin": "https://example.com/" - } - }, - "Details": { - "type": "object", - "description": "This struct is a response of server in bad situation\nThat can be INTERNAL SERVER ERROR or BAD REQUEST\nYou can find all information in reason field", - "required": [ - "reason" - ], - "properties": { - "reason": { - "type": "string", - "description": "This field will contain error information" - } - } - }, - "GetOriginResponse": { - "type": "object", - "required": [ - "origin" - ], - "properties": { - "origin": { - "$ref": "#/components/schemas/OriginModel" - } - }, - "example": { - "origin": { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - } - }, - "ListOriginsResponse": { - "type": "object", - "required": [ - "origins" - ], - "properties": { - "origins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OriginModel" - }, - "description": "List of retrieved origins" - } - }, - "example": { - "origins": [ - { - "id": 42, - "subdomain_id": 1, - "value": "https://example.com" - } - ] - } - }, - "LoginRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "LoginResponse": { - "type": "object", - "description": "The JWT token generated for authentication purposes.", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "Token in JWT format" - } - }, - "example": { - "token": "ferwfwerfwer.fwerfwerfwerfwer.fwerfewfr" - } - }, - "OriginModel": { - "type": "object", - "required": [ - "id", - "subdomain_id", - "value" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "subdomain_id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "string" - } - } - }, - "RegistrationRequest": { - "type": "object", - "required": [ - "login", - "password" - ], - "properties": { - "login": { - "type": "string", - "description": "The username used for authentication.\nIt must adhere to the following criteria:\n- Minimum length of 5 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 5 - }, - "password": { - "type": "string", - "description": "The password used for authentication.\nIt must meet the following requirements:\n- Minimum length of 12 characters.\n- Maximum length of 40 characters.", - "maxLength": 40, - "minLength": 12 - } - } - }, - "RegistrationResponse": { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "Auto generated id of a registered user" - } - }, - "example": { - "id": 1293983717 - } - }, - "UploadData": { - "type": "object", - "required": [ - "archive" - ], - "properties": { - "archive": { - "type": "string", - "format": "binary" - } - } - } - }, - "securitySchemes": { - "Bearer-JWT": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } -} diff --git a/readme.md b/readme.md index 240f6b8..744c7de 100644 --- a/readme.md +++ b/readme.md @@ -37,8 +37,7 @@ ## Docs -In progress... -~~Read [docs here]("http://sero-docs.clowzed.ru") for fast installation.~~ +Read [docs here]("clowzed.github.io/sero-docs/") for fast installation. ## 🔧 Tools