Add configurable vault security settings
This commit is contained in:
@@ -136,6 +136,8 @@ type ui struct {
|
||||
apiPolicyOperation widget.Editor
|
||||
apiPolicyPath widget.Editor
|
||||
apiPolicyEntryID widget.Editor
|
||||
securityCipher widget.Editor
|
||||
securityKDF widget.Editor
|
||||
entryID widget.Editor
|
||||
entryTitle widget.Editor
|
||||
entryUsername widget.Editor
|
||||
@@ -170,8 +172,11 @@ type ui struct {
|
||||
synchronizeVault widget.Clickable
|
||||
toggleSyncMenu widget.Clickable
|
||||
openAdvancedSync widget.Clickable
|
||||
openSecuritySettings widget.Clickable
|
||||
closeAdvancedSync widget.Clickable
|
||||
closeSecuritySettings widget.Clickable
|
||||
runAdvancedSync widget.Clickable
|
||||
saveSecuritySettings widget.Clickable
|
||||
editEntry widget.Clickable
|
||||
cancelEdit widget.Clickable
|
||||
pickVaultPath widget.Clickable
|
||||
@@ -268,6 +273,7 @@ type ui struct {
|
||||
syncRemotePassword widget.Editor
|
||||
syncDialogOpen bool
|
||||
syncMenuOpen bool
|
||||
securityDialogOpen bool
|
||||
showSyncPassword bool
|
||||
keyboardFocus focusID
|
||||
defaultSaveAsPath string
|
||||
@@ -349,6 +355,8 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
||||
apiPolicyOperation: widget.Editor{SingleLine: true, Submit: false},
|
||||
apiPolicyPath: widget.Editor{SingleLine: true, Submit: false},
|
||||
apiPolicyEntryID: widget.Editor{SingleLine: true, Submit: false},
|
||||
securityCipher: widget.Editor{SingleLine: true, Submit: false},
|
||||
securityKDF: widget.Editor{SingleLine: true, Submit: false},
|
||||
entryID: widget.Editor{SingleLine: true, Submit: false},
|
||||
entryTitle: widget.Editor{SingleLine: true, Submit: false},
|
||||
entryUsername: widget.Editor{SingleLine: true, Submit: false},
|
||||
@@ -398,6 +406,8 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
||||
u.expandLessIcon, _ = widget.NewIcon(icons.NavigationExpandLess)
|
||||
u.chevronDownIcon, _ = widget.NewIcon(icons.NavigationArrowDropDown)
|
||||
u.passwordProfile.SetText("strong")
|
||||
u.securityCipher.SetText(vault.CipherChaCha20)
|
||||
u.securityKDF.SetText(vault.KDFArgon2)
|
||||
u.keyboardFocus = focusSearch
|
||||
u.setCustomFieldRows(nil)
|
||||
u.loadRecentVaults()
|
||||
@@ -628,6 +638,12 @@ func (u *ui) createVaultAction() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := u.state.ConfigureSecurity(vault.SecuritySettings{
|
||||
Cipher: strings.TrimSpace(u.securityCipher.Text()),
|
||||
KDF: strings.TrimSpace(u.securityKDF.Text()),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := u.state.CreateVault(key); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -640,6 +656,7 @@ func (u *ui) createVaultAction() error {
|
||||
}
|
||||
u.resetPasswordPeek()
|
||||
u.currentPath = append([]string(nil), u.state.CurrentPath...)
|
||||
u.loadSecuritySettingsFromSession()
|
||||
u.editingEntry = false
|
||||
u.filter()
|
||||
return nil
|
||||
@@ -662,6 +679,7 @@ func (u *ui) openVaultAction() error {
|
||||
u.resetPasswordPeek()
|
||||
u.currentPath = append([]string(nil), u.state.CurrentPath...)
|
||||
u.restoreRecentVaultGroup(path)
|
||||
u.loadSecuritySettingsFromSession()
|
||||
u.editingEntry = false
|
||||
u.filter()
|
||||
return nil
|
||||
@@ -709,6 +727,7 @@ func (u *ui) openRemoteAction() error {
|
||||
)
|
||||
u.resetPasswordPeek()
|
||||
u.restoreRecentRemoteGroup(strings.TrimSpace(u.remoteBaseURL.Text()), strings.TrimSpace(u.remotePath.Text()))
|
||||
u.loadSecuritySettingsFromSession()
|
||||
u.editingEntry = false
|
||||
u.filter()
|
||||
return nil
|
||||
@@ -737,6 +756,7 @@ func (u *ui) unlockAction() error {
|
||||
}
|
||||
u.resetPasswordPeek()
|
||||
u.currentPath = append([]string(nil), u.state.CurrentPath...)
|
||||
u.loadSecuritySettingsFromSession()
|
||||
u.editingEntry = false
|
||||
u.filter()
|
||||
return nil
|
||||
@@ -751,6 +771,27 @@ func (u *ui) changeMasterKeyAction() error {
|
||||
return u.state.ChangeMasterKey(key)
|
||||
}
|
||||
|
||||
func (u *ui) loadSecuritySettingsFromSession() {
|
||||
settings, err := u.state.SecuritySettings()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
u.securityCipher.SetText(settings.Cipher)
|
||||
u.securityKDF.SetText(settings.KDF)
|
||||
}
|
||||
|
||||
func (u *ui) saveSecuritySettingsAction() error {
|
||||
settings := vault.SecuritySettings{
|
||||
Cipher: strings.TrimSpace(u.securityCipher.Text()),
|
||||
KDF: strings.TrimSpace(u.securityKDF.Text()),
|
||||
}
|
||||
if err := u.state.ConfigureSecurity(settings); err != nil {
|
||||
return err
|
||||
}
|
||||
u.securityDialogOpen = false
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *ui) clearMasterPassword() {
|
||||
u.masterPassword.SetText("")
|
||||
}
|
||||
@@ -1518,13 +1559,23 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
||||
for u.openAdvancedSync.Clicked(gtx) {
|
||||
u.openAdvancedSyncDialog()
|
||||
}
|
||||
for u.openSecuritySettings.Clicked(gtx) {
|
||||
u.loadSecuritySettingsFromSession()
|
||||
u.securityDialogOpen = true
|
||||
}
|
||||
for u.closeAdvancedSync.Clicked(gtx) {
|
||||
u.syncDialogOpen = false
|
||||
u.showSyncPassword = false
|
||||
}
|
||||
for u.closeSecuritySettings.Clicked(gtx) {
|
||||
u.securityDialogOpen = false
|
||||
}
|
||||
for u.runAdvancedSync.Clicked(gtx) {
|
||||
u.runAction("advanced synchronize vault", u.advancedSyncAction)
|
||||
}
|
||||
for u.saveSecuritySettings.Clicked(gtx) {
|
||||
u.runAction("save security settings", u.saveSecuritySettingsAction)
|
||||
}
|
||||
for u.unlockVault.Clicked(gtx) {
|
||||
u.runAction("unlock vault", u.unlockAction)
|
||||
}
|
||||
@@ -1835,6 +1886,12 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
||||
}
|
||||
return u.syncDialog(gtx)
|
||||
}),
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
if !u.securityDialogOpen {
|
||||
return layout.Dimensions{}
|
||||
}
|
||||
return u.securityDialog(gtx)
|
||||
}),
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
if _, ok := u.pendingApproval(); !ok {
|
||||
return layout.Dimensions{}
|
||||
@@ -1891,6 +1948,61 @@ func (u *ui) syncDialog(gtx layout.Context) layout.Dimensions {
|
||||
)
|
||||
}
|
||||
|
||||
func (u *ui) securityDialog(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
paint.FillShape(gtx.Ops, color.NRGBA{A: 90}, clip.Rect{Max: gtx.Constraints.Max}.Op())
|
||||
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||
}),
|
||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
width := gtx.Dp(unit.Dp(620))
|
||||
if width > gtx.Constraints.Max.X {
|
||||
width = gtx.Constraints.Max.X - gtx.Dp(unit.Dp(24))
|
||||
}
|
||||
if width < 1 {
|
||||
width = gtx.Constraints.Max.X
|
||||
}
|
||||
gtx.Constraints.Min.X = width
|
||||
gtx.Constraints.Max.X = width
|
||||
return card(gtx, u.securityDialogContent)
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func (u *ui) securityDialogContent(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(20), "Security Settings")
|
||||
lbl.Color = accentColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(14), "Choose the KDBX cipher and KDF family KeePassGO should use for new or future saves.")
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout),
|
||||
layout.Rigid(labeledEditorHelp(u.theme, "Cipher", "Supported values: "+strings.Join([]string{vault.CipherAES256, vault.CipherChaCha20}, ", "), &u.securityCipher, false)),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(labeledEditorHelp(u.theme, "KDF", "Supported values: "+strings.Join([]string{vault.KDFAES, vault.KDFArgon2}, ", "), &u.securityKDF, false)),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return tonedButton(gtx, u.theme, &u.closeSecuritySettings, "Cancel")
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return tonedButton(gtx, u.theme, &u.saveSecuritySettings, "Save Security Settings")
|
||||
}),
|
||||
)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
func (u *ui) approvalDialog(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
@@ -2168,6 +2280,10 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
|
||||
layout.Rigid(u.syncButtonGroup),
|
||||
layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Security")
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
btn := material.Button(u.theme, &u.lockVault, "Lock")
|
||||
return btn.Layout(gtx)
|
||||
@@ -2505,6 +2621,10 @@ func (u *ui) detailPanel(gtx layout.Context) layout.Dimensions {
|
||||
}),
|
||||
layout.Rigid(u.syncButtonGroup),
|
||||
layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Security")
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
btn := material.Button(u.theme, &u.lockVault, "Lock")
|
||||
return btn.Layout(gtx)
|
||||
|
||||
Reference in New Issue
Block a user