From f53e71afff03e675378d6433ee8978250e5f4050 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sat, 29 Mar 2025 19:44:53 +0100 Subject: [PATCH] Add doc for session routes --- auth/Dockerfile | 2 +- auth/docs/docs.go | 729 +++++++++++++++++++++++++++++++++++++++++ auth/docs/swagger.json | 705 +++++++++++++++++++++++++++++++++++++++ auth/docs/swagger.yaml | 458 -------------------------- auth/sessions.go | 66 ++-- 5 files changed, 1480 insertions(+), 480 deletions(-) create mode 100644 auth/docs/docs.go create mode 100644 auth/docs/swagger.json delete mode 100644 auth/docs/swagger.yaml diff --git a/auth/Dockerfile b/auth/Dockerfile index ef2e361b..cc700b89 100644 --- a/auth/Dockerfile +++ b/auth/Dockerfile @@ -12,7 +12,7 @@ COPY sql ./sql RUN sqlc generate COPY . . -RUN swag init --parseDependency --outputTypes yaml +RUN swag init --parseDependency --outputTypes json,go RUN CGO_ENABLED=0 GOOS=linux go build -o /keibi FROM gcr.io/distroless/base-debian11 diff --git a/auth/docs/docs.go b/auth/docs/docs.go new file mode 100644 index 00000000..284074e5 --- /dev/null +++ b/auth/docs/docs.go @@ -0,0 +1,729 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": { + "name": "Repository", + "url": "https://github.com/zoriya/kyoo" + }, + "license": { + "name": "GPL-3.0", + "url": "https://www.gnu.org/licenses/gpl-3.0.en.html" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/.well-known/jwks.json": { + "get": { + "description": "Get the jwks info, used to validate jwts.", + "produces": [ + "application/json" + ], + "tags": [ + "jwt" + ], + "summary": "Jwks", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.JwkSet" + } + } + } + } + }, + "/jwt": { + "get": { + "security": [ + { + "Token": [] + } + ], + "description": "Convert a session token to a short lived JWT.", + "produces": [ + "application/json" + ], + "tags": [ + "jwt" + ], + "summary": "Get JWT", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.Jwt" + }, + "headers": { + "Authorization": { + "type": "string", + "description": "Jwt (same value as the returned token)" + } + } + }, + "403": { + "description": "Invalid session token (or expired)", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/sessions": { + "post": { + "description": "Login to your account and open a session", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Login", + "parameters": [ + { + "type": "string", + "example": "android tv", + "description": "The device the created session will be used on", + "name": "device", + "in": "query" + }, + { + "description": "Account informations", + "name": "login", + "in": "body", + "schema": { + "$ref": "#/definitions/main.LoginDto" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/main.SessionWToken" + } + }, + "403": { + "description": "Invalid password", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "404": { + "description": "Account does not exists", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "422": { + "description": "User does not have a password (registered via oidc, please login via oidc)", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/sessions/current": { + "delete": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Delete a session and logout", + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Logout", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.Session" + } + }, + "403": { + "description": "Invalid jwt token (or expired)", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "422": { + "description": "Invalid session id", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/sessions/{id}": { + "delete": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Delete a session and logout", + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Delete other session", + "parameters": [ + { + "type": "string", + "format": "uuid", + "example": "e05089d6-9179-4b5b-a63e-94dd5fc2a397", + "description": "The id of the session to delete", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.Session" + } + }, + "404": { + "description": "Session not found with specified id (if not using the /current route)", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "422": { + "description": "Invalid session id", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/users": { + "get": { + "security": [ + { + "Jwt": [ + "users.read" + ] + } + ], + "description": "List all users existing in this instance.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "List all users", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "used for pagination.", + "name": "afterId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "400": { + "description": "Invalid after id", + "schema": {} + } + } + }, + "post": { + "description": "Register as a new user and open a session for it", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Register", + "parameters": [ + { + "type": "string", + "description": "The device the created session will be used on", + "name": "device", + "in": "query" + }, + { + "description": "Registration informations", + "name": "user", + "in": "body", + "schema": { + "$ref": "#/definitions/main.RegisterDto" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dbc.Session" + } + }, + "400": { + "description": "Invalid register body", + "schema": {} + }, + "409": { + "description": "Duplicated email or username", + "schema": {} + } + } + } + }, + "/users/me": { + "get": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Get informations about the currently connected user", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get me", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "401": { + "description": "Missing jwt token", + "schema": {} + }, + "403": { + "description": "Invalid jwt token (or expired)", + "schema": {} + } + } + }, + "delete": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Delete your account and all your sessions", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Delete self", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + } + } + } + }, + "/users/{id}": { + "get": { + "security": [ + { + "Jwt": [ + "users.read" + ] + } + ], + "description": "Get informations about a user from it's id", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get user", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "The id of the user", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "404": { + "description": "No user with the given id found", + "schema": {} + } + } + }, + "delete": { + "security": [ + { + "Jwt": [ + "users.delete" + ] + } + ], + "description": "Delete an account and all it's sessions.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Delete user", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "User id of the user to delete", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "404": { + "description": "Invalid user id", + "schema": {} + } + } + } + } + }, + "definitions": { + "dbc.Session": { + "type": "object", + "properties": { + "createdDate": { + "type": "string" + }, + "device": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lastUsed": { + "type": "string" + }, + "pk": { + "type": "integer" + }, + "token": { + "type": "string" + }, + "userPk": { + "type": "integer" + } + } + }, + "main.JwkSet": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "e": { + "type": "string", + "example": "AQAB" + }, + "key_ops": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "[verify]" + ] + }, + "kty": { + "type": "string", + "example": "RSA" + }, + "n": { + "type": "string", + "example": "oBcXcJUR-Sb8_b4qIj28LRAPxdF_6odRr52K5-ymiEkR2DOlEuXBtM-biWxPESW-U-zhfHzdVLf6ioy5xL0bJTh8BMIorkrDliN3vb81jCvyOMgZ7ATMJpMAQMmSDN7sL3U45r22FaoQufCJMQHmUsZPecdQSgj2aFBiRXxsLleYlSezdBVT_gKH-coqeYXSC_hk-ezSq4aDZ10BlDnZ-FA7-ES3T7nBmJEAU7KDAGeSvbYAfYimOW0r-Vc0xQNuwGCfzZtSexKXDbYbNwOVo3SjfCabq-gMfap_owcHbKicGBZu1LDlh7CpkmLQf_kv6GihM2LWFFh6Vwg2cltiwF22EIPlUDtYTkUR0qRkdNJaNkwV5Vv_6r3pzSmu5ovRriKtlrvJMjlTnLb4_ltsge3fw5Z34cJrsp094FbUc2O6Or4FGEXUldieJCnVRhs2_h6SDcmeMXs1zfvE5GlDnq8tZV6WMJ5Sb4jNO7rs_hTkr23_E6mVg-DdtozGfqzRzhIjPym6D_jVfR6dZv5W0sKwOHRmT7nYq-C7b2sAwmNNII296M4Rq-jn0b5pgSeMDYbIpbIA4thU8LYU0lBZp_ZVwWKG1RFZDxz3k9O5UVth2kTpTWlwn0hB1aAvgXHo6in1CScITGA72p73RbDieNnLFaCK4xUVstkWAKLqPxs" + }, + "use": { + "type": "string", + "example": "sig" + } + } + } + } + } + }, + "main.Jwt": { + "type": "object", + "properties": { + "token": { + "description": "The jwt token you can use for all authorized call to either keibi or other services.", + "type": "string", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30" + } + } + }, + "main.KError": { + "type": "object", + "properties": { + "details": {}, + "message": { + "type": "string", + "example": "No user found with this id" + }, + "status": { + "type": "integer", + "example": 404 + } + } + }, + "main.LoginDto": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "description": "Either the email or the username.", + "type": "string", + "example": "zoriya" + }, + "password": { + "description": "Password of the account.", + "type": "string", + "example": "password1234" + } + } + }, + "main.OidcHandle": { + "type": "object", + "properties": { + "id": { + "description": "Id of this oidc handle.", + "type": "string" + }, + "profileUrl": { + "description": "Link to the profile of the user on the external service. Null if unknown or irrelevant.", + "type": "string", + "format": "url" + }, + "username": { + "description": "Username of the user on the external service.", + "type": "string" + } + } + }, + "main.RegisterDto": { + "type": "object", + "required": [ + "email", + "password", + "username" + ], + "properties": { + "email": { + "description": "Valid email that could be used for forgotten password requests. Can be used for login.", + "type": "string", + "format": "email" + }, + "password": { + "description": "Password to use.", + "type": "string" + }, + "username": { + "description": "Username of the new account, can't contain @ signs. Can be used for login.", + "type": "string" + } + } + }, + "main.Session": { + "type": "object", + "properties": { + "createdDate": { + "description": "When was the session first opened", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + }, + "device": { + "description": "Device that created the session.", + "type": "string", + "example": "Web - Firefox" + }, + "id": { + "description": "Unique id of this session. Can be used for calls to DELETE", + "type": "string", + "example": "e05089d6-9179-4b5b-a63e-94dd5fc2a397" + }, + "lastUsed": { + "description": "Last date this session was used to access a service.", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + } + } + }, + "main.SessionWToken": { + "type": "object", + "properties": { + "createdDate": { + "description": "When was the session first opened", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + }, + "device": { + "description": "Device that created the session.", + "type": "string", + "example": "Web - Firefox" + }, + "id": { + "description": "Unique id of this session. Can be used for calls to DELETE", + "type": "string", + "example": "e05089d6-9179-4b5b-a63e-94dd5fc2a397" + }, + "lastUsed": { + "description": "Last date this session was used to access a service.", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + }, + "token": { + "type": "string", + "example": "lyHzTYm9yi+pkEv3m2tamAeeK7Dj7N3QRP7xv7dPU5q9MAe8tU4ySwYczE0RaMr4fijsA==" + } + } + }, + "main.User": { + "type": "object", + "properties": { + "claims": { + "description": "List of custom claims JWT created via get /jwt will have", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "createdDate": { + "description": "When was this account created?", + "type": "string" + }, + "email": { + "description": "Email of the user. Can be used as a login.", + "type": "string", + "format": "email" + }, + "id": { + "description": "Id of the user.", + "type": "string" + }, + "lastSeen": { + "description": "When was the last time this account made any authorized request?", + "type": "string" + }, + "oidc": { + "description": "List of other login method available for this user. Access tokens wont be returned here.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/main.OidcHandle" + } + }, + "username": { + "description": "Username of the user. Can be used as a login.", + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Jwt": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + }, + "Token": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "kyoo.zoriya.dev", + BasePath: "/auth", + Schemes: []string{}, + Title: "Keibi - Kyoo's auth", + Description: "Auth system made for kyoo.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/auth/docs/swagger.json b/auth/docs/swagger.json new file mode 100644 index 00000000..ec7b927e --- /dev/null +++ b/auth/docs/swagger.json @@ -0,0 +1,705 @@ +{ + "swagger": "2.0", + "info": { + "description": "Auth system made for kyoo.", + "title": "Keibi - Kyoo's auth", + "contact": { + "name": "Repository", + "url": "https://github.com/zoriya/kyoo" + }, + "license": { + "name": "GPL-3.0", + "url": "https://www.gnu.org/licenses/gpl-3.0.en.html" + }, + "version": "1.0" + }, + "host": "kyoo.zoriya.dev", + "basePath": "/auth", + "paths": { + "/.well-known/jwks.json": { + "get": { + "description": "Get the jwks info, used to validate jwts.", + "produces": [ + "application/json" + ], + "tags": [ + "jwt" + ], + "summary": "Jwks", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.JwkSet" + } + } + } + } + }, + "/jwt": { + "get": { + "security": [ + { + "Token": [] + } + ], + "description": "Convert a session token to a short lived JWT.", + "produces": [ + "application/json" + ], + "tags": [ + "jwt" + ], + "summary": "Get JWT", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.Jwt" + }, + "headers": { + "Authorization": { + "type": "string", + "description": "Jwt (same value as the returned token)" + } + } + }, + "403": { + "description": "Invalid session token (or expired)", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/sessions": { + "post": { + "description": "Login to your account and open a session", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Login", + "parameters": [ + { + "type": "string", + "example": "android tv", + "description": "The device the created session will be used on", + "name": "device", + "in": "query" + }, + { + "description": "Account informations", + "name": "login", + "in": "body", + "schema": { + "$ref": "#/definitions/main.LoginDto" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/main.SessionWToken" + } + }, + "403": { + "description": "Invalid password", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "404": { + "description": "Account does not exists", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "422": { + "description": "User does not have a password (registered via oidc, please login via oidc)", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/sessions/current": { + "delete": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Delete a session and logout", + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Logout", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.Session" + } + }, + "403": { + "description": "Invalid jwt token (or expired)", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "422": { + "description": "Invalid session id", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/sessions/{id}": { + "delete": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Delete a session and logout", + "produces": [ + "application/json" + ], + "tags": [ + "sessions" + ], + "summary": "Delete other session", + "parameters": [ + { + "type": "string", + "format": "uuid", + "example": "e05089d6-9179-4b5b-a63e-94dd5fc2a397", + "description": "The id of the session to delete", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.Session" + } + }, + "404": { + "description": "Session not found with specified id (if not using the /current route)", + "schema": { + "$ref": "#/definitions/main.KError" + } + }, + "422": { + "description": "Invalid session id", + "schema": { + "$ref": "#/definitions/main.KError" + } + } + } + } + }, + "/users": { + "get": { + "security": [ + { + "Jwt": [ + "users.read" + ] + } + ], + "description": "List all users existing in this instance.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "List all users", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "used for pagination.", + "name": "afterId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "400": { + "description": "Invalid after id", + "schema": {} + } + } + }, + "post": { + "description": "Register as a new user and open a session for it", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Register", + "parameters": [ + { + "type": "string", + "description": "The device the created session will be used on", + "name": "device", + "in": "query" + }, + { + "description": "Registration informations", + "name": "user", + "in": "body", + "schema": { + "$ref": "#/definitions/main.RegisterDto" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/dbc.Session" + } + }, + "400": { + "description": "Invalid register body", + "schema": {} + }, + "409": { + "description": "Duplicated email or username", + "schema": {} + } + } + } + }, + "/users/me": { + "get": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Get informations about the currently connected user", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get me", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "401": { + "description": "Missing jwt token", + "schema": {} + }, + "403": { + "description": "Invalid jwt token (or expired)", + "schema": {} + } + } + }, + "delete": { + "security": [ + { + "Jwt": [] + } + ], + "description": "Delete your account and all your sessions", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Delete self", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + } + } + } + }, + "/users/{id}": { + "get": { + "security": [ + { + "Jwt": [ + "users.read" + ] + } + ], + "description": "Get informations about a user from it's id", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get user", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "The id of the user", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "404": { + "description": "No user with the given id found", + "schema": {} + } + } + }, + "delete": { + "security": [ + { + "Jwt": [ + "users.delete" + ] + } + ], + "description": "Delete an account and all it's sessions.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Delete user", + "parameters": [ + { + "type": "string", + "format": "uuid", + "description": "User id of the user to delete", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.User" + } + }, + "404": { + "description": "Invalid user id", + "schema": {} + } + } + } + } + }, + "definitions": { + "dbc.Session": { + "type": "object", + "properties": { + "createdDate": { + "type": "string" + }, + "device": { + "type": "string" + }, + "id": { + "type": "string" + }, + "lastUsed": { + "type": "string" + }, + "pk": { + "type": "integer" + }, + "token": { + "type": "string" + }, + "userPk": { + "type": "integer" + } + } + }, + "main.JwkSet": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "type": "object", + "properties": { + "e": { + "type": "string", + "example": "AQAB" + }, + "key_ops": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "[verify]" + ] + }, + "kty": { + "type": "string", + "example": "RSA" + }, + "n": { + "type": "string", + "example": "oBcXcJUR-Sb8_b4qIj28LRAPxdF_6odRr52K5-ymiEkR2DOlEuXBtM-biWxPESW-U-zhfHzdVLf6ioy5xL0bJTh8BMIorkrDliN3vb81jCvyOMgZ7ATMJpMAQMmSDN7sL3U45r22FaoQufCJMQHmUsZPecdQSgj2aFBiRXxsLleYlSezdBVT_gKH-coqeYXSC_hk-ezSq4aDZ10BlDnZ-FA7-ES3T7nBmJEAU7KDAGeSvbYAfYimOW0r-Vc0xQNuwGCfzZtSexKXDbYbNwOVo3SjfCabq-gMfap_owcHbKicGBZu1LDlh7CpkmLQf_kv6GihM2LWFFh6Vwg2cltiwF22EIPlUDtYTkUR0qRkdNJaNkwV5Vv_6r3pzSmu5ovRriKtlrvJMjlTnLb4_ltsge3fw5Z34cJrsp094FbUc2O6Or4FGEXUldieJCnVRhs2_h6SDcmeMXs1zfvE5GlDnq8tZV6WMJ5Sb4jNO7rs_hTkr23_E6mVg-DdtozGfqzRzhIjPym6D_jVfR6dZv5W0sKwOHRmT7nYq-C7b2sAwmNNII296M4Rq-jn0b5pgSeMDYbIpbIA4thU8LYU0lBZp_ZVwWKG1RFZDxz3k9O5UVth2kTpTWlwn0hB1aAvgXHo6in1CScITGA72p73RbDieNnLFaCK4xUVstkWAKLqPxs" + }, + "use": { + "type": "string", + "example": "sig" + } + } + } + } + } + }, + "main.Jwt": { + "type": "object", + "properties": { + "token": { + "description": "The jwt token you can use for all authorized call to either keibi or other services.", + "type": "string", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30" + } + } + }, + "main.KError": { + "type": "object", + "properties": { + "details": {}, + "message": { + "type": "string", + "example": "No user found with this id" + }, + "status": { + "type": "integer", + "example": 404 + } + } + }, + "main.LoginDto": { + "type": "object", + "required": [ + "login", + "password" + ], + "properties": { + "login": { + "description": "Either the email or the username.", + "type": "string", + "example": "zoriya" + }, + "password": { + "description": "Password of the account.", + "type": "string", + "example": "password1234" + } + } + }, + "main.OidcHandle": { + "type": "object", + "properties": { + "id": { + "description": "Id of this oidc handle.", + "type": "string" + }, + "profileUrl": { + "description": "Link to the profile of the user on the external service. Null if unknown or irrelevant.", + "type": "string", + "format": "url" + }, + "username": { + "description": "Username of the user on the external service.", + "type": "string" + } + } + }, + "main.RegisterDto": { + "type": "object", + "required": [ + "email", + "password", + "username" + ], + "properties": { + "email": { + "description": "Valid email that could be used for forgotten password requests. Can be used for login.", + "type": "string", + "format": "email" + }, + "password": { + "description": "Password to use.", + "type": "string" + }, + "username": { + "description": "Username of the new account, can't contain @ signs. Can be used for login.", + "type": "string" + } + } + }, + "main.Session": { + "type": "object", + "properties": { + "createdDate": { + "description": "When was the session first opened", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + }, + "device": { + "description": "Device that created the session.", + "type": "string", + "example": "Web - Firefox" + }, + "id": { + "description": "Unique id of this session. Can be used for calls to DELETE", + "type": "string", + "example": "e05089d6-9179-4b5b-a63e-94dd5fc2a397" + }, + "lastUsed": { + "description": "Last date this session was used to access a service.", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + } + } + }, + "main.SessionWToken": { + "type": "object", + "properties": { + "createdDate": { + "description": "When was the session first opened", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + }, + "device": { + "description": "Device that created the session.", + "type": "string", + "example": "Web - Firefox" + }, + "id": { + "description": "Unique id of this session. Can be used for calls to DELETE", + "type": "string", + "example": "e05089d6-9179-4b5b-a63e-94dd5fc2a397" + }, + "lastUsed": { + "description": "Last date this session was used to access a service.", + "type": "string", + "example": "2025-03-29T18:20:05.267Z" + }, + "token": { + "type": "string", + "example": "lyHzTYm9yi+pkEv3m2tamAeeK7Dj7N3QRP7xv7dPU5q9MAe8tU4ySwYczE0RaMr4fijsA==" + } + } + }, + "main.User": { + "type": "object", + "properties": { + "claims": { + "description": "List of custom claims JWT created via get /jwt will have", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "createdDate": { + "description": "When was this account created?", + "type": "string" + }, + "email": { + "description": "Email of the user. Can be used as a login.", + "type": "string", + "format": "email" + }, + "id": { + "description": "Id of the user.", + "type": "string" + }, + "lastSeen": { + "description": "When was the last time this account made any authorized request?", + "type": "string" + }, + "oidc": { + "description": "List of other login method available for this user. Access tokens wont be returned here.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/main.OidcHandle" + } + }, + "username": { + "description": "Username of the user. Can be used as a login.", + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Jwt": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + }, + "Token": { + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/auth/docs/swagger.yaml b/auth/docs/swagger.yaml deleted file mode 100644 index a3a2b77e..00000000 --- a/auth/docs/swagger.yaml +++ /dev/null @@ -1,458 +0,0 @@ -basePath: /auth -definitions: - dbc.Session: - properties: - createdDate: - type: string - device: - type: string - id: - type: string - lastUsed: - type: string - pk: - type: integer - token: - type: string - userPk: - type: integer - type: object - main.JwkSet: - properties: - keys: - items: - properties: - e: - example: AQAB - type: string - key_ops: - example: - - '[verify]' - items: - type: string - type: array - kty: - example: RSA - type: string - "n": - example: oBcXcJUR-Sb8_b4qIj28LRAPxdF_6odRr52K5-ymiEkR2DOlEuXBtM-biWxPESW-U-zhfHzdVLf6ioy5xL0bJTh8BMIorkrDliN3vb81jCvyOMgZ7ATMJpMAQMmSDN7sL3U45r22FaoQufCJMQHmUsZPecdQSgj2aFBiRXxsLleYlSezdBVT_gKH-coqeYXSC_hk-ezSq4aDZ10BlDnZ-FA7-ES3T7nBmJEAU7KDAGeSvbYAfYimOW0r-Vc0xQNuwGCfzZtSexKXDbYbNwOVo3SjfCabq-gMfap_owcHbKicGBZu1LDlh7CpkmLQf_kv6GihM2LWFFh6Vwg2cltiwF22EIPlUDtYTkUR0qRkdNJaNkwV5Vv_6r3pzSmu5ovRriKtlrvJMjlTnLb4_ltsge3fw5Z34cJrsp094FbUc2O6Or4FGEXUldieJCnVRhs2_h6SDcmeMXs1zfvE5GlDnq8tZV6WMJ5Sb4jNO7rs_hTkr23_E6mVg-DdtozGfqzRzhIjPym6D_jVfR6dZv5W0sKwOHRmT7nYq-C7b2sAwmNNII296M4Rq-jn0b5pgSeMDYbIpbIA4thU8LYU0lBZp_ZVwWKG1RFZDxz3k9O5UVth2kTpTWlwn0hB1aAvgXHo6in1CScITGA72p73RbDieNnLFaCK4xUVstkWAKLqPxs - type: string - use: - example: sig - type: string - type: object - type: array - type: object - main.Jwt: - properties: - token: - description: The jwt token you can use for all authorized call to either keibi - or other services. - example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30 - type: string - type: object - main.KError: - properties: - details: {} - message: - example: No user found with this id - type: string - status: - example: 404 - type: integer - type: object - main.LoginDto: - properties: - login: - description: Either the email or the username. - type: string - password: - description: Password of the account. - type: string - required: - - login - - password - type: object - main.OidcHandle: - properties: - id: - description: Id of this oidc handle. - type: string - profileUrl: - description: Link to the profile of the user on the external service. Null - if unknown or irrelevant. - format: url - type: string - username: - description: Username of the user on the external service. - type: string - type: object - main.RegisterDto: - properties: - email: - description: Valid email that could be used for forgotten password requests. - Can be used for login. - format: email - type: string - password: - description: Password to use. - type: string - username: - description: Username of the new account, can't contain @ signs. Can be used - for login. - type: string - required: - - email - - password - - username - type: object - main.Session: - properties: - createdDate: - description: When was the session first opened - type: string - device: - description: Device that created the session. - type: string - id: - description: Unique id of this session. Can be used for calls to DELETE - type: string - lastUsed: - description: Last date this session was used to access a service. - type: string - type: object - main.User: - properties: - claims: - additionalProperties: - type: string - description: List of custom claims JWT created via get /jwt will have - type: object - createdDate: - description: When was this account created? - type: string - email: - description: Email of the user. Can be used as a login. - format: email - type: string - id: - description: Id of the user. - type: string - lastSeen: - description: When was the last time this account made any authorized request? - type: string - oidc: - additionalProperties: - $ref: '#/definitions/main.OidcHandle' - description: List of other login method available for this user. Access tokens - wont be returned here. - type: object - username: - description: Username of the user. Can be used as a login. - type: string - type: object -host: kyoo.zoriya.dev -info: - contact: - name: Repository - url: https://github.com/zoriya/kyoo - description: Auth system made for kyoo. - license: - name: GPL-3.0 - url: https://www.gnu.org/licenses/gpl-3.0.en.html - title: Keibi - Kyoo's auth - version: "1.0" -paths: - /.well-known/jwks.json: - get: - description: Get the jwks info, used to validate jwts. - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.JwkSet' - summary: Jwks - tags: - - jwt - /jwt: - get: - description: Convert a session token to a short lived JWT. - produces: - - application/json - responses: - "200": - description: OK - headers: - Authorization: - description: Jwt (same value as the returned token) - type: string - schema: - $ref: '#/definitions/main.Jwt' - "403": - description: Invalid session token (or expired) - schema: - $ref: '#/definitions/main.KError' - security: - - Token: [] - summary: Get JWT - tags: - - jwt - /sessions: - post: - consumes: - - application/json - description: Login to your account and open a session - parameters: - - description: The device the created session will be used on - in: query - name: device - type: string - - description: Account informations - in: body - name: login - schema: - $ref: '#/definitions/main.LoginDto' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/dbc.Session' - "400": - description: Invalid login body - schema: {} - "403": - description: Invalid password - schema: {} - "404": - description: Account does not exists - schema: {} - "422": - description: User does not have a password (registered via oidc, please - login via oidc) - schema: {} - summary: Login - tags: - - sessions - /sessions/{id}: - delete: - description: Delete a session and logout - parameters: - - description: The id of the session to delete - format: uuid - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.Session' - "400": - description: Invalid session id - schema: {} - "401": - description: Missing jwt token - schema: {} - "403": - description: Invalid jwt token (or expired) - schema: {} - "404": - description: Session not found with specified id (if not using the /current - route) - schema: {} - security: - - Jwt: [] - summary: Logout - tags: - - sessions - /sessions/current: - delete: - description: Delete a session and logout - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.Session' - "400": - description: Invalid session id - schema: {} - "401": - description: Missing jwt token - schema: {} - "403": - description: Invalid jwt token (or expired) - schema: {} - "404": - description: Session not found with specified id (if not using the /current - route) - schema: {} - security: - - Jwt: [] - summary: Logout - tags: - - sessions - /users: - get: - consumes: - - application/json - description: List all users existing in this instance. - parameters: - - description: used for pagination. - format: uuid - in: query - name: afterId - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.User' - "400": - description: Invalid after id - schema: {} - security: - - Jwt: - - users.read - summary: List all users - tags: - - users - post: - consumes: - - application/json - description: Register as a new user and open a session for it - parameters: - - description: The device the created session will be used on - in: query - name: device - type: string - - description: Registration informations - in: body - name: user - schema: - $ref: '#/definitions/main.RegisterDto' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/dbc.Session' - "400": - description: Invalid register body - schema: {} - "409": - description: Duplicated email or username - schema: {} - summary: Register - tags: - - users - /users/{id}: - delete: - consumes: - - application/json - description: Delete an account and all it's sessions. - parameters: - - description: User id of the user to delete - format: uuid - in: path - name: id - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.User' - "404": - description: Invalid user id - schema: {} - security: - - Jwt: - - users.delete - summary: Delete user - tags: - - users - get: - description: Get informations about a user from it's id - parameters: - - description: The id of the user - format: uuid - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.User' - "404": - description: No user with the given id found - schema: {} - security: - - Jwt: - - users.read - summary: Get user - tags: - - users - /users/me: - delete: - consumes: - - application/json - description: Delete your account and all your sessions - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.User' - security: - - Jwt: [] - summary: Delete self - tags: - - users - get: - description: Get informations about the currently connected user - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.User' - "401": - description: Missing jwt token - schema: {} - "403": - description: Invalid jwt token (or expired) - schema: {} - security: - - Jwt: [] - summary: Get me - tags: - - users -securityDefinitions: - Jwt: - in: header - name: Authorization - type: apiKey - Token: - in: header - name: Authorization - type: apiKey -swagger: "2.0" diff --git a/auth/sessions.go b/auth/sessions.go index 1092f5fa..cf4d8752 100644 --- a/auth/sessions.go +++ b/auth/sessions.go @@ -18,13 +18,18 @@ import ( type Session struct { // Unique id of this session. Can be used for calls to DELETE - Id uuid.UUID `json:"id"` + Id uuid.UUID `json:"id" example:"e05089d6-9179-4b5b-a63e-94dd5fc2a397"` // When was the session first opened - CreatedDate time.Time `json:"createdDate"` + CreatedDate time.Time `json:"createdDate" example:"2025-03-29T18:20:05.267Z"` // Last date this session was used to access a service. - LastUsed time.Time `json:"lastUsed"` + LastUsed time.Time `json:"lastUsed" example:"2025-03-29T18:20:05.267Z"` // Device that created the session. - Device *string `json:"device"` + Device *string `json:"device" example:"Web - Firefox"` +} + +type SessionWToken struct { + Session + Token string `json:"token" example:"lyHzTYm9yi+pkEv3m2tamAeeK7Dj7N3QRP7xv7dPU5q9MAe8tU4ySwYczE0RaMr4fijsA=="` } func MapSession(ses *dbc.Session) Session { @@ -36,11 +41,23 @@ func MapSession(ses *dbc.Session) Session { } } +func MapSessionToken(ses *dbc.Session) SessionWToken { + return SessionWToken{ + Session: Session{ + Id: ses.Id, + CreatedDate: ses.CreatedDate, + LastUsed: ses.LastUsed, + Device: ses.Device, + }, + Token: ses.Token, + } +} + type LoginDto struct { // Either the email or the username. - Login string `json:"login" validate:"required"` + Login string `json:"login" validate:"required" example:"zoriya"` // Password of the account. - Password string `json:"password" validate:"required"` + Password string `json:"password" validate:"required" example:"password1234"` } // @Summary Login @@ -48,19 +65,18 @@ type LoginDto struct { // @Tags sessions // @Accept json // @Produce json -// @Param device query string false "The device the created session will be used on" +// @Param device query string false "The device the created session will be used on" example(android tv) // @Param login body LoginDto false "Account informations" -// @Success 201 {object} dbc.Session -// @Failure 400 {object} problem.Problem "Invalid login body" -// @Failure 403 {object} problem.Problem "Invalid password" -// @Failure 404 {object} problem.Problem "Account does not exists" -// @Failure 422 {object} problem.Problem "User does not have a password (registered via oidc, please login via oidc)" +// @Success 201 {object} SessionWToken +// @Failure 403 {object} KError "Invalid password" +// @Failure 404 {object} KError "Account does not exists" +// @Failure 422 {object} KError "User does not have a password (registered via oidc, please login via oidc)" // @Router /sessions [post] func (h *Handler) Login(c echo.Context) error { var req LoginDto err := c.Bind(&req) if err != nil { - return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + return echo.NewHTTPError(http.StatusUnprocessableEntity, err.Error()) } if err = c.Validate(&req); err != nil { return err @@ -117,13 +133,9 @@ func (h *Handler) createSession(c echo.Context, user *User) error { // @Tags sessions // @Produce json // @Security Jwt -// @Param id path string true "The id of the session to delete" Format(uuid) // @Success 200 {object} Session -// @Failure 400 {object} problem.Problem "Invalid session id" -// @Failure 401 {object} problem.Problem "Missing jwt token" -// @Failure 403 {object} problem.Problem "Invalid jwt token (or expired)" -// @Failure 404 {object} problem.Problem "Session not found with specified id (if not using the /current route)" -// @Router /sessions/{id} [delete] +// @Failure 401 {object} KError "Missing jwt token" +// @Failure 403 {object} KError "Invalid jwt token (or expired)" // @Router /sessions/current [delete] func (h *Handler) Logout(c echo.Context) error { uid, err := GetCurrentUserId(c) @@ -135,13 +147,13 @@ func (h *Handler) Logout(c echo.Context) error { if session == "current" { sid, ok := c.Get("user").(*jwt.Token).Claims.(jwt.MapClaims)["sid"] if !ok { - return echo.NewHTTPError(400, "Missing session id") + return echo.NewHTTPError(http.StatusInternalServerError, "Missing session id") } session = sid.(string) } sid, err := uuid.Parse(session) if err != nil { - return echo.NewHTTPError(400, "Invalid session id") + return echo.NewHTTPError(422, "Invalid session id") } ret, err := h.db.DeleteSession(context.Background(), dbc.DeleteSessionParams{ @@ -155,3 +167,15 @@ func (h *Handler) Logout(c echo.Context) error { } return c.JSON(200, MapSession(&ret)) } + +// @Summary Delete other session +// @Description Delete a session and logout +// @Tags sessions +// @Produce json +// @Security Jwt +// @Param id path string true "The id of the session to delete" Format(uuid) Example(e05089d6-9179-4b5b-a63e-94dd5fc2a397) +// @Success 200 {object} Session +// @Failure 404 {object} KError "Session not found with specified id (if not using the /current route)" +// @Failure 422 {object} KError "Invalid session id" +// @Router /sessions/{id} [delete] +func DocOnly() {}