From c6111de0504b2ed94cd2035e7f4f5cf0975b319b Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Thu, 28 Sep 2023 15:46:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=A4=E6=AD=A5=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AE=BE=E7=BD=AE=E6=A0=87=E9=A2=98=EF=BC=8C?= =?UTF-8?q?=E5=8C=BA=E5=88=86=E7=B3=BB=E7=BB=9F=20(#2411)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #2404 --- backend/app/api/v1/setting.go | 22 +++++++------------ backend/app/dto/auth.go | 5 +++++ backend/router/ro_setting.go | 2 +- backend/utils/mfa/mfa.go | 4 ++-- cmd/server/docs/docs.go | 17 +++++++++----- cmd/server/docs/swagger.json | 17 +++++++++----- cmd/server/docs/swagger.yaml | 13 ++++++----- frontend/src/api/interface/setting.ts | 4 ++++ frontend/src/api/modules/setting.ts | 4 ++-- frontend/src/lang/modules/en.ts | 2 ++ frontend/src/lang/modules/tw.ts | 1 + frontend/src/lang/modules/zh.ts | 1 + frontend/src/views/setting/safe/mfa/index.vue | 19 ++++++++++++++-- 13 files changed, 73 insertions(+), 38 deletions(-) diff --git a/backend/app/api/v1/setting.go b/backend/app/api/v1/setting.go index 41830abc8..ff447f952 100644 --- a/backend/app/api/v1/setting.go +++ b/backend/app/api/v1/setting.go @@ -2,10 +2,8 @@ package v1 import ( "errors" - "fmt" "os" "path" - "strconv" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/dto" @@ -311,23 +309,19 @@ func (b *BaseApi) SystemClean(c *gin.Context) { // @Tags System Setting // @Summary Load mfa info // @Description 获取 mfa 信息 -// @Param interval path string true "request" +// @Accept json +// @Param request body dto.MfaCredential true "request" // @Success 200 {object} mfa.Otp // @Security ApiKeyAuth -// @Router /settings/mfa/:interval [get] -func (b *BaseApi) GetMFA(c *gin.Context) { - intervalStr, ok := c.Params.Get("interval") - if !ok { - helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error interval in path")) - return - } - interval, err := strconv.Atoi(intervalStr) - if err != nil { - helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, fmt.Errorf("type conversion failed, err: %v", err)) +// @Router /settings/mfa [post] +func (b *BaseApi) LoadMFA(c *gin.Context) { + var req dto.MfaRequest + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) return } - otp, err := mfa.GetOtp("admin", interval) + otp, err := mfa.GetOtp("admin", req.Title, req.Interval) if err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return diff --git a/backend/app/dto/auth.go b/backend/app/dto/auth.go index 85cf8d8c9..3d6e0084b 100644 --- a/backend/app/dto/auth.go +++ b/backend/app/dto/auth.go @@ -11,6 +11,11 @@ type UserLoginInfo struct { MfaStatus string `json:"mfaStatus"` } +type MfaRequest struct { + Title string `json:"title"` + Interval int `json:"interval"` +} + type MfaCredential struct { Secret string `json:"secret"` Code string `json:"code"` diff --git a/backend/router/ro_setting.go b/backend/router/ro_setting.go index 5c73afbe2..20b399813 100644 --- a/backend/router/ro_setting.go +++ b/backend/router/ro_setting.go @@ -30,7 +30,7 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) { settingRouter.GET("/time/option", baseApi.LoadTimeZone) settingRouter.POST("/time/sync", baseApi.SyncTime) settingRouter.POST("/monitor/clean", baseApi.CleanMonitor) - settingRouter.GET("/mfa/:interval", baseApi.GetMFA) + settingRouter.POST("/mfa", baseApi.LoadMFA) settingRouter.POST("/mfa/bind", baseApi.MFABind) settingRouter.POST("/scan", baseApi.ScanSystem) settingRouter.POST("/clean", baseApi.SystemClean) diff --git a/backend/utils/mfa/mfa.go b/backend/utils/mfa/mfa.go index 0ece19eb5..30b644a5e 100644 --- a/backend/utils/mfa/mfa.go +++ b/backend/utils/mfa/mfa.go @@ -18,11 +18,11 @@ type Otp struct { QrImage string `json:"qrImage"` } -func GetOtp(username string, interval int) (otp Otp, err error) { +func GetOtp(username, title string, interval int) (otp Otp, err error) { secret := gotp.RandomSecret(secretLength) otp.Secret = secret totp := gotp.NewTOTP(secret, 6, interval, nil) - uri := totp.ProvisioningUri(username, "1Panel") + uri := totp.ProvisioningUri(username, title) subImg, err := qrcode.Encode(uri, qrcode.Medium, 256) dist := make([]byte, 3000) base64.StdEncoding.Encode(dist, subImg) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 392c19803..d3c0f14d3 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -8648,25 +8648,30 @@ const docTemplate = `{ } } }, - "/settings/mfa/:interval": { - "get": { + "/settings/mfa": { + "post": { "security": [ { "ApiKeyAuth": [] } ], "description": "获取 mfa 信息", + "consumes": [ + "application/json" + ], "tags": [ "System Setting" ], "summary": "Load mfa info", "parameters": [ { - "type": "string", "description": "request", - "name": "interval", - "in": "path", - "required": true + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.MfaCredential" + } } ], "responses": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 3b9bba6fa..f2562ca5a 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -8641,25 +8641,30 @@ } } }, - "/settings/mfa/:interval": { - "get": { + "/settings/mfa": { + "post": { "security": [ { "ApiKeyAuth": [] } ], "description": "获取 mfa 信息", + "consumes": [ + "application/json" + ], "tags": [ "System Setting" ], "summary": "Load mfa info", "parameters": [ { - "type": "string", "description": "request", - "name": "interval", - "in": "path", - "required": true + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.MfaCredential" + } } ], "responses": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 00bce06f4..214389336 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -9611,15 +9611,18 @@ paths: formatEN: reset an expired Password formatZH: 重置过期密码 paramKeys: [] - /settings/mfa/:interval: - get: + /settings/mfa: + post: + consumes: + - application/json description: 获取 mfa 信息 parameters: - description: request - in: path - name: interval + in: body + name: request required: true - type: string + schema: + $ref: '#/definitions/dto.MfaCredential' responses: "200": description: OK diff --git a/frontend/src/api/interface/setting.ts b/frontend/src/api/interface/setting.ts index 7e7634a92..5080f391a 100644 --- a/frontend/src/api/interface/setting.ts +++ b/frontend/src/api/interface/setting.ts @@ -70,6 +70,10 @@ export namespace Setting { export interface PortUpdate { serverPort: number; } + export interface MFARequest { + title: string; + interval: number; + } export interface MFAInfo { secret: string; qrImage: string; diff --git a/frontend/src/api/modules/setting.ts b/frontend/src/api/modules/setting.ts index 6d1a4bae5..f1d763619 100644 --- a/frontend/src/api/modules/setting.ts +++ b/frontend/src/api/modules/setting.ts @@ -57,8 +57,8 @@ export const cleanMonitors = () => { return http.post(`/settings/monitor/clean`, {}); }; -export const getMFA = (interval: number) => { - return http.get(`/settings/mfa/${interval}`, {}); +export const loadMFA = (param: Setting.MFARequest) => { + return http.post(`/settings/mfa`, param); }; export const loadDaemonJsonPath = () => { diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 2d46ab682..1c37e5e05 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1125,6 +1125,8 @@ const message = { mfa: 'MFA', secret: 'Secret', mfaInterval: 'Refresh interval (s)', + mfaTitleHelper: + 'Used to differentiate between different 1Panel hosts. After modification, please rescan or manually add the key information!', mfaIntervalHelper: 'Please rescan or manually add key information after modifying the refresh time.', mfaAlert: 'MFA password is generated based on the current time. Please ensure that the server time is synchronized.', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 2f53179b4..5f4e43e58 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -1117,6 +1117,7 @@ const message = { mfaHelper3: '輸入手機應用上的 6 位數字', mfaCode: '驗證碼', mfaInterval: '刷新時間(秒)', + mfaTitleHelper: '用於區分不同 1Panel 主機,修改後請重新掃描或手動添加密鑰信息!', mfaIntervalHelper: '修改刷新時間後,請重新掃描或手動添加密鑰信息!', sslChangeHelper: 'https 設置修改需要重啟服務,是否繼續?', sslDisable: '禁用', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 53199a085..2550803fb 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -1118,6 +1118,7 @@ const message = { mfaHelper3: '输入手机应用上的 6 位数字', mfaCode: '验证码', mfaInterval: '刷新时间(秒)', + mfaTitleHelper: '用于区分不同 1Panel 主机,修改后请重新扫描或手动添加密钥信息!', mfaIntervalHelper: '修改刷新时间后,请重新扫描或手动添加密钥信息!', sslChangeHelper: 'https 设置修改需要重启服务,是否继续?', sslDisable: '禁用', diff --git a/frontend/src/views/setting/safe/mfa/index.vue b/frontend/src/views/setting/safe/mfa/index.vue index 45d069a3f..4f644ada7 100644 --- a/frontend/src/views/setting/safe/mfa/index.vue +++ b/frontend/src/views/setting/safe/mfa/index.vue @@ -52,6 +52,16 @@ + + + + + {{ $t('setting.mfaTitleHelper') }} +