feature/simplify ucan mpc did (#1195)

* feat: enable DID auth middleware

* feat: implement passkey creation flow

* feat: persist user address in cookie and retrieve user profile using address cookie

* feat: implement human verification challenge during session initialization

* refactor: remove unnecessary random number generation in profile creation

* refactor: rename credential validation handler and update related routes

* feat: improve profile validation and user experience

* feat: add page rendering for profile and passkey creation

* refactor: remove unused register handler and update routes

* refactor: remove unused imports and simplify credential validation

* fix: Correct insecure gRPC client connection

* refactor: rename models files for better organization

* refactor: refactor grpc client creation and management

* refactor: refactor common clients package

* <no value>

* feat: add CapAccount, CapInterchain, CapVault enums

* feat: add ChainId to ResAccount and ResInterchain

* feat: add asset code to resource account enumeration

* refactor: rename services package to providers

* feat: implement gateway database interactions

* refactor: move gateway repository to internal/gateway

* refactor: Migrate database provider to use sqlx

* refactor: Rename Vaults to VaultProvider in HTTPContext struct

* refactor: Migrate from GORM to sqlc Queries in database context methods

* refactor: Replace GORM with standard SQL and simplify database initialization

* refactor: Migrate session management from GORM to sqlc with type conversion

* refactor: Update import paths and model references in context package

* fix: Resolve session type conversion and middleware issues

* refactor: Migrate database from GORM to sqlx

* refactor: Move models to pkg/common, improve code structure

* refactor: move repository package to internal directory

* refactor: move gateway internal packages to context directory

* refactor: migrate database provider to use sqlx queries

* feat: add session ID to HTTP context and use it to load session data

* feat: implement vault creation API endpoint

* feat: add DIDKey generation from PubKey

* refactor: remove unused DIDAuth components

* refactor: move DID auth controller to vault context

* chore: remove unused DIDAuth package

* refactor: improve clarity of enclave refresh function

* feat: implement nonce-based key encryption for improved security

* feat: Add Export and Import methods with comprehensive tests for Enclave

* fix: Validate AES key length in keyshare encryption and decryption

* fix: Resolve key length validation by hashing input keys

* refactor: Update keyshare import to use protocol decoding

* feat: Refactor enclave encryption to support full enclave export/import

* refactor: Simplify Enclave interface methods by removing role parameter

* refactor: remove unnecessary serialization from enclave interface

* refactor: rename models package in gateway context

* refactor: rename keystore vault constants

* refactor: remove context parameter from Resolver methods

* feat: add CurrentBlock context function and update related components

* refactor: rename resolver.go to resolvers.go

* feat: Add SQLite random() generation for session and profile initialization

* refactor: Update SQL queries to use SQLite-style parameter placeholders

* refactor: Replace '?' placeholders with '$n' PostgreSQL parameter syntax

* <no value>

* refactor: refactor gateway to use middleware for database interactions and improve modularity

* feat: implement gateway for Sonr highway

* refactor: Remove unused gateway context and refactor cookie/header handling

* refactor: improve server initialization and middleware handling

* feat: implement human verification for profile creation

* feat: implement session management middleware

* refactor: refactor common models and config to internal package

* refactor: move env config to internal/config

* refactor: move database-related code to  directory

* refactor: move IPFS client to common package and improve code structure

* refactor: move querier to common package and rename to chain_query

* refactor: move webworker model to internal/models

* feat: add initial view template for Sonr.ID

* docs(concepts): Add documentation for cosmos-proto

* docs: move IBC transfer documentation to tools section

* refactor: rename initpkl.go to pkl_init.go for better naming consistency

* docs(theme): update dark mode toggle icons

* refactor: update sqlite3 driver to ncruces/go-sqlite3

* feat: add Vault model and database interactions

* refactor: Improve SQLite schema with better constraints and indexes

* chore: update project dependencies

* fix: use grpc.WithInsecure() for gRPC connection

* config: set localhost as default Sonr gRPC URL

* refactor: improve gateway middleware and refactor server initialization

* refactor: Remove foreign key pragma from schema SQL

* refactor: Remove foreign key constraints from database schema

* refactor: Convert primary key columns from INTEGER to TEXT

* refactor: Remove unnecessary redirect in error handling
This commit is contained in:
Prad Nukala
2024-12-16 20:29:54 +00:00
committed by GitHub
parent 6d27b926f6
commit 7c4586ce90
196 changed files with 4480 additions and 3192 deletions
+25
View File
@@ -0,0 +1,25 @@
package database
import (
"context"
"database/sql"
_ "github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
config "github.com/onsonr/sonr/internal/config/hway"
"github.com/onsonr/sonr/internal/database/sink"
)
// NewDB initializes and returns a configured database connection
func NewDB(env config.Hway) (*sql.DB, error) {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
return nil, err
}
// create tables
if _, err := db.ExecContext(context.Background(), sink.SchemaSQL); err != nil {
return nil, err
}
return db, nil
}
+31
View File
@@ -0,0 +1,31 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
package repository
import (
"context"
"database/sql"
)
type DBTX interface {
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
PrepareContext(context.Context, string) (*sql.Stmt, error)
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}
func New(db DBTX) *Queries {
return &Queries{db: db}
}
type Queries struct {
db DBTX
}
func (q *Queries) WithTx(tx *sql.Tx) *Queries {
return &Queries{
db: tx,
}
}
+99
View File
@@ -0,0 +1,99 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
package repository
import (
"database/sql"
"time"
)
type Account struct {
ID string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
Number int64
Sequence int64
Address string
PublicKey string
ChainID string
Controller string
IsSubsidiary bool
IsValidator bool
IsDelegator bool
IsAccountable bool
}
type Asset struct {
ID string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
Name string
Symbol string
Decimals int64
ChainID string
Channel string
AssetType string
CoingeckoID sql.NullString
}
type Credential struct {
ID int64
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
Handle string
CredentialID string
AuthenticatorAttachment string
Origin string
Type string
Transports string
}
type Profile struct {
ID int64
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
Address string
Handle string
Origin string
Name string
}
type Session struct {
ID string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
BrowserName string
BrowserVersion string
ClientIpaddr string
Platform string
IsDesktop bool
IsMobile bool
IsTablet bool
IsTv bool
IsBot bool
Challenge string
IsHumanFirst bool
IsHumanLast bool
ProfileID int64
}
type Vault struct {
ID int64
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
Handle string
Origin string
Address string
Cid string
Config string
SessionID string
RedirectUri string
}
+581
View File
@@ -0,0 +1,581 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// source: query.sql
package repository
import (
"context"
)
const checkHandleExists = `-- name: CheckHandleExists :one
SELECT COUNT(*) > 0 as handle_exists FROM profiles
WHERE handle = ?
AND deleted_at IS NULL
`
func (q *Queries) CheckHandleExists(ctx context.Context, handle string) (bool, error) {
row := q.db.QueryRowContext(ctx, checkHandleExists, handle)
var handle_exists bool
err := row.Scan(&handle_exists)
return handle_exists, err
}
const createSession = `-- name: CreateSession :one
INSERT INTO sessions (
id,
browser_name,
browser_version,
client_ipaddr,
platform,
is_desktop,
is_mobile,
is_tablet,
is_tv,
is_bot,
challenge,
is_human_first,
is_human_last,
profile_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
RETURNING id, created_at, updated_at, deleted_at, browser_name, browser_version, client_ipaddr, platform, is_desktop, is_mobile, is_tablet, is_tv, is_bot, challenge, is_human_first, is_human_last, profile_id
`
type CreateSessionParams struct {
ID string
BrowserName string
BrowserVersion string
ClientIpaddr string
Platform string
IsDesktop bool
IsMobile bool
IsTablet bool
IsTv bool
IsBot bool
Challenge string
IsHumanFirst bool
IsHumanLast bool
ProfileID int64
}
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) (Session, error) {
row := q.db.QueryRowContext(ctx, createSession,
arg.ID,
arg.BrowserName,
arg.BrowserVersion,
arg.ClientIpaddr,
arg.Platform,
arg.IsDesktop,
arg.IsMobile,
arg.IsTablet,
arg.IsTv,
arg.IsBot,
arg.Challenge,
arg.IsHumanFirst,
arg.IsHumanLast,
arg.ProfileID,
)
var i Session
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.BrowserName,
&i.BrowserVersion,
&i.ClientIpaddr,
&i.Platform,
&i.IsDesktop,
&i.IsMobile,
&i.IsTablet,
&i.IsTv,
&i.IsBot,
&i.Challenge,
&i.IsHumanFirst,
&i.IsHumanLast,
&i.ProfileID,
)
return i, err
}
const getChallengeBySessionID = `-- name: GetChallengeBySessionID :one
SELECT challenge FROM sessions
WHERE id = ? AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetChallengeBySessionID(ctx context.Context, id string) (string, error) {
row := q.db.QueryRowContext(ctx, getChallengeBySessionID, id)
var challenge string
err := row.Scan(&challenge)
return challenge, err
}
const getCredentialByID = `-- name: GetCredentialByID :one
SELECT id, created_at, updated_at, deleted_at, handle, credential_id, authenticator_attachment, origin, type, transports FROM credentials
WHERE credential_id = ?
AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetCredentialByID(ctx context.Context, credentialID string) (Credential, error) {
row := q.db.QueryRowContext(ctx, getCredentialByID, credentialID)
var i Credential
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Handle,
&i.CredentialID,
&i.AuthenticatorAttachment,
&i.Origin,
&i.Type,
&i.Transports,
)
return i, err
}
const getCredentialsByHandle = `-- name: GetCredentialsByHandle :many
SELECT id, created_at, updated_at, deleted_at, handle, credential_id, authenticator_attachment, origin, type, transports FROM credentials
WHERE handle = ?
AND deleted_at IS NULL
`
func (q *Queries) GetCredentialsByHandle(ctx context.Context, handle string) ([]Credential, error) {
rows, err := q.db.QueryContext(ctx, getCredentialsByHandle, handle)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Credential
for rows.Next() {
var i Credential
if err := rows.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Handle,
&i.CredentialID,
&i.AuthenticatorAttachment,
&i.Origin,
&i.Type,
&i.Transports,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const getHumanVerificationNumbers = `-- name: GetHumanVerificationNumbers :one
SELECT is_human_first, is_human_last FROM sessions
WHERE id = ? AND deleted_at IS NULL
LIMIT 1
`
type GetHumanVerificationNumbersRow struct {
IsHumanFirst bool
IsHumanLast bool
}
func (q *Queries) GetHumanVerificationNumbers(ctx context.Context, id string) (GetHumanVerificationNumbersRow, error) {
row := q.db.QueryRowContext(ctx, getHumanVerificationNumbers, id)
var i GetHumanVerificationNumbersRow
err := row.Scan(&i.IsHumanFirst, &i.IsHumanLast)
return i, err
}
const getProfileByAddress = `-- name: GetProfileByAddress :one
SELECT id, created_at, updated_at, deleted_at, address, handle, origin, name FROM profiles
WHERE address = ? AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetProfileByAddress(ctx context.Context, address string) (Profile, error) {
row := q.db.QueryRowContext(ctx, getProfileByAddress, address)
var i Profile
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Address,
&i.Handle,
&i.Origin,
&i.Name,
)
return i, err
}
const getProfileByHandle = `-- name: GetProfileByHandle :one
SELECT id, created_at, updated_at, deleted_at, address, handle, origin, name FROM profiles
WHERE handle = ?
AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetProfileByHandle(ctx context.Context, handle string) (Profile, error) {
row := q.db.QueryRowContext(ctx, getProfileByHandle, handle)
var i Profile
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Address,
&i.Handle,
&i.Origin,
&i.Name,
)
return i, err
}
const getProfileByID = `-- name: GetProfileByID :one
SELECT id, created_at, updated_at, deleted_at, address, handle, origin, name FROM profiles
WHERE id = ? AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetProfileByID(ctx context.Context, id int64) (Profile, error) {
row := q.db.QueryRowContext(ctx, getProfileByID, id)
var i Profile
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Address,
&i.Handle,
&i.Origin,
&i.Name,
)
return i, err
}
const getSessionByClientIP = `-- name: GetSessionByClientIP :one
SELECT id, created_at, updated_at, deleted_at, browser_name, browser_version, client_ipaddr, platform, is_desktop, is_mobile, is_tablet, is_tv, is_bot, challenge, is_human_first, is_human_last, profile_id FROM sessions
WHERE client_ipaddr = ? AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetSessionByClientIP(ctx context.Context, clientIpaddr string) (Session, error) {
row := q.db.QueryRowContext(ctx, getSessionByClientIP, clientIpaddr)
var i Session
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.BrowserName,
&i.BrowserVersion,
&i.ClientIpaddr,
&i.Platform,
&i.IsDesktop,
&i.IsMobile,
&i.IsTablet,
&i.IsTv,
&i.IsBot,
&i.Challenge,
&i.IsHumanFirst,
&i.IsHumanLast,
&i.ProfileID,
)
return i, err
}
const getSessionByID = `-- name: GetSessionByID :one
SELECT id, created_at, updated_at, deleted_at, browser_name, browser_version, client_ipaddr, platform, is_desktop, is_mobile, is_tablet, is_tv, is_bot, challenge, is_human_first, is_human_last, profile_id FROM sessions
WHERE id = ? AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetSessionByID(ctx context.Context, id string) (Session, error) {
row := q.db.QueryRowContext(ctx, getSessionByID, id)
var i Session
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.BrowserName,
&i.BrowserVersion,
&i.ClientIpaddr,
&i.Platform,
&i.IsDesktop,
&i.IsMobile,
&i.IsTablet,
&i.IsTv,
&i.IsBot,
&i.Challenge,
&i.IsHumanFirst,
&i.IsHumanLast,
&i.ProfileID,
)
return i, err
}
const getVaultConfigByCID = `-- name: GetVaultConfigByCID :one
SELECT id, created_at, updated_at, deleted_at, handle, origin, address, cid, config, session_id, redirect_uri FROM vaults
WHERE cid = ?
AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetVaultConfigByCID(ctx context.Context, cid string) (Vault, error) {
row := q.db.QueryRowContext(ctx, getVaultConfigByCID, cid)
var i Vault
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Handle,
&i.Origin,
&i.Address,
&i.Cid,
&i.Config,
&i.SessionID,
&i.RedirectUri,
)
return i, err
}
const getVaultRedirectURIBySessionID = `-- name: GetVaultRedirectURIBySessionID :one
SELECT redirect_uri FROM vaults
WHERE session_id = ?
AND deleted_at IS NULL
LIMIT 1
`
func (q *Queries) GetVaultRedirectURIBySessionID(ctx context.Context, sessionID string) (string, error) {
row := q.db.QueryRowContext(ctx, getVaultRedirectURIBySessionID, sessionID)
var redirect_uri string
err := row.Scan(&redirect_uri)
return redirect_uri, err
}
const insertCredential = `-- name: InsertCredential :one
INSERT INTO credentials (
handle,
credential_id,
origin,
type,
transports
) VALUES (?, ?, ?, ?, ?)
RETURNING id, created_at, updated_at, deleted_at, handle, credential_id, authenticator_attachment, origin, type, transports
`
type InsertCredentialParams struct {
Handle string
CredentialID string
Origin string
Type string
Transports string
}
func (q *Queries) InsertCredential(ctx context.Context, arg InsertCredentialParams) (Credential, error) {
row := q.db.QueryRowContext(ctx, insertCredential,
arg.Handle,
arg.CredentialID,
arg.Origin,
arg.Type,
arg.Transports,
)
var i Credential
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Handle,
&i.CredentialID,
&i.AuthenticatorAttachment,
&i.Origin,
&i.Type,
&i.Transports,
)
return i, err
}
const insertProfile = `-- name: InsertProfile :one
INSERT INTO profiles (
address,
handle,
origin,
name
) VALUES (?, ?, ?, ?)
RETURNING id, created_at, updated_at, deleted_at, address, handle, origin, name
`
type InsertProfileParams struct {
Address string
Handle string
Origin string
Name string
}
func (q *Queries) InsertProfile(ctx context.Context, arg InsertProfileParams) (Profile, error) {
row := q.db.QueryRowContext(ctx, insertProfile,
arg.Address,
arg.Handle,
arg.Origin,
arg.Name,
)
var i Profile
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Address,
&i.Handle,
&i.Origin,
&i.Name,
)
return i, err
}
const softDeleteCredential = `-- name: SoftDeleteCredential :exec
UPDATE credentials
SET deleted_at = CURRENT_TIMESTAMP
WHERE credential_id = ?
`
func (q *Queries) SoftDeleteCredential(ctx context.Context, credentialID string) error {
_, err := q.db.ExecContext(ctx, softDeleteCredential, credentialID)
return err
}
const softDeleteProfile = `-- name: SoftDeleteProfile :exec
UPDATE profiles
SET deleted_at = CURRENT_TIMESTAMP
WHERE address = ?
`
func (q *Queries) SoftDeleteProfile(ctx context.Context, address string) error {
_, err := q.db.ExecContext(ctx, softDeleteProfile, address)
return err
}
const updateProfile = `-- name: UpdateProfile :one
UPDATE profiles
SET
name = ?,
handle = ?,
updated_at = CURRENT_TIMESTAMP
WHERE address = ?
AND deleted_at IS NULL
RETURNING id, created_at, updated_at, deleted_at, address, handle, origin, name
`
type UpdateProfileParams struct {
Name string
Handle string
Address string
}
func (q *Queries) UpdateProfile(ctx context.Context, arg UpdateProfileParams) (Profile, error) {
row := q.db.QueryRowContext(ctx, updateProfile, arg.Name, arg.Handle, arg.Address)
var i Profile
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.Address,
&i.Handle,
&i.Origin,
&i.Name,
)
return i, err
}
const updateSessionHumanVerification = `-- name: UpdateSessionHumanVerification :one
UPDATE sessions
SET
is_human_first = ?,
is_human_last = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
RETURNING id, created_at, updated_at, deleted_at, browser_name, browser_version, client_ipaddr, platform, is_desktop, is_mobile, is_tablet, is_tv, is_bot, challenge, is_human_first, is_human_last, profile_id
`
type UpdateSessionHumanVerificationParams struct {
IsHumanFirst bool
IsHumanLast bool
ID string
}
func (q *Queries) UpdateSessionHumanVerification(ctx context.Context, arg UpdateSessionHumanVerificationParams) (Session, error) {
row := q.db.QueryRowContext(ctx, updateSessionHumanVerification, arg.IsHumanFirst, arg.IsHumanLast, arg.ID)
var i Session
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.BrowserName,
&i.BrowserVersion,
&i.ClientIpaddr,
&i.Platform,
&i.IsDesktop,
&i.IsMobile,
&i.IsTablet,
&i.IsTv,
&i.IsBot,
&i.Challenge,
&i.IsHumanFirst,
&i.IsHumanLast,
&i.ProfileID,
)
return i, err
}
const updateSessionWithProfileID = `-- name: UpdateSessionWithProfileID :one
UPDATE sessions
SET
profile_id = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
RETURNING id, created_at, updated_at, deleted_at, browser_name, browser_version, client_ipaddr, platform, is_desktop, is_mobile, is_tablet, is_tv, is_bot, challenge, is_human_first, is_human_last, profile_id
`
type UpdateSessionWithProfileIDParams struct {
ProfileID int64
ID string
}
func (q *Queries) UpdateSessionWithProfileID(ctx context.Context, arg UpdateSessionWithProfileIDParams) (Session, error) {
row := q.db.QueryRowContext(ctx, updateSessionWithProfileID, arg.ProfileID, arg.ID)
var i Session
err := row.Scan(
&i.ID,
&i.CreatedAt,
&i.UpdatedAt,
&i.DeletedAt,
&i.BrowserName,
&i.BrowserVersion,
&i.ClientIpaddr,
&i.Platform,
&i.IsDesktop,
&i.IsMobile,
&i.IsTablet,
&i.IsTv,
&i.IsBot,
&i.Challenge,
&i.IsHumanFirst,
&i.IsHumanLast,
&i.ProfileID,
)
return i, err
}
+58
View File
@@ -0,0 +1,58 @@
package database
import (
ctx "github.com/onsonr/sonr/internal/context"
"github.com/go-webauthn/webauthn/protocol"
"github.com/labstack/echo/v4"
"github.com/medama-io/go-useragent"
"github.com/onsonr/sonr/internal/database/repository"
"github.com/segmentio/ksuid"
)
func BaseSessionCreateParams(e echo.Context) repository.CreateSessionParams {
// f := rand.Intn(5) + 1
// l := rand.Intn(4) + 1
challenge, _ := protocol.CreateChallenge()
id := getOrCreateSessionID(e)
ua := useragent.NewParser()
s := ua.Parse(e.Request().UserAgent())
return repository.CreateSessionParams{
ID: id,
BrowserName: s.GetBrowser(),
BrowserVersion: s.GetMajorVersion(),
ClientIpaddr: e.RealIP(),
Platform: s.GetOS(),
IsMobile: s.IsMobile(),
IsTablet: s.IsTablet(),
IsDesktop: s.IsDesktop(),
IsBot: s.IsBot(),
IsTv: s.IsTV(),
// IsHumanFirst: int64(f),
// IsHumanLast: int64(l),
Challenge: challenge.String(),
}
}
func getOrCreateSessionID(c echo.Context) string {
if ok := ctx.CookieExists(c, ctx.SessionID); !ok {
sessionID := ksuid.New().String()
ctx.WriteCookie(c, ctx.SessionID, sessionID)
return sessionID
}
sessionID, err := ctx.ReadCookie(c, ctx.SessionID)
if err != nil {
sessionID = ksuid.New().String()
ctx.WriteCookie(c, ctx.SessionID, sessionID)
}
return sessionID
}
func boolToInt64(b bool) int64 {
if b {
return 1
}
return 0
}
+8
View File
@@ -0,0 +1,8 @@
package sink
import (
_ "embed"
)
//go:embed schema.sql
var SchemaSQL string
+138
View File
@@ -0,0 +1,138 @@
-- name: InsertCredential :one
INSERT INTO credentials (
handle,
credential_id,
origin,
type,
transports
) VALUES (?, ?, ?, ?, ?)
RETURNING *;
-- name: InsertProfile :one
INSERT INTO profiles (
address,
handle,
origin,
name
) VALUES (?, ?, ?, ?)
RETURNING *;
-- name: GetProfileByID :one
SELECT * FROM profiles
WHERE id = ? AND deleted_at IS NULL
LIMIT 1;
-- name: GetProfileByAddress :one
SELECT * FROM profiles
WHERE address = ? AND deleted_at IS NULL
LIMIT 1;
-- name: GetChallengeBySessionID :one
SELECT challenge FROM sessions
WHERE id = ? AND deleted_at IS NULL
LIMIT 1;
-- name: GetHumanVerificationNumbers :one
SELECT is_human_first, is_human_last FROM sessions
WHERE id = ? AND deleted_at IS NULL
LIMIT 1;
-- name: GetSessionByID :one
SELECT * FROM sessions
WHERE id = ? AND deleted_at IS NULL
LIMIT 1;
-- name: GetSessionByClientIP :one
SELECT * FROM sessions
WHERE client_ipaddr = ? AND deleted_at IS NULL
LIMIT 1;
-- name: UpdateSessionHumanVerification :one
UPDATE sessions
SET
is_human_first = ?,
is_human_last = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
RETURNING *;
-- name: UpdateSessionWithProfileID :one
UPDATE sessions
SET
profile_id = ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?
RETURNING *;
-- name: CheckHandleExists :one
SELECT COUNT(*) > 0 as handle_exists FROM profiles
WHERE handle = ?
AND deleted_at IS NULL;
-- name: GetCredentialsByHandle :many
SELECT * FROM credentials
WHERE handle = ?
AND deleted_at IS NULL;
-- name: GetCredentialByID :one
SELECT * FROM credentials
WHERE credential_id = ?
AND deleted_at IS NULL
LIMIT 1;
-- name: SoftDeleteCredential :exec
UPDATE credentials
SET deleted_at = CURRENT_TIMESTAMP
WHERE credential_id = ?;
-- name: SoftDeleteProfile :exec
UPDATE profiles
SET deleted_at = CURRENT_TIMESTAMP
WHERE address = ?;
-- name: UpdateProfile :one
UPDATE profiles
SET
name = ?,
handle = ?,
updated_at = CURRENT_TIMESTAMP
WHERE address = ?
AND deleted_at IS NULL
RETURNING *;
-- name: GetProfileByHandle :one
SELECT * FROM profiles
WHERE handle = ?
AND deleted_at IS NULL
LIMIT 1;
-- name: GetVaultConfigByCID :one
SELECT * FROM vaults
WHERE cid = ?
AND deleted_at IS NULL
LIMIT 1;
-- name: GetVaultRedirectURIBySessionID :one
SELECT redirect_uri FROM vaults
WHERE session_id = ?
AND deleted_at IS NULL
LIMIT 1;
-- name: CreateSession :one
INSERT INTO sessions (
id,
browser_name,
browser_version,
client_ipaddr,
platform,
is_desktop,
is_mobile,
is_tablet,
is_tv,
is_bot,
challenge,
is_human_first,
is_human_last,
profile_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
RETURNING *;
+121
View File
@@ -0,0 +1,121 @@
-- Profiles represent user identities
CREATE TABLE profiles (
id TEXT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
address TEXT NOT NULL,
handle TEXT NOT NULL UNIQUE,
origin TEXT NOT NULL,
name TEXT NOT NULL,
UNIQUE(address, origin)
);
-- Accounts represent blockchain accounts
CREATE TABLE accounts (
id TEXT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
number INTEGER NOT NULL,
sequence INTEGER NOT NULL DEFAULT 0,
address TEXT NOT NULL UNIQUE,
public_key TEXT NOT NULL CHECK(json_valid(public_key)),
chain_id TEXT NOT NULL,
controller TEXT NOT NULL,
is_subsidiary BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_subsidiary IN (0,1)),
is_validator BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_validator IN (0,1)),
is_delegator BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_delegator IN (0,1)),
is_accountable BOOLEAN NOT NULL DEFAULT TRUE CHECK(is_accountable IN (0,1))
);
-- Assets represent tokens and coins
CREATE TABLE assets (
id TEXT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
name TEXT NOT NULL,
symbol TEXT NOT NULL,
decimals INTEGER NOT NULL CHECK(decimals >= 0),
chain_id TEXT NOT NULL,
channel TEXT NOT NULL,
asset_type TEXT NOT NULL,
coingecko_id TEXT,
UNIQUE(chain_id, symbol)
);
-- Credentials store WebAuthn credentials
CREATE TABLE credentials (
id TEXT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
handle TEXT NOT NULL,
credential_id TEXT NOT NULL UNIQUE,
authenticator_attachment TEXT NOT NULL,
origin TEXT NOT NULL,
type TEXT NOT NULL,
transports TEXT NOT NULL
);
-- Sessions track user authentication state
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
browser_name TEXT NOT NULL,
browser_version TEXT NOT NULL,
client_ipaddr TEXT NOT NULL,
platform TEXT NOT NULL,
is_desktop BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_desktop IN (0,1)),
is_mobile BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_mobile IN (0,1)),
is_tablet BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_tablet IN (0,1)),
is_tv BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_tv IN (0,1)),
is_bot BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_bot IN (0,1)),
challenge TEXT NOT NULL,
is_human_first BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_human_first IN (0,1)),
is_human_last BOOLEAN NOT NULL DEFAULT FALSE CHECK(is_human_last IN (0,1)),
profile_id INTEGER NOT NULL
);
-- Vaults store encrypted data
CREATE TABLE vaults (
id TEXT PRIMARY KEY,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP,
handle TEXT NOT NULL,
origin TEXT NOT NULL,
address TEXT NOT NULL,
cid TEXT NOT NULL UNIQUE,
config TEXT NOT NULL CHECK(json_valid(config)),
session_id TEXT NOT NULL,
redirect_uri TEXT NOT NULL
);
-- Indexes for common queries
CREATE INDEX idx_profiles_handle ON profiles(handle);
CREATE INDEX idx_profiles_address ON profiles(address);
CREATE INDEX idx_profiles_deleted_at ON profiles(deleted_at);
CREATE INDEX idx_accounts_address ON accounts(address);
CREATE INDEX idx_accounts_chain_id ON accounts(chain_id);
CREATE INDEX idx_accounts_deleted_at ON accounts(deleted_at);
CREATE INDEX idx_assets_symbol ON assets(symbol);
CREATE INDEX idx_assets_chain_id ON assets(chain_id);
CREATE INDEX idx_assets_deleted_at ON assets(deleted_at);
CREATE INDEX idx_credentials_handle ON credentials(handle);
CREATE INDEX idx_credentials_origin ON credentials(origin);
CREATE INDEX idx_credentials_deleted_at ON credentials(deleted_at);
CREATE INDEX idx_sessions_profile_id ON sessions(profile_id);
CREATE INDEX idx_sessions_client_ipaddr ON sessions(client_ipaddr);
CREATE INDEX idx_sessions_deleted_at ON sessions(deleted_at);
CREATE INDEX idx_vaults_handle ON vaults(handle);
CREATE INDEX idx_vaults_session_id ON vaults(session_id);
CREATE INDEX idx_vaults_deleted_at ON vaults(deleted_at);
+9
View File
@@ -0,0 +1,9 @@
version: "2"
sql:
- engine: "sqlite"
queries: "./sink/query.sql"
schema: "./sink/schema.sql"
gen:
go:
package: "repository"
out: "repository"