From b888e35e51f2a4924f72a21f807094daeb03343b Mon Sep 17 00:00:00 2001 From: Sebastien Valla <83454858+SebastienValla@users.noreply.github.com> Date: Wed, 26 Oct 2022 13:39:42 +0200 Subject: [PATCH] 146-2-step-confirmation-on-delete-wallet-action (#227) adds a confirmation step on cancel wallet --- int/api/html/front/errors.js | 1 + int/api/html/front/wallet.js | 3 +- int/api/server.go | 2 +- int/api/wallet/delete.go | 37 ++++++++++++++++++------ int/api/wallet/errors.go | 3 ++ pkg/gui/password.go | 56 ++++++++++++++++++++++++++++++++++-- 6 files changed, 89 insertions(+), 13 deletions(-) diff --git a/int/api/html/front/errors.js b/int/api/html/front/errors.js index 23cdef3ad..23746e5a3 100644 --- a/int/api/html/front/errors.js +++ b/int/api/html/front/errors.js @@ -2,6 +2,7 @@ const errorCodes = new Map([ ["Wallet-0001", "That nickname is taken. Try Another"], ["Wallet-0002", "Wrong password. Try again"], ["Wallet-0003", "Error while retrieving that wallet. Try again"], + ["Wallet-0004", "Wallet not canceled"], ["Wallet-1001", "Enter a wallet nickname"], ["Wallet-1002", "Enter a wallet password"], ["Wallet-1003", "Error while creating your wallet. Try again"], diff --git a/int/api/html/front/wallet.js b/int/api/html/front/wallet.js index 58464a250..271033346 100644 --- a/int/api/html/front/wallet.js +++ b/int/api/html/front/wallet.js @@ -98,10 +98,9 @@ function deleteRow(element) { .delete("/mgmt/wallet/" + nickname) .then((_) => { wallets = wallets.filter((wallet) => wallet.nickname != nickname); + document.getElementById("user-wallet-table").deleteRow(rowIndex); }) .catch((e) => { errorAlert(getErrorMessage(e.response.data.code)); }); - - document.getElementById("user-wallet-table").deleteRow(rowIndex); } diff --git a/int/api/server.go b/int/api/server.go index 78924352a..5b5c47475 100644 --- a/int/api/server.go +++ b/int/api/server.go @@ -83,7 +83,7 @@ func StartServer(app *fyne.App) { localAPI.MgmtWalletGetHandler = wallet.NewGet(&walletStorage) localAPI.MgmtWalletCreateHandler = wallet.NewCreate(&walletStorage) localAPI.MgmtWalletImportHandler = wallet.NewImport(&walletStorage) - localAPI.MgmtWalletDeleteHandler = wallet.NewDelete(&walletStorage) + localAPI.MgmtWalletDeleteHandler = wallet.NewDelete(&walletStorage, app) localAPI.WebsiteCreatorPrepareHandler = operations.WebsiteCreatorPrepareHandlerFunc( websites.CreatePrepareForWebsiteHandler(app), diff --git a/int/api/wallet/delete.go b/int/api/wallet/delete.go index 6f35341da..e753ba77c 100644 --- a/int/api/wallet/delete.go +++ b/int/api/wallet/delete.go @@ -3,23 +3,31 @@ package wallet import ( "sync" + "fyne.io/fyne/v2" "github.com/go-openapi/runtime/middleware" "github.com/massalabs/thyra/api/swagger/server/models" "github.com/massalabs/thyra/api/swagger/server/restapi/operations" + "github.com/massalabs/thyra/pkg/gui" "github.com/massalabs/thyra/pkg/wallet" ) //nolint:nolintlint,ireturn -func NewDelete(walletStorage *sync.Map) operations.MgmtWalletDeleteHandler { - return &walletDelete{walletStorage: walletStorage} +func NewDelete(walletStorage *sync.Map, app *fyne.App) operations.MgmtWalletDeleteHandler { + return &walletDelete{walletStorage: walletStorage, app: app} } type walletDelete struct { walletStorage *sync.Map + app *fyne.App } //nolint:nolintlint,ireturn func (c *walletDelete) Handle(params operations.MgmtWalletDeleteParams) middleware.Responder { + walletLoaded, err := wallet.Load(params.Nickname) + if err != nil { + return createInternalServerError(errorCodeGetWallet, err.Error()) + } + if len(params.Nickname) == 0 { return operations.NewMgmtWalletDeleteBadRequest().WithPayload( &models.Error{ @@ -28,16 +36,29 @@ func (c *walletDelete) Handle(params operations.MgmtWalletDeleteParams) middlewa }) } + password := gui.AskPasswordDeleteWallet(params.Nickname, c.app) + + err = walletLoaded.Unprotect(password, 0) + if err != nil { + return createInternalServerError(errorCodeWalletWrongPassword, err.Error()) + } + c.walletStorage.Delete(params.Nickname) - err := wallet.Delete(params.Nickname) + err = wallet.Delete(params.Nickname) if err != nil { - return operations.NewMgmtWalletDeleteInternalServerError().WithPayload( - &models.Error{ - Code: errorCodeWalletDeleteFile, - Message: err.Error(), - }) + return createInternalServerError(errorCodeWalletDeleteFile, err.Error()) } return operations.NewMgmtWalletDeleteNoContent() } + +//nolint:nolintlint,ireturn +func createInternalServerError(errorCode string, errorMessage string) middleware.Responder { + return operations.NewWebsiteCreatorPrepareInternalServerError(). + WithPayload( + &models.Error{ + Code: errorCode, + Message: errorMessage, + }) +} diff --git a/int/api/wallet/errors.go b/int/api/wallet/errors.go index 938fcc165..089a80209 100644 --- a/int/api/wallet/errors.go +++ b/int/api/wallet/errors.go @@ -2,6 +2,9 @@ package wallet const ( errorCodeWalletAlreadyExists = "Wallet-0001" + errorCodeWalletWrongPassword = "Wallet-0002" + errorCodeGetWallet = "Wallet-0003" + errorCodeCanceled = "Wallet-0004" errorCodeWalletCreateNoNickname = "Wallet-1001" errorCodeWalletCreateNoPassword = "Wallet-1002" errorCodeWalletCreateNew = "Wallet-1003" diff --git a/pkg/gui/password.go b/pkg/gui/password.go index 557eb57e0..378614d6f 100644 --- a/pkg/gui/password.go +++ b/pkg/gui/password.go @@ -2,6 +2,8 @@ package gui import ( "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/widget" ) @@ -9,14 +11,16 @@ func AskPassword(nickname string, app *fyne.App) string { return Password(nickname, app) } +func AskPasswordDeleteWallet(nickname string, app *fyne.App) string { + return PasswordDeleteWallet(nickname, app) +} + // inspired by https://hackernoon.com/asyncawait-in-golang-an-introductory-guide-ol1e34sg // Thyra password input dialog. func PasswordDialog(nickname string, app *fyne.App) chan string { passwordText := make(chan string) - window := (*app).NewWindow("Massa - Thyra") - width := 250.0 height := 90.0 @@ -50,7 +54,55 @@ func PasswordDialog(nickname string, app *fyne.App) chan string { return passwordText } +func PasswordDeleteDialog(nickname string, app *fyne.App) chan string { + passwordText := make(chan string) + + window := (*app).NewWindow("Massa - Thyra") + + width := 250.0 + height := 80.0 + + window.Resize(fyne.Size{Width: float32(width), Height: float32(height)}) + + password := widget.NewPasswordEntry() + items := []*widget.FormItem{ + widget.NewFormItem("Password", password), + } + + //nolint:exhaustruct + form := &widget.Form{ + Items: items, + OnSubmit: func() { + window.Hide() + passwordText <- password.Text + }, + OnCancel: func() { + passwordText <- "" + window.Hide() + }, + SubmitText: "Delete", + CancelText: "Cancel", + } + spacer := layout.NewSpacer() + text1 := widget.NewLabel(`Delete "` + nickname + `" Wallet ?`) + title := container.New(layout.NewHBoxLayout(), spacer, text1, spacer) + text2 := widget.NewLabel("If you delete a wallet, you will lose your MAS associated to it and ") + text3 := widget.NewLabel("won't be able to edit websites linked to this wallet anymore ") + content := container.New(layout.NewVBoxLayout(), text2, text3, spacer) + centeredForm := container.New(layout.NewVBoxLayout(), spacer, form, spacer) + window.SetContent(container.New(layout.NewVBoxLayout(), title, spacer, content, spacer, centeredForm, spacer)) + window.CenterOnScreen() + window.Canvas().Focus(password) + window.Show() + + return passwordText +} + // This function is blocking, it returns when the user submit or cancel the form. func Password(nickname string, app *fyne.App) string { return <-PasswordDialog(nickname, app) } + +func PasswordDeleteWallet(nickname string, app *fyne.App) string { + return <-PasswordDeleteDialog(nickname, app) +}