tmp
This commit is contained in:
parent
cfb4940fe8
commit
c7156f7aab
@ -1,6 +1,6 @@
|
||||
services:
|
||||
database:
|
||||
image: postgres:16
|
||||
image: postgres:17
|
||||
container_name: draincloud-db
|
||||
ports:
|
||||
- 5432:5432
|
||||
@ -8,3 +8,8 @@ services:
|
||||
POSTGRES_USERNAME: draincloud
|
||||
POSTGRES_DB: draincloud
|
||||
POSTGRES_PASSWORD: draincloud.dev.secret
|
||||
volumes:
|
||||
- draincloud-db-data:/
|
||||
|
||||
volumes:
|
||||
draincloud-db-data: {}
|
@ -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
|
||||
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) {
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
29
migrations/20240930221426_add_users.sql
Normal file
29
migrations/20240930221426_add_users.sql
Normal file
@ -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
|
26
migrations/20240930221522_add_sessions.sql
Normal file
26
migrations/20240930221522_add_sessions.sql
Normal file
@ -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
|
13
migrations/20240930222057_add_files.sql
Normal file
13
migrations/20240930222057_add_files.sql
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user