package app import ( "os" "runtime" "strings" "github.com/grvlle/constellation_wallet/backend/models" "golang.org/x/crypto/bcrypt" ) // LoginError 获取一个字符串并将其作为 error 推送到登录屏幕 func (a *WalletApplication) LoginError(errMsg string) { if errMsg != "" { a.RT.Events.Emit("login_error", errMsg, true) } } // Login 当用户使用 wallet 对象登录时,FE 会调用 Login 已在数据库中 func (a *WalletApplication) Login(keystorePath, keystorePassword, keyPassword, alias string) bool { alias = strings.ToLower(alias) a.wallet = models.Wallet{ KeyStorePath: keystorePath, WalletAlias: alias} if runtime.GOOS == "windows" && !a.javaInstalled() { a.LoginError("无法检测到 Java 路径。请确保已安装 Java。") return false } if !a.TransactionFinished { a.log.Warn("在待处理交易期间无法登录其他钱包。") a.LoginError("在待处理交易期间无法登录其他钱包。") return false } if keystorePath == "" { a.LoginError("请提供 KeyStore 文件的路径。") return false } if !a.passwordsProvided(keystorePassword, keyPassword, alias) { a.log.Warnln("未提供一个或多个密码。") return false } _ = os.Setenv("CL_STOREPASS", keystorePassword) _ = os.Setenv("CL_KEYPASS", keyPassword) if err := a.DB.First(&a.wallet, "wallet_alias = ?", alias).Error; err != nil { a.log.Errorln("无法查询现有钱包的数据库对象。原因: ", err) return a.ImportWallet(keystorePath, keystorePassword, keyPassword, alias) } if !a.WalletKeystoreAccess() { a.LoginError("访问被拒绝。请确保您输入了正确的凭据。") return false } if !a.NewUser { a.DB.Model(&a.wallet).Update("KeystorePath", keystorePath) a.log.Infoln("PrivateKey path: ", keystorePath) } // 根据 DB 中存储的加盐哈希检查密码字符串。还要确保已访问 KeyStore。 if a.CheckAccess(keystorePassword, a.wallet.KeystorePasswordHash) && a.CheckAccess(keyPassword, a.wallet.KeyPasswordHash) && a.KeyStoreAccess { a.UserLoggedIn = true // os.Setenv("CL_STOREPASS", keystorePassword) // os.Setenv("CL_KEYPASS", keyPassword) } else { a.UserLoggedIn = false a.LoginError("访问被拒绝。请确保您输入了正确的凭据。") } if a.UserLoggedIn && a.KeyStoreAccess && !a.NewUser { err := a.initWallet(keystorePath) if err != nil { a.UserLoggedIn = false } } a.NewUser = false return a.UserLoggedIn } // CheckTermsOfService 从 FE 调用 CheckTermsOfService 以检查 termsOfService 是否已被接受 func (a *WalletApplication) CheckTermsOfService() bool { return a.wallet.TermsOfService } // LogOut 将重置钱包 UI 并清除钱包对象 func (a *WalletApplication) LogOut() bool { if a.TransactionFinished { a.UserLoggedIn = false a.wallet = models.Wallet{} return true } a.sendWarning("Cannot log out while transaction is processing. Please try again.") return false } // ImportKey 在浏览 fs 中查找密钥文件时从前端调用 func (a *WalletApplication) ImportKey() string { var keyfile = a.RT.Dialog.SelectFile() if keyfile == "" { a.LoginError("Access Denied. No key path detected.") return "" } if keyfile[len(keyfile)-4:] != ".p12" { a.LoginError("Access Denied. Not a key file.") return "" } a.log.Info("Path to imported key: " + keyfile) return keyfile } // SelectDirToStoreKey 在创建新的密钥文件时,从 FE 调用 SelectDirToStoreKey func (a *WalletApplication) SelectDirToStoreKey() string { var keyfile = a.RT.Dialog.SelectSaveFile() if len(keyfile) <= 0 { a.LoginError("No valid path were provided. Please try again.") return "" } if keyfile[len(keyfile)-4:] != ".p12" { keyfile = keyfile + ".p12" return keyfile } return keyfile } // GenerateSaltedHash 将纯文本转换为加盐哈希 func (a *WalletApplication) GenerateSaltedHash(s string) (string, error) { saltedBytes := []byte(s) hashedBytes, err := bcrypt.GenerateFromPassword(saltedBytes, bcrypt.DefaultCost) if err != nil { return "", err } hash := string(hashedBytes[:]) return hash, nil } // CheckAccess 验证用户是否输入了正确的密码 func (a *WalletApplication) CheckAccess(password, passwordHash string) bool { err := a.Compare(password, passwordHash) if err != nil { a.log.Warnln("用户尝试使用错误的凭据登录!") return false } a.log.Infoln("密码检查通过") return true } // Compare 将字符串与加盐哈希进行比较 func (a *WalletApplication) Compare(s, hash string) error { incoming := []byte(s) existing := []byte(hash) return bcrypt.CompareHashAndPassword(existing, incoming) }