From c7156f7aab640ce86f51b5f5cc60e786da696283 Mon Sep 17 00:00:00 2001 From: optclblast Date: Tue, 1 Oct 2024 01:21:37 +0300 Subject: [PATCH] tmp --- docker-compose.yaml | 9 +- internal/app/app.go | 102 ++++++++++++++++++++- internal/domain/requests.go | 13 +++ internal/storage/interface.go | 2 +- migrations/20240927205337_add_users.go | 53 ----------- migrations/20240930221426_add_users.sql | 29 ++++++ migrations/20240930221522_add_sessions.sql | 26 ++++++ migrations/20240930222057_add_files.sql | 13 +++ 8 files changed, 190 insertions(+), 57 deletions(-) delete mode 100644 migrations/20240927205337_add_users.go create mode 100644 migrations/20240930221426_add_users.sql create mode 100644 migrations/20240930221522_add_sessions.sql create mode 100644 migrations/20240930222057_add_files.sql diff --git a/docker-compose.yaml b/docker-compose.yaml index 065e914..d7ef5e2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,10 +1,15 @@ services: database: - image: postgres:16 + image: postgres:17 container_name: draincloud-db ports: - 5432:5432 environment: POSTGRES_USERNAME: draincloud POSTGRES_DB: draincloud - POSTGRES_PASSWORD: draincloud.dev.secret \ No newline at end of file + POSTGRES_PASSWORD: draincloud.dev.secret + volumes: + - draincloud-db-data:/ + +volumes: + draincloud-db-data: {} \ No newline at end of file diff --git a/internal/app/app.go b/internal/app/app.go index e0891c0..958d1b8 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -1,11 +1,22 @@ package app import ( + "crypto/rand" + "encoding/base64" + "fmt" + "net/http" + "time" + + "git.optclblast.xyz/draincloud/draincloud-light/internal/domain" + "git.optclblast.xyz/draincloud/draincloud-light/internal/logger" + "git.optclblast.xyz/draincloud/draincloud-light/internal/storage" "github.com/gin-gonic/gin" + "golang.org/x/crypto/bcrypt" ) type DrainCloud struct { - mux *gin.Engine + mux *gin.Engine + datadase storage.Database } func New() *DrainCloud { @@ -16,6 +27,8 @@ func New() *DrainCloud { authGroup := mux.Group("/auth") { authGroup.POST("/register", d.Register) + authGroup.POST("/login", d.Login) + authGroup.POST("/logout", d.Logout) } d.mux = mux @@ -24,5 +37,92 @@ func New() *DrainCloud { } func (d *DrainCloud) Register(ctx *gin.Context) { + logger.Debug(ctx, "[register] new request") + + req := new(domain.RegisterRequest) + err := ctx.BindJSON(req) + if err != nil { + logger.Error(ctx, "[register] failed to bind request", logger.Err(err)) + ctx.JSON(http.StatusBadRequest, map[string]string{ + "error": "bad request", + }) + return + } + + _, err = d.register(ctx, req) + if err != nil { + logger.Error(ctx, "[register] failed to register user", logger.Err(err)) + ctx.JSON(http.StatusBadRequest, map[string]string{ + "error": err.Error(), + }) + return + } + + ctx.JSON(http.StatusOK, map[string]bool{ + "ok": true, + }) +} + +type registerResult struct { + cookies []http.Cookie +} + +func (d *DrainCloud) register(ctx *gin.Context, req *domain.RegisterRequest) (*registerResult, error) { + if err := validateLoginAndPassword(req.Login, req.Password); err != nil { + return nil, fmt.Errorf("invalid creds: %w", err) + } + + _, err := bcrypt.GenerateFromPassword([]byte(req.Password), 10) + if err != nil { + logger.Error(ctx, "[register] failed to generate password", logger.Err(err)) + return nil, fmt.Errorf("failed to generate password: %w", err) + } + + // _, err = d.datadase.AddUser(ctx, req.Login, req.Login, passwordHash) + // if err != nil { + // return nil, fmt.Errorf("failed to add new user: %w", err) + // } + + sessionToken, err := generateSessionToken(50) + if err != nil { + return nil, fmt.Errorf("failed to generate a session token: %w", err) + } + + ctx.SetCookie("__Session_token", sessionToken, int((time.Hour * 24).Seconds()), "_path", "_domain", true, true) + + csrfToken, err := generateSessionToken(50) + if err != nil { + return nil, fmt.Errorf("failed to generate a csrf token: %w", err) + } + + ctx.SetCookie("__Csrf_token", csrfToken, int((time.Hour * 24).Seconds()), "_path", "_domain", true, false) + + return ®isterResult{}, nil +} + +func validateLoginAndPassword(login, password string) error { + if len(login) < 8 { + return fmt.Errorf("login must be longer than 8 chars") + } + + if len(password) < 8 { + 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 +} + +func (d *DrainCloud) Login(ctx *gin.Context) { + +} +func (d *DrainCloud) Logout(ctx *gin.Context) { } diff --git a/internal/domain/requests.go b/internal/domain/requests.go index db87e3a..97d3241 100644 --- a/internal/domain/requests.go +++ b/internal/domain/requests.go @@ -4,3 +4,16 @@ type RegisterRequest struct { Login string `json:"login"` Password string `json:"password"` } + +type RegisterResponse struct { + Ok bool `json:"ok"` + Message string `json:"message"` +} + +type LoginRequest struct { + Login string `json:"login"` + Password string `json:"password"` +} + +type LogoutRequest struct { +} diff --git a/internal/storage/interface.go b/internal/storage/interface.go index e3e8062..b01e2e8 100644 --- a/internal/storage/interface.go +++ b/internal/storage/interface.go @@ -11,7 +11,7 @@ type Database interface { } type AuthStorage interface { - AddUser(ctx context.Context, user *models.User) error + AddUser(ctx context.Context, login string, username string, passwordHash []byte) (uint64, error) GetUserByLogin(ctx context.Context, login string) (*models.User, error) GetUserByID(ctx context.Context, id uint64) (*models.User, error) } diff --git a/migrations/20240927205337_add_users.go b/migrations/20240927205337_add_users.go deleted file mode 100644 index e769af3..0000000 --- a/migrations/20240927205337_add_users.go +++ /dev/null @@ -1,53 +0,0 @@ -package migrations - -import ( - "context" - "database/sql" - - "git.optclblast.xyz/draincloud/draincloud-light/internal/logger" - "github.com/pressly/goose/v3" -) - -func init() { - goose.AddMigrationContext(upAddUsers, downAddUsers) -} - -func upAddUsers(ctx context.Context, tx *sql.Tx) error { - const stmt = ` - CREATE TABLE IF NOT EXISTS users ( - id bigserial PRIMARY KEY - , username TEXT DEFAULT NULL - , login TEXT NOT NULL UNIQUE - , PASSWORD bytea NOT NULL - , created_at timestamptz DEFAULT current_timestamp - , updated_at timestamptz DEFAULT current_timestamp - ); - - ALTER TABLE users ADD CONSTRAINT users_username_len CHECK(length(username) > 250) NOT VALID; - ALTER TABLE users ADD CONSTRAINT users_login_len CHECK(length(username) > 250) NOT VALID; - - CREATE INDEX CONCURRENTLY idx_users_login ON - users (login); - CREATE INDEX CONCURRENTLY idx_users_username ON - users (username);` - - if _, err := tx.ExecContext(ctx, stmt); err != nil { - logger.Error(ctx, "[migration] error", logger.Err(err)) - return err - } - - return nil -} - -func downAddUsers(ctx context.Context, tx *sql.Tx) error { - const stmt = ` - DROP INDEX CONCURRENTLY IF EXISTS idx_users_login; - DROP INDEX CONCURRENTLY IF EXISTS idx_users_username; - DROP TABLE IF EXISTS users;` - - if _, err := tx.ExecContext(ctx, stmt); err != nil { - logger.Error(ctx, "[migration] error", logger.Err(err)) - return err - } - return nil -} diff --git a/migrations/20240930221426_add_users.sql b/migrations/20240930221426_add_users.sql new file mode 100644 index 0000000..6a23d2f --- /dev/null +++ b/migrations/20240930221426_add_users.sql @@ -0,0 +1,29 @@ +-- +goose Up +-- +goose StatementBegin +SELECT 'up SQL query'; + +CREATE TABLE IF NOT EXISTS users ( + id bigserial PRIMARY KEY + , username TEXT DEFAULT NULL + , login TEXT NOT NULL UNIQUE + , PASSWORD bytea NOT NULL + , created_at timestamptz DEFAULT current_timestamp + , updated_at timestamptz DEFAULT current_timestamp +); + +ALTER TABLE users ADD CONSTRAINT users_username_len CHECK(length(username) > 250) NOT VALID; +ALTER TABLE users ADD CONSTRAINT users_login_len CHECK(length(username) > 250) NOT VALID; + +CREATE INDEX CONCURRENTLY idx_users_login ON + users (login); +CREATE INDEX CONCURRENTLY idx_users_username ON + users (username); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT 'down SQL query'; +DROP INDEX CONCURRENTLY IF EXISTS idx_users_login; +DROP INDEX CONCURRENTLY IF EXISTS idx_users_username; +DROP TABLE IF EXISTS users; +-- +goose StatementEnd diff --git a/migrations/20240930221522_add_sessions.sql b/migrations/20240930221522_add_sessions.sql new file mode 100644 index 0000000..e1c5d40 --- /dev/null +++ b/migrations/20240930221522_add_sessions.sql @@ -0,0 +1,26 @@ +-- +goose Up +-- +goose StatementBegin +SELECT 'up SQL query'; + +CREATE TABLE sessions ( + id bigserial primary key, + session_token varchar(200) not null unique, + csrf_token varchar(200) not null unique, + user_id bigserial references users(id), + created_at timestamp default current_timestamp, + expired_at timestamp not null +); + +create index concurrently if not exists idx_sessions_session_token_csrf_token + on sessions (session_token, csrf_token); + +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT 'down SQL query'; + +drop index concurrently idx_sessions_session_token_csrf_token; +drop table sessions; + +-- +goose StatementEnd diff --git a/migrations/20240930222057_add_files.sql b/migrations/20240930222057_add_files.sql new file mode 100644 index 0000000..8eeb86d --- /dev/null +++ b/migrations/20240930222057_add_files.sql @@ -0,0 +1,13 @@ +-- +goose Up +-- +goose StatementBegin +SELECT 'up SQL query'; + +create table files_meta ( + id bigserial primary key +); +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +SELECT 'down SQL query'; +-- +goose StatementEnd