Added checking JWT-tokens using fiber lib.
This commit is contained in:
parent
e99d452f8d
commit
1980e45fde
@ -1,13 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
jwtware "github.com/gofiber/contrib/jwt"
|
||||||
"go.uber.org/zap"
|
"github.com/gofiber/fiber/v2"
|
||||||
"os"
|
"github.com/sirupsen/logrus"
|
||||||
"reader/internal/config"
|
"reader/internal/handlers"
|
||||||
logger "reader/internal/log"
|
|
||||||
"reader/internal/metrics"
|
|
||||||
"reader/internal/unpacker"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -15,29 +12,54 @@ func main() {
|
|||||||
//
|
//
|
||||||
//http.HandleFunc("GET /api/v1/download/", handlers.Download) // example request: {"date": "07-03-2025", "start_time": "16-43", "end_time": "16-44"}
|
//http.HandleFunc("GET /api/v1/download/", handlers.Download) // example request: {"date": "07-03-2025", "start_time": "16-43", "end_time": "16-44"}
|
||||||
//http.HandleFunc("GET /api/v1/hls/", handlers.HLS)
|
//http.HandleFunc("GET /api/v1/hls/", handlers.HLS)
|
||||||
//http.HandleFunc("GET /api/v1/vods/", handlers.ListVodsHandler)
|
|
||||||
//http.HandleFunc("GET /api/v1/vods/{id}/", handlers.ConfigVodsHandler)
|
|
||||||
//http.HandleFunc("DELETE /api/v1/vods/{id}/", handlers.DelVodsHandler)
|
|
||||||
//http.HandleFunc("GET /api/v1/vods/{id}/files/", handlers.ListFilesVodsHandler)
|
|
||||||
//http.HandleFunc("GET /api/v1/vods/{id}/{res}/{file}", handlers.SingleVodsHandler)
|
|
||||||
//http.HandleFunc("DELETE /api/v1/vods/{id}/{res}/{file}", handlers.DelSingleVodsHandler)
|
|
||||||
//
|
|
||||||
//log.Println("Starting server on:")
|
//log.Println("Starting server on:")
|
||||||
//log.Printf("Serving on HTTP port: %d\n", port)
|
//log.Printf("Serving on HTTP port: %d\n", port)
|
||||||
//
|
//
|
||||||
//log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
//log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
|
||||||
|
|
||||||
go metrics.Metrics()
|
//go metrics.Metrics()
|
||||||
logger.StartMainLogger(config.Local, "reader")
|
//logger.StartMainLogger(config.Local, "reader")
|
||||||
|
//
|
||||||
|
//// Check if the data folder in the directory.
|
||||||
|
//homeDir, err := os.UserHomeDir()
|
||||||
|
//if err != nil {
|
||||||
|
//}
|
||||||
|
//config.DirData = fmt.Sprintf("%s/%s/vod", homeDir, config.Local)
|
||||||
|
//
|
||||||
|
//err = unpacker.CreateVideo()
|
||||||
|
//if err != nil {
|
||||||
|
// logger.Log.Error("failed to create flow", zap.Error(err))
|
||||||
|
//}
|
||||||
|
|
||||||
// Check if the data folder in the directory.
|
app := fiber.New()
|
||||||
homeDir, err := os.UserHomeDir()
|
|
||||||
if err != nil {
|
|
||||||
}
|
|
||||||
config.DirData = fmt.Sprintf("%s/%s/vod", homeDir, config.Local)
|
|
||||||
|
|
||||||
err = unpacker.CreateVideo()
|
authStorage := &handlers.AuthStorage{map[string]handlers.User{}}
|
||||||
if err != nil {
|
authHandler := &handlers.AuthHandler{Storage: authStorage}
|
||||||
logger.Log.Error("failed to create flow", zap.Error(err))
|
userHandler := &handlers.UserHandler{Storage: authStorage}
|
||||||
}
|
|
||||||
|
// Группа обработчиков, которые доступны неавторизованным пользователям
|
||||||
|
publicGroup := app.Group("")
|
||||||
|
publicGroup.Post("/register", authHandler.Register)
|
||||||
|
publicGroup.Post("/login", authHandler.Login)
|
||||||
|
|
||||||
|
// Группа обработчиков, которые требуют авторизации
|
||||||
|
authorizedGroup := app.Group("")
|
||||||
|
authorizedGroup.Use(jwtware.New(jwtware.Config{
|
||||||
|
SigningKey: jwtware.SigningKey{
|
||||||
|
Key: handlers.JwtSecretKey,
|
||||||
|
},
|
||||||
|
ContextKey: handlers.ContextKeyUser,
|
||||||
|
}))
|
||||||
|
authorizedGroup.Get("/profile", userHandler.Profile)
|
||||||
|
|
||||||
|
// API Flussonic Media Server adapted handlers.
|
||||||
|
authorizedGroup.Get("/vods/:id/:res/:file", handlers.SingleVodsHandler)
|
||||||
|
authorizedGroup.Delete("/vods/:id/:res/:file", handlers.DelSingleVodsHandler)
|
||||||
|
authorizedGroup.Get("/vods/:id/files", handlers.ListFilesVodsHandler)
|
||||||
|
authorizedGroup.Delete("/vods/:id", handlers.DelVodsHandler)
|
||||||
|
authorizedGroup.Get("/vods/:id", handlers.ConfigVodsHandler)
|
||||||
|
authorizedGroup.Get("/vods", handlers.ListVodsHandler)
|
||||||
|
|
||||||
|
logrus.Fatal(app.Listen(":8100"))
|
||||||
}
|
}
|
||||||
|
@ -9,11 +9,17 @@ require (
|
|||||||
github.com/bluenviron/mediacommon v1.14.0
|
github.com/bluenviron/mediacommon v1.14.0
|
||||||
github.com/bluenviron/mediacommon/v2 v2.0.0
|
github.com/bluenviron/mediacommon/v2 v2.0.0
|
||||||
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21
|
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21
|
||||||
|
github.com/gofiber/contrib/jwt v1.1.0
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.6
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
|
github.com/sirupsen/logrus v1.9.3
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect
|
||||||
|
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||||
github.com/asticode/go-astikit v0.54.0 // indirect
|
github.com/asticode/go-astikit v0.54.0 // indirect
|
||||||
github.com/asticode/go-astits v1.13.0 // indirect
|
github.com/asticode/go-astits v1.13.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
@ -22,6 +28,9 @@ require (
|
|||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/grafov/m3u8 v0.12.1 // indirect
|
github.com/grafov/m3u8 v0.12.1 // indirect
|
||||||
github.com/klauspost/compress v1.18.0 // indirect
|
github.com/klauspost/compress v1.18.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/pion/randutil v0.1.0 // indirect
|
github.com/pion/randutil v0.1.0 // indirect
|
||||||
github.com/pion/rtcp v1.2.15 // indirect
|
github.com/pion/rtcp v1.2.15 // indirect
|
||||||
@ -30,6 +39,10 @@ require (
|
|||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.63.0 // indirect
|
github.com/prometheus/common v0.63.0 // indirect
|
||||||
github.com/prometheus/procfs v0.16.0 // indirect
|
github.com/prometheus/procfs v0.16.0 // indirect
|
||||||
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||||
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/net v0.39.0 // indirect
|
golang.org/x/net v0.39.0 // indirect
|
||||||
golang.org/x/sys v0.32.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250403101647-d3117763025c h1:XL0wdylLmMB3WK55l8X1dc/TmBIuVHO9/gUho79NsHw=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250403101647-d3117763025c/go.mod h1:dDCZejhHOcSrjFJi6iwB82bTIYEA6IX2CXFXHffrU30=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409113019-60d315c6f613 h1:bFD/cmpO58rhun8q1vZFa31F+D/s5wiL7x+JEVXumsA=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409113019-60d315c6f613/go.mod h1:dDCZejhHOcSrjFJi6iwB82bTIYEA6IX2CXFXHffrU30=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409113444-ba39c3a9fd2f h1:uhHmn71zIKPPhWf4pNMQQFBd23GZt+TFrLTbEBHhaHM=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409113444-ba39c3a9fd2f/go.mod h1:dDCZejhHOcSrjFJi6iwB82bTIYEA6IX2CXFXHffrU30=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409113609-a11ba13ae8ad h1:+7jOhNFyIeLVmsyUQFAxXSKcNKM06Hj9OLxE3vCTYtA=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409113609-a11ba13ae8ad/go.mod h1:dDCZejhHOcSrjFJi6iwB82bTIYEA6IX2CXFXHffrU30=
|
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409123815-ca6ff10458e1 h1:od5GvRrFeiz7ko3Z+j4aj2RyULrI37JockSIvju0zNs=
|
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409123815-ca6ff10458e1 h1:od5GvRrFeiz7ko3Z+j4aj2RyULrI37JockSIvju0zNs=
|
||||||
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409123815-ca6ff10458e1/go.mod h1:dDCZejhHOcSrjFJi6iwB82bTIYEA6IX2CXFXHffrU30=
|
git.insit.tech/psa/rtsp_reader-writer/writer v0.0.0-20250409123815-ca6ff10458e1/go.mod h1:dDCZejhHOcSrjFJi6iwB82bTIYEA6IX2CXFXHffrU30=
|
||||||
git.insit.tech/sas/rtsp_proxy v0.0.0-20250403064958-d4446b880371 h1:rfv9H0aF9piFSfdh1ZPPMU+vb2ws/nZyanRJfZmteGI=
|
|
||||||
git.insit.tech/sas/rtsp_proxy v0.0.0-20250403064958-d4446b880371/go.mod h1:C8AfoW1Go9xoZz2VdGYKjK8h3ormC3zYb40h7OGL+rs=
|
|
||||||
git.insit.tech/sas/rtsp_proxy v0.0.0-20250408124826-100d046486db h1:ED88DsYnxGxKNr8aARLuYOfgE2Dmj3fFlVR5PzdmrOE=
|
git.insit.tech/sas/rtsp_proxy v0.0.0-20250408124826-100d046486db h1:ED88DsYnxGxKNr8aARLuYOfgE2Dmj3fFlVR5PzdmrOE=
|
||||||
git.insit.tech/sas/rtsp_proxy v0.0.0-20250408124826-100d046486db/go.mod h1:C8AfoW1Go9xoZz2VdGYKjK8h3ormC3zYb40h7OGL+rs=
|
git.insit.tech/sas/rtsp_proxy v0.0.0-20250408124826-100d046486db/go.mod h1:C8AfoW1Go9xoZz2VdGYKjK8h3ormC3zYb40h7OGL+rs=
|
||||||
|
github.com/MicahParks/keyfunc/v2 v2.1.0 h1:6ZXKb9Rp6qp1bDbJefnG7cTH8yMN1IC/4nf+GVjO99k=
|
||||||
|
github.com/MicahParks/keyfunc/v2 v2.1.0/go.mod h1:rW42fi+xgLJ2FRRXAfNx9ZA8WpD4OeE/yHVMteCkw9k=
|
||||||
|
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||||
|
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||||
github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
|
github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
|
||||||
github.com/asticode/go-astikit v0.54.0 h1:uq9eurgisdkYwJU9vSWIQaPH4MH0cac82sQH00kmSNQ=
|
github.com/asticode/go-astikit v0.54.0 h1:uq9eurgisdkYwJU9vSWIQaPH4MH0cac82sQH00kmSNQ=
|
||||||
github.com/asticode/go-astikit v0.54.0/go.mod h1:fV43j20UZYfXzP9oBn33udkvCvDvCDhzjVqoLFuuYZE=
|
github.com/asticode/go-astikit v0.54.0/go.mod h1:fV43j20UZYfXzP9oBn33udkvCvDvCDhzjVqoLFuuYZE=
|
||||||
@ -28,10 +22,17 @@ github.com/bluenviron/mediacommon/v2 v2.0.0/go.mod h1:iHEz1SFIet6zBwAQoh1a92vTQ3
|
|||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
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.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21 h1:yfrARW/aVlqKORCdKrYdU0PZUKPqQvYEUQBKfVlNa9Q=
|
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21 h1:yfrARW/aVlqKORCdKrYdU0PZUKPqQvYEUQBKfVlNa9Q=
|
||||||
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21/go.mod h1:HZqGD/LXHB1VCGUGNzuyxSsD12f3KjbJbvImAmoK/mM=
|
github.com/gen2brain/aac-go v0.0.0-20230119102159-ef1e76509d21/go.mod h1:HZqGD/LXHB1VCGUGNzuyxSsD12f3KjbJbvImAmoK/mM=
|
||||||
|
github.com/gofiber/contrib/jwt v1.1.0 h1:ka5WjWsZ2cd0irvfpmH9hIKj+fflvVRzQxJ7Nv1H3tE=
|
||||||
|
github.com/gofiber/contrib/jwt v1.1.0/go.mod h1:CpIwrkUQ3Q6IP8y9n3f0wP9bOnSKx39EDp2fBVgMFVk=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
@ -42,8 +43,19 @@ github.com/grafov/m3u8 v0.12.1 h1:DuP1uA1kvRRmGNAZ0m+ObLv1dvrfNO0TPx0c/enNk0s=
|
|||||||
github.com/grafov/m3u8 v0.12.1/go.mod h1:nqzOkfBiZJENr52zTVd/Dcl03yzphIMbJqkXGu+u080=
|
github.com/grafov/m3u8 v0.12.1/go.mod h1:nqzOkfBiZJENr52zTVd/Dcl03yzphIMbJqkXGu+u080=
|
||||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
|
||||||
@ -58,8 +70,6 @@ github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKq
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
|
||||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
|
||||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
@ -68,10 +78,23 @@ github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA
|
|||||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||||
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
|
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
|
||||||
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
|
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
|
||||||
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
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/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||||
|
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||||
|
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||||
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
github.com/youpy/go-riff v0.1.0 h1:vZO/37nI4tIET8tQI0Qn0Y79qQh99aEpponTPiPut7k=
|
github.com/youpy/go-riff v0.1.0 h1:vZO/37nI4tIET8tQI0Qn0Y79qQh99aEpponTPiPut7k=
|
||||||
github.com/youpy/go-riff v0.1.0/go.mod h1:83nxdDV4Z9RzrTut9losK7ve4hUnxUR8ASSz4BsKXwQ=
|
github.com/youpy/go-riff v0.1.0/go.mod h1:83nxdDV4Z9RzrTut9losK7ve4hUnxUR8ASSz4BsKXwQ=
|
||||||
github.com/youpy/go-wav v0.3.2 h1:NLM8L/7yZ0Bntadw/0h95OyUsen+DQIVf9gay+SUsMU=
|
github.com/youpy/go-wav v0.3.2 h1:NLM8L/7yZ0Bntadw/0h95OyUsen+DQIVf9gay+SUsMU=
|
||||||
@ -84,19 +107,21 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
|
||||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
|
||||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
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-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
197
reader/internal/auth/auth.go
Normal file
197
reader/internal/auth/auth.go
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
jwtware "github.com/gofiber/contrib/jwt"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
contextKeyUser = "user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Auth() {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
authStorage := &AuthStorage{map[string]User{}}
|
||||||
|
authHandler := &AuthHandler{storage: authStorage}
|
||||||
|
userHandler := &UserHandler{storage: authStorage}
|
||||||
|
|
||||||
|
// Группа обработчиков, которые доступны неавторизованным пользователям
|
||||||
|
publicGroup := app.Group("")
|
||||||
|
publicGroup.Post("/register", authHandler.Register)
|
||||||
|
publicGroup.Post("/login", authHandler.Login)
|
||||||
|
|
||||||
|
// Группа обработчиков, которые требуют авторизации
|
||||||
|
authorizedGroup := app.Group("")
|
||||||
|
authorizedGroup.Use(jwtware.New(jwtware.Config{
|
||||||
|
SigningKey: jwtware.SigningKey{
|
||||||
|
Key: jwtSecretKey,
|
||||||
|
},
|
||||||
|
ContextKey: contextKeyUser,
|
||||||
|
}))
|
||||||
|
authorizedGroup.Get("/profile", userHandler.Profile)
|
||||||
|
|
||||||
|
logrus.Fatal(app.Listen(":8000"))
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Обработчик HTTP-запросов на регистрацию и аутентификацию пользователей
|
||||||
|
AuthHandler struct {
|
||||||
|
storage *AuthStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Хранилище зарегистрированных пользователей
|
||||||
|
// Данные хранятся в оперативной памяти
|
||||||
|
AuthStorage struct {
|
||||||
|
users map[string]User
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура данных с информацией о пользователе
|
||||||
|
User struct {
|
||||||
|
Email string
|
||||||
|
Name string
|
||||||
|
password string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Структура HTTP-запроса на регистрацию пользователя
|
||||||
|
type RegisterRequest struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов на регистрацию пользователя
|
||||||
|
func (h *AuthHandler) Register(c *fiber.Ctx) error {
|
||||||
|
regReq := RegisterRequest{}
|
||||||
|
if err := c.BodyParser(®Req); err != nil {
|
||||||
|
return fmt.Errorf("body parser: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, что пользователь с таким email еще не зарегистрирован
|
||||||
|
if _, exists := h.storage.users[regReq.Email]; exists {
|
||||||
|
return errors.New("the user already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем в память нового зарегистрированного пользователя
|
||||||
|
h.storage.users[regReq.Email] = User{
|
||||||
|
Email: regReq.Email,
|
||||||
|
Name: regReq.Name,
|
||||||
|
password: regReq.Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура HTTP-запроса на вход в аккаунт
|
||||||
|
type LoginRequest struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура HTTP-ответа на вход в аккаунт
|
||||||
|
// В ответе содержится JWT-токен авторизованного пользователя
|
||||||
|
type LoginResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errBadCredentials = errors.New("email or password is incorrect")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Секретный ключ для подписи JWT-токена
|
||||||
|
// Необходимо хранить в безопасном месте
|
||||||
|
var jwtSecretKey = []byte("very-secret-key")
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов на вход в аккаунт
|
||||||
|
func (h *AuthHandler) Login(c *fiber.Ctx) error {
|
||||||
|
regReq := LoginRequest{}
|
||||||
|
if err := c.BodyParser(®Req); err != nil {
|
||||||
|
return fmt.Errorf("body parser: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ищем пользователя в памяти приложения по электронной почте
|
||||||
|
user, exists := h.storage.users[regReq.Email]
|
||||||
|
// Если пользователь не найден, возвращаем ошибку
|
||||||
|
if !exists {
|
||||||
|
return errBadCredentials
|
||||||
|
}
|
||||||
|
// Если пользователь найден, но у него другой пароль, возвращаем ошибку
|
||||||
|
if user.password != regReq.Password {
|
||||||
|
return errBadCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерируем JWT-токен для пользователя,
|
||||||
|
// который он будет использовать в будущих HTTP-запросах
|
||||||
|
|
||||||
|
// Генерируем полезные данные, которые будут храниться в токене
|
||||||
|
payload := jwt.MapClaims{
|
||||||
|
"sub": user.Email,
|
||||||
|
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создаем новый JWT-токен и подписываем его по алгоритму HS256
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
|
||||||
|
|
||||||
|
t, err := token.SignedString(jwtSecretKey)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("JWT token signing")
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(LoginResponse{AccessToken: t})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов, которые связаны с пользователем
|
||||||
|
type UserHandler struct {
|
||||||
|
storage *AuthStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура HTTP-ответа с информацией о пользователе
|
||||||
|
type ProfileResponse struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func jwtPayloadFromRequest(c *fiber.Ctx) (jwt.MapClaims, bool) {
|
||||||
|
jwtToken, ok := c.Context().Value(contextKeyUser).(*jwt.Token)
|
||||||
|
if !ok {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"jwt_token_context_value": c.Context().Value(contextKeyUser),
|
||||||
|
}).Error("wrong type of JWT token in context")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, ok := jwtToken.Claims.(jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"jwt_token_claims": jwtToken.Claims,
|
||||||
|
}).Error("wrong type of JWT token claims")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов на получение информации о пользователе
|
||||||
|
func (h *UserHandler) Profile(c *fiber.Ctx) error {
|
||||||
|
jwtPayload, ok := jwtPayloadFromRequest(c)
|
||||||
|
if !ok {
|
||||||
|
return c.SendStatus(fiber.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo, ok := h.storage.users[jwtPayload["sub"].(string)]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(ProfileResponse{
|
||||||
|
Email: userInfo.Email,
|
||||||
|
Name: userInfo.Name,
|
||||||
|
})
|
||||||
|
}
|
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
jwtware "github.com/gofiber/contrib/jwt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -12,9 +13,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.insit.tech/psa/rtsp_reader-writer/writer/pkg/storage"
|
"git.insit.tech/psa/rtsp_reader-writer/writer/pkg/storage"
|
||||||
"go.uber.org/zap"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
"reader/internal/config"
|
"reader/internal/config"
|
||||||
logger "reader/internal/log"
|
|
||||||
"reader/internal/processor"
|
"reader/internal/processor"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -162,13 +164,11 @@ func HLS(w http.ResponseWriter, r *http.Request) {
|
|||||||
//
|
//
|
||||||
// This method allows to get the list of all VOD locations. VOD location is a virtual filepath used to place files for
|
// This method allows to get the list of all VOD locations. VOD location is a virtual filepath used to place files for
|
||||||
// VOD (Video on Demand) broadcasting.
|
// VOD (Video on Demand) broadcasting.
|
||||||
func ListVodsHandler(w http.ResponseWriter, r *http.Request) {
|
func ListVodsHandler(c *fiber.Ctx) error {
|
||||||
// Read directory.
|
// Read directory.
|
||||||
entries, err := os.ReadDir(config.DirData)
|
entries, err := os.ReadDir(config.DirData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
logger.Log.Error("failed to read dir", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter only folders.
|
// Filter only folders.
|
||||||
@ -186,27 +186,20 @@ func ListVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write header and code response.
|
// Write header and code response.
|
||||||
w.Header().Set("Content-Type", "application/json")
|
return c.JSON(VodsRes)
|
||||||
if err := json.NewEncoder(w).Encode(VodsRes); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
logger.Log.Error("failed to encode dir", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfigVodsHandler returns configuration of the requested VOD location.
|
// ConfigVodsHandler returns configuration of the requested VOD location.
|
||||||
//
|
//
|
||||||
// This method allows to get a single VOD location.
|
// This method allows to get a single VOD location.
|
||||||
func ConfigVodsHandler(w http.ResponseWriter, r *http.Request) {
|
func ConfigVodsHandler(c *fiber.Ctx) error {
|
||||||
// Read camera id.
|
// Read camera id.
|
||||||
id := r.PathValue("id")
|
id := c.Params("id")
|
||||||
|
|
||||||
// Get resolutions.
|
// Get resolutions.
|
||||||
resolutions, err := storage.GetResolutions(id)
|
resolutions, err := storage.GetResolutions(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
return c.SendStatus(fiber.StatusBadRequest)
|
||||||
logger.Log.Error("camera does not exist", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate response fields.
|
// Calculate response fields.
|
||||||
@ -217,20 +210,19 @@ func ConfigVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Read directory.
|
// Read directory.
|
||||||
entries, err := os.ReadDir(resDir)
|
entries, err := os.ReadDir(resDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
logger.Log.Error("resolution does not exist", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a folder has files that was not created or modified for last 5 minutes.
|
// Check if a folder has files that was not created or modified for last 5 minutes.
|
||||||
disabled, err := Inactive5Minutes(entries)
|
disabled, err := Inactive5Minutes(entries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the difference between first existing rec file and the last one in milliseconds.
|
||||||
segmentDuration, err := recDurationMilliseconds(entries)
|
segmentDuration, err := recDurationMilliseconds(entries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the Response.
|
// Prepare the Response.
|
||||||
@ -244,39 +236,30 @@ func ConfigVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write header and code response.
|
// Write header and code response.
|
||||||
w.Header().Set("Content-Type", "application/json")
|
return c.JSON(VodsRes)
|
||||||
if err := json.NewEncoder(w).Encode(VodsRes); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
logger.Log.Error("failed to encode dir", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w.Write([]byte("Whole VOD location configuration"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelVodsHandler delete archive of the requested VOD location.
|
// DelVodsHandler delete archive of the requested VOD location.
|
||||||
//
|
//
|
||||||
// This method delete a single VOD location by its prefix.
|
// This method delete a single VOD location by its prefix.
|
||||||
func DelVodsHandler(w http.ResponseWriter, r *http.Request) {
|
func DelVodsHandler(c *fiber.Ctx) error {
|
||||||
// Read camera id.
|
// Read camera id.
|
||||||
id := r.PathValue("id")
|
id := c.Params("id")
|
||||||
|
|
||||||
err := os.Remove(fmt.Sprintf("%s/%s", config.DirData, id))
|
err := os.Remove(fmt.Sprintf("%s/%s", config.DirData, id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
return c.SendStatus(fiber.StatusBadRequest)
|
||||||
logger.Log.Error("camera does not exist", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusNoContent)
|
return c.SendStatus(fiber.StatusNoContent)
|
||||||
w.Write([]byte("Deleted"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListFilesVodsHandler returns the list of all files and folders in archive for a specific VOD location.
|
// ListFilesVodsHandler returns the list of all files and folders in archive for a specific VOD location.
|
||||||
//
|
//
|
||||||
// This method allows to get the list of all files and folders for a specific VOD location.
|
// This method allows to get the list of all files and folders for a specific VOD location.
|
||||||
func ListFilesVodsHandler(w http.ResponseWriter, r *http.Request) {
|
func ListFilesVodsHandler(c *fiber.Ctx) error {
|
||||||
// Read camera id.
|
// Read camera id.
|
||||||
id := r.PathValue("id")
|
id := c.Params("id")
|
||||||
|
|
||||||
// Create map for response.
|
// Create map for response.
|
||||||
files := make(map[string][]string)
|
files := make(map[string][]string)
|
||||||
@ -284,9 +267,7 @@ func ListFilesVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Get resolutions.
|
// Get resolutions.
|
||||||
resolutions, err := storage.GetResolutions(id)
|
resolutions, err := storage.GetResolutions(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
return c.SendStatus(fiber.StatusBadRequest)
|
||||||
logger.Log.Error("camera does not exist", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, resolution := range resolutions {
|
for _, resolution := range resolutions {
|
||||||
@ -296,9 +277,7 @@ func ListFilesVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Read directory.
|
// Read directory.
|
||||||
entries, err := os.ReadDir(resDir)
|
entries, err := os.ReadDir(resDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
logger.Log.Error("resolution does not exist", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create slice for files in folders.
|
// Create slice for files in folders.
|
||||||
@ -320,37 +299,27 @@ func ListFilesVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write header and code response.
|
// Write header and code response.
|
||||||
w.Header().Set("Content-Type", "application/json")
|
return c.JSON(vodsRes)
|
||||||
w.Write([]byte("List of files in the VOD storage"))
|
|
||||||
if err := json.NewEncoder(w).Encode(vodsRes); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
logger.Log.Error("failed to encode dir", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SingleVodsHandler returns a specific file in archive for a specific resolution and VOD location.
|
// SingleVodsHandler returns a specific file in archive for a specific resolution and VOD location.
|
||||||
//
|
//
|
||||||
// This method allows to get a single VOD file.
|
// This method allows to get a single VOD file.
|
||||||
func SingleVodsHandler(w http.ResponseWriter, r *http.Request) {
|
func SingleVodsHandler(c *fiber.Ctx) error {
|
||||||
// Read camera id, res, filename.
|
// Read camera id, res, filename.
|
||||||
id := r.PathValue("id")
|
id := c.Params("id")
|
||||||
res := r.PathValue("res")
|
res := c.Params("res")
|
||||||
file := r.PathValue("file")
|
file := c.Params("file")
|
||||||
|
|
||||||
// Calculate file size in bytes.
|
// Calculate file size in bytes.
|
||||||
FileBytes, err := storage.FileBytes(id, res, file)
|
FileBytes, err := storage.FileBytes(id, res, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusBadRequest)
|
||||||
logger.Log.Error("file not found", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dur, tracks, err := storage.GetDurAndTracks(id, res, file)
|
dur, tracks, err := storage.GetDurAndTracks(id, res, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
logger.Log.Error("file not found", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
media := MediaSingleVodsResponse{
|
media := MediaSingleVodsResponse{
|
||||||
@ -364,37 +333,216 @@ func SingleVodsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
vodsRes := SingleVodsResponse{
|
vodsRes := SingleVodsResponse{
|
||||||
Name: file,
|
Name: file,
|
||||||
Prefix: id,
|
Prefix: id,
|
||||||
Url: r.URL.String(),
|
Url: c.OriginalURL(),
|
||||||
Folder: res,
|
Folder: res,
|
||||||
Bytes: FileBytes,
|
Bytes: FileBytes,
|
||||||
MediaInfo: media,
|
MediaInfo: media,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write header and code response.
|
// Write header and code response.
|
||||||
w.Header().Set("Content-Type", "application/json")
|
return c.JSON(vodsRes)
|
||||||
w.Write([]byte("Whole VOD file configuration"))
|
|
||||||
if err := json.NewEncoder(w).Encode(vodsRes); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
||||||
logger.Log.Error("failed to encode dir", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DelSingleVodsHandler deletes a VOD file by its name.
|
// DelSingleVodsHandler deletes a VOD file by its name.
|
||||||
//
|
//
|
||||||
// This method deletes a VOD file by its name.
|
// This method deletes a VOD file by its name.
|
||||||
func DelSingleVodsHandler(w http.ResponseWriter, r *http.Request) {
|
func DelSingleVodsHandler(c *fiber.Ctx) error {
|
||||||
// Read camera id, res, filename.
|
// Read camera id, res, filename.
|
||||||
id := r.PathValue("id")
|
id := c.Params("id")
|
||||||
res := r.PathValue("res")
|
res := c.Params("res")
|
||||||
file := r.PathValue("file")
|
file := c.Params("file")
|
||||||
|
|
||||||
if err := os.Remove(fmt.Sprintf("%s/%s/%s/%s", config.DirData, id, res, file)); err != nil {
|
if err := os.Remove(fmt.Sprintf("%s/%s/%s/%s", config.DirData, id, res, file)); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusNotFound)
|
return c.SendStatus(fiber.StatusNotFound)
|
||||||
logger.Log.Error("file does not exist", zap.Error(err))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusNoContent)
|
return c.SendStatus(fiber.StatusNoContent)
|
||||||
w.Write([]byte("Deleted"))
|
}
|
||||||
|
|
||||||
|
// //////////////////////////////////////////////////////////////////////////
|
||||||
|
// //////////////////////////////////////////////////////////////////////////
|
||||||
|
const (
|
||||||
|
ContextKeyUser = "user"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Auth() {
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
authStorage := &AuthStorage{map[string]User{}}
|
||||||
|
authHandler := &AuthHandler{Storage: authStorage}
|
||||||
|
userHandler := &UserHandler{Storage: authStorage}
|
||||||
|
|
||||||
|
// Группа обработчиков, которые доступны неавторизованным пользователям
|
||||||
|
publicGroup := app.Group("")
|
||||||
|
publicGroup.Post("/register", authHandler.Register)
|
||||||
|
publicGroup.Post("/login", authHandler.Login)
|
||||||
|
|
||||||
|
// Группа обработчиков, которые требуют авторизации
|
||||||
|
authorizedGroup := app.Group("")
|
||||||
|
authorizedGroup.Use(jwtware.New(jwtware.Config{
|
||||||
|
SigningKey: jwtware.SigningKey{
|
||||||
|
Key: JwtSecretKey,
|
||||||
|
},
|
||||||
|
ContextKey: ContextKeyUser,
|
||||||
|
}))
|
||||||
|
authorizedGroup.Get("/profile", userHandler.Profile)
|
||||||
|
|
||||||
|
logrus.Fatal(app.Listen(":8100"))
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Обработчик HTTP-запросов на регистрацию и аутентификацию пользователей
|
||||||
|
AuthHandler struct {
|
||||||
|
Storage *AuthStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Хранилище зарегистрированных пользователей
|
||||||
|
// Данные хранятся в оперативной памяти
|
||||||
|
AuthStorage struct {
|
||||||
|
Users map[string]User
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура данных с информацией о пользователе
|
||||||
|
User struct {
|
||||||
|
Email string
|
||||||
|
Name string
|
||||||
|
password string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Структура HTTP-запроса на регистрацию пользователя
|
||||||
|
type RegisterRequest struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов на регистрацию пользователя
|
||||||
|
func (h *AuthHandler) Register(c *fiber.Ctx) error {
|
||||||
|
regReq := RegisterRequest{}
|
||||||
|
if err := c.BodyParser(®Req); err != nil {
|
||||||
|
return fmt.Errorf("body parser: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем, что пользователь с таким email еще не зарегистрирован
|
||||||
|
if _, exists := h.Storage.Users[regReq.Email]; exists {
|
||||||
|
return errors.New("the user already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сохраняем в память нового зарегистрированного пользователя
|
||||||
|
h.Storage.Users[regReq.Email] = User{
|
||||||
|
Email: regReq.Email,
|
||||||
|
Name: regReq.Name,
|
||||||
|
password: regReq.Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.SendStatus(fiber.StatusCreated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура HTTP-запроса на вход в аккаунт
|
||||||
|
type LoginRequest struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура HTTP-ответа на вход в аккаунт
|
||||||
|
// В ответе содержится JWT-токен авторизованного пользователя
|
||||||
|
type LoginResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errBadCredentials = errors.New("email or password is incorrect")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Секретный ключ для подписи JWT-токена
|
||||||
|
// Необходимо хранить в безопасном месте
|
||||||
|
var JwtSecretKey = []byte("very-secret-key")
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов на вход в аккаунт
|
||||||
|
func (h *AuthHandler) Login(c *fiber.Ctx) error {
|
||||||
|
regReq := LoginRequest{}
|
||||||
|
if err := c.BodyParser(®Req); err != nil {
|
||||||
|
return fmt.Errorf("body parser: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ищем пользователя в памяти приложения по электронной почте
|
||||||
|
user, exists := h.Storage.Users[regReq.Email]
|
||||||
|
// Если пользователь не найден, возвращаем ошибку
|
||||||
|
if !exists {
|
||||||
|
return errBadCredentials
|
||||||
|
}
|
||||||
|
// Если пользователь найден, но у него другой пароль, возвращаем ошибку
|
||||||
|
if user.password != regReq.Password {
|
||||||
|
return errBadCredentials
|
||||||
|
}
|
||||||
|
|
||||||
|
// Генерируем JWT-токен для пользователя,
|
||||||
|
// который он будет использовать в будущих HTTP-запросах
|
||||||
|
|
||||||
|
// Генерируем полезные данные, которые будут храниться в токене
|
||||||
|
payload := jwt.MapClaims{
|
||||||
|
"sub": user.Email,
|
||||||
|
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Создаем новый JWT-токен и подписываем его по алгоритму HS256
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, payload)
|
||||||
|
|
||||||
|
t, err := token.SignedString(JwtSecretKey)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("JWT token signing")
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(LoginResponse{AccessToken: t})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов, которые связаны с пользователем
|
||||||
|
type UserHandler struct {
|
||||||
|
Storage *AuthStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
// Структура HTTP-ответа с информацией о пользователе
|
||||||
|
type ProfileResponse struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func jwtPayloadFromRequest(c *fiber.Ctx) (jwt.MapClaims, bool) {
|
||||||
|
jwtToken, ok := c.Context().Value(ContextKeyUser).(*jwt.Token)
|
||||||
|
if !ok {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"jwt_token_context_value": c.Context().Value(ContextKeyUser),
|
||||||
|
}).Error("wrong type of JWT token in context")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
payload, ok := jwtToken.Claims.(jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"jwt_token_claims": jwtToken.Claims,
|
||||||
|
}).Error("wrong type of JWT token claims")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик HTTP-запросов на получение информации о пользователе
|
||||||
|
func (h *UserHandler) Profile(c *fiber.Ctx) error {
|
||||||
|
jwtPayload, ok := jwtPayloadFromRequest(c)
|
||||||
|
if !ok {
|
||||||
|
return c.SendStatus(fiber.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo, ok := h.Storage.Users[jwtPayload["sub"].(string)]
|
||||||
|
if !ok {
|
||||||
|
return errors.New("user not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(ProfileResponse{
|
||||||
|
Email: userInfo.Email,
|
||||||
|
Name: userInfo.Name,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user