handlers moved to new system, upload need to be fixed and resolvers must be tested
This commit is contained in:
parent
7ce2b41ce7
commit
87985762bf
@ -26,7 +26,7 @@ func main() {
|
||||
|
||||
engine := filesengine.NewFilesEngine(nil, nil)
|
||||
|
||||
go app.New(pg, engine).
|
||||
go app.New(ctx, pg, engine).
|
||||
Run(ctx)
|
||||
|
||||
<-ctx.Done()
|
||||
|
@ -2,14 +2,12 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/app/handlers"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/domain"
|
||||
filesengine "git.optclblast.xyz/draincloud/draincloud-core/internal/files_engine"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/processor"
|
||||
resolvedispatcher "git.optclblast.xyz/draincloud/draincloud-core/internal/resolve_dispatcher"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/resolvers/auth"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -23,12 +21,18 @@ type DrainCloud struct {
|
||||
}
|
||||
|
||||
func New(
|
||||
ctx context.Context,
|
||||
database storage.Database,
|
||||
filesEngine *filesengine.FilesEngine,
|
||||
) *DrainCloud {
|
||||
mux := gin.Default()
|
||||
|
||||
dispatcher := resolvedispatcher.New()
|
||||
dispatcher.RegisterResolver(
|
||||
ctx,
|
||||
auth.AuthResolverV1Name,
|
||||
auth.NewAuthResolver(database),
|
||||
)
|
||||
|
||||
d := &DrainCloud{
|
||||
database: database,
|
||||
@ -39,16 +43,19 @@ func New(
|
||||
// Built-in auth component of DrainCloud-Core
|
||||
authGroup := mux.Group("/auth")
|
||||
{
|
||||
// authGroup.POST("/register", d.Register)
|
||||
authGroup.POST("/register", d.ginProcessor.Process(
|
||||
handlers.NewRegisterHandler(database),
|
||||
))
|
||||
authGroup.POST("/logon", d.Login)
|
||||
authGroup.POST("/logon", d.ginProcessor.Process(
|
||||
handlers.NewLogonHandler(database),
|
||||
))
|
||||
}
|
||||
|
||||
filesGroup := mux.Group("/files")
|
||||
{
|
||||
filesGroup.POST("/upload", d.UploadFile)
|
||||
filesGroup.POST("/upload", d.ginProcessor.Process(
|
||||
handlers.NewUploadFileHandler(filesEngine),
|
||||
))
|
||||
}
|
||||
|
||||
d.mux = mux
|
||||
@ -59,23 +66,3 @@ func New(
|
||||
func (d *DrainCloud) Run(ctx context.Context) error {
|
||||
return d.mux.Run()
|
||||
}
|
||||
|
||||
func writeError(ctx *gin.Context, err error) {
|
||||
switch {
|
||||
case errors.Is(err, ErrorAccessDenied):
|
||||
ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{
|
||||
Code: http.StatusForbidden,
|
||||
Message: err.Error(),
|
||||
})
|
||||
case errors.Is(err, ErrorSessionExpired):
|
||||
ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{
|
||||
Code: http.StatusForbidden,
|
||||
Message: err.Error(),
|
||||
})
|
||||
default:
|
||||
ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{
|
||||
Code: http.StatusInternalServerError,
|
||||
Message: "Internal Error",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const (
|
||||
csrfTokenCookie = "__Csrf_token"
|
||||
sessionTokenCookie = "__Session_token"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorUnauthorized = errors.New("unauthorized")
|
||||
)
|
||||
|
||||
func (d *DrainCloud) authorize(ctx *gin.Context) (*models.Session, error) {
|
||||
session, err := d.getSession(ctx)
|
||||
if err != nil && !errors.Is(err, http.ErrNoCookie) {
|
||||
return nil, ErrorUnauthorized
|
||||
}
|
||||
|
||||
if session == nil {
|
||||
return nil, ErrorUnauthorized
|
||||
}
|
||||
|
||||
if err := validateSession(ctx, session); err != nil {
|
||||
// TODO add audit log entry
|
||||
return nil, ErrorUnauthorized
|
||||
}
|
||||
|
||||
logger.Debug(ctx, "[authorize] user authorized", slog.String("session_id", session.ID.String()))
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func validateLoginAndPassword(login, password string) error {
|
||||
if len(login) < 4 {
|
||||
return fmt.Errorf("login must be longer than 8 chars")
|
||||
}
|
||||
|
||||
if len(password) < 6 {
|
||||
return fmt.Errorf("password must be longer than 8 chars")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateSessionToken(length int) (string, error) {
|
||||
bytes := make([]byte, length)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
return "", fmt.Errorf("failed to generate token: %w", err)
|
||||
}
|
||||
return base64.URLEncoding.EncodeToString(bytes), nil
|
||||
}
|
@ -1,84 +1,100 @@
|
||||
package app
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/domain"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/errs"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrorAccessDenied = errors.New("access denied")
|
||||
ErrorSessionExpired = errors.New("session expired")
|
||||
)
|
||||
type LogonHandler struct {
|
||||
*handler.BaseHandler
|
||||
authStorage storage.AuthStorage
|
||||
}
|
||||
|
||||
func (d *DrainCloud) Login(ctx *gin.Context) {
|
||||
logger.Debug(ctx, "[Login] new request")
|
||||
func NewLogonHandler(
|
||||
authStorage storage.AuthStorage,
|
||||
) *LogonHandler {
|
||||
h := &LogonHandler{
|
||||
authStorage: authStorage,
|
||||
BaseHandler: handler.New().
|
||||
WithName("logonv1").
|
||||
WithRequiredResolveParams(),
|
||||
}
|
||||
h.WithProcessFunc(h.process)
|
||||
return h
|
||||
}
|
||||
|
||||
req := new(domain.LoginRequest)
|
||||
err := ctx.BindJSON(req)
|
||||
func (h *LogonHandler) process(ctx context.Context, req *common.Request, w handler.Writer) error {
|
||||
logger.Debug(ctx, "[Logon] new request")
|
||||
|
||||
body := new(domain.LogonRequest)
|
||||
err := json.Unmarshal(req.Body, body)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "[Login] failed to bind request", logger.Err(err))
|
||||
ctx.JSON(http.StatusBadRequest, map[string]string{
|
||||
logger.Error(ctx, "[Logon] failed to bind request", logger.Err(err))
|
||||
w.Write(ctx, map[string]string{
|
||||
"error": "bad request",
|
||||
})
|
||||
return
|
||||
}, handler.WithCode(http.StatusBadRequest))
|
||||
return nil
|
||||
}
|
||||
|
||||
resp, err := d.login(ctx, req)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "[Login] failed to login user", logger.Err(err))
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]string{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, resp)
|
||||
}
|
||||
|
||||
func (d *DrainCloud) login(ctx *gin.Context, req *domain.LoginRequest) (*domain.LoginResponse, error) {
|
||||
session, err := d.getSession(ctx)
|
||||
session, err := h.getSession(ctx, req)
|
||||
if err != nil && !errors.Is(err, http.ErrNoCookie) {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
if session != nil {
|
||||
if err := validateSession(ctx, session); err != nil {
|
||||
if err := validateSession(ctx, req, session); err != nil {
|
||||
// TODO add audit log entry
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debug(ctx, "[login] user is already logged in", slog.String("session_id", session.ID.String()))
|
||||
return &domain.LoginResponse{
|
||||
w.Write(ctx, &domain.LogonResponse{
|
||||
Ok: true,
|
||||
}, nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
logger.Debug(ctx, "[login] session not found. trying to authorize")
|
||||
logger.Debug(ctx, "[login] session not founh. trying to authorize")
|
||||
|
||||
resp, err := h.login(ctx, body, session, w)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "[Logon] failed to login user", logger.Err(err))
|
||||
return err
|
||||
}
|
||||
|
||||
w.Write(ctx, resp)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *LogonHandler) login(ctx context.Context, req *domain.LogonRequest, session *models.Session, w handler.Writer) (*domain.LogonResponse, error) {
|
||||
passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10)
|
||||
if err != nil {
|
||||
logger.Error(ctx, "[login] failed to generate password hash", logger.Err(err))
|
||||
return nil, fmt.Errorf("failed to generate password hash: %w", err)
|
||||
}
|
||||
|
||||
user, err := d.database.GetUserByLogin(ctx, req.Login)
|
||||
user, err := h.authStorage.GetUserByLogin(ctx, req.Login)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch user by login: %w", err)
|
||||
}
|
||||
|
||||
if bytes.Equal(passwordHash, user.PasswordHash) {
|
||||
logger.Warn(ctx, "[login] failed to login user. passwords hashes not equal")
|
||||
return nil, ErrorAccessDenied
|
||||
return nil, errs.ErrorAccessDenied
|
||||
}
|
||||
|
||||
sessionCreatedAt := time.Now()
|
||||
@ -88,20 +104,20 @@ func (d *DrainCloud) login(ctx *gin.Context, req *domain.LoginRequest) (*domain.
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate a session token: %w", err)
|
||||
}
|
||||
ctx.SetCookie(sessionTokenCookie, sessionToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, true)
|
||||
w.SetCookie(sessionTokenCookie, sessionToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, true)
|
||||
|
||||
csrfToken, err := generateSessionToken(100)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate a csrf token: %w", err)
|
||||
}
|
||||
ctx.SetCookie(csrfTokenCookie, csrfToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, false)
|
||||
w.SetCookie(csrfTokenCookie, csrfToken, int(sessionExpiredAt.Sub(sessionCreatedAt).Seconds()), "_path", "_domain", true, false)
|
||||
|
||||
sessionID, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate session id: %w", err)
|
||||
}
|
||||
|
||||
if _, err = d.database.AddSession(ctx, &models.Session{
|
||||
if _, err = h.authStorage.AddSession(ctx, &models.Session{
|
||||
ID: sessionID,
|
||||
SessionToken: sessionToken,
|
||||
CsrfToken: csrfToken,
|
||||
@ -114,17 +130,17 @@ func (d *DrainCloud) login(ctx *gin.Context, req *domain.LoginRequest) (*domain.
|
||||
|
||||
// TODO add audit log entry
|
||||
|
||||
return &domain.LoginResponse{
|
||||
return &domain.LogonResponse{
|
||||
Ok: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *DrainCloud) getSession(ctx *gin.Context) (*models.Session, error) {
|
||||
token, err := ctx.Cookie(sessionTokenCookie)
|
||||
func (h *LogonHandler) getSession(ctx context.Context, req *common.Request) (*models.Session, error) {
|
||||
token, err := common.GetValue[string](req.Metadata, sessionTokenCookie)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch session cookie from request: %w", err)
|
||||
}
|
||||
csrfToken, err := ctx.Cookie(csrfTokenCookie)
|
||||
csrfToken, err := common.GetValue[string](req.Metadata, csrfTokenCookie)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch csrf cookie from request: %w", err)
|
||||
}
|
||||
@ -133,7 +149,7 @@ func (d *DrainCloud) getSession(ctx *gin.Context) (*models.Session, error) {
|
||||
return nil, fmt.Errorf("session token or csrf token is empty")
|
||||
}
|
||||
|
||||
session, err := d.database.GetSession(ctx, token)
|
||||
session, err := h.authStorage.GetSession(ctx, token)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch session from repo: %w", err)
|
||||
}
|
||||
@ -141,22 +157,22 @@ func (d *DrainCloud) getSession(ctx *gin.Context) (*models.Session, error) {
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func validateSession(ctx *gin.Context, session *models.Session) error {
|
||||
func validateSession(ctx context.Context, req *common.Request, session *models.Session) error {
|
||||
if session == nil {
|
||||
return ErrorAccessDenied
|
||||
return errs.ErrorAccessDenied
|
||||
}
|
||||
|
||||
csrfToken, err := ctx.Cookie(csrfTokenCookie)
|
||||
csrfToken, err := common.GetValue[string](req.Metadata, csrfTokenCookie)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch csrf cookie from request: %w", err)
|
||||
}
|
||||
|
||||
if session.CsrfToken != csrfToken {
|
||||
return ErrorAccessDenied
|
||||
return errs.ErrorAccessDenied
|
||||
}
|
||||
|
||||
if session.ExpiredAt.Before(time.Now()) {
|
||||
return ErrorSessionExpired
|
||||
return errs.ErrorSessionExpired
|
||||
}
|
||||
|
||||
return nil
|
91
internal/app/handlers/upload_file.go
Normal file
91
internal/app/handlers/upload_file.go
Normal file
@ -0,0 +1,91 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
|
||||
filesengine "git.optclblast.xyz/draincloud/draincloud-core/internal/files_engine"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/resolvers/auth"
|
||||
)
|
||||
|
||||
const (
|
||||
maxFileSize = 10 << 30
|
||||
)
|
||||
|
||||
type UploadFileHandler struct {
|
||||
*handler.BaseHandler
|
||||
filesEngine *filesengine.FilesEngine
|
||||
}
|
||||
|
||||
func NewUploadFileHandler(
|
||||
filesEngine *filesengine.FilesEngine,
|
||||
) *UploadFileHandler {
|
||||
h := &UploadFileHandler{
|
||||
filesEngine: filesEngine,
|
||||
BaseHandler: handler.New().
|
||||
WithName("uploadfilev1").
|
||||
WithRequiredResolveParams(
|
||||
auth.AuthResolverV1Name,
|
||||
),
|
||||
}
|
||||
h.WithProcessFunc(h.process)
|
||||
return h
|
||||
}
|
||||
|
||||
func (d *UploadFileHandler) process(ctx context.Context, req *common.Request, w handler.Writer) error {
|
||||
if err := req.RawReq.ParseMultipartForm(maxFileSize); err != nil {
|
||||
logger.Error(ctx, "uploadFile handler error", logger.Err(err))
|
||||
return err
|
||||
}
|
||||
|
||||
// if err := d.uploadFile(ctx, userID); err != nil {
|
||||
// logger.Error(ctx, "uploadFile handle", logger.Err(err))
|
||||
// writeError(ctx, err)
|
||||
// return
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
// func (d *UploadFileHandler) uploadFile(ctx context.Context, req *common.Request) error {
|
||||
// title := ctx.PostForm("file")
|
||||
// logger.Info(ctx, "uploadFile", slog.Any("postForm data", spew.Sdump(title)))
|
||||
|
||||
// file, header, err := req.RawReq.FormFile("file")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// logger.Info(ctx, "uploadFile", slog.Any("header", spew.Sdump(header)))
|
||||
|
||||
// data, err := io.ReadAll(file)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// ext := parseExtension(header.Filename)
|
||||
|
||||
// id, err := d.filesEngine.SaveFile(ctx, filesengine.File{
|
||||
// Name: header.Filename,
|
||||
// UserID: userID,
|
||||
// Data: data,
|
||||
// Ext: ext,
|
||||
// Size: int64(len(data)),
|
||||
// Type: "", // че такое type?
|
||||
// })
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("failed to save file: %w", err)
|
||||
// }
|
||||
// logger.Debug(ctx, "new file id", "id", id)
|
||||
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func parseExtension(filename string) string {
|
||||
// parts := strings.Split(filename, ".")
|
||||
// if len(parts) == 0 {
|
||||
// return ""
|
||||
// }
|
||||
|
||||
// return parts[len(parts)-1]
|
||||
// }
|
@ -1,28 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/reqcontext"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type authorizer interface {
|
||||
authorize(ctx *gin.Context) (*models.Session, error)
|
||||
}
|
||||
|
||||
func WithAuth(handler gin.HandlerFunc, auth authorizer) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
sess, err := auth.authorize(ctx)
|
||||
if err != nil {
|
||||
writeError(ctx, err)
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
authCtx := reqcontext.WithSession(ctx.Request.Context(), sess)
|
||||
authCtx = reqcontext.WithUserID(authCtx, sess.UserID)
|
||||
ctx.Request = ctx.Request.WithContext(authCtx)
|
||||
|
||||
handler(ctx)
|
||||
}
|
||||
}
|
@ -1,81 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
filesengine "git.optclblast.xyz/draincloud/draincloud-core/internal/files_engine"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/reqcontext"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
const (
|
||||
maxFileSize = 10 << 30
|
||||
)
|
||||
|
||||
func (d *DrainCloud) UploadFile(ctx *gin.Context) {
|
||||
if err := ctx.Request.ParseMultipartForm(maxFileSize); err != nil {
|
||||
logger.Error(ctx, "uploadFile handler error", logger.Err(err))
|
||||
writeError(ctx, err)
|
||||
return
|
||||
}
|
||||
|
||||
userID, err := reqcontext.GetUserID(ctx)
|
||||
if err != nil {
|
||||
writeError(ctx, ErrorAccessDenied)
|
||||
return
|
||||
}
|
||||
|
||||
if err := d.uploadFile(ctx, userID); err != nil {
|
||||
logger.Error(ctx, "uploadFile handle", logger.Err(err))
|
||||
writeError(ctx, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DrainCloud) uploadFile(ctx *gin.Context, userID uuid.UUID) error {
|
||||
title := ctx.PostForm("file")
|
||||
logger.Info(ctx, "uploadFile", slog.Any("postForm data", spew.Sdump(title)))
|
||||
|
||||
file, header, err := ctx.Request.FormFile("file")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info(ctx, "uploadFile", slog.Any("header", spew.Sdump(header)))
|
||||
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ext := parseExtension(header.Filename)
|
||||
|
||||
id, err := d.filesEngine.SaveFile(ctx, filesengine.File{
|
||||
Name: header.Filename,
|
||||
UserID: userID,
|
||||
Data: data,
|
||||
Ext: ext,
|
||||
Size: int64(len(data)),
|
||||
Type: "", // че такое type?
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to save file: %w", err)
|
||||
}
|
||||
logger.Debug(ctx, "new file id", "id", id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseExtension(filename string) string {
|
||||
parts := strings.Split(filename, ".")
|
||||
if len(parts) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return parts[len(parts)-1]
|
||||
}
|
@ -10,12 +10,12 @@ type RegisterResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
type LogonRequest struct {
|
||||
Login string `json:"login"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
type LogonResponse struct {
|
||||
Ok bool `json:"ok"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
@ -6,8 +6,20 @@ import (
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
|
||||
)
|
||||
|
||||
type WriteOptions struct {
|
||||
Code int
|
||||
}
|
||||
|
||||
type WriteOption func(opts *WriteOptions)
|
||||
|
||||
func WithCode(code int) WriteOption {
|
||||
return func(opts *WriteOptions) {
|
||||
opts.Code = code
|
||||
}
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write(ctx context.Context, resp any)
|
||||
Write(ctx context.Context, resp any, opts ...WriteOption)
|
||||
SetCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -17,8 +18,15 @@ func wrapGin(ctx *gin.Context) ginWriter {
|
||||
}
|
||||
}
|
||||
|
||||
func (w ginWriter) Write(ctx context.Context, resp any) {
|
||||
w.ctx.JSON(http.StatusOK, resp)
|
||||
func (w ginWriter) Write(ctx context.Context, resp any, opts ...handler.WriteOption) {
|
||||
params := &handler.WriteOptions{
|
||||
Code: http.StatusOK,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(params)
|
||||
}
|
||||
|
||||
w.ctx.JSON(params.Code, resp)
|
||||
}
|
||||
|
||||
func (w ginWriter) SetCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) {
|
||||
|
@ -15,6 +15,10 @@ import (
|
||||
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthResolverV1Name = "auth.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
csrfTokenCookie = "__Csrf_token"
|
||||
sessionTokenCookie = "__Session_token"
|
||||
@ -24,6 +28,12 @@ type AuthResolver struct {
|
||||
authStorage storage.AuthStorage
|
||||
}
|
||||
|
||||
func NewAuthResolver(authStorage storage.AuthStorage) *AuthResolver {
|
||||
return &AuthResolver{
|
||||
authStorage: authStorage,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *AuthResolver) Resolve(ctx context.Context, req *common.Request) error {
|
||||
return r.authorize(ctx, req)
|
||||
}
|
Loading…
Reference in New Issue
Block a user