forked from stellar/go
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
exp/services/recoverysigner: allow recoverysigner to sign transaction…
…s with operations containing a whitelisted source account (stellar#3227) ### What Allow recoverysigner to sign transactions with operations containing another source account if it's listed in the config variables. ### Why The validation below prevents recoverysigner from signing CAP-33 `BeginSponsoringFutureReserves` operations https://github.com/stellar/go/blob/c2c77fb6066b7a06a0c31835039926ae7d9d3970/exp/services/recoverysigner/internal/serve/account_sign.go#L132-L138 For a `BeginSponsoringFutureReserves` operation we shouldn't be validating its account address but the sponsored id.
- Loading branch information
1 parent
b361462
commit 15de5ff
Showing
5 changed files
with
218 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package serve | |
|
||
import ( | ||
"context" | ||
"fmt" | ||
"io/ioutil" | ||
"net/http" | ||
"net/http/httptest" | ||
|
@@ -985,6 +986,159 @@ func TestAccountSign_signingAddressEmailOwnerAuthenticated(t *testing.T) { | |
assert.JSONEq(t, wantBody, string(body)) | ||
} | ||
|
||
// Test that when the source account of the operation is listed in the allowed | ||
// source accounts a successful response is returned. | ||
func TestAccountSign_signingAddressEmailOwnerAuthenticatedOpSourceAccountIsAllowedSourceAccount(t *testing.T) { | ||
s := &account.DBStore{DB: dbtest.Open(t).Open()} | ||
s.Add(account.Account{ | ||
Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", | ||
Identities: []account.Identity{ | ||
{ | ||
Role: "sender", | ||
AuthMethods: []account.AuthMethod{ | ||
{Type: account.AuthMethodTypeEmail, Value: "[email protected]"}, | ||
}, | ||
}, | ||
}, | ||
}) | ||
h := accountSignHandler{ | ||
Logger: supportlog.DefaultLogger, | ||
AccountStore: s, | ||
SigningKeys: []*keypair.Full{ | ||
keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H | ||
keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS | ||
}, | ||
NetworkPassphrase: network.TestNetworkPassphrase, | ||
AllowedSourceAccounts: []*keypair.FromAddress{ | ||
keypair.MustParseAddress("GDR3RJVOHYR5A4RSLZ7D3GOSTPBGD2FY7KJD7ZB7363ROOQHWYDVVULS"), | ||
}, | ||
} | ||
|
||
tx, err := txnbuild.NewTransaction( | ||
txnbuild.TransactionParams{ | ||
SourceAccount: &txnbuild.SimpleAccount{AccountID: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4"}, | ||
IncrementSequenceNum: true, | ||
Operations: []txnbuild.Operation{ | ||
&txnbuild.BeginSponsoringFutureReserves{ | ||
SponsoredID: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", | ||
SourceAccount: &txnbuild.SimpleAccount{AccountID: "GDR3RJVOHYR5A4RSLZ7D3GOSTPBGD2FY7KJD7ZB7363ROOQHWYDVVULS"}, | ||
}, | ||
&txnbuild.SetOptions{ | ||
Signer: &txnbuild.Signer{ | ||
Address: "GD7CGJSJ5OBOU5KOP2UQDH3MPY75UTEY27HVV5XPSL2X6DJ2VGTOSXEU", | ||
Weight: 20, | ||
}, | ||
}, | ||
&txnbuild.EndSponsoringFutureReserves{}, | ||
}, | ||
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{Email: "[email protected]"}) | ||
req := fmt.Sprintf(`{"transaction": "%s"}`, txEnc) | ||
r := httptest.NewRequest("POST", "/GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4/sign/GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H", 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 := `{ | ||
"signature": "Tpl/yZoKkahakaX4fSrdIeBLL2oi4uKegs5bLXFj5fG6Rcfe2D4EeSHcjJmmO2ZscuY8pX8+YPo70AvCtfw9Ag==", | ||
"network_passphrase": "Test SDF Network ; September 2015" | ||
}` | ||
assert.JSONEq(t, wantBody, string(body)) | ||
} | ||
|
||
// Test that when the source account of the operation is not the account sign | ||
// the request is calling sign on a bad request response is returned. | ||
func TestAccountSign_signingAddressEmailOwnerAuthenticatedOpSourceAccountInvalid(t *testing.T) { | ||
s := &account.DBStore{DB: dbtest.Open(t).Open()} | ||
s.Add(account.Account{ | ||
Address: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", | ||
Identities: []account.Identity{ | ||
{ | ||
Role: "sender", | ||
AuthMethods: []account.AuthMethod{ | ||
{Type: account.AuthMethodTypeEmail, Value: "[email protected]"}, | ||
}, | ||
}, | ||
}, | ||
}) | ||
h := accountSignHandler{ | ||
Logger: supportlog.DefaultLogger, | ||
AccountStore: s, | ||
SigningKeys: []*keypair.Full{ | ||
keypair.MustParseFull("SBIB72S6JMTGJRC6LMKLC5XMHZ2IOHZSZH4SASTN47LECEEJ7QEB6EYK"), // GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H | ||
keypair.MustParseFull("SBJGZKZ7LU2FQNEFBUOBW4LHCA5BOZCABIJTR7BQIFWQ3P763ZW7MYDD"), // GAPE22DOMALCH42VOR4S3HN6KIZZ643G7D3GNTYF4YOWWXP6UVRAF5JS | ||
}, | ||
NetworkPassphrase: network.TestNetworkPassphrase, | ||
AllowedSourceAccounts: nil, | ||
} | ||
|
||
tx, err := txnbuild.NewTransaction( | ||
txnbuild.TransactionParams{ | ||
SourceAccount: &txnbuild.SimpleAccount{AccountID: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4"}, | ||
IncrementSequenceNum: true, | ||
Operations: []txnbuild.Operation{ | ||
&txnbuild.BeginSponsoringFutureReserves{ | ||
SponsoredID: "GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4", | ||
SourceAccount: &txnbuild.SimpleAccount{AccountID: "GDR3RJVOHYR5A4RSLZ7D3GOSTPBGD2FY7KJD7ZB7363ROOQHWYDVVULS"}, | ||
}, | ||
&txnbuild.SetOptions{ | ||
Signer: &txnbuild.Signer{ | ||
Address: "GD7CGJSJ5OBOU5KOP2UQDH3MPY75UTEY27HVV5XPSL2X6DJ2VGTOSXEU", | ||
Weight: 20, | ||
}, | ||
}, | ||
&txnbuild.EndSponsoringFutureReserves{}, | ||
}, | ||
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{Email: "[email protected]"}) | ||
req := fmt.Sprintf(`{"transaction": "%s"}`, txEnc) | ||
r := httptest.NewRequest("POST", "/GA6HNE7O2N2IXIOBZNZ4IPTS2P6DSAJJF5GD5PDLH5GYOZ6WMPSKCXD4/sign/GBOG4KF66M4AFRBUHOTJQJRO7BGGFCSGIICTI5BHXHKXCWV2C67QRN5H", 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.StatusBadRequest, 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 := `{"error": "The request was invalid in some way."}` | ||
assert.JSONEq(t, wantBody, string(body)) | ||
} | ||
|
||
// Test that when authenticated with a email signing is possible. | ||
func TestAccountSign_signingAddressEmailOtherAuthenticated(t *testing.T) { | ||
s := &account.DBStore{DB: dbtest.Open(t).Open()} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters