Merge pull request #3 from Floriansylvain/dev

Dev
This commit is contained in:
Florian Sylvain
2022-12-26 02:55:51 +01:00
committed by GitHub
33 changed files with 1518 additions and 903 deletions
View File
@@ -1,11 +1,12 @@
FROM node:latest as build-stage FROM node:latest as build-stage
WORKDIR /app WORKDIR /app
COPY package*.json ./ COPY ./web/admin-gui/package*.json ./
COPY ./.env ./
RUN npm install RUN npm install
COPY ./ . COPY ./web/admin-gui/ .
RUN npm run build RUN npm run build
FROM nginx as production-stage FROM nginx as production-stage
RUN mkdir /app RUN mkdir /app
COPY --from=build-stage /app/dist /app COPY --from=build-stage /app/dist /app
COPY nginx.conf /etc/nginx/nginx.conf COPY ./web/admin-gui/nginx.conf /etc/nginx/nginx.conf
+4 -2
View File
@@ -12,7 +12,9 @@ docker-compose up
TODO TODO
## Environment variables ## Environment variables
- ./env - ./env
- API_PORT - APP_HOST_ADDRESS
- FRONT_PORT - APP_API_PORT
- APP_FRONT_PORT
- APP_JWT_SECRET
## Demo ## Demo
TODO TODO
+48 -10
View File
@@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"os" "os"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -8,30 +9,67 @@ import (
"github.com/joho/godotenv" "github.com/joho/godotenv"
) )
var ginMode = os.Getenv("APP_GIN_MODE")
var apiPort = os.Getenv("APP_API_PORT")
var frontPort = os.Getenv("APP_FRONT_PORT")
var hostAddress = os.Getenv("APP_HOST_ADDRESS")
func initEnvVariables() { func initEnvVariables() {
if godotenv.Load() != nil { if godotenv.Load() != nil {
panic("Error loading .env file.") panic("Error loading .env file.")
} }
} }
func initJWT() {
errInit := internal.AuthMiddleware.MiddlewareInit()
if errInit != nil {
fmt.Printf(errInit.Error())
}
}
func initBasicRoutes(r *gin.Engine) {
r.POST("/login/", internal.AuthMiddleware.LoginHandler)
r.GET("/ping/", internal.Ping)
}
func corsMiddleware(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", fmt.Sprintf("http://%v:%v", hostAddress, frontPort))
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
func initArticlesRoutes(r *gin.Engine) {
articlesRouter := r.Group("/articles")
articlesRouter.Use(corsMiddleware, internal.AuthMiddleware.MiddlewareFunc())
articlesRouter.GET("/", internal.GetAllArticlesHandler)
articlesRouter.GET("/:id", internal.GetArticleHandler)
articlesRouter.POST("/:id", internal.AddArticleHandler)
articlesRouter.DELETE("/:id", internal.DeleteArticleHandler)
}
func initGin() { func initGin() {
r := gin.Default() r := gin.Default()
r.SetTrustedProxies([]string{"localhost"}) r.Use(corsMiddleware)
r.GET("/ping", internal.Ping) if ginMode == "release" {
gin.SetMode(ginMode)
}
r.GET("/articles/", internal.AuthCheck, internal.GetAllArticles) initBasicRoutes(r)
r.GET("/articles/:id", internal.AuthCheck, internal.GetArticle) initArticlesRoutes(r)
r.POST("/articles/:id", internal.AuthCheck, internal.AddArticle)
r.DELETE("/articles/:id", internal.AuthCheck, internal.DeleteArticle)
r.POST("/login", internal.LoginUser) r.Run(":" + apiPort)
r.POST("/logout", internal.LogoutUser)
r.Run(":" + os.Getenv("API_PORT"))
} }
func main() { func main() {
initEnvVariables() initEnvVariables()
initJWT()
initGin() initGin()
} }
+8 -4
View File
@@ -1,20 +1,24 @@
services: services:
backend: backend:
build: . build:
context: ./
dockerfile: ./Dockerfile.backend
image: gohcms-backend image: gohcms-backend
env_file: env_file:
- .env - .env
ports: ports:
- "${API_PORT}:8080" - "${APP_API_PORT}:${APP_API_PORT}"
networks: networks:
- back-net - back-net
frontend: frontend:
build: web/admin-gui/. build:
context: ./
dockerfile: ./Dockerfile.frontend
image: gohcms-frontend image: gohcms-frontend
env_file: env_file:
- .env - .env
ports: ports:
- "${FRONT_PORT}:80" - "${APP_FRONT_PORT}:80"
networks: networks:
- front-net - front-net
db: db:
+25 -20
View File
@@ -2,37 +2,42 @@ module github.com/gotest
go 1.19 go 1.19
require (
github.com/appleboy/gin-jwt/v2 v2.9.1
github.com/gin-gonic/gin v1.8.1
github.com/joho/godotenv v1.4.0
go.mongodb.org/mongo-driver v1.11.1
)
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.8.1 // 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.0 // indirect github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/goccy/go-json v0.9.7 // indirect github.com/goccy/go-json v0.10.0 // indirect
github.com/golang/snappy v0.0.1 // indirect github.com/golang-jwt/jwt/v4 v4.4.3 // indirect
github.com/joho/godotenv v1.4.0 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.6 // indirect github.com/klauspost/compress v1.15.13 // 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.16 // indirect
github.com/mattn/go-sqlite3 v1.14.15 // indirect github.com/mattn/go-sqlite3 v1.14.15 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // 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/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/montanaflynn/stats v0.6.6 // indirect
github.com/pelletier/go-toml/v2 v2.0.1 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect github.com/ugorji/go/codec v1.2.7 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
go.mongodb.org/mongo-driver v1.10.3 // indirect golang.org/x/crypto v0.4.0 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/net v0.4.0 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect golang.org/x/sync v0.1.0 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.3.0 // indirect
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 // indirect golang.org/x/text v0.5.0 // indirect
golang.org/x/text v0.3.7 // indirect google.golang.org/protobuf v1.28.1 // 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
) )
+74
View File
@@ -1,3 +1,6 @@
github.com/appleboy/gin-jwt/v2 v2.9.1 h1:l29et8iLW6omcHltsOP6LLk4s3v4g2FbFs0koxGWVZs=
github.com/appleboy/gin-jwt/v2 v2.9.1/go.mod h1:jwcPZJ92uoC9nOUTOKWoN/f6JZOgMSKlFSHw5/FrRUk=
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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.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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -12,13 +15,21 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0= github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ=
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
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/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/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/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/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=
@@ -28,6 +39,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
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=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.13 h1:NFn1Wr8cfnenSJSA46lLq4wHCcBzKTSjnBIexDMMOV0=
github.com/klauspost/compress v1.15.13/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
@@ -38,16 +51,24 @@ 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/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
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-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
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/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 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/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.6.6 h1:Duep6KMIDpY4Yo11iFsvyqJDyfzLF9+sndUKT+v64GQ=
github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -55,11 +76,19 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= 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/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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/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/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
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 v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0= 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/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
@@ -67,39 +96,84 @@ github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk=
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA=
go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8=
go.mongodb.org/mongo-driver v1.11.1 h1:QP0znIRTuL0jf1oBQoAoM0C6ZJfBK4kx0Uumtv1A7w8=
go.mongodb.org/mongo-driver v1.11.1/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069 h1:siQdpVirKtzPhKl3lZWozZraCFObP8S1v6PRp0bLrtU=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 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 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/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 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-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-119
View File
@@ -1,119 +0,0 @@
package internal
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
)
type Article struct {
Id_name string `json:"id_name" bson:"id_name"`
Date int64 `json:"date" bson:"date"`
Content interface{} `json:"content" bson:"content"`
}
type DelArticle struct {
Id_name string `json:"id_name" bson:"id_name"`
}
var ARTICLES_LOCATION = Location{Database: "gohcms", Collection: "articles"}
// TODO Change to GetArticleList that will find filter json context
func GetAllArticles(c *gin.Context) {
var articles []Article
documents, err := getDocuments(ARTICLES_LOCATION, bson.D{})
if err != nil {
SendBadRequest(c, err.Error())
return
}
for i := 0; i < len(documents); i++ {
var newArticle Article
bson.Unmarshal(documents[i], &newArticle)
articles = append(articles, newArticle)
}
c.JSON(http.StatusOK, articles)
}
func GetArticle(c *gin.Context) {
articleID := c.Params.ByName("id")
articles, err := getDocuments(ARTICLES_LOCATION,
bson.D{{Key: "id_name", Value: articleID}})
if err != nil {
SendBadRequest(c, err.Error())
return
}
if len(articles) == 0 {
SendBadRequest(c, "The ID provided doesn't match any article.")
return
}
var parsedArticle Article
bson.Unmarshal(articles[0], &parsedArticle)
c.JSON(http.StatusOK, parsedArticle)
}
func IsArticleIdAlreadyUsed(id string) bool {
documents, _ := getDocuments(ARTICLES_LOCATION, bson.D{})
for i := 0; i < len(documents); i++ {
var newArticle Article
bson.Unmarshal(documents[i], &newArticle)
if newArticle.Id_name == id {
return true
}
}
return false
}
func AddArticle(c *gin.Context) {
var article Article
article.Id_name = c.Params.ByName("id")
if c.BindJSON(&article) != nil {
SendBadRequest(c, "Could not correctly parse the article.")
return
}
document, err := bson.Marshal(article)
if err != nil {
SendBadRequest(c, "Could not correctly marshal the article.")
return
}
if IsArticleIdAlreadyUsed(article.Id_name) {
SendBadRequest(c, "Article ID already used.")
return
}
err = pushDocument(ARTICLES_LOCATION, document)
if err != nil {
SendBadRequest(c, "Could not insert document into DB.")
return
}
SendOk(c, "Article successfully added!")
}
func DeleteArticle(c *gin.Context) {
var delArticle DelArticle
delArticle.Id_name = c.Params.ByName("id")
if c.BindJSON(&delArticle) != nil {
SendBadRequest(c, "Could not correctly parse the article ID.")
return
}
document, err := bson.Marshal(delArticle)
if err != nil {
SendBadRequest(c, "Could not correctly marshal the article ID.")
return
}
deleteCount, err := deleteDocument(ARTICLES_LOCATION, document)
if err != nil {
SendBadRequest(c, "Could not insert document into DB.")
return
}
SendOk(c, fmt.Sprintf("%d articles were successfully deleted!", deleteCount))
}
+40
View File
@@ -0,0 +1,40 @@
package internal
import (
"go.mongodb.org/mongo-driver/bson"
)
type Article struct {
IdName string `json:"id_name" bson:"id_name"`
Date int64 `json:"date" bson:"date"`
Content interface{} `json:"content" bson:"content"`
}
type DelArticle struct {
IdName string `json:"id_name" bson:"id_name"`
}
var articlesLocation = Location{Database: "gohcms", Collection: "articles"}
func GetAllArticlesBusiness(documents [][]byte) []Article {
var articles = []Article{}
for i := 0; i < len(documents); i++ {
var newArticle Article
bson.Unmarshal(documents[i], &newArticle)
articles = append(articles, newArticle)
}
return articles
}
func IsArticleIdAlreadyUsed(id string, documents [][]byte) bool {
for i := 0; i < len(documents); i++ {
var newArticle Article
bson.Unmarshal(documents[i], &newArticle)
if newArticle.IdName == id {
return true
}
}
return false
}
+83
View File
@@ -0,0 +1,83 @@
package internal
import (
"fmt"
"net/http"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
)
func GetAllArticlesHandler(c *gin.Context) {
documents, err := getDocuments(articlesLocation, bson.D{})
if err != nil {
SendBadRequest(c, err.Error())
return
}
c.JSON(http.StatusOK, GetAllArticlesBusiness(documents))
}
func GetArticleHandler(c *gin.Context) {
articleID := c.Params.ByName("id")
article, err := getUniqueDocument(articlesLocation,
bson.D{{Key: "id_name", Value: articleID}})
if err != nil {
SendBadRequest(c, "The ID provided doesn't match any article.")
return
}
var parsedArticle Article
bson.Unmarshal(article, &parsedArticle)
c.JSON(http.StatusOK, parsedArticle)
}
func AddArticleHandler(c *gin.Context) {
var article Article
article.IdName = c.Params.ByName("id")
if c.BindJSON(&article) != nil {
SendBadRequest(c, "Could not correctly parse the article.")
return
}
document, err := bson.Marshal(article)
if err != nil {
SendBadRequest(c, "Could not correctly marshal the article.")
return
}
documents, _ := getDocuments(articlesLocation, gin.H{})
if IsArticleIdAlreadyUsed(article.IdName, documents) {
SendBadRequest(c, "Article ID already used.")
return
}
err = pushDocument(articlesLocation, document)
if err != nil {
SendBadRequest(c, fmt.Sprintf(`Could not insert document into DB: %v`, err.Error()))
return
}
SendOk(c, "Article successfully added!")
}
func DeleteArticleHandler(c *gin.Context) {
var delArticle DelArticle
delArticle.IdName = c.Params.ByName("id")
if c.BindJSON(&delArticle) != nil {
SendBadRequest(c, "Could not correctly parse the article ID.")
return
}
document, err := bson.Marshal(delArticle)
if err != nil {
SendBadRequest(c, "Could not correctly marshal the article ID.")
return
}
deleteCount, err := deleteDocument(articlesLocation, document)
if err != nil {
SendBadRequest(c, "Could not insert document into DB.")
return
}
SendOk(c, fmt.Sprintf("%d articles were successfully deleted!", deleteCount))
}
+42
View File
@@ -0,0 +1,42 @@
package internal
import (
"log"
"testing"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
)
var Article1, _ = bson.Marshal(Article{
IdName: "test_article_1",
Date: 1671482492,
Content: gin.H{},
})
var Article2, _ = bson.Marshal(Article{
IdName: "test_article_2",
Date: 1671899112,
Content: gin.H{},
})
var BSONConvertedArticles = [][]byte{Article1, Article2}
func TestGetAllArticlesBusiness(t *testing.T) {
documents := GetAllArticlesBusiness(BSONConvertedArticles)
article := documents[0]
if article.IdName != "test_article_1" {
log.Fatalf(`Excepted "test_article_1" as IdName, found "%v"`, article.IdName)
} else if article.Date != 1671482492 {
log.Fatalf(`Excepted 1671482492 as Date, found "%v"`, article.Date)
}
}
func TestIsArticleIdAlreadyUsed(t *testing.T) {
if IsArticleIdAlreadyUsed("test_article_1", BSONConvertedArticles) == false {
log.Fatalf(`Excepted true, found false`)
} else if IsArticleIdAlreadyUsed("test_article_3", BSONConvertedArticles) == true {
log.Fatalf(`Excepted false, found true`)
}
}
+23 -83
View File
@@ -1,11 +1,13 @@
package internal package internal
import ( import (
"crypto/sha256"
"errors" "errors"
"fmt" "os"
"time"
jwt "github.com/appleboy/gin-jwt/v2"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson"
) )
type User struct { type User struct {
@@ -13,92 +15,30 @@ type User struct {
Password string `json:"password" bson:"password"` Password string `json:"password" bson:"password"`
} }
var USERS_LOCATION = Location{Database: "gohcms", Collection: "users"} var UsersLocation = Location{Database: "gohcms", Collection: "users"}
func getUserHashedPassword(user User) string { var AuthMiddleware, _ = jwt.New(&jwt.GinJWTMiddleware{
password := sha256.New() Realm: "GohCMS",
password.Write([]byte(user.Password)) Key: []byte(os.Getenv("APP_JWT_SECRET")),
return fmt.Sprintf("%x", password.Sum(nil)) Timeout: time.Hour,
} MaxRefresh: time.Hour,
Authenticator: JWTAuthenticator,
})
func isUserLoggedIn(user User) bool { func JWTAuthenticator(c *gin.Context) (interface{}, error) {
for i := 0; i < len(SESSIONS); i++ { var user = User{}
hash1 := fmt.Sprint(SESSIONS[i].Token.Sum(nil)) err := c.BindJSON(&user)
hash2 := fmt.Sprint(generateSessionToken(user).Sum(nil))
if hash1 != hash2 {
continue
}
sessionExpired := isSessionExpired(SESSIONS[i])
if sessionExpired {
removeSession(user)
}
return !sessionExpired
}
return false
}
func isUserReal(user User) bool {
docUsers, _ := getDocuments(USERS_LOCATION, user)
return len(docUsers) == 1
}
func parseUserFromContext(c *gin.Context) (User, error) {
var user User
if c.BindJSON(&user) != nil {
return User{}, errors.New("could not correctly parse user crendentials")
}
user.Password = getUserHashedPassword(user)
return user, nil
}
func LoginUser(c *gin.Context) {
user, err := parseUserFromContext(c)
if err != nil { if err != nil {
SendBadRequest(c, err.Error()) return nil, errors.New("wrong credentials json format.")
return
} }
if isUserLoggedIn(user) {
SendBadRequest(c, "User is already logged in!")
return
}
if !isUserReal(user) {
SendBadRequest(c, "Unknown email or wrong password.")
return
}
addSession(user)
SendOk(c, "User successfully logged in.")
}
func LogoutUser(c *gin.Context) { _, err = getUniqueDocument(UsersLocation, bson.D{
user, err := parseUserFromContext(c) {Key: "email", Value: user.Email},
{Key: "password", Value: user.Password},
})
if err != nil { if err != nil {
SendBadRequest(c, err.Error()) return nil, errors.New("wrong email or password.")
return
}
if !isUserLoggedIn(user) {
SendBadRequest(c, "User is not logged in!")
return
}
removeSession(user)
SendOk(c, "User successfully logged out.")
}
func AuthCheck(c *gin.Context) {
var user User
username, password, isOk := c.Request.BasicAuth()
if !isOk {
SendBadRequest(c, "Incorrect or missing user credentials.")
c.Abort()
return
}
user.Email = username
user.Password = password
user.Password = getUserHashedPassword(user)
if !isUserLoggedIn(user) {
SendForbidden(c, "Authentification failed, credentials could be wrong, user may not be logged in, session may have expired.")
c.Abort()
return
} }
return gin.H{"email": user.Email}, nil
} }
+12
View File
@@ -52,6 +52,18 @@ func getDocuments(location Location, filter interface{}) ([][]byte, error) {
return results, nil return results, nil
} }
func getUniqueDocument(location Location, filter interface{}) ([]byte, error) {
client := getNewClient()
collection := client.Database(location.Database).Collection(location.Collection)
defer client.Disconnect(context.TODO())
singleResult := collection.FindOne(context.TODO(), filter)
if singleResult.Err() != nil {
return nil, errors.New("no document was found, check the filter or the location.")
}
return singleResult.DecodeBytes()
}
func deleteDocument(location Location, filter interface{}) (int64, error) { func deleteDocument(location Location, filter interface{}) (int64, error) {
client := getNewClient() client := getNewClient()
collection := client.Database(location.Database).Collection(location.Collection) collection := client.Database(location.Database).Collection(location.Collection)
-49
View File
@@ -1,49 +0,0 @@
package internal
import (
"crypto"
"fmt"
"hash"
"time"
)
type Session struct {
Token hash.Hash `json:"token"`
ExpirationTimestamp int64 `json:"expirationTimestamp"`
}
var SESSIONS []Session
const SESSION_DURATION int64 = 3600
func generateSessionToken(user User) hash.Hash {
token := crypto.SHA256.New()
stringToHash := fmt.Sprintf(user.Email + user.Password)
token.Write([]byte(stringToHash))
return token
}
func isSessionExpired(session Session) bool {
return session.ExpirationTimestamp < time.Now().Unix()
}
func addSession(user User) {
SESSIONS = append(SESSIONS, Session{
Token: generateSessionToken(user),
ExpirationTimestamp: time.Now().Unix() + SESSION_DURATION,
})
}
func removeSession(user User) {
index := 0
sessLen := len(SESSIONS)
for i := 0; i < sessLen; i++ {
if SESSIONS[i].Token == generateSessionToken(user) {
index = i
break
}
}
SESSIONS[index] = SESSIONS[sessLen-1]
SESSIONS[sessLen-1] = Session{}
SESSIONS = SESSIONS[:sessLen-1]
}
+5
View File
@@ -42,3 +42,8 @@ db.createCollection('users', {
} }
} }
}) })
db.users.insertOne({
email: "root",
password: "root"
})
+1
View File
@@ -1 +1,2 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
declare const __APP_ENV__: Record<string, string>
+565 -509
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -9,7 +9,7 @@
"type-check": "vue-tsc --noEmit" "type-check": "vue-tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"pinia": "^2.0.21", "pinia": "^2.0.28",
"vue": "^3.2.38", "vue": "^3.2.38",
"vue-editor-js": "^2.0.2", "vue-editor-js": "^2.0.2",
"vue-router": "^4.1.5" "vue-router": "^4.1.5"
+4 -2
View File
@@ -1,7 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { RouterView } from 'vue-router' import { RouterView, useRoute } from 'vue-router'
import Navbar from './components/Navbar.vue';
</script> </script>
<template> <template>
<RouterView /> <Navbar v-if="useRoute().name !== 'login'"></Navbar>
<RouterView />
</template> </template>
+116
View File
@@ -0,0 +1,116 @@
@import url('https://fonts.googleapis.com/css2?family=Frank+Ruhl+Libre:wght@500&family=Hind:wght@400;500;600;700&family=Nunito:wght@500;600;700&display=swap');
:root {
--regular-weight: 400;
--medium-weight: 500;
--semibold-weight: 600;
--bold-weight: 700;
--radius: 15px;
--font-body: 16px;
--font-small: 14px;
--font-verysmall: 12px;
--primary: #2CD358;
--primary-dark: #00BA2A;
--primary-light: #97E6A2;
--secondary: #D32CA6;
--secondary-dark: #BA0094;
--secondary-light: #E88DCA;
--neutral-dark: #121212;
--neutral-medium: #707070;
--neutral-light: #aaaaaa;
--neutral-verylight: #e7e7e7;
--brand-blue: #00ACD7;
--error: #E80000;
}
body {
margin: 0;
}
h1 {
font-family: 'Frank Ruhl Libre', serif;
font-size: 40px;
}
h2 { font-size: 32px; }
h3 { font-size: 24px; }
h4 { font-size: 18px; }
h2, h3, h4, h5, h6 {
font-family: 'Nunito', sans-serif;
}
* {
font-family: 'Hind', sans-serif;
color: var(--neutral-dark);
box-sizing: border-box;
}
.label-input,
.label-input-error {
display: flex;
flex-direction: column;
}
.label-input label,
.label-input-error label {
font-size: var(--font-body);
font-weight: var(--semibold-weight);
}
.label-input p,
.label-input-error p {
color: var(--neutral-medium);
font-size: var(--font-body);
font-weight: var(--medium-weight);
margin: 0;
}
.label-input input,
.label-input-error input {
padding: 3px 16px;
font-size: var(--font-body);
border: solid 1.25px var(--neutral-light);
border-radius: var(--radius);
}
.label-input-error input {
border: solid 1.75px var(--error);
}
.label-input-error p {
color: var(--error);
}
.button-primary,
.button-disabled {
border-radius: var(--radius);
border: none;
padding: 3px 16px;
font-size: var(--font-body);
font-weight: var(--medium-weight);
background-color: var(--primary);
transition: background-color 150ms;
cursor: pointer;
}
.button-primary:hover {
background-color: var(--primary-light);
}
.button-primary:active {
background-color: var(--primary-dark);
}
.button-disabled {
color: var(--neutral-dark);
background-color: var(--neutral-light);
cursor: default;
}
View File
+79
View File
@@ -0,0 +1,79 @@
<script setup lang="ts">
import { useAuthStore } from '@/stores/AuthStore';
import { deleteCookie } from '@/utils/cookies';
import { RouterLink, useRouter } from 'vue-router'
const router = useRouter()
function logout() {
deleteCookie('JWTtoken')
deleteCookie('JWTexpire')
useAuthStore().clearAll()
router.push('/')
}
</script>
<template>
<header>
<h2><span style="color:var(--brand-blue)">Go</span>hCMS</h2>
<nav>
<RouterLink to="/home">Accueil</RouterLink>
<RouterLink to="/articles">Articles</RouterLink>
<a class="disconnect-link" @click="logout()">Se déconnecter</a>
</nav>
</header>
</template>
<style scoped>
header {
display: flex;
align-items: center;
padding: 0 24px;
box-shadow: #0005 0 0 10px;
width: 100%;
}
header h2 {
margin: 0;
padding: 10px 0;
width: fit-content;
color: var(--neutral-dark);
}
header h2 span {
font-family: inherit;
}
header nav {
display: flex;
gap: 16px;
width: 100%;
padding: 20px;
}
header nav a {
text-decoration: none;
border-radius: var(--radius);
padding: 4px 16px;
cursor: pointer;
transition: 150ms background-color;
}
header nav a:hover {
background-color: var(--neutral-verylight);
}
.disconnect-link {
margin-left: auto;
}
.disconnect-link:hover {
background-color: #fff;
color: var(--error);
}
</style>
+1 -2
View File
@@ -1,11 +1,10 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import './assets/main.css' import '@/assets/base.css'
const app = createApp(App) const app = createApp(App)
+62 -9
View File
@@ -1,15 +1,68 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory, type NavigationGuard } from 'vue-router'
import { useAuthStore } from '@/stores/AuthStore'
import { nextTick } from 'vue'
import Debug from '@/views/Debug.vue'
import Login from '@/views/Login.vue'
import Home from '@/views/Home.vue' import Home from '@/views/Home.vue'
import Articles from '@/views/Articles.vue'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
routes: [ routes: [
{ {
path: '/', path: '/',
name: 'home', name: 'login',
component: Home component: Login,
}, meta: {
] title: 'GohCMS - Connexion'
}
},
{
path: '/debug',
name: 'debug',
component: Debug,
meta: {
title: 'GohCMS - Debug'
}
},
{
path: '/home',
name: 'home',
component: Home,
meta: {
title: 'GohCMS - Accueil'
}
},
{
path: '/articles',
name: 'articles',
component: Articles,
meta: {
title: 'GohCMS - Articles'
}
},
]
})
router.beforeEach(async (to, from) => {
const isTokenValid = useAuthStore().isValid()
if (to.name === 'login') {
if (isTokenValid) return {
name: 'home'
}
} else {
if (!isTokenValid) {
return {
name: 'login',
}
}
}
})
router.afterEach((to, from) => {
nextTick(() => {
document.title = to.meta.title as string ?? 'GohCMS'
})
}) })
export default router export default router
+52
View File
@@ -0,0 +1,52 @@
import { getCookie } from "@/utils/cookies";
import { defineStore } from "pinia";
import { ref } from "vue";
import { useErrorsStore } from "./ErrorsStore";
export interface jwtFormat {
code: number,
expire: string,
token: string
}
export const useAuthStore = defineStore("AuthStore", () => {
const expire = ref('')
const token = ref('')
function clearAll(): void {
expire.value = ''
token.value = ''
}
function isSet(): boolean {
return token.value !== undefined && token.value !== ''
}
function isExpired(): boolean {
const tokenDate = new Date(expire.value)
const currentDate = new Date()
if (currentDate.getTime() > tokenDate.getTime()) {
useErrorsStore().sessionExpired = true
return true
}
return false
}
function isValid(): boolean {
return isSet() && !isExpired()
}
function initStore(): void {
const JWTtoken = getCookie('JWTtoken')
const JWTexpire = getCookie('JWTexpire')
if (JWTtoken !== "" && JWTexpire !== "") {
token.value = JWTtoken
expire.value = JWTexpire
}
}
initStore()
return { expire, token, isValid, clearAll }
})
+14
View File
@@ -0,0 +1,14 @@
import { defineStore } from "pinia";
import { ref, type Ref } from "vue";
interface storeErrors {
sessionExpired: boolean
}
export const useErrorsStore = defineStore("ErrorsStore", () => {
const errors: Ref<storeErrors> = ref({
sessionExpired: false
})
return errors
})
+21
View File
@@ -0,0 +1,21 @@
export interface cookie {
key: string,
value: string,
expire: string
}
export function setCookie(cookieData: cookie): void {
document.cookie = `${cookieData.key}=${cookieData.value}; SameSite=Strict; Expires=${cookieData.expire};Secure`
}
export function getCookie(cookieName: string): string {
return document.cookie.match('(^|;)\\s*' + cookieName + '\\s*=\\s*([^;]+)')?.pop() || ''
}
export function deleteCookie(cookieName: string): void {
setCookie({
key: cookieName,
value: '',
expire: new Date(0).toString()
})
}
-11
View File
@@ -1,11 +0,0 @@
export interface Pong {
message: string;
}
export async function pingApi(): Promise<String> {
let result: String = ''
await fetch('http://localhost:8080/ping')
.then(response => response.json())
.then(jsonResponse => result = jsonResponse.message)
return result
}
+11
View File
@@ -0,0 +1,11 @@
<script setup lang="ts">
</script>
<template>
<p>articles page</p>
</template>
<style scoped>
</style>
+71
View File
@@ -0,0 +1,71 @@
<script setup lang="ts">
// import EditorJS from '@editorjs/editorjs';
import { useAuthStore, type jwtFormat } from '@/stores/AuthStore';
import { ref } from 'vue';
const email = ref('')
const password = ref('')
const baseURL = `http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}`
function getArticles() {
fetch(`${baseURL}/articles/`, {
headers: { "Authorization": `Bearer ${useAuthStore().token}` }
})
.then(response => response.json())
.then(result => console.log(result))
}
function ping() {
fetch(`${baseURL}/ping/`, {
headers: { "Authorization": `Bearer ${useAuthStore().token}` }
})
.then(response => response.json())
.then(result => console.log(result))
}
function jwtHandler(apiResponse: jwtFormat): void {
if (apiResponse.code !== 200) {
console.log(apiResponse)
return
}
useAuthStore().token = apiResponse.token
useAuthStore().expire = apiResponse.expire
console.log('success! logged in.')
}
function login(email: string, password: string): void {
fetch(`${baseURL}/login/`, {
method: "POST",
body: JSON.stringify({
email: email,
password: password
})
})
.then(response => response.json())
.then(result => jwtHandler(result))
}
</script>
<template>
<h2>Connexion</h2>
<form @submit.prevent="login(email, password)">
<div>
<label for="email">Email address</label>
<input id="email" name="email" placeholder="email" type="text" v-model="email">
</div>
<div>
<label for="password">Password</label>
<input id="password" name="password" placeholder="password" type="password" v-model="password">
</div>
<button type="submit">Se connecter</button>
</form>
<div>
<div>
<button class="button-primary" @click="getArticles()">get all articles</button>
<button class="button-primary" @click="ping()">ping</button>
</div>
</div>
</template>
+1 -70
View File
@@ -1,77 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
// import EditorJS from '@editorjs/editorjs';
import { pingApi } from '@/utils/ping';
import { onMounted, ref } from 'vue';
const inputArticleID = ref('')
const username = ref('')
const password = ref('')
onMounted(async function() {
console.log('ping...')
const pong = await pingApi()
console.log(pong)
})
function addArticle() {
fetch(`http://localhost:8080/articles/${Math.random() * 100}`, {
method: "POST",
headers: {"Authorization" : `Basic ${btoa(`${username.value}:${password.value}`)}`},
body: JSON.stringify({
content: {},
date: new Date().getTime()
})
})
.then(response => response.json())
.then(result => console.log(result))
}
function deleteArticle(articleID: String) {
fetch(`http://localhost:8080/articles/${articleID}`, {
method: "DELETE",
headers: {"Authorization" : `Basic ${btoa(`${username.value}:${password.value}`)}`},
body: JSON.stringify({
id_name: articleID
})
})
.then(response => response.json())
.then(result => console.log(result))
}
function getArticle(articleID: String) {
fetch(`http://localhost:8080/articles/${articleID}`, {
headers: {"Authorization" : `Basic ${btoa(`${username.value}:${password.value}`)}`},
})
.then(response => response.json())
.then(result => console.log(result))
}
function auth(type: string, username: string, password: string) {
fetch(`http://localhost:8080/${type}`, {
method: "POST",
body: JSON.stringify({
email: username,
password: password
})
})
.then(response => response.json())
.then(result => console.log(result))
}
</script> </script>
<template> <template>
<p>Salut à tous</p> <p>home page</p>
<button @click="addArticle">add rand article</button>
<button @click="getArticle('')">display articles in console</button> <br>
<label for="articleIDinput"></label>
<input id="articleIDinput" name="articleIDinput" type="text" placeholder="article ID" v-model="inputArticleID">
<button @click="deleteArticle(inputArticleID)">delete this article</button>
<button @click="getArticle(inputArticleID)">get this article</button> <br>
<input type="text" name="username" id="username" v-model="username" placeholder="username">
<input type="text" name="password" id="password" v-model="password" placeholder="password">
<button @click="auth('login', username, password)">login</button>
<button @click="auth('logout', username, password)">logout</button>
</template> </template>
<style scoped> <style scoped>
+129
View File
@@ -0,0 +1,129 @@
<script setup lang="ts">
import { useAuthStore, type jwtFormat } from '@/stores/AuthStore';
import { useErrorsStore } from '@/stores/ErrorsStore';
import { setCookie } from '@/utils/cookies';
import { ref, type Ref } from 'vue';
import { useRouter } from 'vue-router';
const isTokenOK: Ref<boolean|undefined> = ref(undefined)
const router = useRouter()
const authStore = useAuthStore()
const email = ref('')
const password = ref('')
const isFormEmpty: ()=>boolean = () => {
return email.value === '' || password.value === ''
}
function updateJWTcookies(JWTdata: jwtFormat): void {
const cookieExpire = new Date(JWTdata.expire)
cookieExpire.setDate(cookieExpire.getDate() + 1)
setCookie({
key: 'JWTtoken',
value: JWTdata.token,
expire: cookieExpire.toString()
})
setCookie({
key: 'JWTexpire',
value: JWTdata.expire,
expire: cookieExpire.toString()
})
}
function disableErrors(): void {
useErrorsStore().sessionExpired = false
}
function jwtHandler(apiResponse: jwtFormat): void {
if (apiResponse.code !== 200) {
console.error(apiResponse)
isTokenOK.value = false
return
}
updateJWTcookies(apiResponse)
disableErrors()
authStore.token = apiResponse.token
authStore.expire = apiResponse.expire
isTokenOK.value = true
}
function login(email: string, password: string): void {
fetch(`http://${__APP_ENV__.APP_HOST_ADDRESS}:${__APP_ENV__.APP_API_PORT}/login/`, {
method: "POST",
body: JSON.stringify({
email: email,
password: password
})
})
.then(response => response.json())
.then(result => {
jwtHandler(result)
if (isTokenOK.value === true) {
router.push('/home')
}
})
}
</script>
<template>
<div class="login-page">
<div class="login-form">
<h2>Connexion à <span style="color:var(--brand-blue)">Go</span>hCMS</h2>
<form @submit.prevent="login(email, password)">
<div class="inputs-group">
<div :class="`label-input${isTokenOK === false ? '-error' : ''}`">
<label for="email">Adresse mail</label>
<input id="email" name="email" placeholder="E-mail" type="text" v-model="email">
</div>
<div :class="`label-input${isTokenOK === false ? '-error' : ''}`">
<label for="password">Mot de passe</label>
<input id="password" name="password" placeholder="Mot de passe" type="password" v-model="password">
<p v-if="isTokenOK === false"> E-mail et/ou mot de passe incorrect(s).</p>
<p v-else-if="useErrorsStore().sessionExpired"> Votre session a expiré.</p>
</div>
</div>
<button :class="`button-${isFormEmpty() ? 'disabled' : 'primary'}`" type="submit" :disabled="isFormEmpty()">
Se connecter
</button>
</form>
</div>
</div>
</template>
<style scoped>
h2 {
margin: 0 0 16px 0;
}
h2 span {
font-family: inherit;
}
.login-page {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.login-form {
width: fit-content;
max-width: 100%;
padding: 32px;
}
.inputs-group,
.login-form form {
display: flex;
flex-direction: column;
gap: 8px;
}
.login-form form {
gap: 32px;
}
</style>
+22 -9
View File
@@ -1,14 +1,27 @@
import { fileURLToPath, URL } from 'node:url' import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue' import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig(({ command, mode }) => {
plugins: [vue()], const env1 = loadEnv(mode, "./../../", "")
resolve: { const env2 = loadEnv(mode, process.cwd(), "")
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)) return {
} plugins: [vue()],
} resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
define: {
__APP_ENV__: {
...env1,
...env2,
}
},
server: {
port: env1.APP_FRONT_PORT,
}
}
}) })