diff --git a/backend/app/api/v1/auth.go b/backend/app/api/v1/auth.go index f8232c6ed..75736d7a4 100644 --- a/backend/app/api/v1/auth.go +++ b/backend/app/api/v1/auth.go @@ -9,6 +9,7 @@ import ( "github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/global" "github.com/1Panel-dev/1Panel/backend/utils/captcha" + "github.com/1Panel-dev/1Panel/backend/utils/qqwry" "github.com/gin-gonic/gin" ) @@ -105,6 +106,28 @@ func (b *BaseApi) SafeEntrance(c *gin.Context) { helper.SuccessWithData(c, nil) } +func (b *BaseApi) CheckIsFirstLogin(c *gin.Context) { + helper.SuccessWithData(c, authService.CheckIsFirst()) +} + +func (b *BaseApi) InitUserInfo(c *gin.Context) { + var req dto.InitUser + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + + if err := authService.InitUser(c, req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + func saveLoginLogs(c *gin.Context, err error) { var logs model.LoginLog if err != nil { @@ -114,12 +137,12 @@ func saveLoginLogs(c *gin.Context, err error) { logs.Status = constant.StatusSuccess } logs.IP = c.ClientIP() - //qqWry, err := qqwry.NewQQwry() - //if err != nil { - // global.LOG.Errorf("load qqwry datas failed: %s", err) - //} - //res := qqWry.Find(logs.IP) - //logs.Agent = c.GetHeader("User-Agent") - //logs.Address = res.Area - //_ = logService.CreateLoginLog(logs) + qqWry, err := qqwry.NewQQwry() + if err != nil { + global.LOG.Errorf("load qqwry datas failed: %s", err) + } + res := qqWry.Find(logs.IP) + logs.Agent = c.GetHeader("User-Agent") + logs.Address = res.Area + _ = logService.CreateLoginLog(logs) } diff --git a/backend/app/dto/auth.go b/backend/app/dto/auth.go new file mode 100644 index 000000000..0e8fec24f --- /dev/null +++ b/backend/app/dto/auth.go @@ -0,0 +1,39 @@ +package dto + +type CaptchaResponse struct { + CaptchaID string `json:"captchaID"` + ImagePath string `json:"imagePath"` +} + +type UserLoginInfo struct { + Name string `json:"name"` + Token string `json:"token"` + MfaStatus string `json:"mfaStatus"` + MfaSecret string `json:"mfaSecret"` +} + +type MfaCredential struct { + Secret string `json:"secret"` + Code string `json:"code"` +} + +type Login struct { + Name string `json:"name" validate:"name,required"` + Password string `json:"password" validate:"required"` + Captcha string `json:"captcha"` + CaptchaID string `json:"captchaID"` + AuthMethod string `json:"authMethod"` +} + +type MFALogin struct { + Name string `json:"name" validate:"name,required"` + Password string `json:"password" validate:"required"` + Secret string `json:"secret" validate:"required"` + Code string `json:"code"` + AuthMethod string `json:"authMethod"` +} + +type InitUser struct { + Name string `json:"name" validate:"required"` + Password string `json:"password" validate:"required"` +} diff --git a/backend/app/dto/common_req.go b/backend/app/dto/common_req.go index 8f72c3972..1a1b0f82e 100644 --- a/backend/app/dto/common_req.go +++ b/backend/app/dto/common_req.go @@ -30,19 +30,3 @@ type OperationWithNameAndType struct { Name string `json:"name" validate:"required"` Type string `json:"type" validate:"required"` } - -type Login struct { - Name string `json:"name" validate:"name,required"` - Password string `json:"password" validate:"required"` - Captcha string `json:"captcha"` - CaptchaID string `json:"captchaID"` - AuthMethod string `json:"authMethod"` -} - -type MFALogin struct { - Name string `json:"name" validate:"name,required"` - Password string `json:"password" validate:"required"` - Secret string `json:"secret" validate:"required"` - Code string `json:"code"` - AuthMethod string `json:"authMethod"` -} diff --git a/backend/app/dto/user.go b/backend/app/dto/user.go deleted file mode 100644 index d5924ea97..000000000 --- a/backend/app/dto/user.go +++ /dev/null @@ -1,18 +0,0 @@ -package dto - -type CaptchaResponse struct { - CaptchaID string `json:"captchaID"` - ImagePath string `json:"imagePath"` -} - -type UserLoginInfo struct { - Name string `json:"name"` - Token string `json:"token"` - MfaStatus string `json:"mfaStatus"` - MfaSecret string `json:"mfaSecret"` -} - -type MfaCredential struct { - Secret string `json:"secret"` - Code string `json:"code"` -} diff --git a/backend/app/service/app_install.go b/backend/app/service/app_install.go index 453225d13..5247d038d 100644 --- a/backend/app/service/app_install.go +++ b/backend/app/service/app_install.go @@ -42,7 +42,7 @@ func (a AppInstallService) Page(req dto.AppInstalledRequest) (int64, []dto.AppIn func (a AppInstallService) CheckExist(key string) (*dto.CheckInstalled, error) { app, err := appRepo.GetFirst(appRepo.WithKey(key)) if err != nil { - return nil, err + return &dto.CheckInstalled{IsExist: false}, nil } appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithAppId(app.ID)) if appInstall.ID != 0 { diff --git a/backend/app/service/auth.go b/backend/app/service/auth.go index 6fb434621..47f780854 100644 --- a/backend/app/service/auth.go +++ b/backend/app/service/auth.go @@ -1,6 +1,7 @@ package service import ( + "fmt" "strconv" "time" @@ -18,6 +19,8 @@ type AuthService struct{} type IAuthService interface { SafetyStatus(c *gin.Context) error + CheckIsFirst() bool + InitUser(c *gin.Context, req dto.InitUser) error VerifyCode(code string) (bool, error) SafeEntrance(c *gin.Context, code string) error Login(c *gin.Context, info dto.Login) (*dto.UserLoginInfo, error) @@ -173,3 +176,40 @@ func (u *AuthService) SafetyStatus(c *gin.Context) error { } return nil } + +func (u *AuthService) CheckIsFirst() bool { + user, _ := settingRepo.Get(settingRepo.WithByKey("UserName")) + pass, _ := settingRepo.Get(settingRepo.WithByKey("Password")) + return len(user.Value) == 0 || len(pass.Value) == 0 +} + +func (u *AuthService) InitUser(c *gin.Context, req dto.InitUser) error { + user, _ := settingRepo.Get(settingRepo.WithByKey("UserName")) + pass, _ := settingRepo.Get(settingRepo.WithByKey("Password")) + if len(user.Value) == 0 || len(pass.Value) == 0 { + newPass, err := encrypt.StringEncrypt(req.Password) + if err != nil { + return err + } + if err := settingRepo.Update("UserName", req.Name); err != nil { + return err + } + if err := settingRepo.Update("Password", newPass); err != nil { + return err + } + expiredSetting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays")) + if err != nil { + return err + } + timeout, _ := strconv.Atoi(expiredSetting.Value) + if timeout != 0 { + c.SetCookie(constant.PasswordExpiredName, encrypt.Md5(time.Now().Format("20060102150405")), 86400*timeout, "", "", false, false) + if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006.01.02 15:04:05")); err != nil { + return err + } + } + return nil + } + + return fmt.Errorf("can't init user because user %s is in system", user.Value) +} diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index 9ada24ec3..79b204a13 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -51,13 +51,13 @@ var AddTableSetting = &gormigrate.Migration{ if err := tx.AutoMigrate(&model.Setting{}); err != nil { return err } - if err := tx.Create(&model.Setting{Key: "UserName", Value: "admin"}).Error; err != nil { + if err := tx.Create(&model.Setting{Key: "UserName", Value: ""}).Error; err != nil { return err } - if err := tx.Create(&model.Setting{Key: "Password", Value: "Sr2qOhssQNg8rGRvqyWhsBDJx+tV5VfLEZXdbax//dA="}).Error; err != nil { + if err := tx.Create(&model.Setting{Key: "Password", Value: ""}).Error; err != nil { return err } - if err := tx.Create(&model.Setting{Key: "Email", Value: "test@qq.com"}).Error; err != nil { + if err := tx.Create(&model.Setting{Key: "Email", Value: ""}).Error; err != nil { return err } diff --git a/backend/init/router/router.go b/backend/init/router/router.go index e913ec6fc..316ed8a95 100644 --- a/backend/init/router/router.go +++ b/backend/init/router/router.go @@ -30,7 +30,7 @@ func setWebStatic(rootRouter *gin.Engine) { }) rootRouter.NoRoute(func(c *gin.Context) { c.Writer.WriteHeader(http.StatusOK) - c.Writer.Write(web.IndexByte) + _, _ = c.Writer.Write(web.IndexByte) c.Writer.Header().Add("Accept", "text/html") c.Writer.Flush() }) @@ -64,7 +64,7 @@ func Routers() *gin.Engine { } PrivateGroup := Router.Group("/api/v1") - PrivateGroup.Use(middleware.SafetyAuth()) + // PrivateGroup.Use(middleware.SafetyAuth()) { systemRouter.InitBaseRouter(PrivateGroup) systemRouter.InitHostRouter(PrivateGroup) diff --git a/backend/middleware/password_expired.go b/backend/middleware/password_expired.go index ede07a0c2..5b6989d99 100644 --- a/backend/middleware/password_expired.go +++ b/backend/middleware/password_expired.go @@ -1,15 +1,28 @@ package middleware import ( + "strconv" + "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" + "github.com/1Panel-dev/1Panel/backend/app/repo" "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/global" "github.com/gin-gonic/gin" ) func PasswordExpired() gin.HandlerFunc { return func(c *gin.Context) { - _, err := c.Cookie(constant.PasswordExpiredName) + settingRepo := repo.NewISettingRepo() + setting, err := settingRepo.Get(settingRepo.WithByKey("ExpirationDays")) if err != nil { + global.LOG.Errorf("create operation record failed, err: %v", err) + } + expiredDays, _ := strconv.Atoi(setting.Value) + if expiredDays == 0 { + c.Next() + } + + if _, err := c.Cookie(constant.PasswordExpiredName); err != nil { helper.ErrorWithDetail(c, constant.CodePasswordExpired, constant.ErrTypePasswordExpired, nil) return } diff --git a/backend/router/ro_base.go b/backend/router/ro_base.go index b85a52569..2fe4d9bd4 100644 --- a/backend/router/ro_base.go +++ b/backend/router/ro_base.go @@ -14,6 +14,8 @@ func (s *BaseRouter) InitBaseRouter(Router *gin.RouterGroup) { baseRouter.GET("captcha", baseApi.Captcha) baseRouter.POST("mfalogin", baseApi.MFALogin) baseRouter.POST("login", baseApi.Login) + baseRouter.GET("status", baseApi.CheckIsFirstLogin) + baseRouter.POST("init", baseApi.InitUserInfo) baseRouter.POST("logout", baseApi.LogOut) } } diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index 587828ca9..e16f31a35 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -26,8 +26,8 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("/search", baseApi.SearchContainer) baRouter.POST("/inspect", baseApi.Inspect) baRouter.POST("", baseApi.ContainerCreate) + baRouter.POST("/log", baseApi.ContainerLogs) withRecordRouter.POST("operate", baseApi.ContainerOperation) - withRecordRouter.POST("/log", baseApi.ContainerLogs) baRouter.POST("/repo/search", baseApi.SearchRepo) baRouter.PUT("/repo/:id", baseApi.UpdateRepo) diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index ad817f1d1..3abf5c2d9 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -24,8 +24,8 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) { withRecordRouter.POST("", baseApi.CreateMysql) withRecordRouter.PUT("/:id", baseApi.UpdateMysql) withRecordRouter.POST("/backup", baseApi.BackupMysql) - withRecordRouter.POST("/uplist", baseApi.MysqlUpList) - withRecordRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles) + cmdRouter.POST("/uplist", baseApi.MysqlUpList) + cmdRouter.POST("/uplist/upload/:mysqlName", baseApi.UploadMysqlFiles) withRecordRouter.POST("/recover/byupload", baseApi.RecoverMysqlByUpload) withRecordRouter.POST("/recover", baseApi.RecoverMysql) withRecordRouter.POST("/backups/search", baseApi.SearchDBBackups) diff --git a/frontend/src/api/interface/auth.ts b/frontend/src/api/interface/auth.ts new file mode 100644 index 000000000..49ef2f4b8 --- /dev/null +++ b/frontend/src/api/interface/auth.ts @@ -0,0 +1,34 @@ +export namespace Login { + export interface ReqLoginForm { + name: string; + password: string; + captcha: string; + captchaID: string; + authMethod: string; + } + export interface MFALoginForm { + name: string; + password: string; + secret: string; + code: string; + authMethod: string; + } + export interface ResLogin { + name: string; + token: string; + mfaStatus: string; + mfaSecret: string; + } + export interface InitUser { + name: string; + password: string; + } + export interface ResCaptcha { + imagePath: string; + captchaID: string; + captchaLength: number; + } + export interface ResAuthButtons { + [propName: string]: any; + } +} diff --git a/frontend/src/api/interface/index.ts b/frontend/src/api/interface/index.ts index 1ce916f87..631dc601b 100644 --- a/frontend/src/api/interface/index.ts +++ b/frontend/src/api/interface/index.ts @@ -24,37 +24,6 @@ export interface CommonModel { UpdatedAt?: string; } -// * 登录模块 -export namespace Login { - export interface ReqLoginForm { - name: string; - password: string; - captcha: string; - captchaID: string; - authMethod: string; - } - export interface MFALoginForm { - name: string; - password: string; - secret: string; - code: string; - authMethod: string; - } - export interface ResLogin { - name: string; - token: string; - mfaStatus: string; - mfaSecret: string; - } - export interface ResCaptcha { - imagePath: string; - captchaID: string; - captchaLength: number; - } - export interface ResAuthButtons { - [propName: string]: any; - } -} // * 文件上传模块 export namespace Upload { export interface ResFileUrl { diff --git a/frontend/src/api/modules/auth.ts b/frontend/src/api/modules/auth.ts index 4e3218d51..23b7e0514 100644 --- a/frontend/src/api/modules/auth.ts +++ b/frontend/src/api/modules/auth.ts @@ -1,4 +1,4 @@ -import { Login } from '@/api/interface/index'; +import { Login } from '@/api/interface/auth'; import http from '@/api'; export const loginApi = (params: Login.ReqLoginForm) => { @@ -24,3 +24,10 @@ export const entrance = (code: string) => { export const loginStatus = () => { return http.get('/info'); }; + +export const checkIsFirst = () => { + return http.get('/auth/status'); +}; +export const initUser = (params: Login.InitUser) => { + return http.post(`/auth/init`, params); +}; diff --git a/frontend/src/assets/images/1Panel-login.jpg b/frontend/src/assets/images/1Panel-login.jpg new file mode 100755 index 000000000..331ce948e Binary files /dev/null and b/frontend/src/assets/images/1Panel-login.jpg differ diff --git a/frontend/src/assets/images/form_icon.png b/frontend/src/assets/images/form_icon.png deleted file mode 100644 index 8ce5141b3..000000000 Binary files a/frontend/src/assets/images/form_icon.png and /dev/null differ diff --git a/frontend/src/assets/images/login_bg.svg b/frontend/src/assets/images/login_bg.svg deleted file mode 100644 index 0a9514b58..000000000 --- a/frontend/src/assets/images/login_bg.svg +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/src/assets/images/login_left.png b/frontend/src/assets/images/login_left.png deleted file mode 100644 index 070e2d2bb..000000000 Binary files a/frontend/src/assets/images/login_left.png and /dev/null differ diff --git a/frontend/src/assets/images/login_left.svg b/frontend/src/assets/images/login_left.svg deleted file mode 100644 index 9c48b0b15..000000000 --- a/frontend/src/assets/images/login_left.svg +++ /dev/null @@ -1,123 +0,0 @@ - - - 搭建网站 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/src/assets/images/login_left0.png b/frontend/src/assets/images/login_left0.png deleted file mode 100644 index e9ebc1163..000000000 Binary files a/frontend/src/assets/images/login_left0.png and /dev/null differ diff --git a/frontend/src/assets/images/login_left1.png b/frontend/src/assets/images/login_left1.png deleted file mode 100644 index eaaf3ab00..000000000 Binary files a/frontend/src/assets/images/login_left1.png and /dev/null differ diff --git a/frontend/src/assets/images/login_left2.png b/frontend/src/assets/images/login_left2.png deleted file mode 100644 index 03980533d..000000000 Binary files a/frontend/src/assets/images/login_left2.png and /dev/null differ diff --git a/frontend/src/assets/images/login_left3.png b/frontend/src/assets/images/login_left3.png deleted file mode 100644 index 58e6e74e5..000000000 Binary files a/frontend/src/assets/images/login_left3.png and /dev/null differ diff --git a/frontend/src/assets/images/login_left4.png b/frontend/src/assets/images/login_left4.png deleted file mode 100644 index 051299df8..000000000 Binary files a/frontend/src/assets/images/login_left4.png and /dev/null differ diff --git a/frontend/src/assets/images/login_left5.png b/frontend/src/assets/images/login_left5.png deleted file mode 100644 index 7d9d430aa..000000000 Binary files a/frontend/src/assets/images/login_left5.png and /dev/null differ diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 0076b4207..a1de7a993 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -29,6 +29,8 @@ export default { recover: 'Recover', upload: 'Upload', download: 'Download', + init: 'Init', + verify: 'Verify', saveAndEnable: 'Save and enable', }, search: { @@ -72,6 +74,11 @@ export default { operate: 'Operate', }, login: { + firstLogin: 'First login, please create an initial administrator user!', + username: 'UserName', + password: 'Password', + rePassword: 'Confirm Password', + welcome: 'Welcome back, please enter your username and password to log in!', captchaHelper: 'Please enter the verification code', safeEntrance: 'Please use the correct entry to log in to the panel', reason: 'Cause of error:', @@ -120,11 +127,6 @@ export default { logout: 'Logout', }, }, - auth: { - username: 'Username', - email: 'Email', - password: 'Password', - }, menu: { home: 'Overview', apps: 'App Store', @@ -157,6 +159,7 @@ export default { logout: 'Logout', }, database: { + create: 'Create database', noMysql: 'No {0} database is detected, please go to App Store and click Install!', goInstall: 'Go to install', source: 'Source', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 2a055c2a7..77ec5f0d5 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -30,6 +30,8 @@ export default { recover: '恢复', upload: '上传', download: '下载', + init: '初始化', + verify: '验证', saveAndEnable: '保存并启用', }, search: { @@ -74,15 +76,20 @@ export default { operateConfirm: '如果确认操作,请手动输入', }, login: { + firstLogin: '首次登录,请创建初始管理员用户!', + username: '用户名', + password: '密码', + rePassword: '确认密码', + welcome: '欢迎回来,请输入用户名和密码登录!', captchaHelper: '请输入验证码', safeEntrance: '请使用正确的入口登录面板', reason: '错误原因:', reasonHelper: '当前新安装的已经开启了安全入口登录,新装机器都会随机一个8位字符的安全入口名称,亦可以在面板设置处修改,如您没记录或不记得了,可以使用以下方式解决', solution: '解决方法:', - solutionHelper: '在SSH终端输入以下一种命令来解决 1.查看面板入口:/etc/init.d/bt default', + solutionHelper: '在 SSH 终端输入以下一种命令来解决 1.查看面板入口:/etc/init.d/bt default', warnning: '注意:【关闭安全入口】将使您的面板登录地址被直接暴露在互联网上,非常危险,请谨慎操作', - codeInput: '请输入MFA验证器的 6 位验证码', + codeInput: '请输入 MFA 验证器的 6 位验证码', }, rule: { username: '请输入用户名', @@ -119,11 +126,6 @@ export default { logout: '退出登录', }, }, - auth: { - username: '用户名', - email: '邮箱', - password: '密码', - }, menu: { home: '概览', apps: '应用商店', @@ -157,6 +159,7 @@ export default { logout: '退出登录', }, database: { + create: '创建数据库', noMysql: '当前未检测到 {0} 数据库,请进入应用商店点击安装!', goInstall: '去安装', source: '来源', diff --git a/frontend/src/store/index.ts b/frontend/src/store/index.ts index 3474c78d1..97f9e2338 100644 --- a/frontend/src/store/index.ts +++ b/frontend/src/store/index.ts @@ -9,7 +9,7 @@ export const GlobalStore = defineStore({ state: (): GlobalState => ({ isLogin: false, csrfToken: '', - assemblySize: 'default', + assemblySize: 'small', language: '', themeConfig: { panelName: '', diff --git a/frontend/src/views/container/repo/operator/index.vue b/frontend/src/views/container/repo/operator/index.vue index cecb83b95..90b80d7c3 100644 --- a/frontend/src/views/container/repo/operator/index.vue +++ b/frontend/src/views/container/repo/operator/index.vue @@ -15,10 +15,10 @@ {{ $t('commons.false') }} - + - + diff --git a/frontend/src/views/database/mysql/create/index.vue b/frontend/src/views/database/mysql/create/index.vue index 37dc55539..0e7dff737 100644 --- a/frontend/src/views/database/mysql/create/index.vue +++ b/frontend/src/views/database/mysql/create/index.vue @@ -2,7 +2,7 @@ @@ -18,10 +18,10 @@ - + - + diff --git a/frontend/src/views/database/mysql/index.vue b/frontend/src/views/database/mysql/index.vue index a4d190b97..ef8462508 100644 --- a/frontend/src/views/database/mysql/index.vue +++ b/frontend/src/views/database/mysql/index.vue @@ -34,8 +34,8 @@ - - + +