Save remote bindings from the sync menu

This commit is contained in:
Joe Julian
2026-04-06 16:02:19 -07:00
parent 37297856c4
commit adf91445c3
2 changed files with 147 additions and 0 deletions
+86
View File
@@ -1,6 +1,8 @@
package main
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"flag"
@@ -276,6 +278,7 @@ type ui struct {
toggleMainMenu widget.Clickable
openAdvancedSync widget.Clickable
openSelectedVaultRemote widget.Clickable
saveCurrentRemoteBinding widget.Clickable
openSecuritySettings widget.Clickable
openRemotePrefsHelp widget.Clickable
closeAdvancedSync widget.Clickable
@@ -1985,6 +1988,66 @@ func (u *ui) selectedVaultRemoteBinding() (appstate.RemoteBinding, bool) {
}, true
}
func remoteBindingSuffix(baseURL, path, username string) string {
sum := sha256.Sum256([]byte(strings.TrimSpace(baseURL) + "\n" + strings.TrimSpace(path) + "\n" + strings.TrimSpace(username)))
return hex.EncodeToString(sum[:8])
}
func (u *ui) currentRemoteBindingInput() (appstate.RemoteBindingInput, error) {
baseURL := strings.TrimSpace(u.remoteBaseURL.Text())
remotePath := strings.TrimSpace(u.remotePath.Text())
username := strings.TrimSpace(u.remoteUsername.Text())
password := u.remotePassword.Text()
localVaultPath := strings.TrimSpace(u.vaultPath.Text())
switch {
case localVaultPath == "":
return appstate.RemoteBindingInput{}, fmt.Errorf("local vault path is required")
case baseURL == "":
return appstate.RemoteBindingInput{}, fmt.Errorf("remote base URL is required")
case remotePath == "":
return appstate.RemoteBindingInput{}, fmt.Errorf("remote path is required")
case username == "":
return appstate.RemoteBindingInput{}, fmt.Errorf("remote username is required")
case password == "":
return appstate.RemoteBindingInput{}, fmt.Errorf("remote password is required")
}
suffix := remoteBindingSuffix(baseURL, remotePath, username)
credentialTitle := "WebDAV Sign-In"
if username != "" {
credentialTitle += " · " + username
}
return appstate.RemoteBindingInput{
LocalVaultPath: localVaultPath,
RemoteProfileID: "remote-profile-" + suffix,
RemoteProfileName: friendlyRecentRemoteLabel(recentRemoteRecord{BaseURL: baseURL, Path: remotePath}),
BaseURL: baseURL,
RemotePath: remotePath,
CredentialEntryID: "remote-credential-" + suffix,
CredentialTitle: credentialTitle,
Username: username,
Password: password,
CredentialPath: append([]string(nil), u.currentPath...),
SyncMode: appstate.SyncModeAutomaticOnOpenSave,
}, nil
}
func (u *ui) saveCurrentRemoteBindingAction() error {
input, err := u.currentRemoteBindingInput()
if err != nil {
return err
}
binding, err := u.state.ConfigureRemoteBinding(input)
if err != nil {
return err
}
u.selectedVaultRemoteProfileID = binding.RemoteProfileID
u.selectedVaultRemoteCredentialEntryID = binding.CredentialEntryID
return nil
}
func (u *ui) resolvedSelectedVaultRemoteBinding() (appstate.RemoteBinding, appstate.ResolvedRemoteBinding, bool, error) {
binding, ok := u.selectedVaultRemoteBinding()
if !ok {
@@ -3341,6 +3404,9 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
}
u.startOpenRemoteAction()
}
for u.saveCurrentRemoteBinding.Clicked(gtx) {
u.runAction("save remote binding", u.saveCurrentRemoteBindingAction)
}
for u.clearVaultSelection.Clicked(gtx) {
if u.lifecycleBusy() {
continue
@@ -4531,6 +4597,26 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions {
}
}
}
if u.hasOpenVault() {
baseURL := strings.TrimSpace(u.remoteBaseURL.Text())
remotePath := strings.TrimSpace(u.remotePath.Text())
username := strings.TrimSpace(u.remoteUsername.Text())
password := u.remotePassword.Text()
if baseURL != "" && remotePath != "" && username != "" && password != "" {
rows = append(rows,
layout.Rigid(layout.Spacer{Height: unit.Dp(10)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(11), "Store the current remote sign-in in this vault")
lbl.Color = mutedColor
return lbl.Layout(gtx)
}),
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return tonedButton(gtx, u.theme, &u.saveCurrentRemoteBinding, "Save Current Remote In Vault")
}),
)
}
}
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, rows...)
})
}