Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

txnbuild: adds a 5 minute grace period to ReadChallengeTx MinTime constraint #3824

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions txnbuild/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ file. This project adheres to [Semantic Versioning](http://semver.org/).

* GenericTransaction, Transaction, and FeeBumpTransaction now implement
encoding.TextMarshaler and encoding.TextUnmarshaler.
* Adds 5-minute grace period to `transaction.ReadChallengeTx`'s minimum time bound constraint. ([#3824](https://github.com/stellar/go/pull/3824))

## [v7.1.1](https://github.com/stellar/go/releases/tag/horizonclient-v7.1.1) - 2021-06-25

Expand Down
4 changes: 3 additions & 1 deletion txnbuild/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -1098,8 +1098,10 @@ func ReadChallengeTx(challengeTx, serverAccountID, network, webAuthDomain string
if tx.Timebounds().MaxTime == TimeoutInfinite {
return tx, clientAccountID, matchedHomeDomain, errors.New("transaction requires non-infinite timebounds")
}
// Apply a grace period to the challenge MinTime to account for clock drift between the server and client
var gracePeriod int64 = 5 * 60 // seconds
currentTime := time.Now().UTC().Unix()
if currentTime < tx.Timebounds().MinTime || currentTime > tx.Timebounds().MaxTime {
if currentTime+gracePeriod < tx.Timebounds().MinTime || currentTime > tx.Timebounds().MaxTime {
return tx, clientAccountID, matchedHomeDomain, errors.Errorf("transaction is not within range of the specified timebounds (currentTime=%d, MinTime=%d, MaxTime=%d)",
currentTime, tx.Timebounds().MinTime, tx.Timebounds().MaxTime)
}
Expand Down
73 changes: 73 additions & 0 deletions txnbuild/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2023,6 +2023,79 @@ func TestReadChallengeTx_invalidTimeboundsOutsideRange(t *testing.T) {
assert.Regexp(t, "transaction is not within range of the specified timebounds", err.Error())
}

func TestReadChallengeTx_validTimeboundsWithGracePeriod(t *testing.T) {
serverKP := newKeypair0()
clientKP := newKeypair1()
txSource := NewSimpleAccount(serverKP.Address(), -1)
op := ManageData{
SourceAccount: clientKP.Address(),
Name: "testanchor.stellar.org auth",
Value: []byte(base64.StdEncoding.EncodeToString(make([]byte, 48))),
}
webAuthDomainOp := ManageData{
SourceAccount: serverKP.Address(),
Name: "web_auth_domain",
Value: []byte("testwebauth.stellar.org"),
}
unixNow := time.Now().UTC().Unix()
tx, err := NewTransaction(
TransactionParams{
SourceAccount: &txSource,
IncrementSequenceNum: true,
Operations: []Operation{&op, &webAuthDomainOp},
BaseFee: MinBaseFee,
Timebounds: NewTimebounds(unixNow+5*59, unixNow+60*60),
},
)
assert.NoError(t, err)

tx, err = tx.Sign(network.TestNetworkPassphrase, serverKP)
assert.NoError(t, err)
tx64, err := tx.Base64()
require.NoError(t, err)
readTx, readClientAccountID, _, err := ReadChallengeTx(tx64, serverKP.Address(), network.TestNetworkPassphrase, "testwebauth.stellar.org", []string{"testanchor.stellar.org"})
assert.Equal(t, tx, readTx)
assert.Equal(t, clientKP.Address(), readClientAccountID)
assert.NoError(t, err)
}

func TestReadChallengeTx_invalidTimeboundsWithGracePeriod(t *testing.T) {
serverKP := newKeypair0()
clientKP := newKeypair1()
txSource := NewSimpleAccount(serverKP.Address(), -1)
op := ManageData{
SourceAccount: clientKP.Address(),
Name: "testanchor.stellar.org auth",
Value: []byte(base64.StdEncoding.EncodeToString(make([]byte, 48))),
}
webAuthDomainOp := ManageData{
SourceAccount: serverKP.Address(),
Name: "web_auth_domain",
Value: []byte("testwebauth.stellar.org"),
}
unixNow := time.Now().UTC().Unix()
tx, err := NewTransaction(
TransactionParams{
SourceAccount: &txSource,
IncrementSequenceNum: true,
Operations: []Operation{&op, &webAuthDomainOp},
BaseFee: MinBaseFee,
Timebounds: NewTimebounds(unixNow+5*61, unixNow+60*60),
},
)
assert.NoError(t, err)

tx, err = tx.Sign(network.TestNetworkPassphrase, serverKP)
assert.NoError(t, err)
tx64, err := tx.Base64()
require.NoError(t, err)
readTx, readClientAccountID, _, err := ReadChallengeTx(tx64, serverKP.Address(), network.TestNetworkPassphrase, "testwebauth.stellar.org", []string{"testanchor.stellar.org"})
assert.Equal(t, tx, readTx)
assert.Equal(t, "", readClientAccountID)
assert.Error(t, err)
assert.Regexp(t, "transaction is not within range of the specified timebounds", err.Error())
}

func TestReadChallengeTx_invalidOperationWrongType(t *testing.T) {
serverKP := newKeypair0()
clientKP := newKeypair1()
Expand Down