Compare commits

..

2 Commits

37 changed files with 433 additions and 1466 deletions

View File

@ -26,7 +26,7 @@ func main() {
engine := filesengine.NewFilesEngine(nil, nil) engine := filesengine.NewFilesEngine(nil, nil)
go app.New(pg, engine). go app.New(ctx, pg, engine).
Run(ctx) Run(ctx)
<-ctx.Done() <-ctx.Done()

7
go.mod
View File

@ -3,7 +3,6 @@ module git.optclblast.xyz/draincloud/draincloud-core
go 1.23.0 go 1.23.0
require ( require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/fatih/color v1.17.0 github.com/fatih/color v1.17.0
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.7.0
github.com/gin-gonic/gin v1.10.0 github.com/gin-gonic/gin v1.10.0
@ -12,9 +11,9 @@ require (
github.com/jmoiron/sqlx v1.4.0 github.com/jmoiron/sqlx v1.4.0
github.com/nats-io/nats.go v1.37.0 github.com/nats-io/nats.go v1.37.0
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.28.0 golang.org/x/crypto v0.28.0
golang.org/x/sync v0.8.0 golang.org/x/sync v0.8.0
google.golang.org/grpc v1.62.1
) )
require ( require (
@ -28,6 +27,7 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
@ -44,7 +44,6 @@ require (
github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect github.com/nats-io/nuid v1.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect
@ -52,7 +51,6 @@ require (
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
@ -63,6 +61,7 @@ require (
golang.org/x/net v0.25.0 // indirect golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/text v0.19.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

16
go.sum
View File

@ -36,8 +36,12 @@ github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpv
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -115,7 +119,6 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -153,6 +156,13 @@ golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
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=

View File

@ -2,14 +2,12 @@ package app
import ( import (
"context" "context"
"errors"
"net/http"
"git.optclblast.xyz/draincloud/draincloud-core/internal/app/handlers" "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" filesengine "git.optclblast.xyz/draincloud/draincloud-core/internal/files_engine"
"git.optclblast.xyz/draincloud/draincloud-core/internal/processor" "git.optclblast.xyz/draincloud/draincloud-core/internal/processor"
resolvedispatcher "git.optclblast.xyz/draincloud/draincloud-core/internal/resolve_dispatcher" 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" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -23,12 +21,18 @@ type DrainCloud struct {
} }
func New( func New(
ctx context.Context,
database storage.Database, database storage.Database,
filesEngine *filesengine.FilesEngine, filesEngine *filesengine.FilesEngine,
) *DrainCloud { ) *DrainCloud {
mux := gin.Default() mux := gin.Default()
dispatcher := resolvedispatcher.New() dispatcher := resolvedispatcher.New()
dispatcher.RegisterResolver(
ctx,
auth.AuthResolverV1Name,
auth.NewAuthResolver(database),
)
d := &DrainCloud{ d := &DrainCloud{
database: database, database: database,
@ -36,19 +40,36 @@ func New(
ginProcessor: processor.NewGinProcessor(database, dispatcher), ginProcessor: processor.NewGinProcessor(database, dispatcher),
} }
// TODO. Maybe overkill
internalGroup := mux.Group("/_internal")
{
regGroup := internalGroup.Group("/register")
{
regGroup.POST("/resolver", d.ginProcessor.Process(
handlers.NewInternalRegisterResolverHandler(dispatcher),
))
regGroup.POST("/plugin", func(ctx *gin.Context) {})
}
}
// Built-in auth component of DrainCloud-Core // Built-in auth component of DrainCloud-Core
authGroup := mux.Group("/auth") authGroup := mux.Group("/auth")
{ {
// authGroup.POST("/register", d.Register)
authGroup.POST("/register", d.ginProcessor.Process( authGroup.POST("/register", d.ginProcessor.Process(
handlers.NewRegisterHandler(database), handlers.NewRegisterHandler(database),
)) ))
authGroup.POST("/logon", d.Login) authGroup.POST("/logon", d.ginProcessor.Process(
handlers.NewLogonHandler(database),
))
} }
filesGroup := mux.Group("/files") filesGroup := mux.Group("/files")
{ {
filesGroup.POST("/upload", d.UploadFile) filesGroup.POST("/upload", d.ginProcessor.Process(
handlers.NewUploadFileHandler(filesEngine),
))
} }
d.mux = mux d.mux = mux
@ -59,23 +80,3 @@ func New(
func (d *DrainCloud) Run(ctx context.Context) error { func (d *DrainCloud) Run(ctx context.Context) error {
return d.mux.Run() 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",
})
}
}

View File

@ -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
}

View File

@ -1,84 +1,100 @@
package app package handlers
import ( import (
"bytes" "bytes"
"context"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"log/slog" "log/slog"
"net/http" "net/http"
"time" "time"
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
"git.optclblast.xyz/draincloud/draincloud-core/internal/domain" "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/logger"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
"github.com/gin-gonic/gin" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
"github.com/google/uuid" "github.com/google/uuid"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
var ( type LogonHandler struct {
ErrorAccessDenied = errors.New("access denied") *handler.BaseHandler
ErrorSessionExpired = errors.New("session expired") authStorage storage.AuthStorage
) }
func (d *DrainCloud) Login(ctx *gin.Context) { func NewLogonHandler(
logger.Debug(ctx, "[Login] new request") authStorage storage.AuthStorage,
) *LogonHandler {
h := &LogonHandler{
authStorage: authStorage,
BaseHandler: handler.New().
WithName("logonv1").
WithRequiredResolveParams(),
}
h.WithProcessFunc(h.process)
return h
}
req := new(domain.LoginRequest) func (h *LogonHandler) process(ctx context.Context, req *common.Request, w handler.Writer) error {
err := ctx.BindJSON(req) logger.Debug(ctx, "[Logon] new request")
body := new(domain.LogonRequest)
err := json.Unmarshal(req.Body, body)
if err != nil { if err != nil {
logger.Error(ctx, "[Login] failed to bind request", logger.Err(err)) logger.Error(ctx, "[Logon] failed to bind request", logger.Err(err))
ctx.JSON(http.StatusBadRequest, map[string]string{ w.Write(ctx, map[string]string{
"error": "bad request", "error": "bad request",
}) }, handler.WithCode(http.StatusBadRequest))
return return nil
} }
resp, err := d.login(ctx, req) session, err := h.getSession(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)
if err != nil && !errors.Is(err, http.ErrNoCookie) { if err != nil && !errors.Is(err, http.ErrNoCookie) {
return nil, err return err
} }
if session != nil { if session != nil {
if err := validateSession(ctx, session); err != nil { if err := validateSession(req, session); err != nil {
// TODO add audit log entry // 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())) 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, 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 *auth.Session, w handler.Writer) (*domain.LogonResponse, error) {
passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10) passwordHash, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10)
if err != nil { if err != nil {
logger.Error(ctx, "[login] failed to generate password hash", logger.Err(err)) logger.Error(ctx, "[login] failed to generate password hash", logger.Err(err))
return nil, fmt.Errorf("failed to generate password hash: %w", 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 { if err != nil {
return nil, fmt.Errorf("failed to fetch user by login: %w", err) return nil, fmt.Errorf("failed to fetch user by login: %w", err)
} }
if bytes.Equal(passwordHash, user.PasswordHash) { if bytes.Equal(passwordHash, user.PasswordHash) {
logger.Warn(ctx, "[login] failed to login user. passwords hashes not equal") logger.Warn(ctx, "[login] failed to login user. passwords hashes not equal")
return nil, ErrorAccessDenied return nil, errs.ErrorAccessDenied
} }
sessionCreatedAt := time.Now() sessionCreatedAt := time.Now()
@ -88,20 +104,20 @@ func (d *DrainCloud) login(ctx *gin.Context, req *domain.LoginRequest) (*domain.
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to generate a session token: %w", err) 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) csrfToken, err := generateSessionToken(100)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to generate a csrf token: %w", err) 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() sessionID, err := uuid.NewV7()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to generate session id: %w", err) 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, &auth.Session{
ID: sessionID, ID: sessionID,
SessionToken: sessionToken, SessionToken: sessionToken,
CsrfToken: csrfToken, CsrfToken: csrfToken,
@ -114,17 +130,17 @@ func (d *DrainCloud) login(ctx *gin.Context, req *domain.LoginRequest) (*domain.
// TODO add audit log entry // TODO add audit log entry
return &domain.LoginResponse{ return &domain.LogonResponse{
Ok: true, Ok: true,
}, nil }, nil
} }
func (d *DrainCloud) getSession(ctx *gin.Context) (*models.Session, error) { func (h *LogonHandler) getSession(ctx context.Context, req *common.Request) (*auth.Session, error) {
token, err := ctx.Cookie(sessionTokenCookie) token, err := common.GetValue[string](req.Metadata, sessionTokenCookie)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch session cookie from request: %w", err) 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 { if err != nil {
return nil, fmt.Errorf("failed to fetch csrf cookie from request: %w", err) 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") 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 { if err != nil {
return nil, fmt.Errorf("failed to fetch session from repo: %w", err) 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 return session, nil
} }
func validateSession(ctx *gin.Context, session *models.Session) error { func validateSession(req *common.Request, session *auth.Session) error {
if session == nil { if session == nil {
return ErrorAccessDenied return errs.ErrorAccessDenied
} }
csrfToken, err := ctx.Cookie(csrfTokenCookie) csrfToken, err := common.GetValue[string](req.Metadata, csrfTokenCookie)
if err != nil { if err != nil {
return fmt.Errorf("failed to fetch csrf cookie from request: %w", err) return fmt.Errorf("failed to fetch csrf cookie from request: %w", err)
} }
if session.CsrfToken != csrfToken { if session.CsrfToken != csrfToken {
return ErrorAccessDenied return errs.ErrorAccessDenied
} }
if session.ExpiredAt.Before(time.Now()) { if session.ExpiredAt.Before(time.Now()) {
return ErrorSessionExpired return errs.ErrorSessionExpired
} }
return nil return nil

View File

@ -11,7 +11,7 @@ import (
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler" "git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
"github.com/google/uuid" "github.com/google/uuid"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@ -71,7 +71,7 @@ func (d *RegisterHandler) register(
return nil, fmt.Errorf("failed to generate user id: %w", err) return nil, fmt.Errorf("failed to generate user id: %w", err)
} }
user := &models.User{ user := &auth.User{
ID: userID, ID: userID,
Username: req.Login, Username: req.Login,
Login: req.Login, Login: req.Login,
@ -103,7 +103,7 @@ func (d *RegisterHandler) register(
return nil, fmt.Errorf("failed to generate session id: %w", err) return nil, fmt.Errorf("failed to generate session id: %w", err)
} }
if _, err = d.authStorage.AddSession(ctx, &models.Session{ if _, err = d.authStorage.AddSession(ctx, &auth.Session{
ID: sessionID, ID: sessionID,
SessionToken: sessionToken, SessionToken: sessionToken,
CsrfToken: csrfToken, CsrfToken: csrfToken,

View File

@ -0,0 +1,38 @@
package handlers
import (
"context"
"fmt"
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
resolvedispatcher "git.optclblast.xyz/draincloud/draincloud-core/internal/resolve_dispatcher"
)
// TODO. Maybe remove
type InternalRegisterResolverHandler struct {
*handler.BaseHandler
resolveDispatcher *resolvedispatcher.ResolveDispatcher
}
func NewInternalRegisterResolverHandler(
resolveDispatcher *resolvedispatcher.ResolveDispatcher,
) *InternalRegisterResolverHandler {
h := &InternalRegisterResolverHandler{
resolveDispatcher: resolveDispatcher,
}
h.BaseHandler = handler.New().
WithName("internal_registerresolver").
WithProcessFunc(h.process)
return h
}
func (h *InternalRegisterResolverHandler) process(
ctx context.Context,
req *common.Request,
w handler.Writer,
) error {
//_, ok := h.resolveDispatcher.GetResolver()
return fmt.Errorf("uniplemented")
}

View File

@ -0,0 +1,95 @@
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/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,
// TODO with MultipartReaderResolverV1Name
// or
// MultipartDataResolverV1Name
),
}
h.WithProcessFunc(h.process)
return h
}
func (d *UploadFileHandler) process(ctx context.Context, req *common.Request, w handler.Writer) error {
// TODO fetch (interface{ ParseMultipartForm(size int) error }) from req.GetValue[ParseMultipartFormer](req.ResolveValues)
// 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]
// }

View File

@ -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)
}
}

View File

@ -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]
}

View File

@ -3,6 +3,8 @@ package closer
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"sync/atomic"
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
) )
@ -12,14 +14,22 @@ var globalCloser *Closer = &Closer{
} }
type Closer struct { type Closer struct {
_lock atomic.Bool
closeFns []func() error closeFns []func() error
} }
func (c *Closer) Add(fn func() error) { func (c *Closer) Add(fn func() error) {
if c._lock.Load() {
return
}
c.closeFns = append(c.closeFns, fn) c.closeFns = append(c.closeFns, fn)
} }
func (c *Closer) Close() error { func (c *Closer) Close() error {
if !c._lock.CompareAndSwap(false, true) {
return fmt.Errorf("already closed")
}
var commonErr error var commonErr error
for _, fn := range c.closeFns { for _, fn := range c.closeFns {
if err := fn(); err != nil { if err := fn(); err != nil {

View File

@ -8,7 +8,7 @@ import (
"sync" "sync"
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
"github.com/google/uuid" "github.com/google/uuid"
) )
@ -46,15 +46,14 @@ func NewRequestPool() *RequestPool {
type Request struct { type Request struct {
ID string ID string
Session *models.Session Session *auth.Session
User *models.User User *auth.User
// ResolveValues - data required to process request. // ResolveValues - data required to process request.
ResolveValues *sync.Map ResolveValues *sync.Map
// Metadata - an additional data, usually added with preprocessing. // Metadata - an additional data, usually added with preprocessing.
Metadata *sync.Map Metadata *sync.Map
// Request body // Request body
Body []byte Body []byte
RawReq *http.Request
} }
// NewRequestFromHttp builds a new *Request struct from raw http Request. No auth data validated. // NewRequestFromHttp builds a new *Request struct from raw http Request. No auth data validated.
@ -65,7 +64,6 @@ func NewRequestFromHttp(pool *RequestPool, req *http.Request) *Request {
headers := req.Header headers := req.Header
out.Metadata = &sync.Map{} out.Metadata = &sync.Map{}
out.RawReq = req
for _, cookie := range cookies { for _, cookie := range cookies {
out.Metadata.Store(cookie.Name, cookie.Value) out.Metadata.Store(cookie.Name, cookie.Value)

View File

@ -0,0 +1,7 @@
package domain
type RegisterResolverRequest struct {
ResolverName string `json:"resolver_name"`
ResolverEndpoint string `json:"resolver_endpoint"`
RequiredResolveParams []string `json:"required_resolve_params"`
}

View File

@ -10,12 +10,12 @@ type RegisterResponse struct {
Message string `json:"message"` Message string `json:"message"`
} }
type LoginRequest struct { type LogonRequest struct {
Login string `json:"login"` Login string `json:"login"`
Password string `json:"password"` Password string `json:"password"`
} }
type LoginResponse struct { type LogonResponse struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Message string `json:"message"` Message string `json:"message"`
} }

View File

@ -0,0 +1,9 @@
package handler
import (
"context"
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
)
type CallHandler func(ctx context.Context, req *common.Request) ([]byte, error)

View File

@ -6,8 +6,20 @@ import (
"git.optclblast.xyz/draincloud/draincloud-core/internal/common" "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 { 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) SetCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool)
} }

View File

@ -0,0 +1,24 @@
package plugin
import (
"context"
"fmt"
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
)
type PluginHandler struct {
*handler.BaseHandler
store *PluginStore
}
func (_ *PluginHandler) GetName() string {
return "pluginv1"
}
func (p *PluginHandler) GetProcessFn() func(ctx context.Context, req *common.Request, w handler.Writer) error {
return func(ctx context.Context, req *common.Request, w handler.Writer) error {
return fmt.Errorf("unimplemented")
}
}

View File

@ -23,6 +23,15 @@ func (s *PluginStore) Add(plugin *Plugin) {
s.plugins[PluginStoreKey(plugin.md.Namespace, plugin.md.Name, plugin.md.Version)] = plugin s.plugins[PluginStoreKey(plugin.md.Namespace, plugin.md.Name, plugin.md.Version)] = plugin
} }
func (s *PluginStore) Get(plugin string) *Plugin {
s.m.RLock()
defer s.m.RUnlock()
if p, ok := s.plugins[plugin]; ok {
return p
}
return nil
}
func PluginStoreKey(ns, name string, v int) string { func PluginStoreKey(ns, name string, v int) string {
return fmt.Sprintf("%s.%s.%v", ns, name, v) return fmt.Sprintf("%s.%s.%v", ns, name, v)
} }

View File

@ -48,10 +48,12 @@ func (p *GinProcessor) Process(handler handler.Handler) gin.HandlerFunc {
} }
// 3. Call preprocessing fn's, middlewares etc. // 3. Call preprocessing fn's, middlewares etc.
if err = handler.GetPreprocessFn()(ctx, req, wrapGin(ctx)); err != nil { if preprocessFn := handler.GetPreprocessFn(); preprocessFn != nil {
if err = preprocessFn(ctx, req, wrapGin(ctx)); err != nil {
p.writeError(ctx, err) p.writeError(ctx, err)
return return
} }
}
// 4. Call handler.ProcessFn // 4. Call handler.ProcessFn
if err = handler.GetProcessFn()(ctx, req, wrapGin(ctx)); err != nil { if err = handler.GetProcessFn()(ctx, req, wrapGin(ctx)); err != nil {
@ -61,8 +63,8 @@ func (p *GinProcessor) Process(handler handler.Handler) gin.HandlerFunc {
} }
} }
func (p *GinProcessor) resolve(ctx context.Context, h handler.Handler, req *common.Request) error { func (p *GinProcessor) resolve(ctx *gin.Context, h handler.Handler, req *common.Request) error {
eg, ctx := errgroup.WithContext(ctx) eg, c := errgroup.WithContext(ctx)
for _, r := range h.GetRequiredResolveParams() { for _, r := range h.GetRequiredResolveParams() {
resolver, err := p.resolveDispatcher.GetResolver(r) resolver, err := p.resolveDispatcher.GetResolver(r)
if err != nil { if err != nil {
@ -71,7 +73,7 @@ func (p *GinProcessor) resolve(ctx context.Context, h handler.Handler, req *comm
resolveValueName := r resolveValueName := r
eg.Go(func() error { eg.Go(func() error {
if resolveErr := resolver.Resolve(ctx, req); resolveErr != nil { if resolveErr := resolver.Resolve(c, req, ctx); resolveErr != nil {
return fmt.Errorf("failed to resolve '%s' value: %w", resolveValueName, resolveErr) return fmt.Errorf("failed to resolve '%s' value: %w", resolveValueName, resolveErr)
} }
return nil return nil
@ -87,6 +89,9 @@ func (p *GinProcessor) resolve(ctx context.Context, h handler.Handler, req *comm
func (p *GinProcessor) writeError(ctx *gin.Context, err error) { func (p *GinProcessor) writeError(ctx *gin.Context, err error) {
logger.Error(ctx, "error process request", logger.Err(err)) logger.Error(ctx, "error process request", logger.Err(err))
// TODO do a custom error handling for resolvers / handlers / processors etc
switch { switch {
case errors.Is(err, errs.ErrorAccessDenied): case errors.Is(err, errs.ErrorAccessDenied):
ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{ ctx.JSON(http.StatusInternalServerError, domain.ErrorJson{

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"net/http" "net/http"
"git.optclblast.xyz/draincloud/draincloud-core/internal/handler"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -17,8 +18,15 @@ func wrapGin(ctx *gin.Context) ginWriter {
} }
} }
func (w ginWriter) Write(ctx context.Context, resp any) { func (w ginWriter) Write(ctx context.Context, resp any, opts ...handler.WriteOption) {
w.ctx.JSON(http.StatusOK, resp) 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) { func (w ginWriter) SetCookie(name string, value string, maxAge int, path string, domain string, secure bool, httpOnly bool) {

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
"github.com/google/uuid" "github.com/google/uuid"
) )
@ -26,12 +26,12 @@ func GetUserID(ctx context.Context) (uuid.UUID, error) {
return uuid.Nil, fmt.Errorf("userID not passed with context") return uuid.Nil, fmt.Errorf("userID not passed with context")
} }
func WithSession(parent context.Context, session *models.Session) context.Context { func WithSession(parent context.Context, session *auth.Session) context.Context {
return context.WithValue(parent, SessionCtxKey, session) return context.WithValue(parent, SessionCtxKey, session)
} }
func GetSession(ctx context.Context) (*models.Session, error) { func GetSession(ctx context.Context) (*auth.Session, error) {
if ses, ok := ctx.Value(UserIDCtxKey).(*models.Session); ok { if ses, ok := ctx.Value(UserIDCtxKey).(*auth.Session); ok {
return ses, nil return ses, nil
} }
return nil, fmt.Errorf("session not passed with context") return nil, fmt.Errorf("session not passed with context")

View File

@ -12,7 +12,11 @@ import (
"git.optclblast.xyz/draincloud/draincloud-core/internal/errs" "git.optclblast.xyz/draincloud/draincloud-core/internal/errs"
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" models "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
)
const (
AuthResolverV1Name = "auth.v1"
) )
const ( const (
@ -24,10 +28,20 @@ type AuthResolver struct {
authStorage storage.AuthStorage authStorage storage.AuthStorage
} }
func (r *AuthResolver) Resolve(ctx context.Context, req *common.Request) error { func NewAuthResolver(authStorage storage.AuthStorage) *AuthResolver {
return &AuthResolver{
authStorage: authStorage,
}
}
func (r *AuthResolver) Resolve(ctx context.Context, req *common.Request, _ any) error {
return r.authorize(ctx, req) return r.authorize(ctx, req)
} }
func (r *AuthResolver) GetRequiredResolveParams() []string {
return nil
}
func (p *AuthResolver) authorize(ctx context.Context, req *common.Request) error { func (p *AuthResolver) authorize(ctx context.Context, req *common.Request) error {
session, err := p.getSession(ctx, req) session, err := p.getSession(ctx, req)
if err != nil && !errors.Is(err, http.ErrNoCookie) { if err != nil && !errors.Is(err, http.ErrNoCookie) {

View File

@ -0,0 +1,33 @@
package pluginname
import (
"context"
"git.optclblast.xyz/draincloud/draincloud-core/internal/common"
"github.com/gin-gonic/gin"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const (
PluginNameResolverName = "plugin_name"
)
type PluginNameResolver struct{}
func (p *PluginNameResolver) Resolve(ctx context.Context, req *common.Request, rawReq any) error {
ginCtx, ok := rawReq.(*gin.Context)
if !ok {
return status.Errorf(codes.Internal, "invalid request type")
}
pluginName := ginCtx.Param("plugin_name")
if pluginName == "" {
return status.Error(codes.InvalidArgument, "plugin name is empty")
}
req.ResolveValues.Store(PluginNameResolverName, pluginName)
return nil
}
func (p *PluginNameResolver) GetRequiredResolveParams() []string {
return nil
}

View File

@ -7,5 +7,6 @@ import (
) )
type Resolver interface { type Resolver interface {
Resolve(ctx context.Context, req *common.Request) error Resolve(ctx context.Context, req *common.Request, reqReq any) error
GetRequiredResolveParams() []string
} }

View File

@ -0,0 +1,6 @@
package seal
// TODO
type SealResolver struct {
wardenClient any
}

View File

@ -12,6 +12,8 @@ import (
type Storage struct { type Storage struct {
lm *sync.Map lm *sync.Map
dir string dir string
// If file is not belongs to current node FS - redirect to corresponding node
// cluster DrainCloudCluster
} }
func NewFSStorage(dir string) *Storage { func NewFSStorage(dir string) *Storage {
@ -63,8 +65,6 @@ func (s *Storage) DeleteFile(ctx context.Context, id int64) error {
tx := lockFile(s.lm, id) tx := lockFile(s.lm, id)
defer unlockFile(s.lm, id, tx) defer unlockFile(s.lm, id, tx)
return nil return nil
} }

View File

@ -4,8 +4,8 @@ import (
"context" "context"
"os" "os"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
auditmodels "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/audit" auditmodels "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/audit"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/files" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/files"
"github.com/google/uuid" "github.com/google/uuid"
) )
@ -16,11 +16,11 @@ type Database interface {
type AuthStorage interface { type AuthStorage interface {
AddUser(ctx context.Context, id uuid.UUID, login string, username string, passwordHash []byte) error AddUser(ctx context.Context, id uuid.UUID, login string, username string, passwordHash []byte) error
GetUserByLogin(ctx context.Context, login string) (*models.User, error) GetUserByLogin(ctx context.Context, login string) (*auth.User, error)
GetUserByID(ctx context.Context, id uuid.UUID) (*models.User, error) GetUserByID(ctx context.Context, id uuid.UUID) (*auth.User, error)
AddSession(ctx context.Context, ses *models.Session) (uuid.UUID, error) AddSession(ctx context.Context, ses *auth.Session) (uuid.UUID, error)
GetSession(ctx context.Context, sessionToken string) (*models.Session, error) GetSession(ctx context.Context, sessionToken string) (*auth.Session, error)
RemoveSession(ctx context.Context, id uuid.UUID) error RemoveSession(ctx context.Context, id uuid.UUID) error
} }

View File

@ -1,4 +1,4 @@
package models package auth
import ( import (
"time" "time"

View File

@ -9,7 +9,7 @@ import (
"git.optclblast.xyz/draincloud/draincloud-core/internal/closer" "git.optclblast.xyz/draincloud/draincloud-core/internal/closer"
"git.optclblast.xyz/draincloud/draincloud-core/internal/logger" "git.optclblast.xyz/draincloud/draincloud-core/internal/logger"
"git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models" "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/auth"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgconn"
@ -45,19 +45,19 @@ func (d *Database) AddUser(ctx context.Context, id uuid.UUID, login string, user
return addUser(ctx, d.db, id, login, username, passwordHash) return addUser(ctx, d.db, id, login, username, passwordHash)
} }
func (d *Database) GetUserByID(ctx context.Context, id uuid.UUID) (*models.User, error) { func (d *Database) GetUserByID(ctx context.Context, id uuid.UUID) (*auth.User, error) {
return getUserByID(ctx, d.db, id) return getUserByID(ctx, d.db, id)
} }
func (d *Database) GetUserByLogin(ctx context.Context, login string) (*models.User, error) { func (d *Database) GetUserByLogin(ctx context.Context, login string) (*auth.User, error) {
return getUserByLogin(ctx, d.db, login) return getUserByLogin(ctx, d.db, login)
} }
func (d *Database) AddSession(ctx context.Context, ses *models.Session) (uuid.UUID, error) { func (d *Database) AddSession(ctx context.Context, ses *auth.Session) (uuid.UUID, error) {
return addSession(ctx, d.db, ses) return addSession(ctx, d.db, ses)
} }
func (d *Database) GetSession(ctx context.Context, sessionToken string) (*models.Session, error) { func (d *Database) GetSession(ctx context.Context, sessionToken string) (*auth.Session, error) {
const stmt = `SELECT const stmt = `SELECT
s.id, s.session_token, s.csrf_token, s.user_id, s.created_at, s.expired_at s.id, s.session_token, s.csrf_token, s.user_id, s.created_at, s.expired_at
FROM sessions as s FROM sessions as s
@ -77,7 +77,7 @@ func (d *Database) GetSession(ctx context.Context, sessionToken string) (*models
return nil, err return nil, err
} }
return &models.Session{ return &auth.Session{
ID: id, ID: id,
SessionToken: sesToken, SessionToken: sesToken,
CsrfToken: csrfToken, CsrfToken: csrfToken,
@ -112,9 +112,9 @@ func addUser(ctx context.Context, conn dbtx, id uuid.UUID, login string, usernam
return nil return nil
} }
func getUserByID(ctx context.Context, conn dbtx, id uuid.UUID) (*models.User, error) { func getUserByID(ctx context.Context, conn dbtx, id uuid.UUID) (*auth.User, error) {
const stmt = `SELECT * FROM users WHERE id = $1 LIMIT 1` const stmt = `SELECT * FROM users WHERE id = $1 LIMIT 1`
u := new(models.User) u := new(auth.User)
row := conn.QueryRow(ctx, stmt, id) row := conn.QueryRow(ctx, stmt, id)
if err := row.Scan(&u.ID, &u.Login, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt); err != nil { if err := row.Scan(&u.ID, &u.Login, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt); err != nil {
return nil, fmt.Errorf("failed to fetch user by id: %w", err) return nil, fmt.Errorf("failed to fetch user by id: %w", err)
@ -123,9 +123,9 @@ func getUserByID(ctx context.Context, conn dbtx, id uuid.UUID) (*models.User, er
return u, nil return u, nil
} }
func getUserByLogin(ctx context.Context, conn dbtx, login string) (*models.User, error) { func getUserByLogin(ctx context.Context, conn dbtx, login string) (*auth.User, error) {
const stmt = `SELECT * FROM users WHERE login = $1 LIMIT 1` const stmt = `SELECT * FROM users WHERE login = $1 LIMIT 1`
u := new(models.User) u := new(auth.User)
row := conn.QueryRow(ctx, stmt, login) row := conn.QueryRow(ctx, stmt, login)
if err := row.Scan(&u.ID, &u.Login, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt); err != nil { if err := row.Scan(&u.ID, &u.Login, &u.Username, &u.PasswordHash, &u.CreatedAt, &u.UpdatedAt); err != nil {
return nil, fmt.Errorf("failed to fetch user by login: %w", err) return nil, fmt.Errorf("failed to fetch user by login: %w", err)
@ -134,7 +134,7 @@ func getUserByLogin(ctx context.Context, conn dbtx, login string) (*models.User,
return u, nil return u, nil
} }
func addSession(ctx context.Context, conn dbtx, session *models.Session) (uuid.UUID, error) { func addSession(ctx context.Context, conn dbtx, session *auth.Session) (uuid.UUID, error) {
const stmt = `INSERT INTO sessions (id,session_token, csrf_token, user_id, const stmt = `INSERT INTO sessions (id,session_token, csrf_token, user_id,
created_at, expired_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id;` created_at, expired_at) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id;`
var id uuid.UUID var id uuid.UUID

View File

@ -1,3 +1,4 @@
// TODO wtf?
package pool package pool
import ( import (

View File

@ -1,85 +0,0 @@
// Code generated by mockery v2.48.0. DO NOT EDIT.
package storage
import (
context "context"
audit "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models/audit"
mock "github.com/stretchr/testify/mock"
)
// MockAuthAuditLogStorage is an autogenerated mock type for the AuthAuditLogStorage type
type MockAuthAuditLogStorage struct {
mock.Mock
}
type MockAuthAuditLogStorage_Expecter struct {
mock *mock.Mock
}
func (_m *MockAuthAuditLogStorage) EXPECT() *MockAuthAuditLogStorage_Expecter {
return &MockAuthAuditLogStorage_Expecter{mock: &_m.Mock}
}
// AddEntry provides a mock function with given fields: ctx, entry
func (_m *MockAuthAuditLogStorage) AddEntry(ctx context.Context, entry audit.AuditLogEntry) error {
ret := _m.Called(ctx, entry)
if len(ret) == 0 {
panic("no return value specified for AddEntry")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, audit.AuditLogEntry) error); ok {
r0 = rf(ctx, entry)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockAuthAuditLogStorage_AddEntry_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddEntry'
type MockAuthAuditLogStorage_AddEntry_Call struct {
*mock.Call
}
// AddEntry is a helper method to define mock.On call
// - ctx context.Context
// - entry audit.AuditLogEntry
func (_e *MockAuthAuditLogStorage_Expecter) AddEntry(ctx interface{}, entry interface{}) *MockAuthAuditLogStorage_AddEntry_Call {
return &MockAuthAuditLogStorage_AddEntry_Call{Call: _e.mock.On("AddEntry", ctx, entry)}
}
func (_c *MockAuthAuditLogStorage_AddEntry_Call) Run(run func(ctx context.Context, entry audit.AuditLogEntry)) *MockAuthAuditLogStorage_AddEntry_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(audit.AuditLogEntry))
})
return _c
}
func (_c *MockAuthAuditLogStorage_AddEntry_Call) Return(_a0 error) *MockAuthAuditLogStorage_AddEntry_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockAuthAuditLogStorage_AddEntry_Call) RunAndReturn(run func(context.Context, audit.AuditLogEntry) error) *MockAuthAuditLogStorage_AddEntry_Call {
_c.Call.Return(run)
return _c
}
// NewMockAuthAuditLogStorage creates a new instance of MockAuthAuditLogStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockAuthAuditLogStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockAuthAuditLogStorage {
mock := &MockAuthAuditLogStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,377 +0,0 @@
// Code generated by mockery v2.48.0. DO NOT EDIT.
package storage
import (
context "context"
models "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
mock "github.com/stretchr/testify/mock"
)
// MockAuthStorage is an autogenerated mock type for the AuthStorage type
type MockAuthStorage struct {
mock.Mock
}
type MockAuthStorage_Expecter struct {
mock *mock.Mock
}
func (_m *MockAuthStorage) EXPECT() *MockAuthStorage_Expecter {
return &MockAuthStorage_Expecter{mock: &_m.Mock}
}
// AddSession provides a mock function with given fields: ctx, ses
func (_m *MockAuthStorage) AddSession(ctx context.Context, ses *models.Session) (int64, error) {
ret := _m.Called(ctx, ses)
if len(ret) == 0 {
panic("no return value specified for AddSession")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *models.Session) (int64, error)); ok {
return rf(ctx, ses)
}
if rf, ok := ret.Get(0).(func(context.Context, *models.Session) int64); ok {
r0 = rf(ctx, ses)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, *models.Session) error); ok {
r1 = rf(ctx, ses)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockAuthStorage_AddSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddSession'
type MockAuthStorage_AddSession_Call struct {
*mock.Call
}
// AddSession is a helper method to define mock.On call
// - ctx context.Context
// - ses *models.Session
func (_e *MockAuthStorage_Expecter) AddSession(ctx interface{}, ses interface{}) *MockAuthStorage_AddSession_Call {
return &MockAuthStorage_AddSession_Call{Call: _e.mock.On("AddSession", ctx, ses)}
}
func (_c *MockAuthStorage_AddSession_Call) Run(run func(ctx context.Context, ses *models.Session)) *MockAuthStorage_AddSession_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*models.Session))
})
return _c
}
func (_c *MockAuthStorage_AddSession_Call) Return(_a0 int64, _a1 error) *MockAuthStorage_AddSession_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockAuthStorage_AddSession_Call) RunAndReturn(run func(context.Context, *models.Session) (int64, error)) *MockAuthStorage_AddSession_Call {
_c.Call.Return(run)
return _c
}
// AddUser provides a mock function with given fields: ctx, login, username, passwordHash
func (_m *MockAuthStorage) AddUser(ctx context.Context, login string, username string, passwordHash []byte) (int64, error) {
ret := _m.Called(ctx, login, username, passwordHash)
if len(ret) == 0 {
panic("no return value specified for AddUser")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) (int64, error)); ok {
return rf(ctx, login, username, passwordHash)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) int64); ok {
r0 = rf(ctx, login, username, passwordHash)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, string, string, []byte) error); ok {
r1 = rf(ctx, login, username, passwordHash)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockAuthStorage_AddUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUser'
type MockAuthStorage_AddUser_Call struct {
*mock.Call
}
// AddUser is a helper method to define mock.On call
// - ctx context.Context
// - login string
// - username string
// - passwordHash []byte
func (_e *MockAuthStorage_Expecter) AddUser(ctx interface{}, login interface{}, username interface{}, passwordHash interface{}) *MockAuthStorage_AddUser_Call {
return &MockAuthStorage_AddUser_Call{Call: _e.mock.On("AddUser", ctx, login, username, passwordHash)}
}
func (_c *MockAuthStorage_AddUser_Call) Run(run func(ctx context.Context, login string, username string, passwordHash []byte)) *MockAuthStorage_AddUser_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].([]byte))
})
return _c
}
func (_c *MockAuthStorage_AddUser_Call) Return(_a0 int64, _a1 error) *MockAuthStorage_AddUser_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockAuthStorage_AddUser_Call) RunAndReturn(run func(context.Context, string, string, []byte) (int64, error)) *MockAuthStorage_AddUser_Call {
_c.Call.Return(run)
return _c
}
// GetSession provides a mock function with given fields: ctx, sessionToken
func (_m *MockAuthStorage) GetSession(ctx context.Context, sessionToken string) (*models.Session, error) {
ret := _m.Called(ctx, sessionToken)
if len(ret) == 0 {
panic("no return value specified for GetSession")
}
var r0 *models.Session
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.Session, error)); ok {
return rf(ctx, sessionToken)
}
if rf, ok := ret.Get(0).(func(context.Context, string) *models.Session); ok {
r0 = rf(ctx, sessionToken)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.Session)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, sessionToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockAuthStorage_GetSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSession'
type MockAuthStorage_GetSession_Call struct {
*mock.Call
}
// GetSession is a helper method to define mock.On call
// - ctx context.Context
// - sessionToken string
func (_e *MockAuthStorage_Expecter) GetSession(ctx interface{}, sessionToken interface{}) *MockAuthStorage_GetSession_Call {
return &MockAuthStorage_GetSession_Call{Call: _e.mock.On("GetSession", ctx, sessionToken)}
}
func (_c *MockAuthStorage_GetSession_Call) Run(run func(ctx context.Context, sessionToken string)) *MockAuthStorage_GetSession_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockAuthStorage_GetSession_Call) Return(_a0 *models.Session, _a1 error) *MockAuthStorage_GetSession_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockAuthStorage_GetSession_Call) RunAndReturn(run func(context.Context, string) (*models.Session, error)) *MockAuthStorage_GetSession_Call {
_c.Call.Return(run)
return _c
}
// GetUserByID provides a mock function with given fields: ctx, id
func (_m *MockAuthStorage) GetUserByID(ctx context.Context, id uint64) (*models.User, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for GetUserByID")
}
var r0 *models.User
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, uint64) (*models.User, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, uint64) *models.User); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User)
}
}
if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockAuthStorage_GetUserByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByID'
type MockAuthStorage_GetUserByID_Call struct {
*mock.Call
}
// GetUserByID is a helper method to define mock.On call
// - ctx context.Context
// - id uint64
func (_e *MockAuthStorage_Expecter) GetUserByID(ctx interface{}, id interface{}) *MockAuthStorage_GetUserByID_Call {
return &MockAuthStorage_GetUserByID_Call{Call: _e.mock.On("GetUserByID", ctx, id)}
}
func (_c *MockAuthStorage_GetUserByID_Call) Run(run func(ctx context.Context, id uint64)) *MockAuthStorage_GetUserByID_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(uint64))
})
return _c
}
func (_c *MockAuthStorage_GetUserByID_Call) Return(_a0 *models.User, _a1 error) *MockAuthStorage_GetUserByID_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockAuthStorage_GetUserByID_Call) RunAndReturn(run func(context.Context, uint64) (*models.User, error)) *MockAuthStorage_GetUserByID_Call {
_c.Call.Return(run)
return _c
}
// GetUserByLogin provides a mock function with given fields: ctx, login
func (_m *MockAuthStorage) GetUserByLogin(ctx context.Context, login string) (*models.User, error) {
ret := _m.Called(ctx, login)
if len(ret) == 0 {
panic("no return value specified for GetUserByLogin")
}
var r0 *models.User
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.User, error)); ok {
return rf(ctx, login)
}
if rf, ok := ret.Get(0).(func(context.Context, string) *models.User); ok {
r0 = rf(ctx, login)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, login)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockAuthStorage_GetUserByLogin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByLogin'
type MockAuthStorage_GetUserByLogin_Call struct {
*mock.Call
}
// GetUserByLogin is a helper method to define mock.On call
// - ctx context.Context
// - login string
func (_e *MockAuthStorage_Expecter) GetUserByLogin(ctx interface{}, login interface{}) *MockAuthStorage_GetUserByLogin_Call {
return &MockAuthStorage_GetUserByLogin_Call{Call: _e.mock.On("GetUserByLogin", ctx, login)}
}
func (_c *MockAuthStorage_GetUserByLogin_Call) Run(run func(ctx context.Context, login string)) *MockAuthStorage_GetUserByLogin_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockAuthStorage_GetUserByLogin_Call) Return(_a0 *models.User, _a1 error) *MockAuthStorage_GetUserByLogin_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockAuthStorage_GetUserByLogin_Call) RunAndReturn(run func(context.Context, string) (*models.User, error)) *MockAuthStorage_GetUserByLogin_Call {
_c.Call.Return(run)
return _c
}
// RemoveSession provides a mock function with given fields: ctx, id
func (_m *MockAuthStorage) RemoveSession(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for RemoveSession")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockAuthStorage_RemoveSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSession'
type MockAuthStorage_RemoveSession_Call struct {
*mock.Call
}
// RemoveSession is a helper method to define mock.On call
// - ctx context.Context
// - id int64
func (_e *MockAuthStorage_Expecter) RemoveSession(ctx interface{}, id interface{}) *MockAuthStorage_RemoveSession_Call {
return &MockAuthStorage_RemoveSession_Call{Call: _e.mock.On("RemoveSession", ctx, id)}
}
func (_c *MockAuthStorage_RemoveSession_Call) Run(run func(ctx context.Context, id int64)) *MockAuthStorage_RemoveSession_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(int64))
})
return _c
}
func (_c *MockAuthStorage_RemoveSession_Call) Return(_a0 error) *MockAuthStorage_RemoveSession_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockAuthStorage_RemoveSession_Call) RunAndReturn(run func(context.Context, int64) error) *MockAuthStorage_RemoveSession_Call {
_c.Call.Return(run)
return _c
}
// NewMockAuthStorage creates a new instance of MockAuthStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockAuthStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockAuthStorage {
mock := &MockAuthStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,191 +0,0 @@
// Code generated by mockery v2.48.0. DO NOT EDIT.
package storage
import (
context "context"
os "os"
mock "github.com/stretchr/testify/mock"
)
// MockBlobStorage is an autogenerated mock type for the BlobStorage type
type MockBlobStorage struct {
mock.Mock
}
type MockBlobStorage_Expecter struct {
mock *mock.Mock
}
func (_m *MockBlobStorage) EXPECT() *MockBlobStorage_Expecter {
return &MockBlobStorage_Expecter{mock: &_m.Mock}
}
// DeleteFile provides a mock function with given fields: ctx, id
func (_m *MockBlobStorage) DeleteFile(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for DeleteFile")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockBlobStorage_DeleteFile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteFile'
type MockBlobStorage_DeleteFile_Call struct {
*mock.Call
}
// DeleteFile is a helper method to define mock.On call
// - ctx context.Context
// - id int64
func (_e *MockBlobStorage_Expecter) DeleteFile(ctx interface{}, id interface{}) *MockBlobStorage_DeleteFile_Call {
return &MockBlobStorage_DeleteFile_Call{Call: _e.mock.On("DeleteFile", ctx, id)}
}
func (_c *MockBlobStorage_DeleteFile_Call) Run(run func(ctx context.Context, id int64)) *MockBlobStorage_DeleteFile_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(int64))
})
return _c
}
func (_c *MockBlobStorage_DeleteFile_Call) Return(_a0 error) *MockBlobStorage_DeleteFile_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockBlobStorage_DeleteFile_Call) RunAndReturn(run func(context.Context, int64) error) *MockBlobStorage_DeleteFile_Call {
_c.Call.Return(run)
return _c
}
// GetFile provides a mock function with given fields: ctx, id
func (_m *MockBlobStorage) GetFile(ctx context.Context, id int64) (*os.File, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for GetFile")
}
var r0 *os.File
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64) (*os.File, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, int64) *os.File); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*os.File)
}
}
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockBlobStorage_GetFile_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetFile'
type MockBlobStorage_GetFile_Call struct {
*mock.Call
}
// GetFile is a helper method to define mock.On call
// - ctx context.Context
// - id int64
func (_e *MockBlobStorage_Expecter) GetFile(ctx interface{}, id interface{}) *MockBlobStorage_GetFile_Call {
return &MockBlobStorage_GetFile_Call{Call: _e.mock.On("GetFile", ctx, id)}
}
func (_c *MockBlobStorage_GetFile_Call) Run(run func(ctx context.Context, id int64)) *MockBlobStorage_GetFile_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(int64))
})
return _c
}
func (_c *MockBlobStorage_GetFile_Call) Return(_a0 *os.File, _a1 error) *MockBlobStorage_GetFile_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockBlobStorage_GetFile_Call) RunAndReturn(run func(context.Context, int64) (*os.File, error)) *MockBlobStorage_GetFile_Call {
_c.Call.Return(run)
return _c
}
// SaveBlob provides a mock function with given fields: ctx, id, data
func (_m *MockBlobStorage) SaveBlob(ctx context.Context, id int64, data []byte) error {
ret := _m.Called(ctx, id, data)
if len(ret) == 0 {
panic("no return value specified for SaveBlob")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64, []byte) error); ok {
r0 = rf(ctx, id, data)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockBlobStorage_SaveBlob_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveBlob'
type MockBlobStorage_SaveBlob_Call struct {
*mock.Call
}
// SaveBlob is a helper method to define mock.On call
// - ctx context.Context
// - id int64
// - data []byte
func (_e *MockBlobStorage_Expecter) SaveBlob(ctx interface{}, id interface{}, data interface{}) *MockBlobStorage_SaveBlob_Call {
return &MockBlobStorage_SaveBlob_Call{Call: _e.mock.On("SaveBlob", ctx, id, data)}
}
func (_c *MockBlobStorage_SaveBlob_Call) Run(run func(ctx context.Context, id int64, data []byte)) *MockBlobStorage_SaveBlob_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(int64), args[2].([]byte))
})
return _c
}
func (_c *MockBlobStorage_SaveBlob_Call) Return(_a0 error) *MockBlobStorage_SaveBlob_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockBlobStorage_SaveBlob_Call) RunAndReturn(run func(context.Context, int64, []byte) error) *MockBlobStorage_SaveBlob_Call {
_c.Call.Return(run)
return _c
}
// NewMockBlobStorage creates a new instance of MockBlobStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockBlobStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockBlobStorage {
mock := &MockBlobStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,377 +0,0 @@
// Code generated by mockery v2.48.0. DO NOT EDIT.
package storage
import (
context "context"
models "git.optclblast.xyz/draincloud/draincloud-core/internal/storage/models"
mock "github.com/stretchr/testify/mock"
)
// MockDatabase is an autogenerated mock type for the Database type
type MockDatabase struct {
mock.Mock
}
type MockDatabase_Expecter struct {
mock *mock.Mock
}
func (_m *MockDatabase) EXPECT() *MockDatabase_Expecter {
return &MockDatabase_Expecter{mock: &_m.Mock}
}
// AddSession provides a mock function with given fields: ctx, ses
func (_m *MockDatabase) AddSession(ctx context.Context, ses *models.Session) (int64, error) {
ret := _m.Called(ctx, ses)
if len(ret) == 0 {
panic("no return value specified for AddSession")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *models.Session) (int64, error)); ok {
return rf(ctx, ses)
}
if rf, ok := ret.Get(0).(func(context.Context, *models.Session) int64); ok {
r0 = rf(ctx, ses)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, *models.Session) error); ok {
r1 = rf(ctx, ses)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockDatabase_AddSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddSession'
type MockDatabase_AddSession_Call struct {
*mock.Call
}
// AddSession is a helper method to define mock.On call
// - ctx context.Context
// - ses *models.Session
func (_e *MockDatabase_Expecter) AddSession(ctx interface{}, ses interface{}) *MockDatabase_AddSession_Call {
return &MockDatabase_AddSession_Call{Call: _e.mock.On("AddSession", ctx, ses)}
}
func (_c *MockDatabase_AddSession_Call) Run(run func(ctx context.Context, ses *models.Session)) *MockDatabase_AddSession_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*models.Session))
})
return _c
}
func (_c *MockDatabase_AddSession_Call) Return(_a0 int64, _a1 error) *MockDatabase_AddSession_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockDatabase_AddSession_Call) RunAndReturn(run func(context.Context, *models.Session) (int64, error)) *MockDatabase_AddSession_Call {
_c.Call.Return(run)
return _c
}
// AddUser provides a mock function with given fields: ctx, login, username, passwordHash
func (_m *MockDatabase) AddUser(ctx context.Context, login string, username string, passwordHash []byte) (int64, error) {
ret := _m.Called(ctx, login, username, passwordHash)
if len(ret) == 0 {
panic("no return value specified for AddUser")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) (int64, error)); ok {
return rf(ctx, login, username, passwordHash)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string, []byte) int64); ok {
r0 = rf(ctx, login, username, passwordHash)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, string, string, []byte) error); ok {
r1 = rf(ctx, login, username, passwordHash)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockDatabase_AddUser_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddUser'
type MockDatabase_AddUser_Call struct {
*mock.Call
}
// AddUser is a helper method to define mock.On call
// - ctx context.Context
// - login string
// - username string
// - passwordHash []byte
func (_e *MockDatabase_Expecter) AddUser(ctx interface{}, login interface{}, username interface{}, passwordHash interface{}) *MockDatabase_AddUser_Call {
return &MockDatabase_AddUser_Call{Call: _e.mock.On("AddUser", ctx, login, username, passwordHash)}
}
func (_c *MockDatabase_AddUser_Call) Run(run func(ctx context.Context, login string, username string, passwordHash []byte)) *MockDatabase_AddUser_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].([]byte))
})
return _c
}
func (_c *MockDatabase_AddUser_Call) Return(_a0 int64, _a1 error) *MockDatabase_AddUser_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockDatabase_AddUser_Call) RunAndReturn(run func(context.Context, string, string, []byte) (int64, error)) *MockDatabase_AddUser_Call {
_c.Call.Return(run)
return _c
}
// GetSession provides a mock function with given fields: ctx, sessionToken
func (_m *MockDatabase) GetSession(ctx context.Context, sessionToken string) (*models.Session, error) {
ret := _m.Called(ctx, sessionToken)
if len(ret) == 0 {
panic("no return value specified for GetSession")
}
var r0 *models.Session
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.Session, error)); ok {
return rf(ctx, sessionToken)
}
if rf, ok := ret.Get(0).(func(context.Context, string) *models.Session); ok {
r0 = rf(ctx, sessionToken)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.Session)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, sessionToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockDatabase_GetSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSession'
type MockDatabase_GetSession_Call struct {
*mock.Call
}
// GetSession is a helper method to define mock.On call
// - ctx context.Context
// - sessionToken string
func (_e *MockDatabase_Expecter) GetSession(ctx interface{}, sessionToken interface{}) *MockDatabase_GetSession_Call {
return &MockDatabase_GetSession_Call{Call: _e.mock.On("GetSession", ctx, sessionToken)}
}
func (_c *MockDatabase_GetSession_Call) Run(run func(ctx context.Context, sessionToken string)) *MockDatabase_GetSession_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockDatabase_GetSession_Call) Return(_a0 *models.Session, _a1 error) *MockDatabase_GetSession_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockDatabase_GetSession_Call) RunAndReturn(run func(context.Context, string) (*models.Session, error)) *MockDatabase_GetSession_Call {
_c.Call.Return(run)
return _c
}
// GetUserByID provides a mock function with given fields: ctx, id
func (_m *MockDatabase) GetUserByID(ctx context.Context, id uint64) (*models.User, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for GetUserByID")
}
var r0 *models.User
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, uint64) (*models.User, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, uint64) *models.User); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User)
}
}
if rf, ok := ret.Get(1).(func(context.Context, uint64) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockDatabase_GetUserByID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByID'
type MockDatabase_GetUserByID_Call struct {
*mock.Call
}
// GetUserByID is a helper method to define mock.On call
// - ctx context.Context
// - id uint64
func (_e *MockDatabase_Expecter) GetUserByID(ctx interface{}, id interface{}) *MockDatabase_GetUserByID_Call {
return &MockDatabase_GetUserByID_Call{Call: _e.mock.On("GetUserByID", ctx, id)}
}
func (_c *MockDatabase_GetUserByID_Call) Run(run func(ctx context.Context, id uint64)) *MockDatabase_GetUserByID_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(uint64))
})
return _c
}
func (_c *MockDatabase_GetUserByID_Call) Return(_a0 *models.User, _a1 error) *MockDatabase_GetUserByID_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockDatabase_GetUserByID_Call) RunAndReturn(run func(context.Context, uint64) (*models.User, error)) *MockDatabase_GetUserByID_Call {
_c.Call.Return(run)
return _c
}
// GetUserByLogin provides a mock function with given fields: ctx, login
func (_m *MockDatabase) GetUserByLogin(ctx context.Context, login string) (*models.User, error) {
ret := _m.Called(ctx, login)
if len(ret) == 0 {
panic("no return value specified for GetUserByLogin")
}
var r0 *models.User
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*models.User, error)); ok {
return rf(ctx, login)
}
if rf, ok := ret.Get(0).(func(context.Context, string) *models.User); ok {
r0 = rf(ctx, login)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, login)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockDatabase_GetUserByLogin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetUserByLogin'
type MockDatabase_GetUserByLogin_Call struct {
*mock.Call
}
// GetUserByLogin is a helper method to define mock.On call
// - ctx context.Context
// - login string
func (_e *MockDatabase_Expecter) GetUserByLogin(ctx interface{}, login interface{}) *MockDatabase_GetUserByLogin_Call {
return &MockDatabase_GetUserByLogin_Call{Call: _e.mock.On("GetUserByLogin", ctx, login)}
}
func (_c *MockDatabase_GetUserByLogin_Call) Run(run func(ctx context.Context, login string)) *MockDatabase_GetUserByLogin_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockDatabase_GetUserByLogin_Call) Return(_a0 *models.User, _a1 error) *MockDatabase_GetUserByLogin_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockDatabase_GetUserByLogin_Call) RunAndReturn(run func(context.Context, string) (*models.User, error)) *MockDatabase_GetUserByLogin_Call {
_c.Call.Return(run)
return _c
}
// RemoveSession provides a mock function with given fields: ctx, id
func (_m *MockDatabase) RemoveSession(ctx context.Context, id int64) error {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for RemoveSession")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockDatabase_RemoveSession_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveSession'
type MockDatabase_RemoveSession_Call struct {
*mock.Call
}
// RemoveSession is a helper method to define mock.On call
// - ctx context.Context
// - id int64
func (_e *MockDatabase_Expecter) RemoveSession(ctx interface{}, id interface{}) *MockDatabase_RemoveSession_Call {
return &MockDatabase_RemoveSession_Call{Call: _e.mock.On("RemoveSession", ctx, id)}
}
func (_c *MockDatabase_RemoveSession_Call) Run(run func(ctx context.Context, id int64)) *MockDatabase_RemoveSession_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(int64))
})
return _c
}
func (_c *MockDatabase_RemoveSession_Call) Return(_a0 error) *MockDatabase_RemoveSession_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockDatabase_RemoveSession_Call) RunAndReturn(run func(context.Context, int64) error) *MockDatabase_RemoveSession_Call {
_c.Call.Return(run)
return _c
}
// NewMockDatabase creates a new instance of MockDatabase. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockDatabase(t interface {
mock.TestingT
Cleanup(func())
}) *MockDatabase {
mock := &MockDatabase{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,32 +0,0 @@
// Code generated by mockery v2.48.0. DO NOT EDIT.
package storage
import mock "github.com/stretchr/testify/mock"
// MockFileStorage is an autogenerated mock type for the FileStorage type
type MockFileStorage struct {
mock.Mock
}
type MockFileStorage_Expecter struct {
mock *mock.Mock
}
func (_m *MockFileStorage) EXPECT() *MockFileStorage_Expecter {
return &MockFileStorage_Expecter{mock: &_m.Mock}
}
// NewMockFileStorage creates a new instance of MockFileStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockFileStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockFileStorage {
mock := &MockFileStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@ -1,95 +0,0 @@
// Code generated by mockery v2.48.0. DO NOT EDIT.
package storage
import (
context "context"
mock "github.com/stretchr/testify/mock"
)
// MockMetaStorage is an autogenerated mock type for the MetaStorage type
type MockMetaStorage struct {
mock.Mock
}
type MockMetaStorage_Expecter struct {
mock *mock.Mock
}
func (_m *MockMetaStorage) EXPECT() *MockMetaStorage_Expecter {
return &MockMetaStorage_Expecter{mock: &_m.Mock}
}
// SaveMetadata provides a mock function with given fields: ctx, fileType, size, ext
func (_m *MockMetaStorage) SaveMetadata(ctx context.Context, fileType string, size int64, ext string) (int64, error) {
ret := _m.Called(ctx, fileType, size, ext)
if len(ret) == 0 {
panic("no return value specified for SaveMetadata")
}
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, int64, string) (int64, error)); ok {
return rf(ctx, fileType, size, ext)
}
if rf, ok := ret.Get(0).(func(context.Context, string, int64, string) int64); ok {
r0 = rf(ctx, fileType, size, ext)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, string, int64, string) error); ok {
r1 = rf(ctx, fileType, size, ext)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockMetaStorage_SaveMetadata_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SaveMetadata'
type MockMetaStorage_SaveMetadata_Call struct {
*mock.Call
}
// SaveMetadata is a helper method to define mock.On call
// - ctx context.Context
// - fileType string
// - size int64
// - ext string
func (_e *MockMetaStorage_Expecter) SaveMetadata(ctx interface{}, fileType interface{}, size interface{}, ext interface{}) *MockMetaStorage_SaveMetadata_Call {
return &MockMetaStorage_SaveMetadata_Call{Call: _e.mock.On("SaveMetadata", ctx, fileType, size, ext)}
}
func (_c *MockMetaStorage_SaveMetadata_Call) Run(run func(ctx context.Context, fileType string, size int64, ext string)) *MockMetaStorage_SaveMetadata_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string), args[2].(int64), args[3].(string))
})
return _c
}
func (_c *MockMetaStorage_SaveMetadata_Call) Return(_a0 int64, _a1 error) *MockMetaStorage_SaveMetadata_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockMetaStorage_SaveMetadata_Call) RunAndReturn(run func(context.Context, string, int64, string) (int64, error)) *MockMetaStorage_SaveMetadata_Call {
_c.Call.Return(run)
return _c
}
// NewMockMetaStorage creates a new instance of MockMetaStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockMetaStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockMetaStorage {
mock := &MockMetaStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}