Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cmd/update_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ var updateWindowsCmd = &cobra.Command{
Use: "update",
Short: "Update blindspot (CLI and tray)",
Run: func(cmd *cobra.Command, args []string) {
// A running session keeps blindspot.exe open, so Windows can't overwrite it
// during the update (the move fails with the file in use). Tell the user to
// disconnect first, in red, and bail out before attempting anything.
if isSessionRunning() {
fmt.Printf("\033[31mYou are connected to a blindspot network. Disconnect before updating (run: blindspot disconnect).\033[0m\n")
os.Exit(1)
}

exe, err := os.Executable()
if err != nil {
fmt.Fprintf(os.Stderr, "Could not locate the blindspot executable: %v\n", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,18 @@ export function CancelReceive() {
}

/**
* Connect runs `blindspot connect -s <session> -p <password> [-n]`, which triggers
* the UAC elevation + daemon launch and blocks until the session is up (or fails).
* It returns the final status line the CLI printed.
* Connect runs `blindspot connect -s <session> -p <password> [-n] [-H <hostname>]`,
* which triggers the UAC elevation + daemon launch and blocks until the session is
* up (or fails). A non-empty hostname overrides the default rendezvous server. It
* returns the final status line the CLI printed.
* @param {string} session
* @param {string} password
* @param {boolean} isNew
* @param {string} hostname
* @returns {$CancellablePromise<string>}
*/
export function Connect(session, password, isNew) {
return $Call.ByID(1698713851, session, password, isNew);
export function Connect(session, password, isNew, hostname) {
return $Call.ByID(1698713851, session, password, isNew, hostname);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions internal/gui/frontend/public/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ button { font-family: inherit; }
user-select: none;
}
.checkbox input { width: 16px; height: 16px; accent-color: var(--blue); }
/* The custom-rendezvous field appears directly under its checkbox; give it room. */
.checkbox + .input { margin-top: 8px; }

.btn-primary.btn-full { margin-top: 16px; padding: 11px; }
.connect-note { margin: 12px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--text-3); }
Expand Down
28 changes: 26 additions & 2 deletions internal/gui/frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ function App() {
const [session, setSession] = useState('')
const [password, setPassword] = useState('')
const [isNew, setIsNew] = useState(false)
const [useCustomRendezvous, setUseCustomRendezvous] = useState(false)
const [hostname, setHostname] = useState('')
const [copied, setCopied] = useState(false)
const [copiedPeer, setCopiedPeer] = useState('')
const [version, setVersion] = useState('')
Expand Down Expand Up @@ -103,7 +105,8 @@ function App() {
const doConnect = async () => {
setNotice('')
try {
const msg = await TrayService.Connect(session, password, isNew)
const rendezvous = useCustomRendezvous ? hostname : ''
const msg = await TrayService.Connect(session, password, isNew, rendezvous)
flash(msg || 'Connected.')
setPassword('')
} catch (e: any) {
Expand Down Expand Up @@ -255,7 +258,7 @@ function App() {
<input
id="session"
className="input"
placeholder="e.g. home-office"
placeholder="e.g. blindspot-friends"
value={session}
onChange={(e) => setSession(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter' && session) doConnect() }}
Expand All @@ -280,6 +283,27 @@ function App() {
<span>Create a new encrypted network</span>
</label>

<label className="checkbox">
<input
type="checkbox"
checked={useCustomRendezvous}
onChange={(e) => setUseCustomRendezvous(e.target.checked)}
/>
<span>Use a custom rendezvous server</span>
</label>

{useCustomRendezvous && (
<input
id="hostname"
className="input"
placeholder="e.g. rendezvous.trycloudflare.com"
value={hostname}
onChange={(e) => setHostname(e.target.value)}
onKeyDown={(e) => { if (e.key === 'Enter' && session) doConnect() }}
autoComplete="off"
/>
)}

<button className="btn btn-primary btn-full" onClick={doConnect} disabled={status.busy || !session}>
{status.busy ? 'Connecting…' : 'Connect'}
</button>
Expand Down
13 changes: 9 additions & 4 deletions internal/gui/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ func Run() {
tray := &TrayService{}

// Declared up front so the SingleInstance callback below (and the tray menu) can
// close over it; assigned once the app exists.
// close over them; assigned once the app exists. The tray is captured too so those
// paths open the panel anchored to the tray icon (ShowWindow) rather than letting
// Wails center a bare window.Show().
var window *application.WebviewWindow
var systemTray *application.SystemTray

app := application.New(application.Options{
Name: "Blindspot",
Expand All @@ -51,14 +54,16 @@ func Run() {
SingleInstance: &application.SingleInstanceOptions{
UniqueID: "dev.enzogp.blindspot.tray",
OnSecondInstanceLaunch: func(application.SecondInstanceData) {
if window != nil {
if systemTray != nil {
systemTray.ShowWindow() // anchored to the tray, like a tray-icon click
} else if window != nil {
window.Show().Focus()
}
},
},
})

systemTray := app.SystemTray.New()
systemTray = app.SystemTray.New()

// quitting flips true only when the user chooses Quit, so the close hook below
// knows to let the app actually terminate instead of just hiding the window.
Expand Down Expand Up @@ -135,7 +140,7 @@ func Run() {
// setting a menu makes Wails wire right-click to open it (see SystemTray.bind).
trayMenu := application.NewMenu()
trayMenu.Add("Show Blindspot").OnClick(func(_ *application.Context) {
window.Show().Focus()
systemTray.ShowWindow() // anchored to the tray, like a tray-icon click
})
trayMenu.AddSeparator()
trayMenu.Add("Quit Blindspot").OnClick(func(_ *application.Context) {
Expand Down
12 changes: 8 additions & 4 deletions internal/gui/trayservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,10 +189,11 @@ func (s *TrayService) clearTransferAfter(msg string, d time.Duration) {
}()
}

// Connect runs `blindspot connect -s <session> -p <password> [-n]`, which triggers
// the UAC elevation + daemon launch and blocks until the session is up (or fails).
// It returns the final status line the CLI printed.
func (s *TrayService) Connect(session, password string, isNew bool) (string, error) {
// Connect runs `blindspot connect -s <session> -p <password> [-n] [-H <hostname>]`,
// which triggers the UAC elevation + daemon launch and blocks until the session is
// up (or fails). A non-empty hostname overrides the default rendezvous server. It
// returns the final status line the CLI printed.
func (s *TrayService) Connect(session, password string, isNew bool, hostname string) (string, error) {
session = strings.TrimSpace(session)
if session == "" {
return "", fmt.Errorf("session name is required")
Expand All @@ -211,6 +212,9 @@ func (s *TrayService) Connect(session, password string, isNew bool) (string, err
if isNew {
args = append(args, "-n")
}
if hostname = strings.TrimSpace(hostname); hostname != "" {
args = append(args, "-H", hostname)
}

s.setBusy(true)
defer s.setBusy(false)
Expand Down
Loading