From 000a7c53d2659f58f5650dc2d726d5a65d64bbce Mon Sep 17 00:00:00 2001 From: Leigh McCulloch Date: Fri, 29 May 2020 04:28:24 +1000 Subject: [PATCH] exp/services/recoverysigner: add support for configuring and using multiple signing keys (#2627) ### What Add support for configuring and using multiple signing keys where the first signing key in the list is the default used for signing and the others can be selected according to SEP-30 v0.3.0. ### Why The reference implementation adheres to the API changes defined in SEP-30 v0.3.0 that supported multiple signing keys per registered account for the purpose of rotating signing keys, however the reference implementation does not actually support multiple signing keys being configured at one time. ### Note Much of this code is possibly going to be rewritten for #2343 where global keys will be supplemented with unique keys for each account that get stored in the database. ### Known limitations There is some code duplicity in this PR that I don't think is worth optimizing on until unique keys are implemented as trying to abstract commonalities may make @howardtw's job harder if the abstraction doesn't quite align with the logic he inserts. I think we should revisit any duplicate code once the unique key logic is added. --- exp/services/recoverysigner/cmd/serve.go | 4 +- .../internal/serve/account_delete.go | 18 +- .../internal/serve/account_delete_test.go | 79 ++++-- .../internal/serve/account_get.go | 18 +- .../internal/serve/account_get_test.go | 79 ++++-- .../internal/serve/account_list.go | 54 ++-- .../internal/serve/account_list_test.go | 52 +++- .../internal/serve/account_post.go | 18 +- .../internal/serve/account_post_test.go | 115 ++++++--- .../internal/serve/account_put.go | 18 +- .../internal/serve/account_put_test.go | 70 ++++-- .../internal/serve/account_sign.go | 26 +- .../account_sign_signing_address_test.go | 235 +++++++++++++----- .../internal/serve/account_sign_test.go | 165 ++++++++---- .../recoverysigner/internal/serve/serve.go | 57 +++-- 15 files changed, 711 insertions(+), 297 deletions(-) diff --git a/exp/services/recoverysigner/cmd/serve.go b/exp/services/recoverysigner/cmd/serve.go index 61887e7ba4..f7b1f35ed5 100644 --- a/exp/services/recoverysigner/cmd/serve.go +++ b/exp/services/recoverysigner/cmd/serve.go @@ -45,9 +45,9 @@ func (c *ServeCommand) Command() *cobra.Command { }, { Name: "signing-key", - Usage: "Stellar signing key used for signing transactions (will be deprecated with per-account keys in the future)", + Usage: "Stellar signing key(s) used for signing transactions comma separated (first key is preferred signer) (will be deprecated with per-account keys in the future)", OptType: types.String, - ConfigKey: &opts.SigningKey, + ConfigKey: &opts.SigningKeys, Required: true, }, { diff --git a/exp/services/recoverysigner/internal/serve/account_delete.go b/exp/services/recoverysigner/internal/serve/account_delete.go index 418cd57beb..c59d7ac5ae 100644 --- a/exp/services/recoverysigner/internal/serve/account_delete.go +++ b/exp/services/recoverysigner/internal/serve/account_delete.go @@ -12,9 +12,9 @@ import ( ) type accountDeleteHandler struct { - Logger *supportlog.Entry - SigningAddress *keypair.FromAddress - AccountStore account.Store + Logger *supportlog.Entry + SigningAddresses []*keypair.FromAddress + AccountStore account.Store } type accountDeleteRequest struct { @@ -53,12 +53,16 @@ func (h accountDeleteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) return } + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } resp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } // Authorized if authenticated as the account. diff --git a/exp/services/recoverysigner/internal/serve/account_delete_test.go b/exp/services/recoverysigner/internal/serve/account_delete_test.go index ceba47e708..0bf99f7575 100644 --- a/exp/services/recoverysigner/internal/serve/account_delete_test.go +++ b/exp/services/recoverysigner/internal/serve/account_delete_test.go @@ -33,9 +33,12 @@ func TestAccountDelete_authenticatedNotAuthorized(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -76,9 +79,12 @@ func TestAccountDelete_notAuthenticated(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -119,9 +125,12 @@ func TestAccountDelete_notFound(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -168,9 +177,12 @@ func TestAccountDelete_authenticatedByIdentityAddress(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -206,6 +218,10 @@ func TestAccountDelete_authenticatedByIdentityAddress(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -237,9 +253,12 @@ func TestAccountDelete_authenticatedByAccountAddress(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -274,6 +293,10 @@ func TestAccountDelete_authenticatedByAccountAddress(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -305,9 +328,12 @@ func TestAccountDelete_authenticatedByPhoneNumber(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -343,6 +369,10 @@ func TestAccountDelete_authenticatedByPhoneNumber(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -374,9 +404,12 @@ func TestAccountDelete_authenticatedByEmail(t *testing.T) { }, }) h := accountDeleteHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -412,6 +445,10 @@ func TestAccountDelete_authenticatedByEmail(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` diff --git a/exp/services/recoverysigner/internal/serve/account_get.go b/exp/services/recoverysigner/internal/serve/account_get.go index 2c5f356b6e..a716d7c968 100644 --- a/exp/services/recoverysigner/internal/serve/account_get.go +++ b/exp/services/recoverysigner/internal/serve/account_get.go @@ -12,9 +12,9 @@ import ( ) type accountGetHandler struct { - Logger *supportlog.Entry - SigningAddress *keypair.FromAddress - AccountStore account.Store + Logger *supportlog.Entry + SigningAddresses []*keypair.FromAddress + AccountStore account.Store } type accountGetRequest struct { @@ -53,12 +53,16 @@ func (h accountGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } resp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } // Authorized if authenticated as the account. diff --git a/exp/services/recoverysigner/internal/serve/account_get_test.go b/exp/services/recoverysigner/internal/serve/account_get_test.go index f904d57240..10db804c5f 100644 --- a/exp/services/recoverysigner/internal/serve/account_get_test.go +++ b/exp/services/recoverysigner/internal/serve/account_get_test.go @@ -33,9 +33,12 @@ func TestAccountGet_authenticatedNotAuthorized(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -76,9 +79,12 @@ func TestAccountGet_notAuthenticated(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -119,9 +125,12 @@ func TestAccountGet_notFound(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -168,9 +177,12 @@ func TestAccountGet_authenticatedByIdentityAddress(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -206,6 +218,10 @@ func TestAccountGet_authenticatedByIdentityAddress(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -233,9 +249,12 @@ func TestAccountGet_authenticatedByAccountAddress(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -270,6 +289,10 @@ func TestAccountGet_authenticatedByAccountAddress(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -297,9 +320,12 @@ func TestAccountGet_authenticatedByPhoneNumber(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -335,6 +361,10 @@ func TestAccountGet_authenticatedByPhoneNumber(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -362,9 +392,12 @@ func TestAccountGet_authenticatedByEmail(t *testing.T) { }, }) h := accountGetHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -400,6 +433,10 @@ func TestAccountGet_authenticatedByEmail(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` diff --git a/exp/services/recoverysigner/internal/serve/account_list.go b/exp/services/recoverysigner/internal/serve/account_list.go index 88c278683c..9aedcd0381 100644 --- a/exp/services/recoverysigner/internal/serve/account_list.go +++ b/exp/services/recoverysigner/internal/serve/account_list.go @@ -11,9 +11,9 @@ import ( ) type accountListHandler struct { - Logger *supportlog.Entry - SigningAddress *keypair.FromAddress - AccountStore account.Store + Logger *supportlog.Entry + SigningAddresses []*keypair.FromAddress + AccountStore account.Store } type accountListResponse struct { @@ -48,12 +48,16 @@ func (h accountListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { serverError.Render(w) return } else { + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } accResp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } for _, i := range acc.Identities { accRespIdentity := accountResponseIdentity{ @@ -75,12 +79,16 @@ func (h accountListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } for _, acc := range accs { + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } accResp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } for _, i := range acc.Identities { accRespIdentity := accountResponseIdentity{ @@ -110,12 +118,16 @@ func (h accountListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } for _, acc := range accs { + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } accResp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } for _, i := range acc.Identities { accRespIdentity := accountResponseIdentity{ @@ -145,12 +157,16 @@ func (h accountListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } for _, acc := range accs { + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } accResp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } for _, i := range acc.Identities { accRespIdentity := accountResponseIdentity{ diff --git a/exp/services/recoverysigner/internal/serve/account_list_test.go b/exp/services/recoverysigner/internal/serve/account_list_test.go index 6204cf61d8..54e03e15da 100644 --- a/exp/services/recoverysigner/internal/serve/account_list_test.go +++ b/exp/services/recoverysigner/internal/serve/account_list_test.go @@ -46,9 +46,12 @@ func TestAccountList_authenticatedButNonePermitted(t *testing.T) { }, }) h := accountListHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -108,9 +111,12 @@ func TestAccountList_authenticatedByPhoneNumber(t *testing.T) { }, }) h := accountListHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -140,6 +146,10 @@ func TestAccountList_authenticatedByPhoneNumber(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }, @@ -153,6 +163,10 @@ func TestAccountList_authenticatedByPhoneNumber(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] } @@ -197,9 +211,12 @@ func TestAccountList_authenticatedByEmail(t *testing.T) { }, }) h := accountListHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -229,6 +246,10 @@ func TestAccountList_authenticatedByEmail(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }, @@ -242,6 +263,10 @@ func TestAccountList_authenticatedByEmail(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] } @@ -286,9 +311,12 @@ func TestAccountList_notAuthenticated(t *testing.T) { }, }) h := accountListHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() diff --git a/exp/services/recoverysigner/internal/serve/account_post.go b/exp/services/recoverysigner/internal/serve/account_post.go index d6cf9a5da1..05d467f618 100644 --- a/exp/services/recoverysigner/internal/serve/account_post.go +++ b/exp/services/recoverysigner/internal/serve/account_post.go @@ -13,9 +13,9 @@ import ( ) type accountPostHandler struct { - Logger *supportlog.Entry - SigningAddress *keypair.FromAddress - AccountStore account.Store + Logger *supportlog.Entry + SigningAddresses []*keypair.FromAddress + AccountStore account.Store } type accountPostRequest struct { @@ -139,12 +139,16 @@ func (h accountPostHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { l.Info("Account registered.") + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } resp := accountResponse{ Address: acc.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } for _, i := range acc.Identities { respIdentity := accountResponseIdentity{ diff --git a/exp/services/recoverysigner/internal/serve/account_post_test.go b/exp/services/recoverysigner/internal/serve/account_post_test.go index 85eba61643..9914e0634a 100644 --- a/exp/services/recoverysigner/internal/serve/account_post_test.go +++ b/exp/services/recoverysigner/internal/serve/account_post_test.go @@ -22,9 +22,12 @@ import ( func TestAccountPost_newWithRoleOwnerContentTypeJSON(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -66,6 +69,10 @@ func TestAccountPost_newWithRoleOwnerContentTypeJSON(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -92,9 +99,12 @@ func TestAccountPost_newWithRoleOwnerContentTypeJSON(t *testing.T) { func TestAccountPost_newWithRoleOwnerContentTypeForm(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -135,6 +145,10 @@ func TestAccountPost_newWithRoleOwnerContentTypeForm(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -161,9 +175,12 @@ func TestAccountPost_newWithRoleOwnerContentTypeForm(t *testing.T) { func TestAccountPost_newWithRolesSenderReceiverContentTypeJSON(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -214,6 +231,10 @@ func TestAccountPost_newWithRolesSenderReceiverContentTypeJSON(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -248,9 +269,12 @@ func TestAccountPost_newWithRolesSenderReceiverContentTypeJSON(t *testing.T) { func TestAccountPost_newWithRolesSenderReceiverContentTypeForm(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -299,6 +323,10 @@ func TestAccountPost_newWithRolesSenderReceiverContentTypeForm(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -336,9 +364,12 @@ func TestAccountPost_accountAddressInvalid(t *testing.T) { Address: "GDIXCQJ2W2N6TAS6AYW4LW2EBV7XNRUCLNHQB37FARDEWBQXRWP47Q6N", }) h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -374,9 +405,12 @@ func TestAccountPost_accountAlreadyExists(t *testing.T) { Address: "GDIXCQJ2W2N6TAS6AYW4LW2EBV7XNRUCLNHQB37FARDEWBQXRWP47Q6N", }) h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -422,9 +456,12 @@ func TestAccountPost_accountAlreadyExists(t *testing.T) { func TestAccountPost_identitiesNotProvided(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -457,9 +494,12 @@ func TestAccountPost_identitiesNotProvided(t *testing.T) { func TestAccountPost_roleNotProvided(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -502,9 +542,12 @@ func TestAccountPost_roleNotProvided(t *testing.T) { func TestAccountPost_authMethodsNotProvided(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -546,9 +589,12 @@ func TestAccountPost_authMethodTypeUnrecognized(t *testing.T) { Address: "GDIXCQJ2W2N6TAS6AYW4LW2EBV7XNRUCLNHQB37FARDEWBQXRWP47Q6N", }) h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -597,9 +643,12 @@ func TestAccountPost_authMethodTypeUnrecognized(t *testing.T) { func TestAccountPost_notAuthenticatedForAccount(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountPostHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() diff --git a/exp/services/recoverysigner/internal/serve/account_put.go b/exp/services/recoverysigner/internal/serve/account_put.go index cf8e3654a1..ad8ce8b83e 100644 --- a/exp/services/recoverysigner/internal/serve/account_put.go +++ b/exp/services/recoverysigner/internal/serve/account_put.go @@ -13,9 +13,9 @@ import ( ) type accountPutHandler struct { - Logger *supportlog.Entry - SigningAddress *keypair.FromAddress - AccountStore account.Store + Logger *supportlog.Entry + SigningAddresses []*keypair.FromAddress + AccountStore account.Store } type accountPutRequest struct { @@ -165,12 +165,16 @@ func (h accountPutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { l.Info("Account updated.") + signers := []accountResponseSigner{} + for _, signingAddress := range h.SigningAddresses { + signers = append(signers, accountResponseSigner{ + Key: signingAddress.Address(), + }) + } resp := accountResponse{ Address: accWithNewIdentiies.Address, - Signer: h.SigningAddress.Address(), - Signers: []accountResponseSigner{ - {Key: h.SigningAddress.Address()}, - }, + Signer: h.SigningAddresses[0].Address(), + Signers: signers, } for _, i := range accWithNewIdentiies.Identities { resp.Identities = append(resp.Identities, accountResponseIdentity{ diff --git a/exp/services/recoverysigner/internal/serve/account_put_test.go b/exp/services/recoverysigner/internal/serve/account_put_test.go index 4409837e4f..33ad0420dd 100644 --- a/exp/services/recoverysigner/internal/serve/account_put_test.go +++ b/exp/services/recoverysigner/internal/serve/account_put_test.go @@ -38,9 +38,12 @@ func TestAccountPut_authenticatedNotAuthorized(t *testing.T) { }, }) h := accountPutHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -99,9 +102,12 @@ func TestAccountPut_notAuthenticated(t *testing.T) { }, }) h := accountPutHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -160,9 +166,12 @@ func TestAccountPut_authenticatedByAccountAddress(t *testing.T) { }, }) h := accountPutHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -206,6 +215,10 @@ func TestAccountPut_authenticatedByAccountAddress(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -250,9 +263,12 @@ func TestAccountPut_authenticatedByIdentityAddress(t *testing.T) { }, }) h := accountPutHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -296,6 +312,10 @@ func TestAccountPut_authenticatedByIdentityAddress(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -340,9 +360,12 @@ func TestAccountPut_authenticatedByPhoneNumber(t *testing.T) { }, }) h := accountPutHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -386,6 +409,10 @@ func TestAccountPut_authenticatedByPhoneNumber(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` @@ -430,9 +457,12 @@ func TestAccountPut_authenticatedByEmail(t *testing.T) { }, }) h := accountPutHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningAddress: keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningAddresses: []*keypair.FromAddress{ + keypair.MustParseAddress("GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE"), + keypair.MustParseAddress("GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS"), + }, } ctx := context.Background() @@ -476,6 +506,10 @@ func TestAccountPut_authenticatedByEmail(t *testing.T) { { "key": "GCAPXRXSU7P6D353YGXMP6ROJIC744HO5OZCIWTXZQK2X757YU5KCHUE", "added_at": "0001-01-01T00:00:00Z" + }, + { + "key": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "added_at": "0001-01-01T00:00:00Z" } ] }` diff --git a/exp/services/recoverysigner/internal/serve/account_sign.go b/exp/services/recoverysigner/internal/serve/account_sign.go index fdf45a925d..a6c388b566 100644 --- a/exp/services/recoverysigner/internal/serve/account_sign.go +++ b/exp/services/recoverysigner/internal/serve/account_sign.go @@ -14,7 +14,7 @@ import ( type accountSignHandler struct { Logger *supportlog.Entry - SigningKey *keypair.Full + SigningKeys []*keypair.Full NetworkPassphrase string AccountStore account.Store } @@ -57,10 +57,22 @@ func (h accountSignHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { l.Info("Request to sign transaction.") - if req.SigningAddress != nil && req.SigningAddress.Address() != h.SigningKey.Address() { - l.Info("Signing key not found.") - notFound.Render(w) - return + var signingKey *keypair.Full + if req.SigningAddress != nil { + for _, sk := range h.SigningKeys { + if req.SigningAddress.Address() == sk.Address() { + signingKey = sk + break + } + } + if signingKey == nil { + l.Info("Signing key not found.") + notFound.Render(w) + return + } + } + if signingKey == nil { + signingKey = h.SigningKeys[0] } // Find the account that the request is for. @@ -149,7 +161,7 @@ func (h accountSignHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { serverError.Render(w) return } - sig, err := h.SigningKey.SignBase64(hash[:]) + sig, err := signingKey.SignBase64(hash[:]) if err != nil { l.Error("Error signing transaction:", err) serverError.Render(w) @@ -159,7 +171,7 @@ func (h accountSignHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { l.Info("Transaction signed.") resp := accountSignResponse{ - Signer: h.SigningKey.Address(), + Signer: signingKey.Address(), Signature: sig, NetworkPassphrase: h.NetworkPassphrase, } diff --git a/exp/services/recoverysigner/internal/serve/account_sign_signing_address_test.go b/exp/services/recoverysigner/internal/serve/account_sign_signing_address_test.go index e9e22fc662..9a32d9fda9 100644 --- a/exp/services/recoverysigner/internal/serve/account_sign_signing_address_test.go +++ b/exp/services/recoverysigner/internal/serve/account_sign_signing_address_test.go @@ -27,9 +27,12 @@ import ( func TestAccountSign_signingAddressAuthenticatedButNotFound(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -70,9 +73,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedButNotPermitted(t *testin Address: "GBLOP46WEVXWO5N75TDX7GXLYFQE3XLDT5NQ2VYIBEWWEMSZWR3AUISZ", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -105,9 +111,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedButNotPermitted(t *testin func TestAccountSign_signingAddressAccountAuthenticatedButInvalidAddress(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -135,9 +144,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedButInvalidAddress(t *test func TestAccountSign_signingAddressAccountAuthenticatedButEmptyAddress(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -201,9 +213,12 @@ func TestAccountSign_signingAddressPhoneNumberAuthenticatedButNotPermitted(t *te }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -272,9 +287,12 @@ func TestAccountSign_signingAddressEmailAuthenticatedButNotPermitted(t *testing. }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -311,9 +329,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedButSigningAddressInvalid( Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -364,6 +385,70 @@ func TestAccountSign_signingAddressAccountAuthenticatedButSigningAddressInvalid( assert.JSONEq(t, wantBody, string(body)) } +func TestAccountSign_signingAddressAccountAuthenticatedOtherSignerSelected(t *testing.T) { + s := &account.DBStore{DB: dbtest.Open(t).Open()} + s.Add(account.Account{ + Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", + }) + h := accountSignHandler{ + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, + NetworkPassphrase: network.TestNetworkPassphrase, + } + + tx, err := txnbuild.NewTransaction( + txnbuild.TransactionParams{ + SourceAccount: &txnbuild.SimpleAccount{AccountID: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4"}, + IncrementSequenceNum: true, + Operations: []txnbuild.Operation{ + &txnbuild.SetOptions{ + Signer: &txnbuild.Signer{ + Address: "GD7CGJSJ5OBOU5KOP2UQDH3MPY75UTEY27HVV5XPSL2X6DJ2VGTOSXEU", + Weight: 20, + }, + }, + }, + BaseFee: txnbuild.MinBaseFee, + Timebounds: txnbuild.NewTimebounds(0, 1), + }, + ) + require.NoError(t, err) + txEnc, err := tx.Base64() + require.NoError(t, err) + t.Log("Tx:", txEnc) + + ctx := context.Background() + ctx = auth.NewContext(ctx, auth.Auth{Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4"}) + req := `{ + "transaction": "` + txEnc + `" +}` + r := httptest.NewRequest("POST", "/GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4/sign/GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", strings.NewReader(req)) + r = r.WithContext(ctx) + + w := httptest.NewRecorder() + m := chi.NewMux() + m.Post("/{address}/sign/{signing-address}", h.ServeHTTP) + m.ServeHTTP(w, r) + resp := w.Result() + + require.Equal(t, http.StatusOK, resp.StatusCode) + assert.Equal(t, "application/json; charset=utf-8", resp.Header.Get("Content-Type")) + + body, err := ioutil.ReadAll(resp.Body) + require.NoError(t, err) + + wantBody := `{ + "signer": "GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS", + "signature": "8Tew6rTol9me8H9u7ezJXg6SEqzOr7cwSf1y9+Vri275XEDH9xWtZ2klTX2uUSPy56otUoIySPqsV3dUFs2kDA==", + "network_passphrase": "Test SDF Network ; September 2015" +}` + assert.JSONEq(t, wantBody, string(body)) +} + // Test that when the source account of the transaction matches the account the // request is for, that the transaction is signed and a signature is returned. // The operation source account does not need to be set. @@ -373,9 +458,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedTxSourceAccountValid(t *t Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -437,9 +525,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedTxAndOpSourceAccountValid Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -501,9 +592,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedTxSourceAccountInvalid(t Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -561,9 +655,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedOpSourceAccountInvalid(t Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -622,9 +719,12 @@ func TestAccountSign_signingAddressAccountAuthenticatedTxAndOpSourceAccountInval Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -689,9 +789,12 @@ func TestAccountSign_signingAddressPhoneNumberOwnerAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -759,9 +862,12 @@ func TestAccountSign_signingAddressPhoneNumberOtherAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -829,9 +935,12 @@ func TestAccountSign_signingAddressEmailOwnerAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -899,9 +1008,12 @@ func TestAccountSign_signingAddressEmailOtherAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -961,9 +1073,12 @@ func TestAccountSign_signingAddressCannotParseTransaction(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -1000,9 +1115,12 @@ func TestAccountSign_signingAddressRejectsFeeBumpTx(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -1090,9 +1208,12 @@ func TestAccountSign_signingAddressValidContentTypeForm(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } diff --git a/exp/services/recoverysigner/internal/serve/account_sign_test.go b/exp/services/recoverysigner/internal/serve/account_sign_test.go index 2de021e99a..4b92dbd295 100644 --- a/exp/services/recoverysigner/internal/serve/account_sign_test.go +++ b/exp/services/recoverysigner/internal/serve/account_sign_test.go @@ -2,7 +2,6 @@ package serve import ( "context" - "github.com/stellar/go/xdr" "io/ioutil" "net/http" "net/http/httptest" @@ -10,6 +9,8 @@ import ( "strings" "testing" + "github.com/stellar/go/xdr" + "github.com/go-chi/chi" "github.com/stellar/go/exp/services/recoverysigner/internal/account" "github.com/stellar/go/exp/services/recoverysigner/internal/db/dbtest" @@ -26,9 +27,12 @@ import ( func TestAccountSign_authenticatedButNotFound(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -69,9 +73,12 @@ func TestAccountSign_accountAuthenticatedButNotPermitted(t *testing.T) { Address: "GBLOP46WEVXWO5N75TDX7GXLYFQE3XLDT5NQ2VYIBEWWEMSZWR3AUISZ", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -104,9 +111,12 @@ func TestAccountSign_accountAuthenticatedButNotPermitted(t *testing.T) { func TestAccountSign_accountAuthenticatedButInvalidAddress(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -134,9 +144,12 @@ func TestAccountSign_accountAuthenticatedButInvalidAddress(t *testing.T) { func TestAccountSign_accountAuthenticatedButEmptyAddress(t *testing.T) { s := &account.DBStore{DB: dbtest.Open(t).Open()} h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -200,9 +213,12 @@ func TestAccountSign_phoneNumberAuthenticatedButNotPermitted(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -271,9 +287,12 @@ func TestAccountSign_emailAuthenticatedButNotPermitted(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -312,9 +331,12 @@ func TestAccountSign_accountAuthenticatedTxSourceAccountValid(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -376,9 +398,12 @@ func TestAccountSign_accountAuthenticatedTxAndOpSourceAccountValid(t *testing.T) Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -440,9 +465,12 @@ func TestAccountSign_accountAuthenticatedTxSourceAccountInvalid(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -500,9 +528,12 @@ func TestAccountSign_accountAuthenticatedOpSourceAccountInvalid(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -561,9 +592,12 @@ func TestAccountSign_accountAuthenticatedTxAndOpSourceAccountInvalid(t *testing. Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -628,9 +662,12 @@ func TestAccountSign_phoneNumberOwnerAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -698,9 +735,12 @@ func TestAccountSign_phoneNumberOtherAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -768,9 +808,12 @@ func TestAccountSign_emailOwnerAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -838,9 +881,12 @@ func TestAccountSign_emailOtherAuthenticated(t *testing.T) { }, }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -900,9 +946,12 @@ func TestAccountSign_cannotParseTransaction(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -939,9 +988,12 @@ func TestAccountSign_rejectsFeeBumpTx(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } @@ -1029,9 +1081,12 @@ func TestAccountSign_validContentTypeForm(t *testing.T) { Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", }) h := accountSignHandler{ - Logger: supportlog.DefaultLogger, - AccountStore: s, - SigningKey: keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), + Logger: supportlog.DefaultLogger, + AccountStore: s, + SigningKeys: []*keypair.Full{ + keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H + keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS + }, NetworkPassphrase: network.TestNetworkPassphrase, } diff --git a/exp/services/recoverysigner/internal/serve/serve.go b/exp/services/recoverysigner/internal/serve/serve.go index 1ee0f9d570..e749b55cd3 100644 --- a/exp/services/recoverysigner/internal/serve/serve.go +++ b/exp/services/recoverysigner/internal/serve/serve.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "net/http" + "strings" firebaseauth "firebase.google.com/go/auth" "github.com/go-chi/chi" @@ -24,7 +25,7 @@ type Options struct { DatabaseURL string Port int NetworkPassphrase string - SigningKey string + SigningKeys string SEP10JWKS string SEP10JWTIssuer string FirebaseProjectID string @@ -63,7 +64,8 @@ func Serve(opts Options) { type handlerDeps struct { Logger *supportlog.Entry NetworkPassphrase string - SigningKey *keypair.Full + SigningKeys []*keypair.Full + SigningAddresses []*keypair.FromAddress AccountStore account.Store SEP10JWK jose.JSONWebKey SEP10JWTIssuer string @@ -75,14 +77,20 @@ func getHandlerDeps(opts Options) (handlerDeps, error) { // TODO: Replace this signing key with randomly generating a unique signing // key for each account so that it is not possible to identify which // accounts are recoverable via a recovery signer. - signingKey, err := keypair.ParseFull(opts.SigningKey) - if err != nil { - return handlerDeps{}, errors.Wrap(err, "parsing signing key seed") + signingKeys := []*keypair.Full{} + signingAddresses := []*keypair.FromAddress{} + for i, signingKeyStr := range strings.Split(opts.SigningKeys, ",") { + signingKey, err := keypair.ParseFull(signingKeyStr) + if err != nil { + return handlerDeps{}, errors.Wrap(err, "parsing signing key seed") + } + signingKeys = append(signingKeys, signingKey) + signingAddresses = append(signingAddresses, signingKey.FromAddress()) + opts.Logger.Info("Signing key ", i, ": ", signingKey.Address()) } - opts.Logger.Info("Signing key: ", signingKey.Address()) sep10JWKS := &jose.JSONWebKeySet{} - err = json.Unmarshal([]byte(opts.SEP10JWKS), sep10JWKS) + err := json.Unmarshal([]byte(opts.SEP10JWKS), sep10JWKS) if err != nil { return handlerDeps{}, errors.Wrap(err, "parsing SEP-10 JSON Web Key (JWK) Set") } @@ -136,7 +144,8 @@ func getHandlerDeps(opts Options) (handlerDeps, error) { deps := handlerDeps{ Logger: opts.Logger, NetworkPassphrase: opts.NetworkPassphrase, - SigningKey: signingKey, + SigningKeys: signingKeys, + SigningAddresses: signingAddresses, AccountStore: accountStore, SEP10JWK: sep10JWK, SEP10JWTIssuer: opts.SEP10JWTIssuer, @@ -158,34 +167,34 @@ func handler(deps handlerDeps) http.Handler { mux.Use(auth.SEP10Middleware(deps.SEP10JWTIssuer, deps.SEP10JWK)) mux.Use(auth.FirebaseMiddleware(auth.FirebaseTokenVerifierLive{AuthClient: deps.FirebaseAuthClient})) mux.Get("/", accountListHandler{ - Logger: deps.Logger, - SigningAddress: deps.SigningKey.FromAddress(), - AccountStore: deps.AccountStore, + Logger: deps.Logger, + SigningAddresses: deps.SigningAddresses, + AccountStore: deps.AccountStore, }.ServeHTTP) mux.Route("/{address}", func(mux chi.Router) { mux.Post("/", accountPostHandler{ - Logger: deps.Logger, - SigningAddress: deps.SigningKey.FromAddress(), - AccountStore: deps.AccountStore, + Logger: deps.Logger, + SigningAddresses: deps.SigningAddresses, + AccountStore: deps.AccountStore, }.ServeHTTP) mux.Put("/", accountPutHandler{ - Logger: deps.Logger, - SigningAddress: deps.SigningKey.FromAddress(), - AccountStore: deps.AccountStore, + Logger: deps.Logger, + SigningAddresses: deps.SigningAddresses, + AccountStore: deps.AccountStore, }.ServeHTTP) mux.Get("/", accountGetHandler{ - Logger: deps.Logger, - SigningAddress: deps.SigningKey.FromAddress(), - AccountStore: deps.AccountStore, + Logger: deps.Logger, + SigningAddresses: deps.SigningAddresses, + AccountStore: deps.AccountStore, }.ServeHTTP) mux.Delete("/", accountDeleteHandler{ - Logger: deps.Logger, - SigningAddress: deps.SigningKey.FromAddress(), - AccountStore: deps.AccountStore, + Logger: deps.Logger, + SigningAddresses: deps.SigningAddresses, + AccountStore: deps.AccountStore, }.ServeHTTP) signHandler := accountSignHandler{ Logger: deps.Logger, - SigningKey: deps.SigningKey, + SigningKeys: deps.SigningKeys, NetworkPassphrase: deps.NetworkPassphrase, AccountStore: deps.AccountStore, }