diff --git a/Cargo.lock b/Cargo.lock
index fab4e3dd..db5989a4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -949,6 +949,12 @@ version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
+[[package]]
+name = "dtoa"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
+
[[package]]
name = "either"
version = "1.6.1"
@@ -1229,9 +1235,11 @@ dependencies = [
"sailfish",
"serde 1.0.125",
"serde_json",
+ "serde_yaml",
"sqlx",
"url",
"validator",
+ "yaml-rust",
]
[[package]]
@@ -2432,6 +2440,18 @@ dependencies = [
"serde 1.0.125",
]
+[[package]]
+name = "serde_yaml"
+version = "0.8.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23"
+dependencies = [
+ "dtoa",
+ "linked-hash-map",
+ "serde 1.0.125",
+ "yaml-rust",
+]
+
[[package]]
name = "sha-1"
version = "0.9.4"
diff --git a/Cargo.toml b/Cargo.toml
index da09f371..42ef51d4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,6 +44,7 @@ derive_more = "0.99"
serde = "1"
serde_json = "1"
+serde_yaml = "0.8"
url = "2.2"
@@ -58,3 +59,8 @@ m_captcha = { version = "0.1.2", git = "https://github.com/mCaptcha/mCaptcha" }
rand = "0.8"
sailfish = "0.3.2"
+
+[build-dependencies]
+serde_yaml = "0.8"
+serde_json = "1"
+yaml-rust = "0.4"
diff --git a/build.rs b/build.rs
index 22cd97d3..ee1a3459 100644
--- a/build.rs
+++ b/build.rs
@@ -16,6 +16,7 @@
*/
use std::process::Command;
+
fn main() {
// note: add error checking yourself.
let output = Command::new("git")
@@ -24,4 +25,11 @@ fn main() {
.unwrap();
let git_hash = String::from_utf8(output.stdout).unwrap();
println!("cargo:rustc-env=GIT_HASH={}", git_hash);
+
+ let yml = include_str!("./openapi.yaml");
+ let api_json: serde_json::Value = serde_yaml::from_str(yml).unwrap();
+ println!(
+ "cargo:rustc-env=OPEN_API_DOCS={}",
+ serde_json::to_string(&api_json).unwrap()
+ );
}
diff --git a/docs/index.html b/docs/index.html
index 5260c975..4116f441 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -39,7 +39,7 @@
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
- url: "/docs/swagger.json",
+ url: "/docs/openapi.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
diff --git a/docs/openapi.json b/docs/openapi.json
deleted file mode 100644
index c5570297..00000000
--- a/docs/openapi.json
+++ /dev/null
@@ -1,382 +0,0 @@
-{
- "openapi": "3.0.0",
- "info": {
- "version": "0.1.0",
- "title": "mCaptcha/guard"
- },
- "servers": [
- {
- "url": "/"
- }
- ],
- "paths": {
- "/api//signup": {
- "post": {
- "summary": "Registration endpoint",
- "operationId": "registerUser",
- "tags": ["user"],
- "requestBody": {
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/RegisterUser"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Successful registration"
- },
- "400": {
- "description": "Bad request: username contains profainity/blacklisted words or email not acceptable or password too long/short or duplicate username/password",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- },
- "500": {
- "description": "Internal server error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- }
- }
- }
- },
- "/api//signin": {
- "post": {
- "summary": "Login endpoint",
- "operationId": "loginUser",
- "tags": ["user", "authentication"],
- "requestBody": {
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/LoginUser"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "Successful authentication"
- },
- "401": {
- "description": "authentication failed, wrong password",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- },
- "404": {
- "description": "username not found",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- },
- "500": {
- "description": "Internal server error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- }
- }
- }
- },
- "/api//signout": {
- "post": {
- "security": [
- {
- "cookieAuth": []
- }
- ],
- "summary": "Signout endpoint",
- "operationId": "signoutUser",
- "tags": ["user", "authentication"],
- "responses": {
- "200": {
- "description": "OK"
- }
- }
- }
- },
- "/api//account/delete": {
- "post": {
- "security": [
- {
- "cookieAuth": []
- }
- ],
- "summary": "Delete user account",
- "operationId": "deleteUserAccount",
- "tags": ["user"],
- "requestBody": {
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/DeleteUser"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "OK"
- },
- "401": {
- "description": "(cookie)authentication required or wrong password",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- },
- "404": {
- "description": "username not found",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- },
- "500": {
- "description": "Internal server error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- }
- }
- }
- },
- "/api//account/username/exists": {
- "post": {
- "summary": "Check if username exists",
- "operationId": "usernameExists",
- "tags": ["user"],
- "requestBody": {
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UserDetailCheck"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UserDetailCheckRes"
- }
- }
- }
- },
- "500": {
- "description": "Internal server error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- }
- }
- }
- },
- "/api//account/email/exists": {
- "post": {
- "summary": "Check if email exists",
- "operationId": "emailExists",
- "tags": ["user"],
- "requestBody": {
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UserDetailCheck"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/UserDetailCheckRes"
- }
- }
- }
- },
- "500": {
- "description": "Internal server error",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/Error"
- }
- }
- }
- }
- }
- }
- },
- "/api//meta/build": {
- "post": {
- "summary": "Check if email exists",
- "operationId": "emailExists",
- "tags": ["user"],
- "responses": {
- "200": {
- "description": "OK",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/BuildDetails"
- }
- }
- }
- }
- }
- }
- },
- "components": {
- "schemas": {
- "RegisterUser": {
- "type": "object",
- "required": ["username", "password", "email"],
- "properties": {
- "username": {
- "type": "string"
- },
- "email": {
- "type": "string"
- },
- "password": {
- "type": "string",
- "format": "password"
- }
- }
- },
- "LoginUser": {
- "type": "object",
- "required": ["username", "password"],
- "properties": {
- "username": {
- "type": "string"
- },
- "password": {
- "type": "string",
- "format": "password"
- }
- }
- },
- "DeleteUser": {
- "type": "object",
- "required": ["password"],
- "properties": {
- "password": {
- "type": "string",
- "format": "password"
- }
- }
- },
- "Error": {
- "type": "object",
- "required": ["error"],
- "properties": {
- "error": {
- "type": "string"
- }
- }
- },
- "User": {
- "type": "object",
- "required": ["id", "name"],
- "properties": {
- "id": {
- "type": "integer",
- "format": "int64"
- },
- "name": {
- "type": "string"
- }
- }
- },
- "UserDetailCheck": {
- "type": "object",
- "required": ["val"],
- "properties": {
- "val": {
- "type": "string"
- }
- }
- },
- "UserDetailCheckRes": {
- "type": "object",
- "required": ["exists"],
- "properties": {
- "val": {
- "type": "boolean"
- }
- }
- }
- },
- "BuildDetails": {
- "type": "object",
- "required": ["version", "git_commit_hash"],
- "properties": {
- "version": {
- "type": "string"
- },
- "git_commit_hash": {
- "type": "string"
- }
- }
- }
- },
-
- "securitySchemes": {
- "cookieAuth": {
- "type": "apiKey",
- "in": "cookie",
- "name": "Authorization"
- }
- }
- }
-}
diff --git a/docs/swagger.json b/docs/swagger.json
deleted file mode 100644
index adfcff82..00000000
--- a/docs/swagger.json
+++ /dev/null
@@ -1 +0,0 @@
-{"openapi":"3.0.0","info":{"version":"0.1.0","title":"mCaptcha/guard"},"servers":[{"url":"/"}],"paths":{"/api/v1/signup":{"post":{"summary":"Registration endpoint","operationId":"registerUser","tags":["user"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterUser"},"example":{"username":"testuser","password":"mysuperlongandsecurepassword","email":"testuser@example.com"}}}},"responses":{"200":{"description":"Successful registration"},"400":{"description":"Bad request: username contains profainity/blacklisted words or email not acceptable or password too long/short or duplicate username/password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/signin":{"post":{"summary":"Login endpoint","operationId":"loginUser","tags":["user","authentication"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginUser"},"example":{"username":"testuser","password":"mysuperlongandsecurepassword"}}}},"responses":{"200":{"description":"Successful authentication"},"401":{"description":"authentication failed, wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"username not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/signout":{"post":{"security":[{"cookieAuth":[]}],"summary":"Signout endpoint","operationId":"signoutUser","tags":["user","authentication"],"responses":{"200":{"description":"OK"}}}},"/api/v1/account/delete":{"post":{"security":[{"cookieAuth":[]}],"summary":"Delete account","operationId":"deleteAccount","tags":["user"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteUser"},"example":{"password":"mysuperlongandsecurepassword"}}}},"responses":{"200":{"description":"OK"},"401":{"description":"(cookie)authentication required or wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"username not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/username/exists":{"post":{"summary":"Check if username exists","operationId":"usernameExists","tags":["user"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDetailCheck"},"example":{"val":"testuser"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDetailCheckRes"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/email/exists":{"post":{"summary":"Check if email exists","operationId":"emailExists","tags":["user"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDetailCheck"},"example":{"val":"testuser@example.com"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDetailCheckRes"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/meta/health":{"get":{"summary":"Health check","operationId":"healthCheck","tags":["meta","health"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}}}}},"/api/v1/meta/build":{"get":{"summary":"Get server binary build details","operationId":"buildDetails","tags":["meta","build"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildDetails"}}}}}}},"/api/v1/mcaptcha/domain/add":{"post":{"security":[{"cookieAuth":[]}],"summary":"Add new domain to mCaptcha","operationId":"addDomain","tags":["mcaptcha","domain"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/addDomain"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Bad request: Submited domain name isn't a URI","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed, wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/domain/verify/challenge/get":{"post":{"security":[{"cookieAuth":[]}],"summary":"Get verification challenge for adding a domain","operationId":"challengeDomain","tags":["mcaptcha","domain"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/addDomain"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainVerificationChallenge"}}}},"400":{"description":"Bad request: Submited domain name isn't a URI","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed, wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/domain/verify/challenge/prove":{"post":{"security":[{"cookieAuth":[]}],"summary":"Verifiy domain","operationId":"proveDomain","tags":["mcaptcha","domain"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/addDomain"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Bad request: challenge is courrupt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed or challenge verification failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Client server unavailable, please check if your server is online","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/delete":{"post":{"security":[{"cookieAuth":[]}],"summary":"Delete domain from mcaptcha","operationId":"deleteDomain","tags":["mcaptcha","domain"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/addDomain"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Bad request: Submited URI is not a URI","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/add":{"post":{"security":[{"cookieAuth":[]}],"summary":"Add token for registered domain","operationId":"addToken","tags":["mcaptcha","domain","token"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaID"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaDetails"}}}},"400":{"description":"Bad request: Submited URI is not a URI or duplicate token name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/update":{"post":{"security":[{"cookieAuth":[]}],"summary":"Update token key","operationId":"updateTokenKey","tags":["mcaptcha","domain","token"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaID"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaDetails"}}}},"400":{"description":"Bad request: Submited URI is not a URI or duplicate token name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/get":{"post":{"security":[{"cookieAuth":[]}],"summary":"Get token key","operationId":"getTokenKey","tags":["mcaptcha","domain","token"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaID"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaDetails"}}}},"400":{"description":"Bad request: Submited URI is not a URI","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"token name not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/delete":{"post":{"security":[{"cookieAuth":[]}],"summary":"Delete token from mcaptcha","operationId":"deleteToken","tags":["mcaptcha","domain","token"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCaptchaID"}}}},"responses":{"200":{"description":"OK"},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/levels/add":{"post":{"security":[{"cookieAuth":[]}],"summary":"Add levels to a token","operationId":"addTokenLevels","tags":["mcaptcha","domain","token","levels"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddLevels"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"duplicate visitor count or difficulty_factor is zero or difficulty_factor decreases with increase in visitor count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/levels/update":{"post":{"security":[{"cookieAuth":[]}],"summary":"Update levels of a token","operationId":"updateTokenLevels","tags":["mcaptcha","domain","token","levels"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddLevels"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"duplicate visitor count or difficulty_factor is zero or difficulty_factor decreases with increase in visitor count","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/levels/delete":{"post":{"security":[{"cookieAuth":[]}],"tags":["mcaptcha","domain","token","levels"],"summary":"Delete levels of a token","operationId":"deleteTokenLevels","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddLevels"}}}},"responses":{"200":{"description":"OK"},"401":{"description":"(cookie)authentication required or wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/levels/get":{"post":{"security":[{"cookieAuth":[]}],"tags":["mcaptcha","domain","token","levels"],"summary":"Get levels of a token","operationId":"getTokenLevels","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddLevels"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Levels"}}}},"401":{"description":"(cookie)authentication required or wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/token/get":{"post":{"security":[{"cookieAuth":[]}],"tags":["mcaptcha","domain","token","levels","duration"],"summary":"Get duration of a token","operationId":"getTokenDuration","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GetDuration"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Duration"}}}},"401":{"description":"(cookie)authentication required or wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/mcaptcha/domain/token/token/update":{"post":{"security":[{"cookieAuth":[]}],"tags":["mcaptcha","domain","token","levels","duration"],"summary":"update duration of a token","operationId":"updateTokenDuration","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDuration"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"Bad request: Duration must be greater than 0"},"401":{"description":"(cookie)authentication required or wrong password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"RegisterUser":{"type":"object","required":["username","password","email"],"properties":{"username":{"type":"string"},"email":{"type":"string"},"password":{"type":"string","format":"password"}}},"LoginUser":{"type":"object","required":["username","password"],"properties":{"username":{"type":"string"},"password":{"type":"string","format":"password"}}},"DeleteUser":{"type":"object","required":["password"],"properties":{"password":{"type":"string","format":"password"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}},"User":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"UserDetailCheck":{"type":"object","required":["val"],"properties":{"val":{"type":"string"}}},"Health":{"type":"object","required":["db"],"properties":{"db":{"type":"boolean"}}},"UserDetailCheckRes":{"type":"object","required":["exists"],"properties":{"val":{"type":"boolean"}}},"BuildDetails":{"type":"object","required":["version","git_commit_hash"],"properties":{"version":{"type":"string"},"git_commit_hash":{"type":"string"}}},"AddDomain":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"DomainVerificationChallenge":{"type":"object","required":["verification_challenge"],"properties":{"verification_challenge":{"type":"string"}}},"MCaptchaID":{"type":"object","required":["name","domain"],"properties":{"name":{"type":"string"},"domain":{"type":"string"}}},"MCaptchaDetails":{"type":"object","required":["name","key"],"properties":{"name":{"type":"string"},"key":{"type":"string"}}},"Level":{"type":"object","required":["visitor_threshold","difficulty_factor"],"properties":{"visitor_threshold":{"type":"number","minimum":1,"maximum":2147483647},"difficulty_factor":{"type":"number","minimum":1}}},"GetLevels":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}},"Levels":{"type":"array","items":{"$ref":"#/components/schemas/Level"}},"AddLevels":{"type":"object","required":["name","levels"],"properties":{"name":{"type":"string"},"levels":{"type":"array","items":{"$ref":"#/components/schemas/Level"}}}},"GetDuration":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}},"Duration":{"type":"object","required":["duration"],"properties":{"duration":{"type":"number","minimum":1,"maximum":2147483647}}},"UpdateDuration":{"type":"object","required":["duration","token_name"],"properties":{"token_name":{"type":"string"},"duration":{"type":"number","minimum":1,"maximum":2147483647}}}},"securitySchemes":{"cookieAuth":{"type":"apiKey","in":"cookie","name":"Authorization"}}}}
\ No newline at end of file
diff --git a/src/docs.rs b/src/docs.rs
index 2b64293c..119ceb66 100644
--- a/src/docs.rs
+++ b/src/docs.rs
@@ -46,12 +46,20 @@ async fn dist(path: web::Path