refactor: Flatten directory structure
Move project files from uzdb/ subdirectory to root directory for cleaner project structure.
Changes:
- Move frontend/ to root
- Move internal/ to root
- Move build/ to root
- Move all config files (go.mod, wails.json, etc.) to root
- Remove redundant uzdb/ subdirectory nesting
Project structure is now:
├── frontend/ # React application
├── internal/ # Go backend
├── build/ # Wails build assets
├── doc/ # Design documentation
├── main.go # Entry point
└── ...
🤖 Generated with Qoder
This commit is contained in:
136
internal/utils/errors.go
Normal file
136
internal/utils/errors.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GenerateID generates a unique ID (UUID-like)
|
||||
func GenerateID() string {
|
||||
b := make([]byte, 16)
|
||||
rand.Read(b)
|
||||
return formatUUID(b)
|
||||
}
|
||||
|
||||
// formatUUID formats bytes as UUID string
|
||||
func formatUUID(b []byte) string {
|
||||
uuid := make([]byte, 36)
|
||||
hex.Encode(uuid[0:8], b[0:4])
|
||||
hex.Encode(uuid[9:13], b[4:6])
|
||||
hex.Encode(uuid[14:18], b[6:8])
|
||||
hex.Encode(uuid[19:23], b[8:10])
|
||||
hex.Encode(uuid[24:], b[10:])
|
||||
uuid[8] = '-'
|
||||
uuid[13] = '-'
|
||||
uuid[18] = '-'
|
||||
uuid[23] = '-'
|
||||
return string(uuid)
|
||||
}
|
||||
|
||||
// FormatDuration formats duration in milliseconds
|
||||
func FormatDuration(d time.Duration) int64 {
|
||||
return d.Milliseconds()
|
||||
}
|
||||
|
||||
// SanitizeSQL removes potentially dangerous SQL patterns
|
||||
// Note: This is not a replacement for parameterized queries
|
||||
func SanitizeSQL(sql string) string {
|
||||
// Remove multiple semicolons
|
||||
sql = strings.ReplaceAll(sql, ";;", ";")
|
||||
// Trim whitespace
|
||||
sql = strings.TrimSpace(sql)
|
||||
return sql
|
||||
}
|
||||
|
||||
// TruncateString truncates a string to max length
|
||||
func TruncateString(s string, maxLen int) string {
|
||||
if len(s) <= maxLen {
|
||||
return s
|
||||
}
|
||||
return s[:maxLen]
|
||||
}
|
||||
|
||||
// GenerateRandomBytes generates random bytes
|
||||
func GenerateRandomBytes(n int) ([]byte, error) {
|
||||
b := make([]byte, n)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate random bytes: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// EncodeBase64 encodes bytes to base64 string
|
||||
func EncodeBase64(data []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(data)
|
||||
}
|
||||
|
||||
// DecodeBase64 decodes base64 string to bytes
|
||||
func DecodeBase64(s string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(s)
|
||||
}
|
||||
|
||||
// MaskPassword masks password for logging
|
||||
func MaskPassword(password string) string {
|
||||
if len(password) <= 4 {
|
||||
return strings.Repeat("*", len(password))
|
||||
}
|
||||
return password[:2] + strings.Repeat("*", len(password)-2)
|
||||
}
|
||||
|
||||
// ContainsAny checks if string contains any of the substrings
|
||||
func ContainsAny(s string, substrings ...string) bool {
|
||||
for _, sub := range substrings {
|
||||
if strings.Contains(s, sub) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsReadOnlyQuery checks if SQL query is read-only
|
||||
func IsReadOnlyQuery(sql string) bool {
|
||||
sql = strings.TrimSpace(strings.ToUpper(sql))
|
||||
|
||||
// Read-only operations
|
||||
readOnlyPrefixes := []string{
|
||||
"SELECT",
|
||||
"SHOW",
|
||||
"DESCRIBE",
|
||||
"EXPLAIN",
|
||||
"WITH",
|
||||
}
|
||||
|
||||
for _, prefix := range readOnlyPrefixes {
|
||||
if strings.HasPrefix(sql, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsDDLQuery checks if SQL query is DDL
|
||||
func IsDDLQuery(sql string) bool {
|
||||
sql = strings.TrimSpace(strings.ToUpper(sql))
|
||||
|
||||
ddlKeywords := []string{
|
||||
"CREATE",
|
||||
"ALTER",
|
||||
"DROP",
|
||||
"TRUNCATE",
|
||||
"RENAME",
|
||||
}
|
||||
|
||||
for _, keyword := range ddlKeywords {
|
||||
if strings.HasPrefix(sql, keyword) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user