1 Commits

Author SHA1 Message Date
c5e95239b5 refactor nkode-core 2025-01-21 01:19:27 -06:00
55 changed files with 423 additions and 975 deletions

View File

@@ -1,11 +1,11 @@
root = "." root = "."
testdata_dir = "testdata" testdata_dir = "testdata"
tmp_dir = "bin" tmp_dir = "tmp"
[build] [build]
args_bin = [] args_bin = []
bin = "./bin/restapi" bin = "./tmp/main"
cmd = "go build -o ./bin/restapi ./cmd/restapi" cmd = "go build -o ./tmp/main ."
delay = 1000 delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"] exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = [] exclude_file = []

1
.gitignore vendored
View File

@@ -10,4 +10,3 @@ secrets.json
flaticon_svgs flaticon_svgs
flaticon_colored_svgs flaticon_colored_svgs
icons icons
bin

View File

@@ -6,6 +6,7 @@ WORKDIR /app
# volume for nkode.db # volume for nkode.db
VOLUME /app/data/sqlite VOLUME /app/data/sqlite
VOLUME /app/data/icons
# Copy go.mod and go.sum files # Copy go.mod and go.sum files
COPY go.mod go.sum ./ COPY go.mod go.sum ./
@@ -18,7 +19,7 @@ RUN go mod download
COPY . . COPY . .
# Build the application # Build the application
RUN go build -o go-nkode ./cmd/restapi RUN go build -o go-nkode ./cmd
# Stage 2: Runtime # Stage 2: Runtime
FROM debian:bookworm-slim FROM debian:bookworm-slim
@@ -31,7 +32,9 @@ RUN apt-get update && \
#ENV FRONTEND_HOST=https://app.nkode.tech #ENV FRONTEND_HOST=https://app.nkode.tech
#ENV FRONTEND_HOST=http://localhost:8090 #ENV FRONTEND_HOST=http://localhost:8090
ENV SQLITE_DB=/app/data/sqlite/demo.db ENV SVG_DIR=/app/data/icons
ENV DB_PATH=/app/data/sqlite/nkode.db
ENV SQLITE_DB=/app/data/sqlite/nkode.db
# Set the working directory inside the runtime container # Set the working directory inside the runtime container
WORKDIR /app WORKDIR /app
@@ -40,7 +43,7 @@ WORKDIR /app
COPY --from=builder /app/go-nkode . COPY --from=builder /app/go-nkode .
# Expose the port the application will run on # Expose the port the application will run on
EXPOSE 8090 EXPOSE 8080
# Command to run the application # Command to run the application
CMD ["./go-nkode"] CMD ["./go-nkode"]

View File

@@ -4,17 +4,8 @@ vars:
compose_file: "./compose/local-compose.yaml" compose_file: "./compose/local-compose.yaml"
cache_bust: cache_bust:
sh: "date +%s" sh: "date +%s"
test_db: "~/databases/demo.db"
schema_db: "./sqlite/schema.sql"
svg_path: "~/svgs/flaticon_colored_svgs"
session_secret: "c3fca773c8889eb3352745c4fe503df0"
frontend: "http://localhost:8080"
tasks: tasks:
demo_run:
cmds:
- sh -c "SQLITE_DB={{.test_db}} JWT_SECRET={{.session_secret}} FRONTEND_HOST={{.frontend}} air"
build: build:
cmds: cmds:
- docker compose -f {{.compose_file}} build --no-cache - docker compose -f {{.compose_file}} build --no-cache
@@ -29,7 +20,7 @@ tasks:
- docker system prune -f - docker system prune -f
push: push:
cmds: cmds:
- docker buildx build --platform linux/amd64,linux/arm64 -t registry.infra.nkode.tech/go-nkode:dod --push . - docker buildx build --platform linux/amd64,linux/arm64 -t registry.infra.nkode.tech/go-nkode:latest --push .
exec: exec:
cmds: cmds:
- docker exec -it cron-nkode bash - docker exec -it cron-nkode bash

View File

@@ -1,273 +0,0 @@
package main
import (
"context"
"database/sql"
_ "embed"
"flag"
"fmt"
"go-nkode/internal/entities"
"go-nkode/internal/models"
"go-nkode/internal/repository"
sqlite_queue "go-nkode/internal/sqlc"
"go-nkode/sqlite"
"log"
"os"
"path/filepath"
"strings"
_ "github.com/mattn/go-sqlite3"
)
func main() {
if len(os.Args) < 2 {
log.Fatal("Please provide a command: build-db")
}
switch os.Args[1] {
case "build-db":
BuildDB()
case "create-customer":
CreateCustomer()
case "add-user":
AddUser()
default:
log.Fatalf("Unknown command: %s", os.Args[1])
}
}
func CreateCustomer() {
cliCmd := flag.NewFlagSet("create-customer", flag.ExitOnError)
customerIDStr := cliCmd.String("customer-id", "", "Customer UUID")
dbPath := cliCmd.String("db-path", "", "Path to sqlite database")
if err := cliCmd.Parse(os.Args[2:]); err != nil {
log.Fatalf("Failed to parse flags: %v", err)
}
customerID, err := models.CustomerIDFromString(*customerIDStr)
if err != nil {
log.Fatalf("Failed to parse flags: %v", err)
}
ctx := context.Background()
sqliteDb, err := sqlite_queue.OpenSqliteDb(*dbPath)
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
queue.Start()
defer queue.Stop()
sqliteRepo := repository.NewSqliteRepository(ctx, queue)
if err != nil {
log.Fatal("error starting sqlite repo: ", err)
}
nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := entities.NewCustomer(nkodePolicy)
customer.ID = customerID
if err != nil {
log.Fatal(err)
}
if err = sqliteRepo.CreateCustomer(*customer); err != nil {
log.Fatal(err)
}
}
func AddUser() {
cliCmd := flag.NewFlagSet("add-user", flag.ExitOnError)
imgPath := cliCmd.String("img-path", "", "Path to directory with image files to add to database. The total must number must equal attrs-per-key X numb-of-keys")
imgType := cliCmd.String("img-type", "webp", "Image types webp, svg, png, jpeg, default webp")
customerIDStr := cliCmd.String("customer-id", "", "Customer ID")
dbPath := cliCmd.String("db-path", "", "Path to the database")
userEmailStr := cliCmd.String("user-email", "", "User email")
attrsPerKey := cliCmd.Int("attrs-per-key", -1, "Attributes per key")
numbOfKeys := cliCmd.Int("numb-of-keys", -1, "Number of keys")
nkodeIcons := cliCmd.String("nkode-icons", "", "common separated file names of the users nKode icons with no space. filename order sets the nkode passcode order")
if err := cliCmd.Parse(os.Args[2:]); err != nil {
log.Fatalf("Failed to parse flags: %v", err)
}
fmt.Println("os args: ", os.Args)
ctx := context.Background()
sqliteDb, err := sqlite_queue.OpenSqliteDb(*dbPath)
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
queue.Start()
defer queue.Stop()
sqliteRepo := repository.NewSqliteRepository(ctx, queue)
if err != nil {
log.Fatal("error starting sqlite repo: ", err)
}
customer, err := validCustomerID(*customerIDStr, &sqliteRepo)
if err != nil {
log.Println("db path: ", *dbPath)
log.Fatal("invalid customer id: ", err)
}
validateUserEmail(*userEmailStr, customer.ID, &sqliteRepo)
kp := entities.KeypadDimension{
AttrsPerKey: *attrsPerKey,
NumbOfKeys: *numbOfKeys,
}
if *attrsPerKey < entities.KeypadMin.AttrsPerKey || entities.KeypadMax.AttrsPerKey < *attrsPerKey {
log.Fatalf("invalid attributes per key valid range is %d-%d", entities.KeypadMin.AttrsPerKey, entities.KeypadMax.AttrsPerKey)
}
if *numbOfKeys < entities.KeypadMin.NumbOfKeys || entities.KeypadMax.NumbOfKeys < *numbOfKeys {
log.Fatalf("invalid number of keys. valid range is %d-%d", entities.KeypadMin.NumbOfKeys, entities.KeypadMax.NumbOfKeys)
}
if kp.IsDispersable() {
log.Fatal("Keypad can't be dispersable")
}
imgs := getImgs(*imgPath, *imgType)
if len(imgs) != kp.TotalAttrs() {
log.Fatal("svgs in directory not equal to keypad size")
}
imgIDs := make([]int, len(imgs))
for idx, img := range imgs {
id, err := sqliteRepo.AddSVGIcon(img)
if err != nil {
log.Fatal(err)
}
imgIDs[idx] = int(id)
}
iconNames := strings.Split(*nkodeIcons, ",")
passcodeIdxs := getPasscodeSvgIdx(iconNames, *imgPath)
if err = customer.IsValidNKode(kp, passcodeIdxs); err != nil {
log.Fatal("invalid nkode: ", err)
}
userInterface, err := entities.NewUserInterface(&kp, models.SvgIdInterface(imgIDs))
if err != nil {
log.Fatal("error creating user interface: ", err)
}
user, err := entities.NewUser(customer, *userEmailStr, passcodeIdxs, *userInterface, kp)
if err != nil {
log.Fatal("error creating user: ", err)
}
if err = sqliteRepo.WriteNewUser(*user); err != nil {
log.Fatal("error storing user: ", err)
}
}
func getPasscodeSvgIdx(nkodeSvgFileNames []string, svgDir string) []int {
files, err := os.ReadDir(svgDir)
if err != nil {
log.Fatal(err)
}
fileNames := make([]string, 0)
for _, file := range files {
if file.IsDir() || filepath.Ext(file.Name()) != ".svg" {
continue
}
fileNames = append(fileNames, file.Name())
}
passcode := make([]int, 0)
for _, fileName := range nkodeSvgFileNames {
idx := indexOf(fileNames, fileName)
if idx == -1 {
log.Fatal("file does not exist in svg dir: ", fileName)
}
passcode = append(passcode, idx)
}
return passcode
}
func indexOf(slice []string, value string) int {
for i, v := range slice {
if v == value {
return i
}
}
return -1 // not found
}
func getImgs(imgDir, imgType string) []string {
files, err := os.ReadDir(imgDir)
if err != nil {
log.Fatalf("error opening dir: %s with err: %v", imgDir, err)
}
imgs := make([]string, 0)
for _, file := range files {
if file.IsDir() || filepath.Ext(file.Name()) != "."+imgType {
continue
}
filePath := filepath.Join(imgDir, file.Name())
content, err := os.ReadFile(filePath)
if err != nil {
log.Println("Error reading file:", filePath, err)
continue
}
imgs = append(imgs, string(content))
}
return imgs
}
func validCustomerID(id string, repo *repository.SqliteRepository) (entities.Customer, error) {
cID, err := models.CustomerIDFromString(id)
if err != nil {
return entities.Customer{}, err
}
customer, err := repo.GetCustomer(cID)
if err != nil {
return entities.Customer{}, err
}
return *customer, nil
}
func validateUserEmail(email string, customerID models.CustomerID, repo *repository.SqliteRepository) {
userEmail, err := models.ParseEmail(email)
if err != nil {
log.Fatal("user email error: ", err)
}
_, err = repo.GetUser(userEmail, customerID)
if err == nil {
log.Fatal("user already exists")
}
fmt.Println("user email is valid:", userEmail)
}
func BuildDB() {
sqliteSchema, err := sqlite.FS.ReadFile("schema.sql")
if err != nil {
log.Fatal(err)
}
cliCmd := flag.NewFlagSet("build-db", flag.ExitOnError)
dbPath := cliCmd.String("db-path", "", "Path to the database")
imgPath := cliCmd.String("img-path", "", "Path to the directory with images")
imgType := cliCmd.String("img-type", "svg", "Image types webp, svg, png, jpeg, default webp")
if err = cliCmd.Parse(os.Args[2:]); err != nil {
log.Fatalf("Failed to parse flags: %v", err)
}
if err = MakeTables(*dbPath, string(sqliteSchema)); err != nil {
log.Fatal(err)
}
ctx := context.Background()
sqliteDb, err := sqlite_queue.OpenSqliteDb(*dbPath)
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
queue.Start()
defer queue.Stop()
sqliteRepo := repository.NewSqliteRepository(ctx, queue)
if err != nil {
log.Fatal("error starting sqlite repo: ", err)
}
numbImgs := IconImgToSqlite(&sqliteRepo, *imgPath, *imgType)
log.Printf("Successfully added %d Images in %s to the database at %s\n", numbImgs, *imgPath, *dbPath)
}
func IconImgToSqlite(repo *repository.SqliteRepository, imgDir, imgType string) int {
imgs := getImgs(imgDir, imgType)
for _, img := range imgs {
if _, err := repo.AddSVGIcon(img); err != nil {
log.Fatal(err)
}
}
return len(imgs)
}
func MakeTables(dbPath string, schema string) error {
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
if err = os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
return err
}
if _, err = os.Create(dbPath); err != nil {
return err
}
}
db, err := sql.Open("sqlite3", dbPath)
if err != nil {
return err
}
if _, err = db.Exec(schema); err != nil {
return err
}
return db.Close()
}

View File

@@ -8,10 +8,11 @@ import (
httpSwagger "github.com/swaggo/http-swagger" httpSwagger "github.com/swaggo/http-swagger"
_ "go-nkode/docs" _ "go-nkode/docs"
"go-nkode/internal/api" "go-nkode/internal/api"
"go-nkode/internal/email" api2 "go-nkode/pkg/nkode-core/api"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/email"
"go-nkode/internal/repository" "go-nkode/pkg/nkode-core/entities"
sqliteQueue "go-nkode/internal/sqlc" "go-nkode/pkg/nkode-core/repository"
sqliteQueue "go-nkode/pkg/nkode-core/sqlc"
"log" "log"
"net/http" "net/http"
"os" "os"
@@ -56,7 +57,7 @@ func main() {
} }
ctx := context.Background() ctx := context.Background()
queue, err := sqliteQueue.NewQueue(ctx, sqliteDb) queue, err := sqliteQueue.NewQueue(sqliteDb, ctx)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -67,14 +68,18 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
}(queue) }(queue)
sesClient := email.NewSESClient() sesClient := email.NewSESClient()
emailQueue := email.NewEmailQueue(emailQueueBufferSize, maxEmailsPerSecond, &sesClient) emailQueue := email.NewEmailQueue(emailQueueBufferSize, maxEmailsPerSecond, &sesClient)
emailQueue.Start() emailQueue.Start()
defer emailQueue.Stop() defer emailQueue.Stop()
sqlitedb := repository.NewSqliteRepository(ctx, queue)
nkodeApi := api.NewNKodeAPI(&sqlitedb, emailQueue) sqlitedb := repository.NewSqliteRepository(queue, ctx)
nkodeApi := api2.NewNKodeAPI(&sqlitedb, emailQueue)
AddDefaultCustomer(nkodeApi) AddDefaultCustomer(nkodeApi)
handler := api.NKodeHandler{Api: nkodeApi} handler := api.NKodeHandler{Api: nkodeApi}
mux := http.NewServeMux() mux := http.NewServeMux()
mux.Handle(api.CreateNewCustomer, &handler) mux.Handle(api.CreateNewCustomer, &handler)
mux.Handle(api.GenerateSignupResetInterface, &handler) mux.Handle(api.GenerateSignupResetInterface, &handler)
@@ -86,10 +91,12 @@ func main() {
mux.Handle(api.RandomSvgInterface, &handler) mux.Handle(api.RandomSvgInterface, &handler)
mux.Handle(api.RefreshToken, &handler) mux.Handle(api.RefreshToken, &handler)
mux.Handle(api.ResetNKode, &handler) mux.Handle(api.ResetNKode, &handler)
// Serve Swagger UI // Serve Swagger UI
mux.Handle("/swagger/", httpSwagger.WrapHandler) mux.Handle("/swagger/", httpSwagger.WrapHandler)
fmt.Println("Running on localhost:8090...")
log.Fatal(http.ListenAndServe(":8090", corsMiddleware(mux))) fmt.Println("Running on localhost:8080...")
log.Fatal(http.ListenAndServe(":8080", corsMiddleware(mux)))
} }
func corsMiddleware(next http.Handler) http.Handler { func corsMiddleware(next http.Handler) http.Handler {
@@ -110,13 +117,13 @@ func corsMiddleware(next http.Handler) http.Handler {
}) })
} }
func AddDefaultCustomer(nkodeApi api.NKodeAPI) { func AddDefaultCustomer(nkodeApi api2.NKodeAPI) {
newId, err := uuid.Parse("ed9ed6e0-082c-4b57-8d8c-f00ed6493457") newId, err := uuid.Parse("ed9ed6e0-082c-4b57-8d8c-f00ed6493457")
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
customerId := models.CustomerID(newId) customerId := entities.CustomerId(newId)
nkodePolicy := models.NewDefaultNKodePolicy() nkodePolicy := entities.NewDefaultNKodePolicy()
_, err = nkodeApi.CreateNewCustomer(nkodePolicy, &customerId) _, err = nkodeApi.CreateNewCustomer(nkodePolicy, &customerId)
if err != nil { if err != nil {
log.Println(err) log.Println(err)

View File

@@ -6,9 +6,9 @@ import (
"fmt" "fmt"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/internal/api" "go-nkode/internal/api"
"go-nkode/internal/entities"
"go-nkode/internal/models" "go-nkode/internal/models"
"go-nkode/internal/security" "go-nkode/pkg/nkode-core/entities"
security2 "go-nkode/pkg/nkode-core/security"
"io" "io"
"net/http" "net/http"
"strings" "strings"
@@ -18,7 +18,7 @@ import (
func TestApi(t *testing.T) { func TestApi(t *testing.T) {
base := "http://localhost:8080" base := "http://localhost:8080"
newCustomerBody := models.NewCustomerPost{ newCustomerBody := models.NewCustomerPost{
NKodePolicy: models.NewDefaultNKodePolicy(), NKodePolicy: entities.NewDefaultNKodePolicy(),
} }
kp := entities.KeypadDimension{ kp := entities.KeypadDimension{
AttrsPerKey: 14, AttrsPerKey: 14,
@@ -27,7 +27,7 @@ func TestApi(t *testing.T) {
var customerResp models.CreateNewCustomerResp var customerResp models.CreateNewCustomerResp
testApiPost(t, base+api.CreateNewCustomer, newCustomerBody, &customerResp) testApiPost(t, base+api.CreateNewCustomer, newCustomerBody, &customerResp)
userEmail := "test_username" + security.GenerateRandomString(12) + "@example.com" userEmail := "test_username" + security2.GenerateRandomString(12) + "@example.com"
signupInterfaceBody := models.GenerateSignupRestInterfacePost{ signupInterfaceBody := models.GenerateSignupRestInterfacePost{
CustomerId: customerResp.CustomerId, CustomerId: customerResp.CustomerId,
AttrsPerKey: kp.AttrsPerKey, AttrsPerKey: kp.AttrsPerKey,
@@ -35,7 +35,7 @@ func TestApi(t *testing.T) {
UserEmail: strings.ToUpper(userEmail), // should be case-insensitive UserEmail: strings.ToUpper(userEmail), // should be case-insensitive
Reset: false, Reset: false,
} }
var signupInterfaceResp models.GenerateSignupResetInterfaceResp var signupInterfaceResp entities.SignupResetInterface
testApiPost(t, base+api.GenerateSignupResetInterface, signupInterfaceBody, &signupInterfaceResp) testApiPost(t, base+api.GenerateSignupResetInterface, signupInterfaceBody, &signupInterfaceResp)
assert.Len(t, signupInterfaceResp.SvgInterface, kp.TotalAttrs()) assert.Len(t, signupInterfaceResp.SvgInterface, kp.TotalAttrs())
passcodeLen := 4 passcodeLen := 4
@@ -66,7 +66,7 @@ func TestApi(t *testing.T) {
UserEmail: userEmail, UserEmail: userEmail,
} }
var loginInterfaceResp models.GetLoginInterfaceResp var loginInterfaceResp entities.LoginInterface
testApiPost(t, base+api.GetLoginInterface, loginInterfaceBody, &loginInterfaceResp) testApiPost(t, base+api.GetLoginInterface, loginInterfaceBody, &loginInterfaceResp)
assert.Equal(t, loginInterfaceResp.AttrsPerKey, kp.AttrsPerKey) assert.Equal(t, loginInterfaceResp.AttrsPerKey, kp.AttrsPerKey)
assert.Equal(t, loginInterfaceResp.NumbOfKeys, kp.NumbOfKeys) assert.Equal(t, loginInterfaceResp.NumbOfKeys, kp.NumbOfKeys)
@@ -78,11 +78,11 @@ func TestApi(t *testing.T) {
KeySelection: loginKeySelection, KeySelection: loginKeySelection,
} }
var jwtTokens security.AuthenticationTokens var jwtTokens security2.AuthenticationTokens
testApiPost(t, base+api.Login, loginBody, &jwtTokens) testApiPost(t, base+api.Login, loginBody, &jwtTokens)
refreshClaims, err := security.ParseRegisteredClaimToken(jwtTokens.RefreshToken) refreshClaims, err := security2.ParseRegisteredClaimToken(jwtTokens.RefreshToken)
assert.Equal(t, refreshClaims.Subject, userEmail) assert.Equal(t, refreshClaims.Subject, userEmail)
accessClaims, err := security.ParseRegisteredClaimToken(jwtTokens.AccessToken) accessClaims, err := security2.ParseRegisteredClaimToken(jwtTokens.AccessToken)
assert.Equal(t, accessClaims.Subject, userEmail) assert.Equal(t, accessClaims.Subject, userEmail)
renewBody := models.RenewAttributesPost{CustomerId: customerResp.CustomerId} renewBody := models.RenewAttributesPost{CustomerId: customerResp.CustomerId}
testApiPost(t, base+api.RenewAttributes, renewBody, nil) testApiPost(t, base+api.RenewAttributes, renewBody, nil)
@@ -104,7 +104,7 @@ func TestApi(t *testing.T) {
var refreshTokenResp models.RefreshTokenResp var refreshTokenResp models.RefreshTokenResp
testApiGet(t, base+api.RefreshToken, &refreshTokenResp, jwtTokens.RefreshToken) testApiGet(t, base+api.RefreshToken, &refreshTokenResp, jwtTokens.RefreshToken)
accessClaims, err = security.ParseRegisteredClaimToken(refreshTokenResp.AccessToken) accessClaims, err = security2.ParseRegisteredClaimToken(refreshTokenResp.AccessToken)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, accessClaims.Subject, userEmail) assert.Equal(t, accessClaims.Subject, userEmail)
} }

View File

@@ -1,9 +1,10 @@
services: services:
go-nkode: go-nkode:
container_name: go-nkode container_name: go-nkode
image: registry.infra.nkode.tech/go-nkode:dod image: registry.infra.nkode.tech/go-nkode
volumes: volumes:
- /var/go-nkode/sqlite:/app/data/sqlite - /var/go-nkode/sqlite:/app/data/sqlite
- /var/go-nkode/icons:/app/data/icons
environment: environment:
- JWT_SECRET=${JWT_SECRET} - JWT_SECRET=${JWT_SECRET}

25
go.mod
View File

@@ -3,6 +3,7 @@ module go-nkode
go 1.23.0 go 1.23.0
require ( require (
github.com/DonovanKelly/sugar-n-spice v1.0.1
github.com/aws/aws-sdk-go-v2 v1.31.0 github.com/aws/aws-sdk-go-v2 v1.31.0
github.com/aws/aws-sdk-go-v2/config v1.27.37 github.com/aws/aws-sdk-go-v2/config v1.27.37
github.com/aws/aws-sdk-go-v2/service/ses v1.27.1 github.com/aws/aws-sdk-go-v2/service/ses v1.27.1
@@ -13,12 +14,10 @@ require (
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/swaggo/http-swagger v1.3.4 github.com/swaggo/http-swagger v1.3.4
github.com/swaggo/swag v1.16.4 github.com/swaggo/swag v1.16.4
github.com/swaggo/swag/example/celler v0.0.0-20241025062444-99698582709d
golang.org/x/crypto v0.29.0 golang.org/x/crypto v0.29.0
) )
require ( require (
github.com/DonovanKelly/sugar-n-spice v1.0.1 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.35 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.35 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect
@@ -31,39 +30,17 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.1 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.31.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.31.1 // indirect
github.com/aws/smithy-go v1.21.0 // indirect github.com/aws/smithy-go v1.21.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/swaggo/files v1.0.1 // indirect github.com/swaggo/files v1.0.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
golang.org/x/arch v0.3.0 // indirect
golang.org/x/net v0.31.0 // indirect golang.org/x/net v0.31.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.27.0 // indirect golang.org/x/tools v0.27.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

71
go.sum
View File

@@ -30,21 +30,9 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.31.1 h1:8K0UNOkZiK9Uh3HIF6Bx0rcNCftq
github.com/aws/aws-sdk-go-v2/service/sts v1.31.1/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= github.com/aws/aws-sdk-go-v2/service/sts v1.31.1/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI=
github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA=
github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
@@ -53,21 +41,8 @@ github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9Z
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
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/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
@@ -76,48 +51,21 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
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/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
@@ -126,16 +74,7 @@ github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64
github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/swaggo/swag/example/celler v0.0.0-20241025062444-99698582709d h1:zyYK35EKMhtoXGSxZJm9yxO9KzYEr0M9/63FhaBKr4c=
github.com/swaggo/swag/example/celler v0.0.0-20241025062444-99698582709d/go.mod h1:kw/fmH4DXH7Dp7d8aLEU1ub7UA82GhJJ0ZABDxEJaM0=
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.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
@@ -157,12 +96,8 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -170,23 +105,17 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o= golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q= golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@@ -5,16 +5,17 @@ import (
"errors" "errors"
"github.com/google/uuid" "github.com/google/uuid"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/entities"
"go-nkode/internal/models" "go-nkode/internal/models"
"go-nkode/internal/security" "go-nkode/pkg/nkode-core/api"
"go-nkode/pkg/nkode-core/entities"
"go-nkode/pkg/nkode-core/security"
"log" "log"
"net/http" "net/http"
"strings" "strings"
) )
type NKodeHandler struct { type NKodeHandler struct {
Api NKodeAPI Api api.NKodeAPI
} }
const ( const (
@@ -103,10 +104,12 @@ func (h *NKodeHandler) GenerateSignupResetInterfaceHandler(w http.ResponseWriter
methodNotAllowed(w) methodNotAllowed(w)
return return
} }
var signupResetPost models.GenerateSignupRestInterfacePost var signupResetPost models.GenerateSignupRestInterfacePost
if err := decodeJson(w, r, &signupResetPost); err != nil { if err := decodeJson(w, r, &signupResetPost); err != nil {
return return
} }
kp := entities.KeypadDimension{ kp := entities.KeypadDimension{
AttrsPerKey: signupResetPost.AttrsPerKey, AttrsPerKey: signupResetPost.AttrsPerKey,
NumbOfKeys: signupResetPost.NumbOfKeys, NumbOfKeys: signupResetPost.NumbOfKeys,
@@ -120,16 +123,17 @@ func (h *NKodeHandler) GenerateSignupResetInterfaceHandler(w http.ResponseWriter
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := models.ParseEmail(signupResetPost.UserEmail) userEmail, err := entities.ParseEmail(signupResetPost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
return return
} }
resp, err := h.Api.GenerateSignupResetInterface(userEmail, models.CustomerID(customerId), kp, signupResetPost.Reset) resp, err := h.Api.GenerateSignupResetInterface(userEmail, entities.CustomerId(customerId), kp, signupResetPost.Reset)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
} }
marshalAndWriteBytes(w, resp) marshalAndWriteBytes(w, resp)
} }
@@ -153,7 +157,7 @@ func (h *NKodeHandler) SetNKodeHandler(w http.ResponseWriter, r *http.Request) {
badRequest(w, malformedSessionId) badRequest(w, malformedSessionId)
return return
} }
confirmInterface, err := h.Api.SetNKode(models.CustomerID(customerId), models.SessionId(sessionId), setNKodePost.KeySelection) confirmInterface, err := h.Api.SetNKode(entities.CustomerId(customerId), entities.SessionId(sessionId), setNKodePost.KeySelection)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
@@ -183,7 +187,7 @@ func (h *NKodeHandler) ConfirmNKodeHandler(w http.ResponseWriter, r *http.Reques
badRequest(w, malformedSessionId) badRequest(w, malformedSessionId)
return return
} }
if err = h.Api.ConfirmNKode(models.CustomerID(customerId), models.SessionId(sessionId), confirmNKodePost.KeySelection); err != nil { if err = h.Api.ConfirmNKode(entities.CustomerId(customerId), entities.SessionId(sessionId), confirmNKodePost.KeySelection); err != nil {
handleError(w, err) handleError(w, err)
return return
} }
@@ -205,11 +209,11 @@ func (h *NKodeHandler) GetLoginInterfaceHandler(w http.ResponseWriter, r *http.R
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := models.ParseEmail(loginInterfacePost.UserEmail) userEmail, err := entities.ParseEmail(loginInterfacePost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
} }
loginInterface, err := h.Api.GetLoginInterface(userEmail, models.CustomerID(customerId)) loginInterface, err := h.Api.GetLoginInterface(userEmail, entities.CustomerId(customerId))
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
@@ -233,12 +237,12 @@ func (h *NKodeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := models.ParseEmail(loginPost.UserEmail) userEmail, err := entities.ParseEmail(loginPost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
return return
} }
jwtTokens, err := h.Api.Login(models.CustomerID(customerId), userEmail, loginPost.KeySelection) jwtTokens, err := h.Api.Login(entities.CustomerId(customerId), userEmail, loginPost.KeySelection)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
@@ -262,7 +266,7 @@ func (h *NKodeHandler) RenewAttributesHandler(w http.ResponseWriter, r *http.Req
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
if err = h.Api.RenewAttributes(models.CustomerID(customerId)); err != nil { if err = h.Api.RenewAttributes(entities.CustomerId(customerId)); err != nil {
handleError(w, err) handleError(w, err)
return return
} }
@@ -283,7 +287,7 @@ func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http.
respBody := models.RandomSvgInterfaceResp{ respBody := models.RandomSvgInterfaceResp{
Svgs: svgs, Svgs: svgs,
Colors: models.SetColors, Colors: entities.SetColors,
} }
marshalAndWriteBytes(w, respBody) marshalAndWriteBytes(w, respBody)
@@ -305,13 +309,13 @@ func (h *NKodeHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Reques
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := models.ParseEmail(refreshClaims.Subject) userEmail, err := entities.ParseEmail(refreshClaims.Subject)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
log.Println(err) log.Println(err)
return return
} }
accessToken, err := h.Api.RefreshToken(userEmail, models.CustomerID(customerId), refreshToken) accessToken, err := h.Api.RefreshToken(userEmail, entities.CustomerId(customerId), refreshToken)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
@@ -337,13 +341,13 @@ func (h *NKodeHandler) ResetNKode(w http.ResponseWriter, r *http.Request) {
return return
} }
userEmail, err := models.ParseEmail(resetNKodePost.UserEmail) userEmail, err := entities.ParseEmail(resetNKodePost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
return return
} }
if err = h.Api.ResetNKode(userEmail, models.CustomerID(customerId)); err != nil { if err = h.Api.ResetNKode(userEmail, entities.CustomerId(customerId)); err != nil {
internalServerError(w) internalServerError(w)
log.Println(err) log.Println(err)
return return

View File

@@ -1,10 +1,7 @@
package models package models
import ( import (
"fmt" "go-nkode/pkg/nkode-core/entities"
"github.com/google/uuid"
"net/mail"
"strings"
) )
type SetNKodeResp struct { type SetNKodeResp struct {
@@ -13,7 +10,7 @@ type SetNKodeResp struct {
type RandomSvgInterfaceResp struct { type RandomSvgInterfaceResp struct {
Svgs []string `json:"svgs"` Svgs []string `json:"svgs"`
Colors []RGBColor `json:"colors"` Colors []entities.RGBColor `json:"colors"`
} }
type RefreshTokenResp struct { type RefreshTokenResp struct {
@@ -21,7 +18,7 @@ type RefreshTokenResp struct {
} }
type NewCustomerPost struct { type NewCustomerPost struct {
NKodePolicy NKodePolicy `json:"nkode_policy"` NKodePolicy entities.NKodePolicy `json:"nkode_policy"`
} }
type GenerateSignupRestInterfacePost struct { type GenerateSignupRestInterfacePost struct {
@@ -40,7 +37,7 @@ type SetNKodePost struct {
type ConfirmNKodePost struct { type ConfirmNKodePost struct {
CustomerId string `json:"customer_id"` CustomerId string `json:"customer_id"`
KeySelection KeySelection `json:"key_selection"` KeySelection entities.KeySelection `json:"key_selection"`
SessionId string `json:"session_id"` SessionId string `json:"session_id"`
} }
@@ -52,18 +49,13 @@ type GetLoginInterfacePost struct {
type LoginPost struct { type LoginPost struct {
CustomerId string `json:"customer_id"` CustomerId string `json:"customer_id"`
UserEmail string `json:"email"` UserEmail string `json:"email"`
KeySelection KeySelection `json:"key_selection"` KeySelection entities.KeySelection `json:"key_selection"`
} }
type RenewAttributesPost struct { type RenewAttributesPost struct {
CustomerId string `json:"customer_id"` CustomerId string `json:"customer_id"`
} }
type RefreshTokenPost struct {
UserEmail string `json:"email"`
CustomerId string `json:"customer_id"`
}
type ResetNKodePost struct { type ResetNKodePost struct {
UserEmail string `json:"email"` UserEmail string `json:"email"`
CustomerId string `json:"customer_id"` CustomerId string `json:"customer_id"`
@@ -72,104 +64,3 @@ type ResetNKodePost struct {
type CreateNewCustomerResp struct { type CreateNewCustomerResp struct {
CustomerId string `json:"customer_id"` CustomerId string `json:"customer_id"`
} }
type GenerateSignupResetInterfaceResp struct {
SessionId string `json:"session_id"`
UserIdxInterface IdxInterface `json:"user_interface"`
SvgInterface []string `json:"svg_interface"`
Colors []RGBColor `json:"colors"`
}
type GetLoginInterfaceResp struct {
UserIdxInterface IdxInterface `json:"user_interface"`
SvgInterface []string `json:"svg_interface"`
AttrsPerKey int `json:"attrs_per_key"`
NumbOfKeys int `json:"numb_of_keys"`
Colors []RGBColor `json:"colors"`
}
type KeySelection []int
type CustomerID uuid.UUID
func CustomerIdToString(customerId CustomerID) string {
customerUuid := uuid.UUID(customerId)
return customerUuid.String()
}
func CustomerIDFromString(customerID string) (CustomerID, error) {
id, err := uuid.Parse(customerID)
if err != nil {
return CustomerID{}, err
}
return CustomerID(id), nil
}
type SessionId uuid.UUID
type UserId uuid.UUID
func UserIdFromString(userId string) UserId {
id, err := uuid.Parse(userId)
if err != nil {
fmt.Errorf("unable to parse user id %+v", err)
}
return UserId(id)
}
func (s *SessionId) String() string {
id := uuid.UUID(*s)
return id.String()
}
type UserEmail string
func ParseEmail(email string) (UserEmail, error) {
_, err := mail.ParseAddress(email)
if err != nil {
return "", err
}
return UserEmail(strings.ToLower(email)), err
}
type IdxInterface []int
type SvgIdInterface []int
func SessionIdFromString(sessionId string) (SessionId, error) {
id, err := uuid.Parse(sessionId)
if err != nil {
return SessionId{}, err
}
return SessionId(id), nil
}
type EncipheredNKode struct {
Code string
Mask string
}
type RGBColor struct {
Red int `json:"red"`
Green int `json:"green"`
Blue int `json:"blue"`
}
var SetColors = []RGBColor{
{0, 0, 0}, // Black
{255, 0, 0}, // Red
{0, 128, 0}, // Dark Green
{0, 0, 255}, // Blue
{244, 200, 60}, // Yellow
{255, 0, 255}, // Magenta
{0, 200, 200}, // Cyan
{127, 0, 127}, // Purple
{232, 92, 13}, // Orange
{0, 127, 127}, // Teal
{127, 127, 0}, // Olive
{127, 0, 0}, // Dark Red
{128, 128, 128}, // Gray
{228, 102, 102}, // Dark Purple
{185, 17, 240}, // Salmon
{16, 200, 100}, // Green
}

View File

@@ -1,22 +0,0 @@
package repository
import (
"go-nkode/internal/entities"
"go-nkode/internal/models"
)
type CustomerUserRepository interface {
GetCustomer(models.CustomerID) (*entities.Customer, error)
GetUser(models.UserEmail, models.CustomerID) (*entities.User, error)
CreateCustomer(entities.Customer) error
WriteNewUser(entities.User) error
UpdateUserNKode(entities.User) error
UpdateUserInterface(models.UserId, entities.UserInterface) error
UpdateUserRefreshToken(models.UserId, string) error
Renew(models.CustomerID) error
RefreshUserPasscode(entities.User, []int, entities.CustomerAttributes) error
RandomSvgInterface(entities.KeypadDimension) ([]string, error)
RandomSvgIdxInterface(entities.KeypadDimension) (models.SvgIdInterface, error)
GetSvgStringInterface(models.SvgIdInterface) ([]string, error)
AddSVGIcon(svgStr string) (int64, error)
}

View File

@@ -5,11 +5,10 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/email" "go-nkode/pkg/nkode-core/email"
"go-nkode/internal/entities" "go-nkode/pkg/nkode-core/entities"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/repository"
"go-nkode/internal/repository" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security"
"log" "log"
"os" "os"
"time" "time"
@@ -34,22 +33,23 @@ func NewNKodeAPI(db repository.CustomerUserRepository, queue *email.Queue) NKode
} }
} }
func (n *NKodeAPI) CreateNewCustomer(nkodePolicy models.NKodePolicy, id *models.CustomerID) (*models.CustomerID, error) { func (n *NKodeAPI) CreateNewCustomer(nkodePolicy entities.NKodePolicy, id *entities.CustomerId) (*entities.CustomerId, error) {
newCustomer, err := entities.NewCustomer(nkodePolicy) newCustomer, err := entities.NewCustomer(nkodePolicy)
if id != nil { if id != nil {
newCustomer.ID = *id newCustomer.Id = *id
} }
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = n.Db.CreateCustomer(*newCustomer) err = n.Db.CreateCustomer(*newCustomer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &newCustomer.ID, nil return &newCustomer.Id, nil
} }
func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, customerId models.CustomerID, kp entities.KeypadDimension, reset bool) (*models.GenerateSignupResetInterfaceResp, error) { func (n *NKodeAPI) GenerateSignupResetInterface(userEmail entities.UserEmail, customerId entities.CustomerId, kp entities.KeypadDimension, reset bool) (*entities.SignupResetInterface, error) {
user, err := n.Db.GetUser(userEmail, customerId) user, err := n.Db.GetUser(userEmail, customerId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -58,27 +58,23 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, cust
log.Printf("user %s already exists", string(userEmail)) log.Printf("user %s already exists", string(userEmail))
return nil, config.ErrUserAlreadyExists return nil, config.ErrUserAlreadyExists
} }
//svgIdxInterface, err := n.Db.RandomSvgIdxInterface(kp) svgIdxInterface, err := n.Db.RandomSvgIdxInterface(kp)
//if err != nil { if err != nil {
// return nil, err return nil, err
//}
svgIdxInterface := make(models.SvgIdInterface, 54)
for idx := range 54 {
svgIdxInterface[idx] = idx + 1
} }
signupSession, err := entities.NewSignupResetSession(userEmail, kp, customerId, svgIdxInterface, reset) signupSession, err := entities.NewSignupResetSession(userEmail, kp, customerId, svgIdxInterface, reset)
if err != nil { if err != nil {
return nil, err return nil, err
} }
//n.SignupSessions[signupSession.ID] = *signupSession
if err := n.SignupSessionCache.Add(signupSession.Id.String(), *signupSession, sessionExpiration); err != nil { if err := n.SignupSessionCache.Add(signupSession.Id.String(), *signupSession, sessionExpiration); err != nil {
return nil, err return nil, err
} }
svgInterface, err := n.Db.GetSvgStringInterface(signupSession.LoginUserInterface.SvgId) svgInterface, err := n.Db.GetSvgStringInterface(signupSession.LoginUserInterface.SvgId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp := models.GenerateSignupResetInterfaceResp{ resp := entities.SignupResetInterface{
UserIdxInterface: signupSession.SetIdxInterface, UserIdxInterface: signupSession.SetIdxInterface,
SvgInterface: svgInterface, SvgInterface: svgInterface,
SessionId: uuid.UUID(signupSession.Id).String(), SessionId: uuid.UUID(signupSession.Id).String(),
@@ -87,41 +83,9 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, cust
return &resp, nil return &resp, nil
} }
func (n *NKodeAPI) GenerateSignupResetInterfaceRigged(userEmail models.UserEmail, customerId models.CustomerID, kp entities.KeypadDimension, reset bool) (*models.GenerateSignupResetInterfaceResp, error) { func (n *NKodeAPI) SetNKode(customerId entities.CustomerId, sessionId entities.SessionId, keySelection entities.KeySelection) (entities.IdxInterface, error) {
user, err := n.Db.GetUser(userEmail, customerId)
if err != nil {
return nil, err
}
if user != nil && !reset {
log.Printf("user %s already exists", string(userEmail))
return nil, config.ErrUserAlreadyExists
}
svgIdxInterface := make(models.SvgIdInterface, kp.TotalAttrs())
for idx := range kp.TotalAttrs() {
svgIdxInterface[idx] = idx
}
signupSession, err := entities.NewSignupResetSessionRigged(userEmail, kp, customerId, svgIdxInterface, reset)
if err != nil {
return nil, err
}
if err := n.SignupSessionCache.Add(signupSession.Id.String(), *signupSession, sessionExpiration); err != nil {
return nil, err
}
svgInterface, err := n.Db.GetSvgStringInterface(signupSession.LoginUserInterface.SvgId)
if err != nil {
return nil, err
}
resp := models.GenerateSignupResetInterfaceResp{
UserIdxInterface: signupSession.SetIdxInterface,
SvgInterface: svgInterface,
SessionId: uuid.UUID(signupSession.Id).String(),
Colors: signupSession.Colors,
}
return &resp, nil
}
func (n *NKodeAPI) SetNKode(customerId models.CustomerID, sessionId models.SessionId, keySelection models.KeySelection) (models.IdxInterface, error) {
_, err := n.Db.GetCustomer(customerId) _, err := n.Db.GetCustomer(customerId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -143,7 +107,7 @@ func (n *NKodeAPI) SetNKode(customerId models.CustomerID, sessionId models.Sessi
return confirmInterface, nil return confirmInterface, nil
} }
func (n *NKodeAPI) ConfirmNKode(customerId models.CustomerID, sessionId models.SessionId, keySelection models.KeySelection) error { func (n *NKodeAPI) ConfirmNKode(customerId entities.CustomerId, sessionId entities.SessionId, keySelection entities.KeySelection) error {
session, exists := n.SignupSessionCache.Get(sessionId.String()) session, exists := n.SignupSessionCache.Get(sessionId.String())
if !exists { if !exists {
log.Printf("session id does not exist %s", sessionId) log.Printf("session id does not exist %s", sessionId)
@@ -178,7 +142,7 @@ func (n *NKodeAPI) ConfirmNKode(customerId models.CustomerID, sessionId models.S
return err return err
} }
func (n *NKodeAPI) GetLoginInterface(userEmail models.UserEmail, customerId models.CustomerID) (*models.GetLoginInterfaceResp, error) { func (n *NKodeAPI) GetLoginInterface(userEmail entities.UserEmail, customerId entities.CustomerId) (*entities.LoginInterface, error) {
user, err := n.Db.GetUser(userEmail, customerId) user, err := n.Db.GetUser(userEmail, customerId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -191,17 +155,17 @@ func (n *NKodeAPI) GetLoginInterface(userEmail models.UserEmail, customerId mode
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp := models.GetLoginInterfaceResp{ resp := entities.LoginInterface{
UserIdxInterface: user.Interface.IdxInterface, UserIdxInterface: user.Interface.IdxInterface,
SvgInterface: svgInterface, SvgInterface: svgInterface,
NumbOfKeys: user.Kp.NumbOfKeys, NumbOfKeys: user.Kp.NumbOfKeys,
AttrsPerKey: user.Kp.AttrsPerKey, AttrsPerKey: user.Kp.AttrsPerKey,
Colors: models.SetColors, Colors: entities.SetColors,
} }
return &resp, nil return &resp, nil
} }
func (n *NKodeAPI) Login(customerId models.CustomerID, userEmail models.UserEmail, keySelection models.KeySelection) (*security.AuthenticationTokens, error) { func (n *NKodeAPI) Login(customerId entities.CustomerId, userEmail entities.UserEmail, keySelection entities.KeySelection) (*security.AuthenticationTokens, error) {
customer, err := n.Db.GetCustomer(customerId) customer, err := n.Db.GetCustomer(customerId)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -218,6 +182,7 @@ func (n *NKodeAPI) Login(customerId models.CustomerID, userEmail models.UserEmai
if err != nil { if err != nil {
return nil, err return nil, err
} }
if user.Renew { if user.Renew {
err = n.Db.RefreshUserPasscode(*user, passcode, customer.Attributes) err = n.Db.RefreshUserPasscode(*user, passcode, customer.Attributes)
if err != nil { if err != nil {
@@ -240,15 +205,15 @@ func (n *NKodeAPI) Login(customerId models.CustomerID, userEmail models.UserEmai
return &jwtToken, nil return &jwtToken, nil
} }
func (n *NKodeAPI) RenewAttributes(customerId models.CustomerID) error { func (n *NKodeAPI) RenewAttributes(customerId entities.CustomerId) error {
return n.Db.Renew(customerId) return n.Db.Renew(customerId)
} }
func (n *NKodeAPI) RandomSvgInterface() ([]string, error) { func (n *NKodeAPI) RandomSvgInterface() ([]string, error) {
return n.Db.RandomSvgInterface(entities.KeypadDefault) return n.Db.RandomSvgInterface(entities.KeypadMax)
} }
func (n *NKodeAPI) RefreshToken(userEmail models.UserEmail, customerId models.CustomerID, refreshToken string) (string, error) { func (n *NKodeAPI) RefreshToken(userEmail entities.UserEmail, customerId entities.CustomerId, refreshToken string) (string, error) {
user, err := n.Db.GetUser(userEmail, customerId) user, err := n.Db.GetUser(userEmail, customerId)
if err != nil { if err != nil {
return "", err return "", err
@@ -271,14 +236,16 @@ func (n *NKodeAPI) RefreshToken(userEmail models.UserEmail, customerId models.Cu
return security.EncodeAndSignClaims(newAccessClaims) return security.EncodeAndSignClaims(newAccessClaims)
} }
func (n *NKodeAPI) ResetNKode(userEmail models.UserEmail, customerId models.CustomerID) error { func (n *NKodeAPI) ResetNKode(userEmail entities.UserEmail, customerId entities.CustomerId) error {
user, err := n.Db.GetUser(userEmail, customerId) user, err := n.Db.GetUser(userEmail, customerId)
if err != nil { if err != nil {
return fmt.Errorf("error getting user in rest nkode %v", err) return fmt.Errorf("error getting user in rest nkode %v", err)
} }
if user == nil { if user == nil {
return nil return nil
} }
nkodeResetJwt, err := security.ResetNKodeToken(string(userEmail), uuid.UUID(customerId)) nkodeResetJwt, err := security.ResetNKodeToken(string(userEmail), uuid.UUID(customerId))
if err != nil { if err != nil {
return err return err
@@ -288,12 +255,12 @@ func (n *NKodeAPI) ResetNKode(userEmail models.UserEmail, customerId models.Cust
frontendHost = config.FrontendHost frontendHost = config.FrontendHost
} }
htmlBody := fmt.Sprintf("<h1>Hello!</h1><p>Click the link to reset your nKode.</p><a href=\"%s?token=%s\">Reset nKode</a>", frontendHost, nkodeResetJwt) htmlBody := fmt.Sprintf("<h1>Hello!</h1><p>Click the link to reset your nKode.</p><a href=\"%s?token=%s\">Reset nKode</a>", frontendHost, nkodeResetJwt)
emailData := email.Email{ email := email.Email{
Sender: "no-reply@nkode.tech", Sender: "no-reply@nkode.tech",
Recipient: string(userEmail), Recipient: string(userEmail),
Subject: "nKode Reset", Subject: "nKode Reset",
Content: htmlBody, Content: htmlBody,
} }
n.EmailQueue.AddEmail(emailData) n.EmailQueue.AddEmail(email)
return nil return nil
} }

View File

@@ -3,12 +3,11 @@ package api
import ( import (
"context" "context"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/internal/email" "go-nkode/pkg/nkode-core/email"
"go-nkode/internal/entities" "go-nkode/pkg/nkode-core/entities"
"go-nkode/internal/models" repository2 "go-nkode/pkg/nkode-core/repository"
"go-nkode/internal/repository" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security" sqlite_queue "go-nkode/pkg/nkode-core/sqlc"
sqlite_queue "go-nkode/internal/sqlc"
"log" "log"
"os" "os"
"testing" "testing"
@@ -23,7 +22,7 @@ func TestNKodeAPI(t *testing.T) {
sqliteDb, err := sqlite_queue.OpenSqliteDb(dbPath) sqliteDb, err := sqlite_queue.OpenSqliteDb(dbPath)
assert.NoError(t, err) assert.NoError(t, err)
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb) queue, err := sqlite_queue.NewQueue(sqliteDb, ctx)
assert.NoError(t, err) assert.NoError(t, err)
queue.Start() queue.Start()
defer func(queue *sqlite_queue.Queue) { defer func(queue *sqlite_queue.Queue) {
@@ -31,7 +30,7 @@ func TestNKodeAPI(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
}(queue) }(queue)
sqlitedb := repository.NewSqliteRepository(ctx, queue) sqlitedb := repository2.NewSqliteRepository(queue, ctx)
testNKodeAPI(t, &sqlitedb) testNKodeAPI(t, &sqlitedb)
//if _, err := os.Stat(dbPath); err == nil { //if _, err := os.Stat(dbPath); err == nil {
@@ -42,7 +41,7 @@ func TestNKodeAPI(t *testing.T) {
//} //}
} }
func testNKodeAPI(t *testing.T, db repository.CustomerUserRepository) { func testNKodeAPI(t *testing.T, db repository2.CustomerUserRepository) {
bufferSize := 100 bufferSize := 100
emailsPerSec := 14 emailsPerSec := 14
testClient := email.TestEmailClient{} testClient := email.TestEmailClient{}
@@ -52,9 +51,9 @@ func testNKodeAPI(t *testing.T, db repository.CustomerUserRepository) {
attrsPerKey := 5 attrsPerKey := 5
numbOfKeys := 4 numbOfKeys := 4
for idx := 0; idx < 1; idx++ { for idx := 0; idx < 1; idx++ {
userEmail := models.UserEmail("test_username" + security.GenerateRandomString(12) + "@example.com") userEmail := entities.UserEmail("test_username" + security.GenerateRandomString(12) + "@example.com")
passcodeLen := 4 passcodeLen := 4
nkodePolicy := models.NewDefaultNKodePolicy() nkodePolicy := entities.NewDefaultNKodePolicy()
keypadSize := entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys} keypadSize := entities.KeypadDimension{AttrsPerKey: attrsPerKey, NumbOfKeys: numbOfKeys}
nkodeApi := NewNKodeAPI(db, queue) nkodeApi := NewNKodeAPI(db, queue)
customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy, nil) customerId, err := nkodeApi.CreateNewCustomer(nkodePolicy, nil)
@@ -63,7 +62,7 @@ func testNKodeAPI(t *testing.T, db repository.CustomerUserRepository) {
assert.NoError(t, err) assert.NoError(t, err)
setInterface := signupResponse.UserIdxInterface setInterface := signupResponse.UserIdxInterface
sessionIdStr := signupResponse.SessionId sessionIdStr := signupResponse.SessionId
sessionId, err := models.SessionIdFromString(sessionIdStr) sessionId, err := entities.SessionIdFromString(sessionIdStr)
assert.NoError(t, err) assert.NoError(t, err)
keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys} keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
userPasscode := setInterface[:passcodeLen] userPasscode := setInterface[:passcodeLen]
@@ -100,7 +99,7 @@ func testNKodeAPI(t *testing.T, db repository.CustomerUserRepository) {
assert.NoError(t, err) assert.NoError(t, err)
setInterface = resetResponse.UserIdxInterface setInterface = resetResponse.UserIdxInterface
sessionIdStr = resetResponse.SessionId sessionIdStr = resetResponse.SessionId
sessionId, err = models.SessionIdFromString(sessionIdStr) sessionId, err = entities.SessionIdFromString(sessionIdStr)
assert.NoError(t, err) assert.NoError(t, err)
keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys} keypadSize = entities.KeypadDimension{AttrsPerKey: numbOfKeys, NumbOfKeys: numbOfKeys}
userPasscode = setInterface[:passcodeLen] userPasscode = setInterface[:passcodeLen]

View File

@@ -18,7 +18,6 @@ type Client interface {
SendEmail(Email) error SendEmail(Email) error
} }
// Email represents a dummy email structure
type Email struct { type Email struct {
Sender string Sender string
Recipient string Recipient string
@@ -28,9 +27,7 @@ type Email struct {
type TestEmailClient struct{} type TestEmailClient struct{}
// SendEmail simulates sending an email via AWS SES
func (c *TestEmailClient) SendEmail(email Email) error { func (c *TestEmailClient) SendEmail(email Email) error {
// Simulate sending email (replace with actual AWS SES API call)
fmt.Printf("Sending email to %s\n", email.Recipient) fmt.Printf("Sending email to %s\n", email.Recipient)
return nil return nil
} }
@@ -127,7 +124,6 @@ func NewEmailQueue(bufferSize int, emailsPerSecond int, client Client) *Queue {
} }
} }
// AddEmail queues a new email to be sent
func (q *Queue) AddEmail(email Email) { func (q *Queue) AddEmail(email Email) {
if q.stop { if q.stop {
log.Printf("email %s with subject %s not add. Stopping queue", email.Recipient, email.Subject) log.Printf("email %s with subject %s not add. Stopping queue", email.Recipient, email.Subject)
@@ -137,20 +133,17 @@ func (q *Queue) AddEmail(email Email) {
q.emailQueue <- email q.emailQueue <- email
} }
// Start begins processing the email queue with rate limiting
func (q *Queue) Start() { func (q *Queue) Start() {
q.stop = false q.stop = false
// Worker goroutine that processes emails from the queue
go func() { go func() {
for email := range q.emailQueue { for email := range q.emailQueue {
<-q.rateLimit // Wait for the rate limiter to allow the next email <-q.rateLimit
q.sendEmail(email) q.sendEmail(email)
q.wg.Done() // Mark the email as processed q.wg.Done()
} }
}() }()
} }
// sendEmail sends an email using the SES client
func (q *Queue) sendEmail(email Email) { func (q *Queue) sendEmail(email Email) {
if err := q.client.SendEmail(email); err != nil { if err := q.client.SendEmail(email); err != nil {
q.FailedSendCount += 1 q.FailedSendCount += 1
@@ -158,11 +151,8 @@ func (q *Queue) sendEmail(email Email) {
} }
} }
// Stop stops the queue after all emails have been processed
func (q *Queue) Stop() { func (q *Queue) Stop() {
q.stop = true q.stop = true
// Wait for all emails to be processed
q.wg.Wait() q.wg.Wait()
// Stop the email queue
close(q.emailQueue) close(q.emailQueue)
} }

View File

@@ -4,25 +4,24 @@ import (
"github.com/DonovanKelly/sugar-n-spice/set" "github.com/DonovanKelly/sugar-n-spice/set"
"github.com/google/uuid" "github.com/google/uuid"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security" "go-nkode/pkg/nkode-core/sqlc"
"go-nkode/internal/sqlc" "go-nkode/pkg/nkode-core/utils"
"go-nkode/internal/utils"
) )
type Customer struct { type Customer struct {
ID models.CustomerID Id CustomerId
NKodePolicy models.NKodePolicy NKodePolicy NKodePolicy
Attributes CustomerAttributes Attributes CustomerAttributes
} }
func NewCustomer(nkodePolicy models.NKodePolicy) (*Customer, error) { func NewCustomer(nkodePolicy NKodePolicy) (*Customer, error) {
customerAttrs, err := NewCustomerAttributes() customerAttrs, err := NewCustomerAttributes()
if err != nil { if err != nil {
return nil, err return nil, err
} }
customer := Customer{ customer := Customer{
ID: models.CustomerID(uuid.New()), Id: CustomerId(uuid.New()),
NKodePolicy: nkodePolicy, NKodePolicy: nkodePolicy,
Attributes: *customerAttrs, Attributes: *customerAttrs,
} }
@@ -88,7 +87,7 @@ func (c *Customer) RenewKeys() ([]uint64, []uint64, error) {
func (c *Customer) ToSqlcCreateCustomerParams() sqlc.CreateCustomerParams { func (c *Customer) ToSqlcCreateCustomerParams() sqlc.CreateCustomerParams {
return sqlc.CreateCustomerParams{ return sqlc.CreateCustomerParams{
ID: uuid.UUID(c.ID).String(), ID: uuid.UUID(c.Id).String(),
MaxNkodeLen: int64(c.NKodePolicy.MaxNkodeLen), MaxNkodeLen: int64(c.NKodePolicy.MaxNkodeLen),
MinNkodeLen: int64(c.NKodePolicy.MinNkodeLen), MinNkodeLen: int64(c.NKodePolicy.MinNkodeLen),
DistinctSets: int64(c.NKodePolicy.DistinctSets), DistinctSets: int64(c.NKodePolicy.DistinctSets),

View File

@@ -1,7 +1,7 @@
package entities package entities
import ( import (
"go-nkode/internal/security" "go-nkode/pkg/nkode-core/security"
"log" "log"
) )

View File

@@ -2,7 +2,6 @@ package entities
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/internal/models"
"testing" "testing"
) )
@@ -19,10 +18,10 @@ func testNewCustomerAttributes(t *testing.T) {
func testCustomerValidKeyEntry(t *testing.T) { func testCustomerValidKeyEntry(t *testing.T) {
kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 9} kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 9}
nkodePolicy := models.NewDefaultNKodePolicy() nkodePolicy := NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy) customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface) userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err) assert.NoError(t, err)
userEmail := "testing@example.com" userEmail := "testing@example.com"
@@ -43,10 +42,10 @@ func testCustomerValidKeyEntry(t *testing.T) {
func testCustomerIsValidNKode(t *testing.T) { func testCustomerIsValidNKode(t *testing.T) {
kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 7} kp := KeypadDimension{AttrsPerKey: 10, NumbOfKeys: 7}
nkodePolicy := models.NewDefaultNKodePolicy() nkodePolicy := NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy) customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface) userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err) assert.NoError(t, err)
userEmail := "testing123@example.com" userEmail := "testing123@example.com"

View File

@@ -3,7 +3,7 @@ package entities
import ( import (
"errors" "errors"
"fmt" "fmt"
"go-nkode/internal/security" "go-nkode/pkg/nkode-core/security"
) )
func SelectKeyByAttrIdx(interfaceUser []int, passcodeIdxs []int, keypadSize KeypadDimension) ([]int, error) { func SelectKeyByAttrIdx(interfaceUser []int, passcodeIdxs []int, keypadSize KeypadDimension) ([]int, error) {

View File

@@ -0,0 +1,101 @@
package entities
import (
"fmt"
"github.com/google/uuid"
"net/mail"
"strings"
)
type KeySelection []int
type CustomerId uuid.UUID
func CustomerIdToString(customerId CustomerId) string {
customerUuid := uuid.UUID(customerId)
return customerUuid.String()
}
type SessionId uuid.UUID
type UserId uuid.UUID
func UserIdFromString(userId string) UserId {
id, err := uuid.Parse(userId)
if err != nil {
fmt.Errorf("unable to parse user id %+v", err)
}
return UserId(id)
}
func (s *SessionId) String() string {
id := uuid.UUID(*s)
return id.String()
}
type UserEmail string
func ParseEmail(email string) (UserEmail, error) {
_, err := mail.ParseAddress(email)
if err != nil {
return "", err
}
return UserEmail(strings.ToLower(email)), err
}
type IdxInterface []int
type SvgIdInterface []int
func SessionIdFromString(sessionId string) (SessionId, error) {
id, err := uuid.Parse(sessionId)
if err != nil {
return SessionId{}, err
}
return SessionId(id), nil
}
type EncipheredNKode struct {
Code string
Mask string
}
type RGBColor struct {
Red int `json:"red"`
Green int `json:"green"`
Blue int `json:"blue"`
}
var SetColors = []RGBColor{
{0, 0, 0}, // Black
{255, 0, 0}, // Red
{0, 128, 0}, // Dark Green
{0, 0, 255}, // Blue
{244, 200, 60}, // Yellow
{255, 0, 255}, // Magenta
{0, 200, 200}, // Cyan
{127, 0, 127}, // Purple
{232, 92, 13}, // Orange
{0, 127, 127}, // Teal
{127, 127, 0}, // Olive
{127, 0, 0}, // Dark Red
{128, 128, 128}, // Gray
{228, 102, 102}, // Dark Purple
{185, 17, 240}, // Salmon
{16, 200, 100}, // Green
}
type SignupResetInterface struct {
SessionId string `json:"session_id"`
UserIdxInterface IdxInterface `json:"user_interface"`
SvgInterface []string `json:"svg_interface"`
Colors []RGBColor `json:"colors"`
}
type LoginInterface struct {
UserIdxInterface IdxInterface `json:"user_interface"`
SvgInterface []string `json:"svg_interface"`
AttrsPerKey int `json:"attrs_per_key"`
NumbOfKeys int `json:"numb_of_keys"`
Colors []RGBColor `json:"colors"`
}

View File

@@ -1,4 +1,4 @@
package models package entities
import "go-nkode/config" import "go-nkode/config"

View File

@@ -3,16 +3,15 @@ package entities
import ( import (
"github.com/google/uuid" "github.com/google/uuid"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security"
"log" "log"
) )
type User struct { type User struct {
Id models.UserId Id UserId
CustomerId models.CustomerID CustomerId CustomerId
Email models.UserEmail Email UserEmail
EncipheredPasscode models.EncipheredNKode EncipheredPasscode EncipheredNKode
Kp KeypadDimension Kp KeypadDimension
CipherKeys UserCipherKeys CipherKeys UserCipherKeys
Interface UserInterface Interface UserInterface
@@ -114,7 +113,7 @@ func ValidKeyEntry(user User, customer Customer, selectedKeys []int) ([]int, err
} }
func NewUser(customer Customer, userEmail string, passcodeIdx []int, ui UserInterface, kp KeypadDimension) (*User, error) { func NewUser(customer Customer, userEmail string, passcodeIdx []int, ui UserInterface, kp KeypadDimension) (*User, error) {
_, err := models.ParseEmail(userEmail) _, err := ParseEmail(userEmail)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -131,13 +130,13 @@ func NewUser(customer Customer, userEmail string, passcodeIdx []int, ui UserInte
return nil, err return nil, err
} }
newUser := User{ newUser := User{
Id: models.UserId(uuid.New()), Id: UserId(uuid.New()),
Email: models.UserEmail(userEmail), Email: UserEmail(userEmail),
EncipheredPasscode: *encipheredNKode, EncipheredPasscode: *encipheredNKode,
CipherKeys: *newKeys, CipherKeys: *newKeys,
Interface: ui, Interface: ui,
Kp: kp, Kp: kp,
CustomerId: customer.ID, CustomerId: customer.Id,
} }
return &newUser, nil return &newUser, nil
} }

View File

@@ -4,8 +4,7 @@ import (
"crypto/sha256" "crypto/sha256"
"errors" "errors"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -167,7 +166,7 @@ func (u *UserCipherKeys) DecipherMask(mask string, setVals []uint64, passcodeLen
return passcodeSet, nil return passcodeSet, nil
} }
func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*models.EncipheredNKode, error) { func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*EncipheredNKode, error) {
attrVals, err := customerAttrs.AttrValsForKp(*u.Kp) attrVals, err := customerAttrs.AttrValsForKp(*u.Kp)
code, err := u.EncipherSaltHashCode(passcodeAttrIdx, attrVals) code, err := u.EncipherSaltHashCode(passcodeAttrIdx, attrVals)
if err != nil { if err != nil {
@@ -186,7 +185,7 @@ func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs Cust
if err != nil { if err != nil {
return nil, err return nil, err
} }
encipheredCode := models.EncipheredNKode{ encipheredCode := EncipheredNKode{
Code: code, Code: code,
Mask: mask, Mask: mask,
} }

View File

@@ -3,18 +3,17 @@ package entities
import ( import (
"github.com/DonovanKelly/sugar-n-spice/set" "github.com/DonovanKelly/sugar-n-spice/set"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security"
"log" "log"
) )
type UserInterface struct { type UserInterface struct {
IdxInterface models.IdxInterface IdxInterface IdxInterface
SvgId models.SvgIdInterface SvgId SvgIdInterface
Kp *KeypadDimension Kp *KeypadDimension
} }
func NewUserInterface(kp *KeypadDimension, svgId models.SvgIdInterface) (*UserInterface, error) { func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) {
idxInterface := security.IdentityArray(kp.TotalAttrs()) idxInterface := security.IdentityArray(kp.TotalAttrs())
userInterface := UserInterface{ userInterface := UserInterface{
IdxInterface: idxInterface, IdxInterface: idxInterface,

View File

@@ -5,51 +5,26 @@ import (
"github.com/DonovanKelly/sugar-n-spice/set" "github.com/DonovanKelly/sugar-n-spice/set"
"github.com/google/uuid" "github.com/google/uuid"
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security"
"log" "log"
"sort" "sort"
) )
type UserSignSession struct { type UserSignSession struct {
Id models.SessionId Id SessionId
CustomerId models.CustomerID CustomerId CustomerId
LoginUserInterface UserInterface LoginUserInterface UserInterface
Kp KeypadDimension Kp KeypadDimension
SetIdxInterface models.IdxInterface SetIdxInterface IdxInterface
ConfirmIdxInterface models.IdxInterface ConfirmIdxInterface IdxInterface
SetKeySelection models.KeySelection SetKeySelection KeySelection
UserEmail models.UserEmail UserEmail UserEmail
Reset bool Reset bool
Expire int Expire int
Colors []models.RGBColor Colors []RGBColor
} }
func NewSignupResetSessionRigged(userEmail models.UserEmail, kp KeypadDimension, customerId models.CustomerID, svgInterface models.SvgIdInterface, reset bool) (*UserSignSession, error) { func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) {
loginInterface, err := NewUserInterface(&kp, svgInterface)
if err != nil {
return nil, err
}
setIdxInterface := make(models.IdxInterface, 36)
for idx := range 36 {
setIdxInterface[idx] = idx
}
session := UserSignSession{
Id: models.SessionId(uuid.New()),
CustomerId: customerId,
LoginUserInterface: *loginInterface,
SetIdxInterface: setIdxInterface,
ConfirmIdxInterface: nil,
SetKeySelection: nil,
UserEmail: userEmail,
Kp: kp,
Reset: reset,
Colors: []models.RGBColor{},
}
return &session, nil
}
func NewSignupResetSession(userEmail models.UserEmail, kp KeypadDimension, customerId models.CustomerID, svgInterface models.SvgIdInterface, reset bool) (*UserSignSession, error) {
loginInterface, err := NewUserInterface(&kp, svgInterface) loginInterface, err := NewUserInterface(&kp, svgInterface)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -59,7 +34,7 @@ func NewSignupResetSession(userEmail models.UserEmail, kp KeypadDimension, custo
return nil, err return nil, err
} }
session := UserSignSession{ session := UserSignSession{
Id: models.SessionId(uuid.New()), Id: SessionId(uuid.New()),
CustomerId: customerId, CustomerId: customerId,
LoginUserInterface: *loginInterface, LoginUserInterface: *loginInterface,
SetIdxInterface: signupInterface.IdxInterface, SetIdxInterface: signupInterface.IdxInterface,
@@ -70,10 +45,11 @@ func NewSignupResetSession(userEmail models.UserEmail, kp KeypadDimension, custo
Reset: reset, Reset: reset,
Colors: colors, Colors: colors,
} }
return &session, nil return &session, nil
} }
func (s *UserSignSession) DeducePasscode(confirmKeyEntry models.KeySelection) ([]int, error) { func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, error) {
validEntry := all.All[int](confirmKeyEntry, func(i int) bool { validEntry := all.All[int](confirmKeyEntry, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys return 0 <= i && i < s.Kp.NumbOfKeys
}) })
@@ -134,7 +110,7 @@ func (s *UserSignSession) DeducePasscode(confirmKeyEntry models.KeySelection) ([
return passcode, nil return passcode, nil
} }
func (s *UserSignSession) SetUserNKode(keySelection models.KeySelection) (models.IdxInterface, error) { func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface, error) {
validKeySelection := all.All[int](keySelection, func(i int) bool { validKeySelection := all.All[int](keySelection, func(i int) bool {
return 0 <= i && i < s.Kp.NumbOfKeys return 0 <= i && i < s.Kp.NumbOfKeys
}) })
@@ -154,7 +130,7 @@ func (s *UserSignSession) SetUserNKode(keySelection models.KeySelection) (models
return s.ConfirmIdxInterface, nil return s.ConfirmIdxInterface, nil
} }
func (s *UserSignSession) getSelectedKeyVals(keySelections models.KeySelection, userInterface []int) ([][]int, error) { func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInterface []int) ([][]int, error) {
signupKp := s.SignupKeypad() signupKp := s.SignupKeypad()
keypadInterface, err := security.ListToMatrix(userInterface, signupKp.AttrsPerKey) keypadInterface, err := security.ListToMatrix(userInterface, signupKp.AttrsPerKey)
if err != nil { if err != nil {
@@ -168,7 +144,7 @@ func (s *UserSignSession) getSelectedKeyVals(keySelections models.KeySelection,
return keyVals, nil return keyVals, nil
} }
func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []models.RGBColor, error) { func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []RGBColor, error) {
// This method randomly drops sets from the base user interface so it is a square and dispersable matrix // This method randomly drops sets from the base user interface so it is a square and dispersable matrix
if kp.IsDispersable() { if kp.IsDispersable() {
return nil, nil, config.ErrKeypadIsNotDispersible return nil, nil, config.ErrKeypadIsNotDispersible
@@ -195,11 +171,11 @@ func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*User
setIdxs = setIdxs[:kp.NumbOfKeys] setIdxs = setIdxs[:kp.NumbOfKeys]
sort.Ints(setIdxs) sort.Ints(setIdxs)
selectedSets := make([][]int, kp.NumbOfKeys) selectedSets := make([][]int, kp.NumbOfKeys)
selectedColors := make([]models.RGBColor, kp.NumbOfKeys) selectedColors := make([]RGBColor, kp.NumbOfKeys)
for idx, setIdx := range setIdxs { for idx, setIdx := range setIdxs {
selectedSets[idx] = attrSetView[setIdx] selectedSets[idx] = attrSetView[setIdx]
selectedColors[idx] = models.SetColors[setIdx] selectedColors[idx] = SetColors[setIdx]
} }
// convert set view back into key view // convert set view back into key view
selectedSets, err = security.MatrixTranspose(selectedSets) selectedSets, err = security.MatrixTranspose(selectedSets)

View File

@@ -3,7 +3,6 @@ package entities
import ( import (
"github.com/DonovanKelly/sugar-n-spice/all" "github.com/DonovanKelly/sugar-n-spice/all"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/internal/models"
"testing" "testing"
) )
@@ -65,7 +64,7 @@ func TestUserInterface_RandomShuffle(t *testing.T) {
AttrsPerKey: 10, AttrsPerKey: 10,
NumbOfKeys: 8, NumbOfKeys: 8,
} }
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface) userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err) assert.NoError(t, err)
userInterfaceCopy := make([]int, len(userInterface.IdxInterface)) userInterfaceCopy := make([]int, len(userInterface.IdxInterface))
@@ -88,7 +87,7 @@ func TestUserInterface_DisperseInterface(t *testing.T) {
for idx := 0; idx < 10000; idx++ { for idx := 0; idx < 10000; idx++ {
kp := KeypadDimension{AttrsPerKey: 7, NumbOfKeys: 10} kp := KeypadDimension{AttrsPerKey: 7, NumbOfKeys: 10}
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface) userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err) assert.NoError(t, err)
preDispersion, err := userInterface.AttributeAdjacencyGraph() preDispersion, err := userInterface.AttributeAdjacencyGraph()
@@ -107,7 +106,7 @@ func TestUserInterface_DisperseInterface(t *testing.T) {
func TestUserInterface_PartialInterfaceShuffle(t *testing.T) { func TestUserInterface_PartialInterfaceShuffle(t *testing.T) {
kp := KeypadDimension{AttrsPerKey: 7, NumbOfKeys: 10} kp := KeypadDimension{AttrsPerKey: 7, NumbOfKeys: 10}
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs())
userInterface, err := NewUserInterface(&kp, mockSvgInterface) userInterface, err := NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err) assert.NoError(t, err)
preShuffle := userInterface.IdxInterface preShuffle := userInterface.IdxInterface

View File

@@ -0,0 +1,20 @@
package repository
import (
"go-nkode/pkg/nkode-core/entities"
)
type CustomerUserRepository interface {
GetCustomer(entities.CustomerId) (*entities.Customer, error)
GetUser(entities.UserEmail, entities.CustomerId) (*entities.User, error)
CreateCustomer(entities.Customer) error
WriteNewUser(entities.User) error
UpdateUserNKode(entities.User) error
UpdateUserInterface(entities.UserId, entities.UserInterface) error
UpdateUserRefreshToken(entities.UserId, string) error
Renew(entities.CustomerId) error
RefreshUserPasscode(entities.User, []int, entities.CustomerAttributes) error
RandomSvgInterface(entities.KeypadDimension) ([]string, error)
RandomSvgIdxInterface(entities.KeypadDimension) (entities.SvgIdInterface, error)
GetSvgStringInterface(entities.SvgIdInterface) ([]string, error)
}

View File

@@ -3,33 +3,32 @@ package repository
import ( import (
"errors" "errors"
"fmt" "fmt"
"go-nkode/internal/entities" "go-nkode/pkg/nkode-core/entities"
"go-nkode/internal/models"
) )
type InMemoryDb struct { type InMemoryDb struct {
Customers map[models.CustomerID]entities.Customer Customers map[entities.CustomerId]entities.Customer
Users map[models.UserId]entities.User Users map[entities.UserId]entities.User
userIdMap map[string]models.UserId userIdMap map[string]entities.UserId
} }
func NewInMemoryDb() InMemoryDb { func NewInMemoryDb() InMemoryDb {
return InMemoryDb{ return InMemoryDb{
Customers: make(map[models.CustomerID]entities.Customer), Customers: make(map[entities.CustomerId]entities.Customer),
Users: make(map[models.UserId]entities.User), Users: make(map[entities.UserId]entities.User),
userIdMap: make(map[string]models.UserId), userIdMap: make(map[string]entities.UserId),
} }
} }
func (db *InMemoryDb) GetCustomer(id models.CustomerID) (*entities.Customer, error) { func (db *InMemoryDb) GetCustomer(id entities.CustomerId) (*entities.Customer, error) {
customer, exists := db.Customers[id] customer, exists := db.Customers[id]
if !exists { if !exists {
return nil, errors.New(fmt.Sprintf("customer %s dne", customer.ID)) return nil, errors.New(fmt.Sprintf("customer %s dne", customer.Id))
} }
return &customer, nil return &customer, nil
} }
func (db *InMemoryDb) GetUser(username models.UserEmail, customerId models.CustomerID) (*entities.User, error) { func (db *InMemoryDb) GetUser(username entities.UserEmail, customerId entities.CustomerId) (*entities.User, error) {
key := userIdKey(customerId, username) key := userIdKey(customerId, username)
userId, exists := db.userIdMap[key] userId, exists := db.userIdMap[key]
if !exists { if !exists {
@@ -43,12 +42,12 @@ func (db *InMemoryDb) GetUser(username models.UserEmail, customerId models.Custo
} }
func (db *InMemoryDb) CreateCustomer(customer entities.Customer) error { func (db *InMemoryDb) CreateCustomer(customer entities.Customer) error {
_, exists := db.Customers[customer.ID] _, exists := db.Customers[customer.Id]
if exists { if exists {
return errors.New(fmt.Sprintf("can write customer %s; already exists", customer.ID)) return errors.New(fmt.Sprintf("can write customer %s; already exists", customer.Id))
} }
db.Customers[customer.ID] = customer db.Customers[customer.Id] = customer
return nil return nil
} }
@@ -72,7 +71,7 @@ func (db *InMemoryDb) UpdateUserNKode(user entities.User) error {
return errors.ErrUnsupported return errors.ErrUnsupported
} }
func (db *InMemoryDb) UpdateUserInterface(userId models.UserId, ui entities.UserInterface) error { func (db *InMemoryDb) UpdateUserInterface(userId entities.UserId, ui entities.UserInterface) error {
user, exists := db.Users[userId] user, exists := db.Users[userId]
if !exists { if !exists {
return errors.New(fmt.Sprintf("can't update user %s, dne", user.Id)) return errors.New(fmt.Sprintf("can't update user %s, dne", user.Id))
@@ -82,11 +81,11 @@ func (db *InMemoryDb) UpdateUserInterface(userId models.UserId, ui entities.User
return nil return nil
} }
func (db *InMemoryDb) UpdateUserRefreshToken(userId models.UserId, refreshToken string) error { func (db *InMemoryDb) UpdateUserRefreshToken(userId entities.UserId, refreshToken string) error {
return nil return nil
} }
func (db *InMemoryDb) Renew(id models.CustomerID) error { func (db *InMemoryDb) Renew(id entities.CustomerId) error {
customer, exists := db.Customers[id] customer, exists := db.Customers[id]
if !exists { if !exists {
return errors.New(fmt.Sprintf("customer %s does not exist", id)) return errors.New(fmt.Sprintf("customer %s does not exist", id))
@@ -121,19 +120,19 @@ func (db *InMemoryDb) RandomSvgInterface(kp entities.KeypadDimension) ([]string,
return make([]string, kp.TotalAttrs()), nil return make([]string, kp.TotalAttrs()), nil
} }
func (db *InMemoryDb) RandomSvgIdxInterface(kp entities.KeypadDimension) (models.SvgIdInterface, error) { func (db *InMemoryDb) RandomSvgIdxInterface(kp entities.KeypadDimension) (entities.SvgIdInterface, error) {
svgs := make(models.SvgIdInterface, kp.TotalAttrs()) svgs := make(entities.SvgIdInterface, kp.TotalAttrs())
for idx := range svgs { for idx := range svgs {
svgs[idx] = idx svgs[idx] = idx
} }
return svgs, nil return svgs, nil
} }
func (db *InMemoryDb) GetSvgStringInterface(idxs models.SvgIdInterface) ([]string, error) { func (db *InMemoryDb) GetSvgStringInterface(idxs entities.SvgIdInterface) ([]string, error) {
return make([]string, len(idxs)), nil return make([]string, len(idxs)), nil
} }
func userIdKey(customerId models.CustomerID, username models.UserEmail) string { func userIdKey(customerId entities.CustomerId, username entities.UserEmail) string {
key := fmt.Sprintf("%s:%s", customerId, username) key := fmt.Sprintf("%s:%s", customerId, username)
return key return key
} }

View File

@@ -26,7 +26,7 @@ type Root struct {
func main() { func main() {
testDbPath := os.Getenv("TEST_DB_PATH") testDbPath := os.Getenv("TEST_DB_PATH")
dbPath := os.Getenv("SQLITE_PATH") dbPath := os.Getenv("DB_PATH")
dbPaths := []string{testDbPath, dbPath} dbPaths := []string{testDbPath, dbPath}
flaticonSvgDir := os.Getenv("SVG_DIR") flaticonSvgDir := os.Getenv("SVG_DIR")
//dbPath := "/Users/donov/Desktop/nkode.db" //dbPath := "/Users/donov/Desktop/nkode.db"

View File

@@ -8,20 +8,19 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
_ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver _ "github.com/mattn/go-sqlite3" // Import the SQLite3 driver
"go-nkode/config" "go-nkode/config"
"go-nkode/internal/entities" "go-nkode/pkg/nkode-core/entities"
"go-nkode/internal/models" "go-nkode/pkg/nkode-core/security"
"go-nkode/internal/security" sqlc2 "go-nkode/pkg/nkode-core/sqlc"
"go-nkode/internal/sqlc" "go-nkode/pkg/nkode-core/utils"
"go-nkode/internal/utils"
"log" "log"
) )
type SqliteRepository struct { type SqliteRepository struct {
Queue *sqlc.Queue Queue *sqlc2.Queue
ctx context.Context ctx context.Context
} }
func NewSqliteRepository(ctx context.Context, queue *sqlc.Queue) SqliteRepository { func NewSqliteRepository(queue *sqlc2.Queue, ctx context.Context) SqliteRepository {
return SqliteRepository{ return SqliteRepository{
Queue: queue, Queue: queue,
ctx: ctx, ctx: ctx,
@@ -29,33 +28,33 @@ func NewSqliteRepository(ctx context.Context, queue *sqlc.Queue) SqliteRepositor
} }
func (d *SqliteRepository) CreateCustomer(c entities.Customer) error { func (d *SqliteRepository) CreateCustomer(c entities.Customer) error {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.CreateCustomerParams) params, ok := args.(sqlc2.CreateCustomerParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected CreateCustomerParams") return fmt.Errorf("invalid argument type: expected CreateCustomerParams")
} }
return nil, q.CreateCustomer(ctx, params) return q.CreateCustomer(ctx, params)
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, c.ToSqlcCreateCustomerParams()) return d.Queue.EnqueueWriteTx(queryFunc, c.ToSqlcCreateCustomerParams())
return err
} }
func (d *SqliteRepository) WriteNewUser(u entities.User) error { func (d *SqliteRepository) WriteNewUser(u entities.User) error {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.CreateUserParams) params, ok := args.(sqlc2.CreateUserParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected CreateUserParams") return fmt.Errorf("invalid argument type: expected CreateUserParams")
} }
return nil, q.CreateUser(ctx, params) return q.CreateUser(ctx, params)
} }
// Use the wrapped function in EnqueueWriteTx // Use the wrapped function in EnqueueWriteTx
renew := 0 renew := 0
if u.Renew { if u.Renew {
renew = 1 renew = 1
} }
// Map entities.User to CreateUserParams // Map entities.User to CreateUserParams
params := sqlc.CreateUserParams{ params := sqlc2.CreateUserParams{
ID: uuid.UUID(u.Id).String(), ID: uuid.UUID(u.Id).String(),
Email: string(u.Email), Email: string(u.Email),
Renew: int64(renew), Renew: int64(renew),
@@ -75,24 +74,23 @@ func (d *SqliteRepository) WriteNewUser(u entities.User) error {
SvgIDInterface: security.IntArrToByteArr(u.Interface.SvgId), SvgIDInterface: security.IntArrToByteArr(u.Interface.SvgId),
CreatedAt: sql.NullString{String: utils.TimeStamp(), Valid: true}, CreatedAt: sql.NullString{String: utils.TimeStamp(), Valid: true},
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, params) return d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) UpdateUserNKode(u entities.User) error { func (d *SqliteRepository) UpdateUserNKode(u entities.User) error {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.UpdateUserParams) params, ok := args.(sqlc2.UpdateUserParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected UpdateUserParams") return fmt.Errorf("invalid argument type: expected UpdateUserParams")
} }
return nil, q.UpdateUser(ctx, params) return q.UpdateUser(ctx, params)
} }
// Use the wrapped function in EnqueueWriteTx // Use the wrapped function in EnqueueWriteTx
renew := 0 renew := 0
if u.Renew { if u.Renew {
renew = 1 renew = 1
} }
params := sqlc.UpdateUserParams{ params := sqlc2.UpdateUserParams{
Email: string(u.Email), Email: string(u.Email),
Renew: int64(renew), Renew: int64(renew),
RefreshToken: sql.NullString{String: u.RefreshToken, Valid: u.RefreshToken != ""}, RefreshToken: sql.NullString{String: u.RefreshToken, Valid: u.RefreshToken != ""},
@@ -110,81 +108,80 @@ func (d *SqliteRepository) UpdateUserNKode(u entities.User) error {
IdxInterface: security.IntArrToByteArr(u.Interface.IdxInterface), IdxInterface: security.IntArrToByteArr(u.Interface.IdxInterface),
SvgIDInterface: security.IntArrToByteArr(u.Interface.SvgId), SvgIDInterface: security.IntArrToByteArr(u.Interface.SvgId),
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, params) return d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) UpdateUserInterface(id models.UserId, ui entities.UserInterface) error { func (d *SqliteRepository) UpdateUserInterface(id entities.UserId, ui entities.UserInterface) error {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.UpdateUserInterfaceParams) params, ok := args.(sqlc2.UpdateUserInterfaceParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected UpdateUserInterfaceParams") return fmt.Errorf("invalid argument type: expected UpdateUserInterfaceParams")
} }
return nil, q.UpdateUserInterface(ctx, params) return q.UpdateUserInterface(ctx, params)
} }
params := sqlc.UpdateUserInterfaceParams{ params := sqlc2.UpdateUserInterfaceParams{
IdxInterface: security.IntArrToByteArr(ui.IdxInterface), IdxInterface: security.IntArrToByteArr(ui.IdxInterface),
LastLogin: utils.TimeStamp(), LastLogin: utils.TimeStamp(),
ID: uuid.UUID(id).String(), ID: uuid.UUID(id).String(),
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, params)
return err return d.Queue.EnqueueWriteTx(queryFunc, params)
} }
func (d *SqliteRepository) UpdateUserRefreshToken(id models.UserId, refreshToken string) error { func (d *SqliteRepository) UpdateUserRefreshToken(id entities.UserId, refreshToken string) error {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.UpdateUserRefreshTokenParams) params, ok := args.(sqlc2.UpdateUserRefreshTokenParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected UpdateUserRefreshToken") return fmt.Errorf("invalid argument type: expected UpdateUserRefreshToken")
} }
return nil, q.UpdateUserRefreshToken(ctx, params) return q.UpdateUserRefreshToken(ctx, params)
} }
params := sqlc.UpdateUserRefreshTokenParams{ params := sqlc2.UpdateUserRefreshTokenParams{
RefreshToken: sql.NullString{ RefreshToken: sql.NullString{
String: refreshToken, String: refreshToken,
Valid: true, Valid: true,
}, },
ID: uuid.UUID(id).String(), ID: uuid.UUID(id).String(),
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, params) return d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) RenewCustomer(renewParams sqlc.RenewCustomerParams) error { func (d *SqliteRepository) RenewCustomer(renewParams sqlc2.RenewCustomerParams) error {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.RenewCustomerParams) params, ok := args.(sqlc2.RenewCustomerParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected RenewCustomerParams")
} }
return nil, q.RenewCustomer(ctx, params) return q.RenewCustomer(ctx, params)
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, renewParams) return d.Queue.EnqueueWriteTx(queryFunc, renewParams)
return err
} }
func (d *SqliteRepository) Renew(id models.CustomerID) error { func (d *SqliteRepository) Renew(id entities.CustomerId) error {
setXor, attrXor, err := d.renewCustomer(id) setXor, attrXor, err := d.renewCustomer(id)
if err != nil { if err != nil {
return err return err
} }
customerId := models.CustomerIdToString(id) customerId := entities.CustomerIdToString(id)
userRenewRows, err := d.Queue.Queries.GetUserRenew(d.ctx, customerId) userRenewRows, err := d.Queue.Queries.GetUserRenew(d.ctx, customerId)
if err != nil { if err != nil {
return err return err
} }
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc.RenewUserParams) queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc2.RenewUserParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected RenewUserParams") return fmt.Errorf("invalid argument type: expected RenewUserParams")
} }
return nil, q.RenewUser(ctx, params) return q.RenewUser(ctx, params)
} }
for _, row := range userRenewRows { for _, row := range userRenewRows {
user := entities.User{ user := entities.User{
Id: models.UserIdFromString(row.ID), Id: entities.UserIdFromString(row.ID),
CustomerId: models.CustomerID{}, CustomerId: entities.CustomerId{},
Email: "", Email: "",
EncipheredPasscode: models.EncipheredNKode{}, EncipheredPasscode: entities.EncipheredNKode{},
Kp: entities.KeypadDimension{ Kp: entities.KeypadDimension{
AttrsPerKey: int(row.AttributesPerKey), AttrsPerKey: int(row.AttributesPerKey),
NumbOfKeys: int(row.NumberOfKeys), NumbOfKeys: int(row.NumberOfKeys),
@@ -196,23 +193,24 @@ func (d *SqliteRepository) Renew(id models.CustomerID) error {
Interface: entities.UserInterface{}, Interface: entities.UserInterface{},
Renew: false, Renew: false,
} }
if err = user.RenewKeys(setXor, attrXor); err != nil { if err = user.RenewKeys(setXor, attrXor); err != nil {
return err return err
} }
params := sqlc.RenewUserParams{ params := sqlc2.RenewUserParams{
AlphaKey: security.Uint64ArrToByteArr(user.CipherKeys.AlphaKey), AlphaKey: security.Uint64ArrToByteArr(user.CipherKeys.AlphaKey),
SetKey: security.Uint64ArrToByteArr(user.CipherKeys.SetKey), SetKey: security.Uint64ArrToByteArr(user.CipherKeys.SetKey),
Renew: 1, Renew: 1,
ID: uuid.UUID(user.Id).String(), ID: uuid.UUID(user.Id).String(),
} }
if _, err = d.Queue.EnqueueWriteTx(queryFunc, params); err != nil { if err = d.Queue.EnqueueWriteTx(queryFunc, params); err != nil {
return err return err
} }
} }
return nil return nil
} }
func (d *SqliteRepository) renewCustomer(id models.CustomerID) ([]uint64, []uint64, error) { func (d *SqliteRepository) renewCustomer(id entities.CustomerId) ([]uint64, []uint64, error) {
customer, err := d.GetCustomer(id) customer, err := d.GetCustomer(id)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@@ -221,19 +219,21 @@ func (d *SqliteRepository) renewCustomer(id models.CustomerID) ([]uint64, []uint
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc.RenewCustomerParams) queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc2.RenewCustomerParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected RenewCustomerParams") return fmt.Errorf("invalid argument type: expected RenewCustomerParams")
} }
return nil, q.RenewCustomer(ctx, params) return q.RenewCustomer(ctx, params)
} }
params := sqlc.RenewCustomerParams{ params := sqlc2.RenewCustomerParams{
AttributeValues: security.Uint64ArrToByteArr(customer.Attributes.AttrVals), AttributeValues: security.Uint64ArrToByteArr(customer.Attributes.AttrVals),
SetValues: security.Uint64ArrToByteArr(customer.Attributes.SetVals), SetValues: security.Uint64ArrToByteArr(customer.Attributes.SetVals),
ID: uuid.UUID(customer.ID).String(), ID: uuid.UUID(customer.Id).String(),
} }
if _, err = d.Queue.EnqueueWriteTx(queryFunc, params); err != nil {
if err = d.Queue.EnqueueWriteTx(queryFunc, params); err != nil {
return nil, nil, err return nil, nil, err
} }
return setXor, attrXor, nil return setXor, attrXor, nil
@@ -243,14 +243,14 @@ func (d *SqliteRepository) RefreshUserPasscode(user entities.User, passcodeIdx [
if err := user.RefreshPasscode(passcodeIdx, customerAttr); err != nil { if err := user.RefreshPasscode(passcodeIdx, customerAttr); err != nil {
return err return err
} }
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) { queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error {
params, ok := args.(sqlc.RefreshUserPasscodeParams) params, ok := args.(sqlc2.RefreshUserPasscodeParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected RefreshUserPasscodeParams") return fmt.Errorf("invalid argument type: expected RefreshUserPasscodeParams")
} }
return nil, q.RefreshUserPasscode(ctx, params) return q.RefreshUserPasscode(ctx, params)
} }
params := sqlc.RefreshUserPasscodeParams{ params := sqlc2.RefreshUserPasscodeParams{
Renew: 0, Renew: 0,
Code: user.EncipheredPasscode.Code, Code: user.EncipheredPasscode.Code,
Mask: user.EncipheredPasscode.Mask, Mask: user.EncipheredPasscode.Mask,
@@ -261,18 +261,18 @@ func (d *SqliteRepository) RefreshUserPasscode(user entities.User, passcodeIdx [
Salt: user.CipherKeys.Salt, Salt: user.CipherKeys.Salt,
ID: uuid.UUID(user.Id).String(), ID: uuid.UUID(user.Id).String(),
} }
_, err := d.Queue.EnqueueWriteTx(queryFunc, params) return d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) GetCustomer(id models.CustomerID) (*entities.Customer, error) { func (d *SqliteRepository) GetCustomer(id entities.CustomerId) (*entities.Customer, error) {
customer, err := d.Queue.Queries.GetCustomer(d.ctx, uuid.UUID(id).String()) customer, err := d.Queue.Queries.GetCustomer(d.ctx, uuid.UUID(id).String())
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &entities.Customer{ return &entities.Customer{
ID: id, Id: id,
NKodePolicy: models.NKodePolicy{ NKodePolicy: entities.NKodePolicy{
MaxNkodeLen: int(customer.MaxNkodeLen), MaxNkodeLen: int(customer.MaxNkodeLen),
MinNkodeLen: int(customer.MinNkodeLen), MinNkodeLen: int(customer.MinNkodeLen),
DistinctSets: int(customer.DistinctSets), DistinctSets: int(customer.DistinctSets),
@@ -284,8 +284,8 @@ func (d *SqliteRepository) GetCustomer(id models.CustomerID) (*entities.Customer
}, nil }, nil
} }
func (d *SqliteRepository) GetUser(email models.UserEmail, customerId models.CustomerID) (*entities.User, error) { func (d *SqliteRepository) GetUser(email entities.UserEmail, customerId entities.CustomerId) (*entities.User, error) {
userRow, err := d.Queue.Queries.GetUser(d.ctx, sqlc.GetUserParams{ userRow, err := d.Queue.Queries.GetUser(d.ctx, sqlc2.GetUserParams{
Email: string(email), Email: string(email),
CustomerID: uuid.UUID(customerId).String(), CustomerID: uuid.UUID(customerId).String(),
}) })
@@ -295,19 +295,21 @@ func (d *SqliteRepository) GetUser(email models.UserEmail, customerId models.Cus
} }
return nil, fmt.Errorf("failed to get user: %w", err) return nil, fmt.Errorf("failed to get user: %w", err)
} }
kp := entities.KeypadDimension{ kp := entities.KeypadDimension{
AttrsPerKey: int(userRow.AttributesPerKey), AttrsPerKey: int(userRow.AttributesPerKey),
NumbOfKeys: int(userRow.NumberOfKeys), NumbOfKeys: int(userRow.NumberOfKeys),
} }
renew := false renew := false
if userRow.Renew == 1 { if userRow.Renew == 1 {
renew = true renew = true
} }
user := entities.User{ user := entities.User{
Id: models.UserIdFromString(userRow.ID), Id: entities.UserIdFromString(userRow.ID),
CustomerId: customerId, CustomerId: customerId,
Email: email, Email: email,
EncipheredPasscode: models.EncipheredNKode{ EncipheredPasscode: entities.EncipheredNKode{
Code: userRow.Code, Code: userRow.Code,
Mask: userRow.Mask, Mask: userRow.Mask,
}, },
@@ -340,33 +342,14 @@ func (d *SqliteRepository) RandomSvgInterface(kp entities.KeypadDimension) ([]st
return d.getSvgsById(ids) return d.getSvgsById(ids)
} }
func (d *SqliteRepository) RandomSvgIdxInterface(kp entities.KeypadDimension) (models.SvgIdInterface, error) { func (d *SqliteRepository) RandomSvgIdxInterface(kp entities.KeypadDimension) (entities.SvgIdInterface, error) {
return d.getRandomIds(kp.TotalAttrs()) return d.getRandomIds(kp.TotalAttrs())
} }
func (d *SqliteRepository) GetSvgStringInterface(idxs models.SvgIdInterface) ([]string, error) { func (d *SqliteRepository) GetSvgStringInterface(idxs entities.SvgIdInterface) ([]string, error) {
return d.getSvgsById(idxs) return d.getSvgsById(idxs)
} }
func (d *SqliteRepository) AddSVGIcon(svgStr string) (int64, error) {
queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(string)
if !ok {
return nil, fmt.Errorf("invalid argument type: expected string")
}
return q.AddSVGIcon(ctx, params)
}
svgID, err := d.Queue.EnqueueWriteTx(queryFunc, svgStr)
if err != nil {
return -1, err
}
svgIDInt64, ok := svgID.(int64)
if !ok {
return -1, errors.New("svgID in DB isn't int64")
}
return svgIDInt64, nil
}
func (d *SqliteRepository) getSvgsById(ids []int) ([]string, error) { func (d *SqliteRepository) getSvgsById(ids []int) ([]string, error) {
svgs := make([]string, len(ids)) svgs := make([]string, len(ids))
for idx, id := range ids { for idx, id := range ids {

View File

@@ -3,9 +3,8 @@ package repository
import ( import (
"context" "context"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/internal/entities" "go-nkode/pkg/nkode-core/entities"
"go-nkode/internal/models" sqlite_queue "go-nkode/pkg/nkode-core/sqlc"
sqlite_queue "go-nkode/internal/sqlc"
"os" "os"
"testing" "testing"
) )
@@ -17,41 +16,41 @@ func TestNewSqliteDB(t *testing.T) {
sqliteDb, err := sqlite_queue.OpenSqliteDb(dbPath) sqliteDb, err := sqlite_queue.OpenSqliteDb(dbPath)
assert.NoError(t, err) assert.NoError(t, err)
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb) queue, err := sqlite_queue.NewQueue(sqliteDb, ctx)
assert.NoError(t, err) assert.NoError(t, err)
queue.Start() queue.Start()
defer queue.Stop() defer queue.Stop()
db := NewSqliteRepository(ctx, queue) db := NewSqliteRepository(queue, ctx)
assert.NoError(t, err) assert.NoError(t, err)
testSignupLoginRenew(t, &db) testSignupLoginRenew(t, &db)
testSqliteDBRandomSvgInterface(t, &db) testSqliteDBRandomSvgInterface(t, &db)
} }
func testSignupLoginRenew(t *testing.T, db CustomerUserRepository) { func testSignupLoginRenew(t *testing.T, db CustomerUserRepository) {
nkodePolicy := models.NewDefaultNKodePolicy() nkodePolicy := entities.NewDefaultNKodePolicy()
customerOrig, err := entities.NewCustomer(nkodePolicy) customerOrig, err := entities.NewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
err = db.CreateCustomer(*customerOrig) err = db.CreateCustomer(*customerOrig)
assert.NoError(t, err) assert.NoError(t, err)
customer, err := db.GetCustomer(customerOrig.ID) customer, err := db.GetCustomer(customerOrig.Id)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, customerOrig, customer) assert.Equal(t, customerOrig, customer)
username := "test_user@example.com" username := "test_user@example.com"
kp := entities.KeypadDefault kp := entities.KeypadDefault
passcodeIdx := []int{0, 1, 2, 3} passcodeIdx := []int{0, 1, 2, 3}
mockSvgInterface := make(models.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(entities.SvgIdInterface, kp.TotalAttrs())
ui, err := entities.NewUserInterface(&kp, mockSvgInterface) ui, err := entities.NewUserInterface(&kp, mockSvgInterface)
assert.NoError(t, err) assert.NoError(t, err)
userOrig, err := entities.NewUser(*customer, username, passcodeIdx, *ui, kp) userOrig, err := entities.NewUser(*customer, username, passcodeIdx, *ui, kp)
assert.NoError(t, err) assert.NoError(t, err)
err = db.WriteNewUser(*userOrig) err = db.WriteNewUser(*userOrig)
assert.NoError(t, err) assert.NoError(t, err)
user, err := db.GetUser(models.UserEmail(username), customer.ID) user, err := db.GetUser(entities.UserEmail(username), customer.Id)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, userOrig, user) assert.Equal(t, userOrig, user)
err = db.Renew(customer.ID) err = db.Renew(customer.Id)
assert.NoError(t, err) assert.NoError(t, err)
} }

View File

@@ -10,19 +10,6 @@ import (
"database/sql" "database/sql"
) )
const addSVGIcon = `-- name: AddSVGIcon :one
INSERT INTO svg_icon (svg)
VALUES (?)
RETURNING id
`
func (q *Queries) AddSVGIcon(ctx context.Context, svg string) (int64, error) {
row := q.db.QueryRowContext(ctx, addSVGIcon, svg)
var id int64
err := row.Scan(&id)
return id, err
}
const createCustomer = `-- name: CreateCustomer :exec const createCustomer = `-- name: CreateCustomer :exec
INSERT INTO customer ( INSERT INTO customer (
id id

View File

@@ -10,13 +10,12 @@ import (
const writeBufferSize = 100 const writeBufferSize = 100
type GenericQuery func(*Queries, context.Context, any) (any, error) type SqlcGeneric func(*Queries, context.Context, any) error
type WriteTx struct { type WriteTx struct {
ErrChan chan error ErrChan chan error
ReturnChan chan any Query SqlcGeneric
Query GenericQuery Args interface{}
Args any
} }
type Queue struct { type Queue struct {
@@ -28,7 +27,7 @@ type Queue struct {
cancel context.CancelFunc cancel context.CancelFunc
} }
func NewQueue(ctx context.Context, sqlDb *sql.DB) (*Queue, error) { func NewQueue(sqlDb *sql.DB, ctx context.Context) (*Queue, error) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
sqldb := &Queue{ sqldb := &Queue{
Queries: New(sqlDb), Queries: New(sqlDb),
@@ -43,19 +42,15 @@ func NewQueue(ctx context.Context, sqlDb *sql.DB) (*Queue, error) {
func (d *Queue) Start() { func (d *Queue) Start() {
d.wg.Add(1) d.wg.Add(1)
go func() {
// TODO: I think this might be a naive approach.
defer d.wg.Done() defer d.wg.Done()
go func() {
for { for {
select { select {
case <-d.ctx.Done(): case <-d.ctx.Done():
return return
case writeTx := <-d.WriteQueue: case writeTx := <-d.WriteQueue:
ret, err := writeTx.Query(d.Queries, d.ctx, writeTx.Args) err := writeTx.Query(d.Queries, d.ctx, writeTx.Args)
writeTx.ErrChan <- err writeTx.ErrChan <- err
writeTx.ReturnChan <- ret
close(writeTx.ErrChan)
close(writeTx.ReturnChan)
} }
} }
}() }()
@@ -68,24 +63,21 @@ func (d *Queue) Stop() error {
return d.Db.Close() return d.Db.Close()
} }
func (d *Queue) EnqueueWriteTx(queryFunc GenericQuery, args any) (any, error) { func (d *Queue) EnqueueWriteTx(queryFunc SqlcGeneric, args any) error {
select { select {
case <-d.ctx.Done(): case <-d.ctx.Done():
return nil, errors.New("database is shutting down") return errors.New("database is shutting down")
default: default:
} }
errChan := make(chan error, 1) errChan := make(chan error, 1)
retChan := make(chan any, 1)
writeTx := WriteTx{ writeTx := WriteTx{
Query: queryFunc, Query: queryFunc,
Args: args, Args: args,
ErrChan: errChan, ErrChan: errChan,
ReturnChan: retChan,
} }
d.WriteQueue <- writeTx d.WriteQueue <- writeTx
err := <-errChan return <-errChan
val := <-retChan
return val, err
} }
func OpenSqliteDb(dbPath string) (*sql.DB, error) { func OpenSqliteDb(dbPath string) (*sql.DB, error) {

View File

@@ -134,8 +134,3 @@ WHERE id = ?;
-- name: GetSvgCount :one -- name: GetSvgCount :one
SELECT COUNT(*) as count FROM svg_icon; SELECT COUNT(*) as count FROM svg_icon;
-- name: AddSVGIcon :one
INSERT INTO svg_icon (svg)
VALUES (?)
RETURNING id;

View File

@@ -1,48 +0,0 @@
#!/bin/bash
sqlite_db="$HOME/databases/demo.db"
db_schema="../../sqlite/schema.sql"
# svg_path="$HOME/svgs/flaticon_colored_svgs"
# svg_path="$HOME/svgs/flaticon_colored_pngs"
#svg_path="$HOME/icons"
svg_path="$HOME/svgs/warfighter_icons"
# remove existing test database
if [ -f "$sqlite_db" ]; then
echo "Removing existing test database at $sqlite_db"
rm "$sqlite_db"
else
echo "No existing test database found at $sqlite_db"
fi
# rebuild database
sqlite3 "$sqlite_db" < "$db_schema"
cli="../../bin/cli"
# build go cli
echo "building cli"
go build -o $cli ../../cmd/cli/main.go
# build db
echo "building db"
$cli build-db -db-path "$sqlite_db" -img-path "$svg_path"
# create customer
echo "creating customer"
customer_id="ed9ed6e0-082c-4b57-8d8c-f00ed6493457"
$cli create-customer -customer-id "$customer_id" -db-path "$sqlite_db"
## create admin user
#user_email="donovan.a.kelly@pm.me"
#keypad_path="$HOME/svgs/my_icons/"
#$nkode_cli add-user \
# -img-path "$keypad_path" \
# -img-type "svg" \
# -customer-id "$customer_id" \
# -user-email "$user_email" \
# -attrs-per-key 9 -numb-of-keys 6 \
# -db-path "$sqlite_db" \
# -role admin \
# -nkode-icons ae-86.svg,arkansas.svg,banana-slug.svg,blockchain.svg
#

View File

@@ -1,7 +0,0 @@
#!/bin/bash
set -euo pipefail
./rebuild_db.sh
sqlite_db="$HOME/databases/demo.db"
scp $sqlite_db root@nkode.tech:/var/go-nkode/sqlite/demo.db

View File

@@ -1,9 +1,9 @@
version: "2" version: "2"
sql: sql:
- engine: "sqlite" - engine: "sqlite"
queries: "./sqlite/query.sql" queries: "./pkg/nkode-core/sqlite/query.sql"
schema: "./sqlite/schema.sql" schema: "./pkg/nkode-core/sqlite/schema.sql"
gen: gen:
go: go:
package: "sqlc" package: "sqlc"
out: "./internal/sqlc" out: "./pkg/nkode-core/sqlc"

View File

@@ -1,6 +0,0 @@
package sqlite
import "embed"
//go:embed schema.sql
var FS embed.FS