Add Android shared vault import flow
This commit is contained in:
@@ -304,6 +304,7 @@ type ui struct {
|
||||
editEntry widget.Clickable
|
||||
cancelEdit widget.Clickable
|
||||
pickVaultPath widget.Clickable
|
||||
importSharedVault widget.Clickable
|
||||
pickKeyFile widget.Clickable
|
||||
pickSyncLocalPath widget.Clickable
|
||||
clearVaultSelection widget.Clickable
|
||||
@@ -758,6 +759,10 @@ func supportsDesktopFilePicker(goos string) bool {
|
||||
return !strings.EqualFold(strings.TrimSpace(goos), "android")
|
||||
}
|
||||
|
||||
func supportsSharedVaultImport(goos string) bool {
|
||||
return strings.EqualFold(strings.TrimSpace(goos), "android")
|
||||
}
|
||||
|
||||
func (u *ui) selectedAttachmentItems() []attachmentItem {
|
||||
item, ok := u.selectedEntry()
|
||||
if !ok || len(item.Attachments) == 0 {
|
||||
@@ -1418,6 +1423,29 @@ func (u *ui) startChooseSyncLocalSourceAction() {
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ui) startImportSharedVaultAction() {
|
||||
if !supportsSharedVaultImport(runtime.GOOS) || u.fileExplorer == nil {
|
||||
return
|
||||
}
|
||||
u.runBackgroundAction("import shared vault", func() (func() error, error) {
|
||||
file, err := u.fileExplorer.ChooseFile(".kdbx")
|
||||
if err != nil {
|
||||
if errors.Is(err, explorer.ErrUserDecline) {
|
||||
return func() error { return nil }, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
content, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func() error {
|
||||
return u.importSharedVaultBytesAction("shared-vault.kdbx", content)
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ui) advancedSyncToAction() error {
|
||||
switch u.syncSourceMode {
|
||||
case syncSourceRemote:
|
||||
@@ -1452,6 +1480,38 @@ func (u *ui) saveAsTargetPath() string {
|
||||
return u.defaultSaveAsPath
|
||||
}
|
||||
|
||||
func (u *ui) importedVaultDestination(name string) string {
|
||||
baseTarget := u.saveAsTargetPath()
|
||||
baseDir := filepath.Dir(baseTarget)
|
||||
baseName := filepath.Base(strings.TrimSpace(name))
|
||||
switch {
|
||||
case baseName == "" || baseName == "." || baseName == string(filepath.Separator):
|
||||
return baseTarget
|
||||
case strings.HasSuffix(strings.ToLower(baseName), ".kdbx"):
|
||||
return filepath.Join(baseDir, baseName)
|
||||
default:
|
||||
return baseTarget
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ui) importSharedVaultBytesAction(name string, content []byte) error {
|
||||
target := u.importedVaultDestination(name)
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0o700); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.WriteFile(target, append([]byte(nil), content...), 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
u.lifecycleMode = "local"
|
||||
u.vaultPath.SetText(target)
|
||||
u.noteRecentVault(target)
|
||||
u.state.ErrorMessage = ""
|
||||
u.state.StatusMessage = ""
|
||||
u.requestMasterPassFocus = true
|
||||
u.filter()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *ui) noteRecentVault(path string) {
|
||||
path = strings.TrimSpace(path)
|
||||
if path == "" {
|
||||
@@ -3490,6 +3550,12 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
||||
}
|
||||
u.runAction("choose vault path", func() error { return u.chooseExistingFileAction(&u.vaultPath) })
|
||||
}
|
||||
for u.importSharedVault.Clicked(gtx) {
|
||||
if u.lifecycleBusy() {
|
||||
continue
|
||||
}
|
||||
u.startImportSharedVaultAction()
|
||||
}
|
||||
for u.pickKeyFile.Clicked(gtx) {
|
||||
if u.lifecycleBusy() {
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user