228 lines
10 KiB
Go
228 lines
10 KiB
Go
package ratelimits
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/letsencrypt/boulder/config"
|
|
"github.com/letsencrypt/boulder/test"
|
|
)
|
|
|
|
func TestNewTransactionBuilderFromFiles_WithBadLimitsPath(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := NewTransactionBuilderFromFiles("testdata/does-not-exist.yml", "")
|
|
test.AssertError(t, err, "should error")
|
|
|
|
_, err = NewTransactionBuilderFromFiles("testdata/defaults.yml", "testdata/does-not-exist.yml")
|
|
test.AssertError(t, err, "should error")
|
|
}
|
|
|
|
func sortTransactions(txns []Transaction) []Transaction {
|
|
sort.Slice(txns, func(i, j int) bool {
|
|
return txns[i].bucketKey < txns[j].bucketKey
|
|
})
|
|
return txns
|
|
}
|
|
|
|
func TestNewRegistrationsPerIPAddressTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// A check-and-spend transaction for the global limit.
|
|
txn, err := tb.registrationsPerIPAddressTransaction(net.ParseIP("1.2.3.4"))
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
test.AssertEquals(t, txn.bucketKey, "1:1.2.3.4")
|
|
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
|
|
}
|
|
|
|
func TestNewRegistrationsPerIPv6AddressTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// A check-and-spend transaction for the global limit.
|
|
txn, err := tb.registrationsPerIPv6RangeTransaction(net.ParseIP("2001:db8::1"))
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
test.AssertEquals(t, txn.bucketKey, "2:2001:db8::/48")
|
|
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
|
|
}
|
|
|
|
func TestNewOrdersPerAccountTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// A check-and-spend transaction for the global limit.
|
|
txn, err := tb.ordersPerAccountTransaction(123456789)
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
test.AssertEquals(t, txn.bucketKey, "3:123456789")
|
|
test.Assert(t, txn.check && txn.spend, "should be check-and-spend")
|
|
}
|
|
|
|
func TestFailedAuthorizationsPerDomainPerAccountTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "testdata/working_override_13371338.yml")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// A check-only transaction for the default per-account limit.
|
|
txns, err := tb.FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions(123456789, []string{"so.many.labels.here.example.com"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
test.AssertEquals(t, len(txns), 1)
|
|
test.AssertEquals(t, txns[0].bucketKey, "4:123456789:so.many.labels.here.example.com")
|
|
test.Assert(t, txns[0].checkOnly(), "should be check-only")
|
|
test.Assert(t, !txns[0].limit.isOverride, "should not be an override")
|
|
|
|
// A spend-only transaction for the default per-account limit.
|
|
txn, err := tb.FailedAuthorizationsPerDomainPerAccountSpendOnlyTransaction(123456789, "so.many.labels.here.example.com")
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
test.AssertEquals(t, txn.bucketKey, "4:123456789:so.many.labels.here.example.com")
|
|
test.Assert(t, txn.spendOnly(), "should be spend-only")
|
|
test.Assert(t, !txn.limit.isOverride, "should not be an override")
|
|
|
|
// A check-only transaction for the per-account limit override.
|
|
txns, err = tb.FailedAuthorizationsPerDomainPerAccountCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
test.AssertEquals(t, len(txns), 1)
|
|
test.AssertEquals(t, txns[0].bucketKey, "4:13371338:so.many.labels.here.example.com")
|
|
test.Assert(t, txns[0].checkOnly(), "should be check-only")
|
|
test.Assert(t, txns[0].limit.isOverride, "should be an override")
|
|
|
|
// A spend-only transaction for the per-account limit override.
|
|
txn, err = tb.FailedAuthorizationsPerDomainPerAccountSpendOnlyTransaction(13371338, "so.many.labels.here.example.com")
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
test.AssertEquals(t, txn.bucketKey, "4:13371338:so.many.labels.here.example.com")
|
|
test.Assert(t, txn.spendOnly(), "should be spend-only")
|
|
test.Assert(t, txn.limit.isOverride, "should be an override")
|
|
}
|
|
|
|
func TestFailedAuthorizationsForPausingPerDomainPerAccountTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "testdata/working_override_13371338.yml")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// A transaction for the per-account limit override.
|
|
txn, err := tb.FailedAuthorizationsForPausingPerDomainPerAccountTransaction(13371338, "so.many.labels.here.example.com")
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
test.AssertEquals(t, txn.bucketKey, "8:13371338:so.many.labels.here.example.com")
|
|
test.Assert(t, txn.check && txn.spend, "should be check and spend")
|
|
test.Assert(t, txn.limit.isOverride, "should be an override")
|
|
}
|
|
|
|
func TestCertificatesPerDomainTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// One check-only transaction for the global limit.
|
|
txns, err := tb.certificatesPerDomainCheckOnlyTransactions(123456789, []string{"so.many.labels.here.example.com"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
test.AssertEquals(t, len(txns), 1)
|
|
test.AssertEquals(t, txns[0].bucketKey, "5:example.com")
|
|
test.Assert(t, txns[0].checkOnly(), "should be check-only")
|
|
|
|
// One spend-only transaction for the global limit.
|
|
txns, err = tb.CertificatesPerDomainSpendOnlyTransactions(123456789, []string{"so.many.labels.here.example.com"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
test.AssertEquals(t, len(txns), 1)
|
|
test.AssertEquals(t, txns[0].bucketKey, "5:example.com")
|
|
test.Assert(t, txns[0].spendOnly(), "should be spend-only")
|
|
}
|
|
|
|
func TestCertificatesPerDomainPerAccountTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "testdata/working_override_13371338.yml")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// We only expect a single check-only transaction for the per-account limit
|
|
// override. We can safely ignore the global limit when an override is
|
|
// present.
|
|
txns, err := tb.certificatesPerDomainCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
test.AssertEquals(t, len(txns), 1)
|
|
test.AssertEquals(t, txns[0].bucketKey, "6:13371338:example.com")
|
|
test.Assert(t, txns[0].checkOnly(), "should be check-only")
|
|
test.Assert(t, txns[0].limit.isOverride, "should be an override")
|
|
|
|
// Same as above, but with multiple example.com domains.
|
|
txns, err = tb.certificatesPerDomainCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com", "z.example.com"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
test.AssertEquals(t, len(txns), 1)
|
|
test.AssertEquals(t, txns[0].bucketKey, "6:13371338:example.com")
|
|
test.Assert(t, txns[0].checkOnly(), "should be check-only")
|
|
test.Assert(t, txns[0].limit.isOverride, "should be an override")
|
|
|
|
// Same as above, but with different domains.
|
|
txns, err = tb.certificatesPerDomainCheckOnlyTransactions(13371338, []string{"so.many.labels.here.example.com", "z.example.net"})
|
|
test.AssertNotError(t, err, "creating transactions")
|
|
txns = sortTransactions(txns)
|
|
test.AssertEquals(t, len(txns), 2)
|
|
test.AssertEquals(t, txns[0].bucketKey, "6:13371338:example.com")
|
|
test.Assert(t, txns[0].checkOnly(), "should be check-only")
|
|
test.Assert(t, txns[0].limit.isOverride, "should be an override")
|
|
test.AssertEquals(t, txns[1].bucketKey, "6:13371338:example.net")
|
|
test.Assert(t, txns[1].checkOnly(), "should be check-only")
|
|
test.Assert(t, txns[1].limit.isOverride, "should be an override")
|
|
|
|
// Two spend-only transactions, one for the global limit and one for the
|
|
// per-account limit override.
|
|
txns, err = tb.CertificatesPerDomainSpendOnlyTransactions(13371338, []string{"so.many.labels.here.example.com"})
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
test.AssertEquals(t, len(txns), 2)
|
|
txns = sortTransactions(txns)
|
|
test.AssertEquals(t, txns[0].bucketKey, "5:example.com")
|
|
test.Assert(t, txns[0].spendOnly(), "should be spend-only")
|
|
test.Assert(t, !txns[0].limit.isOverride, "should not be an override")
|
|
|
|
test.AssertEquals(t, txns[1].bucketKey, "6:13371338:example.com")
|
|
test.Assert(t, txns[1].spendOnly(), "should be spend-only")
|
|
test.Assert(t, txns[1].limit.isOverride, "should be an override")
|
|
}
|
|
|
|
func TestCertificatesPerFQDNSetTransactions(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tb, err := NewTransactionBuilderFromFiles("../test/config-next/wfe2-ratelimit-defaults.yml", "")
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
// A single check-only transaction for the global limit.
|
|
txn, err := tb.certificatesPerFQDNSetCheckOnlyTransaction([]string{"example.com", "example.net", "example.org"})
|
|
test.AssertNotError(t, err, "creating transaction")
|
|
namesHash := fmt.Sprintf("%x", hashNames([]string{"example.com", "example.net", "example.org"}))
|
|
test.AssertEquals(t, txn.bucketKey, "7:"+namesHash)
|
|
test.Assert(t, txn.checkOnly(), "should be check-only")
|
|
test.Assert(t, !txn.limit.isOverride, "should not be an override")
|
|
}
|
|
|
|
func TestNewTransactionBuilder(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
expectedBurst := int64(10000)
|
|
expectedCount := int64(10000)
|
|
expectedPeriod := config.Duration{Duration: time.Hour * 168}
|
|
|
|
tb, err := NewTransactionBuilder(LimitConfigs{
|
|
NewRegistrationsPerIPAddress.String(): &LimitConfig{
|
|
Burst: expectedBurst,
|
|
Count: expectedCount,
|
|
Period: expectedPeriod},
|
|
})
|
|
test.AssertNotError(t, err, "creating TransactionBuilder")
|
|
|
|
newRegDefault, ok := tb.limitRegistry.defaults[NewRegistrationsPerIPAddress.EnumString()]
|
|
test.Assert(t, ok, "NewRegistrationsPerIPAddress was not populated in registry")
|
|
test.AssertEquals(t, newRegDefault.burst, expectedBurst)
|
|
test.AssertEquals(t, newRegDefault.count, expectedCount)
|
|
test.AssertEquals(t, newRegDefault.period, expectedPeriod)
|
|
}
|