Adding models, DB access, signup, login
* Created Base, Auth, User and Admin models * Added skeleton API structure containing: User signup, User & Admin login, authorized zones, ping tests * Simple user signup functional * Skeleton user login functional, no means to verify as of yet * Added POSTMAN file
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,3 +13,7 @@
|
|||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
# Dependency directories (remove the comment below to include it)
|
||||||
# vendor/
|
# vendor/
|
||||||
|
|
||||||
|
# Other
|
||||||
|
prepack.db
|
||||||
|
test_prepack.db
|
||||||
136
Prepack.postman_collection.json
Normal file
136
Prepack.postman_collection.json
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
{
|
||||||
|
"info": {
|
||||||
|
"_postman_id": "6485c58d-0675-4f5d-9eed-4c2ecd8174ae",
|
||||||
|
"name": "Prepack",
|
||||||
|
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||||
|
},
|
||||||
|
"item": [
|
||||||
|
{
|
||||||
|
"name": "V1 Doot",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "localhost:9091/v1/doot",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "9091",
|
||||||
|
"path": [
|
||||||
|
"v1",
|
||||||
|
"doot"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "V1 Secured Doot",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "localhost:9091/v1/sec/doot",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "9091",
|
||||||
|
"path": [
|
||||||
|
"v1",
|
||||||
|
"sec",
|
||||||
|
"doot"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "V1 Admin Doot",
|
||||||
|
"request": {
|
||||||
|
"method": "GET",
|
||||||
|
"header": [],
|
||||||
|
"url": {
|
||||||
|
"raw": "localhost:9091/v1/adm/doot",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "9091",
|
||||||
|
"path": [
|
||||||
|
"v1",
|
||||||
|
"adm",
|
||||||
|
"doot"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "V1 Signup",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"userkey\": \"NewUser\",\n \"password\": \"NewPass\"\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "localhost:9091/v1/signup",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "9091",
|
||||||
|
"path": [
|
||||||
|
"v1",
|
||||||
|
"signup"
|
||||||
|
],
|
||||||
|
"query": [
|
||||||
|
{
|
||||||
|
"key": "userkey",
|
||||||
|
"value": "NewUser",
|
||||||
|
"disabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "password",
|
||||||
|
"value": "NewPass",
|
||||||
|
"disabled": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "V1 User Login",
|
||||||
|
"request": {
|
||||||
|
"method": "POST",
|
||||||
|
"header": [],
|
||||||
|
"body": {
|
||||||
|
"mode": "raw",
|
||||||
|
"raw": "{\n \"userkey\": \"NewUser\",\n \"password\": \"NewPass\"\n}",
|
||||||
|
"options": {
|
||||||
|
"raw": {
|
||||||
|
"language": "json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"raw": "localhost:9091/v1/login",
|
||||||
|
"host": [
|
||||||
|
"localhost"
|
||||||
|
],
|
||||||
|
"port": "9091",
|
||||||
|
"path": [
|
||||||
|
"v1",
|
||||||
|
"login"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
58
database/database.go
Normal file
58
database/database.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/driver/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Database struct {
|
||||||
|
*gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
var Db *gorm.DB
|
||||||
|
|
||||||
|
func Init() *gorm.DB {
|
||||||
|
db, err := gorm.Open(sqlite.Open("prepack.db"), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO GORM settings
|
||||||
|
database, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
database.SetMaxIdleConns(10)
|
||||||
|
database.SetMaxOpenConns(50)
|
||||||
|
database.SetConnMaxLifetime(time.Minute * 30)
|
||||||
|
|
||||||
|
Db = db
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitTestDb() *gorm.DB {
|
||||||
|
db, err := gorm.Open(sqlite.Open("test_prepack.db"), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO GORM settings
|
||||||
|
database, err := db.DB()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
database.SetMaxIdleConns(10)
|
||||||
|
database.SetMaxOpenConns(50)
|
||||||
|
database.SetConnMaxLifetime(time.Minute * 30)
|
||||||
|
|
||||||
|
Db = db
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDb() *gorm.DB {
|
||||||
|
return Db
|
||||||
|
}
|
||||||
10
go.mod
10
go.mod
@@ -2,16 +2,22 @@ module github.com/yxzzy-wtf/gin-gonic-prepack
|
|||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
|
require github.com/gin-gonic/gin v1.7.7
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/gin-gonic/gin v1.7.7 // indirect
|
|
||||||
github.com/go-playground/locales v0.14.0 // indirect
|
github.com/go-playground/locales v0.14.0 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.0 // indirect
|
github.com/go-playground/universal-translator v0.18.0 // indirect
|
||||||
github.com/go-playground/validator/v10 v10.10.1 // indirect
|
github.com/go-playground/validator/v10 v10.10.1 // indirect
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
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/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // 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/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.7 // indirect
|
github.com/ugorji/go/codec v1.2.7 // indirect
|
||||||
@@ -20,4 +26,6 @@ require (
|
|||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
gorm.io/driver/sqlite v1.3.2 // indirect
|
||||||
|
gorm.io/gorm v1.23.5 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
16
go.sum
16
go.sum
@@ -15,12 +15,21 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
|
|||||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||||
github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig=
|
github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig=
|
||||||
github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
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/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
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 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
@@ -36,6 +45,8 @@ github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ic
|
|||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
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 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
|
||||||
|
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -96,3 +107,8 @@ 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.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-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=
|
||||||
|
gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||||
|
gorm.io/gorm v1.23.5 h1:TnlF26wScKSvknUC/Rn8t0NLLM22fypYBlvj1+aH6dM=
|
||||||
|
gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
|
||||||
|
|||||||
164
main.go
164
main.go
@@ -1,7 +1,169 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import _ "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/yxzzy-wtf/gin-gonic-prepack/database"
|
||||||
|
"github.com/yxzzy-wtf/gin-gonic-prepack/models"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
_ "github.com/golang-jwt/jwt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Migrate(g *gorm.DB) {
|
||||||
|
g.AutoMigrate(&models.User{})
|
||||||
|
g.AutoMigrate(&models.Admin{})
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
db := database.Init()
|
||||||
|
Migrate(db)
|
||||||
|
|
||||||
|
r := gin.Default()
|
||||||
|
v1 := r.Group("/v1")
|
||||||
|
|
||||||
|
// Ping functionality
|
||||||
|
v1.GET("/doot", doot())
|
||||||
|
|
||||||
|
// Standard user login
|
||||||
|
v1.POST("/signup", userSignup())
|
||||||
|
v1.POST("/login", userLogin())
|
||||||
|
v1Sec := v1.Group("/sec", userAuth())
|
||||||
|
|
||||||
|
v1Sec.GET("/doot", doot())
|
||||||
|
|
||||||
|
// Administrative login
|
||||||
|
v1.POST("/admin", adminLogin())
|
||||||
|
v1Admin := v1.Group("/adm", adminAuth())
|
||||||
|
|
||||||
|
v1Admin.GET("/doot", doot())
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
if err := http.ListenAndServe(":9091", r); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func doot() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, map[string]string{"snoot": "dooted"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type login struct {
|
||||||
|
UserKey string `json:"userkey" binding:"required"`
|
||||||
|
Password string `json:"password" binding:"required"`
|
||||||
|
TwoFactor string `json:"twofactorcode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type signup struct {
|
||||||
|
UserKey string `json:"userkey" binding:"required"`
|
||||||
|
Password string `json:"password" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type failmsg struct {
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
const JwtHeader = "jwt"
|
||||||
|
const ServicePath = "TODOPATH"
|
||||||
|
const ServiceDomain = "TODODOMAIN"
|
||||||
|
|
||||||
|
func userLogin() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var loginVals login
|
||||||
|
if err := c.ShouldBind(&loginVals); err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, failmsg{"Requires username and password"})
|
||||||
|
}
|
||||||
|
|
||||||
|
u := models.User{}
|
||||||
|
if err := u.ByEmail(loginVals.UserKey); err != nil {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := u.CheckPassword(loginVals.Password)
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = u.ValidateTwoFactor(loginVals.TwoFactor, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, failmsg{err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !u.Verified {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, failmsg{"not yet verified"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
jwt, maxAge := u.GetJwt()
|
||||||
|
c.SetCookie(JwtHeader, jwt, maxAge, ServicePath, ServiceDomain, true, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userSignup() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
var signupVals signup
|
||||||
|
if err := c.ShouldBind(&signupVals); err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, failmsg{"Requires username and password"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
u := models.User{
|
||||||
|
Email: signupVals.UserKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := u.SetPassword(signupVals.Password); err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusBadRequest, failmsg{"Bad password"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := database.Db.Model(&u).Create(&u).Error; err != nil {
|
||||||
|
if err.Error() == "UNIQUE constraint failed: users.email" {
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, failmsg{"already exists"})
|
||||||
|
} else {
|
||||||
|
fmt.Println(fmt.Errorf("error: %w", err))
|
||||||
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, map[string]string{"id": u.Uid.String()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminLogin() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userAuth() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
jwt := c.GetHeader(JwtHeader)
|
||||||
|
if jwt == "" {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, failmsg{"Requires `" + jwt + "` header"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func adminAuth() gin.HandlerFunc {
|
||||||
|
return func(c *gin.Context) {
|
||||||
|
jwt := c.GetHeader(JwtHeader)
|
||||||
|
if jwt == "" {
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, failmsg{"Requires `" + jwt + "` header"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
24
models/admin.go
Normal file
24
models/admin.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/yxzzy-wtf/gin-gonic-prepack/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Admin struct {
|
||||||
|
Auth
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Admin) GetJwt() (string, int) {
|
||||||
|
return "", 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Admin) ByEmail(email string) error {
|
||||||
|
if err := database.Db.Where("email = ?", email).First(&a).Error; err != nil {
|
||||||
|
return errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
43
models/auth.go
Normal file
43
models/auth.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
Base
|
||||||
|
PasswordHash string
|
||||||
|
TwoFactorSecret string
|
||||||
|
TwoFactorRecovery string
|
||||||
|
Verified bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) SetPassword(pass string) error {
|
||||||
|
passHash, _ := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost)
|
||||||
|
a.PasswordHash = string(passHash)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) CheckPassword(pass string) error {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(a.PasswordHash), []byte(pass))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Auth) ValidateTwoFactor(tfCode string, stamp time.Time) error {
|
||||||
|
if tfCode == "" && a.TwoFactorSecret != "" {
|
||||||
|
return errors.New("requires 2FA")
|
||||||
|
} else if tfCode == "" && a.TwoFactorSecret == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO two factor
|
||||||
|
if len(tfCode) == 6 {
|
||||||
|
// Test 2FA
|
||||||
|
return errors.New("2FA invalid")
|
||||||
|
} else {
|
||||||
|
// May be a renewal code
|
||||||
|
return errors.New("unlock invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
31
models/base.go
Normal file
31
models/base.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Base struct {
|
||||||
|
Uid uuid.UUID `gorm:"type:uuid;primary_key;"`
|
||||||
|
Created time.Time
|
||||||
|
Updated time.Time
|
||||||
|
Deleted time.Time `sql:"index"`
|
||||||
|
Tenant uuid.UUID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Base) BeforeCreate(scope *gorm.DB) error {
|
||||||
|
b.Uid = uuid.New()
|
||||||
|
b.Created = time.Now()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Base) BeforeSave(tx *gorm.DB) error {
|
||||||
|
b.Updated = time.Now()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Base) Delete() {
|
||||||
|
b.Deleted = time.Now()
|
||||||
|
}
|
||||||
24
models/user.go
Normal file
24
models/user.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/yxzzy-wtf/gin-gonic-prepack/database"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Auth
|
||||||
|
Email string `gorm:"unique"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) GetJwt() (string, int) {
|
||||||
|
return "", 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) ByEmail(email string) error {
|
||||||
|
if err := database.Db.Where("email = ?", email).First(&u).Error; err != nil {
|
||||||
|
return errors.New("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user