Add Go project scaffold for Wails v2 SSH/Telnet/RAW TCP client
- go.mod with Wails v2.9.2, x/crypto, go-sqlite3, go-keyring, uuid - cmd/app/main.go: Wails entry point (Nexus Terminal, 1400x900, #1a1a2e) - internal/app/app.go: lifecycle (Startup/Shutdown/DomReady) - internal/models/models.go: full model definitions (Profile, SSHConfig, TelnetConfig, RAWConfig, SessionInfo, KnownHost, AppPreferences, etc.) - internal/models/defaults.go: default values and NewProfile factory - internal/validation/validation.go: thorough field-level validation - frontend/embed.go: embedded frontend assets - Updated existing storage, secrets, config to match new model structure
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// Default port numbers for each protocol.
|
||||
const (
|
||||
DefaultSSHPort = 22
|
||||
DefaultTelnetPort = 23
|
||||
DefaultRAWPort = 23
|
||||
)
|
||||
|
||||
// Default timeout values (in seconds).
|
||||
const (
|
||||
DefaultConnectTimeout = 30
|
||||
DefaultReadTimeout = 0 // no timeout
|
||||
)
|
||||
|
||||
// Default terminal rendering settings.
|
||||
const (
|
||||
DefaultScrollback = 10000
|
||||
DefaultFontSize = 14
|
||||
DefaultFontFamily = "JetBrains Mono, Menlo, Monaco, Consolas, monospace"
|
||||
DefaultCursorStyle = "block"
|
||||
DefaultTerminalType = "xterm-256color"
|
||||
)
|
||||
|
||||
// Default SSH keepalive settings.
|
||||
const (
|
||||
DefaultKeepaliveInterval = 30
|
||||
DefaultKeepaliveCountMax = 3
|
||||
)
|
||||
|
||||
// DefaultAppPreferences returns sensible default application preferences.
|
||||
func DefaultAppPreferences() AppPreferences {
|
||||
return AppPreferences{
|
||||
Theme: "dark",
|
||||
DefaultProtocol: string(ProtocolSSH),
|
||||
ConfirmOnClose: true,
|
||||
ConfirmOnDisconnect: true,
|
||||
ShowStatusBar: true,
|
||||
SidebarWidth: 280,
|
||||
DefaultFontFamily: DefaultFontFamily,
|
||||
DefaultFontSize: DefaultFontSize,
|
||||
DefaultScrollback: DefaultScrollback,
|
||||
DefaultCursorStyle: DefaultCursorStyle,
|
||||
}
|
||||
}
|
||||
|
||||
// NewProfile creates a new Profile with sensible defaults for the given protocol.
|
||||
func NewProfile(protocol Protocol) Profile {
|
||||
now := time.Now()
|
||||
p := Profile{
|
||||
ID: uuid.New().String(),
|
||||
Protocol: protocol,
|
||||
Tags: []string{},
|
||||
ConnectTimeout: DefaultConnectTimeout,
|
||||
ReadTimeout: DefaultReadTimeout,
|
||||
TerminalFontFamily: DefaultFontFamily,
|
||||
TerminalFontSize: DefaultFontSize,
|
||||
TerminalScrollback: DefaultScrollback,
|
||||
TerminalCursorStyle: DefaultCursorStyle,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
||||
switch protocol {
|
||||
case ProtocolSSH:
|
||||
p.Port = DefaultSSHPort
|
||||
p.SSH = &SSHConfig{
|
||||
AuthMethods: []string{"publickey", "password", "keyboard-interactive"},
|
||||
SecretMode: SecretModeAskEveryTime,
|
||||
KeySecretMode: SecretModeAskEveryTime,
|
||||
HostKeyPolicy: HostKeyAsk,
|
||||
TerminalType: DefaultTerminalType,
|
||||
KeepaliveInterval: DefaultKeepaliveInterval,
|
||||
KeepaliveCountMax: DefaultKeepaliveCountMax,
|
||||
JumpHosts: []JumpHost{},
|
||||
EnvVars: map[string]string{},
|
||||
}
|
||||
case ProtocolTelnet:
|
||||
p.Port = DefaultTelnetPort
|
||||
p.Telnet = &TelnetConfig{
|
||||
LocalEcho: false,
|
||||
LineEnding: LineEndingCRLF,
|
||||
TerminalType: DefaultTerminalType,
|
||||
Encoding: "utf-8",
|
||||
}
|
||||
case ProtocolRAW:
|
||||
p.Port = DefaultRAWPort
|
||||
p.RAW = &RAWConfig{
|
||||
LineEnding: LineEndingCRLF,
|
||||
Encoding: "utf-8",
|
||||
PayloadPresets: []PayloadPreset{},
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
// Package models defines the core data structures used throughout
|
||||
// the Nexus Terminal application.
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// Protocol represents the connection protocol for a session.
|
||||
type Protocol string
|
||||
|
||||
const (
|
||||
ProtocolSSH Protocol = "ssh"
|
||||
ProtocolTelnet Protocol = "telnet"
|
||||
ProtocolRAW Protocol = "raw"
|
||||
)
|
||||
|
||||
// HostKeyPolicy determines how unknown or changed SSH host keys are handled.
|
||||
type HostKeyPolicy string
|
||||
|
||||
const (
|
||||
HostKeyStrict HostKeyPolicy = "strict"
|
||||
HostKeyAsk HostKeyPolicy = "ask"
|
||||
HostKeyAcceptNew HostKeyPolicy = "accept-new"
|
||||
HostKeyInsecure HostKeyPolicy = "insecure"
|
||||
)
|
||||
|
||||
// SecretMode controls how credentials are persisted.
|
||||
type SecretMode string
|
||||
|
||||
const (
|
||||
SecretModeSaved SecretMode = "saved"
|
||||
SecretModeSessionOnly SecretMode = "session-only"
|
||||
SecretModeAskEveryTime SecretMode = "ask-every-time"
|
||||
)
|
||||
|
||||
// LineEnding specifies the line-ending convention for Telnet and RAW connections.
|
||||
type LineEnding string
|
||||
|
||||
const (
|
||||
LineEndingLF LineEnding = "lf"
|
||||
LineEndingCR LineEnding = "cr"
|
||||
LineEndingCRLF LineEnding = "crlf"
|
||||
LineEndingNone LineEnding = "none"
|
||||
)
|
||||
|
||||
// Profile holds the full configuration for a connection profile.
|
||||
type Profile struct {
|
||||
ID string `json:"id"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Description string `json:"description"`
|
||||
Protocol Protocol `json:"protocol"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
Tags []string `json:"tags"`
|
||||
Folder string `json:"folder"`
|
||||
Environment string `json:"environment"`
|
||||
Notes string `json:"notes"`
|
||||
Favourite bool `json:"favourite"`
|
||||
LastConnected *time.Time `json:"lastConnected"`
|
||||
ConnectTimeout int `json:"connectTimeout"` // seconds
|
||||
ReadTimeout int `json:"readTimeout"` // seconds
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
|
||||
// Terminal preferences
|
||||
TerminalFontFamily string `json:"terminalFontFamily"`
|
||||
TerminalFontSize int `json:"terminalFontSize"`
|
||||
TerminalScrollback int `json:"terminalScrollback"`
|
||||
TerminalCursorStyle string `json:"terminalCursorStyle"`
|
||||
|
||||
// SSH-specific configuration
|
||||
SSH *SSHConfig `json:"ssh,omitempty"`
|
||||
|
||||
// Telnet-specific configuration
|
||||
Telnet *TelnetConfig `json:"telnet,omitempty"`
|
||||
|
||||
// RAW-specific configuration
|
||||
RAW *RAWConfig `json:"raw,omitempty"`
|
||||
}
|
||||
|
||||
// SSHConfig holds SSH-specific settings for a connection profile.
|
||||
type SSHConfig struct {
|
||||
AuthMethods []string `json:"authMethods"` // password, publickey, keyboard-interactive
|
||||
SecretMode SecretMode `json:"secretMode"`
|
||||
PrivateKeyPath string `json:"privateKeyPath"`
|
||||
KeySecretMode SecretMode `json:"keySecretMode"`
|
||||
HostKeyPolicy HostKeyPolicy `json:"hostKeyPolicy"`
|
||||
TerminalType string `json:"terminalType"`
|
||||
KeepaliveInterval int `json:"keepaliveInterval"`
|
||||
KeepaliveCountMax int `json:"keepaliveCountMax"`
|
||||
Compression bool `json:"compression"`
|
||||
JumpHosts []JumpHost `json:"jumpHosts"`
|
||||
StartupCommand string `json:"startupCommand"`
|
||||
EnvVars map[string]string `json:"envVars"`
|
||||
}
|
||||
|
||||
// JumpHost describes a proxy/bastion host used for SSH multi-hop connections.
|
||||
type JumpHost struct {
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
Username string `json:"username"`
|
||||
AuthMethod string `json:"authMethod"`
|
||||
SecretMode SecretMode `json:"secretMode"`
|
||||
PrivateKeyPath string `json:"privateKeyPath"`
|
||||
}
|
||||
|
||||
// TelnetConfig holds Telnet-specific settings for a connection profile.
|
||||
type TelnetConfig struct {
|
||||
LocalEcho bool `json:"localEcho"`
|
||||
LineEnding LineEnding `json:"lineEnding"`
|
||||
TerminalType string `json:"terminalType"`
|
||||
Encoding string `json:"encoding"`
|
||||
NegotiationDebug bool `json:"negotiationDebug"`
|
||||
LineMode bool `json:"lineMode"`
|
||||
}
|
||||
|
||||
// RAWConfig holds RAW TCP-specific settings for a connection profile.
|
||||
type RAWConfig struct {
|
||||
AutoReconnect bool `json:"autoReconnect"`
|
||||
LineEnding LineEnding `json:"lineEnding"`
|
||||
Encoding string `json:"encoding"`
|
||||
ShowTimestamps bool `json:"showTimestamps"`
|
||||
ShowDirection bool `json:"showDirection"`
|
||||
PayloadPresets []PayloadPreset `json:"payloadPresets"`
|
||||
}
|
||||
|
||||
// PayloadPreset stores a reusable payload for RAW TCP connections.
|
||||
type PayloadPreset struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Payload string `json:"payload"` // base64-encoded for binary safety
|
||||
Format string `json:"format"` // text, hex, escaped
|
||||
}
|
||||
|
||||
// SessionState represents the lifecycle state of a connection session.
|
||||
type SessionState string
|
||||
|
||||
const (
|
||||
SessionConnecting SessionState = "connecting"
|
||||
SessionConnected SessionState = "connected"
|
||||
SessionDisconnected SessionState = "disconnected"
|
||||
SessionError SessionState = "error"
|
||||
)
|
||||
|
||||
// SessionInfo provides metadata about an active or recent session.
|
||||
type SessionInfo struct {
|
||||
ID string `json:"id"`
|
||||
ProfileID string `json:"profileId"`
|
||||
ProfileName string `json:"profileName"`
|
||||
Protocol Protocol `json:"protocol"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
State SessionState `json:"state"`
|
||||
TabName string `json:"tabName"`
|
||||
Pinned bool `json:"pinned"`
|
||||
ConnectedAt time.Time `json:"connectedAt"`
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// KnownHost records a previously-seen SSH host key fingerprint.
|
||||
type KnownHost struct {
|
||||
ID string `json:"id"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
KeyType string `json:"keyType"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
PublicKey string `json:"publicKey"`
|
||||
FirstSeen time.Time `json:"firstSeen"`
|
||||
LastSeen time.Time `json:"lastSeen"`
|
||||
Trusted bool `json:"trusted"`
|
||||
}
|
||||
|
||||
// AppPreferences stores user-level application settings.
|
||||
type AppPreferences struct {
|
||||
Theme string `json:"theme"`
|
||||
DefaultProtocol string `json:"defaultProtocol"`
|
||||
ConfirmOnClose bool `json:"confirmOnClose"`
|
||||
ConfirmOnDisconnect bool `json:"confirmOnDisconnect"`
|
||||
ShowStatusBar bool `json:"showStatusBar"`
|
||||
SidebarWidth int `json:"sidebarWidth"`
|
||||
DefaultFontFamily string `json:"defaultFontFamily"`
|
||||
DefaultFontSize int `json:"defaultFontSize"`
|
||||
DefaultScrollback int `json:"defaultScrollback"`
|
||||
DefaultCursorStyle string `json:"defaultCursorStyle"`
|
||||
}
|
||||
|
||||
// AuditEntry records an auditable action within the application.
|
||||
type AuditEntry struct {
|
||||
ID string `json:"id"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Action string `json:"action"`
|
||||
ProfileID string `json:"profileId,omitempty"`
|
||||
SessionID string `json:"sessionId,omitempty"`
|
||||
Details string `json:"details"`
|
||||
}
|
||||
Reference in New Issue
Block a user