feat: enhance sidebar edit functionality and prevent text selection

- Added aria-label and type attributes to the edit button in the sidebar.
- Implemented a mechanism to prevent multiple edit triggers using requestAnimationFrame.
- Updated mousedown event handling to allow real controls while preventing text selection in WKWebView.

feat: add reconnectSession method to TabManager

- Introduced reconnectSession method to facilitate session reconnections by ID.

feat: implement disconnected overlay in terminal

- Added setDisconnectedOverlay method to show/hide a disconnected overlay for terminal sessions.
- Created _ensureDisconnectOverlay method to manage the overlay's existence and content.

feat: extend Service API with file-related functions

- Added FileExists and FileIsPrivateKey functions to check file existence and identify private keys.
- Introduced ListSSHKeys function to retrieve SSH private key paths from the user's .ssh directory.
- Implemented SFTPStat and SFTPUploadData functions for enhanced SFTP operations.

refactor: clean up code formatting and improve readability

- Adjusted code formatting for better readability across various files, including consistent use of line breaks and indentation.
This commit is contained in:
Andy Dixon
2026-04-22 14:56:52 +01:00
parent 2ce145ba0f
commit 8fa9fb5be5
20 changed files with 2066 additions and 1300 deletions
+119
View File
@@ -3,14 +3,17 @@
package api
import (
"bytes"
"context"
"encoding/base64"
"encoding/json"
"fmt"
"net"
"os"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"
"time"
@@ -145,6 +148,99 @@ func (s *Service) ListProfiles() ([]models.Profile, error) {
return derefProfiles(profiles), nil
}
// ListSSHKeys returns absolute paths to candidate SSH private keys in ~/.ssh.
func (s *Service) ListSSHKeys() ([]string, error) {
home, err := os.UserHomeDir()
if err != nil {
return []string{}, nil
}
dir := filepath.Join(home, ".ssh")
entries, err := os.ReadDir(dir)
if err != nil {
if os.IsNotExist(err) {
return []string{}, nil
}
return nil, err
}
ignored := map[string]bool{
"authorized_keys": true,
"authorized_keys2": true,
"config": true,
"known_hosts": true,
"known_hosts.old": true,
"ssh_config": true,
"ssh_known_hosts": true,
"ssh_known_hosts2": true,
}
keys := make([]string, 0)
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
if ignored[name] {
continue
}
if strings.HasSuffix(name, ".pub") {
continue
}
if strings.HasSuffix(name, ".old") {
continue
}
fullPath := filepath.Join(dir, name)
if !isLikelyPrivateKey(fullPath) {
continue
}
keys = append(keys, fullPath)
}
sort.Strings(keys)
return keys, nil
}
func isLikelyPrivateKey(path string) bool {
file, err := os.Open(path)
if err != nil {
return false
}
defer file.Close()
buf := make([]byte, 512)
n, err := file.Read(buf)
if err != nil && n == 0 {
return false
}
head := buf[:n]
if bytes.HasPrefix(head, []byte("openssh-key-v1")) {
return true
}
if bytes.Contains(head, []byte("BEGIN OPENSSH PRIVATE KEY")) {
return true
}
if bytes.Contains(head, []byte("BEGIN RSA PRIVATE KEY")) {
return true
}
if bytes.Contains(head, []byte("BEGIN DSA PRIVATE KEY")) {
return true
}
if bytes.Contains(head, []byte("BEGIN EC PRIVATE KEY")) {
return true
}
if bytes.Contains(head, []byte("BEGIN ED25519 PRIVATE KEY")) {
return true
}
if bytes.Contains(head, []byte("BEGIN PRIVATE KEY")) {
return true
}
return false
}
// SearchProfiles searches profiles by display name, host, or tags.
func (s *Service) SearchProfiles(query string) ([]models.Profile, error) {
profiles, err := s.store.SearchProfiles(query)
@@ -733,6 +829,29 @@ func (s *Service) SaveFile(title string, defaultName string) (string, error) {
return path, nil
}
// FileExists returns true if the path exists and is not a directory.
func (s *Service) FileExists(path string) (bool, error) {
if path == "" {
return false, nil
}
info, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return !info.IsDir(), nil
}
// FileIsPrivateKey returns true if the path appears to be an SSH private key.
func (s *Service) FileIsPrivateKey(path string) (bool, error) {
if path == "" {
return false, nil
}
return isLikelyPrivateKey(path), nil
}
// GetAppInfo returns build and environment information.
func (s *Service) GetAppInfo() map[string]string {
return map[string]string{