From 99402ebdf0b6162c0e6cb5cf39f6e58cc55c37d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=90=99PiperYxzzy?= Date: Thu, 5 May 2022 23:11:24 +0200 Subject: [PATCH] Adding swagger annotations to core --- controllers/core/core.go | 76 +++++++++- docs/docs.go | 304 +++++++++++++++++++++++++++++++++++++++ docs/swagger.json | 279 +++++++++++++++++++++++++++++++++++ docs/swagger.yaml | 183 +++++++++++++++++++++++ go.mod | 19 ++- go.sum | 45 ++++++ main.go | 6 +- 7 files changed, 907 insertions(+), 5 deletions(-) create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml diff --git a/controllers/core/core.go b/controllers/core/core.go index fe5e7b0..bb70781 100644 --- a/controllers/core/core.go +++ b/controllers/core/core.go @@ -52,6 +52,15 @@ const JwtHeader = "jwt" // attacks, this method will always return {next:"verification pending"}, even // if the given email is already in the system. If the email is already in the system, // that account will be emailed notifying them of the signup attempt. +// @Summary User signup +// @Description Sign a user up for a new account +// @Accept json +// @Produce json +// @Param userkey body string true "user email" +// @Param password body string true "user password" +// @Router /signup [post] +// @Success 200 +// @Failure 400 "userkey missing, or password missing or not strong enough" func UserSignup() gin.HandlerFunc { return func(c *gin.Context) { var signupVals signup @@ -91,6 +100,18 @@ func UserSignup() gin.HandlerFunc { // Function to log in a user based on a given email, password [and 2FA code]. Similar to // AdminLogin but with slight differences. Resistant to enumeration attacks as error messages // are only displayed IFF the user exists AND the password is correct, otherwise a 401 is returned +// @Summary User login +// @Description Secured login for any user accounts +// @Accept json +// @Produce json +// @Param userkey body string true "user email" +// @Param password body string true "user password" +// @Param twofactorcode body string false "the 2fa token for the user, if activated" +// @Router /login [post] +// @Success 200 +// @Failure 401 "not found or credentials invalid" +// @Failure 400 "userkey or password missing" +// @Header 200 {string} jwt "The authentication token for this session, valid for 24h" func UserLogin() gin.HandlerFunc { return func(c *gin.Context) { // Why do we do this? Assuming a consistent and stable service and an attacker @@ -197,6 +218,14 @@ func UserVerify() gin.HandlerFunc { // requires a reset token; then sends an email with the appropriate reset token // to the user email in question. The same response will be returned if the given // user email does not exist +// @Summary Forgot password +// @Description Request a password reset for the provided userkey +// @Accept json +// @Produce json +// @Param userkey body string true "user email to reset" +// @Router /forgot [post] +// @Success 200 +// @Failure 400 "userkey not provided" func UserForgotPassword() gin.HandlerFunc { return func(c *gin.Context) { var forgotVals forgotten @@ -218,6 +247,16 @@ func UserForgotPassword() gin.HandlerFunc { // Method to reset a password, requiring a new password and a valid JWT token // of role="reset". +// @Summary Password reset +// @Description Use a JWT token to validate and reset a password +// @Accept json +// @Produce json +// @Param token body string true "the token emailed to the user" +// @Param password body string true "the new password value" +// @Router /reset [post] +// @Success 200 +// @Failure 400 "token and password not provided" +// @Failure 401 "bad token or user not found" func UserResetForgottenPassword() gin.HandlerFunc { return func(c *gin.Context) { var resetVals reset @@ -265,6 +304,18 @@ func UserResetForgottenPassword() gin.HandlerFunc { } // Admin login functionality, similar to user login but requires 2FA to be set up. +// @Summary User login +// @Description Secured login for any user accounts +// @Accept json +// @Produce json +// @Param userkey body string true "user email" +// @Param password body string true "user password" +// @Param twofactorcode body string true "the 2fa token" +// @Router /admin [post] +// @Success 200 +// @Failure 401 "not found or credentials invalid" +// @Failure 400 "userkey, 2fa token or password missing" +// @Header 200 {string} jwt "The authentication token for this session, valid for 24h" func AdminLogin() gin.HandlerFunc { return func(c *gin.Context) { // Same as user slowdown @@ -443,8 +494,11 @@ func StarterAdmin() gin.HandlerFunc { } } -// A simple context-aware ping method. If there is a "principal" in this request context -// it will indicate the principal Uid and role in the response +// Ping functionality +// @Summary ping example +// @Description unauthenticated ping +// @Product json +// @Router /doot [get] func Doot() gin.HandlerFunc { return func(c *gin.Context) { piCtx, exists := c.Get("principal") @@ -458,6 +512,24 @@ func Doot() gin.HandlerFunc { } } +// @Summary ping example +// @Description user ping and login check +// @Product json +// @Router /sec/doot [get] +// @Param jwt header string true "JWT Cookie set by /login" +func UserDoot() gin.HandlerFunc { + return Doot() +} + +// @Summary ping example +// @Description admin ping and login check +// @Product json +// @Router /adm/doot [get] +// @Param jwt header string true "JWT Cookie set by /admin" +func AdminDoot() gin.HandlerFunc { + return Doot() +} + // To prevent 2FA theft attacks, a TOTP needs to be... well, an OTP. This will // check the database to confirm that this user UID has never used this token in // past, and will fail if such a token has been used by this user. It will then diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..b662b08 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,304 @@ +// Package docs GENERATED BY SWAG; DO NOT EDIT +// This file was generated by swaggo/swag +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/adm/doot": { + "get": { + "description": "admin ping and login check", + "summary": "ping example", + "parameters": [ + { + "type": "string", + "description": "JWT Cookie set by /admin", + "name": "jwt", + "in": "header", + "required": true + } + ], + "responses": {} + } + }, + "/admin": { + "post": { + "description": "Secured login for any user accounts", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "User login", + "parameters": [ + { + "description": "user email", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "user password", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the 2fa token", + "name": "twofactorcode", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "headers": { + "jwt": { + "type": "string", + "description": "The authentication token for this session, valid for 24h" + } + } + }, + "400": { + "description": "userkey, 2fa token or password missing" + }, + "401": { + "description": "not found or credentials invalid" + } + } + } + }, + "/doot": { + "get": { + "description": "unauthenticated ping", + "summary": "ping example", + "responses": {} + } + }, + "/forgot": { + "post": { + "description": "Request a password reset for the provided userkey", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Forgot password", + "parameters": [ + { + "description": "user email to reset", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "userkey not provided" + } + } + } + }, + "/login": { + "post": { + "description": "Secured login for any user accounts", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "User login", + "parameters": [ + { + "description": "user email", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "user password", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the 2fa token for the user, if activated", + "name": "twofactorcode", + "in": "body", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "headers": { + "jwt": { + "type": "string", + "description": "The authentication token for this session, valid for 24h" + } + } + }, + "400": { + "description": "userkey or password missing" + }, + "401": { + "description": "not found or credentials invalid" + } + } + } + }, + "/reset": { + "post": { + "description": "Use a JWT token to validate and reset a password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Password reset", + "parameters": [ + { + "description": "the token emailed to the user", + "name": "token", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the new password value", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "token and password not provided" + }, + "401": { + "description": "bad token or user not found" + } + } + } + }, + "/sec/doot": { + "get": { + "description": "user ping and login check", + "summary": "ping example", + "parameters": [ + { + "type": "string", + "description": "JWT Cookie set by /login", + "name": "jwt", + "in": "header", + "required": true + } + ], + "responses": {} + } + }, + "/signup": { + "post": { + "description": "Sign a user up for a new account", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "User signup", + "parameters": [ + { + "description": "user email", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "user password", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "userkey missing, or password missing or not strong enough" + } + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1", + Host: "", + BasePath: "/v1", + Schemes: []string{}, + Title: "Go-Gin Prepack", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..e94ff96 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,279 @@ +{ + "swagger": "2.0", + "info": { + "title": "Go-Gin Prepack", + "contact": {}, + "version": "1" + }, + "basePath": "/v1", + "paths": { + "/adm/doot": { + "get": { + "description": "admin ping and login check", + "summary": "ping example", + "parameters": [ + { + "type": "string", + "description": "JWT Cookie set by /admin", + "name": "jwt", + "in": "header", + "required": true + } + ], + "responses": {} + } + }, + "/admin": { + "post": { + "description": "Secured login for any user accounts", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "User login", + "parameters": [ + { + "description": "user email", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "user password", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the 2fa token", + "name": "twofactorcode", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "headers": { + "jwt": { + "type": "string", + "description": "The authentication token for this session, valid for 24h" + } + } + }, + "400": { + "description": "userkey, 2fa token or password missing" + }, + "401": { + "description": "not found or credentials invalid" + } + } + } + }, + "/doot": { + "get": { + "description": "unauthenticated ping", + "summary": "ping example", + "responses": {} + } + }, + "/forgot": { + "post": { + "description": "Request a password reset for the provided userkey", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Forgot password", + "parameters": [ + { + "description": "user email to reset", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "userkey not provided" + } + } + } + }, + "/login": { + "post": { + "description": "Secured login for any user accounts", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "User login", + "parameters": [ + { + "description": "user email", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "user password", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the 2fa token for the user, if activated", + "name": "twofactorcode", + "in": "body", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "", + "headers": { + "jwt": { + "type": "string", + "description": "The authentication token for this session, valid for 24h" + } + } + }, + "400": { + "description": "userkey or password missing" + }, + "401": { + "description": "not found or credentials invalid" + } + } + } + }, + "/reset": { + "post": { + "description": "Use a JWT token to validate and reset a password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Password reset", + "parameters": [ + { + "description": "the token emailed to the user", + "name": "token", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "the new password value", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "token and password not provided" + }, + "401": { + "description": "bad token or user not found" + } + } + } + }, + "/sec/doot": { + "get": { + "description": "user ping and login check", + "summary": "ping example", + "parameters": [ + { + "type": "string", + "description": "JWT Cookie set by /login", + "name": "jwt", + "in": "header", + "required": true + } + ], + "responses": {} + } + }, + "/signup": { + "post": { + "description": "Sign a user up for a new account", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "User signup", + "parameters": [ + { + "description": "user email", + "name": "userkey", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "user password", + "name": "password", + "in": "body", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "" + }, + "400": { + "description": "userkey missing, or password missing or not strong enough" + } + } + } + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..18f357a --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,183 @@ +basePath: /v1 +info: + contact: {} + title: Go-Gin Prepack + version: "1" +paths: + /adm/doot: + get: + description: admin ping and login check + parameters: + - description: JWT Cookie set by /admin + in: header + name: jwt + required: true + type: string + responses: {} + summary: ping example + /admin: + post: + consumes: + - application/json + description: Secured login for any user accounts + parameters: + - description: user email + in: body + name: userkey + required: true + schema: + type: string + - description: user password + in: body + name: password + required: true + schema: + type: string + - description: the 2fa token + in: body + name: twofactorcode + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: "" + headers: + jwt: + description: The authentication token for this session, valid for 24h + type: string + "400": + description: userkey, 2fa token or password missing + "401": + description: not found or credentials invalid + summary: User login + /doot: + get: + description: unauthenticated ping + responses: {} + summary: ping example + /forgot: + post: + consumes: + - application/json + description: Request a password reset for the provided userkey + parameters: + - description: user email to reset + in: body + name: userkey + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: "" + "400": + description: userkey not provided + summary: Forgot password + /login: + post: + consumes: + - application/json + description: Secured login for any user accounts + parameters: + - description: user email + in: body + name: userkey + required: true + schema: + type: string + - description: user password + in: body + name: password + required: true + schema: + type: string + - description: the 2fa token for the user, if activated + in: body + name: twofactorcode + schema: + type: string + produces: + - application/json + responses: + "200": + description: "" + headers: + jwt: + description: The authentication token for this session, valid for 24h + type: string + "400": + description: userkey or password missing + "401": + description: not found or credentials invalid + summary: User login + /reset: + post: + consumes: + - application/json + description: Use a JWT token to validate and reset a password + parameters: + - description: the token emailed to the user + in: body + name: token + required: true + schema: + type: string + - description: the new password value + in: body + name: password + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: "" + "400": + description: token and password not provided + "401": + description: bad token or user not found + summary: Password reset + /sec/doot: + get: + description: user ping and login check + parameters: + - description: JWT Cookie set by /login + in: header + name: jwt + required: true + type: string + responses: {} + summary: ping example + /signup: + post: + consumes: + - application/json + description: Sign a user up for a new account + parameters: + - description: user email + in: body + name: userkey + required: true + schema: + type: string + - description: user password + in: body + name: password + required: true + schema: + type: string + produces: + - application/json + responses: + "200": + description: "" + "400": + description: userkey missing, or password missing or not strong enough + summary: User signup +swagger: "2.0" diff --git a/go.mod b/go.mod index 8cf54ab..1b33f75 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,17 @@ go 1.18 require github.com/gin-gonic/gin v1.7.7 require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/boombuler/barcode v1.0.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/spec v0.20.6 // indirect + github.com/go-openapi/swag v0.21.1 // indirect github.com/go-playground/locales v0.14.0 // indirect github.com/go-playground/universal-translator v0.18.0 // indirect github.com/go-playground/validator/v10 v10.10.1 // indirect @@ -15,17 +24,25 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leodido/go-urn v1.2.1 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-sqlite3 v1.14.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pquerna/otp v1.3.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/swaggo/swag v1.8.1 // indirect github.com/ugorji/go/codec v1.2.7 // indirect + github.com/urfave/cli/v2 v2.5.1 // indirect golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f // indirect - golang.org/x/sys v0.0.0-20220429121018-84afa8d3f7b3 // indirect + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 // indirect + golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect golang.org/x/text v0.3.7 // indirect + golang.org/x/tools v0.1.10 // indirect google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/sqlite v1.3.2 // indirect diff --git a/go.sum b/go.sum index 8eb939e..f9d0a7d 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,34 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs= github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= +github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU= @@ -33,6 +54,8 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -45,6 +68,11 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= @@ -56,23 +84,32 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI= +github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/urfave/cli/v2 v2.5.1 h1:YKwdkyA0xTBzOaP2G0DVxBnCheHGP+Y9VbKAs4K1Ess= +github.com/urfave/cli/v2 v2.5.1/go.mod h1:oDzoM7pVwz6wHn5ogWgFUU1s4VJayeQS+aEZDqXIEJs= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -80,6 +117,8 @@ golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -90,6 +129,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220429121018-84afa8d3f7b3 h1:kBsBifDikLCf5sUMbcD8p73OinDtAQWQp8+n7FiyzlA= golang.org/x/sys v0.0.0-20220429121018-84afa8d3f7b3/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -97,6 +138,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= @@ -104,6 +147,7 @@ google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscL google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -111,6 +155,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/sqlite v1.3.2 h1:nWTy4cE52K6nnMhv23wLmur9Y3qWbZvOBz+V4PrGAxg= gorm.io/driver/sqlite v1.3.2/go.mod h1:B+8GyC9K7VgzJAcrcXMRPdnMcck+8FgJynEehEPM16U= diff --git a/main.go b/main.go index a7ea0e6..1c33261 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,9 @@ func Migrate(g *gorm.DB) { g.AutoMigrate(&models.TotpUsage{}) } +// @title Go-Gin Prepack +// @version 1 +// @BasePath /v1 func main() { config.LoadConfig() @@ -33,7 +36,7 @@ func main() { scheduled.Schedule(func() (string, time.Duration) { err := database.Db.Where("used < ?", time.Now().Add(-24*time.Hour)).Delete(&models.TotpUsage{}).Error if err != nil { - return "purge failed: " + err.Error(), time.Hour + return "purge failed, trying again in one hour: " + err.Error(), time.Hour } return "purged old TOTP usages", time.Hour * 24 }) @@ -53,7 +56,6 @@ func main() { v1 := r.Group("/v1") - // Ping functionality v1.GET("/doot", controllers.UnauthRateLimit(), core.Doot()) // Standard user signup, verify, login and forgot/reset pw