diff --git a/server/.env.example b/.env.example
similarity index 79%
rename from server/.env.example
rename to .env.example
index e61fe68..597ba24 100644
--- a/server/.env.example
+++ b/.env.example
@@ -1,5 +1,5 @@
DATABASE_URL=
-# Generate a 32-byte (256-bit) key for AES-256 encryption using `openssl rand -base64 32`
+# Generate a 32-byte (256-bit) key for AES-256 encryption using `openssl rand -hex 32`
ENCRYPTION_KEY=""
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..74a8090
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+build/bin
+node_modules
+tmp/
+.env
+/data.db*
+Vaulterm-res.syso
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..76054d9
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "go.buildTags": "gui"
+}
\ No newline at end of file
diff --git a/app.go b/app.go
new file mode 100644
index 0000000..aef2daa
--- /dev/null
+++ b/app.go
@@ -0,0 +1,34 @@
+//go:build gui
+// +build gui
+
+package main
+
+import (
+ "context"
+ "fmt"
+)
+
+// App struct
+type App struct {
+ ctx context.Context
+ localPort int
+}
+
+// NewApp creates a new App application struct
+func NewApp() *App {
+ return &App{}
+}
+
+// startup is called when the app starts. The context is saved
+// so we can call the runtime methods
+func (a *App) startup(ctx context.Context) {
+ a.ctx = ctx
+}
+
+// Returns local server address
+func (a *App) GetLocalServer() string {
+ if a.localPort == 0 {
+ return ""
+ }
+ return fmt.Sprintf("http://localhost:%d", a.localPort)
+}
diff --git a/build/README.md b/build/README.md
new file mode 100644
index 0000000..1ae2f67
--- /dev/null
+++ b/build/README.md
@@ -0,0 +1,35 @@
+# Build Directory
+
+The build directory is used to house all the build files and assets for your application.
+
+The structure is:
+
+* bin - Output directory
+* darwin - macOS specific files
+* windows - Windows specific files
+
+## Mac
+
+The `darwin` directory holds files specific to Mac builds.
+These may be customised and used as part of the build. To return these files to the default state, simply delete them
+and
+build with `wails build`.
+
+The directory contains the following files:
+
+- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`.
+- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`.
+
+## Windows
+
+The `windows` directory contains the manifest and rc files used when building with `wails build`.
+These may be customised for your application. To return these files to the default state, simply delete them and
+build with `wails build`.
+
+- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to
+ use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file
+ will be created using the `appicon.png` file in the build directory.
+- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`.
+- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer,
+ as well as the application itself (right click the exe -> properties -> details)
+- `wails.exe.manifest` - The main application manifest file.
\ No newline at end of file
diff --git a/build/appicon.png b/build/appicon.png
new file mode 100644
index 0000000..63617fe
Binary files /dev/null and b/build/appicon.png differ
diff --git a/build/darwin/Info.dev.plist b/build/darwin/Info.dev.plist
new file mode 100644
index 0000000..04727c2
--- /dev/null
+++ b/build/darwin/Info.dev.plist
@@ -0,0 +1,68 @@
+
+
+
+ CFBundlePackageType
+ APPL
+ CFBundleName
+ {{.Info.ProductName}}
+ CFBundleExecutable
+ {{.Name}}
+ CFBundleIdentifier
+ com.wails.{{.Name}}
+ CFBundleVersion
+ {{.Info.ProductVersion}}
+ CFBundleGetInfoString
+ {{.Info.Comments}}
+ CFBundleShortVersionString
+ {{.Info.ProductVersion}}
+ CFBundleIconFile
+ iconfile
+ LSMinimumSystemVersion
+ 10.13.0
+ NSHighResolutionCapable
+ true
+ NSHumanReadableCopyright
+ {{.Info.Copyright}}
+ {{if .Info.FileAssociations}}
+ CFBundleDocumentTypes
+
+ {{range .Info.FileAssociations}}
+
+ CFBundleTypeExtensions
+
+ {{.Ext}}
+
+ CFBundleTypeName
+ {{.Name}}
+ CFBundleTypeRole
+ {{.Role}}
+ CFBundleTypeIconFile
+ {{.IconName}}
+
+ {{end}}
+
+ {{end}}
+ {{if .Info.Protocols}}
+ CFBundleURLTypes
+
+ {{range .Info.Protocols}}
+
+ CFBundleURLName
+ com.wails.{{.Scheme}}
+ CFBundleURLSchemes
+
+ {{.Scheme}}
+
+ CFBundleTypeRole
+ {{.Role}}
+
+ {{end}}
+
+ {{end}}
+ NSAppTransportSecurity
+
+ NSAllowsLocalNetworking
+
+
+
+
diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist
new file mode 100644
index 0000000..19cc937
--- /dev/null
+++ b/build/darwin/Info.plist
@@ -0,0 +1,63 @@
+
+
+
+ CFBundlePackageType
+ APPL
+ CFBundleName
+ {{.Info.ProductName}}
+ CFBundleExecutable
+ {{.Name}}
+ CFBundleIdentifier
+ com.wails.{{.Name}}
+ CFBundleVersion
+ {{.Info.ProductVersion}}
+ CFBundleGetInfoString
+ {{.Info.Comments}}
+ CFBundleShortVersionString
+ {{.Info.ProductVersion}}
+ CFBundleIconFile
+ iconfile
+ LSMinimumSystemVersion
+ 10.13.0
+ NSHighResolutionCapable
+ true
+ NSHumanReadableCopyright
+ {{.Info.Copyright}}
+ {{if .Info.FileAssociations}}
+ CFBundleDocumentTypes
+
+ {{range .Info.FileAssociations}}
+
+ CFBundleTypeExtensions
+
+ {{.Ext}}
+
+ CFBundleTypeName
+ {{.Name}}
+ CFBundleTypeRole
+ {{.Role}}
+ CFBundleTypeIconFile
+ {{.IconName}}
+
+ {{end}}
+
+ {{end}}
+ {{if .Info.Protocols}}
+ CFBundleURLTypes
+
+ {{range .Info.Protocols}}
+
+ CFBundleURLName
+ com.wails.{{.Scheme}}
+ CFBundleURLSchemes
+
+ {{.Scheme}}
+
+ CFBundleTypeRole
+ {{.Role}}
+
+ {{end}}
+
+ {{end}}
+
+
diff --git a/build/windows/icon.ico b/build/windows/icon.ico
new file mode 100644
index 0000000..f334798
Binary files /dev/null and b/build/windows/icon.ico differ
diff --git a/build/windows/info.json b/build/windows/info.json
new file mode 100644
index 0000000..9727946
--- /dev/null
+++ b/build/windows/info.json
@@ -0,0 +1,15 @@
+{
+ "fixed": {
+ "file_version": "{{.Info.ProductVersion}}"
+ },
+ "info": {
+ "0000": {
+ "ProductVersion": "{{.Info.ProductVersion}}",
+ "CompanyName": "{{.Info.CompanyName}}",
+ "FileDescription": "{{.Info.ProductName}}",
+ "LegalCopyright": "{{.Info.Copyright}}",
+ "ProductName": "{{.Info.ProductName}}",
+ "Comments": "{{.Info.Comments}}"
+ }
+ }
+}
\ No newline at end of file
diff --git a/build/windows/installer/project.nsi b/build/windows/installer/project.nsi
new file mode 100644
index 0000000..654ae2e
--- /dev/null
+++ b/build/windows/installer/project.nsi
@@ -0,0 +1,114 @@
+Unicode true
+
+####
+## Please note: Template replacements don't work in this file. They are provided with default defines like
+## mentioned underneath.
+## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo.
+## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually
+## from outside of Wails for debugging and development of the installer.
+##
+## For development first make a wails nsis build to populate the "wails_tools.nsh":
+## > wails build --target windows/amd64 --nsis
+## Then you can call makensis on this file with specifying the path to your binary:
+## For a AMD64 only installer:
+## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe
+## For a ARM64 only installer:
+## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe
+## For a installer with both architectures:
+## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe
+####
+## The following information is taken from the ProjectInfo file, but they can be overwritten here.
+####
+## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}"
+## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}"
+## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}"
+## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}"
+## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}"
+###
+## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe"
+## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
+####
+## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html
+####
+## Include the wails tools
+####
+!include "wails_tools.nsh"
+
+# The version information for this two must consist of 4 parts
+VIProductVersion "${INFO_PRODUCTVERSION}.0"
+VIFileVersion "${INFO_PRODUCTVERSION}.0"
+
+VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}"
+VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer"
+VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}"
+VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}"
+VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}"
+VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}"
+
+# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware
+ManifestDPIAware true
+
+!include "MUI.nsh"
+
+!define MUI_ICON "..\icon.ico"
+!define MUI_UNICON "..\icon.ico"
+# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314
+!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps
+!define MUI_ABORTWARNING # This will warn the user if they exit from the installer.
+
+!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page.
+# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer
+!insertmacro MUI_PAGE_DIRECTORY # In which folder install page.
+!insertmacro MUI_PAGE_INSTFILES # Installing page.
+!insertmacro MUI_PAGE_FINISH # Finished installation page.
+
+!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page
+
+!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer
+
+## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1
+#!uninstfinalize 'signtool --file "%1"'
+#!finalize 'signtool --file "%1"'
+
+Name "${INFO_PRODUCTNAME}"
+OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
+InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
+ShowInstDetails show # This will always show the installation details.
+
+Function .onInit
+ !insertmacro wails.checkArchitecture
+FunctionEnd
+
+Section
+ !insertmacro wails.setShellContext
+
+ !insertmacro wails.webview2runtime
+
+ SetOutPath $INSTDIR
+
+ !insertmacro wails.files
+
+ CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
+ CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
+
+ !insertmacro wails.associateFiles
+ !insertmacro wails.associateCustomProtocols
+
+ !insertmacro wails.writeUninstaller
+SectionEnd
+
+Section "uninstall"
+ !insertmacro wails.setShellContext
+
+ RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath
+
+ RMDir /r $INSTDIR
+
+ Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk"
+ Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
+
+ !insertmacro wails.unassociateFiles
+ !insertmacro wails.unassociateCustomProtocols
+
+ !insertmacro wails.deleteUninstaller
+SectionEnd
diff --git a/build/windows/installer/wails_tools.nsh b/build/windows/installer/wails_tools.nsh
new file mode 100644
index 0000000..f9c0f88
--- /dev/null
+++ b/build/windows/installer/wails_tools.nsh
@@ -0,0 +1,249 @@
+# DO NOT EDIT - Generated automatically by `wails build`
+
+!include "x64.nsh"
+!include "WinVer.nsh"
+!include "FileFunc.nsh"
+
+!ifndef INFO_PROJECTNAME
+ !define INFO_PROJECTNAME "{{.Name}}"
+!endif
+!ifndef INFO_COMPANYNAME
+ !define INFO_COMPANYNAME "{{.Info.CompanyName}}"
+!endif
+!ifndef INFO_PRODUCTNAME
+ !define INFO_PRODUCTNAME "{{.Info.ProductName}}"
+!endif
+!ifndef INFO_PRODUCTVERSION
+ !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}"
+!endif
+!ifndef INFO_COPYRIGHT
+ !define INFO_COPYRIGHT "{{.Info.Copyright}}"
+!endif
+!ifndef PRODUCT_EXECUTABLE
+ !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
+!endif
+!ifndef UNINST_KEY_NAME
+ !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
+!endif
+!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
+
+!ifndef REQUEST_EXECUTION_LEVEL
+ !define REQUEST_EXECUTION_LEVEL "admin"
+!endif
+
+RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
+
+!ifdef ARG_WAILS_AMD64_BINARY
+ !define SUPPORTS_AMD64
+!endif
+
+!ifdef ARG_WAILS_ARM64_BINARY
+ !define SUPPORTS_ARM64
+!endif
+
+!ifdef SUPPORTS_AMD64
+ !ifdef SUPPORTS_ARM64
+ !define ARCH "amd64_arm64"
+ !else
+ !define ARCH "amd64"
+ !endif
+!else
+ !ifdef SUPPORTS_ARM64
+ !define ARCH "arm64"
+ !else
+ !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY"
+ !endif
+!endif
+
+!macro wails.checkArchitecture
+ !ifndef WAILS_WIN10_REQUIRED
+ !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later."
+ !endif
+
+ !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED
+ !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}"
+ !endif
+
+ ${If} ${AtLeastWin10}
+ !ifdef SUPPORTS_AMD64
+ ${if} ${IsNativeAMD64}
+ Goto ok
+ ${EndIf}
+ !endif
+
+ !ifdef SUPPORTS_ARM64
+ ${if} ${IsNativeARM64}
+ Goto ok
+ ${EndIf}
+ !endif
+
+ IfSilent silentArch notSilentArch
+ silentArch:
+ SetErrorLevel 65
+ Abort
+ notSilentArch:
+ MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}"
+ Quit
+ ${else}
+ IfSilent silentWin notSilentWin
+ silentWin:
+ SetErrorLevel 64
+ Abort
+ notSilentWin:
+ MessageBox MB_OK "${WAILS_WIN10_REQUIRED}"
+ Quit
+ ${EndIf}
+
+ ok:
+!macroend
+
+!macro wails.files
+ !ifdef SUPPORTS_AMD64
+ ${if} ${IsNativeAMD64}
+ File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}"
+ ${EndIf}
+ !endif
+
+ !ifdef SUPPORTS_ARM64
+ ${if} ${IsNativeARM64}
+ File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}"
+ ${EndIf}
+ !endif
+!macroend
+
+!macro wails.writeUninstaller
+ WriteUninstaller "$INSTDIR\uninstall.exe"
+
+ SetRegView 64
+ WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
+ WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
+ WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
+ WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
+ WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
+ WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
+
+ ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
+ IntFmt $0 "0x%08X" $0
+ WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
+!macroend
+
+!macro wails.deleteUninstaller
+ Delete "$INSTDIR\uninstall.exe"
+
+ SetRegView 64
+ DeleteRegKey HKLM "${UNINST_KEY}"
+!macroend
+
+!macro wails.setShellContext
+ ${If} ${REQUEST_EXECUTION_LEVEL} == "admin"
+ SetShellVarContext all
+ ${else}
+ SetShellVarContext current
+ ${EndIf}
+!macroend
+
+# Install webview2 by launching the bootstrapper
+# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
+!macro wails.webview2runtime
+ !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT
+ !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime"
+ !endif
+
+ SetRegView 64
+ # If the admin key exists and is not empty then webview2 is already installed
+ ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
+ ${If} $0 != ""
+ Goto ok
+ ${EndIf}
+
+ ${If} ${REQUEST_EXECUTION_LEVEL} == "user"
+ # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed
+ ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
+ ${If} $0 != ""
+ Goto ok
+ ${EndIf}
+ ${EndIf}
+
+ SetDetailsPrint both
+ DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}"
+ SetDetailsPrint listonly
+
+ InitPluginsDir
+ CreateDirectory "$pluginsdir\webview2bootstrapper"
+ SetOutPath "$pluginsdir\webview2bootstrapper"
+ File "tmp\MicrosoftEdgeWebview2Setup.exe"
+ ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install'
+
+ SetDetailsPrint both
+ ok:
+!macroend
+
+# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b
+!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
+ ; Backup the previously associated file class
+ ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"
+
+ WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"
+
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}`
+!macroend
+
+!macro APP_UNASSOCIATE EXT FILECLASS
+ ; Backup the previously associated file class
+ ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0"
+
+ DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}`
+!macroend
+
+!macro wails.associateFiles
+ ; Create file associations
+ {{range .Info.FileAssociations}}
+ !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
+
+ File "..\{{.IconName}}.ico"
+ {{end}}
+!macroend
+
+!macro wails.unassociateFiles
+ ; Delete app associations
+ {{range .Info.FileAssociations}}
+ !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}"
+
+ Delete "$INSTDIR\{{.IconName}}.ico"
+ {{end}}
+!macroend
+
+!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND
+ DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
+!macroend
+
+!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL
+ DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
+!macroend
+
+!macro wails.associateCustomProtocols
+ ; Create custom protocols associations
+ {{range .Info.Protocols}}
+ !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
+
+ {{end}}
+!macroend
+
+!macro wails.unassociateCustomProtocols
+ ; Delete app custom protocol associations
+ {{range .Info.Protocols}}
+ !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
+ {{end}}
+!macroend
diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest
new file mode 100644
index 0000000..17e1a23
--- /dev/null
+++ b/build/windows/wails.exe.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+ true/pm
+ permonitorv2,permonitor
+
+
+
\ No newline at end of file
diff --git a/frontend/app.config.ts b/frontend/app.config.ts
index ccece38..ba89900 100644
--- a/frontend/app.config.ts
+++ b/frontend/app.config.ts
@@ -27,7 +27,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
},
web: {
bundler: "metro",
- output: "static",
+ output: "single",
favicon: "./assets/images/favicon.png",
},
plugins: ["expo-router"],
diff --git a/frontend/app/index.tsx b/frontend/app/index.tsx
index 0814aba..bf94b9c 100644
--- a/frontend/app/index.tsx
+++ b/frontend/app/index.tsx
@@ -1,12 +1,36 @@
-import React from "react";
+import React, { useEffect, useState } from "react";
import { Redirect } from "expo-router";
import { useTermSession } from "@/stores/terminal-sessions";
-import { useServer } from "@/stores/app";
+import { setLocalServer, useServer } from "@/stores/app";
+import { GetLocalServer } from "@/lib/wailsjs/go/main/App";
+import { Spinner, View } from "tamagui";
export default function index() {
const { sessions, curSession } = useTermSession();
+ const [isPending, setPending] = useState(true);
const curServer = useServer();
+ useEffect(() => {
+ // load local server
+ (async function () {
+ try {
+ const url = await GetLocalServer();
+ if (url) {
+ setLocalServer(url);
+ }
+ } catch (_) {}
+ setPending(false);
+ })();
+ }, []);
+
+ if (isPending) {
+ return (
+
+
+
+ );
+ }
+
if (!curServer) {
return ;
}
diff --git a/frontend/components/containers/user-menu-button.tsx b/frontend/components/containers/user-menu-button.tsx
index abc69db..05ca444 100644
--- a/frontend/components/containers/user-menu-button.tsx
+++ b/frontend/components/containers/user-menu-button.tsx
@@ -38,9 +38,9 @@ const UserMenuButton = () => {
-
- {user?.name}
-
+
+ {user?.name}
+
{team ? `${team.icon} ${team.name}` : "Personal"}
diff --git a/frontend/hooks/useWebsocket.ts b/frontend/hooks/useWebsocket.ts
index 877ee69..1f8beb4 100644
--- a/frontend/hooks/useWebsocket.ts
+++ b/frontend/hooks/useWebsocket.ts
@@ -1,6 +1,5 @@
import { useServer } from "@/stores/app";
-
-import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useEffect, useRef, useState } from "react";
type UseWebsocketOptions = {
onMessage?: (message: string) => void;
@@ -50,7 +49,8 @@ export const useWebSocket = (url: string, opt?: UseWebsocketOptions) => {
export const useWebsocketUrl = (initParams: any = {}) => {
const server = useServer();
- const baseUrl = server?.url.replace("http://", "ws://") || "";
+ const baseUrl =
+ server?.replace("http://", "ws://").replace("https://", "wss://") || "";
return (url: string, params: any = {}) => {
const query = new URLSearchParams({ ...initParams, ...params });
diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts
index ceabdc1..4cde527 100644
--- a/frontend/lib/api.ts
+++ b/frontend/lib/api.ts
@@ -10,7 +10,7 @@ const api = ofetch.create({
}
// set server url
- config.options.baseURL = server.url;
+ config.options.baseURL = server;
const { token, teamId } = authStore.getState();
diff --git a/frontend/lib/wailsjs/go/main/App.d.ts b/frontend/lib/wailsjs/go/main/App.d.ts
new file mode 100644
index 0000000..483dfe7
--- /dev/null
+++ b/frontend/lib/wailsjs/go/main/App.d.ts
@@ -0,0 +1,4 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export function GetLocalServer():Promise;
diff --git a/frontend/lib/wailsjs/go/main/App.js b/frontend/lib/wailsjs/go/main/App.js
new file mode 100644
index 0000000..7dadce6
--- /dev/null
+++ b/frontend/lib/wailsjs/go/main/App.js
@@ -0,0 +1,7 @@
+// @ts-check
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export function GetLocalServer() {
+ return window['go']['main']['App']['GetLocalServer']();
+}
diff --git a/frontend/lib/wailsjs/runtime/package.json b/frontend/lib/wailsjs/runtime/package.json
new file mode 100644
index 0000000..1e7c8a5
--- /dev/null
+++ b/frontend/lib/wailsjs/runtime/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@wailsapp/runtime",
+ "version": "2.0.0",
+ "description": "Wails Javascript runtime library",
+ "main": "runtime.js",
+ "types": "runtime.d.ts",
+ "scripts": {
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/wailsapp/wails.git"
+ },
+ "keywords": [
+ "Wails",
+ "Javascript",
+ "Go"
+ ],
+ "author": "Lea Anthony ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/wailsapp/wails/issues"
+ },
+ "homepage": "https://github.com/wailsapp/wails#readme"
+}
diff --git a/frontend/lib/wailsjs/runtime/runtime.d.ts b/frontend/lib/wailsjs/runtime/runtime.d.ts
new file mode 100644
index 0000000..94778df
--- /dev/null
+++ b/frontend/lib/wailsjs/runtime/runtime.d.ts
@@ -0,0 +1,249 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+export interface Position {
+ x: number;
+ y: number;
+}
+
+export interface Size {
+ w: number;
+ h: number;
+}
+
+export interface Screen {
+ isCurrent: boolean;
+ isPrimary: boolean;
+ width : number
+ height : number
+}
+
+// Environment information such as platform, buildtype, ...
+export interface EnvironmentInfo {
+ buildType: string;
+ platform: string;
+ arch: string;
+}
+
+// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
+// emits the given event. Optional data may be passed with the event.
+// This will trigger any event listeners.
+export function EventsEmit(eventName: string, ...data: any): void;
+
+// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
+export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
+
+// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
+// sets up a listener for the given event name, but will only trigger a given number times.
+export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
+
+// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
+// sets up a listener for the given event name, but will only trigger once.
+export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
+
+// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
+// unregisters the listener for the given event name.
+export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
+
+// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
+// unregisters all listeners.
+export function EventsOffAll(): void;
+
+// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
+// logs the given message as a raw message
+export function LogPrint(message: string): void;
+
+// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
+// logs the given message at the `trace` log level.
+export function LogTrace(message: string): void;
+
+// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
+// logs the given message at the `debug` log level.
+export function LogDebug(message: string): void;
+
+// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
+// logs the given message at the `error` log level.
+export function LogError(message: string): void;
+
+// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
+// logs the given message at the `fatal` log level.
+// The application will quit after calling this method.
+export function LogFatal(message: string): void;
+
+// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
+// logs the given message at the `info` log level.
+export function LogInfo(message: string): void;
+
+// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
+// logs the given message at the `warning` log level.
+export function LogWarning(message: string): void;
+
+// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
+// Forces a reload by the main application as well as connected browsers.
+export function WindowReload(): void;
+
+// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
+// Reloads the application frontend.
+export function WindowReloadApp(): void;
+
+// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
+// Sets the window AlwaysOnTop or not on top.
+export function WindowSetAlwaysOnTop(b: boolean): void;
+
+// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
+// *Windows only*
+// Sets window theme to system default (dark/light).
+export function WindowSetSystemDefaultTheme(): void;
+
+// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
+// *Windows only*
+// Sets window to light theme.
+export function WindowSetLightTheme(): void;
+
+// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
+// *Windows only*
+// Sets window to dark theme.
+export function WindowSetDarkTheme(): void;
+
+// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
+// Centers the window on the monitor the window is currently on.
+export function WindowCenter(): void;
+
+// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
+// Sets the text in the window title bar.
+export function WindowSetTitle(title: string): void;
+
+// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
+// Makes the window full screen.
+export function WindowFullscreen(): void;
+
+// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
+// Restores the previous window dimensions and position prior to full screen.
+export function WindowUnfullscreen(): void;
+
+// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
+// Returns the state of the window, i.e. whether the window is in full screen mode or not.
+export function WindowIsFullscreen(): Promise;
+
+// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
+// Sets the width and height of the window.
+export function WindowSetSize(width: number, height: number): Promise;
+
+// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
+// Gets the width and height of the window.
+export function WindowGetSize(): Promise;
+
+// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
+// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
+// Setting a size of 0,0 will disable this constraint.
+export function WindowSetMaxSize(width: number, height: number): void;
+
+// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
+// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
+// Setting a size of 0,0 will disable this constraint.
+export function WindowSetMinSize(width: number, height: number): void;
+
+// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
+// Sets the window position relative to the monitor the window is currently on.
+export function WindowSetPosition(x: number, y: number): void;
+
+// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
+// Gets the window position relative to the monitor the window is currently on.
+export function WindowGetPosition(): Promise;
+
+// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
+// Hides the window.
+export function WindowHide(): void;
+
+// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
+// Shows the window, if it is currently hidden.
+export function WindowShow(): void;
+
+// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
+// Maximises the window to fill the screen.
+export function WindowMaximise(): void;
+
+// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
+// Toggles between Maximised and UnMaximised.
+export function WindowToggleMaximise(): void;
+
+// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
+// Restores the window to the dimensions and position prior to maximising.
+export function WindowUnmaximise(): void;
+
+// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
+// Returns the state of the window, i.e. whether the window is maximised or not.
+export function WindowIsMaximised(): Promise;
+
+// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
+// Minimises the window.
+export function WindowMinimise(): void;
+
+// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
+// Restores the window to the dimensions and position prior to minimising.
+export function WindowUnminimise(): void;
+
+// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
+// Returns the state of the window, i.e. whether the window is minimised or not.
+export function WindowIsMinimised(): Promise;
+
+// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
+// Returns the state of the window, i.e. whether the window is normal or not.
+export function WindowIsNormal(): Promise;
+
+// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
+// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
+export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
+
+// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
+// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
+export function ScreenGetAll(): Promise;
+
+// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
+// Opens the given URL in the system browser.
+export function BrowserOpenURL(url: string): void;
+
+// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
+// Returns information about the environment
+export function Environment(): Promise;
+
+// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
+// Quits the application.
+export function Quit(): void;
+
+// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
+// Hides the application.
+export function Hide(): void;
+
+// [Show](https://wails.io/docs/reference/runtime/intro#show)
+// Shows the application.
+export function Show(): void;
+
+// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
+// Returns the current text stored on clipboard
+export function ClipboardGetText(): Promise;
+
+// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
+// Sets a text on the clipboard
+export function ClipboardSetText(text: string): Promise;
+
+// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
+// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
+export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
+
+// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
+// OnFileDropOff removes the drag and drop listeners and handlers.
+export function OnFileDropOff() :void
+
+// Check if the file path resolver is available
+export function CanResolveFilePaths(): boolean;
+
+// Resolves file paths for an array of files
+export function ResolveFilePaths(files: File[]): void
\ No newline at end of file
diff --git a/frontend/lib/wailsjs/runtime/runtime.js b/frontend/lib/wailsjs/runtime/runtime.js
new file mode 100644
index 0000000..623397b
--- /dev/null
+++ b/frontend/lib/wailsjs/runtime/runtime.js
@@ -0,0 +1,238 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+export function LogPrint(message) {
+ window.runtime.LogPrint(message);
+}
+
+export function LogTrace(message) {
+ window.runtime.LogTrace(message);
+}
+
+export function LogDebug(message) {
+ window.runtime.LogDebug(message);
+}
+
+export function LogInfo(message) {
+ window.runtime.LogInfo(message);
+}
+
+export function LogWarning(message) {
+ window.runtime.LogWarning(message);
+}
+
+export function LogError(message) {
+ window.runtime.LogError(message);
+}
+
+export function LogFatal(message) {
+ window.runtime.LogFatal(message);
+}
+
+export function EventsOnMultiple(eventName, callback, maxCallbacks) {
+ return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
+}
+
+export function EventsOn(eventName, callback) {
+ return EventsOnMultiple(eventName, callback, -1);
+}
+
+export function EventsOff(eventName, ...additionalEventNames) {
+ return window.runtime.EventsOff(eventName, ...additionalEventNames);
+}
+
+export function EventsOnce(eventName, callback) {
+ return EventsOnMultiple(eventName, callback, 1);
+}
+
+export function EventsEmit(eventName) {
+ let args = [eventName].slice.call(arguments);
+ return window.runtime.EventsEmit.apply(null, args);
+}
+
+export function WindowReload() {
+ window.runtime.WindowReload();
+}
+
+export function WindowReloadApp() {
+ window.runtime.WindowReloadApp();
+}
+
+export function WindowSetAlwaysOnTop(b) {
+ window.runtime.WindowSetAlwaysOnTop(b);
+}
+
+export function WindowSetSystemDefaultTheme() {
+ window.runtime.WindowSetSystemDefaultTheme();
+}
+
+export function WindowSetLightTheme() {
+ window.runtime.WindowSetLightTheme();
+}
+
+export function WindowSetDarkTheme() {
+ window.runtime.WindowSetDarkTheme();
+}
+
+export function WindowCenter() {
+ window.runtime.WindowCenter();
+}
+
+export function WindowSetTitle(title) {
+ window.runtime.WindowSetTitle(title);
+}
+
+export function WindowFullscreen() {
+ window.runtime.WindowFullscreen();
+}
+
+export function WindowUnfullscreen() {
+ window.runtime.WindowUnfullscreen();
+}
+
+export function WindowIsFullscreen() {
+ return window.runtime.WindowIsFullscreen();
+}
+
+export function WindowGetSize() {
+ return window.runtime.WindowGetSize();
+}
+
+export function WindowSetSize(width, height) {
+ window.runtime.WindowSetSize(width, height);
+}
+
+export function WindowSetMaxSize(width, height) {
+ window.runtime.WindowSetMaxSize(width, height);
+}
+
+export function WindowSetMinSize(width, height) {
+ window.runtime.WindowSetMinSize(width, height);
+}
+
+export function WindowSetPosition(x, y) {
+ window.runtime.WindowSetPosition(x, y);
+}
+
+export function WindowGetPosition() {
+ return window.runtime.WindowGetPosition();
+}
+
+export function WindowHide() {
+ window.runtime.WindowHide();
+}
+
+export function WindowShow() {
+ window.runtime.WindowShow();
+}
+
+export function WindowMaximise() {
+ window.runtime.WindowMaximise();
+}
+
+export function WindowToggleMaximise() {
+ window.runtime.WindowToggleMaximise();
+}
+
+export function WindowUnmaximise() {
+ window.runtime.WindowUnmaximise();
+}
+
+export function WindowIsMaximised() {
+ return window.runtime.WindowIsMaximised();
+}
+
+export function WindowMinimise() {
+ window.runtime.WindowMinimise();
+}
+
+export function WindowUnminimise() {
+ window.runtime.WindowUnminimise();
+}
+
+export function WindowSetBackgroundColour(R, G, B, A) {
+ window.runtime.WindowSetBackgroundColour(R, G, B, A);
+}
+
+export function ScreenGetAll() {
+ return window.runtime.ScreenGetAll();
+}
+
+export function WindowIsMinimised() {
+ return window.runtime.WindowIsMinimised();
+}
+
+export function WindowIsNormal() {
+ return window.runtime.WindowIsNormal();
+}
+
+export function BrowserOpenURL(url) {
+ window.runtime.BrowserOpenURL(url);
+}
+
+export function Environment() {
+ return window.runtime.Environment();
+}
+
+export function Quit() {
+ window.runtime.Quit();
+}
+
+export function Hide() {
+ window.runtime.Hide();
+}
+
+export function Show() {
+ window.runtime.Show();
+}
+
+export function ClipboardGetText() {
+ return window.runtime.ClipboardGetText();
+}
+
+export function ClipboardSetText(text) {
+ return window.runtime.ClipboardSetText(text);
+}
+
+/**
+ * Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
+ *
+ * @export
+ * @callback OnFileDropCallback
+ * @param {number} x - x coordinate of the drop
+ * @param {number} y - y coordinate of the drop
+ * @param {string[]} paths - A list of file paths.
+ */
+
+/**
+ * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
+ *
+ * @export
+ * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
+ * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
+ */
+export function OnFileDrop(callback, useDropTarget) {
+ return window.runtime.OnFileDrop(callback, useDropTarget);
+}
+
+/**
+ * OnFileDropOff removes the drag and drop listeners and handlers.
+ */
+export function OnFileDropOff() {
+ return window.runtime.OnFileDropOff();
+}
+
+export function CanResolveFilePaths() {
+ return window.runtime.CanResolveFilePaths();
+}
+
+export function ResolveFilePaths(files) {
+ return window.runtime.ResolveFilePaths(files);
+}
\ No newline at end of file
diff --git a/frontend/package.json b/frontend/package.json
index 0cc62d2..e83f839 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -12,7 +12,8 @@
"test": "jest --watchAll",
"lint": "expo lint",
"build:preview": "eas build -p android --profile preview --local",
- "build:android": "eas build -p android --local"
+ "build:android": "eas build -p android --local",
+ "build:web": "expo export -p web"
},
"jest": {
"preset": "jest-expo"
diff --git a/frontend/package.json.md5 b/frontend/package.json.md5
new file mode 100644
index 0000000..bf93129
--- /dev/null
+++ b/frontend/package.json.md5
@@ -0,0 +1 @@
+9084e4692d068564abc2554891e6cd45
\ No newline at end of file
diff --git a/frontend/pages/server/page.tsx b/frontend/pages/server/page.tsx
index 22f52fd..11e4453 100644
--- a/frontend/pages/server/page.tsx
+++ b/frontend/pages/server/page.tsx
@@ -11,11 +11,14 @@ import { useMutation } from "@tanstack/react-query";
import { ofetch } from "ofetch";
import { z } from "zod";
import { ErrorAlert } from "@/components/ui/alert";
-import { addServer } from "@/stores/app";
+import appStore, { addServer, setCurrentServer } from "@/stores/app";
import tamaguiConfig from "@/tamagui.config";
+import { useStore } from "zustand";
+import Icons from "@/components/ui/icons";
export default function ServerPage() {
const form = useZForm(serverSchema);
+ const localServer = useStore(appStore, (i) => i.localServer);
const serverConnect = useMutation({
mutationFn: async (body: z.infer) => {
@@ -36,6 +39,13 @@ export default function ServerPage() {
serverConnect.mutate(values);
});
+ const onUseLocalServer = () => {
+ if (localServer) {
+ setCurrentServer(localServer);
+ router.replace("/auth/login");
+ }
+ };
+
return (
<>
-
+
+ {localServer != null && (
+ <>
+ or
+ Use Local Server
+ >
+ )}
>
diff --git a/frontend/stores/app.ts b/frontend/stores/app.ts
index 2177025..2cb6669 100644
--- a/frontend/stores/app.ts
+++ b/frontend/stores/app.ts
@@ -8,15 +8,17 @@ export type AppServer = {
};
type AppStore = {
+ localServer?: string | null;
servers: AppServer[];
- curServerIdx?: number | null;
+ curServer?: string | null;
};
const appStore = createStore(
persist(
() => ({
+ localServer: null,
servers: [],
- curServerIdx: null,
+ curServer: null,
}),
{
name: "vaulterm:app",
@@ -30,36 +32,42 @@ export function addServer(srv: AppServer, setActive?: boolean) {
const isExist = curServers.findIndex((s) => s.url === srv.url);
if (isExist >= 0) {
- setActiveServer(isExist);
+ setCurrentServer(srv.url);
return;
}
appStore.setState((state) => ({
servers: [...state.servers, srv],
- curServerIdx: setActive ? state.servers.length : state.curServerIdx,
+ curServer: setActive ? srv.url : state.curServer,
}));
}
export function removeServer(idx: number) {
appStore.setState((state) => ({
servers: state.servers.filter((_, i) => i !== idx),
- curServerIdx: state.curServerIdx === idx ? null : state.curServerIdx,
}));
}
-export function setActiveServer(idx: number) {
- appStore.setState({ curServerIdx: idx });
+export function setCurrentServer(url: string) {
+ appStore.setState({ curServer: url });
}
export function getCurrentServer() {
- const state = appStore.getState();
- return state.curServerIdx != null ? state.servers[state.curServerIdx] : null;
+ return appStore.getState().curServer;
+}
+
+export function setLocalServer(url: string) {
+ appStore.setState((state) => ({
+ localServer: url,
+ curServer:
+ !state.curServer || state.curServer === state.localServer
+ ? url
+ : state.curServer,
+ }));
}
export const useServer = () => {
- const servers = useStore(appStore, (i) => i.servers);
- const idx = useStore(appStore, (i) => i.curServerIdx);
- return servers.length > 0 && idx != null ? servers[idx] : null;
+ return useStore(appStore, (i) => i.curServer);
};
export default appStore;
diff --git a/server/go.mod b/go.mod
similarity index 64%
rename from server/go.mod
rename to go.mod
index cb5429d..c148092 100644
--- a/server/go.mod
+++ b/go.mod
@@ -10,6 +10,7 @@ require (
github.com/joho/godotenv v1.5.1
github.com/oklog/ulid/v2 v2.1.0
github.com/stretchr/testify v1.9.0
+ github.com/wailsapp/wails/v2 v2.9.2
golang.org/x/crypto v0.28.0
gorm.io/datatypes v1.2.4
gorm.io/driver/postgres v1.5.9
@@ -25,7 +26,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.55.0 // indirect
@@ -35,18 +36,36 @@ require (
require (
filippo.io/edwards25519 v1.1.0 // indirect
+ github.com/bep/debounce v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
+ github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
+ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/kr/text v0.2.0 // indirect
+ github.com/labstack/echo/v4 v4.10.2 // indirect
+ github.com/labstack/gommon v0.4.0 // indirect
+ github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
+ github.com/leaanthony/gosod v1.0.3 // indirect
+ github.com/leaanthony/slicer v1.6.0 // indirect
+ github.com/leaanthony/u v1.1.0 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
+ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
+ github.com/samber/lo v1.38.1 // indirect
+ github.com/tkrajina/go-reflector v0.5.6 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
+ github.com/wailsapp/go-webview2 v1.0.16 // indirect
+ github.com/wailsapp/mimetype v1.4.1 // indirect
+ golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
diff --git a/server/go.sum b/go.sum
similarity index 62%
rename from server/go.sum
rename to go.sum
index 9979d05..421acfe 100644
--- a/server/go.sum
+++ b/go.sum
@@ -2,15 +2,21 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
+github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fasthttp/websocket v1.5.10 h1:bc7NIGyrg1L6sd5pRzCIbXpro54SZLEluZCu0rOpcN4=
github.com/fasthttp/websocket v1.5.10/go.mod h1:BwHeuXGWzCW1/BIKUKD3+qfCl+cTdsHu/f243NcAI/Q=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofiber/contrib/websocket v1.3.2 h1:AUq5PYeKwK50s0nQrnluuINYeep1c4nRCJ0NWsV3cvg=
github.com/gofiber/contrib/websocket v1.3.2/go.mod h1:07u6QGMsvX+sx7iGNCl5xhzuUVArWwLQ3tBIH24i+S8=
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
@@ -29,6 +35,8 @@ github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -41,8 +49,27 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
+github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
+github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
+github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
+github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
+github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
+github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg=
+github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
+github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
+github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
+github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
+github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
+github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
+github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
+github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
+github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
+github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
@@ -55,12 +82,19 @@ github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOa
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
+github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38 h1:D0vL7YNisV2yqE55+q0lFuGse6U8lxlg7fYTctlT5Gc=
github.com/savsgio/gotils v0.0.0-20240704082632-aef3928b8a38/go.mod h1:sM7Mt7uEoCeFSCBM+qBrqvEo+/9vdmj19wzp3yzUhmg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -68,30 +102,56 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
+github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8=
github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM=
+github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU=
+github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
+github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
+github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
+github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
+github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..88f5e1a
--- /dev/null
+++ b/main.go
@@ -0,0 +1,26 @@
+//go:build !gui
+// +build !gui
+
+package main
+
+import (
+ "log"
+ "os"
+
+ srv "rul.sh/vaulterm/server/app"
+)
+
+func main() {
+ server := srv.NewApp()
+
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = "3000"
+ }
+
+ log.Printf("Starting server on port %s\n", port)
+
+ if err := server.Listen(":" + port); err != nil {
+ log.Printf("Server error: %s\n", err)
+ }
+}
diff --git a/main_gui.go b/main_gui.go
new file mode 100644
index 0000000..76a1e3b
--- /dev/null
+++ b/main_gui.go
@@ -0,0 +1,63 @@
+//go:build gui
+// +build gui
+
+package main
+
+import (
+ "context"
+ "embed"
+ "log"
+ "net"
+
+ "github.com/wailsapp/wails/v2/pkg/application"
+ "github.com/wailsapp/wails/v2/pkg/options"
+ "github.com/wailsapp/wails/v2/pkg/options/assetserver"
+ srv "rul.sh/vaulterm/server/app"
+)
+
+//go:embed all:frontend/dist
+var assets embed.FS
+
+func main() {
+ server := srv.NewApp()
+ defer server.Shutdown()
+
+ // Create wails app
+ appCtx := NewApp()
+ app := application.NewWithOptions(&options.App{
+ Title: "Vaulterm",
+ Width: 1150,
+ Height: 720,
+ AssetServer: &assetserver.Options{
+ Assets: assets,
+ },
+ BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
+ OnStartup: func(ctx context.Context) {
+ appCtx.startup(ctx)
+ },
+ Bind: []interface{}{appCtx},
+ })
+
+ // Run the local server
+ go func() {
+ defer app.Quit()
+
+ listener, err := net.Listen("tcp", ":0")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ port := listener.Addr().(*net.TCPAddr).Port
+ appCtx.localPort = port
+
+ log.Printf("Starting server on http://localhost:%d\n", port)
+
+ if err := server.Listener(listener); err != nil {
+ log.Printf("Server error: %s\n", err)
+ }
+ }()
+
+ if err := app.Run(); err != nil {
+ println("Error:", err.Error())
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..53a0f78
--- /dev/null
+++ b/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "vaulterm",
+ "version": "1.0.0",
+ "author": "Khairul Hidayat",
+ "license": "MIT",
+ "description": "Your Unified Vault for Remote Access",
+ "scripts": {
+ "test": "go test -count 1 -p 1 -v rul.sh/vaulterm/server/tests",
+ "dev": "wails dev -s -tags \"gui\"",
+ "build": "cross-env CGO_ENABLED=1 wails build -tags \"gui\" -m -skipbindings -s",
+ "build:frontend": "cd frontend && npm run build:web",
+ "build:server": "cross-env CGO_ENABLED=1 go build -o vaulterm ."
+ },
+ "keywords": [
+ "vaulterm",
+ "ssh",
+ "vnc",
+ "incus",
+ "remote-access",
+ "terminal"
+ ],
+ "devDependencies": {
+ "cross-env": "^7.0.3"
+ }
+}
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
new file mode 100644
index 0000000..17ae51c
--- /dev/null
+++ b/pnpm-lock.yaml
@@ -0,0 +1,70 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+importers:
+
+ .:
+ devDependencies:
+ cross-env:
+ specifier: ^7.0.3
+ version: 7.0.3
+
+packages:
+
+ cross-env@7.0.3:
+ resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==}
+ engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'}
+ hasBin: true
+
+ cross-spawn@7.0.5:
+ resolution: {integrity: sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==}
+ engines: {node: '>= 8'}
+
+ isexe@2.0.0:
+ resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
+
+ path-key@3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+
+ shebang-command@2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+
+ shebang-regex@3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+
+ which@2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+
+snapshots:
+
+ cross-env@7.0.3:
+ dependencies:
+ cross-spawn: 7.0.5
+
+ cross-spawn@7.0.5:
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+
+ isexe@2.0.0: {}
+
+ path-key@3.1.1: {}
+
+ shebang-command@2.0.0:
+ dependencies:
+ shebang-regex: 3.0.0
+
+ shebang-regex@3.0.0: {}
+
+ which@2.0.2:
+ dependencies:
+ isexe: 2.0.0
diff --git a/server/.gitignore b/server/.gitignore
deleted file mode 100644
index 33ca294..0000000
--- a/server/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-tmp/
-.env
-/data.db*
diff --git a/server/Makefile b/server/Makefile
deleted file mode 100644
index 3a6a6b9..0000000
--- a/server/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# Makefile
-
-.PHONY: test build run
-
-# Run tests sequentially with verbose output
-test:
- go test -count 1 -p 1 -v rul.sh/vaulterm/tests
-
-# Build the Go application
-build:
- go build -o myapp .
-
-# Run the built application
-run: build
- ./myapp
diff --git a/server/app/app.go b/server/app/app.go
index 3924f2d..ecc4f34 100644
--- a/server/app/app.go
+++ b/server/app/app.go
@@ -4,13 +4,15 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/joho/godotenv"
- "rul.sh/vaulterm/app/auth"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/middleware"
+ "rul.sh/vaulterm/server/app/auth"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/middleware"
+ "rul.sh/vaulterm/server/utils"
)
func NewApp() *fiber.App {
// Load deps
+ utils.CheckAndCreateEnvFile()
godotenv.Load()
db.Init()
diff --git a/server/app/auth/repository.go b/server/app/auth/repository.go
index 79cb050..72c612d 100644
--- a/server/app/auth/repository.go
+++ b/server/app/auth/repository.go
@@ -2,9 +2,9 @@ package auth
import (
"gorm.io/gorm"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/lib"
- "rul.sh/vaulterm/models"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/lib"
+ "rul.sh/vaulterm/server/models"
)
type Auth struct{ db *gorm.DB }
diff --git a/server/app/auth/router.go b/server/app/auth/router.go
index ec97d01..5f8a667 100644
--- a/server/app/auth/router.go
+++ b/server/app/auth/router.go
@@ -2,10 +2,10 @@ package auth
import (
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/lib"
- "rul.sh/vaulterm/middleware"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/lib"
+ "rul.sh/vaulterm/server/middleware"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func Router(app *fiber.App) {
diff --git a/server/app/auth/schema.go b/server/app/auth/schema.go
index ae7cfaf..2dbc849 100644
--- a/server/app/auth/schema.go
+++ b/server/app/auth/schema.go
@@ -1,6 +1,6 @@
package auth
-import "rul.sh/vaulterm/middleware"
+import "rul.sh/vaulterm/server/middleware"
type LoginSchema struct {
Username string `json:"username"`
diff --git a/server/app/hosts/repository.go b/server/app/hosts/repository.go
index ce45af9..c65bb18 100644
--- a/server/app/hosts/repository.go
+++ b/server/app/hosts/repository.go
@@ -2,9 +2,9 @@ package hosts
import (
"gorm.io/gorm"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
type Hosts struct {
diff --git a/server/app/hosts/router.go b/server/app/hosts/router.go
index 0bb51ac..7e1f563 100644
--- a/server/app/hosts/router.go
+++ b/server/app/hosts/router.go
@@ -6,8 +6,8 @@ import (
"net/http"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func Router(app fiber.Router) {
diff --git a/server/app/hosts/utils.go b/server/app/hosts/utils.go
index 2a20139..cf12fdd 100644
--- a/server/app/hosts/utils.go
+++ b/server/app/hosts/utils.go
@@ -2,13 +2,12 @@ package hosts
import (
"fmt"
- "log"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/app/keychains"
- "rul.sh/vaulterm/lib"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/app/keychains"
+ "rul.sh/vaulterm/server/lib"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func tryConnect(c *fiber.Ctx, host *models.Host) (string, error) {
@@ -46,8 +45,6 @@ func tryConnect(c *fiber.Ctx, host *models.Host) (string, error) {
}
defer c.Close()
- log.Println("Test", c.Conn)
-
os, err := c.GetOS(c)
if err != nil {
return "", err
diff --git a/server/app/keychains/repository.go b/server/app/keychains/repository.go
index 8b6ffa9..23cc079 100644
--- a/server/app/keychains/repository.go
+++ b/server/app/keychains/repository.go
@@ -2,9 +2,9 @@ package keychains
import (
"gorm.io/gorm"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
type Keychains struct {
diff --git a/server/app/keychains/router.go b/server/app/keychains/router.go
index fe0a577..95ccbfc 100644
--- a/server/app/keychains/router.go
+++ b/server/app/keychains/router.go
@@ -5,8 +5,8 @@ import (
"net/http"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func Router(app fiber.Router) {
diff --git a/server/app/router.go b/server/app/router.go
index 76f2b3c..51f9d45 100644
--- a/server/app/router.go
+++ b/server/app/router.go
@@ -2,11 +2,11 @@ package app
import (
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/app/hosts"
- "rul.sh/vaulterm/app/keychains"
- "rul.sh/vaulterm/app/teams"
- "rul.sh/vaulterm/app/teams/members"
- "rul.sh/vaulterm/app/ws"
+ "rul.sh/vaulterm/server/app/hosts"
+ "rul.sh/vaulterm/server/app/keychains"
+ "rul.sh/vaulterm/server/app/teams"
+ "rul.sh/vaulterm/server/app/teams/members"
+ "rul.sh/vaulterm/server/app/ws"
)
func InitRouter(app *fiber.App) {
diff --git a/server/app/teams/members/repository.go b/server/app/teams/members/repository.go
index a1092af..ffc319b 100644
--- a/server/app/teams/members/repository.go
+++ b/server/app/teams/members/repository.go
@@ -3,9 +3,9 @@ package members
import (
"gorm.io/gorm"
"gorm.io/gorm/clause"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
type TeamMembers struct {
diff --git a/server/app/teams/members/router.go b/server/app/teams/members/router.go
index 5e33e83..95732f1 100644
--- a/server/app/teams/members/router.go
+++ b/server/app/teams/members/router.go
@@ -4,10 +4,10 @@ import (
"errors"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/app/teams"
- "rul.sh/vaulterm/app/users"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/app/teams"
+ "rul.sh/vaulterm/server/app/users"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func Router(app fiber.Router) {
diff --git a/server/app/teams/repository.go b/server/app/teams/repository.go
index cc024f5..b3e06e6 100644
--- a/server/app/teams/repository.go
+++ b/server/app/teams/repository.go
@@ -2,9 +2,9 @@ package teams
import (
"gorm.io/gorm"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
type Teams struct {
diff --git a/server/app/teams/router.go b/server/app/teams/router.go
index 45d9284..82491b8 100644
--- a/server/app/teams/router.go
+++ b/server/app/teams/router.go
@@ -5,8 +5,8 @@ import (
"net/http"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func Router(app fiber.Router) fiber.Router {
diff --git a/server/app/users/repository.go b/server/app/users/repository.go
index c13ad39..7ef95aa 100644
--- a/server/app/users/repository.go
+++ b/server/app/users/repository.go
@@ -2,9 +2,9 @@ package users
import (
"gorm.io/gorm"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
type Users struct {
diff --git a/server/app/ws/router.go b/server/app/ws/router.go
index a293eb8..52d7ebf 100644
--- a/server/app/ws/router.go
+++ b/server/app/ws/router.go
@@ -3,8 +3,8 @@ package ws
import (
"github.com/gofiber/contrib/websocket"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/app/ws/stats"
- "rul.sh/vaulterm/app/ws/term"
+ "rul.sh/vaulterm/server/app/ws/stats"
+ "rul.sh/vaulterm/server/app/ws/term"
)
func Router(app fiber.Router) {
diff --git a/server/app/ws/stats/ssh.go b/server/app/ws/stats/ssh.go
index 9a383fa..4bdf653 100644
--- a/server/app/ws/stats/ssh.go
+++ b/server/app/ws/stats/ssh.go
@@ -10,7 +10,7 @@ import (
"time"
"github.com/gofiber/contrib/websocket"
- "rul.sh/vaulterm/lib"
+ "rul.sh/vaulterm/server/lib"
)
func HandleSSHStats(c *websocket.Conn, client *lib.SSHClient) error {
diff --git a/server/app/ws/stats/stats.go b/server/app/ws/stats/stats.go
index 4ff697c..d0899e6 100644
--- a/server/app/ws/stats/stats.go
+++ b/server/app/ws/stats/stats.go
@@ -2,10 +2,10 @@ package stats
import (
"github.com/gofiber/contrib/websocket"
- "rul.sh/vaulterm/app/hosts"
- "rul.sh/vaulterm/lib"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/app/hosts"
+ "rul.sh/vaulterm/server/lib"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func HandleStats(c *websocket.Conn) {
diff --git a/server/app/ws/term/incus.go b/server/app/ws/term/incus.go
index 3cfdbcc..8c37914 100644
--- a/server/app/ws/term/incus.go
+++ b/server/app/ws/term/incus.go
@@ -9,7 +9,7 @@ import (
fastWs "github.com/fasthttp/websocket"
"github.com/gofiber/contrib/websocket"
- "rul.sh/vaulterm/lib"
+ "rul.sh/vaulterm/server/lib"
)
type IncusWebsocketSession struct {
diff --git a/server/app/ws/term/pve.go b/server/app/ws/term/pve.go
index d6060df..0e0be74 100644
--- a/server/app/ws/term/pve.go
+++ b/server/app/ws/term/pve.go
@@ -11,7 +11,7 @@ import (
fastWs "github.com/fasthttp/websocket"
"github.com/gofiber/contrib/websocket"
- "rul.sh/vaulterm/lib"
+ "rul.sh/vaulterm/server/lib"
)
// https://github.com/proxmox/pve-xtermjs/blob/master/README
diff --git a/server/app/ws/term/ssh.go b/server/app/ws/term/ssh.go
index 6c47c78..fba7e51 100644
--- a/server/app/ws/term/ssh.go
+++ b/server/app/ws/term/ssh.go
@@ -8,7 +8,7 @@ import (
"strings"
"github.com/gofiber/contrib/websocket"
- "rul.sh/vaulterm/lib"
+ "rul.sh/vaulterm/server/lib"
)
func NewSSHWebsocketSession(c *websocket.Conn, client *lib.SSHClient) ([]byte, error) {
diff --git a/server/app/ws/term/term.go b/server/app/ws/term/term.go
index c3c012a..8f313a1 100644
--- a/server/app/ws/term/term.go
+++ b/server/app/ws/term/term.go
@@ -5,11 +5,11 @@ import (
"time"
"github.com/gofiber/contrib/websocket"
- "rul.sh/vaulterm/app/hosts"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/lib"
- "rul.sh/vaulterm/models"
- "rul.sh/vaulterm/utils"
+ "rul.sh/vaulterm/server/app/hosts"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/lib"
+ "rul.sh/vaulterm/server/models"
+ "rul.sh/vaulterm/server/utils"
)
func HandleTerm(c *websocket.Conn) {
diff --git a/server/db/database.go b/server/db/database.go
index a44e976..babe18a 100644
--- a/server/db/database.go
+++ b/server/db/database.go
@@ -24,7 +24,8 @@ func Init() {
dsn := os.Getenv("DATABASE_URL")
if dsn == "" {
- dsn = "file:data.db?cache=shared&mode=rwc&_journal_mode=WAL"
+ // WAL: _journal_mode=WAL
+ dsn = "file:data.db?cache=shared&mode=rwc"
}
// Open db connection
diff --git a/server/db/models.go b/server/db/models.go
index 9c2766e..dd936d3 100644
--- a/server/db/models.go
+++ b/server/db/models.go
@@ -1,7 +1,7 @@
package db
import (
- "rul.sh/vaulterm/models"
+ "rul.sh/vaulterm/server/models"
)
var Models = []interface{}{
diff --git a/server/db/seeders.go b/server/db/seeders.go
index 11c466f..3daa9d5 100644
--- a/server/db/seeders.go
+++ b/server/db/seeders.go
@@ -2,8 +2,8 @@ package db
import (
"gorm.io/gorm"
- "rul.sh/vaulterm/lib"
- "rul.sh/vaulterm/models"
+ "rul.sh/vaulterm/server/lib"
+ "rul.sh/vaulterm/server/models"
)
type SeedFn func(*gorm.DB) error
diff --git a/server/lib/crypto.go b/server/lib/crypto.go
index 39ecae3..39d4920 100644
--- a/server/lib/crypto.go
+++ b/server/lib/crypto.go
@@ -138,3 +138,13 @@ func Decrypt(encrypted string) (string, error) {
return string(res), nil
}
+
+// Function to generate a 32-byte random key for AES-256
+func GenerateRandomKey() (string, error) {
+ key := make([]byte, 32) // 32 bytes = 256 bits
+ _, err := rand.Read(key)
+ if err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(key), nil
+}
diff --git a/server/main.go b/server/main.go
deleted file mode 100644
index fda0744..0000000
--- a/server/main.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package main
-
-import (
- "os"
-
- "rul.sh/vaulterm/app"
-)
-
-func main() {
- app := app.NewApp()
-
- port := os.Getenv("PORT")
- if port == "" {
- port = "3000"
- }
-
- app.Listen(":" + port)
-}
diff --git a/server/middleware/auth.go b/server/middleware/auth.go
index 0b05af3..3bd6669 100644
--- a/server/middleware/auth.go
+++ b/server/middleware/auth.go
@@ -1,11 +1,12 @@
package middleware
import (
+ "errors"
"strings"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/db"
- "rul.sh/vaulterm/models"
+ "rul.sh/vaulterm/server/db"
+ "rul.sh/vaulterm/server/models"
)
func Auth(c *fiber.Ctx) error {
@@ -36,6 +37,10 @@ type AuthUser struct {
}
func GetUserSession(sessionId string) (*AuthUser, error) {
+ if sessionId == "" {
+ return nil, errors.New("sessionid is empty")
+ }
+
var session AuthUser
res := db.Get().
diff --git a/server/models/keychain.go b/server/models/keychain.go
index c779d39..776037c 100644
--- a/server/models/keychain.go
+++ b/server/models/keychain.go
@@ -3,7 +3,7 @@ package models
import (
"encoding/json"
- "rul.sh/vaulterm/lib"
+ "rul.sh/vaulterm/server/lib"
)
const (
diff --git a/server/tests/setup_test.go b/server/tests/setup_test.go
index 8d61144..77e90fe 100644
--- a/server/tests/setup_test.go
+++ b/server/tests/setup_test.go
@@ -5,7 +5,7 @@ import (
"os"
"testing"
- "rul.sh/vaulterm/db"
+ "rul.sh/vaulterm/server/db"
)
func TestMain(m *testing.M) {
diff --git a/server/tests/utils.go b/server/tests/utils.go
index d5b6ba6..dd43c11 100644
--- a/server/tests/utils.go
+++ b/server/tests/utils.go
@@ -13,7 +13,7 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
- "rul.sh/vaulterm/app"
+ "rul.sh/vaulterm/server/app"
)
type HTTPTest struct {
diff --git a/server/utils/config.go b/server/utils/config.go
new file mode 100644
index 0000000..600ad05
--- /dev/null
+++ b/server/utils/config.go
@@ -0,0 +1,31 @@
+package utils
+
+import (
+ "fmt"
+ "os"
+
+ "rul.sh/vaulterm/server/lib"
+)
+
+func CheckAndCreateEnvFile() error {
+ // Check if .env file exists
+ if _, err := os.Stat(".env"); !os.IsNotExist(err) {
+ return nil
+ }
+
+ // File doesn't exist, so create it
+ randomKey, err := lib.GenerateRandomKey()
+ if err != nil {
+ return err
+ }
+
+ // Write the random key to the .env file
+ envContent := fmt.Sprintf("ENCRYPTION_KEY=%s\n", randomKey)
+ err = os.WriteFile(".env", []byte(envContent), 0644)
+ if err != nil {
+ return err
+ }
+ fmt.Println(".env file created with ENCRYPTION_KEY.")
+
+ return nil
+}
diff --git a/server/utils/context.go b/server/utils/context.go
index 859021f..18bbc77 100644
--- a/server/utils/context.go
+++ b/server/utils/context.go
@@ -3,7 +3,7 @@ package utils
import (
"github.com/gofiber/contrib/websocket"
"github.com/gofiber/fiber/v2"
- "rul.sh/vaulterm/middleware"
+ "rul.sh/vaulterm/server/middleware"
)
type UserContext = middleware.AuthUser
diff --git a/wails.json b/wails.json
new file mode 100644
index 0000000..bbe13ad
--- /dev/null
+++ b/wails.json
@@ -0,0 +1,14 @@
+{
+ "$schema": "https://wails.io/schemas/config.v2.json",
+ "name": "Vaulterm",
+ "author": {
+ "name": "Khairul Hidayat",
+ "email": "khai@rul.sh"
+ },
+ "outputfilename": "vaulterm",
+ "frontend:install": "pnpm install",
+ "frontend:build": "pnpm run build:web",
+ "frontend:dev:watcher": "pnpm run start",
+ "frontend:dev:serverUrl": "http://localhost:8081",
+ "wailsjsdir": "frontend/lib"
+}
\ No newline at end of file