修改docker默认时区为上海

修复了记住登录无效的问题
修复了ssh下载文件名称不正确的问题
授权凭证增加了密钥类型
This commit is contained in:
dushixiang
2021-01-08 23:01:41 +08:00
parent 636b91e0f7
commit bc9daf2b01
22 changed files with 274 additions and 74 deletions

View File

@ -1,13 +1,11 @@
package api
import (
"log"
"time"
"next-terminal/pkg/global"
"next-terminal/pkg/model"
"next-terminal/pkg/totp"
"next-terminal/pkg/utils"
"time"
"github.com/labstack/echo/v4"
)
@ -15,6 +13,7 @@ import (
type LoginAccount struct {
Username string `json:"username"`
Password string `json:"password"`
Remember bool `json:"remember"`
TOTP string `json:"totp"`
}
@ -28,6 +27,12 @@ type ChangePassword struct {
OldPassword string `json:"oldPassword"`
}
type Authorization struct {
Token string
Remember bool
User model.User
}
func LoginEndpoint(c echo.Context) error {
var loginAccount LoginAccount
if err := c.Bind(&loginAccount); err != nil {
@ -43,15 +48,24 @@ func LoginEndpoint(c echo.Context) error {
return Fail(c, -1, "您输入的账号或密码不正确")
}
log.Println(user, loginAccount)
if !totp.Validate(loginAccount.TOTP, user.TOTPSecret) {
return Fail(c, -2, "您的TOTP不匹配")
}
token := utils.UUID()
global.Cache.Set(token, user, time.Minute*time.Duration(30))
authorization := Authorization{
Token: token,
Remember: loginAccount.Remember,
User: user,
}
if authorization.Remember {
// 记住登录有效期两周
global.Cache.Set(token, authorization, time.Hour*time.Duration(24*14))
} else {
global.Cache.Set(token, authorization, time.Hour*time.Duration(2))
}
model.UpdateUserById(&model.User{Online: true}, user.ID)

View File

@ -112,11 +112,8 @@ func AssetTcpingEndpoint(c echo.Context) (err error) {
}
active := utils.Tcping(item.IP, item.Port)
asset := model.Asset{
Active: active,
}
model.UpdateAssetById(&asset, item.ID)
model.UpdateAssetActiveById(active, item.ID)
return Success(c, active)
}

View File

@ -21,6 +21,31 @@ func CredentialCreateEndpoint(c echo.Context) error {
item.ID = utils.UUID()
item.Created = utils.NowJsonTime()
switch item.Type {
case model.Custom:
item.PrivateKey = "-"
item.Passphrase = "-"
if len(item.Username) == 0 {
item.Username = "-"
}
if len(item.Password) == 0 {
item.Password = "-"
}
case model.PrivateKey:
item.Password = "-"
if len(item.Username) == 0 {
item.Username = "-"
}
if len(item.PrivateKey) == 0 {
item.PrivateKey = "-"
}
if len(item.Passphrase) == 0 {
item.Passphrase = "-"
}
default:
return Fail(c, -1, "类型错误")
}
if err := model.CreateNewCredential(&item); err != nil {
return err
}
@ -49,6 +74,31 @@ func CredentialUpdateEndpoint(c echo.Context) error {
return err
}
switch item.Type {
case model.Custom:
item.PrivateKey = "-"
item.Passphrase = "-"
if len(item.Username) == 0 {
item.Username = "-"
}
if len(item.Password) == 0 {
item.Password = "-"
}
case model.PrivateKey:
item.Password = "-"
if len(item.Username) == 0 {
item.Username = "-"
}
if len(item.PrivateKey) == 0 {
item.PrivateKey = "-"
}
if len(item.Passphrase) == 0 {
item.Passphrase = "-"
}
default:
return Fail(c, -1, "类型错误")
}
model.UpdateCredentialById(&item, id)
return Success(c, nil)

View File

@ -34,12 +34,19 @@ func Auth(next echo.HandlerFunc) echo.HandlerFunc {
}
token := GetToken(c)
user, found := global.Cache.Get(token)
authorization, found := global.Cache.Get(token)
if !found {
logrus.Debugf("您的登录信息已失效,请重新登录后再试。")
return Fail(c, 403, "您的登录信息已失效,请重新登录后再试。")
}
global.Cache.Set(token, user, time.Minute*time.Duration(30))
if authorization.(Authorization).Remember {
// 记住登录有效期两周
global.Cache.Set(token, authorization, time.Hour*time.Duration(24*14))
} else {
global.Cache.Set(token, authorization, time.Hour*time.Duration(2))
}
return next(c)
}
}

View File

@ -154,7 +154,7 @@ func GetCurrentAccount(c echo.Context) (model.User, bool) {
token := GetToken(c)
get, b := global.Cache.Get(token)
if b {
return get.(model.User), true
return get.(Authorization).User, true
}
return model.User{}, false
}

View File

@ -185,8 +185,14 @@ func SessionCreateEndpoint(c echo.Context) error {
return err
}
session.Username = credential.Username
session.Password = credential.Password
if credential.Type == model.Custom {
session.Username = credential.Username
session.Password = credential.Password
} else {
session.Username = credential.Username
session.PrivateKey = credential.PrivateKey
session.Passphrase = credential.Passphrase
}
}
if err := model.CreateNewSession(session); err != nil {
@ -223,12 +229,11 @@ func SessionUploadEndpoint(c echo.Context) error {
}
dstFile, err := tun.SftpClient.Create(remoteFile)
defer dstFile.Close()
if err != nil {
return err
}
defer dstFile.Close()
buf := make([]byte, 1024)
for {
n, _ := src.Read(buf)
@ -282,7 +287,9 @@ func SessionDownloadEndpoint(c echo.Context) error {
}
defer dstFile.Close()
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", remoteFile))
// 获取带后缀的文件名称
filenameWithSuffix := path.Base(remoteFile)
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filenameWithSuffix))
var buff bytes.Buffer
if _, err := dstFile.WriteTo(&buff); err != nil {

View File

@ -49,6 +49,7 @@ func (w *NextWriter) Read() ([]byte, int, error) {
func SSHEndpoint(c echo.Context) error {
ws, err := UpGrader.Upgrade(c.Response().Writer, c.Request(), nil)
if err != nil {
logrus.Errorf("升级为WebSocket协议失败%v", err.Error())
return err
}
@ -58,11 +59,13 @@ func SSHEndpoint(c echo.Context) error {
sshClient, err := CreateSshClient(assetId)
if err != nil {
logrus.Errorf("创建SSH客户端失败%v", err.Error())
return err
}
session, err := sshClient.NewSession()
if err != nil {
logrus.Errorf("创建SSH会话失败%v", err.Error())
return err
}
defer session.Close()
@ -123,36 +126,62 @@ func CreateSshClient(assetId string) (*ssh.Client, error) {
return nil, err
}
var (
accountType = asset.AccountType
username = asset.Username
password = asset.Password
privateKey = asset.PrivateKey
passphrase = asset.Passphrase
)
var authMethod ssh.AuthMethod
if asset.AccountType == "credential" {
if accountType == "credential" {
credential, err := model.FindCredentialById(asset.CredentialId)
if err != nil {
return nil, err
}
asset.Username = credential.Username
asset.Password = credential.Password
authMethod = ssh.Password(asset.Password)
} else if asset.AccountType == "private-key" {
accountType = credential.Type
username = credential.Username
password = credential.Password
privateKey = credential.PrivateKey
passphrase = credential.Passphrase
}
if username == "-" {
username = ""
}
if password == "-" {
password = ""
}
if privateKey == "-" {
privateKey = ""
}
if passphrase == "-" {
passphrase = ""
}
if accountType == model.PrivateKey {
var key ssh.Signer
if len(asset.Passphrase) > 0 {
key, err = ssh.ParsePrivateKeyWithPassphrase([]byte(asset.PrivateKey), []byte(asset.Passphrase))
if len(passphrase) > 0 {
key, err = ssh.ParsePrivateKeyWithPassphrase([]byte(privateKey), []byte(passphrase))
if err != nil {
return nil, err
}
} else {
key, err = ssh.ParsePrivateKey([]byte(asset.PrivateKey))
key, err = ssh.ParsePrivateKey([]byte(privateKey))
if err != nil {
return nil, err
}
}
authMethod = ssh.PublicKeys(key)
} else {
authMethod = ssh.Password(asset.Password)
authMethod = ssh.Password(password)
}
config := &ssh.ClientConfig{
Timeout: 1 * time.Second,
User: asset.Username,
User: username,
Auth: []ssh.AuthMethod{authMethod},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

View File

@ -29,6 +29,7 @@ func TunEndpoint(c echo.Context) error {
width := c.QueryParam("width")
height := c.QueryParam("height")
dpi := c.QueryParam("dpi")
sessionId := c.QueryParam("sessionId")
connectionId := c.QueryParam("connectionId")
@ -38,6 +39,7 @@ func TunEndpoint(c echo.Context) error {
configuration := guacd.NewConfiguration()
configuration.SetParameter("width", width)
configuration.SetParameter("height", height)
configuration.SetParameter("dpi", dpi)
propertyMap := model.FindAllPropertiesMap()
@ -73,8 +75,6 @@ func TunEndpoint(c echo.Context) error {
configuration.SetParameter("security", "any")
configuration.SetParameter("ignore-cert", "true")
configuration.SetParameter("create-drive-path", "true")
configuration.SetParameter("dpi", "96")
configuration.SetParameter("resize-method", "reconnect")
configuration.SetParameter(guacd.EnableDrive, propertyMap[guacd.EnableDrive])
configuration.SetParameter(guacd.DriveName, propertyMap[guacd.DriveName])
@ -99,9 +99,7 @@ func TunEndpoint(c echo.Context) error {
configuration.SetParameter("password", session.Password)
}
fontSize, _ := strconv.Atoi(propertyMap[guacd.FontSize])
fontSize = fontSize * 2
configuration.SetParameter(guacd.FontSize, strconv.Itoa(fontSize))
configuration.SetParameter(guacd.FontSize, propertyMap[guacd.FontSize])
configuration.SetParameter(guacd.FontName, propertyMap[guacd.FontName])
configuration.SetParameter(guacd.ColorScheme, propertyMap[guacd.ColorScheme])
break

View File

@ -134,8 +134,10 @@ func NewTunnel(address string, config Configuration) (ret *Tunnel, err error) {
width := config.GetParameter("width")
height := config.GetParameter("height")
dpi := config.GetParameter("dpi")
// send size
if err := ret.WriteInstructionAndFlush(NewInstruction("size", width, height, "96")); err != nil {
if err := ret.WriteInstructionAndFlush(NewInstruction("size", width, height, dpi)); err != nil {
return nil, err
}

View File

@ -10,7 +10,7 @@ import (
func RunTicker() {
var ch chan int
//定时任务
// 定时任务,每隔一小时删除一次未使用的会话信息
ticker := time.NewTicker(time.Minute * 60)
go func() {
for range ticker.C {

View File

@ -85,6 +85,11 @@ func UpdateAssetById(o *Asset, id string) {
global.DB.Updates(o)
}
func UpdateAssetActiveById(active bool, id string) {
sql := "update assets set active = ? where id = ?"
global.DB.Exec(sql, active, id)
}
func DeleteAssetById(id string) {
global.DB.Where("id = ?", id).Delete(&Asset{})
}

View File

@ -5,12 +5,21 @@ import (
"next-terminal/pkg/utils"
)
// 密码
const Custom = "custom"
// 密钥
const PrivateKey = "private-key"
type Credential struct {
ID string `gorm:"primary_key" json:"id"`
Name string `json:"name"`
Username string `json:"username"`
Password string `json:"password"`
Created utils.JsonTime `json:"created"`
ID string `gorm:"primary_key" json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Username string `json:"username"`
Password string `json:"password"`
PrivateKey string `json:"privateKey"`
Passphrase string `json:"passphrase"`
Created utils.JsonTime `json:"created"`
}
func (r *Credential) TableName() string {