diff --git a/README.md b/README.md index 053d14b..8f13039 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,53 @@ -# next-terminal -just do go +# Next Terminal +你的下一个终端。 -## 主要功能 +## 快速了解 + +Next Terminal是使用Golang和React开发的一款HTML5的远程桌面网关,具有小巧、易安装、易使用、资源占用小的特点,支持RDP、SSH、VNC和Telnet协议的连接和管理。 + +Next Terminal基于Apache Guacamole开发,使用到了guacd服务。 + +## 快速安装 + +### docker安装 + +因为程序依赖了mysql,所以在启动时需要指定mysql的连接信息。 + +```shell +docker run -p 8088:8088 --env MYSQL_HOSTNAME=d-mysql-57 --env MYSQL_USERNAME=root --env MYSQL_PASSWORD=root --name next-terminal --link d-mysql-57 dushixiang/next-terminal:0.0.1 +``` + +程序安装目录地址为 `/usr/local/nt` + +录屏文件存放目录为 `/usr/local/nt/recording` + +远程桌面挂载目录为 `/usr/local/nt/drive` + +可以通过 `-v` 参数将宿主机器的目录映射到docker中 + + +## 相关截图 + +资源占用截图 + +![资源占用截图](./screenshot/docker_stats.png) + +资产管理 + +![资产](./screenshot/assets.png) + +rdp + +![rdp](./screenshot/rdp.png) + +vnc + +![vnc](./screenshot/vnc.png) + +ssh + +![ssh](./screenshot/ssh.png) + +批量执行命令 + +![批量执行命令](./screenshot/command.png) \ No newline at end of file diff --git a/pkg/api/session.go b/pkg/api/session.go index ce8c0c5..0580c5e 100644 --- a/pkg/api/session.go +++ b/pkg/api/session.go @@ -33,6 +33,22 @@ func SessionPagingEndpoint(c echo.Context) error { return err } + for i := 0; i < len(items); i++ { + if len(items[i].Recording) > 0 { + recording := items[i].Recording + "/recording" + + if utils.FileExists(recording) { + log.Infof("检测到录屏文件[%v]存在", recording) + items[i].Recording = "1" + } else { + log.Warnf("检测到录屏文件[%v]不存在", recording) + items[i].Recording = "0" + } + } else { + items[i].Recording = "0" + } + } + return Success(c, H{ "total": total, "items": items, @@ -436,11 +452,11 @@ func SessionRmEndpoint(c echo.Context) error { func SessionRecordingEndpoint(c echo.Context) error { sessionId := c.Param("id") - recordingPath, err := model.GetRecordingPath() + session, err := model.FindSessionById(sessionId) if err != nil { return err } - recording := path.Join(recordingPath, sessionId, "recording") + recording := path.Join(session.Recording, "recording") log.Printf("读取录屏文件:%s", recording) return c.File(recording) } diff --git a/pkg/api/tunnel.go b/pkg/api/tunnel.go index ea79e4b..e1975a6 100644 --- a/pkg/api/tunnel.go +++ b/pkg/api/tunnel.go @@ -49,18 +49,9 @@ func TunEndpoint(c echo.Context) error { return err } - for name := range propertyMap { - if name == guacd.FontSize { - fontSize, _ := strconv.Atoi(propertyMap[name]) - fontSize = fontSize * 2 - configuration.SetParameter(name, strconv.Itoa(fontSize)) - } else { - configuration.SetParameter(name, propertyMap[name]) - } - } - if propertyMap[guacd.EnableRecording] == "true" { configuration.SetParameter(guacd.RecordingPath, path.Join(propertyMap[guacd.RecordingPath], sessionId)) + configuration.SetParameter(guacd.CreateRecordingPath, propertyMap[guacd.CreateRecordingPath]) } else { configuration.SetParameter(guacd.RecordingPath, "") } @@ -77,17 +68,34 @@ func TunEndpoint(c echo.Context) error { configuration.SetParameter("dpi", "96") configuration.SetParameter("resize-method", "reconnect") - configuration.SetParameter("enable-sftp", "") + configuration.SetParameter(guacd.EnableDrive, propertyMap[guacd.EnableDrive]) + configuration.SetParameter(guacd.DriveName, propertyMap[guacd.DriveName]) + configuration.SetParameter(guacd.DrivePath, propertyMap[guacd.DrivePath]) + configuration.SetParameter(guacd.EnableWallpaper, propertyMap[guacd.EnableWallpaper]) + configuration.SetParameter(guacd.EnableTheming, propertyMap[guacd.EnableTheming]) + configuration.SetParameter(guacd.EnableFontSmoothing, propertyMap[guacd.EnableFontSmoothing]) + configuration.SetParameter(guacd.EnableFullWindowDrag, propertyMap[guacd.EnableFullWindowDrag]) + configuration.SetParameter(guacd.EnableDesktopComposition, propertyMap[guacd.EnableDesktopComposition]) + configuration.SetParameter(guacd.EnableMenuAnimations, propertyMap[guacd.EnableMenuAnimations]) + configuration.SetParameter(guacd.DisableBitmapCaching, propertyMap[guacd.DisableBitmapCaching]) + configuration.SetParameter(guacd.DisableOffscreenCaching, propertyMap[guacd.DisableOffscreenCaching]) + configuration.SetParameter(guacd.DisableGlyphCaching, propertyMap[guacd.DisableGlyphCaching]) break case "ssh": - if session.PrivateKey == "-" { - configuration.SetParameter("username", session.Username) - configuration.SetParameter("password", session.Password) - } else { + if len(session.PrivateKey) > 0 && session.PrivateKey != "-" { configuration.SetParameter("private-key", session.PrivateKey) configuration.SetParameter("passphrase", session.Passphrase) + } else { + configuration.SetParameter("username", session.Username) + configuration.SetParameter("password", session.Password) } + fontSize, _ := strconv.Atoi(propertyMap[guacd.FontSize]) + fontSize = fontSize * 2 + configuration.SetParameter(guacd.FontSize, strconv.Itoa(fontSize)) + configuration.SetParameter(guacd.FontName, propertyMap[guacd.FontName]) + configuration.SetParameter(guacd.ColorScheme, propertyMap[guacd.ColorScheme]) + sftpClient, err = CreateSftpClient(session.AssetId) if err != nil { return err diff --git a/pkg/api/user.go b/pkg/api/user.go index 23c47d6..40cec03 100644 --- a/pkg/api/user.go +++ b/pkg/api/user.go @@ -62,10 +62,18 @@ func UserUpdateEndpoint(c echo.Context) error { } func UserDeleteEndpoint(c echo.Context) error { - id := c.Param("id") - split := strings.Split(id, ",") + ids := c.Param("id") + account, found := GetCurrentAccount(c) + if !found { + return Fail(c, -1, "获取当前登录账户失败") + } + split := strings.Split(ids, ",") for i := range split { - model.DeleteUserById(split[i]) + userId := split[i] + if account.ID == userId { + return Fail(c, -1, "不允许删除自身账户") + } + model.DeleteUserById(userId) } return Success(c, nil) diff --git a/pkg/guacd/guacd.go b/pkg/guacd/guacd.go index 52a49a3..1f014f9 100644 --- a/pkg/guacd/guacd.go +++ b/pkg/guacd/guacd.go @@ -34,7 +34,7 @@ const ( ) const Delimiter = ';' -const Version = "VERSION_1_1_0" +const Version = "VERSION_1_2_0" type Configuration struct { ConnectionID string diff --git a/pkg/handle/runner.go b/pkg/handle/runner.go index 6a9d4ff..1908cb3 100644 --- a/pkg/handle/runner.go +++ b/pkg/handle/runner.go @@ -87,7 +87,7 @@ func InitProperties() error { Name: guacd.RecordingPath, Value: path + "/recording/", } - if !utils.Exists(property.Value) { + if !utils.FileExists(property.Value) { if err := os.Mkdir(property.Value, os.ModePerm); err != nil { return err } @@ -125,7 +125,7 @@ func InitProperties() error { Name: guacd.DrivePath, Value: path + "/drive/", } - if !utils.Exists(property.Value) { + if !utils.FileExists(property.Value) { if err := os.Mkdir(property.Value, os.ModePerm); err != nil { return err } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index f3e5d70..788363d 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -82,7 +82,7 @@ func Tcping(ip string, port int) bool { } // 判断所给路径文件/文件夹是否存在 -func Exists(path string) bool { +func FileExists(path string) bool { _, err := os.Stat(path) //os.Stat获取文件信息 if err != nil { if os.IsExist(err) { diff --git a/screenshot/command.png b/screenshot/command.png new file mode 100644 index 0000000..b082707 Binary files /dev/null and b/screenshot/command.png differ diff --git a/screenshot/docker_stats.png b/screenshot/docker_stats.png new file mode 100644 index 0000000..57d9103 Binary files /dev/null and b/screenshot/docker_stats.png differ diff --git a/screenshot/rdp.png b/screenshot/rdp.png new file mode 100644 index 0000000..90b55ef Binary files /dev/null and b/screenshot/rdp.png differ diff --git a/screenshot/ssh.png b/screenshot/ssh.png new file mode 100644 index 0000000..cac04f5 Binary files /dev/null and b/screenshot/ssh.png differ diff --git a/screenshot/vnc.png b/screenshot/vnc.png new file mode 100644 index 0000000..f27065c Binary files /dev/null and b/screenshot/vnc.png differ diff --git a/web/package.json b/web/package.json index 219ee45..7c3e073 100644 --- a/web/package.json +++ b/web/package.json @@ -1,6 +1,6 @@ { "name": "next-terminal", - "version": "0.1.0", + "version": "0.0.1", "private": true, "dependencies": { "@ant-design/icons": "^4.3.0", diff --git a/web/src/components/session/OfflineSession.js b/web/src/components/session/OfflineSession.js index df64e15..3933ef9 100644 --- a/web/src/components/session/OfflineSession.js +++ b/web/src/components/session/OfflineSession.js @@ -288,7 +288,7 @@ class OfflineSession extends Component { render: (text, record) => { let disabled = true; let color = '#d9d9d9' - if (record['recording'] && record['recording'].length > 0) { + if (record['recording'] && record['recording'] === '1') { disabled = false color = '' } @@ -297,7 +297,8 @@ class OfflineSession extends Component {
+ icon={} + onClick={() => this.showPlayback(record.id)}>回放