Skip to content

Commit 97c3bb7

Browse files
committed
Merge branch 'refactorConnectBykeystore'
2 parents e8662b1 + b8ffa0c commit 97c3bb7

File tree

10 files changed

+146
-116
lines changed

10 files changed

+146
-116
lines changed

backend/accounts.go

Lines changed: 96 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -894,6 +894,101 @@ func (backend *Backend) addAccount(account accounts.Interface) {
894894
}
895895
}
896896

897+
// ConnectKeystore ensures that the keystore with the given root fingerprint is connected,
898+
// prompts the user if necessary, and returns the keystore instance.
899+
func (backend *Backend) ConnectKeystore(rootFingerprint []byte) (keystore.Keystore, error) {
900+
type data struct {
901+
Type string `json:"typ"`
902+
KeystoreName string `json:"keystoreName"`
903+
ErrorCode string `json:"errorCode,omitempty"`
904+
ErrorMessage string `json:"errorMessage"`
905+
}
906+
var keystoreName string
907+
persistedKeystore, err := backend.config.AccountsConfig().LookupKeystore(rootFingerprint)
908+
if err == nil {
909+
keystoreName = persistedKeystore.Name
910+
}
911+
var ks keystore.Keystore
912+
timeout := 20 * time.Minute
913+
outerLoop:
914+
for {
915+
backend.Notify(observable.Event{
916+
Subject: "connect-keystore",
917+
Action: action.Replace,
918+
Object: data{
919+
Type: "connect",
920+
KeystoreName: keystoreName,
921+
},
922+
})
923+
ks, err = backend.connectKeystore.connect(
924+
backend.Keystore(),
925+
rootFingerprint,
926+
timeout,
927+
)
928+
if err == nil || errp.Cause(err) != ErrWrongKeystore {
929+
break
930+
} else {
931+
backend.Notify(observable.Event{
932+
Subject: "connect-keystore",
933+
Action: action.Replace,
934+
Object: data{
935+
Type: "error",
936+
ErrorCode: err.Error(),
937+
ErrorMessage: "",
938+
},
939+
})
940+
c := make(chan bool)
941+
// retryCallback is called when the current keystore is deregistered or when
942+
// CancelConnectKeystore() is called.
943+
// In the first case it allows to make a new connection attempt, in the last one
944+
// it'll make this function return ErrUserAbort.
945+
backend.connectKeystore.SetRetryConnect(func(retry bool) {
946+
c <- retry
947+
})
948+
select {
949+
case retry := <-c:
950+
if !retry {
951+
err = errp.ErrUserAbort
952+
break outerLoop
953+
}
954+
case <-time.After(timeout):
955+
backend.connectKeystore.SetRetryConnect(nil)
956+
err = errTimeout
957+
break outerLoop
958+
}
959+
}
960+
}
961+
switch {
962+
case errp.Cause(err) == errReplaced:
963+
// If a previous connect-keystore request is in progress, the previous request is
964+
// failed, but we don't dismiss the prompt, as the new prompt has already been shown
965+
// by the above "connect" notification.
966+
case err == nil || errp.Cause(err) == errp.ErrUserAbort:
967+
// Dismiss prompt after success or upon user abort.
968+
backend.Notify(observable.Event{
969+
Subject: "connect-keystore",
970+
Action: action.Replace,
971+
Object: nil,
972+
})
973+
default:
974+
var errorCode = ""
975+
if errp.Cause(err) == errTimeout {
976+
errorCode = err.Error()
977+
}
978+
// Display error to user.
979+
backend.Notify(observable.Event{
980+
Subject: "connect-keystore",
981+
Action: action.Replace,
982+
Object: data{
983+
Type: "error",
984+
ErrorMessage: err.Error(),
985+
ErrorCode: errorCode,
986+
},
987+
})
988+
}
989+
return ks, err
990+
}
991+
897992
// The accountsAndKeystoreLock must be held when calling this function.
898993
func (backend *Backend) createAndAddAccount(coin coinpkg.Coin, persistedConfig *config.Account) {
899994
if backend.accounts.lookup(persistedConfig.Code) != nil {
@@ -906,100 +1001,11 @@ func (backend *Backend) createAndAddAccount(coin coinpkg.Coin, persistedConfig *
9061001
DBFolder: backend.arguments.CacheDirectoryPath(),
9071002
NotesFolder: backend.arguments.NotesDirectoryPath(),
9081003
ConnectKeystore: func() (keystore.Keystore, error) {
909-
type data struct {
910-
Type string `json:"typ"`
911-
KeystoreName string `json:"keystoreName"`
912-
ErrorCode string `json:"errorCode,omitempty"`
913-
ErrorMessage string `json:"errorMessage"`
914-
}
9151004
accountRootFingerprint, err := persistedConfig.SigningConfigurations.RootFingerprint()
9161005
if err != nil {
9171006
return nil, err
9181007
}
919-
keystoreName := ""
920-
persistedKeystore, err := backend.config.AccountsConfig().LookupKeystore(accountRootFingerprint)
921-
if err == nil {
922-
keystoreName = persistedKeystore.Name
923-
}
924-
var ks keystore.Keystore
925-
timeout := 20 * time.Minute
926-
outerLoop:
927-
for {
928-
backend.Notify(observable.Event{
929-
Subject: "connect-keystore",
930-
Action: action.Replace,
931-
Object: data{
932-
Type: "connect",
933-
KeystoreName: keystoreName,
934-
},
935-
})
936-
ks, err = backend.connectKeystore.connect(
937-
backend.Keystore(),
938-
accountRootFingerprint,
939-
timeout,
940-
)
941-
if err == nil || errp.Cause(err) != ErrWrongKeystore {
942-
break
943-
} else {
944-
backend.Notify(observable.Event{
945-
Subject: "connect-keystore",
946-
Action: action.Replace,
947-
Object: data{
948-
Type: "error",
949-
ErrorCode: err.Error(),
950-
ErrorMessage: "",
951-
},
952-
})
953-
c := make(chan bool)
954-
// retryCallback is called when the current keystore is deregistered or when
955-
// CancelConnectKeystore() is called.
956-
// In the first case it allows to make a new connection attempt, in the last one
957-
// it'll make this function return ErrUserAbort.
958-
backend.connectKeystore.SetRetryConnect(func(retry bool) {
959-
c <- retry
960-
})
961-
select {
962-
case retry := <-c:
963-
if !retry {
964-
err = errp.ErrUserAbort
965-
break outerLoop
966-
}
967-
case <-time.After(timeout):
968-
backend.connectKeystore.SetRetryConnect(nil)
969-
err = errTimeout
970-
break outerLoop
971-
}
972-
}
973-
}
974-
switch {
975-
case errp.Cause(err) == errReplaced:
976-
// If a previous connect-keystore request is in progress, the previous request is
977-
// failed, but we don't dismiss the prompt, as the new prompt has already been shown
978-
// by the above "connect" notification.
979-
case err == nil || errp.Cause(err) == errp.ErrUserAbort:
980-
// Dismiss prompt after success or upon user abort.
981-
backend.Notify(observable.Event{
982-
Subject: "connect-keystore",
983-
Action: action.Replace,
984-
Object: nil,
985-
})
986-
default:
987-
var errorCode = ""
988-
if errp.Cause(err) == errTimeout {
989-
errorCode = err.Error()
990-
}
991-
// Display error to user.
992-
backend.Notify(observable.Event{
993-
Subject: "connect-keystore",
994-
Action: action.Replace,
995-
Object: data{
996-
Type: "error",
997-
ErrorMessage: err.Error(),
998-
ErrorCode: errorCode,
999-
},
1000-
})
1001-
}
1002-
return ks, err
1008+
return backend.ConnectKeystore(accountRootFingerprint)
10031009
},
10041010
RateUpdater: backend.ratesUpdater,
10051011
GetNotifier: func(configurations signing.Configurations) accounts.Notifier {

backend/coins/btc/handlers/handlers.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ func NewHandlers(
7676
handleFunc("/has-secure-output", handlers.ensureAccountInitialized(handlers.getHasSecureOutput)).Methods("GET")
7777
handleFunc("/has-payment-request", handlers.ensureAccountInitialized(handlers.getHasPaymentRequest)).Methods("GET")
7878
handleFunc("/notes/tx", handlers.ensureAccountInitialized(handlers.postSetTxNote)).Methods("POST")
79-
handleFunc("/connect-keystore", handlers.ensureAccountInitialized(handlers.postConnectKeystore)).Methods("POST")
8079
handleFunc("/eth-sign-msg", handlers.ensureAccountInitialized(handlers.postEthSignMsg)).Methods("POST")
8180
handleFunc("/eth-sign-typed-msg", handlers.ensureAccountInitialized(handlers.postEthSignTypedMsg)).Methods("POST")
8281
handleFunc("/eth-sign-wallet-connect-tx", handlers.ensureAccountInitialized(handlers.postEthSignWalletConnectTx)).Methods("POST")
@@ -663,15 +662,6 @@ func (handlers *Handlers) postSetTxNote(r *http.Request) (interface{}, error) {
663662
return nil, handlers.account.SetTxNote(args.InternalTxID, args.Note)
664663
}
665664

666-
func (handlers *Handlers) postConnectKeystore(r *http.Request) (interface{}, error) {
667-
type response struct {
668-
Success bool `json:"success"`
669-
}
670-
671-
_, err := handlers.account.Config().ConnectKeystore()
672-
return response{Success: err == nil}, nil
673-
}
674-
675665
type signingResponse struct {
676666
Success bool `json:"success"`
677667
Signature string `json:"signature"`

backend/handlers/handlers.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ type Backend interface {
117117
LookupEthAccountCode(address string) (accountsTypes.Code, string, error)
118118
Bluetooth() *bluetooth.Bluetooth
119119
IsOnline() bool
120+
ConnectKeystore([]byte) (keystore.Keystore, error)
120121
}
121122

122123
// Handlers provides a web api to the backend.
@@ -251,6 +252,7 @@ func NewHandlers(
251252
getAPIRouterNoError(apiRouter)("/aopp/approve", handlers.postAOPPApprove).Methods("POST")
252253
getAPIRouter(apiRouter)("/aopp/choose-account", handlers.postAOPPChooseAccount).Methods("POST")
253254
getAPIRouterNoError(apiRouter)("/cancel-connect-keystore", handlers.postCancelConnectKeystore).Methods("POST")
255+
getAPIRouterNoError(apiRouter)("/connect-keystore", handlers.postConnectKeystore).Methods("POST")
254256
getAPIRouterNoError(apiRouter)("/set-watchonly", handlers.postSetWatchonly).Methods("POST")
255257
getAPIRouterNoError(apiRouter)("/on-auth-setting-changed", handlers.postOnAuthSettingChanged).Methods("POST")
256258
getAPIRouterNoError(apiRouter)("/export-log", handlers.postExportLog).Methods("POST")
@@ -1494,3 +1496,20 @@ func (handlers *Handlers) postBluetoothConnect(r *http.Request) interface{} {
14941496
func (handlers *Handlers) getOnline(r *http.Request) interface{} {
14951497
return handlers.backend.IsOnline()
14961498
}
1499+
1500+
func (handlers *Handlers) postConnectKeystore(r *http.Request) interface{} {
1501+
type response struct {
1502+
Success bool `json:"success"`
1503+
}
1504+
1505+
var request struct {
1506+
RootFingerprint jsonp.HexBytes `json:"rootFingerprint"`
1507+
}
1508+
1509+
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
1510+
return response{Success: false}
1511+
}
1512+
1513+
_, err := handlers.backend.ConnectKeystore([]byte(request.RootFingerprint))
1514+
return response{Success: err == nil}
1515+
}

frontends/web/src/api/account.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,6 @@ export const addAccount = (coinCode: string, name: string): Promise<TAddAccount>
452452
});
453453
};
454454

455-
export const connectKeystore = (code: AccountCode): Promise<{ success: boolean; }> => {
456-
return apiPost(`account/${code}/connect-keystore`);
457-
};
458-
459455
export type TSignMessage = { success: false, aborted?: boolean; errorMessage?: string; } | { success: true; signature: string; }
460456

461457
export type TSignWalletConnectTx = {

frontends/web/src/api/keystores.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ export const registerTest = (pin: string): Promise<null> => {
3939
export const deregisterTest = (): Promise<null> => {
4040
return apiPost('test/deregister');
4141
};
42+
43+
export const connectKeystore = (rootFingerprint: string): Promise<{ success: boolean; }> => {
44+
return apiPost('connect-keystore', { rootFingerprint });
45+
};

frontends/web/src/routes/account/actionButtons.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ import { useNavigate } from 'react-router-dom';
1919
import { useTranslation } from 'react-i18next';
2020
import { WalletConnectLight } from '@/components/icon';
2121
import { useMediaQuery } from '@/hooks/mediaquery';
22-
import { connectKeystore, AccountCode, IAccount, CoinCode } from '@/api/account';
22+
import { AccountCode, IAccount, CoinCode } from '@/api/account';
2323
import { isEthereumBased } from './utils';
2424
import { ButtonLink } from '@/components/forms';
25+
import { connectKeystore } from '@/api/keystores';
2526
import style from './account.module.css';
2627

2728
type TProps = {
@@ -46,7 +47,7 @@ export const ActionButtons = ({ canSend, code, coinCode, exchangeSupported, acco
4647
const sendLink = `/account/${code}/send`;
4748
const maybeRouteSend = async (e: MouseEvent<HTMLAnchorElement>) => {
4849
e.preventDefault();
49-
const connectResult = await connectKeystore(code);
50+
const connectResult = await connectKeystore(account.keystore.rootFingerprint);
5051
if (connectResult.success) {
5152
// Proceed to the send screen if the keystore was connected.
5253
navigate(sendLink);

frontends/web/src/routes/account/receive/receive.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { ReceiveGuide } from './components/guide';
3030
import { Header } from '@/components/layout';
3131
import { QRCode } from '@/components/qrcode/qrcode';
3232
import { ArrowCirlceLeft, ArrowCirlceLeftActive, ArrowCirlceRight, ArrowCirlceRightActive } from '@/components/icon';
33+
import { connectKeystore } from '@/api/keystores';
3334
import style from './receive.module.css';
3435

3536
type TProps = {
@@ -160,10 +161,10 @@ export const Receive = ({
160161
};
161162

162163
const verifyAddress = async (addressesIndex: number) => {
163-
if (!receiveAddresses || code === undefined) {
164+
if (!receiveAddresses || account === undefined) {
164165
return;
165166
}
166-
const connectResult = await accountApi.connectKeystore(code);
167+
const connectResult = await connectKeystore(account.keystore.rootFingerprint);
167168
if (!connectResult.success) {
168169
return;
169170
}

frontends/web/src/routes/account/send/send.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { FiatValue } from './components/fiat-value';
4141
import { TSelectedUTXOs } from './utxos';
4242
import { TProposalError, txProposalErrorHandling } from './services';
4343
import { CoinControl } from './coin-control';
44+
import { connectKeystore } from '@/api/keystores';
4445
import style from './send.module.css';
4546

4647
type SendProps = {
@@ -134,7 +135,8 @@ class Send extends Component<Props, State> {
134135

135136
private send = async () => {
136137
const code = this.props.account.code;
137-
const connectResult = await accountApi.connectKeystore(code);
138+
const rootFingerprint = this.props.account.keystore.rootFingerprint;
139+
const connectResult = await connectKeystore(rootFingerprint);
138140
if (!connectResult.success) {
139141
return;
140142
}

frontends/web/src/routes/bitsurance/account.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@
1717
import { useState, useEffect, useCallback } from 'react';
1818
import { useNavigate } from 'react-router-dom';
1919
import { useTranslation } from 'react-i18next';
20-
import { IAccount, connectKeystore } from '@/api/account';
20+
import { IAccount } from '@/api/account';
2121
import { BitsuranceGuide } from './guide';
2222
import { GroupedAccountSelector } from '@/components/groupedaccountselector/groupedaccountselector';
2323
import { GuidedContent, GuideWrapper, Header, Main } from '@/components/layout';
2424
import { Spinner } from '@/components/spinner/Spinner';
2525
import { View, ViewContent } from '@/components/view/view';
2626
import { bitsuranceLookup } from '@/api/bitsurance';
2727
import { alertUser } from '@/components/alert/Alert';
28+
import { connectKeystore } from '@/api/keystores';
2829

2930
type TProps = {
3031
accounts: IAccount[];
@@ -66,7 +67,7 @@ export const BitsuranceAccount = ({ code, accounts }: TProps) => {
6667
// if there is only one account available let's automatically redirect to the widget
6768
useEffect(() => {
6869
if (btcAccounts !== undefined && btcAccounts.length === 1) {
69-
connectKeystore(btcAccounts[0].code).then(connectResult => {
70+
connectKeystore(btcAccounts[0].keystore.rootFingerprint).then(connectResult => {
7071
if (!connectResult.success) {
7172
return;
7273
}
@@ -79,7 +80,11 @@ export const BitsuranceAccount = ({ code, accounts }: TProps) => {
7980
const handleProceed = async () => {
8081
setDisabled(true);
8182
try {
82-
const connectResult = await connectKeystore(selected);
83+
const account = btcAccounts?.find(acc => acc.code === selected);
84+
if (account === undefined) {
85+
return;
86+
}
87+
const connectResult = await connectKeystore(account.keystore.rootFingerprint);
8388
if (!connectResult.success) {
8489
return;
8590
}

0 commit comments

Comments
 (0)