663 lines
18 KiB
Go
663 lines
18 KiB
Go
// Package docs provides API documentation using Swagger/OpenAPI
|
|
package docs
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
)
|
|
|
|
// SwaggerInfo holds the API information
|
|
var SwaggerInfo = struct {
|
|
Title string
|
|
Description string
|
|
Version string
|
|
Host string
|
|
BasePath string
|
|
Schemes []string
|
|
}{
|
|
Title: "OTPM API",
|
|
Description: "API for One-Time Password Manager",
|
|
Version: "1.0.0",
|
|
Host: "localhost:8080",
|
|
BasePath: "/",
|
|
Schemes: []string{"http", "https"},
|
|
}
|
|
|
|
// SwaggerJSON returns the Swagger JSON
|
|
func SwaggerJSON() []byte {
|
|
swagger := map[string]interface{}{
|
|
"swagger": "2.0",
|
|
"info": map[string]interface{}{
|
|
"title": SwaggerInfo.Title,
|
|
"description": SwaggerInfo.Description,
|
|
"version": SwaggerInfo.Version,
|
|
},
|
|
"host": SwaggerInfo.Host,
|
|
"basePath": SwaggerInfo.BasePath,
|
|
"schemes": SwaggerInfo.Schemes,
|
|
"paths": getPaths(),
|
|
"definitions": map[string]interface{}{
|
|
"LoginRequest": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"code": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "WeChat authorization code",
|
|
},
|
|
},
|
|
"required": []string{"code"},
|
|
},
|
|
"LoginResponse": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"token": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "JWT token",
|
|
},
|
|
"openid": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "WeChat OpenID",
|
|
},
|
|
},
|
|
},
|
|
"CreateOTPRequest": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"name": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP name",
|
|
},
|
|
"issuer": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP issuer",
|
|
},
|
|
"secret": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP secret",
|
|
},
|
|
"algorithm": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP algorithm",
|
|
"enum": []string{"SHA1", "SHA256", "SHA512"},
|
|
},
|
|
"digits": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "OTP digits",
|
|
"enum": []int{6, 8},
|
|
},
|
|
"period": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "OTP period in seconds",
|
|
"enum": []int{30, 60},
|
|
},
|
|
},
|
|
"required": []string{"name", "issuer", "secret", "algorithm", "digits", "period"},
|
|
},
|
|
"OTP": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"id": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP ID",
|
|
},
|
|
"user_id": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "User ID",
|
|
},
|
|
"name": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP name",
|
|
},
|
|
"issuer": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP issuer",
|
|
},
|
|
"algorithm": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP algorithm",
|
|
},
|
|
"digits": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "OTP digits",
|
|
},
|
|
"period": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "OTP period in seconds",
|
|
},
|
|
"created_at": map[string]interface{}{
|
|
"type": "string",
|
|
"format": "date-time",
|
|
"description": "Creation time",
|
|
},
|
|
"updated_at": map[string]interface{}{
|
|
"type": "string",
|
|
"format": "date-time",
|
|
"description": "Last update time",
|
|
},
|
|
},
|
|
},
|
|
"OTPCodeResponse": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"code": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP code",
|
|
},
|
|
"expires_in": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "Seconds until expiration",
|
|
},
|
|
},
|
|
},
|
|
"VerifyOTPRequest": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"code": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP code to verify",
|
|
},
|
|
},
|
|
"required": []string{"code"},
|
|
},
|
|
"VerifyOTPResponse": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"valid": map[string]interface{}{
|
|
"type": "boolean",
|
|
"description": "Whether the code is valid",
|
|
},
|
|
},
|
|
},
|
|
"UpdateOTPRequest": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"name": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP name",
|
|
},
|
|
"issuer": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP issuer",
|
|
},
|
|
"algorithm": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "OTP algorithm",
|
|
"enum": []string{"SHA1", "SHA256", "SHA512"},
|
|
},
|
|
"digits": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "OTP digits",
|
|
"enum": []int{6, 8},
|
|
},
|
|
"period": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "OTP period in seconds",
|
|
"enum": []int{30, 60},
|
|
},
|
|
},
|
|
},
|
|
"ErrorResponse": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"code": map[string]interface{}{
|
|
"type": "integer",
|
|
"description": "Error code",
|
|
},
|
|
"message": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "Error message",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"securityDefinitions": map[string]interface{}{
|
|
"Bearer": map[string]interface{}{
|
|
"type": "apiKey",
|
|
"name": "Authorization",
|
|
"in": "header",
|
|
"description": "JWT token with Bearer prefix",
|
|
},
|
|
},
|
|
}
|
|
|
|
data, _ := json.MarshalIndent(swagger, "", " ")
|
|
return data
|
|
}
|
|
|
|
// getPaths returns the API paths
|
|
func getPaths() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"/login": map[string]interface{}{
|
|
"post": map[string]interface{}{
|
|
"summary": "Login with WeChat",
|
|
"description": "Login with WeChat authorization code",
|
|
"tags": []string{"auth"},
|
|
"parameters": []map[string]interface{}{
|
|
{
|
|
"name": "body",
|
|
"in": "body",
|
|
"description": "Login request",
|
|
"required": true,
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/LoginRequest",
|
|
},
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "Successful login",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/LoginResponse",
|
|
},
|
|
},
|
|
"400": map[string]interface{}{
|
|
"description": "Invalid request",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/verify-token": map[string]interface{}{
|
|
"post": map[string]interface{}{
|
|
"summary": "Verify token",
|
|
"description": "Verify JWT token",
|
|
"tags": []string{"auth"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "Token is valid",
|
|
"schema": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"valid": map[string]interface{}{
|
|
"type": "boolean",
|
|
"description": "Whether the token is valid",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/otp": map[string]interface{}{
|
|
"get": map[string]interface{}{
|
|
"summary": "List OTPs",
|
|
"description": "List all OTPs for the authenticated user",
|
|
"tags": []string{"otp"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "List of OTPs",
|
|
"schema": map[string]interface{}{
|
|
"type": "array",
|
|
"items": map[string]interface{}{
|
|
"$ref": "#/definitions/OTP",
|
|
},
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"post": map[string]interface{}{
|
|
"summary": "Create OTP",
|
|
"description": "Create a new OTP",
|
|
"tags": []string{"otp"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"parameters": []map[string]interface{}{
|
|
{
|
|
"name": "body",
|
|
"in": "body",
|
|
"description": "OTP creation request",
|
|
"required": true,
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/CreateOTPRequest",
|
|
},
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "OTP created",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/OTP",
|
|
},
|
|
},
|
|
"400": map[string]interface{}{
|
|
"description": "Invalid request",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/otp/{id}": map[string]interface{}{
|
|
"put": map[string]interface{}{
|
|
"summary": "Update OTP",
|
|
"description": "Update an existing OTP",
|
|
"tags": []string{"otp"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"parameters": []map[string]interface{}{
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "OTP ID",
|
|
"required": true,
|
|
"type": "string",
|
|
},
|
|
{
|
|
"name": "body",
|
|
"in": "body",
|
|
"description": "OTP update request",
|
|
"required": true,
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/UpdateOTPRequest",
|
|
},
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "OTP updated",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/OTP",
|
|
},
|
|
},
|
|
"400": map[string]interface{}{
|
|
"description": "Invalid request",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"404": map[string]interface{}{
|
|
"description": "OTP not found",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"delete": map[string]interface{}{
|
|
"summary": "Delete OTP",
|
|
"description": "Delete an existing OTP",
|
|
"tags": []string{"otp"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"parameters": []map[string]interface{}{
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "OTP ID",
|
|
"required": true,
|
|
"type": "string",
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "OTP deleted",
|
|
"schema": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"message": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "Success message",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"404": map[string]interface{}{
|
|
"description": "OTP not found",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/otp/{id}/code": map[string]interface{}{
|
|
"get": map[string]interface{}{
|
|
"summary": "Get OTP code",
|
|
"description": "Get the current OTP code",
|
|
"tags": []string{"otp"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"parameters": []map[string]interface{}{
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "OTP ID",
|
|
"required": true,
|
|
"type": "string",
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "OTP code",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/OTPCodeResponse",
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"404": map[string]interface{}{
|
|
"description": "OTP not found",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/otp/{id}/verify": map[string]interface{}{
|
|
"post": map[string]interface{}{
|
|
"summary": "Verify OTP code",
|
|
"description": "Verify an OTP code",
|
|
"tags": []string{"otp"},
|
|
"security": []map[string]interface{}{
|
|
{
|
|
"Bearer": []string{},
|
|
},
|
|
},
|
|
"parameters": []map[string]interface{}{
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"description": "OTP ID",
|
|
"required": true,
|
|
"type": "string",
|
|
},
|
|
{
|
|
"name": "body",
|
|
"in": "body",
|
|
"description": "OTP verification request",
|
|
"required": true,
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/VerifyOTPRequest",
|
|
},
|
|
},
|
|
},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "OTP verification result",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/VerifyOTPResponse",
|
|
},
|
|
},
|
|
"400": map[string]interface{}{
|
|
"description": "Invalid request",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"401": map[string]interface{}{
|
|
"description": "Unauthorized",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"404": map[string]interface{}{
|
|
"description": "OTP not found",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
"500": map[string]interface{}{
|
|
"description": "Internal server error",
|
|
"schema": map[string]interface{}{
|
|
"$ref": "#/definitions/ErrorResponse",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/health": map[string]interface{}{
|
|
"get": map[string]interface{}{
|
|
"summary": "Health check",
|
|
"description": "Check if the API is healthy",
|
|
"tags": []string{"system"},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "API is healthy",
|
|
"schema": map[string]interface{}{
|
|
"type": "object",
|
|
"properties": map[string]interface{}{
|
|
"status": map[string]interface{}{
|
|
"type": "string",
|
|
"description": "Health status",
|
|
},
|
|
"time": map[string]interface{}{
|
|
"type": "string",
|
|
"format": "date-time",
|
|
"description": "Current time",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/metrics": map[string]interface{}{
|
|
"get": map[string]interface{}{
|
|
"summary": "Metrics",
|
|
"description": "Get application metrics",
|
|
"tags": []string{"system"},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "Application metrics",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"/swagger.json": map[string]interface{}{
|
|
"get": map[string]interface{}{
|
|
"summary": "Swagger JSON",
|
|
"description": "Get Swagger JSON",
|
|
"tags": []string{"system"},
|
|
"responses": map[string]interface{}{
|
|
"200": map[string]interface{}{
|
|
"description": "Swagger JSON",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// Handler returns an HTTP handler for Swagger JSON
|
|
func Handler() http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Write(SwaggerJSON())
|
|
}
|
|
}
|