mirror of
https://hubproxy.babadafafafafa.cn/https://github.com/1Panel-dev/1Panel.git
synced 2026-09-20 08:03:55 +08:00
feat: normalize mfa and api config fields (#12642)
This commit is contained in:
committed by
zhengkunwang223
parent
8fb8d97dcf
commit
8d44105f88
@@ -20,7 +20,7 @@ type APIAuthConfig struct {
|
||||
ApiInterfaceStatus string
|
||||
ApiKey string
|
||||
IpWhiteList string
|
||||
ApiKeyValidityTime string
|
||||
ApiKeyValidityTime int
|
||||
}
|
||||
|
||||
type APIAuthConfigLoader func(c *gin.Context) (APIAuthConfig, error)
|
||||
@@ -83,16 +83,19 @@ func LoadAPIAuthConfig(_ *gin.Context) (APIAuthConfig, error) {
|
||||
if config.IpWhiteList, err = settingRepo.GetValueByKey("IpWhiteList"); err != nil {
|
||||
return config, err
|
||||
}
|
||||
if config.ApiKeyValidityTime, err = settingRepo.GetValueByKey("ApiKeyValidityTime"); err != nil {
|
||||
apiValidity, err := settingRepo.GetValueByKey("ApiKeyValidityTime")
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
if config.ApiKeyValidityTime, err = strconv.Atoi(apiValidity); err != nil {
|
||||
return config, err
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func isValid1PanelTimestamp(panelTimestamp string, apiKeyValidityTime string) bool {
|
||||
apiTime, err := strconv.Atoi(apiKeyValidityTime)
|
||||
if err != nil || apiTime < 0 {
|
||||
global.LOG.Errorf("apiTime %d, err: %v", apiTime, err)
|
||||
func isValid1PanelTimestamp(panelTimestamp string, apiKeyValidityTime int) bool {
|
||||
apiTime := apiKeyValidityTime
|
||||
if apiTime < 0 {
|
||||
return false
|
||||
}
|
||||
if apiTime == 0 {
|
||||
|
||||
@@ -103,15 +103,19 @@ func VerifyMFALogin(c *gin.Context, sessionID, code, entrance string) (string, s
|
||||
if session.Entrance != entrance {
|
||||
return "", "", buserr.New("ErrEntrance")
|
||||
}
|
||||
mfaSecret, err := settingRepo.Get(repo.WithByKey("MFASecret"))
|
||||
mfaSecret, err := settingRepo.GetValueByKey("MFASecret")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
mfaInterval, err := settingRepo.Get(repo.WithByKey("MFAInterval"))
|
||||
mfaInterval, err := settingRepo.GetValueByKey("MFAInterval")
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if !mfa.ValidCode(code, mfaInterval.Value, mfaSecret.Value) {
|
||||
interval, err := strconv.Atoi(mfaInterval)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if !mfa.ValidCode(interval, code, mfaSecret) {
|
||||
return "", "ErrMFA", nil
|
||||
}
|
||||
mfaSessions.Delete(sessionID)
|
||||
@@ -194,13 +198,13 @@ func LoadMFA(req dto.MfaRequest) (mfa.Otp, error) {
|
||||
return otp, nil
|
||||
}
|
||||
func MFABind(req dto.MfaCredential) error {
|
||||
success := mfa.ValidCode(req.Code, req.Interval, req.Secret)
|
||||
success := mfa.ValidCode(req.Interval, req.Code, req.Secret)
|
||||
if !success {
|
||||
return errors.New("code is not valid")
|
||||
}
|
||||
|
||||
settingRepo := repo.NewISettingRepo()
|
||||
if err := settingRepo.Update("MFAInterval", req.Interval); err != nil {
|
||||
if err := settingRepo.Update("MFAInterval", strconv.Itoa(req.Interval)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.Update("MFAStatus", constant.StatusEnable); err != nil {
|
||||
@@ -227,6 +231,8 @@ func GetCurrentUserInfo() (*dto.CurrentUserInfo, error) {
|
||||
}
|
||||
delete(stringSettingMap, "SessionTimeout")
|
||||
delete(stringSettingMap, "ExpirationDays")
|
||||
delete(stringSettingMap, "MFAInterval")
|
||||
delete(stringSettingMap, "ApiKeyValidityTime")
|
||||
arr, err := json.Marshal(stringSettingMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -236,6 +242,8 @@ func GetCurrentUserInfo() (*dto.CurrentUserInfo, error) {
|
||||
}
|
||||
info.SessionTimeout, _ = strconv.Atoi(settingMap["SessionTimeout"])
|
||||
info.ExpirationDays, _ = strconv.Atoi(settingMap["ExpirationDays"])
|
||||
info.MFAInterval, _ = strconv.Atoi(settingMap["MFAInterval"])
|
||||
info.ApiKeyValidityTime, _ = strconv.Atoi(settingMap["ApiKeyValidityTime"])
|
||||
info.Name = settingMap["UserName"]
|
||||
return &info, nil
|
||||
}
|
||||
@@ -296,7 +304,7 @@ func UpdateApiConfig(req dto.ApiInterfaceConfig) error {
|
||||
if err := settingRepo.UpdateOrCreate("IpWhiteList", req.IpWhiteList); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := settingRepo.UpdateOrCreate("ApiKeyValidityTime", req.ApiKeyValidityTime); err != nil {
|
||||
if err := settingRepo.UpdateOrCreate("ApiKeyValidityTime", strconv.Itoa(req.ApiKeyValidityTime)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -18,17 +18,6 @@ type PasskeyBeginResponse struct {
|
||||
PublicKey interface{} `json:"publicKey"`
|
||||
}
|
||||
|
||||
type MfaRequest struct {
|
||||
Title string `json:"title" validate:"required"`
|
||||
Interval int `json:"interval" validate:"required"`
|
||||
}
|
||||
|
||||
type MfaCredential struct {
|
||||
Secret string `json:"secret" validate:"required"`
|
||||
Code string `json:"code" validate:"required"`
|
||||
Interval string `json:"interval" validate:"required"`
|
||||
}
|
||||
|
||||
type Login struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Password string `json:"password" validate:"required"`
|
||||
@@ -37,11 +26,6 @@ type Login struct {
|
||||
Language string `json:"language" validate:"required,oneof=zh en 'zh-Hant' ko ja ru ms 'pt-BR' tr 'es-ES'"`
|
||||
}
|
||||
|
||||
type MFALogin struct {
|
||||
SessionID string `json:"sessionId" validate:"required"`
|
||||
Code string `json:"code" validate:"required"`
|
||||
}
|
||||
|
||||
type SystemSetting struct {
|
||||
IsDemo bool `json:"isDemo"`
|
||||
Language string `json:"language"`
|
||||
@@ -52,11 +36,35 @@ type PasskeyID struct {
|
||||
ID string `json:"id" validate:"required"`
|
||||
}
|
||||
|
||||
// mfa
|
||||
type MFALogin struct {
|
||||
SessionID string `json:"sessionId" validate:"required"`
|
||||
Code string `json:"code" validate:"required"`
|
||||
}
|
||||
|
||||
type MfaRequest struct {
|
||||
Title string `json:"title" validate:"required"`
|
||||
Interval int `json:"interval" validate:"required"`
|
||||
}
|
||||
|
||||
type MfaCredential struct {
|
||||
Secret string `json:"secret" validate:"required"`
|
||||
Code string `json:"code" validate:"required"`
|
||||
Interval int `json:"interval" validate:"required"`
|
||||
}
|
||||
|
||||
type ApiInterfaceConfig struct {
|
||||
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
IpWhiteList string `json:"ipWhiteList"`
|
||||
ApiKeyValidityTime int `json:"apiKeyValidityTime"`
|
||||
}
|
||||
|
||||
type CurrentUserInfo struct {
|
||||
Name string `json:"name"`
|
||||
SessionTimeout int `json:"sessionTimeout"`
|
||||
MFAStatus string `json:"mfaStatus"`
|
||||
MFAInterval string `json:"mfaInterval"`
|
||||
MFAInterval int `json:"mfaInterval"`
|
||||
ExpirationDays int `json:"expirationDays"`
|
||||
ExpirationTime string `json:"expirationTime"`
|
||||
ComplexitySetting string `json:"complexitySetting"`
|
||||
@@ -64,7 +72,7 @@ type CurrentUserInfo struct {
|
||||
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
IpWhiteList string `json:"ipWhiteList"`
|
||||
ApiKeyValidityTime string `json:"apiKeyValidityTime"`
|
||||
ApiKeyValidityTime int `json:"apiKeyValidityTime"`
|
||||
}
|
||||
type CurrentUserUpdate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
|
||||
@@ -235,13 +235,6 @@ type MenuLabelSort struct {
|
||||
Sort int `json:"sort"`
|
||||
}
|
||||
|
||||
type ApiInterfaceConfig struct {
|
||||
ApiInterfaceStatus string `json:"apiInterfaceStatus"`
|
||||
ApiKey string `json:"apiKey"`
|
||||
IpWhiteList string `json:"ipWhiteList"`
|
||||
ApiKeyValidityTime string `json:"apiKeyValidityTime"`
|
||||
}
|
||||
|
||||
type TerminalInfo struct {
|
||||
LineHeight string `json:"lineHeight"`
|
||||
LetterSpacing string `json:"letterSpacing"`
|
||||
|
||||
@@ -181,8 +181,9 @@ var WebUrlMap = map[string]struct{}{
|
||||
"/xpack/cluster/postgres": {},
|
||||
"/xpack/cluster/redis": {},
|
||||
|
||||
"/enterprise/users/list": {},
|
||||
"/enterprise/users/roles": {},
|
||||
"/enterprise/users/list": {},
|
||||
"/enterprise/users/roles": {},
|
||||
"/enterprise/license-required": {},
|
||||
}
|
||||
|
||||
var DynamicRoutes = []string{
|
||||
|
||||
@@ -3,10 +3,8 @@ package mfa
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/global"
|
||||
"github.com/skip2/go-qrcode"
|
||||
"github.com/xlzd/gotp"
|
||||
)
|
||||
@@ -32,12 +30,7 @@ func GetOtp(username, title string, interval int) (otp Otp, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ValidCode(code, intervalStr, secret string) bool {
|
||||
interval, err := strconv.Atoi(intervalStr)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("type conversion failed, err: %v", err)
|
||||
return false
|
||||
}
|
||||
func ValidCode(interval int, code, secret string) bool {
|
||||
totp := gotp.NewTOTP(secret, 6, interval, nil)
|
||||
now := time.Now().Unix()
|
||||
prevTime := now - int64(interval)
|
||||
|
||||
@@ -82,13 +82,13 @@ export namespace Login {
|
||||
export interface MFABind {
|
||||
secret: string;
|
||||
code: string;
|
||||
interval: string;
|
||||
interval: number;
|
||||
}
|
||||
export interface ApiConfig {
|
||||
apiInterfaceStatus: string;
|
||||
apiKey: string;
|
||||
ipWhiteList: string;
|
||||
apiKeyValidityTime: string;
|
||||
apiKeyValidityTime: number;
|
||||
}
|
||||
export interface PasswordUpdate {
|
||||
oldPassword: string;
|
||||
|
||||
@@ -147,12 +147,22 @@
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-switch
|
||||
@change="handleApi"
|
||||
v-model="form.apiInterfaceStatus"
|
||||
active-value="Enable"
|
||||
inactive-value="Disable"
|
||||
/>
|
||||
<div class="setting-action-row">
|
||||
<el-switch
|
||||
@change="handleApi"
|
||||
v-model="form.apiInterfaceStatus"
|
||||
active-value="Enable"
|
||||
inactive-value="Disable"
|
||||
/>
|
||||
<el-button
|
||||
v-if="form.apiInterfaceStatus === 'Enable'"
|
||||
link
|
||||
type="primary"
|
||||
@click="openApiDetail"
|
||||
>
|
||||
{{ $t('commons.button.view') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<span class="input-help">{{ $t('setting.apiInterfaceHelper') }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
@@ -356,7 +366,7 @@
|
||||
<span class="input-help">{{ $t('setting.ipWhiteListHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('setting.apiKeyValidityTime')" prop="apiKeyValidityTime">
|
||||
<el-input :placeholder="$t('setting.apiKeyValidityTimeEgs')" v-model="form.apiKeyValidityTime">
|
||||
<el-input :placeholder="$t('setting.apiKeyValidityTimeEgs')" v-model.number="form.apiKeyValidityTime">
|
||||
<template #append>{{ $t('commons.units.minute') }}</template>
|
||||
</el-input>
|
||||
<span class="input-help">
|
||||
@@ -667,6 +677,11 @@ const handleApiDialogClose = () => {
|
||||
form.apiInterfaceStatus = savedApiStatus.value;
|
||||
};
|
||||
|
||||
const openApiDetail = async () => {
|
||||
await ensureApiKey();
|
||||
apiDialogOpen.value = true;
|
||||
};
|
||||
|
||||
const openPasskeyDrawer = async () => {
|
||||
const settingRes = await loadPasskeySettingInfo();
|
||||
hasBindDomain.value = !!settingRes?.data.bindDomain?.trim().length;
|
||||
@@ -862,7 +877,7 @@ const onBindMFA = async (formEl: FormInstance | undefined) => {
|
||||
const param = {
|
||||
code: mfaForm.code,
|
||||
secret: mfaForm.secret,
|
||||
interval: mfaForm.interval + '',
|
||||
interval: mfaForm.interval,
|
||||
};
|
||||
loading.value = true;
|
||||
await bindMFA(param)
|
||||
@@ -887,7 +902,7 @@ const onSaveApi = async (formEl: FormInstance | undefined) => {
|
||||
apiKey: form.apiKey,
|
||||
ipWhiteList: form.ipWhiteList,
|
||||
apiInterfaceStatus: form.apiInterfaceStatus,
|
||||
apiKeyValidityTime: form.apiKeyValidityTime + '',
|
||||
apiKeyValidityTime: form.apiKeyValidityTime,
|
||||
};
|
||||
loading.value = true;
|
||||
await updateApiConfig(param)
|
||||
@@ -981,7 +996,7 @@ const handleApi = async () => {
|
||||
apiKey: form.apiKey,
|
||||
ipWhiteList: form.ipWhiteList,
|
||||
apiInterfaceStatus: form.apiInterfaceStatus,
|
||||
apiKeyValidityTime: form.apiKeyValidityTime + '',
|
||||
apiKeyValidityTime: form.apiKeyValidityTime,
|
||||
};
|
||||
await updateApiConfig(param)
|
||||
.then(() => {
|
||||
@@ -1024,6 +1039,12 @@ defineExpose({
|
||||
border-top: 1px solid var(--el-border-color-lighter);
|
||||
}
|
||||
|
||||
.setting-action-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.api-key-input {
|
||||
width: calc(100% - 125px);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user