diff --git a/README.md b/README.md index c71a969..0ddc070 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,14 @@ https://next.typesafe.cn/ 账号:test 密码:test 默认账号密码为 admin/admin 。 +## 手动编译 + +1. 找一台Linux 机器或者Mac +2. 安装 go 1.18 或以上版本 +3. 安装 nodejs 16,安装 npm 或 yarn +4. 进入 web 目录 执行 yarn install 或 npm install +5. 返回上级目录,也就是项目根目录,执行 sh build.sh + ## 问题反馈 - Issues diff --git a/server/api/asset.go b/server/api/asset.go index 3866970..02133e0 100644 --- a/server/api/asset.go +++ b/server/api/asset.go @@ -5,12 +5,11 @@ import ( "context" "encoding/csv" "errors" - "next-terminal/server/common" - "next-terminal/server/common/maps" - "next-terminal/server/common/nt" "strconv" "strings" + "next-terminal/server/common/maps" + "next-terminal/server/common/nt" "next-terminal/server/model" "next-terminal/server/repository" "next-terminal/server/service" @@ -22,7 +21,7 @@ import ( type AssetApi struct{} func (assetApi AssetApi) AssetCreateEndpoint(c echo.Context) error { - m := echo.Map{} + m := maps.Map{} if err := c.Bind(&m); err != nil { return err } @@ -71,29 +70,31 @@ func (assetApi AssetApi) AssetImportEndpoint(c echo.Context) error { record := records[i] if len(record) >= 9 { port, _ := strconv.Atoi(record[3]) - asset := model.Asset{ - ID: utils.UUID(), - Name: record[0], - Protocol: record[1], - IP: record[2], - Port: port, - AccountType: nt.Custom, - Username: record[4], - Password: record[5], - PrivateKey: record[6], - Passphrase: record[7], - Description: record[8], - Created: common.NowJsonTime(), - Owner: account.ID, - Active: true, + asset := maps.Map{ + "id": utils.UUID(), + "name": record[0], + "protocol": record[1], + "ip": record[2], + "port": port, + "accountType": nt.Custom, + "username": record[4], + "password": record[5], + "privateKey": record[6], + "passphrase": record[7], + "Description": record[8], + "owner": account.ID, + } + + if record[6] != "" { + asset["accountType"] = nt.PrivateKey } if len(record) >= 10 { tags := strings.ReplaceAll(record[9], "|", ",") - asset.Tags = tags + asset["tags"] = tags } - err := repository.AssetRepository.Create(context.TODO(), &asset) + _, err := service.AssetService.Create(context.Background(), asset) if err != nil { errorCount++ m[strconv.Itoa(i)] = err.Error() @@ -151,7 +152,7 @@ func (assetApi AssetApi) AssetAllEndpoint(c echo.Context) error { func (assetApi AssetApi) AssetUpdateEndpoint(c echo.Context) error { id := c.Param("id") - m := echo.Map{} + m := maps.Map{} if err := c.Bind(&m); err != nil { return err } diff --git a/server/api/term.go b/server/api/term.go index ae580c4..1ef6c91 100644 --- a/server/api/term.go +++ b/server/api/term.go @@ -50,7 +50,7 @@ func (api WebTerminalApi) SshEndpoint(c echo.Context) error { s, err := service.SessionService.FindByIdAndDecrypt(ctx, sessionId) if err != nil { - return WriteMessage(ws, dto.NewMessage(Closed, "获取会话失败")) + return WriteMessage(ws, dto.NewMessage(Closed, "获取会话或解密数据失败")) } if err := api.permissionCheck(c, s.AssetId); err != nil { diff --git a/server/branding/branding.go b/server/branding/branding.go index 388f9eb..96d5abc 100644 --- a/server/branding/branding.go +++ b/server/branding/branding.go @@ -9,5 +9,5 @@ var Banner = ` ___ ___ \/|::/ / /:/\/__/ |:/ / \/__/ \/__/ ` -var Version = `v1.3.0-beta2` +var Version = `v1.3.0-beta4` var Hi = Banner + Version diff --git a/server/repository/asset.go b/server/repository/asset.go index 0993476..79f2929 100644 --- a/server/repository/asset.go +++ b/server/repository/asset.go @@ -3,15 +3,14 @@ package repository import ( "context" "fmt" - "next-terminal/server/common/nt" "strconv" "strings" + "next-terminal/server/common/maps" + "next-terminal/server/common/nt" "next-terminal/server/config" "next-terminal/server/model" "next-terminal/server/utils" - - "github.com/labstack/echo/v4" ) var AssetRepository = new(assetRepository) @@ -172,7 +171,7 @@ func (r assetRepository) FindTags(c context.Context) (o []string, err error) { return utils.Distinct(o), nil } -func (r assetRepository) UpdateAttributes(c context.Context, assetId, protocol string, m echo.Map) error { +func (r assetRepository) UpdateAttributes(c context.Context, assetId, protocol string, m maps.Map) error { var data []model.AssetAttribute var parameterNames []string switch protocol { @@ -202,7 +201,7 @@ func (r assetRepository) UpdateAttributes(c context.Context, assetId, protocol s return r.GetDB(c).CreateInBatches(&data, len(data)).Error } -func genAttribute(assetId, name string, m echo.Map) model.AssetAttribute { +func genAttribute(assetId, name string, m maps.Map) model.AssetAttribute { value := fmt.Sprintf("%v", m[name]) attribute := model.AssetAttribute{ Id: utils.Sign([]string{assetId, name}), diff --git a/server/service/asset.go b/server/service/asset.go index 499717b..df49195 100644 --- a/server/service/asset.go +++ b/server/service/asset.go @@ -7,6 +7,7 @@ import ( "fmt" "golang.org/x/net/proxy" "net" + "next-terminal/server/common/maps" "next-terminal/server/common/nt" "strconv" "time" @@ -18,7 +19,6 @@ import ( "next-terminal/server/repository" "next-terminal/server/utils" - "github.com/labstack/echo/v4" "gorm.io/gorm" ) @@ -173,22 +173,22 @@ func (s assetService) CheckStatus(asset *model.Asset, ip string, port int) (bool } } -func (s assetService) Create(ctx context.Context, m echo.Map) (model.Asset, error) { +func (s assetService) Create(ctx context.Context, m maps.Map) (*model.Asset, error) { data, err := json.Marshal(m) if err != nil { - return model.Asset{}, err + return nil, err } var item model.Asset if err := json.Unmarshal(data, &item); err != nil { - return model.Asset{}, err + return nil, err } item.ID = utils.UUID() item.Created = common.NowJsonTime() item.Active = true - return item, s.Transaction(ctx, func(ctx context.Context) error { + return &item, s.Transaction(ctx, func(ctx context.Context) error { if err := s.Encrypt(&item, config.GlobalCfg.EncryptionPassword); err != nil { return err } @@ -222,7 +222,7 @@ func (s assetService) DeleteById(id string) error { }) } -func (s assetService) UpdateById(id string, m echo.Map) error { +func (s assetService) UpdateById(id string, m maps.Map) error { data, err := json.Marshal(m) if err != nil { return err diff --git a/server/service/backup.go b/server/service/backup.go index 94a4ac1..43b1c9a 100644 --- a/server/service/backup.go +++ b/server/service/backup.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "next-terminal/server/common/maps" "strings" "next-terminal/server/common" @@ -15,7 +16,6 @@ import ( "next-terminal/server/repository" "next-terminal/server/utils" - "github.com/labstack/echo/v4" "gorm.io/gorm" ) @@ -265,7 +265,7 @@ func (service backupService) Import(backup *dto.Backup) error { if err != nil { return err } - m := echo.Map{} + m := maps.Map{} if err := json.Unmarshal(data, &m); err != nil { return err } diff --git a/server/utils/license.go b/server/utils/license.go deleted file mode 100644 index 7eac72f..0000000 --- a/server/utils/license.go +++ /dev/null @@ -1,54 +0,0 @@ -package utils - -import ( - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/sha512" - "crypto/x509" - "encoding/pem" - - "github.com/denisbrodbeck/machineid" -) - -// SignatureRSA rsa私钥签名 -func SignatureRSA(plainText []byte, rsaPrivateKey string) (signed []byte, err error) { - // 使用pem对读取的内容解码得到block - block, _ := pem.Decode([]byte(rsaPrivateKey)) - //x509将数据解析得到私钥结构体 - privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) - if err != nil { - return nil, err - } - // 创建一个hash对象 - h := sha512.New() - _, _ = h.Write(plainText) - // 计算hash值 - hashText := h.Sum(nil) - // 使用rsa函数对散列值签名 - signed, err = rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA512, hashText) - if err != nil { - return - } - return signed, nil -} - -// VerifyRSA rsa签名认证 -func VerifyRSA(plainText, signText []byte, rsaPublicKey string) bool { - // pem解码得到block - block, _ := pem.Decode([]byte(rsaPublicKey)) - // x509解析得到接口 - publicKey, err := x509.ParsePKCS1PublicKey(block.Bytes) - if err != nil { - return false - } - // 对原始明文进行hash运算得到散列值 - hashText := sha512.Sum512(plainText) - // 签名认证 - err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA512, hashText[:], signText) - return err == nil -} - -func GetMachineId() (string, error) { - return machineid.ID() -} diff --git a/web/package.json b/web/package.json index 4b8796d..96448b9 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "next-terminal", - "version": "1.3.0-beta3", + "version": "1.3.0-beta4", "private": true, "dependencies": { "@ant-design/charts": "^1.4.2", diff --git a/web/src/components/access/Guacd.css b/web/src/components/access/Guacd.css new file mode 100644 index 0000000..a1758a9 --- /dev/null +++ b/web/src/components/access/Guacd.css @@ -0,0 +1,3 @@ +#display > div { + margin: 0 auto; +} \ No newline at end of file diff --git a/web/src/components/access/Guacd.js b/web/src/components/access/Guacd.js index 079bac2..42242e6 100644 --- a/web/src/components/access/Guacd.js +++ b/web/src/components/access/Guacd.js @@ -19,6 +19,7 @@ import Draggable from "react-draggable"; import FileSystem from "../devops/FileSystem"; import GuacdClipboard from "./GuacdClipboard"; import {debounce} from "../../utils/fun"; +import './Guacd.css'; let fixedSize = false; @@ -74,17 +75,15 @@ const Guacd = () => { tunnel.onerror = onError; // Get display div from document - const display = document.getElementById("display"); + const displayEle = document.getElementById("display"); // Add client to display div const element = client.getDisplay().getElement(); - display.appendChild(element); + displayEle.appendChild(element); - let scale = 1; let dpi = 96; if (protocol === 'telnet') { dpi = dpi * 2; - scale = 0.5; } let token = getToken(); @@ -99,21 +98,31 @@ const Guacd = () => { let paramStr = qs.stringify(params); client.connect(paramStr); + let display = client.getDisplay(); + display.onresize = function (width, height) { + display.scale(Math.min( + window.innerHeight / display.getHeight(), + window.innerWidth / display.getHeight() + )) + } const mouse = new Guacamole.Mouse(element); - mouse.onmousedown = mouse.onmouseup = function (mouseState) { + mouse.onmousedown = mouse.onmouseup = mouse.onmousemove = function (mouseState) { + client.getDisplay().showCursor(false); + mouseState.x = mouseState.x / display.getScale(); + mouseState.y = mouseState.y / display.getScale(); client.sendMouseState(mouseState); }; - mouse.onmousemove = function (mouseState) { - mouseState.x = mouseState.x / scale; - mouseState.y = mouseState.y / scale; - client.sendMouseState(mouseState); + const touch = new Guacamole.Mouse.Touchpad(element); // or Guacamole.Touchscreen + + touch.onmousedown = touch.onmousemove = touch.onmouseup = function (state) { + client.sendMouseState(state); }; const sink = new Guacamole.InputSink(); - display.appendChild(sink.getElement()); + displayEle.appendChild(sink.getElement()); sink.focus(); const keyboard = new Guacamole.Keyboard(sink.getElement()); @@ -130,7 +139,6 @@ const Guacd = () => { setGuacd({ client, - scale, sink, }); } @@ -162,17 +170,12 @@ const Guacd = () => { }, [guacd]) const onWindowResize = () => { - console.log(guacd, fixedSize); if (guacd.client && !fixedSize) { const display = guacd.client.getDisplay(); - let scale = guacd.scale; - display.scale(scale); - let width = window.innerWidth; - let height = window.innerHeight; - - guacd.client.sendSize(width / scale, height / scale); - - setBox({width, height}) + display.scale(Math.min( + window.innerHeight / display.getHeight(), + window.innerWidth / display.getHeight() + )); } } @@ -438,7 +441,6 @@ const Guacd = () => {