fix metagen deps

This commit is contained in:
2025-03-09 16:42:08 -04:00
parent 78cd5cc2bb
commit 963b83534c
10 changed files with 95 additions and 92 deletions

View File

@@ -4,7 +4,7 @@ import (
"crypto/rand" "crypto/rand"
"errors" "errors"
"math/big" "math/big"
"maxwarden/config" "maxwarden/constants"
"maxwarden/entries" "maxwarden/entries"
"maxwarden/security" "maxwarden/security"
"maxwarden/users" "maxwarden/users"
@@ -28,7 +28,7 @@ type Identity struct {
} }
func NewIdentity(userid int32, securityStamp string, masterKey string, rememberMe bool) *Identity { func NewIdentity(userid int32, securityStamp string, masterKey string, rememberMe bool) *Identity {
expirationDuration := time.Duration(time.Hour * 24 * time.Duration(config.IDENTITY_COOKIE_EXPIRY_DAYS)) expirationDuration := time.Duration(time.Hour * 24 * time.Duration(constants.IDENTITY_COOKIE_EXPIRY_DAYS))
expiration := time.Now().Add(expirationDuration) expiration := time.Now().Add(expirationDuration)
// hash password input // hash password input
@@ -63,7 +63,7 @@ func Authenticate(username string, password string) (int32, string, bool) {
user, userErr := users.FetchByUsername(username) user, userErr := users.FetchByUsername(username)
if userErr != nil || user.FailedAttempts > int32(config.MAX_LOGIN_ATTEMPTS) { if userErr != nil || user.FailedAttempts > int32(constants.MAX_LOGIN_ATTEMPTS) {
// set user password to dummy password to keep timing consistent when validating password // set user password to dummy password to keep timing consistent when validating password
user.Password = "$2a$14$KW5OO1wZqGGq3SrpBFj0Oema5DG8Ph7lZJvq0ECkkYBpNFom6b9vO" user.Password = "$2a$14$KW5OO1wZqGGq3SrpBFj0Oema5DG8Ph7lZJvq0ECkkYBpNFom6b9vO"
security.ComparePasswords(password, user.Password) security.ComparePasswords(password, user.Password)
@@ -95,7 +95,7 @@ func Authenticate(username string, password string) (int32, string, bool) {
// } // }
mk := security.SHA512_58(password) mk := security.SHA512_58(password)
user.Data, _ = security.EncryptDataWithKey(&secrets, mk) user.Data, _ = security.EncryptData(&secrets, mk)
} }
users.Update(user) users.Update(user)
@@ -109,8 +109,8 @@ func CheckPasswordCriteria(password string) error {
return errors.New("Password cannot be blank.") return errors.New("Password cannot be blank.")
} }
if len(password) < config.PASSWORD_MIN_LENGTH { if len(password) < constants.PASSWORD_MIN_LENGTH {
return errors.New("Password must be at least " + strconv.Itoa(config.PASSWORD_MIN_LENGTH) + " characters long.") return errors.New("Password must be at least " + strconv.Itoa(constants.PASSWORD_MIN_LENGTH) + " characters long.")
} }
uppercaseCount := 0 uppercaseCount := 0
@@ -136,20 +136,20 @@ func CheckPasswordCriteria(password string) error {
} }
} }
if uppercaseCount < config.PASSWORD_REQUIRED_UPPERCASE { if uppercaseCount < constants.PASSWORD_REQUIRED_UPPERCASE {
return errors.New("Password must contain at least " + strconv.Itoa(config.PASSWORD_REQUIRED_UPPERCASE) + " uppercase character(s).") return errors.New("Password must contain at least " + strconv.Itoa(constants.PASSWORD_REQUIRED_UPPERCASE) + " uppercase character(s).")
} }
if lowercaseCount < config.PASSWORD_REQUIRED_LOWERCASE { if lowercaseCount < constants.PASSWORD_REQUIRED_LOWERCASE {
return errors.New("Password must contain at least " + strconv.Itoa(config.PASSWORD_REQUIRED_LOWERCASE) + " lowercase character(s).") return errors.New("Password must contain at least " + strconv.Itoa(constants.PASSWORD_REQUIRED_LOWERCASE) + " lowercase character(s).")
} }
if numberCount < config.PASSWORD_REQUIRED_NUMBERS { if numberCount < constants.PASSWORD_REQUIRED_NUMBERS {
return errors.New("Password must contain at least " + strconv.Itoa(config.PASSWORD_REQUIRED_NUMBERS) + " number(s).") return errors.New("Password must contain at least " + strconv.Itoa(constants.PASSWORD_REQUIRED_NUMBERS) + " number(s).")
} }
if symbolCount < config.PASSWORD_REQUIRED_SYMBOLS { if symbolCount < constants.PASSWORD_REQUIRED_SYMBOLS {
return errors.New("Password must contain at least " + strconv.Itoa(config.PASSWORD_REQUIRED_SYMBOLS) + " symbol(s).") return errors.New("Password must contain at least " + strconv.Itoa(constants.PASSWORD_REQUIRED_SYMBOLS) + " symbol(s).")
} }
return nil return nil

View File

@@ -20,7 +20,7 @@ func main() {
} }
masterKey := security.SHA512_58(os.Args[1]) masterKey := security.SHA512_58(os.Args[1])
cryptData, _ := security.EncryptDataWithKey(&testData, masterKey) cryptData, _ := security.EncryptData(&testData, masterKey)
println(passHash) println(passHash)
println(cryptData) println(cryptData)

View File

@@ -10,34 +10,6 @@ import (
"github.com/joho/godotenv" "github.com/joho/godotenv"
) )
const (
SESSION_COOKIE_NAME = "_maxwarden_session"
SESSION_COOKIE_EXPIRY_DAYS int = 100
SESSION_COOKIE_ENTROPY int = 33
IDENTITY_COOKIE_NAME string = "_maxwarden_identity"
IDENTITY_COOKIE_EXPIRY_DAYS int = 30
IDENTITY_TOKEN_EXPIRY_DAYS int = 30
IDENTITY_COOKIE_ENTROPY int = 33
IDENTITY_LOGIN_PATH string = "/auth/login"
IDENTITY_LOGOUT_PATH string = "/auth/logout"
IDENTITY_DEFAULT_PATH string = "/app"
IDENTITY_AUTH_REDIRECT bool = true
IDENTITY_AUTH_KEY string = "CORRECT_HORSE_BATTERY_STAPLE"
// This key is NOT used for the hashing of passwords, or secure session data over the wire.
// It is ONLY used for performing quick file and string hashes, where security is not a factor.
DATA_HASH_KEY string = "01234567890123456789012345678901"
PASSWORD_MIN_LENGTH int = 8
PASSWORD_REQUIRED_UPPERCASE int = 1
PASSWORD_REQUIRED_LOWERCASE int = 1
PASSWORD_REQUIRED_NUMBERS int = 1
PASSWORD_REQUIRED_SYMBOLS int = 0
MAX_LOGIN_ATTEMPTS int = 5
)
type configuration struct { type configuration struct {
Domain string `env:"DOMAIN"` Domain string `env:"DOMAIN"`
Host string `env:"HOST"` Host string `env:"HOST"`

29
constants/constants.go Normal file
View File

@@ -0,0 +1,29 @@
package constants
const (
SESSION_COOKIE_NAME = "_maxwarden_session"
SESSION_COOKIE_EXPIRY_DAYS int = 100
SESSION_COOKIE_ENTROPY int = 33
IDENTITY_COOKIE_NAME string = "_maxwarden_identity"
IDENTITY_COOKIE_EXPIRY_DAYS int = 30
IDENTITY_TOKEN_EXPIRY_DAYS int = 30
IDENTITY_COOKIE_ENTROPY int = 33
IDENTITY_LOGIN_PATH string = "/auth/login"
IDENTITY_LOGOUT_PATH string = "/auth/logout"
IDENTITY_DEFAULT_PATH string = "/app"
IDENTITY_AUTH_REDIRECT bool = true
IDENTITY_AUTH_KEY string = "CORRECT_HORSE_BATTERY_STAPLE"
// This key is NOT used for the hashing of passwords, or secure session data over the wire.
// It is ONLY used for performing quick file and string hashes, where security is not a factor.
DATA_HASH_KEY string = "01234567890123456789012345678901"
PASSWORD_MIN_LENGTH int = 8
PASSWORD_REQUIRED_UPPERCASE int = 1
PASSWORD_REQUIRED_LOWERCASE int = 1
PASSWORD_REQUIRED_NUMBERS int = 1
PASSWORD_REQUIRED_SYMBOLS int = 0
MAX_LOGIN_ATTEMPTS int = 5
)

View File

@@ -44,7 +44,7 @@ func Filter(f EntryFilter) ([]Secret, error) {
user, _ := users.FetchById(f.UserId) user, _ := users.FetchById(f.UserId)
// we need to do the rest in memory because the data is encrypted, so we need to decrypt the data // we need to do the rest in memory because the data is encrypted, so we need to decrypt the data
secrets, decErr := security.DecryptDataWithKey[[]Secret](user.Data, f.MasterKey) secrets, decErr := security.DecryptData[[]Secret](user.Data, f.MasterKey)
if decErr != nil { if decErr != nil {
return nil, decErr return nil, decErr
} }
@@ -83,7 +83,7 @@ func Filter(f EntryFilter) ([]Secret, error) {
func FetchSecretFromID(userId int32, masterKey string, secretId string) (Secret, error) { func FetchSecretFromID(userId int32, masterKey string, secretId string) (Secret, error) {
user, _ := users.FetchById(userId) user, _ := users.FetchById(userId)
secrets, decErr := security.DecryptDataWithKey[[]Secret](user.Data, masterKey) secrets, decErr := security.DecryptData[[]Secret](user.Data, masterKey)
if decErr != nil { if decErr != nil {
return Secret{}, decErr return Secret{}, decErr
} }
@@ -104,7 +104,7 @@ func FetchSecretFromID(userId int32, masterKey string, secretId string) (Secret,
func DeleteSecret(userId int32, masterKey string, secretId string) error { func DeleteSecret(userId int32, masterKey string, secretId string) error {
user, _ := users.FetchById(userId) user, _ := users.FetchById(userId)
secrets, decErr := security.DecryptDataWithKey[[]Secret](user.Data, masterKey) secrets, decErr := security.DecryptData[[]Secret](user.Data, masterKey)
if decErr != nil { if decErr != nil {
return decErr return decErr
} }
@@ -121,7 +121,7 @@ func DeleteSecret(userId int32, masterKey string, secretId string) error {
} }
} }
enc, _ := security.EncryptDataWithKey(&output, masterKey) enc, _ := security.EncryptData(&output, masterKey)
user.Data = enc user.Data = enc
_, userErr := users.Update(user) _, userErr := users.Update(user)
@@ -132,7 +132,7 @@ func DeleteSecret(userId int32, masterKey string, secretId string) error {
func Update(userId int32, masterKey string, secret Secret) error { func Update(userId int32, masterKey string, secret Secret) error {
user, _ := users.FetchById(userId) user, _ := users.FetchById(userId)
secrets, _ := security.DecryptDataWithKey[[]Secret](user.Data, masterKey) secrets, _ := security.DecryptData[[]Secret](user.Data, masterKey)
if secrets == nil { if secrets == nil {
return errors.New("user secrets are null") return errors.New("user secrets are null")
} }
@@ -149,7 +149,7 @@ func Update(userId int32, masterKey string, secret Secret) error {
} }
} }
enc, _ := security.EncryptDataWithKey(secrets, masterKey) enc, _ := security.EncryptData(secrets, masterKey)
user.Data = enc user.Data = enc
_, updateErr := users.Update(user) _, updateErr := users.Update(user)
@@ -160,7 +160,7 @@ func Update(userId int32, masterKey string, secret Secret) error {
func Add(userId int32, masterKey string, secret Secret) error { func Add(userId int32, masterKey string, secret Secret) error {
user, _ := users.FetchById(userId) user, _ := users.FetchById(userId)
secrets, _ := security.DecryptDataWithKey[[]Secret](user.Data, masterKey) secrets, _ := security.DecryptData[[]Secret](user.Data, masterKey)
if secrets == nil { if secrets == nil {
return errors.New("user secrets are null") return errors.New("user secrets are null")
} }
@@ -171,7 +171,7 @@ func Add(userId int32, masterKey string, secret Secret) error {
*secrets = append(*secrets, secret) *secrets = append(*secrets, secret)
enc, _ := security.EncryptDataWithKey(secrets, masterKey) enc, _ := security.EncryptData(secrets, masterKey)
user.Data = enc user.Data = enc
_, updateErr := users.Update(user) _, updateErr := users.Update(user)

View File

@@ -7,7 +7,7 @@ import (
. "maragu.dev/gomponents/html" . "maragu.dev/gomponents/html"
"maxwarden/auth" "maxwarden/auth"
"maxwarden/config" "maxwarden/constants"
"maxwarden/middleware" "maxwarden/middleware"
"log" "log"
@@ -46,7 +46,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
defaultPath := config.IDENTITY_DEFAULT_PATH defaultPath := constants.IDENTITY_DEFAULT_PATH
http.Redirect(w, r, defaultPath, http.StatusFound) http.Redirect(w, r, defaultPath, http.StatusFound)
} }
} }

View File

@@ -2,7 +2,7 @@ package auth
import ( import (
"net/http" "net/http"
"maxwarden/config" "maxwarden/constants"
"maxwarden/middleware" "maxwarden/middleware"
) )
@@ -10,5 +10,5 @@ func LogoutHandler(w http.ResponseWriter, r *http.Request) {
middleware.DeleteIdentityCookie(w, r) middleware.DeleteIdentityCookie(w, r)
middleware.DeleteSessionCookie(w, r) middleware.DeleteSessionCookie(w, r)
http.Redirect(w, r, config.IDENTITY_LOGIN_PATH, http.StatusFound) http.Redirect(w, r, constants.IDENTITY_LOGIN_PATH, http.StatusFound)
} }

View File

@@ -3,12 +3,13 @@ package middleware
import ( import (
"context" "context"
"log" "log"
"net/http"
"net/url"
"maxwarden/auth" "maxwarden/auth"
"maxwarden/config" "maxwarden/config"
"maxwarden/constants"
"maxwarden/security" "maxwarden/security"
"maxwarden/users" "maxwarden/users"
"net/http"
"net/url"
"strings" "strings"
"time" "time"
) )
@@ -16,10 +17,10 @@ import (
type identityKey struct{} type identityKey struct{}
func LoadIdentity(h http.HandlerFunc, requireAuth bool) http.HandlerFunc { func LoadIdentity(h http.HandlerFunc, requireAuth bool) http.HandlerFunc {
loginPath := config.IDENTITY_LOGIN_PATH loginPath := constants.IDENTITY_LOGIN_PATH
logoutPath := config.IDENTITY_LOGOUT_PATH logoutPath := constants.IDENTITY_LOGOUT_PATH
defaultPath := config.IDENTITY_DEFAULT_PATH defaultPath := constants.IDENTITY_DEFAULT_PATH
redirect := config.IDENTITY_AUTH_REDIRECT redirect := constants.IDENTITY_AUTH_REDIRECT
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var identity *auth.Identity var identity *auth.Identity
@@ -35,7 +36,10 @@ func LoadIdentity(h http.HandlerFunc, requireAuth bool) http.HandlerFunc {
if len(splitToken) >= 2 { if len(splitToken) >= 2 {
token = splitToken[1] token = splitToken[1]
identity, _ = security.DecryptData[auth.Identity]([]byte(security.DecodeBase58(token))) identity, _ = security.DecryptData[auth.Identity](
[]byte(security.DecodeBase58(token)),
config.GetConfig().IdentityPrivateKey,
)
} }
if identity == nil { if identity == nil {
@@ -51,9 +55,12 @@ func LoadIdentity(h http.HandlerFunc, requireAuth bool) http.HandlerFunc {
return return
} }
} else { } else {
identityCookie, err := r.Cookie(config.IDENTITY_COOKIE_NAME) identityCookie, err := r.Cookie(constants.IDENTITY_COOKIE_NAME)
if err == nil { if err == nil {
identity, _ = security.DecryptData[auth.Identity]([]byte(security.DecodeBase58(identityCookie.Value))) identity, _ = security.DecryptData[auth.Identity](
[]byte(security.DecodeBase58(identityCookie.Value)),
config.GetConfig().IdentityPrivateKey,
)
} }
if identity == nil { if identity == nil {
@@ -117,7 +124,7 @@ func PutIdentityCookie(w http.ResponseWriter, r *http.Request, identity *auth.Id
// calculate total bytes used by other cookies // calculate total bytes used by other cookies
var totalBytes int var totalBytes int
for _, cookie := range cookies { for _, cookie := range cookies {
if cookie.Name == config.IDENTITY_COOKIE_NAME { if cookie.Name == constants.IDENTITY_COOKIE_NAME {
continue continue
} else { } else {
totalBytes += len(cookie.Value) totalBytes += len(cookie.Value)
@@ -139,7 +146,7 @@ func PutIdentityCookie(w http.ResponseWriter, r *http.Request, identity *auth.Id
// The key should not be checked into VCS, and be regenerated if theft is // The key should not be checked into VCS, and be regenerated if theft is
// suspected. Resetting the key will log *everyone* out, since no sessions // suspected. Resetting the key will log *everyone* out, since no sessions
// or identities will validate. // or identities will validate.
identityData, err := security.EncryptData(identity) identityData, err := security.EncryptData(identity, config.GetConfig().IdentityPrivateKey)
if err != nil { if err != nil {
return return
} }
@@ -152,7 +159,7 @@ func PutIdentityCookie(w http.ResponseWriter, r *http.Request, identity *auth.Id
} }
httpCookie := &http.Cookie{ httpCookie := &http.Cookie{
Name: config.IDENTITY_COOKIE_NAME, Name: constants.IDENTITY_COOKIE_NAME,
Value: security.EncodeBase58(identityData), Value: security.EncodeBase58(identityData),
HttpOnly: true, HttpOnly: true,
Secure: r.URL.Scheme == "https", Secure: r.URL.Scheme == "https",
@@ -167,7 +174,7 @@ func PutIdentityCookie(w http.ResponseWriter, r *http.Request, identity *auth.Id
func DeleteIdentityCookie(w http.ResponseWriter, r *http.Request) { func DeleteIdentityCookie(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{ http.SetCookie(w, &http.Cookie{
Name: config.IDENTITY_COOKIE_NAME, Name: constants.IDENTITY_COOKIE_NAME,
MaxAge: -1, MaxAge: -1,
Expires: time.Now().Add(-100 * time.Hour), Expires: time.Now().Add(-100 * time.Hour),
Path: "/", Path: "/",

View File

@@ -3,9 +3,10 @@ package middleware
import ( import (
"context" "context"
"log" "log"
"net/http"
"maxwarden/config" "maxwarden/config"
"maxwarden/constants"
"maxwarden/security" "maxwarden/security"
"net/http"
"time" "time"
) )
@@ -15,9 +16,13 @@ func LoadSession(h http.HandlerFunc) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var sessionMap map[string]interface{} var sessionMap map[string]interface{}
sessionCookie, err := r.Cookie(config.SESSION_COOKIE_NAME) sessionCookie, err := r.Cookie(constants.SESSION_COOKIE_NAME)
if err == nil { if err == nil {
decryptMap, _ := security.DecryptData[map[string]interface{}]([]byte(security.DecodeBase58(sessionCookie.Value))) decryptMap, _ := security.DecryptData[map[string]interface{}](
[]byte(security.DecodeBase58(sessionCookie.Value)),
config.GetConfig().IdentityPrivateKey,
)
sessionMap = *decryptMap sessionMap = *decryptMap
} }
@@ -41,14 +46,14 @@ func PutSessionCookie(w http.ResponseWriter, r *http.Request, session map[string
// calculate total bytes used by other cookies // calculate total bytes used by other cookies
var totalBytes int var totalBytes int
for _, cookie := range cookies { for _, cookie := range cookies {
if cookie.Name == config.SESSION_COOKIE_NAME { if cookie.Name == constants.SESSION_COOKIE_NAME {
continue continue
} else { } else {
totalBytes += len(cookie.Value) totalBytes += len(cookie.Value)
} }
} }
sessionData, err := security.EncryptData(&session) sessionData, err := security.EncryptData(&session, config.GetConfig().IdentityPrivateKey)
if err != nil { if err != nil {
return return
} }
@@ -61,7 +66,7 @@ func PutSessionCookie(w http.ResponseWriter, r *http.Request, session map[string
} }
httpCookie := &http.Cookie{ httpCookie := &http.Cookie{
Name: config.SESSION_COOKIE_NAME, Name: constants.SESSION_COOKIE_NAME,
Value: security.EncodeBase58(sessionData), Value: security.EncodeBase58(sessionData),
HttpOnly: true, HttpOnly: true,
Secure: r.URL.Scheme == "https", Secure: r.URL.Scheme == "https",
@@ -74,7 +79,7 @@ func PutSessionCookie(w http.ResponseWriter, r *http.Request, session map[string
func DeleteSessionCookie(w http.ResponseWriter, r *http.Request) { func DeleteSessionCookie(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{ http.SetCookie(w, &http.Cookie{
Name: config.SESSION_COOKIE_NAME, Name: constants.SESSION_COOKIE_NAME,
MaxAge: -1, MaxAge: -1,
Expires: time.Now().Add(-100 * time.Hour), Expires: time.Now().Add(-100 * time.Hour),
Path: "/", Path: "/",

View File

@@ -11,12 +11,12 @@ import (
"fmt" "fmt"
"io" "io"
"log" "log"
"maxwarden/config"
"os" "os"
"maxwarden/constants"
"github.com/btcsuite/btcutil/base58" "github.com/btcsuite/btcutil/base58"
"github.com/minio/highwayhash" "github.com/minio/highwayhash"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
@@ -59,7 +59,7 @@ func SHA512_58(in string) string {
} }
func HighwayHash58(in string) (string, error) { func HighwayHash58(in string) (string, error) {
key := []byte(config.DATA_HASH_KEY) key := []byte(constants.DATA_HASH_KEY)
hasher, err := highwayhash.New(key) hasher, err := highwayhash.New(key)
if err != nil { if err != nil {
@@ -77,7 +77,7 @@ func HighwayHash58(in string) (string, error) {
} }
func HighwayHash(in string) (string, error) { func HighwayHash(in string) (string, error) {
key := []byte(config.DATA_HASH_KEY) key := []byte(constants.DATA_HASH_KEY)
hasher, err := highwayhash.New(key) hasher, err := highwayhash.New(key)
if err != nil { if err != nil {
@@ -93,7 +93,7 @@ func HighwayHash(in string) (string, error) {
} }
func QuickFileHash(filepath string) (string, error) { func QuickFileHash(filepath string) (string, error) {
key := []byte(config.DATA_HASH_KEY) key := []byte(constants.DATA_HASH_KEY)
file, err := os.Open(filepath) file, err := os.Open(filepath)
if err != nil { if err != nil {
@@ -196,17 +196,7 @@ func DecryptSecret(encryptedData []byte, passKey string) ([]byte, error) {
return decryptedData, nil return decryptedData, nil
} }
// Encrypt data using default private key func EncryptData[T any](data *T, key string) ([]byte, error) {
func EncryptData[T any](data *T) ([]byte, error) {
return EncryptDataWithKey(data, config.GetConfig().IdentityPrivateKey)
}
// Decrypt data using default private key
func DecryptData[T any](data []byte) (*T, error) {
return DecryptDataWithKey[T](data, config.GetConfig().IdentityPrivateKey)
}
func EncryptDataWithKey[T any](data *T, key string) ([]byte, error) {
// serialize // serialize
b := bytes.Buffer{} b := bytes.Buffer{}
e := gob.NewEncoder(&b) e := gob.NewEncoder(&b)
@@ -224,7 +214,7 @@ func EncryptDataWithKey[T any](data *T, key string) ([]byte, error) {
return out, nil return out, nil
} }
func DecryptDataWithKey[T any](data []byte, key string) (*T, error) { func DecryptData[T any](data []byte, key string) (*T, error) {
dest := new(T) dest := new(T)
secret, err := DecryptSecret(data, key) secret, err := DecryptSecret(data, key)