mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-08-31 02:41:34 +00:00
feat(auth): make password encryption opt-in #6743
This commit is contained in:
parent
8454082f93
commit
918427d8ab
@ -79,6 +79,8 @@
|
||||
|
||||
# 会话密钥
|
||||
# SESSION_SECRET=random_string
|
||||
# 登录密码请求体 RSA-OAEP 加密;默认关闭,且不能替代 HTTPS
|
||||
# PASSWORD_LOGIN_ENCRYPTION_ENABLED=true
|
||||
# false/未配置:本地 HTTP 模式,关闭 refresh/logout OriginGuard,且不得设置 TRUSTED_URL;兼容本地开发代理。
|
||||
# true:启用 Secure Refresh Cookie 和严格 OriginGuard,必须同时列出全部可信 HTTPS Origin。
|
||||
# SESSION_COOKIE_TRUSTED_URL 多项用英文逗号分隔;不支持通配符、路径或域名后缀匹配。
|
||||
|
||||
@ -60,6 +60,7 @@ var ItemsPerPage = 10
|
||||
var MaxRecentItems = 1000
|
||||
|
||||
var PasswordLoginEnabled = true
|
||||
var PasswordLoginEncryptionEnabled = false
|
||||
var PasswordRegisterEnabled = true
|
||||
var EmailVerificationEnabled = false
|
||||
var GitHubOAuthEnabled = false
|
||||
|
||||
@ -87,6 +87,7 @@ func InitEnv() {
|
||||
DebugEnabled = os.Getenv("DEBUG") == "true"
|
||||
MemoryCacheEnabled = os.Getenv("MEMORY_CACHE_ENABLED") == "true"
|
||||
IsMasterNode = os.Getenv("NODE_TYPE") != "slave"
|
||||
PasswordLoginEncryptionEnabled = GetEnvOrDefaultBool("PASSWORD_LOGIN_ENCRYPTION_ENABLED", false)
|
||||
initNodeNameIdentity()
|
||||
TLSInsecureSkipVerify = GetEnvOrDefaultBool("TLS_INSECURE_SKIP_VERIFY", false)
|
||||
if TLSInsecureSkipVerify {
|
||||
|
||||
@ -94,6 +94,8 @@ func GetStatus(c *gin.Context) {
|
||||
"password_register_enabled": common.PasswordRegisterEnabled,
|
||||
"default_use_auto_group": setting.DefaultUseAutoGroup,
|
||||
|
||||
"password_login_encryption_enabled": common.PasswordLoginEncryptionEnabled,
|
||||
|
||||
"usd_exchange_rate": operation_setting.USDExchangeRate,
|
||||
"price": operation_setting.Price,
|
||||
"stripe_unit_price": setting.StripeUnitPrice,
|
||||
|
||||
@ -40,12 +40,17 @@ var (
|
||||
)
|
||||
|
||||
func GetPasswordEncryptionKey(c *gin.Context) {
|
||||
if !common.PasswordLoginEncryptionEnabled {
|
||||
common.ApiSuccess(c, gin.H{"enabled": false})
|
||||
return
|
||||
}
|
||||
keyID, publicKey := common.PasswordEncryptionPublicKey()
|
||||
if keyID == "" || publicKey == "" {
|
||||
common.ApiErrorI18n(c, i18n.MsgDatabaseError)
|
||||
return
|
||||
}
|
||||
common.ApiSuccess(c, gin.H{
|
||||
"enabled": true,
|
||||
"kid": keyID,
|
||||
"public_key": publicKey,
|
||||
})
|
||||
@ -64,7 +69,11 @@ func Login(c *gin.Context) {
|
||||
}
|
||||
username := loginRequest.Username
|
||||
password := loginRequest.Password
|
||||
if loginRequest.PasswordEncrypted != "" {
|
||||
if common.PasswordLoginEncryptionEnabled {
|
||||
if loginRequest.PasswordEncrypted == "" || loginRequest.EncryptionKeyID == "" {
|
||||
common.ApiErrorI18n(c, i18n.MsgInvalidParams)
|
||||
return
|
||||
}
|
||||
password, err = common.DecryptPassword(loginRequest.PasswordEncrypted, loginRequest.EncryptionKeyID)
|
||||
if err != nil {
|
||||
common.ApiErrorI18n(c, i18n.MsgUserUsernameOrPasswordError)
|
||||
|
||||
8
main.go
8
main.go
@ -318,9 +318,11 @@ func InitResources() error {
|
||||
common.FatalLog("failed to initialize authorization: " + err.Error())
|
||||
return err
|
||||
}
|
||||
if err = model.InitPasswordEncryption(); err != nil {
|
||||
common.FatalLog("failed to initialize password encryption: " + err.Error())
|
||||
return err
|
||||
if common.PasswordLoginEncryptionEnabled {
|
||||
if err = model.InitPasswordEncryption(); err != nil {
|
||||
common.FatalLog("failed to initialize password encryption: " + err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
model.CheckSetup()
|
||||
|
||||
@ -48,22 +48,34 @@ import type {
|
||||
export async function login(payload: LoginPayload): Promise<LoginResponse> {
|
||||
const turnstile = payload.turnstile ?? ''
|
||||
try {
|
||||
const encryptedPassword = await encryptPassword(payload.password)
|
||||
let passwordFields:
|
||||
| { password: string }
|
||||
| { password_encrypted: string; encryption_key_id: string }
|
||||
if (payload.passwordEncryptionEnabled) {
|
||||
const encryptedPassword = await encryptPassword(payload.password)
|
||||
passwordFields = {
|
||||
password_encrypted: encryptedPassword.password_encrypted,
|
||||
encryption_key_id: encryptedPassword.encryption_key_id,
|
||||
}
|
||||
} else {
|
||||
passwordFields = { password: payload.password }
|
||||
}
|
||||
const res = await api.post<LoginResponse>(
|
||||
`/api/user/login?turnstile=${turnstile}`,
|
||||
{
|
||||
username: payload.username,
|
||||
password_encrypted: encryptedPassword.password_encrypted,
|
||||
encryption_key_id: encryptedPassword.encryption_key_id,
|
||||
...passwordFields,
|
||||
},
|
||||
{ skipAuthRefresh: true }
|
||||
)
|
||||
if (!res.data?.success) {
|
||||
if (payload.passwordEncryptionEnabled && !res.data?.success) {
|
||||
clearPasswordEncryptionCache()
|
||||
}
|
||||
return res.data
|
||||
} catch (error: unknown) {
|
||||
clearPasswordEncryptionCache()
|
||||
if (payload.passwordEncryptionEnabled) {
|
||||
clearPasswordEncryptionCache()
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,6 +84,10 @@ export function UserAuthForm({
|
||||
(status?.password_login_enabled ??
|
||||
status?.data?.password_login_enabled ??
|
||||
true) !== false
|
||||
const passwordLoginEncryptionEnabled =
|
||||
(status?.password_login_encryption_enabled ??
|
||||
status?.data?.password_login_encryption_enabled ??
|
||||
false) === true
|
||||
const {
|
||||
isTurnstileEnabled,
|
||||
turnstileSiteKey,
|
||||
@ -171,6 +175,7 @@ export function UserAuthForm({
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
turnstile: submittedTurnstileToken,
|
||||
passwordEncryptionEnabled: passwordLoginEncryptionEnabled,
|
||||
})
|
||||
|
||||
if (res.success) {
|
||||
|
||||
@ -26,6 +26,7 @@ export interface LoginPayload {
|
||||
username: string
|
||||
password: string
|
||||
turnstile?: string
|
||||
passwordEncryptionEnabled?: boolean
|
||||
}
|
||||
|
||||
export interface TwoFAPayload {
|
||||
@ -133,6 +134,7 @@ export interface SystemStatus {
|
||||
oauth_register_enabled?: boolean
|
||||
register_enabled?: boolean
|
||||
password_login_enabled?: boolean
|
||||
password_login_encryption_enabled?: boolean
|
||||
password_register_enabled?: boolean
|
||||
custom_oauth_providers?: CustomOAuthProviderInfo[]
|
||||
[key: string]: unknown
|
||||
@ -178,6 +180,7 @@ export interface SystemStatus {
|
||||
oauth_register_enabled?: boolean
|
||||
register_enabled?: boolean
|
||||
password_login_enabled?: boolean
|
||||
password_login_encryption_enabled?: boolean
|
||||
password_register_enabled?: boolean
|
||||
custom_oauth_providers?: CustomOAuthProviderInfo[]
|
||||
[key: string]: unknown
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user