mirror of
				https://github.com/1Panel-dev/1Panel.git
				synced 2025-11-01 03:37:19 +08:00 
			
		
		
		
	feat: 主机密码加密存储 (#1516)
This commit is contained in:
		
							parent
							
								
									695d4b4a16
								
							
						
					
					
						commit
						30bb64d058
					
				
					 11 changed files with 643 additions and 811 deletions
				
			
		|  | @ -7,7 +7,7 @@ import ( | |||
| 	"github.com/1Panel-dev/1Panel/backend/app/dto" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/constant" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/global" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/utils/copier" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/utils/encrypt" | ||||
| 	"github.com/gin-gonic/gin" | ||||
| ) | ||||
| 
 | ||||
|  | @ -36,7 +36,12 @@ func (b *BaseApi) CreateHost(c *gin.Context) { | |||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.Password = string(password) | ||||
| 		passwordItem, err := encrypt.StringEncrypt(string(password)) | ||||
| 		if err != nil { | ||||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.Password = passwordItem | ||||
| 	} | ||||
| 	if req.AuthMode == "key" && len(req.PrivateKey) != 0 { | ||||
| 		privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey) | ||||
|  | @ -44,7 +49,12 @@ func (b *BaseApi) CreateHost(c *gin.Context) { | |||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.PrivateKey = string(privateKey) | ||||
| 		keyItem, err := encrypt.StringEncrypt(string(privateKey)) | ||||
| 		if err != nil { | ||||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.Password = keyItem | ||||
| 	} | ||||
| 
 | ||||
| 	host, err := hostService.Create(req) | ||||
|  | @ -148,33 +158,6 @@ func (b *BaseApi) SearchHost(c *gin.Context) { | |||
| 	}) | ||||
| } | ||||
| 
 | ||||
| // @Tags Host | ||||
| // @Summary Load host info | ||||
| // @Description 加载主机信息 | ||||
| // @Accept json | ||||
| // @Param id path integer true "request" | ||||
| // @Success 200 {object} dto.HostInfo | ||||
| // @Security ApiKeyAuth | ||||
| // @Router /hosts/:id [get] | ||||
| func (b *BaseApi) GetHostInfo(c *gin.Context) { | ||||
| 	id, err := helper.GetParamID(c) | ||||
| 	if err != nil { | ||||
| 		helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 		return | ||||
| 	} | ||||
| 	host, err := hostService.GetHostInfo(id) | ||||
| 	if err != nil { | ||||
| 		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) | ||||
| 		return | ||||
| 	} | ||||
| 	var hostDto dto.HostInfo | ||||
| 	if err := copier.Copy(&hostDto, host); err != nil { | ||||
| 		helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) | ||||
| 		return | ||||
| 	} | ||||
| 	helper.SuccessWithData(c, hostDto) | ||||
| } | ||||
| 
 | ||||
| // @Tags Host | ||||
| // @Summary Delete host | ||||
| // @Description 删除主机 | ||||
|  | @ -227,7 +210,12 @@ func (b *BaseApi) UpdateHost(c *gin.Context) { | |||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.Password = string(password) | ||||
| 		passwordItem, err := encrypt.StringEncrypt(string(password)) | ||||
| 		if err != nil { | ||||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.Password = passwordItem | ||||
| 	} | ||||
| 	if req.AuthMode == "key" && len(req.PrivateKey) != 0 { | ||||
| 		privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey) | ||||
|  | @ -235,7 +223,12 @@ func (b *BaseApi) UpdateHost(c *gin.Context) { | |||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.PrivateKey = string(privateKey) | ||||
| 		keyItem, err := encrypt.StringEncrypt(string(privateKey)) | ||||
| 		if err != nil { | ||||
| 			helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) | ||||
| 			return | ||||
| 		} | ||||
| 		req.PrivateKey = keyItem | ||||
| 	} | ||||
| 
 | ||||
| 	upMap := make(map[string]interface{}) | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import ( | |||
| 	"github.com/1Panel-dev/1Panel/backend/app/dto" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/app/model" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/constant" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/utils/encrypt" | ||||
| 	"github.com/1Panel-dev/1Panel/backend/utils/ssh" | ||||
| 	"github.com/jinzhu/copier" | ||||
| 	"github.com/pkg/errors" | ||||
|  | @ -89,7 +90,20 @@ func (u *HostService) TestLocalConn(id uint) bool { | |||
| 	if err := copier.Copy(&connInfo, &host); err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if len(host.Password) != 0 { | ||||
| 		host.Password, err = encrypt.StringDecrypt(host.Password) | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		connInfo.Password = host.Password | ||||
| 	} | ||||
| 	if len(host.PrivateKey) != 0 { | ||||
| 		host.PrivateKey, err = encrypt.StringDecrypt(host.PrivateKey) | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		connInfo.PrivateKey = []byte(host.PrivateKey) | ||||
| 	} | ||||
| 	if len(host.PassPhrase) != 0 { | ||||
| 		connInfo.PassPhrase = []byte(host.PassPhrase) | ||||
| 	} | ||||
|  | @ -107,6 +121,18 @@ func (u *HostService) GetHostInfo(id uint) (*model.Host, error) { | |||
| 	if err != nil { | ||||
| 		return nil, constant.ErrRecordNotFound | ||||
| 	} | ||||
| 	if len(host.Password) != 0 { | ||||
| 		host.Password, err = encrypt.StringDecrypt(host.Password) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	if len(host.PrivateKey) != 0 { | ||||
| 		host.PrivateKey, err = encrypt.StringDecrypt(host.PrivateKey) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return &host, err | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ func Init() { | |||
| 		migrations.AddBackupAccountDir, | ||||
| 		migrations.AddMfaInterval, | ||||
| 		migrations.UpdateAppDetail, | ||||
| 		migrations.EncryptHostPassword, | ||||
| 	}) | ||||
| 	if err := m.Migrate(); err != nil { | ||||
| 		global.LOG.Error(err) | ||||
|  |  | |||
|  | @ -426,3 +426,35 @@ var UpdateAppDetail = &gormigrate.Migration{ | |||
| 		return nil | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| var EncryptHostPassword = &gormigrate.Migration{ | ||||
| 	ID: "20230703-encrypt-host-password", | ||||
| 	Migrate: func(tx *gorm.DB) error { | ||||
| 		var hosts []model.Host | ||||
| 		if err := tx.Find(&hosts).Error; err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		for _, host := range hosts { | ||||
| 			if len(host.Password) != 0 { | ||||
| 				pass, err := encrypt.StringEncrypt(host.Password) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if err := tx.Model(&model.Host{}).Where("id = ?", host.ID).Update("password", pass).Error; err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 			if len(host.PrivateKey) != 0 { | ||||
| 				key, err := encrypt.StringEncrypt(host.PrivateKey) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				if err := tx.Model(&model.Host{}).Update("private_key", key).Error; err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	}, | ||||
| } | ||||
|  |  | |||
|  | @ -24,7 +24,6 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) { | |||
| 		hostRouter.POST("/tree", baseApi.HostTree) | ||||
| 		hostRouter.POST("/test/byinfo", baseApi.TestByInfo) | ||||
| 		hostRouter.POST("/test/byid/:id", baseApi.TestByID) | ||||
| 		hostRouter.GET(":id", baseApi.GetHostInfo) | ||||
| 
 | ||||
| 		hostRouter.GET("/firewall/base", baseApi.LoadFirewallBaseInfo) | ||||
| 		hostRouter.POST("/firewall/search", baseApi.SearchFirewallRule) | ||||
|  |  | |||
|  | @ -34,6 +34,7 @@ func Start() { | |||
| 	log.Init() | ||||
| 	app.Init() | ||||
| 	db.Init() | ||||
| 	hook.Init() | ||||
| 	migration.Init() | ||||
| 	validator.Init() | ||||
| 	gob.Register(psession.SessionUser{}) | ||||
|  | @ -42,7 +43,6 @@ func Start() { | |||
| 	gin.SetMode("debug") | ||||
| 	cron.Run() | ||||
| 	business.Init() | ||||
| 	hook.Init() | ||||
| 
 | ||||
| 	rootRouter := router.Routers() | ||||
| 	address := fmt.Sprintf(":%s", global.CONF.System.Port) | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ import ( | |||
| 	"crypto/rand" | ||||
| 	"encoding/base64" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 
 | ||||
|  | @ -15,6 +16,9 @@ import ( | |||
| ) | ||||
| 
 | ||||
| func StringEncrypt(text string) (string, error) { | ||||
| 	if len(text) == 0 { | ||||
| 		return "", errors.New("it is not possible to encrypt an empty string.") | ||||
| 	} | ||||
| 	key := global.CONF.System.EncryptKey | ||||
| 	pass := []byte(text) | ||||
| 	xpass, err := aesEncryptWithSalt([]byte(key), pass) | ||||
|  | @ -26,6 +30,9 @@ func StringEncrypt(text string) (string, error) { | |||
| } | ||||
| 
 | ||||
| func StringDecrypt(text string) (string, error) { | ||||
| 	if len(text) == 0 { | ||||
| 		return "", errors.New("it is not possible to decrypt an empty string.") | ||||
| 	} | ||||
| 	key := global.CONF.System.EncryptKey | ||||
| 	bytesPass, err := base64.StdEncoding.DecodeString(text) | ||||
| 	if err != nil { | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -11,9 +11,6 @@ export const searchHosts = (params: Host.SearchWithPage) => { | |||
| export const getHostTree = (params: Host.ReqSearch) => { | ||||
|     return http.post<Array<Host.HostTree>>(`/hosts/tree`, params); | ||||
| }; | ||||
| export const getHostInfo = (id: number) => { | ||||
|     return http.get<Host.Host>(`/hosts/` + id); | ||||
| }; | ||||
| export const addHost = (params: Host.HostOperate) => { | ||||
|     let reqest = deepCopy(params) as Host.HostOperate; | ||||
|     if (reqest.password) { | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue