aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Riedstra <mitch@riedstra.dev>2023-01-05 21:10:26 -0500
committerMitchell Riedstra <mitch@riedstra.dev>2023-01-05 21:10:26 -0500
commit1e1cd261dd9c944f595c9023c8aa3e76aae751af (patch)
tree7b18c557dc38cb0dcc99f15a489298c1bd54f40f
parentc71b37eb23d4c8af7ab983de34c6da5be9363f3a (diff)
downloadpaste-swagger.tar.gz
paste-swagger.tar.xz
Start on swagger docsswagger
-rwxr-xr-xbuild.sh10
-rw-r--r--docs/docs.go182
-rw-r--r--docs/swagger.json158
-rw-r--r--docs/swagger.yaml108
-rw-r--r--go.mod13
-rw-r--r--go.sum54
-rw-r--r--main.go129
7 files changed, 648 insertions, 6 deletions
diff --git a/build.sh b/build.sh
index 8ae273f..b4fe585 100755
--- a/build.sh
+++ b/build.sh
@@ -16,9 +16,13 @@ if ! git diff-index --quiet HEAD ; then
version="dirty: $version"
fi
-cd ui
-npm run build
-cd ..
+# cd ui
+# npm install
+# npm run build
+# cd ..
+
+go install github.com/swaggo/swag/cmd/swag@latest
+swag init
export CGO_ENABLED=0
diff --git a/docs/docs.go b/docs/docs.go
new file mode 100644
index 0000000..95e9128
--- /dev/null
+++ b/docs/docs.go
@@ -0,0 +1,182 @@
+// 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": {
+ "name": "Mitchell Riedstra",
+ "url": "https://riedstra.dev",
+ "email": "mitch@riedstra.dev"
+ },
+ "license": {
+ "name": "ISC"
+ },
+ "version": "{{.Version}}"
+ },
+ "host": "{{.Host}}",
+ "basePath": "{{.BasePath}}",
+ "paths": {
+ "/v0/del/{id}": {
+ "delete": {
+ "description": "Remove a paste from the filesystem",
+ "produces": [
+ "text/plain"
+ ],
+ "tags": [
+ "v0"
+ ],
+ "summary": "Deletes a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v0/view/{id}": {
+ "get": {
+ "description": "Fetches the contents of a paste if given an ID",
+ "produces": [
+ "text/plain"
+ ],
+ "tags": [
+ "v0"
+ ],
+ "summary": "View a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v1/del/{id}": {
+ "delete": {
+ "description": "Remove a paste from the filesystem",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "v1"
+ ],
+ "summary": "Deletes a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v1/getToken": {
+ "post": {
+ "description": "Returns an API key that's valid for a pre-determined amount of hours",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "v1"
+ ],
+ "summary": "Get an API key with valid credentials",
+ "parameters": [
+ {
+ "description": "User Credentials",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/main.Credentials"
+ }
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v1/view/{id}": {
+ "get": {
+ "description": "Fetches the contents of a paste if given an ID",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "v1"
+ ],
+ "summary": "View a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ }
+ },
+ "definitions": {
+ "main.Credentials": {
+ "description": "User's credentials",
+ "type": "object",
+ "properties": {
+ "Password": {
+ "type": "string"
+ },
+ "Username": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "securityDefinitions": {
+ "": {
+ "type": "apiKey",
+ "name": "Authorization",
+ "in": "header"
+ },
+ "BasicAuth": {
+ "type": "basic"
+ }
+ }
+}`
+
+// SwaggerInfo holds exported Swagger Info so clients can modify it
+var SwaggerInfo = &swag.Spec{
+ Version: "1.0",
+ Host: "",
+ BasePath: "/api",
+ Schemes: []string{},
+ Title: "Simple Pastebin API",
+ Description: "User's credentials",
+ 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..27c60a0
--- /dev/null
+++ b/docs/swagger.json
@@ -0,0 +1,158 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "description": "User's credentials",
+ "title": "Simple Pastebin API",
+ "contact": {
+ "name": "Mitchell Riedstra",
+ "url": "https://riedstra.dev",
+ "email": "mitch@riedstra.dev"
+ },
+ "license": {
+ "name": "ISC"
+ },
+ "version": "1.0"
+ },
+ "basePath": "/api",
+ "paths": {
+ "/v0/del/{id}": {
+ "delete": {
+ "description": "Remove a paste from the filesystem",
+ "produces": [
+ "text/plain"
+ ],
+ "tags": [
+ "v0"
+ ],
+ "summary": "Deletes a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v0/view/{id}": {
+ "get": {
+ "description": "Fetches the contents of a paste if given an ID",
+ "produces": [
+ "text/plain"
+ ],
+ "tags": [
+ "v0"
+ ],
+ "summary": "View a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v1/del/{id}": {
+ "delete": {
+ "description": "Remove a paste from the filesystem",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "v1"
+ ],
+ "summary": "Deletes a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v1/getToken": {
+ "post": {
+ "description": "Returns an API key that's valid for a pre-determined amount of hours",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "v1"
+ ],
+ "summary": "Get an API key with valid credentials",
+ "parameters": [
+ {
+ "description": "User Credentials",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/main.Credentials"
+ }
+ }
+ ],
+ "responses": {}
+ }
+ },
+ "/v1/view/{id}": {
+ "get": {
+ "description": "Fetches the contents of a paste if given an ID",
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "v1"
+ ],
+ "summary": "View a paste for a given ID",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "Paste ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {}
+ }
+ }
+ },
+ "definitions": {
+ "main.Credentials": {
+ "description": "User's credentials",
+ "type": "object",
+ "properties": {
+ "Password": {
+ "type": "string"
+ },
+ "Username": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "securityDefinitions": {
+ "": {
+ "type": "apiKey",
+ "name": "Authorization",
+ "in": "header"
+ },
+ "BasicAuth": {
+ "type": "basic"
+ }
+ }
+} \ No newline at end of file
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
new file mode 100644
index 0000000..bcff994
--- /dev/null
+++ b/docs/swagger.yaml
@@ -0,0 +1,108 @@
+basePath: /api
+definitions:
+ main.Credentials:
+ description: User's credentials
+ properties:
+ Password:
+ type: string
+ Username:
+ type: string
+ type: object
+info:
+ contact:
+ email: mitch@riedstra.dev
+ name: Mitchell Riedstra
+ url: https://riedstra.dev
+ description: User's credentials
+ license:
+ name: ISC
+ title: Simple Pastebin API
+ version: "1.0"
+paths:
+ /v0/del/{id}:
+ delete:
+ description: Remove a paste from the filesystem
+ parameters:
+ - description: Paste ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - text/plain
+ responses: {}
+ summary: Deletes a paste for a given ID
+ tags:
+ - v0
+ /v0/view/{id}:
+ get:
+ description: Fetches the contents of a paste if given an ID
+ parameters:
+ - description: Paste ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - text/plain
+ responses: {}
+ summary: View a paste for a given ID
+ tags:
+ - v0
+ /v1/del/{id}:
+ delete:
+ description: Remove a paste from the filesystem
+ parameters:
+ - description: Paste ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses: {}
+ summary: Deletes a paste for a given ID
+ tags:
+ - v1
+ /v1/getToken:
+ post:
+ consumes:
+ - application/json
+ description: Returns an API key that's valid for a pre-determined amount of
+ hours
+ parameters:
+ - description: User Credentials
+ in: body
+ name: request
+ required: true
+ schema:
+ $ref: '#/definitions/main.Credentials'
+ produces:
+ - application/json
+ responses: {}
+ summary: Get an API key with valid credentials
+ tags:
+ - v1
+ /v1/view/{id}:
+ get:
+ description: Fetches the contents of a paste if given an ID
+ parameters:
+ - description: Paste ID
+ in: path
+ name: id
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses: {}
+ summary: View a paste for a given ID
+ tags:
+ - v1
+securityDefinitions:
+ "":
+ in: header
+ name: Authorization
+ type: apiKey
+ BasicAuth:
+ type: basic
+swagger: "2.0"
diff --git a/go.mod b/go.mod
index 150eecf..1181110 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,19 @@ require (
)
require (
+ github.com/KyleBanks/depth v1.2.1 // 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.19.15 // indirect
github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/mailru/easyjson v0.7.6 // indirect
+ github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect
+ github.com/swaggo/http-swagger v1.3.3 // indirect
+ github.com/swaggo/swag v1.8.1 // indirect
+ golang.org/x/net v0.3.0 // indirect
golang.org/x/sys v0.3.0 // indirect
+ golang.org/x/tools v0.1.10 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
)
diff --git a/go.sum b/go.sum
index a0552d8..6d99f62 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,62 @@
+github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
+github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
+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/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 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
+github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/golang-jwt/jwt/v4 v4.4.3 h1:Hxl6lhQFj4AnOX6MLrsCb/+7tCj7DxP7VA+2rDIq5AU=
github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+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 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc=
+github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w=
+github.com/swaggo/http-swagger v1.3.3 h1:Hu5Z0L9ssyBLofaama21iYaF2VbWyA8jdohaaCGpHsc=
+github.com/swaggo/http-swagger v1.3.3/go.mod h1:sE+4PjD89IxMPm77FnkDz0sdO+p5lbXzrVWT6OTVVGo=
+github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI=
+github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+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=
+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/yaml.v2 v2.2.2/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=
diff --git a/main.go b/main.go
index d61be41..1def8f8 100644
--- a/main.go
+++ b/main.go
@@ -25,6 +25,9 @@ import (
jwt "github.com/golang-jwt/jwt/v4"
"golang.org/x/crypto/bcrypt"
"golang.org/x/term"
+
+ httpSwagger "github.com/swaggo/http-swagger"
+ _ "riedstra.dev/mitch/paste/docs"
)
// Default to the system umask
@@ -69,6 +72,20 @@ type Response struct {
Data any `json:",omitempty"`
}
+// @title Simple Pastebin API
+// @version 1.0
+// @description Simple pastebin backed by your filesystem
+// @contact.name Mitchell Riedstra
+// @contact.url https://riedstra.dev
+// @contact.email mitch@riedstra.dev
+// @license.name ISC
+// @BasePath /api
+//
+// @securityDefinitions.basic BasicAuth
+// @securitydefinitions.apikey
+// @in header
+// @name Authorization
+// @tokenURL /v1/login
func main() {
var (
listen = ":6130"
@@ -297,9 +314,14 @@ func (a *App) Handler() http.Handler {
"/api/v0/view/",
a.HandleViewPlain()),
+ "/api/v1/getToken": tokenHandler(a.users, a.jwtKey, a.sessionHours),
"/api/v1/login": loginHandler(a.users, a.jwtKey, a.sessionHours),
"/api/v1/logout": logoutHandler(),
+ "/swagger/": httpSwagger.Handler(
+ httpSwagger.URL("/swagger/doc.json"),
+ ),
+
"/_app/": http.FileServer(http.FS(a.static)),
"/": a.HandleIndex(a.static),
}
@@ -392,8 +414,8 @@ func genTokenKey() string {
// encoding the response status code in the header, JSON, and a friendly
// message as well as any other exported members of the Response struct.
func sendJSON(er Response) {
- er.w.WriteHeader(er.Code)
er.w.Header().Add("Content-type", "application/json")
+ er.w.WriteHeader(er.Code)
enc := json.NewEncoder(er.w)
enc.SetIndent("", " ")
_ = enc.Encode(er)
@@ -403,8 +425,8 @@ func sendJSON(er Response) {
// output verbatim unless the rdr is not nil, in which case the rdr
// is used instead
func sendPlain(r Response, rdr io.Reader) {
+ r.w.Header().Add("Content-type", "text/plain")
r.w.WriteHeader(r.Code)
- r.w.Header().Add("Content-type", "application/json")
if rdr != nil {
_, _ = io.Copy(r.w, rdr)
} else {
@@ -532,6 +554,66 @@ func (users UsersMap) AuthHandler(next http.Handler, jwtKey string,
})
}
+// Credentials
+//
+// @Description User's credentials
+type Credentials struct {
+ Username string `json:"Username"`
+ Password string `json:"Password"`
+}
+
+// tokenHandler
+//
+// @Summary Get an API key with valid credentials
+// @Description Returns an API key that's valid for a pre-determined amount of hours
+// @Tags v1
+// @Produce json
+// @Accept json
+// @Param request body Credentials true "User Credentials"
+// @Router /v1/getToken [post]
+func tokenHandler(users UsersMap, jwtKey string, sessionHours int,
+) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ sendJSON(Response{w, http.StatusBadRequest,
+ "Invalid type. POST only", nil})
+ return
+ }
+
+ dec := json.NewDecoder(r.Body)
+ in := &Credentials{}
+
+ err := dec.Decode(in)
+ if err != nil {
+ sendJSON(Response{w, http.StatusBadRequest, "Invalid request", nil})
+ return
+ }
+
+ if !users.IsValidLogin(in.Username, in.Password) {
+ sendJSON(Response{w, http.StatusUnauthorized,
+ "Invalid username or password", nil})
+ return
+ }
+ expires := time.Now().Add(time.Hour * time.Duration(sessionHours))
+
+ claims := &jwt.RegisteredClaims{
+ ExpiresAt: jwt.NewNumericDate(expires),
+ ID: in.Username,
+ }
+
+ token := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
+ ss, err := token.SignedString([]byte(jwtKey))
+ if err != nil {
+ sendJSON(Response{w, http.StatusInternalServerError,
+ "Invalid username or password", nil})
+ return
+ }
+
+ sendJSON(Response{w, http.StatusOK, "Ok",
+ struct{ Token string } { ss }})
+ })
+}
+
func loginHandler(users UsersMap, jwtKey string, sessionHours int,
) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -665,6 +747,14 @@ func getPastePathFromRawURL(storage, u string) string {
filepath.Clean(u), "/", ""))
}
+// HandleViewJSON
+//
+// @Summary View a paste for a given ID
+// @Description Fetches the contents of a paste if given an ID
+// @Tags v1
+// @Produce json
+// @Param id path string true "Paste ID"
+// @Router /v1/view/{id} [get]
func (a *App) HandleViewJSON() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pth := getPastePathFromRawURL(a.storage, r.URL.Path)
@@ -688,6 +778,14 @@ func (a *App) HandleViewJSON() http.Handler {
})
}
+// HandleViewPlain
+//
+// @Summary View a paste for a given ID
+// @Description Fetches the contents of a paste if given an ID
+// @Tags v0
+// @Produce text/plain
+// @Param id path string true "Paste ID"
+// @Router /v0/view/{id} [get]
func (a *App) HandleViewPlain() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pth := getPastePathFromRawURL(a.storage, r.URL.Path)
@@ -703,6 +801,16 @@ func (a *App) HandleViewPlain() http.Handler {
})
}
+// HandleDel
+//
+// @Summary Deletes a paste for a given ID
+// @Description Remove a paste from the filesystem
+// @Tags v0
+// @Produce text/plain
+// @Param id path string true "Paste ID"
+// @Router /v0/del/{id} [delete]
+// @securityDefinitions.basic BasicAuth
+// @securityDefinitions.apikey ApiKeyAuth
func (a *App) HandleDel() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
pth := getPastePathFromRawURL(a.storage, r.URL.Path)
@@ -724,9 +832,24 @@ func (a *App) HandleDel() http.Handler {
})
}
+// HandleDelJSON
+//
+// @Summary Deletes a paste for a given ID
+// @Description Remove a paste from the filesystem
+// @Tags v1
+// @Produce application/json
+// @Param id path string true "Paste ID"
+// @Router /v1/del/{id} [delete]
+// @securityDefinitions.basic BasicAuth
+// @name Authorization
func (a *App) HandleDelJSON() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- logger.Println("Made it to delete...")
+ if r.Method != "DELETE" {
+ sendJSON(Response{w, http.StatusMethodNotAllowed,
+ "Method not allowed", nil})
+ return
+ }
+
pth := getPastePathFromRawURL(a.storage, r.URL.Path)
logger.Println("Deleting path: ", pth)
err := os.Remove(pth)