feat(models): add settings and auth models

This commit is contained in:
2026-01-07 12:38:33 -05:00
parent c551a08641
commit b16c44170e
7 changed files with 3832 additions and 0 deletions

103
models/auth.go Normal file
View File

@@ -0,0 +1,103 @@
package models
// AppInfo represents an application requesting authorization
type AppInfo struct {
Name string
Domain string
LogoIcon string
Verified bool
}
// WalletInfo represents a user's wallet details
type WalletInfo struct {
Name string
Address string
Balance string
}
// TokenAmount represents a token amount with its value
type TokenAmount struct {
Symbol string
Amount string
USD string
Initials string
}
// TxDetails represents transaction details for authorization
type TxDetails struct {
Type string
FromToken TokenAmount
ToToken TokenAmount
Network string
NetworkFee string
MaxFee string
Slippage string
Contract string
Function string
RawData string
}
// AuthRequest represents an authorization request from an app
type AuthRequest struct {
Type string
App AppInfo
Wallet WalletInfo
Message string
MessageHex string
Transaction *TxDetails
}
// DefaultAuthRequest returns a sample authorization request for testing
func DefaultAuthRequest(reqType string) AuthRequest {
if reqType == "" {
reqType = "connect"
}
return AuthRequest{
Type: reqType,
App: AppInfo{
Name: "Uniswap",
Domain: "app.uniswap.org",
LogoIcon: "cube",
Verified: true,
},
Wallet: WalletInfo{
Name: "Main Wallet",
Address: "sonr1x9f...7k2m",
Balance: "1,234.56 SNR",
},
Message: `Welcome to Uniswap!
Click to sign in and accept the Uniswap Terms of Service.
This request will not trigger a blockchain transaction or cost any gas fees.
Wallet address:
sonr1x9f4h2k8m3n5p7q2r4s6t8v0w3x5y7z9a1b3c5d7k2m
Nonce: 8f4a2b1c`,
MessageHex: "0x57656c636f6d6520746f20556e697377617021...",
Transaction: &TxDetails{
Type: "Swap",
FromToken: TokenAmount{
Symbol: "ETH",
Amount: "100.00",
USD: "$234,567.00",
Initials: "E",
},
ToToken: TokenAmount{
Symbol: "USDC",
Amount: "125,000",
USD: "$125,000.00",
Initials: "U",
},
Network: "Sonr Mainnet",
NetworkFee: "~$0.12",
MaxFee: "$0.26",
Slippage: "0.5%",
Contract: "0x7a25...3f8b",
Function: "swapExactTokensForTokens()",
RawData: "0x38ed1739\n0000000000000000000000000000000000000056bc75e2d63100000...",
},
}
}

163
models/dashboard.go Normal file
View File

@@ -0,0 +1,163 @@
package models
// Token represents a cryptocurrency token in the wallet
type Token struct {
Symbol string
Name string
Balance string
Value string
Change string
Positive bool
Color string
Initials string
Network string
}
// Transaction represents a wallet transaction
type Transaction struct {
Type string
Asset string
Amount string
USD string
Date string
Time string
Hash string
Positive bool
Address string
}
// NFT represents a non-fungible token in the wallet
type NFT struct {
Name string
Collection string
Image string
Floor string
Value string
Badge string
Verified bool
}
type AreaSeriesData struct {
Date string `json:"date"`
Industry string `json:"industry"`
Value float64 `json:"value"`
}
type BubbleData struct {
Name string `json:"name"`
Sector string `json:"sector"`
Value float64 `json:"value"`
}
// DashboardData holds all data for the dashboard view
type DashboardData struct {
TotalBalance string
Change24h string
Tokens []Token
Transactions []Transaction
NFTs []NFT
PortfolioChart []AreaSeriesData
MarketCapBubble []BubbleData
}
// DefaultTokens returns sample token data
func DefaultTokens() []Token {
return []Token{
{Symbol: "SNR", Name: "Sonr", Balance: "8,432.50", Value: "$4,216.25", Change: "+5.67%", Positive: true, Color: "linear-gradient(135deg, #17c2ff, #0090ff)", Initials: "S", Network: "Sonr Mainnet"},
{Symbol: "ETH", Name: "Ethereum", Balance: "2.847", Value: "$6,682.04", Change: "+3.24%", Positive: true, Color: "#627eea", Initials: "E", Network: "Ethereum"},
{Symbol: "USDC", Name: "USD Coin", Balance: "1,250.00", Value: "$1,250.00", Change: "0.00%", Positive: true, Color: "#2775ca", Initials: "U", Network: "Ethereum"},
{Symbol: "AVAX", Name: "Avalanche", Balance: "24.83", Value: "$699.03", Change: "-2.18%", Positive: false, Color: "#e84142", Initials: "A", Network: "Avalanche"},
}
}
// DefaultTransactions returns sample transaction data
func DefaultTransactions() []Transaction {
return []Transaction{
{Type: "receive", Asset: "ETH", Amount: "+0.25 ETH", USD: "$586.25", Date: "Today", Time: "2:34 PM", Hash: "0x8f4a2b1c...", Positive: true, Address: "0x742d...35Cb"},
{Type: "send", Asset: "SNR", Amount: "-500 SNR", USD: "$250.00", Date: "Yesterday", Time: "11:22 AM", Hash: "0x7d3e2a1b...", Positive: false, Address: "sonr1k4m...9p3q"},
{Type: "swap", Asset: "ETH -> USDC", Amount: "0.5 ETH", USD: "-> 1,172.50 USDC", Date: "Jan 1", Time: "9:15 AM", Hash: "0x1a2b3c4d...", Positive: true, Address: "Uniswap V3"},
}
}
// DefaultNFTs returns sample NFT data
func DefaultNFTs() []NFT {
return []NFT{
{Name: "Bored Ape #4521", Collection: "Bored Ape Yacht Club", Image: "https://images.unsplash.com/photo-1620641788421-7a1c342ea42e?w=400&h=400&fit=crop", Floor: "28.5 ETH", Value: "32.0 ETH", Badge: "Listed", Verified: true},
{Name: "Sonr Genesis #001", Collection: "Sonr Genesis", Image: "https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=400&h=400&fit=crop", Floor: "0.8 ETH", Value: "2.5 ETH", Badge: "Rare", Verified: true},
}
}
// DefaultPortfolioChartData returns sample stacked area data for portfolio performance
func DefaultPortfolioChartData() []AreaSeriesData {
return []AreaSeriesData{
// Day 1
{Date: "2024-12-25", Industry: "ETH", Value: 3200},
{Date: "2024-12-25", Industry: "SNR", Value: 2100},
{Date: "2024-12-25", Industry: "USDC", Value: 1200},
{Date: "2024-12-25", Industry: "AVAX", Value: 500},
// Day 2
{Date: "2024-12-26", Industry: "ETH", Value: 3350},
{Date: "2024-12-26", Industry: "SNR", Value: 2200},
{Date: "2024-12-26", Industry: "USDC", Value: 1200},
{Date: "2024-12-26", Industry: "AVAX", Value: 520},
// Day 3
{Date: "2024-12-27", Industry: "ETH", Value: 3500},
{Date: "2024-12-27", Industry: "SNR", Value: 2350},
{Date: "2024-12-27", Industry: "USDC", Value: 1200},
{Date: "2024-12-27", Industry: "AVAX", Value: 480},
// Day 4
{Date: "2024-12-28", Industry: "ETH", Value: 3280},
{Date: "2024-12-28", Industry: "SNR", Value: 2400},
{Date: "2024-12-28", Industry: "USDC", Value: 1200},
{Date: "2024-12-28", Industry: "AVAX", Value: 510},
// Day 5
{Date: "2024-12-29", Industry: "ETH", Value: 3450},
{Date: "2024-12-29", Industry: "SNR", Value: 2550},
{Date: "2024-12-29", Industry: "USDC", Value: 1250},
{Date: "2024-12-29", Industry: "AVAX", Value: 530},
// Day 6
{Date: "2024-12-30", Industry: "ETH", Value: 3600},
{Date: "2024-12-30", Industry: "SNR", Value: 2680},
{Date: "2024-12-30", Industry: "USDC", Value: 1250},
{Date: "2024-12-30", Industry: "AVAX", Value: 550},
// Day 7
{Date: "2024-12-31", Industry: "ETH", Value: 3750},
{Date: "2024-12-31", Industry: "SNR", Value: 2800},
{Date: "2024-12-31", Industry: "USDC", Value: 1250},
{Date: "2024-12-31", Industry: "AVAX", Value: 580},
// Day 8
{Date: "2025-01-01", Industry: "ETH", Value: 3680},
{Date: "2025-01-01", Industry: "SNR", Value: 2900},
{Date: "2025-01-01", Industry: "USDC", Value: 1250},
{Date: "2025-01-01", Industry: "AVAX", Value: 600},
}
}
// DefaultMarketCapBubbleData returns sample bubble chart data for market cap dominance
func DefaultMarketCapBubbleData() []BubbleData {
return []BubbleData{
{Name: "BTC", Sector: "Layer 1", Value: 45000},
{Name: "ETH", Sector: "Layer 1", Value: 28000},
{Name: "SNR", Sector: "Layer 1", Value: 8500},
{Name: "SOL", Sector: "Layer 1", Value: 12000},
{Name: "AVAX", Sector: "Layer 1", Value: 6000},
{Name: "USDC", Sector: "Stablecoin", Value: 15000},
{Name: "USDT", Sector: "Stablecoin", Value: 18000},
{Name: "UNI", Sector: "DeFi", Value: 4500},
{Name: "AAVE", Sector: "DeFi", Value: 3200},
{Name: "LINK", Sector: "Oracle", Value: 5800},
}
}
// DefaultDashboardData returns a complete dashboard data set with sample data
func DefaultDashboardData() DashboardData {
return DashboardData{
TotalBalance: "12847.32",
Change24h: "+$302.18",
Tokens: DefaultTokens(),
Transactions: DefaultTransactions(),
NFTs: DefaultNFTs(),
PortfolioChart: DefaultPortfolioChartData(),
MarketCapBubble: DefaultMarketCapBubbleData(),
}
}

15
models/login.go Normal file
View File

@@ -0,0 +1,15 @@
package models
// LoginState holds the current login flow state
type LoginState struct {
Step string
Method string
Error string
}
// DefaultLoginState returns a new login state at step 1
func DefaultLoginState() LoginState {
return LoginState{
Step: "1",
}
}

32
models/register.go Normal file
View File

@@ -0,0 +1,32 @@
package models
// DeviceCapabilities holds WebAuthn capability detection results
type DeviceCapabilities struct {
Platform bool // Biometrics (Face ID, Touch ID, Windows Hello)
CrossPlatform bool // Security keys (YubiKey, etc.)
Conditional bool // Passkey autofill support
}
// RegisterState holds the current registration flow state
type RegisterState struct {
Step int
Method string // "passkey", "security-key", or "qr-code"
Username string
Error string
}
// DefaultRegisterState returns a new registration state at step 1
func DefaultRegisterState() RegisterState {
return RegisterState{
Step: 1,
}
}
// DefaultDeviceCapabilities returns capabilities assuming full support (for testing)
func DefaultDeviceCapabilities() DeviceCapabilities {
return DeviceCapabilities{
Platform: true,
CrossPlatform: true,
Conditional: true,
}
}

225
models/settings.go Normal file
View File

@@ -0,0 +1,225 @@
package models
import "time"
type SocialLinks struct {
Twitter string
GitHub string
Discord string
}
type ProfileSettings struct {
AvatarURL string
Initials string
DisplayName string
Username string
Bio string
Website string
SocialLinks SocialLinks
Visibility string
}
type Device struct {
ID string
Name string
Type string
Browser string
OS string
AuthType string
AddedAt time.Time
LastUsed time.Time
IsCurrent bool
}
type OAuthScope struct {
Name string
Description string
Enabled bool
Required bool
}
type AuthorizedClient struct {
ID string
Name string
Domain string
Initials string
Color string
Status string
}
type OAuthSettings struct {
DefaultScopes []OAuthScope
SessionDuration string
ConsentPrompt string
Clients []AuthorizedClient
}
type NotificationItem struct {
Key string
Title string
Description string
Enabled bool
Threshold int
}
type NotificationPrefs struct {
SecurityAlerts []NotificationItem
Transactions []NotificationItem
Apps []NotificationItem
Marketing []NotificationItem
}
type Email struct {
ID string
Address string
IsPrimary bool
IsVerified bool
AddedAt time.Time
}
type Phone struct {
ID string
Number string
IsPrimary bool
IsVerified bool
AddedAt time.Time
Use2FA bool
}
type SMSSettings struct {
Enabled bool
RecoveryCodes bool
}
type APIKey struct {
ID string
Name string
KeyPreview string
KeyFull string
Environment string
Permissions string
Status string
CreatedAt time.Time
}
type Webhook struct {
ID string
URL string
Description string
Events []string
Status string
LastTriggered time.Time
FailureCount int
}
type OAuthAppConfig struct {
ClientID string
ClientSecret string
RedirectURIs []string
}
type DeveloperSettings struct {
APIKeys []APIKey
Webhooks []Webhook
OAuthApp OAuthAppConfig
DebugMode bool
TestMode bool
ShowRaw bool
}
type SettingsData struct {
Profile ProfileSettings
Devices []Device
OAuth OAuthSettings
Notifications NotificationPrefs
Emails []Email
Phones []Phone
SMSSettings SMSSettings
Developer DeveloperSettings
}
func DefaultSettingsData() SettingsData {
return SettingsData{
Profile: ProfileSettings{
Initials: "JD",
DisplayName: "John Doe",
Username: "johndoe",
Bio: "Web3 enthusiast and DeFi explorer. Building on Sonr.",
Website: "https://johndoe.dev",
Visibility: "public",
},
Devices: []Device{
{ID: "dev-1", Name: "MacBook Pro", Type: "laptop", Browser: "Chrome", OS: "macOS", AuthType: "Touch ID", AddedAt: time.Now().AddDate(0, 0, -20), LastUsed: time.Now(), IsCurrent: true},
{ID: "dev-2", Name: "iPhone 15 Pro", Type: "mobile", Browser: "Safari", OS: "iOS", AuthType: "Face ID", AddedAt: time.Now().AddDate(0, 0, -25), LastUsed: time.Now().Add(-2 * time.Hour), IsCurrent: false},
{ID: "dev-3", Name: "YubiKey 5C", Type: "key", Browser: "", OS: "", AuthType: "FIDO2", AddedAt: time.Now().AddDate(0, -1, -7), LastUsed: time.Now().AddDate(0, 0, -5), IsCurrent: false},
{ID: "dev-4", Name: "Windows Desktop", Type: "desktop", Browser: "Firefox", OS: "Windows", AuthType: "Windows Hello", AddedAt: time.Now().AddDate(0, -2, 0), LastUsed: time.Now().AddDate(0, 0, -14), IsCurrent: false},
},
OAuth: OAuthSettings{
DefaultScopes: []OAuthScope{
{Name: "openid", Description: "Basic identity information (required)", Enabled: true, Required: true},
{Name: "profile", Description: "Display name and avatar", Enabled: true, Required: false},
{Name: "email", Description: "Email address access", Enabled: false, Required: false},
{Name: "wallet:read", Description: "View wallet balances", Enabled: false, Required: false},
},
SessionDuration: "7d",
ConsentPrompt: "first",
Clients: []AuthorizedClient{
{ID: "client-1", Name: "Uniswap", Domain: "app.uniswap.org", Initials: "U", Color: "linear-gradient(135deg, #ff007a, #ff5ca0)", Status: "active"},
{ID: "client-2", Name: "OpenSea", Domain: "opensea.io", Initials: "O", Color: "linear-gradient(135deg, #627eea, #4c63d2)", Status: "idle"},
},
},
Notifications: NotificationPrefs{
SecurityAlerts: []NotificationItem{
{Key: "security.new_device", Title: "New device login", Description: "When your account is accessed from a new device", Enabled: true},
{Key: "security.suspicious", Title: "Suspicious activity", Description: "Unusual login attempts or access patterns", Enabled: true},
{Key: "security.password", Title: "Password changes", Description: "When security credentials are modified", Enabled: true},
},
Transactions: []NotificationItem{
{Key: "tx.incoming", Title: "Incoming transfers", Description: "When you receive tokens or NFTs", Enabled: true},
{Key: "tx.outgoing", Title: "Outgoing transfers", Description: "Confirmation of sent transactions", Enabled: true},
{Key: "tx.failed", Title: "Failed transactions", Description: "When a transaction fails or is reverted", Enabled: true},
{Key: "tx.large", Title: "Large transactions", Description: "Transactions above threshold", Enabled: true, Threshold: 1000},
},
Apps: []NotificationItem{
{Key: "app.connection", Title: "New app connections", Description: "When a new app connects to your wallet", Enabled: true},
{Key: "app.signature", Title: "Signature requests", Description: "When an app requests a signature", Enabled: true},
{Key: "app.permission", Title: "Permission changes", Description: "When app permissions are modified", Enabled: false},
},
Marketing: []NotificationItem{
{Key: "marketing.updates", Title: "Product updates", Description: "New features and improvements", Enabled: false},
{Key: "marketing.newsletter", Title: "Newsletter", Description: "Weekly digest of Sonr ecosystem news", Enabled: false},
},
},
Emails: []Email{
{ID: "email-1", Address: "john.doe@example.com", IsPrimary: true, IsVerified: true, AddedAt: time.Now().AddDate(0, 0, -20)},
{ID: "email-2", Address: "johndoe.work@company.io", IsPrimary: false, IsVerified: true, AddedAt: time.Now().AddDate(0, -1, -15)},
{ID: "email-3", Address: "backup@gmail.com", IsPrimary: false, IsVerified: false, AddedAt: time.Now().AddDate(0, 0, -2)},
},
Phones: []Phone{
{ID: "phone-1", Number: "+1 (555) 123-4567", IsPrimary: true, IsVerified: true, AddedAt: time.Now().AddDate(0, 0, -20), Use2FA: true},
{ID: "phone-2", Number: "+44 7700 900123", IsPrimary: false, IsVerified: true, AddedAt: time.Now().AddDate(0, -2, -10), Use2FA: false},
},
SMSSettings: SMSSettings{
Enabled: true,
RecoveryCodes: false,
},
Developer: DeveloperSettings{
APIKeys: []APIKey{
{ID: "key-1", Name: "Production Key", KeyPreview: "sk_live_••••••••••••••••••••••••3f8b", KeyFull: "sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f23f8b", Environment: "live", Permissions: "full", Status: "active", CreatedAt: time.Now().AddDate(0, 0, -35)},
{ID: "key-2", Name: "Test Key", KeyPreview: "sk_test_••••••••••••••••••••••••9a2c", KeyFull: "sk_test_z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4z3y2x1w0v9u89a2c", Environment: "test", Permissions: "full", Status: "active", CreatedAt: time.Now().AddDate(0, 0, -35)},
},
Webhooks: []Webhook{
{ID: "wh-1", URL: "https://api.myapp.com/webhooks/sonr", Description: "Main webhook", Events: []string{"*"}, Status: "active", LastTriggered: time.Now().Add(-2 * time.Hour), FailureCount: 0},
{ID: "wh-2", URL: "https://hooks.slack.com/services/...", Description: "Slack notifications", Events: []string{"transaction.*"}, Status: "failing", LastTriggered: time.Now().Add(-1 * time.Hour), FailureCount: 3},
},
OAuthApp: OAuthAppConfig{
ClientID: "sonr_client_a1b2c3d4e5f6",
ClientSecret: "sonr_secret_x9y8z7w6v5u4t3s2r1",
RedirectURIs: []string{"https://myapp.com/auth/callback", "http://localhost:3000/auth/callback"},
},
DebugMode: false,
TestMode: true,
ShowRaw: false,
},
}
}

1142
views/settings.templ Normal file

File diff suppressed because it is too large Load Diff

2152
views/settings_templ.go Normal file

File diff suppressed because it is too large Load Diff