4 Commits

Author SHA1 Message Date
c4d34046b6 update sqlite db 2025-08-05 13:13:19 -05:00
30b2a1eb53 update docker port 2025-08-05 10:07:24 -05:00
421862fd96 update docker 2025-08-05 09:52:56 -05:00
8d4c8f71b0 rigged shuffle 2025-08-01 10:49:46 -05:00
55 changed files with 975 additions and 423 deletions

View File

@@ -1,11 +1,11 @@
root = "." root = "."
testdata_dir = "testdata" testdata_dir = "testdata"
tmp_dir = "tmp" tmp_dir = "bin"
[build] [build]
args_bin = [] args_bin = []
bin = "./tmp/main" bin = "./bin/restapi"
cmd = "go build -o ./tmp/main ." cmd = "go build -o ./bin/restapi ./cmd/restapi"
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,3 +10,4 @@ secrets.json
flaticon_svgs flaticon_svgs
flaticon_colored_svgs flaticon_colored_svgs
icons icons
bin

View File

@@ -6,7 +6,6 @@ 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 ./
@@ -19,7 +18,7 @@ RUN go mod download
COPY . . COPY . .
# Build the application # Build the application
RUN go build -o go-nkode ./cmd RUN go build -o go-nkode ./cmd/restapi
# Stage 2: Runtime # Stage 2: Runtime
FROM debian:bookworm-slim FROM debian:bookworm-slim
@@ -32,9 +31,7 @@ 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 SVG_DIR=/app/data/icons ENV SQLITE_DB=/app/data/sqlite/demo.db
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
@@ -43,7 +40,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 8080 EXPOSE 8090
# Command to run the application # Command to run the application
CMD ["./go-nkode"] CMD ["./go-nkode"]

View File

@@ -4,8 +4,17 @@ 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
@@ -20,7 +29,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:latest --push . - docker buildx build --platform linux/amd64,linux/arm64 -t registry.infra.nkode.tech/go-nkode:dod --push .
exec: exec:
cmds: cmds:
- docker exec -it cron-nkode bash - docker exec -it cron-nkode bash

273
cmd/cli/main.go Normal file
View File

@@ -0,0 +1,273 @@
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,11 +8,10 @@ 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"
api2 "go-nkode/pkg/nkode-core/api" "go-nkode/internal/email"
"go-nkode/pkg/nkode-core/email" "go-nkode/internal/models"
"go-nkode/pkg/nkode-core/entities" "go-nkode/internal/repository"
"go-nkode/pkg/nkode-core/repository" sqliteQueue "go-nkode/internal/sqlc"
sqliteQueue "go-nkode/pkg/nkode-core/sqlc"
"log" "log"
"net/http" "net/http"
"os" "os"
@@ -57,7 +56,7 @@ func main() {
} }
ctx := context.Background() ctx := context.Background()
queue, err := sqliteQueue.NewQueue(sqliteDb, ctx) queue, err := sqliteQueue.NewQueue(ctx, sqliteDb)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@@ -68,18 +67,14 @@ 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)
sqlitedb := repository.NewSqliteRepository(queue, ctx) nkodeApi := api.NewNKodeAPI(&sqlitedb, emailQueue)
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)
@@ -91,12 +86,10 @@ 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...")
fmt.Println("Running on localhost:8080...") log.Fatal(http.ListenAndServe(":8090", corsMiddleware(mux)))
log.Fatal(http.ListenAndServe(":8080", corsMiddleware(mux)))
} }
func corsMiddleware(next http.Handler) http.Handler { func corsMiddleware(next http.Handler) http.Handler {
@@ -117,13 +110,13 @@ func corsMiddleware(next http.Handler) http.Handler {
}) })
} }
func AddDefaultCustomer(nkodeApi api2.NKodeAPI) { func AddDefaultCustomer(nkodeApi api.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 := entities.CustomerId(newId) customerId := models.CustomerID(newId)
nkodePolicy := entities.NewDefaultNKodePolicy() nkodePolicy := models.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/pkg/nkode-core/entities" "go-nkode/internal/security"
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: entities.NewDefaultNKodePolicy(), NKodePolicy: models.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" + security2.GenerateRandomString(12) + "@example.com" userEmail := "test_username" + security.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 entities.SignupResetInterface var signupInterfaceResp models.GenerateSignupResetInterfaceResp
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 entities.LoginInterface var loginInterfaceResp models.GetLoginInterfaceResp
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 security2.AuthenticationTokens var jwtTokens security.AuthenticationTokens
testApiPost(t, base+api.Login, loginBody, &jwtTokens) testApiPost(t, base+api.Login, loginBody, &jwtTokens)
refreshClaims, err := security2.ParseRegisteredClaimToken(jwtTokens.RefreshToken) refreshClaims, err := security.ParseRegisteredClaimToken(jwtTokens.RefreshToken)
assert.Equal(t, refreshClaims.Subject, userEmail) assert.Equal(t, refreshClaims.Subject, userEmail)
accessClaims, err := security2.ParseRegisteredClaimToken(jwtTokens.AccessToken) accessClaims, err := security.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 = security2.ParseRegisteredClaimToken(refreshTokenResp.AccessToken) accessClaims, err = security.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,10 +1,9 @@
services: services:
go-nkode: go-nkode:
container_name: go-nkode container_name: go-nkode
image: registry.infra.nkode.tech/go-nkode image: registry.infra.nkode.tech/go-nkode:dod
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,7 +3,6 @@ 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
@@ -14,10 +13,12 @@ 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
@@ -30,17 +31,39 @@ 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,9 +30,21 @@ 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=
@@ -41,8 +53,21 @@ 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=
@@ -51,21 +76,48 @@ 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=
@@ -74,7 +126,16 @@ 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=
@@ -96,8 +157,12 @@ 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=
@@ -105,17 +170,23 @@ 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,17 +5,16 @@ 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/pkg/nkode-core/api" "go-nkode/internal/security"
"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 api.NKodeAPI Api NKodeAPI
} }
const ( const (
@@ -104,12 +103,10 @@ 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,
@@ -123,17 +120,16 @@ func (h *NKodeHandler) GenerateSignupResetInterfaceHandler(w http.ResponseWriter
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := entities.ParseEmail(signupResetPost.UserEmail) userEmail, err := models.ParseEmail(signupResetPost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
return return
} }
resp, err := h.Api.GenerateSignupResetInterface(userEmail, entities.CustomerId(customerId), kp, signupResetPost.Reset) resp, err := h.Api.GenerateSignupResetInterface(userEmail, models.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)
} }
@@ -157,7 +153,7 @@ func (h *NKodeHandler) SetNKodeHandler(w http.ResponseWriter, r *http.Request) {
badRequest(w, malformedSessionId) badRequest(w, malformedSessionId)
return return
} }
confirmInterface, err := h.Api.SetNKode(entities.CustomerId(customerId), entities.SessionId(sessionId), setNKodePost.KeySelection) confirmInterface, err := h.Api.SetNKode(models.CustomerID(customerId), models.SessionId(sessionId), setNKodePost.KeySelection)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
@@ -187,7 +183,7 @@ func (h *NKodeHandler) ConfirmNKodeHandler(w http.ResponseWriter, r *http.Reques
badRequest(w, malformedSessionId) badRequest(w, malformedSessionId)
return return
} }
if err = h.Api.ConfirmNKode(entities.CustomerId(customerId), entities.SessionId(sessionId), confirmNKodePost.KeySelection); err != nil { if err = h.Api.ConfirmNKode(models.CustomerID(customerId), models.SessionId(sessionId), confirmNKodePost.KeySelection); err != nil {
handleError(w, err) handleError(w, err)
return return
} }
@@ -209,11 +205,11 @@ func (h *NKodeHandler) GetLoginInterfaceHandler(w http.ResponseWriter, r *http.R
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := entities.ParseEmail(loginInterfacePost.UserEmail) userEmail, err := models.ParseEmail(loginInterfacePost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
} }
loginInterface, err := h.Api.GetLoginInterface(userEmail, entities.CustomerId(customerId)) loginInterface, err := h.Api.GetLoginInterface(userEmail, models.CustomerID(customerId))
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
@@ -237,12 +233,12 @@ func (h *NKodeHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := entities.ParseEmail(loginPost.UserEmail) userEmail, err := models.ParseEmail(loginPost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
return return
} }
jwtTokens, err := h.Api.Login(entities.CustomerId(customerId), userEmail, loginPost.KeySelection) jwtTokens, err := h.Api.Login(models.CustomerID(customerId), userEmail, loginPost.KeySelection)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
return return
@@ -266,7 +262,7 @@ func (h *NKodeHandler) RenewAttributesHandler(w http.ResponseWriter, r *http.Req
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
if err = h.Api.RenewAttributes(entities.CustomerId(customerId)); err != nil { if err = h.Api.RenewAttributes(models.CustomerID(customerId)); err != nil {
handleError(w, err) handleError(w, err)
return return
} }
@@ -287,7 +283,7 @@ func (h *NKodeHandler) RandomSvgInterfaceHandler(w http.ResponseWriter, r *http.
respBody := models.RandomSvgInterfaceResp{ respBody := models.RandomSvgInterfaceResp{
Svgs: svgs, Svgs: svgs,
Colors: entities.SetColors, Colors: models.SetColors,
} }
marshalAndWriteBytes(w, respBody) marshalAndWriteBytes(w, respBody)
@@ -309,13 +305,13 @@ func (h *NKodeHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Reques
badRequest(w, malformedCustomerId) badRequest(w, malformedCustomerId)
return return
} }
userEmail, err := entities.ParseEmail(refreshClaims.Subject) userEmail, err := models.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, entities.CustomerId(customerId), refreshToken) accessToken, err := h.Api.RefreshToken(userEmail, models.CustomerID(customerId), refreshToken)
if err != nil { if err != nil {
handleError(w, err) handleError(w, err)
@@ -341,13 +337,13 @@ func (h *NKodeHandler) ResetNKode(w http.ResponseWriter, r *http.Request) {
return return
} }
userEmail, err := entities.ParseEmail(resetNKodePost.UserEmail) userEmail, err := models.ParseEmail(resetNKodePost.UserEmail)
if err != nil { if err != nil {
badRequest(w, malformedUserEmail) badRequest(w, malformedUserEmail)
return return
} }
if err = h.Api.ResetNKode(userEmail, entities.CustomerId(customerId)); err != nil { if err = h.Api.ResetNKode(userEmail, models.CustomerID(customerId)); err != nil {
internalServerError(w) internalServerError(w)
log.Println(err) log.Println(err)
return return

View File

@@ -5,10 +5,11 @@ 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/pkg/nkode-core/email" "go-nkode/internal/email"
"go-nkode/pkg/nkode-core/entities" "go-nkode/internal/entities"
"go-nkode/pkg/nkode-core/repository" "go-nkode/internal/models"
"go-nkode/pkg/nkode-core/security" "go-nkode/internal/repository"
"go-nkode/internal/security"
"log" "log"
"os" "os"
"time" "time"
@@ -33,23 +34,22 @@ func NewNKodeAPI(db repository.CustomerUserRepository, queue *email.Queue) NKode
} }
} }
func (n *NKodeAPI) CreateNewCustomer(nkodePolicy entities.NKodePolicy, id *entities.CustomerId) (*entities.CustomerId, error) { func (n *NKodeAPI) CreateNewCustomer(nkodePolicy models.NKodePolicy, id *models.CustomerID) (*models.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 entities.UserEmail, customerId entities.CustomerId, kp entities.KeypadDimension, reset bool) (*entities.SignupResetInterface, error) { func (n *NKodeAPI) GenerateSignupResetInterface(userEmail models.UserEmail, customerId models.CustomerID, kp entities.KeypadDimension, reset bool) (*models.GenerateSignupResetInterfaceResp, 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,23 +58,27 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail entities.UserEmail, cu
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 := entities.SignupResetInterface{ resp := models.GenerateSignupResetInterfaceResp{
UserIdxInterface: signupSession.SetIdxInterface, UserIdxInterface: signupSession.SetIdxInterface,
SvgInterface: svgInterface, SvgInterface: svgInterface,
SessionId: uuid.UUID(signupSession.Id).String(), SessionId: uuid.UUID(signupSession.Id).String(),
@@ -83,9 +87,41 @@ func (n *NKodeAPI) GenerateSignupResetInterface(userEmail entities.UserEmail, cu
return &resp, nil return &resp, nil
} }
func (n *NKodeAPI) SetNKode(customerId entities.CustomerId, sessionId entities.SessionId, keySelection entities.KeySelection) (entities.IdxInterface, error) { func (n *NKodeAPI) GenerateSignupResetInterfaceRigged(userEmail models.UserEmail, customerId models.CustomerID, kp entities.KeypadDimension, reset bool) (*models.GenerateSignupResetInterfaceResp, error) {
_, err := n.Db.GetCustomer(customerId) 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)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -107,7 +143,7 @@ func (n *NKodeAPI) SetNKode(customerId entities.CustomerId, sessionId entities.S
return confirmInterface, nil return confirmInterface, nil
} }
func (n *NKodeAPI) ConfirmNKode(customerId entities.CustomerId, sessionId entities.SessionId, keySelection entities.KeySelection) error { func (n *NKodeAPI) ConfirmNKode(customerId models.CustomerID, sessionId models.SessionId, keySelection models.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)
@@ -142,7 +178,7 @@ func (n *NKodeAPI) ConfirmNKode(customerId entities.CustomerId, sessionId entiti
return err return err
} }
func (n *NKodeAPI) GetLoginInterface(userEmail entities.UserEmail, customerId entities.CustomerId) (*entities.LoginInterface, error) { func (n *NKodeAPI) GetLoginInterface(userEmail models.UserEmail, customerId models.CustomerID) (*models.GetLoginInterfaceResp, 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
@@ -155,17 +191,17 @@ func (n *NKodeAPI) GetLoginInterface(userEmail entities.UserEmail, customerId en
if err != nil { if err != nil {
return nil, err return nil, err
} }
resp := entities.LoginInterface{ resp := models.GetLoginInterfaceResp{
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: entities.SetColors, Colors: models.SetColors,
} }
return &resp, nil return &resp, nil
} }
func (n *NKodeAPI) Login(customerId entities.CustomerId, userEmail entities.UserEmail, keySelection entities.KeySelection) (*security.AuthenticationTokens, error) { func (n *NKodeAPI) Login(customerId models.CustomerID, userEmail models.UserEmail, keySelection models.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
@@ -182,7 +218,6 @@ func (n *NKodeAPI) Login(customerId entities.CustomerId, userEmail entities.User
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 {
@@ -205,15 +240,15 @@ func (n *NKodeAPI) Login(customerId entities.CustomerId, userEmail entities.User
return &jwtToken, nil return &jwtToken, nil
} }
func (n *NKodeAPI) RenewAttributes(customerId entities.CustomerId) error { func (n *NKodeAPI) RenewAttributes(customerId models.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.KeypadMax) return n.Db.RandomSvgInterface(entities.KeypadDefault)
} }
func (n *NKodeAPI) RefreshToken(userEmail entities.UserEmail, customerId entities.CustomerId, refreshToken string) (string, error) { func (n *NKodeAPI) RefreshToken(userEmail models.UserEmail, customerId models.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
@@ -236,16 +271,14 @@ func (n *NKodeAPI) RefreshToken(userEmail entities.UserEmail, customerId entitie
return security.EncodeAndSignClaims(newAccessClaims) return security.EncodeAndSignClaims(newAccessClaims)
} }
func (n *NKodeAPI) ResetNKode(userEmail entities.UserEmail, customerId entities.CustomerId) error { func (n *NKodeAPI) ResetNKode(userEmail models.UserEmail, customerId models.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
@@ -255,12 +288,12 @@ func (n *NKodeAPI) ResetNKode(userEmail entities.UserEmail, customerId entities.
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)
email := email.Email{ emailData := 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(email) n.EmailQueue.AddEmail(emailData)
return nil return nil
} }

View File

@@ -3,11 +3,12 @@ package api
import ( import (
"context" "context"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/pkg/nkode-core/email" "go-nkode/internal/email"
"go-nkode/pkg/nkode-core/entities" "go-nkode/internal/entities"
repository2 "go-nkode/pkg/nkode-core/repository" "go-nkode/internal/models"
"go-nkode/pkg/nkode-core/security" "go-nkode/internal/repository"
sqlite_queue "go-nkode/pkg/nkode-core/sqlc" "go-nkode/internal/security"
sqlite_queue "go-nkode/internal/sqlc"
"log" "log"
"os" "os"
"testing" "testing"
@@ -22,7 +23,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(sqliteDb, ctx) queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
assert.NoError(t, err) assert.NoError(t, err)
queue.Start() queue.Start()
defer func(queue *sqlite_queue.Queue) { defer func(queue *sqlite_queue.Queue) {
@@ -30,7 +31,7 @@ func TestNKodeAPI(t *testing.T) {
log.Fatal(err) log.Fatal(err)
} }
}(queue) }(queue)
sqlitedb := repository2.NewSqliteRepository(queue, ctx) sqlitedb := repository.NewSqliteRepository(ctx, queue)
testNKodeAPI(t, &sqlitedb) testNKodeAPI(t, &sqlitedb)
//if _, err := os.Stat(dbPath); err == nil { //if _, err := os.Stat(dbPath); err == nil {
@@ -41,7 +42,7 @@ func TestNKodeAPI(t *testing.T) {
//} //}
} }
func testNKodeAPI(t *testing.T, db repository2.CustomerUserRepository) { func testNKodeAPI(t *testing.T, db repository.CustomerUserRepository) {
bufferSize := 100 bufferSize := 100
emailsPerSec := 14 emailsPerSec := 14
testClient := email.TestEmailClient{} testClient := email.TestEmailClient{}
@@ -51,9 +52,9 @@ func testNKodeAPI(t *testing.T, db repository2.CustomerUserRepository) {
attrsPerKey := 5 attrsPerKey := 5
numbOfKeys := 4 numbOfKeys := 4
for idx := 0; idx < 1; idx++ { for idx := 0; idx < 1; idx++ {
userEmail := entities.UserEmail("test_username" + security.GenerateRandomString(12) + "@example.com") userEmail := models.UserEmail("test_username" + security.GenerateRandomString(12) + "@example.com")
passcodeLen := 4 passcodeLen := 4
nkodePolicy := entities.NewDefaultNKodePolicy() nkodePolicy := models.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)
@@ -62,7 +63,7 @@ func testNKodeAPI(t *testing.T, db repository2.CustomerUserRepository) {
assert.NoError(t, err) assert.NoError(t, err)
setInterface := signupResponse.UserIdxInterface setInterface := signupResponse.UserIdxInterface
sessionIdStr := signupResponse.SessionId sessionIdStr := signupResponse.SessionId
sessionId, err := entities.SessionIdFromString(sessionIdStr) sessionId, err := models.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]
@@ -99,7 +100,7 @@ func testNKodeAPI(t *testing.T, db repository2.CustomerUserRepository) {
assert.NoError(t, err) assert.NoError(t, err)
setInterface = resetResponse.UserIdxInterface setInterface = resetResponse.UserIdxInterface
sessionIdStr = resetResponse.SessionId sessionIdStr = resetResponse.SessionId
sessionId, err = entities.SessionIdFromString(sessionIdStr) sessionId, err = models.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,6 +18,7 @@ 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
@@ -27,7 +28,9 @@ 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
} }
@@ -124,6 +127,7 @@ 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)
@@ -133,17 +137,20 @@ 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 <-q.rateLimit // Wait for the rate limiter to allow the next email
q.sendEmail(email) q.sendEmail(email)
q.wg.Done() q.wg.Done() // Mark the email as processed
} }
}() }()
} }
// 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
@@ -151,8 +158,11 @@ 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,24 +4,25 @@ 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/pkg/nkode-core/security" "go-nkode/internal/models"
"go-nkode/pkg/nkode-core/sqlc" "go-nkode/internal/security"
"go-nkode/pkg/nkode-core/utils" "go-nkode/internal/sqlc"
"go-nkode/internal/utils"
) )
type Customer struct { type Customer struct {
Id CustomerId ID models.CustomerID
NKodePolicy NKodePolicy NKodePolicy models.NKodePolicy
Attributes CustomerAttributes Attributes CustomerAttributes
} }
func NewCustomer(nkodePolicy NKodePolicy) (*Customer, error) { func NewCustomer(nkodePolicy models.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: CustomerId(uuid.New()), ID: models.CustomerID(uuid.New()),
NKodePolicy: nkodePolicy, NKodePolicy: nkodePolicy,
Attributes: *customerAttrs, Attributes: *customerAttrs,
} }
@@ -87,7 +88,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/pkg/nkode-core/security" "go-nkode/internal/security"
"log" "log"
) )

View File

@@ -2,6 +2,7 @@ package entities
import ( import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/internal/models"
"testing" "testing"
) )
@@ -18,10 +19,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 := NewDefaultNKodePolicy() nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy) customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(models.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"
@@ -42,10 +43,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 := NewDefaultNKodePolicy() nkodePolicy := models.NewDefaultNKodePolicy()
customer, err := NewCustomer(nkodePolicy) customer, err := NewCustomer(nkodePolicy)
assert.NoError(t, err) assert.NoError(t, err)
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(models.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/pkg/nkode-core/security" "go-nkode/internal/security"
) )
func SelectKeyByAttrIdx(interfaceUser []int, passcodeIdxs []int, keypadSize KeypadDimension) ([]int, error) { func SelectKeyByAttrIdx(interfaceUser []int, passcodeIdxs []int, keypadSize KeypadDimension) ([]int, error) {

View File

@@ -3,15 +3,16 @@ package entities
import ( import (
"github.com/google/uuid" "github.com/google/uuid"
"go-nkode/config" "go-nkode/config"
"go-nkode/pkg/nkode-core/security" "go-nkode/internal/models"
"go-nkode/internal/security"
"log" "log"
) )
type User struct { type User struct {
Id UserId Id models.UserId
CustomerId CustomerId CustomerId models.CustomerID
Email UserEmail Email models.UserEmail
EncipheredPasscode EncipheredNKode EncipheredPasscode models.EncipheredNKode
Kp KeypadDimension Kp KeypadDimension
CipherKeys UserCipherKeys CipherKeys UserCipherKeys
Interface UserInterface Interface UserInterface
@@ -113,7 +114,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 := ParseEmail(userEmail) _, err := models.ParseEmail(userEmail)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -130,13 +131,13 @@ func NewUser(customer Customer, userEmail string, passcodeIdx []int, ui UserInte
return nil, err return nil, err
} }
newUser := User{ newUser := User{
Id: UserId(uuid.New()), Id: models.UserId(uuid.New()),
Email: UserEmail(userEmail), Email: models.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,7 +4,8 @@ import (
"crypto/sha256" "crypto/sha256"
"errors" "errors"
"go-nkode/config" "go-nkode/config"
"go-nkode/pkg/nkode-core/security" "go-nkode/internal/models"
"go-nkode/internal/security"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -166,7 +167,7 @@ func (u *UserCipherKeys) DecipherMask(mask string, setVals []uint64, passcodeLen
return passcodeSet, nil return passcodeSet, nil
} }
func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*EncipheredNKode, error) { func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs CustomerAttributes) (*models.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 {
@@ -185,7 +186,7 @@ func (u *UserCipherKeys) EncipherNKode(passcodeAttrIdx []int, customerAttrs Cust
if err != nil { if err != nil {
return nil, err return nil, err
} }
encipheredCode := EncipheredNKode{ encipheredCode := models.EncipheredNKode{
Code: code, Code: code,
Mask: mask, Mask: mask,
} }

View File

@@ -3,17 +3,18 @@ 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/pkg/nkode-core/security" "go-nkode/internal/models"
"go-nkode/internal/security"
"log" "log"
) )
type UserInterface struct { type UserInterface struct {
IdxInterface IdxInterface IdxInterface models.IdxInterface
SvgId SvgIdInterface SvgId models.SvgIdInterface
Kp *KeypadDimension Kp *KeypadDimension
} }
func NewUserInterface(kp *KeypadDimension, svgId SvgIdInterface) (*UserInterface, error) { func NewUserInterface(kp *KeypadDimension, svgId models.SvgIdInterface) (*UserInterface, error) {
idxInterface := security.IdentityArray(kp.TotalAttrs()) idxInterface := security.IdentityArray(kp.TotalAttrs())
userInterface := UserInterface{ userInterface := UserInterface{
IdxInterface: idxInterface, IdxInterface: idxInterface,

View File

@@ -5,26 +5,51 @@ 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/pkg/nkode-core/security" "go-nkode/internal/models"
"go-nkode/internal/security"
"log" "log"
"sort" "sort"
) )
type UserSignSession struct { type UserSignSession struct {
Id SessionId Id models.SessionId
CustomerId CustomerId CustomerId models.CustomerID
LoginUserInterface UserInterface LoginUserInterface UserInterface
Kp KeypadDimension Kp KeypadDimension
SetIdxInterface IdxInterface SetIdxInterface models.IdxInterface
ConfirmIdxInterface IdxInterface ConfirmIdxInterface models.IdxInterface
SetKeySelection KeySelection SetKeySelection models.KeySelection
UserEmail UserEmail UserEmail models.UserEmail
Reset bool Reset bool
Expire int Expire int
Colors []RGBColor Colors []models.RGBColor
} }
func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId CustomerId, svgInterface SvgIdInterface, reset bool) (*UserSignSession, error) { func NewSignupResetSessionRigged(userEmail models.UserEmail, kp KeypadDimension, customerId models.CustomerID, svgInterface models.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
@@ -34,7 +59,7 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C
return nil, err return nil, err
} }
session := UserSignSession{ session := UserSignSession{
Id: SessionId(uuid.New()), Id: models.SessionId(uuid.New()),
CustomerId: customerId, CustomerId: customerId,
LoginUserInterface: *loginInterface, LoginUserInterface: *loginInterface,
SetIdxInterface: signupInterface.IdxInterface, SetIdxInterface: signupInterface.IdxInterface,
@@ -45,11 +70,10 @@ func NewSignupResetSession(userEmail UserEmail, kp KeypadDimension, customerId C
Reset: reset, Reset: reset,
Colors: colors, Colors: colors,
} }
return &session, nil return &session, nil
} }
func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, error) { func (s *UserSignSession) DeducePasscode(confirmKeyEntry models.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
}) })
@@ -110,7 +134,7 @@ func (s *UserSignSession) DeducePasscode(confirmKeyEntry KeySelection) ([]int, e
return passcode, nil return passcode, nil
} }
func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface, error) { func (s *UserSignSession) SetUserNKode(keySelection models.KeySelection) (models.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
}) })
@@ -130,7 +154,7 @@ func (s *UserSignSession) SetUserNKode(keySelection KeySelection) (IdxInterface,
return s.ConfirmIdxInterface, nil return s.ConfirmIdxInterface, nil
} }
func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInterface []int) ([][]int, error) { func (s *UserSignSession) getSelectedKeyVals(keySelections models.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 {
@@ -144,7 +168,7 @@ func (s *UserSignSession) getSelectedKeyVals(keySelections KeySelection, userInt
return keyVals, nil return keyVals, nil
} }
func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []RGBColor, error) { func signupInterface(baseUserInterface UserInterface, kp KeypadDimension) (*UserInterface, []models.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
@@ -171,11 +195,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([]RGBColor, kp.NumbOfKeys) selectedColors := make([]models.RGBColor, kp.NumbOfKeys)
for idx, setIdx := range setIdxs { for idx, setIdx := range setIdxs {
selectedSets[idx] = attrSetView[setIdx] selectedSets[idx] = attrSetView[setIdx]
selectedColors[idx] = SetColors[setIdx] selectedColors[idx] = models.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,6 +3,7 @@ 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"
) )
@@ -64,7 +65,7 @@ func TestUserInterface_RandomShuffle(t *testing.T) {
AttrsPerKey: 10, AttrsPerKey: 10,
NumbOfKeys: 8, NumbOfKeys: 8,
} }
mockSvgInterface := make(SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(models.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))
@@ -87,7 +88,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(SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(models.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()
@@ -106,7 +107,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(SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(models.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

@@ -1,7 +1,10 @@
package models package models
import ( import (
"go-nkode/pkg/nkode-core/entities" "fmt"
"github.com/google/uuid"
"net/mail"
"strings"
) )
type SetNKodeResp struct { type SetNKodeResp struct {
@@ -9,8 +12,8 @@ type SetNKodeResp struct {
} }
type RandomSvgInterfaceResp struct { type RandomSvgInterfaceResp struct {
Svgs []string `json:"svgs"` Svgs []string `json:"svgs"`
Colors []entities.RGBColor `json:"colors"` Colors []RGBColor `json:"colors"`
} }
type RefreshTokenResp struct { type RefreshTokenResp struct {
@@ -18,7 +21,7 @@ type RefreshTokenResp struct {
} }
type NewCustomerPost struct { type NewCustomerPost struct {
NKodePolicy entities.NKodePolicy `json:"nkode_policy"` NKodePolicy NKodePolicy `json:"nkode_policy"`
} }
type GenerateSignupRestInterfacePost struct { type GenerateSignupRestInterfacePost struct {
@@ -36,9 +39,9 @@ type SetNKodePost struct {
} }
type ConfirmNKodePost struct { type ConfirmNKodePost struct {
CustomerId string `json:"customer_id"` CustomerId string `json:"customer_id"`
KeySelection entities.KeySelection `json:"key_selection"` KeySelection KeySelection `json:"key_selection"`
SessionId string `json:"session_id"` SessionId string `json:"session_id"`
} }
type GetLoginInterfacePost struct { type GetLoginInterfacePost struct {
@@ -47,15 +50,20 @@ 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 entities.KeySelection `json:"key_selection"` KeySelection 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"`
@@ -64,3 +72,104 @@ 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,4 +1,4 @@
package entities package models
import "go-nkode/config" import "go-nkode/config"

View File

@@ -0,0 +1,22 @@
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

@@ -3,32 +3,33 @@ package repository
import ( import (
"errors" "errors"
"fmt" "fmt"
"go-nkode/pkg/nkode-core/entities" "go-nkode/internal/entities"
"go-nkode/internal/models"
) )
type InMemoryDb struct { type InMemoryDb struct {
Customers map[entities.CustomerId]entities.Customer Customers map[models.CustomerID]entities.Customer
Users map[entities.UserId]entities.User Users map[models.UserId]entities.User
userIdMap map[string]entities.UserId userIdMap map[string]models.UserId
} }
func NewInMemoryDb() InMemoryDb { func NewInMemoryDb() InMemoryDb {
return InMemoryDb{ return InMemoryDb{
Customers: make(map[entities.CustomerId]entities.Customer), Customers: make(map[models.CustomerID]entities.Customer),
Users: make(map[entities.UserId]entities.User), Users: make(map[models.UserId]entities.User),
userIdMap: make(map[string]entities.UserId), userIdMap: make(map[string]models.UserId),
} }
} }
func (db *InMemoryDb) GetCustomer(id entities.CustomerId) (*entities.Customer, error) { func (db *InMemoryDb) GetCustomer(id models.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 entities.UserEmail, customerId entities.CustomerId) (*entities.User, error) { func (db *InMemoryDb) GetUser(username models.UserEmail, customerId models.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 {
@@ -42,12 +43,12 @@ func (db *InMemoryDb) GetUser(username entities.UserEmail, customerId entities.C
} }
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
} }
@@ -71,7 +72,7 @@ func (db *InMemoryDb) UpdateUserNKode(user entities.User) error {
return errors.ErrUnsupported return errors.ErrUnsupported
} }
func (db *InMemoryDb) UpdateUserInterface(userId entities.UserId, ui entities.UserInterface) error { func (db *InMemoryDb) UpdateUserInterface(userId models.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))
@@ -81,11 +82,11 @@ func (db *InMemoryDb) UpdateUserInterface(userId entities.UserId, ui entities.Us
return nil return nil
} }
func (db *InMemoryDb) UpdateUserRefreshToken(userId entities.UserId, refreshToken string) error { func (db *InMemoryDb) UpdateUserRefreshToken(userId models.UserId, refreshToken string) error {
return nil return nil
} }
func (db *InMemoryDb) Renew(id entities.CustomerId) error { func (db *InMemoryDb) Renew(id models.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))
@@ -120,19 +121,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) (entities.SvgIdInterface, error) { func (db *InMemoryDb) RandomSvgIdxInterface(kp entities.KeypadDimension) (models.SvgIdInterface, error) {
svgs := make(entities.SvgIdInterface, kp.TotalAttrs()) svgs := make(models.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 entities.SvgIdInterface) ([]string, error) { func (db *InMemoryDb) GetSvgStringInterface(idxs models.SvgIdInterface) ([]string, error) {
return make([]string, len(idxs)), nil return make([]string, len(idxs)), nil
} }
func userIdKey(customerId entities.CustomerId, username entities.UserEmail) string { func userIdKey(customerId models.CustomerID, username models.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("DB_PATH") dbPath := os.Getenv("SQLITE_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,19 +8,20 @@ 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/pkg/nkode-core/entities" "go-nkode/internal/entities"
"go-nkode/pkg/nkode-core/security" "go-nkode/internal/models"
sqlc2 "go-nkode/pkg/nkode-core/sqlc" "go-nkode/internal/security"
"go-nkode/pkg/nkode-core/utils" "go-nkode/internal/sqlc"
"go-nkode/internal/utils"
"log" "log"
) )
type SqliteRepository struct { type SqliteRepository struct {
Queue *sqlc2.Queue Queue *sqlc.Queue
ctx context.Context ctx context.Context
} }
func NewSqliteRepository(queue *sqlc2.Queue, ctx context.Context) SqliteRepository { func NewSqliteRepository(ctx context.Context, queue *sqlc.Queue) SqliteRepository {
return SqliteRepository{ return SqliteRepository{
Queue: queue, Queue: queue,
ctx: ctx, ctx: ctx,
@@ -28,33 +29,33 @@ func NewSqliteRepository(queue *sqlc2.Queue, ctx context.Context) SqliteReposito
} }
func (d *SqliteRepository) CreateCustomer(c entities.Customer) error { func (d *SqliteRepository) CreateCustomer(c entities.Customer) error {
queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.CreateCustomerParams) params, ok := args.(sqlc.CreateCustomerParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected CreateCustomerParams") return nil, fmt.Errorf("invalid argument type: expected CreateCustomerParams")
} }
return q.CreateCustomer(ctx, params) return nil, q.CreateCustomer(ctx, params)
} }
return d.Queue.EnqueueWriteTx(queryFunc, c.ToSqlcCreateCustomerParams()) _, err := 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 *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.CreateUserParams) params, ok := args.(sqlc.CreateUserParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected CreateUserParams") return nil, fmt.Errorf("invalid argument type: expected CreateUserParams")
} }
return q.CreateUser(ctx, params) return nil, 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 := sqlc2.CreateUserParams{ params := sqlc.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),
@@ -74,23 +75,24 @@ 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},
} }
return d.Queue.EnqueueWriteTx(queryFunc, params) _, err := 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 *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.UpdateUserParams) params, ok := args.(sqlc.UpdateUserParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected UpdateUserParams") return nil, fmt.Errorf("invalid argument type: expected UpdateUserParams")
} }
return q.UpdateUser(ctx, params) return nil, 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 := sqlc2.UpdateUserParams{ params := sqlc.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 != ""},
@@ -108,80 +110,81 @@ 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),
} }
return d.Queue.EnqueueWriteTx(queryFunc, params) _, err := d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) UpdateUserInterface(id entities.UserId, ui entities.UserInterface) error { func (d *SqliteRepository) UpdateUserInterface(id models.UserId, ui entities.UserInterface) error {
queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.UpdateUserInterfaceParams) params, ok := args.(sqlc.UpdateUserInterfaceParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected UpdateUserInterfaceParams") return nil, fmt.Errorf("invalid argument type: expected UpdateUserInterfaceParams")
} }
return q.UpdateUserInterface(ctx, params) return nil, q.UpdateUserInterface(ctx, params)
} }
params := sqlc2.UpdateUserInterfaceParams{ params := sqlc.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 d.Queue.EnqueueWriteTx(queryFunc, params) return err
} }
func (d *SqliteRepository) UpdateUserRefreshToken(id entities.UserId, refreshToken string) error { func (d *SqliteRepository) UpdateUserRefreshToken(id models.UserId, refreshToken string) error {
queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.UpdateUserRefreshTokenParams) params, ok := args.(sqlc.UpdateUserRefreshTokenParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected UpdateUserRefreshToken") return nil, fmt.Errorf("invalid argument type: expected UpdateUserRefreshToken")
} }
return q.UpdateUserRefreshToken(ctx, params) return nil, q.UpdateUserRefreshToken(ctx, params)
} }
params := sqlc2.UpdateUserRefreshTokenParams{ params := sqlc.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(),
} }
return d.Queue.EnqueueWriteTx(queryFunc, params) _, err := d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) RenewCustomer(renewParams sqlc2.RenewCustomerParams) error { func (d *SqliteRepository) RenewCustomer(renewParams sqlc.RenewCustomerParams) error {
queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.RenewCustomerParams) params, ok := args.(sqlc.RenewCustomerParams)
if !ok { if !ok {
return nil, fmt.Errorf("invalid argument type: expected RenewCustomerParams")
} }
return q.RenewCustomer(ctx, params) return nil, q.RenewCustomer(ctx, params)
} }
return d.Queue.EnqueueWriteTx(queryFunc, renewParams) _, err := d.Queue.EnqueueWriteTx(queryFunc, renewParams)
return err
} }
func (d *SqliteRepository) Renew(id entities.CustomerId) error { func (d *SqliteRepository) Renew(id models.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 := entities.CustomerIdToString(id) customerId := models.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) {
queryFunc := func(q *sqlc2.Queries, ctx context.Context, args any) error { params, ok := args.(sqlc.RenewUserParams)
params, ok := args.(sqlc2.RenewUserParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected RenewUserParams") return nil, fmt.Errorf("invalid argument type: expected RenewUserParams")
} }
return q.RenewUser(ctx, params) return nil, q.RenewUser(ctx, params)
} }
for _, row := range userRenewRows { for _, row := range userRenewRows {
user := entities.User{ user := entities.User{
Id: entities.UserIdFromString(row.ID), Id: models.UserIdFromString(row.ID),
CustomerId: entities.CustomerId{}, CustomerId: models.CustomerID{},
Email: "", Email: "",
EncipheredPasscode: entities.EncipheredNKode{}, EncipheredPasscode: models.EncipheredNKode{},
Kp: entities.KeypadDimension{ Kp: entities.KeypadDimension{
AttrsPerKey: int(row.AttributesPerKey), AttrsPerKey: int(row.AttributesPerKey),
NumbOfKeys: int(row.NumberOfKeys), NumbOfKeys: int(row.NumberOfKeys),
@@ -193,24 +196,23 @@ func (d *SqliteRepository) Renew(id entities.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 := sqlc2.RenewUserParams{ params := sqlc.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 entities.CustomerId) ([]uint64, []uint64, error) { func (d *SqliteRepository) renewCustomer(id models.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
@@ -219,21 +221,19 @@ func (d *SqliteRepository) renewCustomer(id entities.CustomerId) ([]uint64, []ui
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) {
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 fmt.Errorf("invalid argument type: expected RenewCustomerParams") return nil, fmt.Errorf("invalid argument type: expected RenewCustomerParams")
} }
return q.RenewCustomer(ctx, params) return nil, q.RenewCustomer(ctx, params)
} }
params := sqlc2.RenewCustomerParams{ params := sqlc.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 *sqlc2.Queries, ctx context.Context, args any) error { queryFunc := func(q *sqlc.Queries, ctx context.Context, args any) (any, error) {
params, ok := args.(sqlc2.RefreshUserPasscodeParams) params, ok := args.(sqlc.RefreshUserPasscodeParams)
if !ok { if !ok {
return fmt.Errorf("invalid argument type: expected RefreshUserPasscodeParams") return nil, fmt.Errorf("invalid argument type: expected RefreshUserPasscodeParams")
} }
return q.RefreshUserPasscode(ctx, params) return nil, q.RefreshUserPasscode(ctx, params)
} }
params := sqlc2.RefreshUserPasscodeParams{ params := sqlc.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(),
} }
return d.Queue.EnqueueWriteTx(queryFunc, params) _, err := d.Queue.EnqueueWriteTx(queryFunc, params)
return err
} }
func (d *SqliteRepository) GetCustomer(id entities.CustomerId) (*entities.Customer, error) { func (d *SqliteRepository) GetCustomer(id models.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: entities.NKodePolicy{ NKodePolicy: models.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 entities.CustomerId) (*entities.Custom
}, nil }, nil
} }
func (d *SqliteRepository) GetUser(email entities.UserEmail, customerId entities.CustomerId) (*entities.User, error) { func (d *SqliteRepository) GetUser(email models.UserEmail, customerId models.CustomerID) (*entities.User, error) {
userRow, err := d.Queue.Queries.GetUser(d.ctx, sqlc2.GetUserParams{ userRow, err := d.Queue.Queries.GetUser(d.ctx, sqlc.GetUserParams{
Email: string(email), Email: string(email),
CustomerID: uuid.UUID(customerId).String(), CustomerID: uuid.UUID(customerId).String(),
}) })
@@ -295,21 +295,19 @@ func (d *SqliteRepository) GetUser(email entities.UserEmail, customerId entities
} }
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: entities.UserIdFromString(userRow.ID), Id: models.UserIdFromString(userRow.ID),
CustomerId: customerId, CustomerId: customerId,
Email: email, Email: email,
EncipheredPasscode: entities.EncipheredNKode{ EncipheredPasscode: models.EncipheredNKode{
Code: userRow.Code, Code: userRow.Code,
Mask: userRow.Mask, Mask: userRow.Mask,
}, },
@@ -342,14 +340,33 @@ func (d *SqliteRepository) RandomSvgInterface(kp entities.KeypadDimension) ([]st
return d.getSvgsById(ids) return d.getSvgsById(ids)
} }
func (d *SqliteRepository) RandomSvgIdxInterface(kp entities.KeypadDimension) (entities.SvgIdInterface, error) { func (d *SqliteRepository) RandomSvgIdxInterface(kp entities.KeypadDimension) (models.SvgIdInterface, error) {
return d.getRandomIds(kp.TotalAttrs()) return d.getRandomIds(kp.TotalAttrs())
} }
func (d *SqliteRepository) GetSvgStringInterface(idxs entities.SvgIdInterface) ([]string, error) { func (d *SqliteRepository) GetSvgStringInterface(idxs models.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,8 +3,9 @@ package repository
import ( import (
"context" "context"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"go-nkode/pkg/nkode-core/entities" "go-nkode/internal/entities"
sqlite_queue "go-nkode/pkg/nkode-core/sqlc" "go-nkode/internal/models"
sqlite_queue "go-nkode/internal/sqlc"
"os" "os"
"testing" "testing"
) )
@@ -16,41 +17,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(sqliteDb, ctx) queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
assert.NoError(t, err) assert.NoError(t, err)
queue.Start() queue.Start()
defer queue.Stop() defer queue.Stop()
db := NewSqliteRepository(queue, ctx) db := NewSqliteRepository(ctx, queue)
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 := entities.NewDefaultNKodePolicy() nkodePolicy := models.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(entities.SvgIdInterface, kp.TotalAttrs()) mockSvgInterface := make(models.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(entities.UserEmail(username), customer.Id) user, err := db.GetUser(models.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,6 +10,19 @@ 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,12 +10,13 @@ import (
const writeBufferSize = 100 const writeBufferSize = 100
type SqlcGeneric func(*Queries, context.Context, any) error type GenericQuery func(*Queries, context.Context, any) (any, error)
type WriteTx struct { type WriteTx struct {
ErrChan chan error ErrChan chan error
Query SqlcGeneric ReturnChan chan any
Args interface{} Query GenericQuery
Args any
} }
type Queue struct { type Queue struct {
@@ -27,7 +28,7 @@ type Queue struct {
cancel context.CancelFunc cancel context.CancelFunc
} }
func NewQueue(sqlDb *sql.DB, ctx context.Context) (*Queue, error) { func NewQueue(ctx context.Context, sqlDb *sql.DB) (*Queue, error) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
sqldb := &Queue{ sqldb := &Queue{
Queries: New(sqlDb), Queries: New(sqlDb),
@@ -42,15 +43,19 @@ func NewQueue(sqlDb *sql.DB, ctx context.Context) (*Queue, error) {
func (d *Queue) Start() { func (d *Queue) Start() {
d.wg.Add(1) d.wg.Add(1)
defer d.wg.Done()
go func() { go func() {
// TODO: I think this might be a naive approach.
defer d.wg.Done()
for { for {
select { select {
case <-d.ctx.Done(): case <-d.ctx.Done():
return return
case writeTx := <-d.WriteQueue: case writeTx := <-d.WriteQueue:
err := writeTx.Query(d.Queries, d.ctx, writeTx.Args) ret, err := writeTx.Query(d.Queries, d.ctx, writeTx.Args)
writeTx.ErrChan <- err writeTx.ErrChan <- err
writeTx.ReturnChan <- ret
close(writeTx.ErrChan)
close(writeTx.ReturnChan)
} }
} }
}() }()
@@ -63,21 +68,24 @@ func (d *Queue) Stop() error {
return d.Db.Close() return d.Db.Close()
} }
func (d *Queue) EnqueueWriteTx(queryFunc SqlcGeneric, args any) error { func (d *Queue) EnqueueWriteTx(queryFunc GenericQuery, args any) (any, error) {
select { select {
case <-d.ctx.Done(): case <-d.ctx.Done():
return errors.New("database is shutting down") return nil, 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
return <-errChan err := <-errChan
val := <-retChan
return val, err
} }
func OpenSqliteDb(dbPath string) (*sql.DB, error) { func OpenSqliteDb(dbPath string) (*sql.DB, error) {

View File

@@ -1,101 +0,0 @@
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,20 +0,0 @@
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)
}

48
scripts/bash/rebuild_db.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/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
#

7
scripts/bash/scp_db.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/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: "./pkg/nkode-core/sqlite/query.sql" queries: "./sqlite/query.sql"
schema: "./pkg/nkode-core/sqlite/schema.sql" schema: "./sqlite/schema.sql"
gen: gen:
go: go:
package: "sqlc" package: "sqlc"
out: "./pkg/nkode-core/sqlc" out: "./internal/sqlc"

6
sqlite/embed.go Normal file
View File

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

View File

@@ -134,3 +134,8 @@ 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;