From 7ba2196226caf8613646bcf6fba9567b47dc0afe Mon Sep 17 00:00:00 2001 From: ankumeah Date: Tue, 19 May 2026 19:08:03 +0530 Subject: [PATCH 1/7] feat(backend, database): added support for sqlite3 and postgres and seprated db_init into its own container --- backend/Dockerfile | 14 +- {database => backend}/alpha-01.sql | 0 backend/cmd/sourceflame-server/main.go | 47 ++++--- backend/go.mod | 14 +- backend/go.sum | 35 ++++- backend/internal/apis/login.go | 2 + .../internal/database/get_connection_pool.go | 42 ------ .../internal/database/get_sql_connection.go | 41 ++++++ .../internal/database/git_postgres_driver.go | 123 ----------------- backend/internal/database/git_sql_driver.go | 130 ++++++++++++++++++ .../internal/database/pat_postgres_driver.go | 100 -------------- backend/internal/database/pat_sql_driver.go | 108 +++++++++++++++ backend/internal/database/postgres_options.go | 10 ++ backend/internal/database/sqlite_options.go | 10 ++ backend/internal/database/types.go | 9 -- ..._postgres_driver.go => user_sql_driver.go} | 53 ++++--- backend/internal/jwt/jwt.go | 11 +- .../internal/session_store/session_store.go | 12 +- database/Dockerfile | 3 - database/run_postgres.sh | 9 +- db_init/Dockerfile | 19 +++ db_init/get_conn.go | 96 +++++++++++++ db_init/go.mod | 25 ++++ db_init/go.sum | 46 +++++++ db_init/main.go | 61 ++++++++ db_init/postgres_options.go | 10 ++ db_init/sqlite_options.go | 10 ++ env.d.example/backend | 8 +- env.d.example/database | 7 +- env.d.example/pg_database | 1 + k8s/base/config-maps/backend-config-map.yaml | 4 +- k8s/base/config-maps/database-config-map.yaml | 8 -- k8s/base/config-maps/kustomization.yaml | 1 - k8s/base/reverse-proxy/deployment.yaml | 2 - .../secrets.example/database-secrets.yaml | 4 +- 35 files changed, 702 insertions(+), 373 deletions(-) rename {database => backend}/alpha-01.sql (100%) delete mode 100644 backend/internal/database/get_connection_pool.go create mode 100644 backend/internal/database/get_sql_connection.go delete mode 100644 backend/internal/database/git_postgres_driver.go create mode 100644 backend/internal/database/git_sql_driver.go delete mode 100644 backend/internal/database/pat_postgres_driver.go create mode 100644 backend/internal/database/pat_sql_driver.go create mode 100644 backend/internal/database/postgres_options.go create mode 100644 backend/internal/database/sqlite_options.go rename backend/internal/database/{user_postgres_driver.go => user_sql_driver.go} (54%) create mode 100644 db_init/Dockerfile create mode 100644 db_init/get_conn.go create mode 100644 db_init/go.mod create mode 100644 db_init/go.sum create mode 100644 db_init/main.go create mode 100644 db_init/postgres_options.go create mode 100644 db_init/sqlite_options.go create mode 100644 env.d.example/pg_database delete mode 100644 k8s/base/config-maps/database-config-map.yaml diff --git a/backend/Dockerfile b/backend/Dockerfile index cf7bb92..e3a628d 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,18 +2,24 @@ FROM golang:alpine AS builder WORKDIR /opt/backend/ +RUN apk add gcc musl-dev --no-cache + COPY go.mod go.sum ./ RUN go mod download +ARG db_type=sqlite3 + COPY . . -#RUN go build -ldflags="-s -w" -o ./bin/sourceflame-server ./cmd/sourceflame-server/ -RUN --mount=type=cache,target=/root/.cache/go-build go build -ldflags="-s -w" -o ./bin/sourceflame-server ./cmd/sourceflame-server/ +RUN --mount=type=cache,target=/root/.cache/go-build go build -ldflags="-s -w" -tags=${db_type} -o ./bin/sourceflame-server ./cmd/sourceflame-server/ FROM alpine RUN apk add git --no-cache +WORKDIR /opt/backend/ + ENV GIN_MODE=release -COPY --from=builder /opt/backend/bin/sourceflame-server /opt/backend/sourceflame-server +COPY alpha-01.sql . +COPY --from=builder /opt/backend/bin/sourceflame-server . -ENTRYPOINT [ "/opt/backend/sourceflame-server" ] +ENTRYPOINT [ "./sourceflame-server" ] diff --git a/database/alpha-01.sql b/backend/alpha-01.sql similarity index 100% rename from database/alpha-01.sql rename to backend/alpha-01.sql diff --git a/backend/cmd/sourceflame-server/main.go b/backend/cmd/sourceflame-server/main.go index 66c3f65..856b489 100644 --- a/backend/cmd/sourceflame-server/main.go +++ b/backend/cmd/sourceflame-server/main.go @@ -1,6 +1,9 @@ package main import ( + "strconv" + "time" + "github.com/Ankumeah/SourceFlameBackend/internal/apis" a "github.com/Ankumeah/SourceFlameBackend/internal/app" "github.com/Ankumeah/SourceFlameBackend/internal/database" @@ -28,12 +31,11 @@ var env_vars = map[string]string { "SESSION_STORE_HOSTNAME": "", "SESSION_STORE_PORT": "", "SESSION_STORE_TYPE": "", - "DATABASE_USER": "", - "DATABASE_PASSWORD": "", - "DATABASE_HOST": "", - "DATABASE_PORT": "", - "DATABASE_DB": "", - "DATABASE_CONFIG": "", + "DATABASE_URL": "", + "DATABASE_MAX_CONNS": "", + "DATABASE_MAX_IDLE_CONNS": "", + "DATABASE_MAX_LIFETIME": "", + "DATABASE_MAX_IDLE_TIME": "", } func load_env() { @@ -66,7 +68,7 @@ func connect_session_store() { log.Fatalf("Unsupported session store type: %v\n", env_vars["SESSION_STORE_TYPE"]) } if err != nil { - log.Panicf("Error while connecting to session store: %v", err.Error()) + log.Panicf("Error while connecting to session store: %v\n", err.Error()) } app.Store = session_store.Get_Sessions_Uinversal_Redis_Driver(client) @@ -74,23 +76,32 @@ func connect_session_store() { } func connect_database() { - conn_config := database.Connection_Config { - Username: env_vars["DATABASE_USER"], - Password: env_vars["DATABASE_PASSWORD"], - Hostname: env_vars["DATABASE_HOST"], - Port: env_vars["DATABASE_PORT"], - Db_name: env_vars["DATABASE_DB"], - Db_config: env_vars["DATABASE_CONFIG"], + max_conn, err := strconv.Atoi(env_vars["DATABASE_MAX_CONNS"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_CONNS: %v\n", err.Error()) + } + max_idle, err := strconv.Atoi(env_vars["DATABASE_MAX_IDLE_CONNS"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_IDLE_CONNS: %v\n", err.Error()) + } + max_lifetime, err := time.ParseDuration(env_vars["DATABASE_MAX_LIFETIME"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_LIFETIME: %v\n", err.Error()) + } + max_idle_time, err := time.ParseDuration(env_vars["DATABASE_MAX_IDLE_TIME"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_IDLE_TIME: %v\n", err.Error()) } + config := database.New_Sql_Config(int(max_conn), int(max_idle), max_lifetime, max_idle_time) - pool, err := database.Get_Connection_Pool(Ctx, conn_config) + db, err := database.Get_DB_Connection(Ctx, env_vars["DATABASE_URL"], config) if err != nil { log.Fatalf("Error while connecting to database: %v\n", err.Error()) } - app.User_db = database.User_Postgres_Driver(pool) - app.Git_db = database.Git_Postgres_Driver(pool) - app.PAT_db = database.PAT_Postgres_Driver(pool) + app.User_db = database.User_Sql_Driver(db) + app.Git_db = database.Git_Sql_Driver(db) + app.PAT_db = database.PAT_Sql_Driver(db) log.Println("Connected to database") } diff --git a/backend/go.mod b/backend/go.mod index 77718d2..b4e6c18 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -7,7 +7,11 @@ require ( github.com/go-git/go-git/v6 v6.0.0-20260220113129-c02711164eb8 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/jackc/pgx/v5 v5.8.0 + github.com/jmoiron/sqlx v1.4.0 + github.com/mattn/go-sqlite3 v1.14.44 github.com/redis/go-redis/v9 v9.17.3 + github.com/uptrace/bun/dialect/pgdialect v1.2.18 + github.com/uptrace/bun/dialect/sqlitedialect v1.2.18 golang.org/x/crypto v0.48.0 ) @@ -35,6 +39,7 @@ require ( github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.5.0 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect @@ -44,18 +49,23 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pjbgf/sha1cd v0.5.0 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.54.0 // indirect github.com/sergi/go-diff v1.4.0 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.0 // indirect + github.com/uptrace/bun v1.2.18 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect go.uber.org/mock v0.5.0 // indirect golang.org/x/arch v0.20.0 // indirect - golang.org/x/mod v0.32.0 // indirect + golang.org/x/mod v0.33.0 // indirect golang.org/x/net v0.50.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect - golang.org/x/tools v0.41.0 // indirect + golang.org/x/tools v0.42.0 // indirect google.golang.org/protobuf v1.36.9 // indirect ) diff --git a/backend/go.sum b/backend/go.sum index 4562b9a..0db950c 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -1,3 +1,5 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= @@ -53,6 +55,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +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/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= @@ -72,6 +76,10 @@ github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kevinburke/ssh_config v1.5.0 h1:3cPZmE54xb5j3G5xQCjSvokqNwU2uW+3ry1+PRLSPpA= @@ -83,8 +91,13 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8= +github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= @@ -95,6 +108,8 @@ github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= +github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/quic-go v0.54.0 h1:6s1YB9QotYI6Ospeiguknbp2Znb/jZYjZLRXn9kMQBg= @@ -114,18 +129,30 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= +github.com/uptrace/bun v1.2.18 h1:3HnRcMfS6OBPMG1eSOzlbFJ/X/AyMEJb7rMxE6VQvDU= +github.com/uptrace/bun v1.2.18/go.mod h1:wNltaKJk4JtOt4SG5I5zmA7v0/Mzjh1+/S906Rayd3Y= +github.com/uptrace/bun/dialect/pgdialect v1.2.18 h1:IZ6nM2+OYrL8lkEAy7UkSEZvoa3vluTAUlZfPtlRB2k= +github.com/uptrace/bun/dialect/pgdialect v1.2.18/go.mod h1:Tqdf4QP1okrGYpXfodXvCOK6Ob1OOTwSaoAzCgBB3IU= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.18 h1:Z33SY/U++XK9uGWqS4h8OZVxfCXguIG+sU9cYq2PGFQ= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.18/go.mod h1:1MVOS/Ncy4FZbkJcgUFH6OqYoQinYNjkEwsmNQEXz2A= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= -golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= @@ -137,8 +164,8 @@ golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= -golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= -golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/backend/internal/apis/login.go b/backend/internal/apis/login.go index 4d9fae9..6c6e42c 100644 --- a/backend/internal/apis/login.go +++ b/backend/internal/apis/login.go @@ -90,8 +90,10 @@ func add_session(c *gin.Context, store *session_store.Session_store, username st token, token_err = store.Add_Session(ctx, username) if token_err == session_store.Error_too_many_tokens { c.JSON(http.StatusForbidden, gin.H { "error": "Too many refresh tokens" }) + return } else if token_err != nil { c.JSON(internal_server_error()) + return } }) wg.Go(func() { diff --git a/backend/internal/database/get_connection_pool.go b/backend/internal/database/get_connection_pool.go deleted file mode 100644 index 733c060..0000000 --- a/backend/internal/database/get_connection_pool.go +++ /dev/null @@ -1,42 +0,0 @@ -package database - -import ( - "github.com/jackc/pgx/v5/pgxpool" - - "context" - "fmt" - "log" -) - -func Get_Connection_Pool( - ctx context.Context, - conn_config Connection_Config, -) (*pgxpool.Pool, error) { - url_string := fmt.Sprintf( - "user=%v password=%v host=%v port=%v dbname=%v %v", - conn_config.Username, - conn_config.Password, - conn_config.Hostname, - conn_config.Port, - conn_config.Db_name, - conn_config.Db_config, - ) - config, err := pgxpool.ParseConfig(url_string) - if err != nil { - log.Printf("Error while parseing DB config: %v\n", err.Error()) - return nil, err - } - - conn, err := pgxpool.NewWithConfig(ctx, config) - if err != nil { - log.Printf("Error while connecting to DB config: %v\n", err.Error()) - return nil, err - } - - err = conn.Ping(ctx) - if err != nil { - return nil, err - } - - return conn, nil -} diff --git a/backend/internal/database/get_sql_connection.go b/backend/internal/database/get_sql_connection.go new file mode 100644 index 0000000..9474e2e --- /dev/null +++ b/backend/internal/database/get_sql_connection.go @@ -0,0 +1,41 @@ +package database + +import ( + "github.com/jmoiron/sqlx" + + "time" + "context" +) + +type Sql_Config struct { + max_conns int + max_idle int + max_lifetime time.Duration + max_idle_time time.Duration +} +func New_Sql_Config( + max_conn int, + max_idle int, + max_lifetime time.Duration, + max_idle_time time.Duration, +) Sql_Config { + return Sql_Config { + max_conns: max_conn, + max_idle: max_idle, + max_lifetime: max_lifetime, + max_idle_time: max_idle_time, + } +} + +func Get_DB_Connection(ctx context.Context, url string, config Sql_Config) (*sqlx.DB, error) { + db, err := sqlx.Open(driver_name, url) + if err != nil { return nil, err } + db.SetMaxOpenConns(config.max_conns) + db.SetMaxIdleConns(config.max_idle) + db.SetConnMaxLifetime(config.max_lifetime) + db.SetConnMaxIdleTime(config.max_idle_time) + + if err := db.Ping(); err != nil { return nil, err } + + return db, nil +} diff --git a/backend/internal/database/git_postgres_driver.go b/backend/internal/database/git_postgres_driver.go deleted file mode 100644 index 6ea31ab..0000000 --- a/backend/internal/database/git_postgres_driver.go +++ /dev/null @@ -1,123 +0,0 @@ -package database - -import ( - "github.com/jackc/pgx/v5/pgxpool" - "github.com/jackc/pgx/v5" - - "context" - "time" -) - -type git_postgres_driver struct { - db *pgxpool.Pool -} - -func Git_Postgres_Driver( pool *pgxpool.Pool) *Git_db { - return &Git_db { - &git_postgres_driver { pool }, - } -} - -func (p *git_postgres_driver) Create_Repo( - ctx context.Context, - owner_id uint64, - repo_name string, - private bool, -) (uint64, error) { - query := ` - INSERT INTO repos (name, owner_id, private, created_at, stars) - VALUES ($1, $2, $3, $4, 0) - RETURNING id; - ` - - var repo_id uint64 - now := time.Now().Unix() - err := p.db.QueryRow(ctx, query, repo_name, owner_id, private, now).Scan(&repo_id) - - return repo_id, err -} - -func (p *git_postgres_driver) Get_Id( - ctx context.Context, - owner_id uint64, - repo_name string, -) (uint64, error) { - query := ` - SELECT id FROM repos - WHERE (owner_id = $1 AND name = $2); - ` - - var repo_id uint64 - err := p.db.QueryRow(ctx, query, owner_id, repo_name).Scan(&repo_id) - if err == pgx.ErrNoRows { - return 0, Error_invalid_repo - } - - return repo_id, err -} - -func (p *git_postgres_driver) Delete_Repo( - ctx context.Context, - repo_id uint64, -) error { - query := ` - DELETE FROM repos - WHERE (id = $1); - ` - - tag, err := p.db.Exec(ctx, query, repo_id) - if tag.RowsAffected() == 0 { - return Error_invalid_repo - } - return err -} - -func (p *git_postgres_driver) Get_Repos( - ctx context.Context, - user_id uint64, - all bool, - limit uint8, - offset uint64, -) ([]string, error) { - query_all := ` - SELECT name FROM repos - WHERE (owner_id = $1) - LIMIT $2 OFFSET $3; - ` - query := ` - SELECT name FROM repos - WHERE (NOT private AND owner_id = $1) - LIMIT $2 OFFSET $3 - ` - if all { query = query_all } - - rows, _ := p.db.Query(ctx, query, user_id, limit, offset) - repos, err := pgx.CollectRows(rows, pgx.RowTo[string]) - if err != nil { - return nil, err - } - - return repos, nil -} - -func (p *git_postgres_driver) Info( - ctx context.Context, - repo_id uint64, -) (*Repo_Info, error) { - query := ` - SELECT repos.created_at, repos.stars, repos.private, users.username - FROM repos - INNER JOIN users ON repos.owner_id = users.id - WHERE repos.id = $1; - ` - - var info Repo_Info - err := p.db.QueryRow(ctx, query, repo_id).Scan( - &info.Creation, &info.Stars, &info.Private, &info.Owner, - ) - if err == pgx.ErrNoRows { - return nil, Error_invalid_repo - } - - return &info, err -} diff --git a/backend/internal/database/git_sql_driver.go b/backend/internal/database/git_sql_driver.go new file mode 100644 index 0000000..9e86f7d --- /dev/null +++ b/backend/internal/database/git_sql_driver.go @@ -0,0 +1,130 @@ +package database + +import ( + "github.com/jmoiron/sqlx" + + "database/sql" + "context" + "time" +) + +type git_sqlx_driver struct { db *sqlx.DB } +func Git_Sql_Driver(db *sqlx.DB) *Git_db { + return &Git_db { + &git_sqlx_driver { db }, + } +} + +func (s *git_sqlx_driver) Create_Repo( + ctx context.Context, + owner_id uint64, + repo_name string, + private bool, +) (uint64, error) { + query := s.db.Rebind(` + INSERT INTO repos (name, owner_id, private, created_at, stars) + VALUES (?, ?, ?, ?, 0) + RETURNING id; + `) + + var repo_id uint64 + now := time.Now().Unix() + err := s.db.QueryRowContext(ctx, query, repo_name, owner_id, private, now).Scan(&repo_id) + + return repo_id, err +} + +func (s *git_sqlx_driver) Get_Id( + ctx context.Context, + owner_id uint64, + repo_name string, +) (uint64, error) { + query := s.db.Rebind(` + SELECT id FROM repos + WHERE (owner_id = ? AND name = ?); + `) + + var repo_id uint64 + err := s.db.QueryRowContext(ctx, query, owner_id, repo_name).Scan(&repo_id) + if err == sql.ErrNoRows { + return 0, Error_invalid_repo + } + + return repo_id, err +} + +func (s *git_sqlx_driver) Delete_Repo( + ctx context.Context, + repo_id uint64, +) error { + query := s.db.Rebind(` + DELETE FROM repos + WHERE (id = ?); + `) + + tag, err := s.db.ExecContext(ctx, query, repo_id) + if err != nil { return err } + + effected, err := tag.RowsAffected() + if effected == 0 { return Error_invalid_repo } + + return err +} + +func (s *git_sqlx_driver) Get_Repos( + ctx context.Context, + user_id uint64, + all bool, + limit uint8, + offset uint64, +) ([]string, error) { + query_all := ` + SELECT name FROM repos + WHERE (owner_id = ?) + LIMIT ? OFFSET ?; + ` + _query := ` + SELECT name FROM repos + WHERE (NOT private AND owner_id = ?) + LIMIT ? OFFSET ? + ` + if all { _query = query_all } + query := s.db.Rebind(_query) + + rows, err := s.db.QueryContext(ctx, query, user_id, limit, offset) + if err != nil { return nil, err } + defer rows.Close() + + var repos []string + for rows.Next() { + var repo string + err := rows.Scan(&repo) + if err != nil { return nil, err } + repos = append(repos, repo) + } + if rows.Err() != nil { return nil, err } + + return repos, nil +} + +func (s *git_sqlx_driver) Info( + ctx context.Context, + repo_id uint64, +) (*Repo_Info, error) { + query := s.db.Rebind(` + SELECT repos.created_at, repos.stars, repos.private, users.username + FROM repos + INNER JOIN users ON repos.owner_id = users.id + WHERE repos.id = ?; + `) + + var info Repo_Info + err := s.db.QueryRowContext(ctx, query, repo_id).Scan( + &info.Creation, &info.Stars, &info.Private, &info.Owner, + ) + if err == sql.ErrNoRows { + return nil, Error_invalid_repo + } + + return &info, err +} diff --git a/backend/internal/database/pat_postgres_driver.go b/backend/internal/database/pat_postgres_driver.go deleted file mode 100644 index c679d22..0000000 --- a/backend/internal/database/pat_postgres_driver.go +++ /dev/null @@ -1,100 +0,0 @@ -package database - -import ( - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgxpool" - - "context" - "errors" - "time" -) - -type pat_postgres_driver struct { - db *pgxpool.Pool -} - -func PAT_Postgres_Driver( pool *pgxpool.Pool) *PAT_db { - return &PAT_db { - &pat_postgres_driver { pool }, - } -} - -func (p *pat_postgres_driver) Add_PAT(ctx context.Context, owner_id uint64, hash string, pat_name string) (uint64, error) { - query := ` - INSERT INTO pats (name, hash, owner_id, created_at) - VALUES ($1, $2, $3, $4) - RETURNING id; - ` - - var pat_id uint64 - now := time.Now().Unix() - err := p.db.QueryRow(ctx, query, pat_name, hash, owner_id, now).Scan(&pat_id) - - return pat_id, err -} - -func (p *pat_postgres_driver) Validate_PAT(ctx context.Context, owner_id uint64, hash string) (uint64, error) { - query := ` - SELECT id FROM pats - WHERE (owner_id = $1 AND hash = $2) - ` - - var pat_id uint64 - err := p.db.QueryRow(ctx, query, owner_id, hash).Scan(&pat_id) - if errors.Is(err, pgx.ErrNoRows) { - err = Error_invalid_pat - } - - return pat_id, err -} - -func (p *pat_postgres_driver) Get_Id(ctx context.Context, owner_id uint64, pat_name string) (uint64, error) { - query := ` - SELECT id FROM pats - WHERE (owner_id = $1 AND name = $2); - ` - - var pat_id uint64 - err := p.db.QueryRow(ctx, query, owner_id, pat_name).Scan(&pat_id) - if errors.Is(err, pgx.ErrNoRows) { - err = Error_invalid_pat - } - - return pat_id, err -} - -func (p *pat_postgres_driver) Delete_PAT(ctx context.Context, pat_id uint64) error { - query := ` - DELETE FROM pats - WHERE (id = $1); - ` - - tag, err := p.db.Exec(ctx, query, pat_id) - if tag.RowsAffected() == 0 { - return Error_invalid_pat - } - - return err -} -func (p *pat_postgres_driver) Get_PATs(ctx context.Context, user_id uint64) ([]string, error) { - query := ` - SELECT name FROM pats - WHERE (owner_id = $1); - ` - - rows, _ := p.db.Query(ctx, query, user_id) - pats, err := pgx.CollectRows(rows, pgx.RowTo[string]) - - return pats, err -} -func (p *pat_postgres_driver) Info(ctx context.Context, pat_id uint64) (*PAT_Info, error) { - query := ` - SELECT name, created_at, last_used FROM pats - WHERE (id = $1); - ` - - var info PAT_Info - err := p.db.QueryRow(ctx, query, pat_id).Scan(&info.Name, &info.Creation, &info.Last_Used) - - return &info, err -} diff --git a/backend/internal/database/pat_sql_driver.go b/backend/internal/database/pat_sql_driver.go new file mode 100644 index 0000000..36ae1b6 --- /dev/null +++ b/backend/internal/database/pat_sql_driver.go @@ -0,0 +1,108 @@ +package database + +import ( + "github.com/jmoiron/sqlx" + + "database/sql" + "context" + "errors" + "time" +) + +type pat_sqlx_driver struct { db *sqlx.DB } +func PAT_Sql_Driver(pool *sqlx.DB) *PAT_db { + return &PAT_db { + &pat_sqlx_driver { pool }, + } +} + +func (s *pat_sqlx_driver) Add_PAT(ctx context.Context, owner_id uint64, hash string, pat_name string) (uint64, error) { + query := s.db.Rebind(` + INSERT INTO pats (name, hash, owner_id, created_at) + VALUES (?, ?, ?, ?) + RETURNING id; + `) + + var pat_id uint64 + now := time.Now().Unix() + err := s.db.QueryRowContext(ctx, query, pat_name, hash, owner_id, now).Scan(&pat_id) + + return pat_id, err +} + +func (s *pat_sqlx_driver) Validate_PAT(ctx context.Context, owner_id uint64, hash string) (uint64, error) { + query := s.db.Rebind(` + SELECT id FROM pats + WHERE (owner_id = ? AND hash = ?) + `) + + var pat_id uint64 + err := s.db.QueryRowContext(ctx, query, owner_id, hash).Scan(&pat_id) + if errors.Is(err, sql.ErrNoRows) { + err = Error_invalid_pat + } + + return pat_id, err +} + +func (s *pat_sqlx_driver) Get_Id(ctx context.Context, owner_id uint64, pat_name string) (uint64, error) { + query := s.db.Rebind(` + SELECT id FROM pats + WHERE (owner_id = ? AND name = ?); + `) + + var pat_id uint64 + err := s.db.QueryRowContext(ctx, query, owner_id, pat_name).Scan(&pat_id) + if errors.Is(err, sql.ErrNoRows) { + err = Error_invalid_pat + } + + return pat_id, err +} + +func (s *pat_sqlx_driver) Delete_PAT(ctx context.Context, pat_id uint64) error { + query := s.db.Rebind(` + DELETE FROM pats + WHERE (id = ?); + `) + + tag, err := s.db.Exec(query, pat_id) + if err != nil { return err } + + effected, err := tag.RowsAffected() + if effected == 0 { return Error_invalid_pat } + + return err +} +func (s *pat_sqlx_driver) Get_PATs(ctx context.Context, user_id uint64) ([]string, error) { + query := s.db.Rebind(` + SELECT name FROM pats + WHERE (owner_id = ?); + `) + + rows, err := s.db.Query(query, user_id) + if err != nil { return nil, err } + defer rows.Close() + + var pats []string + for rows.Next() { + var pat string + err := rows.Scan(&pat) + if err != nil { return nil, err } + pats = append(pats, pat) + } + if rows.Err() != nil { return nil, err } + + return pats, nil +} +func (s *pat_sqlx_driver) Info(ctx context.Context, pat_id uint64) (*PAT_Info, error) { + query := s.db.Rebind(` + SELECT name, created_at, last_used FROM pats + WHERE (id = ?); + `) + + var info PAT_Info + err := s.db.QueryRowContext(ctx, query, pat_id).Scan(&info.Name, &info.Creation, &info.Last_Used) + + return &info, err +} diff --git a/backend/internal/database/postgres_options.go b/backend/internal/database/postgres_options.go new file mode 100644 index 0000000..09c3674 --- /dev/null +++ b/backend/internal/database/postgres_options.go @@ -0,0 +1,10 @@ +//go:build postgres +package database + +import ( + _ "github.com/jackc/pgx/v5/stdlib" + "github.com/uptrace/bun/dialect/pgdialect" +) + +const driver_name = "pgx" +var dia = pgdialect.New() diff --git a/backend/internal/database/sqlite_options.go b/backend/internal/database/sqlite_options.go new file mode 100644 index 0000000..753b2c8 --- /dev/null +++ b/backend/internal/database/sqlite_options.go @@ -0,0 +1,10 @@ +//go:build sqlite3 +package database + +import ( + _ "github.com/mattn/go-sqlite3" + "github.com/uptrace/bun/dialect/sqlitedialect" +) + +const driver_name = "sqlite3" +var dia = sqlitedialect.New() diff --git a/backend/internal/database/types.go b/backend/internal/database/types.go index 0940843..5d64c77 100644 --- a/backend/internal/database/types.go +++ b/backend/internal/database/types.go @@ -51,12 +51,3 @@ type PAT_Info struct { Creation uint64 `json:"creation"` Last_Used *uint64 `json:"last_used"` } - -type Connection_Config struct { - Username string - Password string - Hostname string - Port string - Db_name string - Db_config string -} diff --git a/backend/internal/database/user_postgres_driver.go b/backend/internal/database/user_sql_driver.go similarity index 54% rename from backend/internal/database/user_postgres_driver.go rename to backend/internal/database/user_sql_driver.go index 863cb2c..53f8ca9 100644 --- a/backend/internal/database/user_postgres_driver.go +++ b/backend/internal/database/user_sql_driver.go @@ -3,36 +3,33 @@ package database import ( "github.com/Ankumeah/SourceFlameBackend/internal/hash" - "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgxpool" + "github.com/jmoiron/sqlx" + "database/sql" "context" "time" ) -type user_postgres_driver struct { - db *pgxpool.Pool -} - -func User_Postgres_Driver( pool *pgxpool.Pool) *User_db { +type user_sqlx_driver struct { db *sqlx.DB } +func User_Sql_Driver(pool *sqlx.DB) *User_db { return &User_db { - &user_postgres_driver { pool }, + &user_sqlx_driver { pool }, } } -func (p *user_postgres_driver) Add_User( +func (s *user_sqlx_driver) Add_User( ctx context.Context, username string, password_hash *hash.Hash, ) (uint64, error) { - query := ` + query := s.db.Rebind(` INSERT INTO users (username, created_at, password_hash, salt) - VALUES ($1, $2, $3, $4) RETURNING (id); - ` + VALUES (?, ?, ?, ?) RETURNING (id); + `) var user_id uint64 now := time.Now().Unix() - if err := p.db.QueryRow(ctx, query, + if err := s.db.QueryRowContext(ctx, query, username, now, password_hash.Hash, password_hash.Salt, ).Scan(&user_id); err != nil { return 0, err @@ -41,26 +38,26 @@ func (p *user_postgres_driver) Add_User( return user_id, nil } -func (p *user_postgres_driver) Delete_User( +func (s *user_sqlx_driver) Delete_User( ctx context.Context, user_id uint64, ) error { - query := "DELETE FROM users WHERE (id = $1);" + query := s.db.Rebind("DELETE FROM users WHERE (id = ?);") - _, err := p.db.Exec(ctx, query, user_id) + _, err := s.db.Exec(query, user_id) return err } -func (p *user_postgres_driver) Get_Hash( +func (s *user_sqlx_driver) Get_Hash( ctx context.Context, user_id uint64, ) (*hash.Hash, error) { - query := "SELECT password_hash, salt FROM users WHERE (id = $1);" + query := s.db.Rebind("SELECT password_hash, salt FROM users WHERE (id = ?);") var password_hash []byte var salt []byte - err := p.db.QueryRow(ctx, query, user_id).Scan(&password_hash, &salt) - if err == pgx.ErrNoRows { + err := s.db.QueryRowContext(ctx, query, user_id).Scan(&password_hash, &salt) + if err == sql.ErrNoRows { return nil, Error_invalid_user } else if err != nil { return nil, err @@ -72,15 +69,15 @@ func (p *user_postgres_driver) Get_Hash( } } -func (p *user_postgres_driver) Get_Id( +func (s *user_sqlx_driver) Get_Id( ctx context.Context, username string, ) (uint64, error) { - query := "SELECT id FROM users WHERE (username = $1);" + query := s.db.Rebind("SELECT id FROM users WHERE (username = ?);") var id uint64 - err := p.db.QueryRow(ctx, query, username).Scan(&id) - if err == pgx.ErrNoRows { + err := s.db.QueryRowContext(ctx, query, username).Scan(&id) + if err == sql.ErrNoRows { return 0, Error_invalid_user } else if err != nil { return 0, err @@ -89,15 +86,15 @@ func (p *user_postgres_driver) Get_Id( } } -func (p *user_postgres_driver) Info( +func (s *user_sqlx_driver) Info( ctx context.Context, user_id uint64, ) (*User_Info, error) { - query := "SELECT created_at FROM users WHERE (id = $1);" + query := s.db.Rebind("SELECT created_at FROM users WHERE (id = ?);") var creation uint64 - err := p.db.QueryRow(ctx, query, user_id).Scan(&creation) - if err == pgx.ErrNoRows { + err := s.db.QueryRowContext(ctx, query, user_id).Scan(&creation) + if err == sql.ErrNoRows { return nil, Error_invalid_user } else if err != nil { return nil, err diff --git a/backend/internal/jwt/jwt.go b/backend/internal/jwt/jwt.go index fc0c736..e2448ea 100644 --- a/backend/internal/jwt/jwt.go +++ b/backend/internal/jwt/jwt.go @@ -6,7 +6,6 @@ import ( "os" "time" "log" - "strconv" ) const jwt_leeway = 10 * time.Second @@ -19,12 +18,12 @@ func init() { if !ok { log.Fatalln("Unset env var: JWT_KEY") } jwt_key = []byte(key) - lifespan, ok := os.LookupEnv("JWT_LIFESPAN_MINS") - if !ok { log.Fatalln("Unset env var: JWT_LIFESPAN_MINS") } + lifespan, ok := os.LookupEnv("JWT_LIFESPAN") + if !ok { log.Fatalln("Unset env var: JWT_LIFESPAN") } - val, err := strconv.Atoi(lifespan) - if err != nil { log.Fatalf("Error converting JWT_LIFESPAN_MINS to int: %v\n", err.Error()) } - jwt_lifespan = time.Duration(val) * time.Minute + val, err := time.ParseDuration(lifespan) + if err != nil { log.Fatalf("Error parseing JWT_LIFESPAN: %v\n", err.Error()) } + jwt_lifespan = val } func Issue_jwt(username string) (string, error) { diff --git a/backend/internal/session_store/session_store.go b/backend/internal/session_store/session_store.go index d413e7e..6fac1a2 100644 --- a/backend/internal/session_store/session_store.go +++ b/backend/internal/session_store/session_store.go @@ -18,17 +18,17 @@ var token_timeout time.Duration var token_limit uint8 func init() { - timeout, ok := os.LookupEnv("TOKEN_TIMEOUT_DAYS") - if !ok { log.Fatalln("Unset env var: TOKEN_TIMEOUT_DAYS") } + _timeout, ok := os.LookupEnv("TOKEN_TIMEOUT") + if !ok { log.Fatalln("Unset env var: TOKEN_TIMEOUT") } - val, err := strconv.Atoi(timeout) - if err != nil { log.Fatalf("Error while converting TOKEN_TIMEOUT_DAYS to int: %v\n", err.Error()) } - token_timeout = time.Duration(val) * 24 * time.Hour + timeout, err := time.ParseDuration(_timeout) + if err != nil { log.Fatalf("Error parseing TOKEN_TIMEOUT: %v\n", err.Error()) } + token_timeout = timeout limit, ok := os.LookupEnv("TOKEN_LIMIT") if !ok { log.Fatalf("Unset env var: TOKEN_LIMIT") } - val, err = strconv.Atoi(limit) + val, err := strconv.Atoi(limit) if err != nil { log.Fatalf("Error while converting TOKEN_LIMIT to int: %v\n", err.Error()) } token_limit = uint8(val) } diff --git a/database/Dockerfile b/database/Dockerfile index 109ba62..7a75d18 100644 --- a/database/Dockerfile +++ b/database/Dockerfile @@ -1,8 +1,5 @@ FROM postgres:alpine -ARG version=alpha-01 -COPY ${version}.sql /docker-entrypoint-initdb.d/ - COPY . /opt/postgres/ RUN chmod +x /opt/postgres/run_postgres.sh diff --git a/database/run_postgres.sh b/database/run_postgres.sh index 3d5db49..2f0cd16 100755 --- a/database/run_postgres.sh +++ b/database/run_postgres.sh @@ -1,8 +1,9 @@ #! /bin/sh -export POSTGRES_USER="${DATABASE_USER}" -export POSTGRES_PASSWORD="${DATABASE_PASSWORD}" -export POSTGRES_DB="${DATABASE_DB}" -export POSTGRES_PORT="${POSTGRES_PORT}" +export POSTGRES_USER=$(echo "$DATABASE_URL" | awk -F/ '{print $3}' | awk -F: '{print $1}') +export POSTGRES_PASSWORD=$(echo "$DATABASE_URL" | awk -F/ '{print $3}' | awk -F: '{print $2}' | awk -F@ '{print $1}') +export POSTGRES_PORT=$(echo "$DATABASE_URL" | awk -F/ '{print $3}' | awk -F: '{print $3}') +export POSTGRES_DB=$(echo "$DATABASE_URL" | awk -F/ '{print $4}' | awk -F\? '{print $1}') +echo POSTGRES_DB $POSTGRES_DB POSTGRES_PORT $POSTGRES_PORT POSTGRES_PASSWORD $POSTGRES_PASSWORD POSTGRES_USER $POSTGRES_USER exec docker-entrypoint.sh postgres diff --git a/db_init/Dockerfile b/db_init/Dockerfile new file mode 100644 index 0000000..939bf2a --- /dev/null +++ b/db_init/Dockerfile @@ -0,0 +1,19 @@ +FROM golang:alpine AS builder + +WORKDIR /opt/db_init/ + +RUN apk add gcc musl-dev --no-cache + +COPY go.mod go.sum ./ +RUN go mod download + +ARG db_type=sqlite3 + +COPY . . +RUN --mount=type=cache,target=/root/.cache/go-build go build -ldflags="-s -w" -tags=${db_type} -o ./bin/db-init ./ + +FROM alpine + +COPY --from=builder /opt/db_init/bin/db-init /opt/db_init/db-init + +ENTRYPOINT [ "/opt/db_init/db-init" ] diff --git a/db_init/get_conn.go b/db_init/get_conn.go new file mode 100644 index 0000000..99533fa --- /dev/null +++ b/db_init/get_conn.go @@ -0,0 +1,96 @@ +package main + +import ( + "github.com/uptrace/bun" + + "time" + "context" + "database/sql" +) + +type User struct { + bun.BaseModel `bun:"table:users"` + + ID uint64 `bun:"id,pk,autoincrement"` + Username string `bun:"username,notnull,unique"` + Created_At uint64 `bun:"created_at,notnull"` + Password_Hash []byte `bun:"password_hash,notnull"` + Salt []byte `bun:"salt,notnull"` + + Repos []*Repo `bun:"rel:has-many,join:id=owner_id"` + PATs []*PAT `bun:"rel:has-many,join:id=owner_id"` +} +type Repo struct { + bun.BaseModel `bun:"table:repos"` + + ID uint64 `bun:"id,pk,autoincrement"` + Name string `bun:"name,notnull"` + Private bool `bun:"private,notnull"` + OwnerID uint64 `bun:"owner_id,notnull"` + CreatedAt uint64 `bun:"created_at,notnull"` + Stars uint64 `bun:"stars,notnull"` + + Owner *User `bun:"rel:belongs-to,join:owner_id=id"` +} +type PAT struct { + bun.BaseModel `bun:"table:pats"` + + ID uint64 `bun:"id,pk,autoincrement"` + Name string `bun:"name,notnull"` + Hash []byte `bun:"hash,notnull"` + OwnerID uint64 `bun:"owner_id,notnull"` + CreatedAt uint64 `bun:"created_at,notnull"` + LastUsed *int64 `bun:"last_used"` + + Owner *User `bun:"rel:belongs-to,join:owner_id=id"` +} + +type Sql_Config struct { + max_conns int + max_idle int + max_lifetime time.Duration + max_idle_time time.Duration +} +func New_Sql_Config( + max_conn int, + max_idle int, + max_lifetime time.Duration, + max_idle_time time.Duration, +) Sql_Config { + return Sql_Config { + max_conns: max_conn, + max_idle: max_idle, + max_lifetime: max_lifetime, + max_idle_time: max_idle_time, + } +} + +func Get_DB_Connection(ctx context.Context, url string, config Sql_Config) (*sql.DB, error) { + db, err := sql.Open(driver_name, url) + if err != nil { return nil, err } + db.SetMaxOpenConns(config.max_conns) + db.SetMaxIdleConns(config.max_idle) + db.SetConnMaxLifetime(config.max_lifetime) + db.SetConnMaxIdleTime(config.max_idle_time) + + if err := db.Ping(); err != nil { return nil, err } + + return db, nil +} + +func Exec_Schema(ctx context.Context, db *sql.DB) error { + bun_db := bun.NewDB(db, dia) + + tx, err := bun_db.BeginTx(ctx, &sql.TxOptions{}) + if err != nil { return err } + defer tx.Rollback() + + _, err = tx.NewCreateTable().Model((*User)(nil)).IfNotExists().Exec(ctx) + if err != nil { return err } + _, err = tx.NewCreateTable().Model((*Repo)(nil)).IfNotExists().Exec(ctx) + if err != nil { return err } + _, err = tx.NewCreateTable().Model((*PAT)(nil)).IfNotExists().Exec(ctx) + if err != nil { return err } + + return tx.Commit() +} diff --git a/db_init/go.mod b/db_init/go.mod new file mode 100644 index 0000000..4e5e44b --- /dev/null +++ b/db_init/go.mod @@ -0,0 +1,25 @@ +module github.com/Ankumeah/SourceFlameBackend/db_init + +go 1.25.5 + +require ( + github.com/jackc/pgx/v5 v5.9.2 + github.com/mattn/go-sqlite3 v1.14.44 + github.com/uptrace/bun v1.2.18 + github.com/uptrace/bun/dialect/pgdialect v1.2.18 + github.com/uptrace/bun/dialect/sqlitedialect v1.2.18 +) + +require ( + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect + github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.29.0 // indirect +) diff --git a/db_init/go.sum b/db_init/go.sum new file mode 100644 index 0000000..7f6820a --- /dev/null +++ b/db_init/go.sum @@ -0,0 +1,46 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw= +github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/mattn/go-sqlite3 v1.14.44 h1:3VSe+xafpbzsLbdr2AWlAZk9yRHiBhTBakioXaCKTF8= +github.com/mattn/go-sqlite3 v1.14.44/go.mod h1:pjEuOr8IwzLJP2MfGeTb0A35jauH+C2kbHKBr7yXKVQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= +github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo= +github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs= +github.com/uptrace/bun v1.2.18 h1:3HnRcMfS6OBPMG1eSOzlbFJ/X/AyMEJb7rMxE6VQvDU= +github.com/uptrace/bun v1.2.18/go.mod h1:wNltaKJk4JtOt4SG5I5zmA7v0/Mzjh1+/S906Rayd3Y= +github.com/uptrace/bun/dialect/pgdialect v1.2.18 h1:IZ6nM2+OYrL8lkEAy7UkSEZvoa3vluTAUlZfPtlRB2k= +github.com/uptrace/bun/dialect/pgdialect v1.2.18/go.mod h1:Tqdf4QP1okrGYpXfodXvCOK6Ob1OOTwSaoAzCgBB3IU= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.18 h1:Z33SY/U++XK9uGWqS4h8OZVxfCXguIG+sU9cYq2PGFQ= +github.com/uptrace/bun/dialect/sqlitedialect v1.2.18/go.mod h1:1MVOS/Ncy4FZbkJcgUFH6OqYoQinYNjkEwsmNQEXz2A= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/db_init/main.go b/db_init/main.go new file mode 100644 index 0000000..3f29912 --- /dev/null +++ b/db_init/main.go @@ -0,0 +1,61 @@ +package main + +import ( + "context" + "log" + "os" + "time" + "strconv" +) + +var Ctx = context.Background() +var env_vars = map[string]string { + "DATABASE_URL": "", + "DATABASE_MAX_CONNS": "", + "DATABASE_MAX_IDLE_CONNS": "", + "DATABASE_MAX_LIFETIME": "", + "DATABASE_MAX_IDLE_TIME": "", +} + +func load_env() { + for env := range env_vars { + _env, ok := os.LookupEnv(env) + if !ok { + log.Fatalf("Unset env var: %v\n", env) + } + + env_vars[env] = _env + } +} + +func main() { + load_env() + + max_conn, err := strconv.Atoi(env_vars["DATABASE_MAX_CONNS"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_CONNS: %v\n", err.Error()) + } + max_idle, err := strconv.Atoi(env_vars["DATABASE_MAX_IDLE_CONNS"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_IDLE_CONNS: %v\n", err.Error()) + } + max_lifetime, err := time.ParseDuration(env_vars["DATABASE_MAX_LIFETIME"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_LIFETIME: %v\n", err.Error()) + } + max_idle_time, err := time.ParseDuration(env_vars["DATABASE_MAX_IDLE_TIME"]) + if err != nil { + log.Fatalf("Error while parsing DATABASE_MAX_IDLE_TIME: %v\n", err.Error()) + } + config := New_Sql_Config(int(max_conn), int(max_idle), max_lifetime, max_idle_time) + + db, err := Get_DB_Connection(Ctx, env_vars["DATABASE_URL"], config) + if err != nil { + log.Fatalf("Error while connecting to database: %v\n", err.Error()) + } + if err = Exec_Schema(Ctx, db); err != nil { + log.Fatalf("Error while execing schema: %v\n", err.Error()) + } + + log.Println("Connected to database") +} diff --git a/db_init/postgres_options.go b/db_init/postgres_options.go new file mode 100644 index 0000000..f5891ad --- /dev/null +++ b/db_init/postgres_options.go @@ -0,0 +1,10 @@ +//go:build postgres +package main + +import ( + _ "github.com/jackc/pgx/v5/stdlib" + "github.com/uptrace/bun/dialect/pgdialect" +) + +const driver_name = "pgx" +var dia = pgdialect.New() diff --git a/db_init/sqlite_options.go b/db_init/sqlite_options.go new file mode 100644 index 0000000..7685025 --- /dev/null +++ b/db_init/sqlite_options.go @@ -0,0 +1,10 @@ +//go:build sqlite3 +package main + +import ( + _ "github.com/mattn/go-sqlite3" + "github.com/uptrace/bun/dialect/sqlitedialect" +) + +const driver_name = "sqlite3" +var dia = sqlitedialect.New() diff --git a/env.d.example/backend b/env.d.example/backend index 5d32aab..3737b14 100644 --- a/env.d.example/backend +++ b/env.d.example/backend @@ -1,7 +1,11 @@ API_VERSION=v1 BACKEND_PORT=5000 JWT_KEY=jwt_key -JWT_LIFESPAN_MINS=15 -TOKEN_TIMEOUT_DAYS=30 +JWT_LIFESPAN=15m +TOKEN_TIMEOUT=720h TOKEN_LIMIT=10 BACKEND_HOSTNAME=backend +DATABASE_MAX_CONNS=2 +DATABASE_MAX_IDLE_CONNS=2 +DATABASE_MAX_LIFETIME=10h +DATABASE_MAX_IDLE_TIME=2h diff --git a/env.d.example/database b/env.d.example/database index 014394f..38b5488 100644 --- a/env.d.example/database +++ b/env.d.example/database @@ -1,6 +1 @@ -DATABASE_HOST=database -DATABASE_PORT=5432 -DATABASE_CONFIG="pool_max_conns=10 pool_min_conns=2 pool_min_idle_conns=2" -DATABASE_DB=db -DATABASE_USER=username -DATABASE_PASSWORD=password +DATABASE_URL="/data/db.sql" diff --git a/env.d.example/pg_database b/env.d.example/pg_database new file mode 100644 index 0000000..229ae05 --- /dev/null +++ b/env.d.example/pg_database @@ -0,0 +1 @@ +DATABASE_URL=postgres://username:password@database:5432/db diff --git a/k8s/base/config-maps/backend-config-map.yaml b/k8s/base/config-maps/backend-config-map.yaml index 47c08f2..b51a83f 100644 --- a/k8s/base/config-maps/backend-config-map.yaml +++ b/k8s/base/config-maps/backend-config-map.yaml @@ -6,6 +6,6 @@ data: API_VERSION: v1 BACKEND_PORT: "5000" BACKEND_HOSTNAME: backend-service - JWT_LIFESPAN_MINS: "15" - TOKEN_TIMEOUT_DAYS: "30" + JWT_LIFESPAN: "15m" + TOKEN_TIMEOUT: "720d" TOKEN_LIMIT: "10" diff --git a/k8s/base/config-maps/database-config-map.yaml b/k8s/base/config-maps/database-config-map.yaml deleted file mode 100644 index 855db45..0000000 --- a/k8s/base/config-maps/database-config-map.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: database-config-map -data: - DATABASE_HOST: database-service - DATABASE_PORT: "5432" - DATABASE_CONFIG: "pool_max_conns=10 pool_min_conns=2 pool_min_idle_conns=2" diff --git a/k8s/base/config-maps/kustomization.yaml b/k8s/base/config-maps/kustomization.yaml index 02cef6e..96bfe74 100644 --- a/k8s/base/config-maps/kustomization.yaml +++ b/k8s/base/config-maps/kustomization.yaml @@ -2,6 +2,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./backend-config-map.yaml - - ./database-config-map.yaml - ./session-store-config-map.yaml - ./reverse-proxy-config-map.yaml diff --git a/k8s/base/reverse-proxy/deployment.yaml b/k8s/base/reverse-proxy/deployment.yaml index 4fc8a33..a025448 100644 --- a/k8s/base/reverse-proxy/deployment.yaml +++ b/k8s/base/reverse-proxy/deployment.yaml @@ -21,7 +21,5 @@ spec: envFrom: - configMapRef: name: reverse-proxy-config-map - - configMapRef: - name: session-store-config-map - configMapRef: name: backend-config-map diff --git a/k8s/base/secrets.example/database-secrets.yaml b/k8s/base/secrets.example/database-secrets.yaml index 9559243..2501928 100644 --- a/k8s/base/secrets.example/database-secrets.yaml +++ b/k8s/base/secrets.example/database-secrets.yaml @@ -3,6 +3,4 @@ kind: Secret metadata: name: database-secrets data: - DATABASE_DB: ZGI= # db - DATABASE_USER: dXNlcm5hbWU= # username - DATABASE_PASSWORD: cGFzc3dvcmQ= # password + DATABASE_URL: cG9zdGdyZXM6Ly91c2VybmFtZTpwYXNzd29yZEBkYXRhYmFzZTo1NDMyL2RiCg== From d0f2173e237d9526e1532b874ad2a5d98956f895 Mon Sep 17 00:00:00 2001 From: ankumeah Date: Tue, 19 May 2026 19:09:24 +0530 Subject: [PATCH 2/7] docs: Updated README.md and docker-compose.yaml with steps to change DB --- README.md | 6 ++++++ docker-compose.yaml | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index ce98945..6a3d7f8 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,12 @@ frontend for it, the frontend can be found here [Work in progress]() > [!NOTE] > A new dir called data/ will appear in the project containing the data created by the project + > [!NOTE] + > Currently we sship support for postgres and sqlite3 out of the box, + out of these sqlite3 is the default option when running with docker compose, + while for any use case involveing docker copmose, sqlite3 is recommended, + if you wish to switch to postgres have a look at ./docker-compose.yaml + - Clone and cd in the repo: `git clone https://github.com/Ankumeah/SourceFlameBackend && cd SourceFlameBackend` - Change the secrets in `./env.d.example/` to your likeing (**VERY IMPORTANT**) - Start docker compose: `docker compose up -d` diff --git a/docker-compose.yaml b/docker-compose.yaml index a8324f2..f1d357a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,37 +1,60 @@ services: backend: - build: ./backend/ + build: + context: ./backend/ + args: + - "db_type=sqlite3" # Currently supported sqlite3 and postgres env_file: - ./env.d.example/backend - ./env.d.example/session_store - - ./env.d.example/database + - ./env.d.example/database # Comment if useing postgres +# - ./env.d.example/pg_database # Comment if useing sqlite3 volumes: - ./data/git/:/srv/git/ + - ./data/database/:/data/ # Comment if not useing sqlite3 restart: unless-stopped depends_on: - - database + - db_init - session_store - database: - build: ./database/ - env_file: ./env.d.example/database - restart: unless-stopped + + db_init: + build: + context: ./db_init/ + args: + - "db_type=sqlite3" # Currently supported sqlite3 and postgres + env_file: + - ./env.d.example/backend + - ./env.d.example/database # Comment if useing postgres +# - ./env.d.example/pg_database # Comment if useing sqlite3 + restart: on-failure volumes: - - ./data/database/:/var/lib/postgresql/ + - ./data/database/:/data/ +# depends_on: # Comment if useing sqlite3 +# - database # Comment if useing sqlite3 + +# database: # Comment if useing sqlite3 +# build: ./database/ # Comment if useing sqlite3 +# env_file: ./env.d.example/pg_database # Comment if useing sqlite3 +# restart: unless-stopped # Comment if useing sqlite3 +# volumes: # Comment if useing sqlite3 +# - ./data/database/:/var/lib/postgresql/ # Comment if useing sqlite3 + session_store: build: ./session_store/ env_file: ./env.d.example/session_store restart: unless-stopped + reverse_proxy: build: ./reverse_proxy/ env_file: - ./env.d.example/reverse_proxy - - ./env.d.example/session_store - ./env.d.example/backend restart: unless-stopped depends_on: - backend ports: - "8000:80" + session_store_gc: build: ./session_store_gc/ env_file: ./env.d.example/session_store From e76aeb2a73788376f164f6631b5a77f5742a973e Mon Sep 17 00:00:00 2001 From: ankumeah Date: Tue, 19 May 2026 22:02:27 +0530 Subject: [PATCH 3/7] refactor(backend): split up main.go and moved constants into app struct --- backend/Dockerfile | 1 - backend/alpha-01.sql | 25 ---- .../sourceflame-server/connect_database.go | 28 ++++ .../connect_session_store.go | 42 ++++++ backend/cmd/sourceflame-server/env.go | 82 +++++++++++ .../cmd/sourceflame-server/get_handlers.go | 19 +++ backend/cmd/sourceflame-server/main.go | 134 +++--------------- backend/internal/apis/login.go | 15 +- backend/internal/apis/repo.go | 10 +- backend/internal/apis/repos.go | 2 +- backend/internal/apis/session.go | 3 +- backend/internal/apis/values.go | 3 - backend/internal/app/types.go | 36 +++++ backend/internal/jwt/jwt.go | 33 +---- backend/internal/jwt/jwt_test.go | 9 +- backend/internal/jwt/types.go | 20 +++ backend/internal/middlewares/check_PAT.go | 3 +- backend/internal/middlewares/check_login.go | 4 +- backend/internal/middlewares/verify_JWT.go | 4 +- backend/internal/session_store/fake_driver.go | 8 +- .../internal/session_store/session_store.go | 44 ++---- .../sessions_universal_redis_driver.go | 16 ++- backend/internal/session_store/types.go | 10 +- 23 files changed, 314 insertions(+), 237 deletions(-) delete mode 100644 backend/alpha-01.sql create mode 100644 backend/cmd/sourceflame-server/connect_database.go create mode 100644 backend/cmd/sourceflame-server/connect_session_store.go create mode 100644 backend/cmd/sourceflame-server/env.go create mode 100644 backend/cmd/sourceflame-server/get_handlers.go delete mode 100644 backend/internal/apis/values.go create mode 100644 backend/internal/jwt/types.go diff --git a/backend/Dockerfile b/backend/Dockerfile index e3a628d..2bb4445 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -19,7 +19,6 @@ RUN apk add git --no-cache WORKDIR /opt/backend/ ENV GIN_MODE=release -COPY alpha-01.sql . COPY --from=builder /opt/backend/bin/sourceflame-server . ENTRYPOINT [ "./sourceflame-server" ] diff --git a/backend/alpha-01.sql b/backend/alpha-01.sql deleted file mode 100644 index 84576be..0000000 --- a/backend/alpha-01.sql +++ /dev/null @@ -1,25 +0,0 @@ -CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - username TEXT NOT NULL UNIQUE, - created_at BIGINT NOT NULL, - password_hash BYTEA NOT NULL, - salt BYTEA NOT NULL -); - -CREATE TABLE IF NOT EXISTS repos ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - private BOOLEAN NOT NULL, - owner_id INT REFERENCES users(id) NOT NULL, - created_at BIGINT NOT NULL, - stars INT NOT NULL -); - -CREATE TABLE IF NOT EXISTS pats ( - id SERIAL PRIMARY KEY, - name TEXT NOT NULL, - hash BYTEA NOT NULL, - owner_id INT REFERENCES users(id) NOT NULL, - created_at BIGINT NOT NULL, - last_used BIGINT -); diff --git a/backend/cmd/sourceflame-server/connect_database.go b/backend/cmd/sourceflame-server/connect_database.go new file mode 100644 index 0000000..b9ffdf7 --- /dev/null +++ b/backend/cmd/sourceflame-server/connect_database.go @@ -0,0 +1,28 @@ +package main + +import ( + "github.com/Ankumeah/SourceFlameBackend/internal/database" + a "github.com/Ankumeah/SourceFlameBackend/internal/app" + + "log" +) + +func connect_database(app *a.App) { + log.Println("Connecting to database") + + config := database.New_Sql_Config( + app.Settings.DATABASE_MAX_CONNS, + app.Settings.DATABASE_MAX_IDLE_CONNS, + app.Settings.DATABASE_MAX_LIFETIME, + app.Settings.DATABASE_MAX_IDLE_TIME, + ) + + db, err := database.Get_DB_Connection(Ctx, app.Settings.DATABASE_URL, config) + if err != nil { log.Fatalf("Error while connecting to database: %v\n", err.Error()) } + + app.User_db = database.User_Sql_Driver(db) + app.Git_db = database.Git_Sql_Driver(db) + app.PAT_db = database.PAT_Sql_Driver(db) + + log.Println("Connected to database") +} diff --git a/backend/cmd/sourceflame-server/connect_session_store.go b/backend/cmd/sourceflame-server/connect_session_store.go new file mode 100644 index 0000000..ec0ac6c --- /dev/null +++ b/backend/cmd/sourceflame-server/connect_session_store.go @@ -0,0 +1,42 @@ +package main + +import ( + "github.com/Ankumeah/SourceFlameBackend/internal/session_store" + a "github.com/Ankumeah/SourceFlameBackend/internal/app" + + "log" +) + +func connect_session_store(app *a.App) { + log.Println("Connecting to session store") + + sessions_config := session_store.Universal_Redis_Config { + Username: app.Settings.SESSION_STORE_SESSIONS_USERNAME, + Password: app.Settings.SESSION_STORE_SESSIONS_PASSWORD, + Hostname: app.Settings.SESSION_STORE_HOSTNAME, + Port: app.Settings.SESSION_STORE_PORT, + } + var client session_store.Redis_client + var err error + + switch app.Settings.SESSION_STORE_TYPE { + case "redis_standalone": + client, err = session_store.Get_Redis_Client(Ctx, sessions_config) + case "redis_cluster": + client, err = session_store.Get_Redis_Cluster_Client(Ctx, sessions_config) + default: + log.Fatalf("Unsupported session store type: %v\n", app.Settings.SESSION_STORE_TYPE) + } + if err != nil { + log.Panicf("Error while connecting to session store: %v\n", err.Error()) + } + + app.Store = session_store.Get_Sessions_Uinversal_Redis_Driver( + client, + app.Settings.TOKEN_TIMEOUT, + app.Settings.TOKEN_LIMIT, + app.Settings.TOKEN_LENGTH, + app.Settings.TOKEN_NAMESPACE, + ) + log.Println("Connected to session store") +} diff --git a/backend/cmd/sourceflame-server/env.go b/backend/cmd/sourceflame-server/env.go new file mode 100644 index 0000000..a4b6209 --- /dev/null +++ b/backend/cmd/sourceflame-server/env.go @@ -0,0 +1,82 @@ +package main + +import ( + a "github.com/Ankumeah/SourceFlameBackend/internal/app" + + "os" + "time" + "log" + "strconv" +) + +var env_vars = map[string]string { + "API_VERSION": "", + "BACKEND_PORT": "", + + "SESSION_STORE_SESSIONS_USERNAME": "", + "SESSION_STORE_SESSIONS_PASSWORD": "", + "SESSION_STORE_HOSTNAME": "", + "SESSION_STORE_PORT": "", + "SESSION_STORE_TYPE": "", + + "DATABASE_URL": "", + "DATABASE_MAX_CONNS": "", + "DATABASE_MAX_IDLE_CONNS": "", + "DATABASE_MAX_LIFETIME": "", + "DATABASE_MAX_IDLE_TIME": "", + + "JWT_KEY": "", + "JWT_LIFESPAN": "", + + "TOKEN_TIMEOUT": "", + "TOKEN_LIMIT": "", +} + +func load_env(s *a.Settings) { + log.Println("Loading env") + + for env := range env_vars { + _env, ok := os.LookupEnv(env) + if !ok { + log.Fatalf("Unset env var: %v\n", env) + } + + env_vars[env] = _env + } + + set_settings(s) + + log.Println("Loaded env") +} + +func set_settings(s *a.Settings) { + s.API_VERSION = env_vars["API_VERSION"] + s.BACKEND_PORT = env_vars["BACKEND_PORT"] + + s.SESSION_STORE_SESSIONS_USERNAME = env_vars["SESSION_STORE_SESSIONS_USERNAME"] + s.SESSION_STORE_SESSIONS_PASSWORD = env_vars["SESSION_STORE_SESSIONS_PASSWORD"] + s.SESSION_STORE_HOSTNAME = env_vars["SESSION_STORE_HOSTNAME"] + s.SESSION_STORE_PORT = env_vars["SESSION_STORE_PORT"] + s.SESSION_STORE_TYPE = env_vars["SESSION_STORE_TYPE"] + + s.DATABASE_URL = env_vars["DATABASE_URL"] + + var err error + s.DATABASE_MAX_CONNS, err = strconv.Atoi(env_vars["DATABASE_MAX_CONNS"]) + if err != nil { log.Fatalf("Error while parseing DATABASE_MAX_CONNS: %v\n", err.Error()) } + s.DATABASE_MAX_IDLE_CONNS, err = strconv.Atoi(env_vars["DATABASE_MAX_IDLE_CONNS"]) + if err != nil { log.Fatalf("Error while parseing DATABASE_MAX_IDLE_CONNS: %v\n", err.Error()) } + s.DATABASE_MAX_LIFETIME, err = time.ParseDuration(env_vars["DATABASE_MAX_LIFETIME"]) + if err != nil { log.Fatalf("Error while parseing DATABASE_MAX_LIFETIME: %v\n", err.Error()) } + s.DATABASE_MAX_IDLE_TIME, err = time.ParseDuration(env_vars["DATABASE_MAX_IDLE_TIME"]) + if err != nil { log.Fatalf("Error while parseing DATABASE_MAX_IDLE_TIME: %v\n", err.Error()) } + + s.JWT_KEY = []byte(env_vars["JWT_KEY"]) + s.JWT_LIFESPAN, err = time.ParseDuration(env_vars["JWT_LIFESPAN"]) + if err != nil { log.Fatalf("Error while parseing JWT_LIFESPAN: %v\n", err.Error()) } + + s.TOKEN_TIMEOUT, err = time.ParseDuration(env_vars["TOKEN_TIMEOUT"]) + if err != nil { log.Fatalf("Error while parseing TOKEN_TIMEOUT: %v\n", err.Error()) } + s.TOKEN_LIMIT, err = strconv.Atoi(env_vars["TOKEN_LIMIT"]) + if err != nil { log.Fatalf("Error while parseing TOKEN_LIMIT: %v\n", err.Error()) } +} diff --git a/backend/cmd/sourceflame-server/get_handlers.go b/backend/cmd/sourceflame-server/get_handlers.go new file mode 100644 index 0000000..6eb1144 --- /dev/null +++ b/backend/cmd/sourceflame-server/get_handlers.go @@ -0,0 +1,19 @@ +package main + +import ( + a "github.com/Ankumeah/SourceFlameBackend/internal/app" + "github.com/Ankumeah/SourceFlameBackend/internal/pat" + "github.com/Ankumeah/SourceFlameBackend/internal/jwt" +) + +func get_handlers(app *a.App) { + app.PAT_Handler = pat.Get_PAT_Handler( + app.Settings.PAT_PREFIX, + app.Settings.PAT_LENGTH, + ) + app.JWT_Handler = jwt.Get_JWT_Handler( + app.Settings.JWT_LEEWAY, + app.Settings.JWT_LIFESPAN, + app.Settings.JWT_KEY, + ) +} diff --git a/backend/cmd/sourceflame-server/main.go b/backend/cmd/sourceflame-server/main.go index 856b489..3be833b 100644 --- a/backend/cmd/sourceflame-server/main.go +++ b/backend/cmd/sourceflame-server/main.go @@ -1,144 +1,46 @@ package main import ( - "strconv" - "time" - - "github.com/Ankumeah/SourceFlameBackend/internal/apis" a "github.com/Ankumeah/SourceFlameBackend/internal/app" - "github.com/Ankumeah/SourceFlameBackend/internal/database" + "github.com/Ankumeah/SourceFlameBackend/internal/apis" "github.com/Ankumeah/SourceFlameBackend/internal/middlewares" - "github.com/Ankumeah/SourceFlameBackend/internal/pat" - "github.com/Ankumeah/SourceFlameBackend/internal/session_store" "github.com/gin-gonic/gin" + "time" "context" "log" - "os" "sync" ) var Ctx = context.Background() -var app = &a.App{} -const pat_prefix = "gho_" -const pat_length = 32 -var env_vars = map[string]string { - "API_VERSION": "", - "BACKEND_PORT": "", - "SESSION_STORE_SESSIONS_USERNAME": "", - "SESSION_STORE_SESSIONS_PASSWORD": "", - "SESSION_STORE_HOSTNAME": "", - "SESSION_STORE_PORT": "", - "SESSION_STORE_TYPE": "", - "DATABASE_URL": "", - "DATABASE_MAX_CONNS": "", - "DATABASE_MAX_IDLE_CONNS": "", - "DATABASE_MAX_LIFETIME": "", - "DATABASE_MAX_IDLE_TIME": "", -} - -func load_env() { - for env := range env_vars { - _env, ok := os.LookupEnv(env) - if !ok { - log.Fatalf("Unset env var: %v\n", env) - } - - env_vars[env] = _env - } -} - -func connect_session_store() { - sessions_config := session_store.Universal_Redis_Config { - Username: env_vars["SESSION_STORE_SESSIONS_USERNAME"], - Password: env_vars["SESSION_STORE_SESSIONS_PASSWORD"], - Hostname: env_vars["SESSION_STORE_HOSTNAME"], - Port: env_vars["SESSION_STORE_PORT"], - } - var client session_store.Redis_client - var err error - - switch env_vars["SESSION_STORE_TYPE"] { - case "redis_standalone": - client, err = session_store.Get_Redis_Client(Ctx, sessions_config) - case "redis_cluster": - client, err = session_store.Get_Redis_Cluster_Client(Ctx, sessions_config) - default: - log.Fatalf("Unsupported session store type: %v\n", env_vars["SESSION_STORE_TYPE"]) - } - if err != nil { - log.Panicf("Error while connecting to session store: %v\n", err.Error()) - } - - app.Store = session_store.Get_Sessions_Uinversal_Redis_Driver(client) - log.Println("Connected to session store") -} - -func connect_database() { - max_conn, err := strconv.Atoi(env_vars["DATABASE_MAX_CONNS"]) - if err != nil { - log.Fatalf("Error while parsing DATABASE_MAX_CONNS: %v\n", err.Error()) - } - max_idle, err := strconv.Atoi(env_vars["DATABASE_MAX_IDLE_CONNS"]) - if err != nil { - log.Fatalf("Error while parsing DATABASE_MAX_IDLE_CONNS: %v\n", err.Error()) - } - max_lifetime, err := time.ParseDuration(env_vars["DATABASE_MAX_LIFETIME"]) - if err != nil { - log.Fatalf("Error while parsing DATABASE_MAX_LIFETIME: %v\n", err.Error()) - } - max_idle_time, err := time.ParseDuration(env_vars["DATABASE_MAX_IDLE_TIME"]) - if err != nil { - log.Fatalf("Error while parsing DATABASE_MAX_IDLE_TIME: %v\n", err.Error()) - } - config := database.New_Sql_Config(int(max_conn), int(max_idle), max_lifetime, max_idle_time) - - db, err := database.Get_DB_Connection(Ctx, env_vars["DATABASE_URL"], config) - if err != nil { - log.Fatalf("Error while connecting to database: %v\n", err.Error()) - } - - app.User_db = database.User_Sql_Driver(db) - app.Git_db = database.Git_Sql_Driver(db) - app.PAT_db = database.PAT_Sql_Driver(db) - - log.Println("Connected to database") -} - -func get_pat_handler() { - app.PAT_Handler = pat.Get_PAT_Handler(pat_prefix, pat_length) - log.Println("Got PAT Handler") -} +var app = &a.App{ Settings: &a.Settings{} } func main() { - log.Println("Loading env") - load_env() + load_env(app.Settings) + app.Settings.PAT_PREFIX = "sf_" + app.Settings.PAT_LENGTH = 32 + app.Settings.AUTH_CHALLENGE_HEADER = `Basic realm="SourceFlame"` + app.Settings.JWT_LEEWAY = time.Second * 10 + app.Settings.TOKEN_LENGTH = 64 + app.Settings.TOKEN_NAMESPACE = "refresh:" var wg sync.WaitGroup - wg.Go(func() { - log.Println("Connecting to session store") - connect_session_store() - }) - wg.Go(func() { - log.Println("Connecting to database") - connect_database() - }) - wg.Go(func() { - log.Println("Getting PAT Handler") - get_pat_handler() - }) + wg.Go(func() { connect_session_store(app) }) + wg.Go(func() { connect_database(app) }) + wg.Go(func() { get_handlers(app) }) wg.Wait() log.Println("Starting http server") r := gin.Default() apiGroup := r.Group( - "/api/" + env_vars["API_VERSION"] + "/", + "/api/" + app.Settings.API_VERSION + "/", middlewars.Log_Middleware(), ) apis.Apis(apiGroup, app) - log.Println("Running backend on port: " + env_vars["BACKEND_PORT"]) - log.Println("API_VERSION: " + env_vars["API_VERSION"]) - r.Run(":" + env_vars["BACKEND_PORT"]) + log.Println("Running backend on port: " + app.Settings.BACKEND_PORT) + log.Println("API_VERSION: " + app.Settings.API_VERSION) + + r.Run(":" + app.Settings.BACKEND_PORT) } diff --git a/backend/internal/apis/login.go b/backend/internal/apis/login.go index 6c6e42c..216e1e4 100644 --- a/backend/internal/apis/login.go +++ b/backend/internal/apis/login.go @@ -4,7 +4,6 @@ import ( a "github.com/Ankumeah/SourceFlameBackend/internal/app" "github.com/Ankumeah/SourceFlameBackend/internal/database" "github.com/Ankumeah/SourceFlameBackend/internal/external_auth" - "github.com/Ankumeah/SourceFlameBackend/internal/jwt" "github.com/Ankumeah/SourceFlameBackend/internal/session_store" "github.com/gin-gonic/gin" @@ -31,7 +30,7 @@ func login(r *gin.RouterGroup, app *a.App) { user_id, err := app.User_db.Get_Id(ctx, request.Username) if err == database.Error_invalid_user { _, err = app.User_db.Add_User(ctx, request.Username, request.Password) - add_session(c, app.Store, request.Username) + add_session(c, app, request.Username) return } else if err != nil { c.JSON(internal_server_error()) @@ -46,7 +45,7 @@ func login(r *gin.RouterGroup, app *a.App) { c.JSON(http.StatusUnauthorized, gin.H { "error": "Invalid password" }) return } else { - add_session(c, app.Store, request.Username) + add_session(c, app, request.Username) } }) @@ -73,11 +72,11 @@ func login(r *gin.RouterGroup, app *a.App) { return } - add_session(c, app.Store, username) + add_session(c, app, username) }) } -func add_session(c *gin.Context, store *session_store.Session_store, username string) bool { +func add_session(c *gin.Context, app *a.App, username string) bool { ctx := c.Request.Context() var wg sync.WaitGroup @@ -87,7 +86,7 @@ func add_session(c *gin.Context, store *session_store.Session_store, username st var jwt_err error wg.Go(func() { - token, token_err = store.Add_Session(ctx, username) + token, token_err = app.Store.Add_Session(ctx, username) if token_err == session_store.Error_too_many_tokens { c.JSON(http.StatusForbidden, gin.H { "error": "Too many refresh tokens" }) return @@ -97,9 +96,9 @@ func add_session(c *gin.Context, store *session_store.Session_store, username st } }) wg.Go(func() { - new_jwt, jwt_err = jwt.Issue_jwt(username) + new_jwt, jwt_err = app.JWT_Handler.Issue_jwt(username) if jwt_err != nil { - store.Delete_Session(ctx, username, token) + app.Store.Delete_Session(ctx, username, token) c.JSON(internal_server_error()) } }) diff --git a/backend/internal/apis/repo.go b/backend/internal/apis/repo.go index 218d903..ad9ee34 100644 --- a/backend/internal/apis/repo.go +++ b/backend/internal/apis/repo.go @@ -14,11 +14,9 @@ import ( "strings" ) -const push_conflict_message = "Push rejected because another client is pushing, please try again in some time" - func repo(r *gin.RouterGroup, app *a.App) { group := r.Group("/repo", - middlewars.Check_Login_Middleware(), + middlewars.Check_Login_Middleware(app.JWT_Handler), middlewars.Check_PAT_Middleware(app), ) @@ -85,7 +83,7 @@ func repo(r *gin.RouterGroup, app *a.App) { } if info.Private && !authed { - c.Header("WWW-Authenticate", auth_challenge_header) + c.Header("WWW-Authenticate", app.Settings.AUTH_CHALLENGE_HEADER) c.JSON(unauthorised_request()) return } else if info.Private && user_id != owner_id { @@ -129,7 +127,7 @@ func repo(r *gin.RouterGroup, app *a.App) { } if info.Private && !authed { - c.Header("WWW-Authenticate", auth_challenge_header) + c.Header("WWW-Authenticate", app.Settings.AUTH_CHALLENGE_HEADER) c.JSON(unauthorised_request()) return } else if info.Private && user_id != owner_id { @@ -167,7 +165,7 @@ func repo(r *gin.RouterGroup, app *a.App) { } if !authed { - c.Header("WWW-Authenticate", auth_challenge_header) + c.Header("WWW-Authenticate", app.Settings.AUTH_CHALLENGE_HEADER) c.JSON(unauthorised_request()) return } else if user_id != owner_id { diff --git a/backend/internal/apis/repos.go b/backend/internal/apis/repos.go index 4a5f9d9..94f67fd 100644 --- a/backend/internal/apis/repos.go +++ b/backend/internal/apis/repos.go @@ -12,7 +12,7 @@ import ( ) func repos(r *gin.RouterGroup, app *a.App) { - group := r.Group("/repos", middlewars.Verify_JWT_Middleware()) + group := r.Group("/repos", middlewars.Verify_JWT_Middleware(app.JWT_Handler)) group.POST("/:repo_name", func (c *gin.Context) { ctx := c.Request.Context() diff --git a/backend/internal/apis/session.go b/backend/internal/apis/session.go index 16df593..e59ab9e 100644 --- a/backend/internal/apis/session.go +++ b/backend/internal/apis/session.go @@ -2,7 +2,6 @@ package apis import ( a "github.com/Ankumeah/SourceFlameBackend/internal/app" - "github.com/Ankumeah/SourceFlameBackend/internal/jwt" "github.com/Ankumeah/SourceFlameBackend/internal/middlewares" "github.com/Ankumeah/SourceFlameBackend/internal/session_store" @@ -17,7 +16,7 @@ func session(r *gin.RouterGroup, app *a.App) { group.POST("/renew_jwt", func (c *gin.Context) { username := c.GetString("username") - token, err := jwt.Issue_jwt(username) + token, err := app.JWT_Handler.Issue_jwt(username) if err != nil { c.JSON(internal_server_error()) return diff --git a/backend/internal/apis/values.go b/backend/internal/apis/values.go deleted file mode 100644 index 0efd5e5..0000000 --- a/backend/internal/apis/values.go +++ /dev/null @@ -1,3 +0,0 @@ -package apis - -const auth_challenge_header = `Basic realm="SourceFlame"` diff --git a/backend/internal/app/types.go b/backend/internal/app/types.go index 31af65e..2f671d9 100644 --- a/backend/internal/app/types.go +++ b/backend/internal/app/types.go @@ -4,6 +4,9 @@ import ( "github.com/Ankumeah/SourceFlameBackend/internal/database" "github.com/Ankumeah/SourceFlameBackend/internal/pat" "github.com/Ankumeah/SourceFlameBackend/internal/session_store" + "github.com/Ankumeah/SourceFlameBackend/internal/jwt" + + "time" ) type App struct { @@ -12,4 +15,37 @@ type App struct { PAT_db *database.PAT_db Store *session_store.Session_store PAT_Handler *pat.PAT_Handler + JWT_Handler *jwt.JWT_Handler + Settings *Settings +} + +type Settings struct { + API_VERSION string + BACKEND_PORT string + + SESSION_STORE_SESSIONS_USERNAME string + SESSION_STORE_SESSIONS_PASSWORD string + SESSION_STORE_HOSTNAME string + SESSION_STORE_PORT string + SESSION_STORE_TYPE string + + DATABASE_URL string + DATABASE_MAX_CONNS int + DATABASE_MAX_IDLE_CONNS int + DATABASE_MAX_LIFETIME time.Duration + DATABASE_MAX_IDLE_TIME time.Duration + + JWT_KEY []byte + JWT_LIFESPAN time.Duration + JWT_LEEWAY time.Duration + + TOKEN_TIMEOUT time.Duration + TOKEN_LIMIT int + TOKEN_LENGTH int + TOKEN_NAMESPACE string + + PAT_PREFIX string + PAT_LENGTH uint8 + + AUTH_CHALLENGE_HEADER string } diff --git a/backend/internal/jwt/jwt.go b/backend/internal/jwt/jwt.go index e2448ea..0e95e8e 100644 --- a/backend/internal/jwt/jwt.go +++ b/backend/internal/jwt/jwt.go @@ -3,41 +3,22 @@ package jwt import ( "github.com/golang-jwt/jwt/v5" - "os" "time" "log" ) -const jwt_leeway = 10 * time.Second - -var jwt_key []byte -var jwt_lifespan time.Duration - -func init() { - key, ok := os.LookupEnv("JWT_KEY") - if !ok { log.Fatalln("Unset env var: JWT_KEY") } - jwt_key = []byte(key) - - lifespan, ok := os.LookupEnv("JWT_LIFESPAN") - if !ok { log.Fatalln("Unset env var: JWT_LIFESPAN") } - - val, err := time.ParseDuration(lifespan) - if err != nil { log.Fatalf("Error parseing JWT_LIFESPAN: %v\n", err.Error()) } - jwt_lifespan = val -} - -func Issue_jwt(username string) (string, error) { +func (h *JWT_Handler) Issue_jwt(username string) (string, error) { now := time.Now() t := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims { Subject: username, IssuedAt: jwt.NewNumericDate(now), - ExpiresAt: jwt.NewNumericDate(now.Add(jwt_lifespan)), + ExpiresAt: jwt.NewNumericDate(now.Add(h.lifespan)), }, ) - signed_jwt, err := t.SignedString(jwt_key) + signed_jwt, err := t.SignedString(h.key) if err != nil { log.Println(err.Error()) return "", err @@ -46,16 +27,14 @@ func Issue_jwt(username string) (string, error) { return signed_jwt, nil } -func Validate_jwt(target_jwt string) (string, error) { +func (h *JWT_Handler) Validate_jwt(target_jwt string) (string, error) { claims := &jwt.RegisteredClaims{} token, err := jwt.ParseWithClaims(target_jwt, claims, - func(t *jwt.Token) (any, error) { - return jwt_key, nil - }, + func(t *jwt.Token) (any, error) { return h.key, nil }, jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}), jwt.WithJSONNumber(), jwt.WithIssuedAt(), - jwt.WithLeeway(jwt_leeway), + jwt.WithLeeway(h.leeway), ) if err != nil { return "", err diff --git a/backend/internal/jwt/jwt_test.go b/backend/internal/jwt/jwt_test.go index 5158a19..f310c22 100644 --- a/backend/internal/jwt/jwt_test.go +++ b/backend/internal/jwt/jwt_test.go @@ -4,6 +4,7 @@ import ( "github.com/Ankumeah/SourceFlameBackend/internal/jwt" "testing" + "time" ) func Test_Issue_jwt(t *testing.T) { @@ -12,9 +13,10 @@ func Test_Issue_jwt(t *testing.T) { } { { "beta" }, } + handler := jwt.Get_JWT_Handler(time.Second, time.Minute, []byte("key")) for _, test := range tests { - jwt, err := jwt.Issue_jwt(test.username) + jwt, err := handler.Issue_jwt(test.username) if err != nil { t.Errorf("Error: %v\n", err.Error()) } else if len(jwt) <= 0 { @@ -31,14 +33,15 @@ func Test_Validate_jwt(t *testing.T) { } { { "beta" }, } + handler := jwt.Get_JWT_Handler(time.Second, time.Minute, []byte("key")) for _, test := range tests { - token, err := jwt.Issue_jwt(test.username) + token, err := handler.Issue_jwt(test.username) if err != nil { t.Error("Error while issueing JWT") } - username, err := jwt.Validate_jwt(token) + username, err := handler.Validate_jwt(token) if err == jwt.Error_invalid_JWT { t.Errorf("JWT was invalid") } else if err != nil { diff --git a/backend/internal/jwt/types.go b/backend/internal/jwt/types.go new file mode 100644 index 0000000..1a540ce --- /dev/null +++ b/backend/internal/jwt/types.go @@ -0,0 +1,20 @@ +package jwt + +import "time" + +type JWT_Handler struct { + leeway time.Duration + lifespan time.Duration + key []byte +} +func Get_JWT_Handler( + leeway time.Duration, + lifespan time.Duration, + key []byte, +) *JWT_Handler { + return &JWT_Handler { + leeway: leeway, + lifespan: lifespan, + key: key, + } +} diff --git a/backend/internal/middlewares/check_PAT.go b/backend/internal/middlewares/check_PAT.go index 5bdb189..51514a4 100644 --- a/backend/internal/middlewares/check_PAT.go +++ b/backend/internal/middlewares/check_PAT.go @@ -1,13 +1,12 @@ package middlewars import ( - "log" - a "github.com/Ankumeah/SourceFlameBackend/internal/app" "github.com/Ankumeah/SourceFlameBackend/internal/database" "github.com/gin-gonic/gin" + "log" "errors" "net/http" "strings" diff --git a/backend/internal/middlewares/check_login.go b/backend/internal/middlewares/check_login.go index 003fa8a..80cdff3 100644 --- a/backend/internal/middlewares/check_login.go +++ b/backend/internal/middlewares/check_login.go @@ -8,7 +8,7 @@ import ( "net/http" ) -func Check_Login_Middleware() gin.HandlerFunc { +func Check_Login_Middleware(handler *jwt.JWT_Handler) gin.HandlerFunc { return func(c *gin.Context) { token := c.GetHeader("X-Authorization") if token == "" { @@ -16,7 +16,7 @@ func Check_Login_Middleware() gin.HandlerFunc { return } - username, err := jwt.Validate_jwt(token) + username, err := handler.Validate_jwt(token) if err == jwt.Error_invalid_JWT { c.JSON(http.StatusUnauthorized, gin.H { "error": "Invalid JWT" }) c.Abort() diff --git a/backend/internal/middlewares/verify_JWT.go b/backend/internal/middlewares/verify_JWT.go index f33e2dc..bef2f0b 100644 --- a/backend/internal/middlewares/verify_JWT.go +++ b/backend/internal/middlewares/verify_JWT.go @@ -8,11 +8,11 @@ import ( "net/http" ) -func Verify_JWT_Middleware() gin.HandlerFunc { +func Verify_JWT_Middleware(handler *jwt.JWT_Handler) gin.HandlerFunc { return func(c *gin.Context) { token := c.GetHeader("X-Authorization") - username, err := jwt.Validate_jwt(token) + username, err := handler.Validate_jwt(token) if err == jwt.Error_invalid_JWT { c.JSON(http.StatusUnauthorized, gin.H { "error": "Invalid JWT" }) c.Abort() diff --git a/backend/internal/session_store/fake_driver.go b/backend/internal/session_store/fake_driver.go index 22dc6ee..9dea0cf 100644 --- a/backend/internal/session_store/fake_driver.go +++ b/backend/internal/session_store/fake_driver.go @@ -10,7 +10,11 @@ type fake_driver struct { } func Get_Fake_Driver() (*Session_store) { - return &Session_store { &fake_driver{ map[string]string{} } } + return &Session_store { + &fake_driver{ map[string]string{} }, + time.Minute, + 2, 8, "fake:", + } } func (d *fake_driver) Add_Session(ctx context.Context, username string, token string, timeout time.Duration) error { @@ -34,6 +38,6 @@ func (d *fake_driver) Delete_Session(ctx context.Context, username string, token return nil } -func (d *fake_driver) Get_Session_Count(ctx context.Context, username string) (uint8, error) { +func (d *fake_driver) Get_Session_Count(ctx context.Context, username string) (int, error) { return 1, nil } diff --git a/backend/internal/session_store/session_store.go b/backend/internal/session_store/session_store.go index 6fac1a2..ef7f899 100644 --- a/backend/internal/session_store/session_store.go +++ b/backend/internal/session_store/session_store.go @@ -4,53 +4,28 @@ import ( "context" "crypto/rand" "encoding/base64" - "strconv" - "time" "log" - "os" "sync" ) -const token_length = 64 -const token_namespace = "refresh:" - -var token_timeout time.Duration -var token_limit uint8 - -func init() { - _timeout, ok := os.LookupEnv("TOKEN_TIMEOUT") - if !ok { log.Fatalln("Unset env var: TOKEN_TIMEOUT") } - - timeout, err := time.ParseDuration(_timeout) - if err != nil { log.Fatalf("Error parseing TOKEN_TIMEOUT: %v\n", err.Error()) } - token_timeout = timeout - - limit, ok := os.LookupEnv("TOKEN_LIMIT") - if !ok { log.Fatalf("Unset env var: TOKEN_LIMIT") } - - val, err := strconv.Atoi(limit) - if err != nil { log.Fatalf("Error while converting TOKEN_LIMIT to int: %v\n", err.Error()) } - token_limit = uint8(val) -} - func (d *Session_store) Add_Session(ctx context.Context, username string) (string, error) { var wg sync.WaitGroup - var count uint8 + var count int var count_err error var token_err error var token string wg.Go(func() { - count, count_err = d.db.Get_Session_Count(ctx, token_namespace + username) + count, count_err = d.db.Get_Session_Count(ctx, d.token_namespace + username) if count_err != nil { log.Printf("Error while getting session count: %v\n", count_err.Error()) - } else if count >= token_limit { + } else if count >= d.token_limit { count_err = Error_too_many_tokens } }) wg.Go(func() { - _token := make([]byte, token_length) + _token := make([]byte, d.token_length) if _, token_err = rand.Read(_token); token_err != nil { log.Printf("Error while genrating token: %v\n", token_err.Error()) return @@ -61,7 +36,12 @@ func (d *Session_store) Add_Session(ctx context.Context, username string) (strin if count_err != nil { return "", count_err } if token_err != nil { return "", token_err } - if err := d.db.Add_Session(ctx, token_namespace + username, token, token_timeout); err != nil { + if err := d.db.Add_Session( + ctx, + d.token_namespace + username, + token, + d.token_timeout, + ); err != nil { log.Printf("Error while adding session: %v\n", err.Error()) return "", err } @@ -70,7 +50,7 @@ func (d *Session_store) Add_Session(ctx context.Context, username string) (strin } func (d *Session_store) Validate_Session(ctx context.Context, username string, token string) (bool, error) { - valid, err := d.db.Validate_Session(ctx, token_namespace + username, token) + valid, err := d.db.Validate_Session(ctx, d.token_namespace + username, token) if err != nil { log.Printf("Error while validateing session: %v\n", err) return false, err @@ -80,7 +60,7 @@ func (d *Session_store) Validate_Session(ctx context.Context, username string, t } func (d *Session_store) Delete_Session(ctx context.Context, username string, token string) error { - if err := d.db.Delete_Session(ctx, token_namespace + username, token); err != nil { + if err := d.db.Delete_Session(ctx, d.token_namespace + username, token); err != nil { log.Printf("Error while deleting session: %v\n", err.Error()) } diff --git a/backend/internal/session_store/sessions_universal_redis_driver.go b/backend/internal/session_store/sessions_universal_redis_driver.go index ce37b0e..9df9c55 100644 --- a/backend/internal/session_store/sessions_universal_redis_driver.go +++ b/backend/internal/session_store/sessions_universal_redis_driver.go @@ -15,9 +15,19 @@ type Redis_client interface { ZCount(ctx context.Context, key string, min string, max string) *redis.IntCmd } type sessions_uinversal_redis_driver struct { rdb Redis_client } -func Get_Sessions_Uinversal_Redis_Driver(client Redis_client) *Session_store { +func Get_Sessions_Uinversal_Redis_Driver( + client Redis_client, + token_timeout time.Duration, + token_limit int, + token_length int, + token_namespace string, +) *Session_store { return &Session_store { &sessions_uinversal_redis_driver { client }, + token_timeout, + token_limit, + token_length, + token_namespace, } } @@ -45,12 +55,12 @@ func (r *sessions_uinversal_redis_driver) Delete_Session(ctx context.Context, us return r.rdb.ZRem(ctx, username, token).Err() } -func (r *sessions_uinversal_redis_driver) Get_Session_Count(ctx context.Context, username string) (uint8, error) { +func (r *sessions_uinversal_redis_driver) Get_Session_Count(ctx context.Context, username string) (int, error) { now := time.Now().Unix() count , err := r.rdb.ZCount(ctx, username, strconv.FormatInt(now, 10), "inf").Result() if err != nil { return 0, err } else { - return uint8(count), nil + return int(count), nil } } diff --git a/backend/internal/session_store/types.go b/backend/internal/session_store/types.go index 9fbaa04..99bafb6 100644 --- a/backend/internal/session_store/types.go +++ b/backend/internal/session_store/types.go @@ -9,7 +9,13 @@ type sessions_driver interface { Add_Session(ctx context.Context, username string, token string, timeout time.Duration) error Validate_Session(ctx context.Context, username string, token string) (bool, error) Delete_Session(ctx context.Context, username string, token string) error - Get_Session_Count(ctx context.Context, username string) (uint8, error) + Get_Session_Count(ctx context.Context, username string) (int, error) } -type Session_store struct { db sessions_driver } +type Session_store struct { + db sessions_driver + token_timeout time.Duration + token_limit int + token_length int + token_namespace string +} From 890c789d4836dda8b0df1790de91003414bf858b Mon Sep 17 00:00:00 2001 From: ankumeah Date: Fri, 22 May 2026 01:18:03 +0530 Subject: [PATCH 4/7] fix(backend): fixed backends writing to local filesystem --- backend/internal/git/types.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/internal/git/types.go b/backend/internal/git/types.go index 462338b..6760438 100644 --- a/backend/internal/git/types.go +++ b/backend/internal/git/types.go @@ -1,15 +1,20 @@ package git -import ( - "path" -) +import "path" const max_blob_size = 2097152 var base_path string func init() { - base_path = path.Join("srv", "git") + // This breaks on windows, + // Im sorry if you are running this on bare + // metal on windows but if you are then you are + // kinda asking for it. + // The fact that you are reading this means you + // can probably change this on your own. + // Good luck and apologies from my side + base_path = path.Join("/srv", "git") } type File struct { From 4526d4400712145876f2e84841ead19d4e268612 Mon Sep 17 00:00:00 2001 From: ankumeah Date: Fri, 22 May 2026 01:25:20 +0530 Subject: [PATCH 5/7] chore(k8s): updated k8s files to support multiple DBs --- database/run_postgres.sh | 1 - k8s/base/backend/deployment.yaml | 2 - k8s/base/config-maps/backend-config-map.yaml | 10 +++- k8s/base/database/db-init-job.yaml | 16 ++++++ k8s/base/database/kustomization.yaml | 1 + k8s/base/database/stateful-set.yaml | 2 - k8s/base/kustomization.yaml | 1 + k8s/base/pv.yaml | 57 +++++++++++++++++++ .../secrets.example/database-secrets.yaml | 2 +- k8s/base/secrets.example/kustomization.yaml | 2 +- .../session-store-secrets.yaml | 1 - 11 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 k8s/base/database/db-init-job.yaml create mode 100644 k8s/base/pv.yaml diff --git a/database/run_postgres.sh b/database/run_postgres.sh index 2f0cd16..a4ce11b 100755 --- a/database/run_postgres.sh +++ b/database/run_postgres.sh @@ -4,6 +4,5 @@ export POSTGRES_USER=$(echo "$DATABASE_URL" | awk -F/ '{print $3}' | awk -F: '{p export POSTGRES_PASSWORD=$(echo "$DATABASE_URL" | awk -F/ '{print $3}' | awk -F: '{print $2}' | awk -F@ '{print $1}') export POSTGRES_PORT=$(echo "$DATABASE_URL" | awk -F/ '{print $3}' | awk -F: '{print $3}') export POSTGRES_DB=$(echo "$DATABASE_URL" | awk -F/ '{print $4}' | awk -F\? '{print $1}') -echo POSTGRES_DB $POSTGRES_DB POSTGRES_PORT $POSTGRES_PORT POSTGRES_PASSWORD $POSTGRES_PASSWORD POSTGRES_USER $POSTGRES_USER exec docker-entrypoint.sh postgres diff --git a/k8s/base/backend/deployment.yaml b/k8s/base/backend/deployment.yaml index 04055e3..c808884 100644 --- a/k8s/base/backend/deployment.yaml +++ b/k8s/base/backend/deployment.yaml @@ -32,8 +32,6 @@ spec: name: session-store-config-map - secretRef: name: database-secrets - - configMapRef: - name: database-config-map volumes: - name: git-storage persistentVolumeClaim: diff --git a/k8s/base/config-maps/backend-config-map.yaml b/k8s/base/config-maps/backend-config-map.yaml index b51a83f..8534d58 100644 --- a/k8s/base/config-maps/backend-config-map.yaml +++ b/k8s/base/config-maps/backend-config-map.yaml @@ -3,9 +3,13 @@ kind: ConfigMap metadata: name: backend-config-map data: - API_VERSION: v1 + API_VERSION: "v1" BACKEND_PORT: "5000" - BACKEND_HOSTNAME: backend-service + BACKEND_HOSTNAME: "backend-service" JWT_LIFESPAN: "15m" - TOKEN_TIMEOUT: "720d" + TOKEN_TIMEOUT: "720h" TOKEN_LIMIT: "10" + DATABASE_MAX_CONNS: "2" + DATABASE_MAX_IDLE_CONNS: "2" + DATABASE_MAX_LIFETIME: "10h" + DATABASE_MAX_IDLE_TIME: "2h" diff --git a/k8s/base/database/db-init-job.yaml b/k8s/base/database/db-init-job.yaml new file mode 100644 index 0000000..8785d4b --- /dev/null +++ b/k8s/base/database/db-init-job.yaml @@ -0,0 +1,16 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: db-init-job +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: db-init + image: sourceflamebackend-db_init:local + envFrom: + - secretRef: + name: database-secrets + - configMapRef: + name: backend-config-map diff --git a/k8s/base/database/kustomization.yaml b/k8s/base/database/kustomization.yaml index 402e403..ab9223a 100644 --- a/k8s/base/database/kustomization.yaml +++ b/k8s/base/database/kustomization.yaml @@ -3,3 +3,4 @@ kind: Kustomization resources: - ./stateful-set.yaml - ./service.yaml + - ./db-init-job.yaml diff --git a/k8s/base/database/stateful-set.yaml b/k8s/base/database/stateful-set.yaml index d36ce57..32839ea 100644 --- a/k8s/base/database/stateful-set.yaml +++ b/k8s/base/database/stateful-set.yaml @@ -25,8 +25,6 @@ spec: envFrom: - secretRef: name: database-secrets - - configMapRef: - name: database-config-map volumes: - name: database-storage persistentVolumeClaim: diff --git a/k8s/base/kustomization.yaml b/k8s/base/kustomization.yaml index eb460e2..dacaa29 100644 --- a/k8s/base/kustomization.yaml +++ b/k8s/base/kustomization.yaml @@ -3,6 +3,7 @@ kind: Kustomization resources: - ./secrets/ - ./config-maps/ + - ./pv.yaml - ./backend/ - ./database/ - ./session-store/ diff --git a/k8s/base/pv.yaml b/k8s/base/pv.yaml new file mode 100644 index 0000000..6c3409c --- /dev/null +++ b/k8s/base/pv.yaml @@ -0,0 +1,57 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: git-storage +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + hostPath: + path: /data/git/ + type: DirectoryOrCreate +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: git-storage + namespace: default +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 10Gi + volumeName: git-storage +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: database-storage +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Retain + storageClassName: "" + hostPath: + path: /data/database/ + type: DirectoryOrCreate +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: database-storage + namespace: default +spec: + accessModes: + - ReadWriteOnce + storageClassName: "" + resources: + requests: + storage: 10Gi + volumeName: database-storage diff --git a/k8s/base/secrets.example/database-secrets.yaml b/k8s/base/secrets.example/database-secrets.yaml index 2501928..c0699aa 100644 --- a/k8s/base/secrets.example/database-secrets.yaml +++ b/k8s/base/secrets.example/database-secrets.yaml @@ -3,4 +3,4 @@ kind: Secret metadata: name: database-secrets data: - DATABASE_URL: cG9zdGdyZXM6Ly91c2VybmFtZTpwYXNzd29yZEBkYXRhYmFzZTo1NDMyL2RiCg== + DATABASE_URL: cG9zdGdyZXNxbDovL3VzZXJuYW1lOnBhc3N3b3JkQGRhdGFiYXNlLXNlcnZpY2U6NTQzMi9kYg== # postgresql://username:password@database-service:5432/db diff --git a/k8s/base/secrets.example/kustomization.yaml b/k8s/base/secrets.example/kustomization.yaml index e552b02..2be316e 100644 --- a/k8s/base/secrets.example/kustomization.yaml +++ b/k8s/base/secrets.example/kustomization.yaml @@ -2,5 +2,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - ./backend-secrets.yaml - - ./session-store-secrets.yaml - ./database-secrets.yaml + - ./session-store-secrets.yaml diff --git a/k8s/base/secrets.example/session-store-secrets.yaml b/k8s/base/secrets.example/session-store-secrets.yaml index fcd2d02..7e0e8bb 100644 --- a/k8s/base/secrets.example/session-store-secrets.yaml +++ b/k8s/base/secrets.example/session-store-secrets.yaml @@ -5,6 +5,5 @@ metadata: data: SESSION_STORE_SESSIONS_USERNAME: c2Vzc2lvbnM= # sessions SESSION_STORE_SESSIONS_PASSWORD: c2Vzc2lvbnM= # sessions - SESSION_STORE_GC_USERNAME: Z2M= # gc SESSION_STORE_GC_PASSWORD: Z2M= # gc From 1f87f48b157ec60f3d78ea86be3ae462ad457bf4 Mon Sep 17 00:00:00 2001 From: ankumeah Date: Fri, 22 May 2026 01:38:06 +0530 Subject: [PATCH 6/7] doc: Updated READMEs --- README.md | 18 ++++++------------ k8s/base/README.md | 11 ++++++----- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 6a3d7f8..d00368f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ frontend for it, the frontend can be found here [Work in progress]() > Currently we sship support for postgres and sqlite3 out of the box, out of these sqlite3 is the default option when running with docker compose, while for any use case involveing docker copmose, sqlite3 is recommended, - if you wish to switch to postgres have a look at ./docker-compose.yaml + if you wish to switch to postgres have a look at docker-compose.yaml - Clone and cd in the repo: `git clone https://github.com/Ankumeah/SourceFlameBackend && cd SourceFlameBackend` - Change the secrets in `./env.d.example/` to your likeing (**VERY IMPORTANT**) @@ -32,15 +32,9 @@ frontend for it, the frontend can be found here [Work in progress]() ### With kustomize - > [!NOTE] - > This dir does not include the yaml files needed to deploy the required - storage or the PVC used to connect the storage to the app. It is the user's - responsibility to setup and connect the storage. The app assumes the - presence of two PVCs by the name of `git-storage` and `database-storage` + ![Read here](https://github.com/Ankumeah/SourceFlameBackend/blob/master/k8s/base/README.md) -- Clone and cd in the repo: `git clone https://github.com/Ankumeah/SourceFlameBackend && cd SourceFlameBackend` -- Change the secrets in `./k8s/base/secrets.example/` to your liking (**VERY IMPORTANT**) -- Move the files to the actual dir: `mv ./k8s/base/secrets.example/ ./k8s/base/secrets/` -- Add PVCs for your storage with names `git-storage` and `database-storage` -- Take a look at the yaml files and patch any values you want (Optional but recommended) -- Apply the files: `kubectl apply -k ./k8s/base/` (Adjust accordingly if patched) +## How to use + + ![openapi.yaml](https://github.com/Ankumeah/SourceFlameBackend/blob/master/openapi.yaml) + ![Quick cheatsheet](https://github.com/Ankumeah/SourceFlameBackend/blob/master/doc.md) diff --git a/k8s/base/README.md b/k8s/base/README.md index aa24155..067288a 100644 --- a/k8s/base/README.md +++ b/k8s/base/README.md @@ -1,14 +1,15 @@ # Deplyment with kustomize > [!NOTE] -> This dir does not include the yaml files needed to deploy the required -storage or the PVC used to connect the storage to the app. It is the user's -responsibility to setup and connect the storage. The app assumes the -presence of two PVCs by the name of `git-storage` and `database-storage` +> This project uses k8s hostPath storage by default (/k8s/base/pv.yaml) +want it is recommended to change this to an actual storage provider +of your choice, the yaml resources to do so are not provided in this repo +and are assumed as the users responsibility. This app assumes the presence +of two PVCs by the names `git-storage` and `database-storage` - Clone and cd in the repo: `git clone https://github.com/Ankumeah/SourceFlameBackend && cd SourceFlameBackend` - Change the secrets in `./k8s/base/secrets.example/` to your liking (**VERY IMPORTANT**) - Move the files to the actual dir: `mv ./k8s/base/secrets.example/ ./k8s/base/secrets/` -- Add PVCs for your storage with names `git-storage` and `database-storage` +- Replace PVCs for your storage with names `git-storage` and `database-storage` (Optional but **HIGHLY** recommended) - Take a look at the yaml files and patch any values you want (Optional but recommended) - Apply the files: `kubectl apply -k ./k8s/base/` (Adjust accordingly if patched) From c27cd5169909d0ae9a2d3b7888fe1cfd4a8e4f58 Mon Sep 17 00:00:00 2001 From: ankumeah Date: Fri, 22 May 2026 01:46:05 +0530 Subject: [PATCH 7/7] fix(ci): added compile tags to checks --- .github/workflows/compile-check.yaml | 2 +- .github/workflows/go-tests.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile-check.yaml b/.github/workflows/compile-check.yaml index f8586ad..6cc8b55 100644 --- a/.github/workflows/compile-check.yaml +++ b/.github/workflows/compile-check.yaml @@ -26,4 +26,4 @@ jobs: - name: Compile working-directory: backend/ - run: go build ./cmd/sourceflame-server/ + run: go build -tags="sqlite3" ./cmd/sourceflame-server/ diff --git a/.github/workflows/go-tests.yaml b/.github/workflows/go-tests.yaml index 93b4d18..bb59be1 100644 --- a/.github/workflows/go-tests.yaml +++ b/.github/workflows/go-tests.yaml @@ -29,4 +29,4 @@ jobs: - name: Run tests working-directory: backend/ - run: go test ./... -v + run: go test ./... -v -tags="sqlite3"