github.com/letsencrypt/boulder@v0.20251208.0/ratelimits/names_test.go (about) 1 package ratelimits 2 3 import ( 4 "fmt" 5 "net/netip" 6 "strings" 7 "testing" 8 9 "github.com/letsencrypt/boulder/identifier" 10 "github.com/letsencrypt/boulder/test" 11 ) 12 13 func TestNameIsValid(t *testing.T) { 14 t.Parallel() 15 type args struct { 16 name Name 17 } 18 tests := []struct { 19 name string 20 args args 21 want bool 22 }{ 23 {name: "Unknown", args: args{name: Unknown}, want: false}, 24 {name: "9001", args: args{name: 9001}, want: false}, 25 {name: "NewRegistrationsPerIPAddress", args: args{name: NewRegistrationsPerIPAddress}, want: true}, 26 } 27 for _, tt := range tests { 28 t.Run(tt.name, func(t *testing.T) { 29 got := tt.args.name.isValid() 30 test.AssertEquals(t, tt.want, got) 31 }) 32 } 33 } 34 35 func TestValidateIdForName(t *testing.T) { 36 t.Parallel() 37 38 testCases := []struct { 39 limit Name 40 desc string 41 id string 42 err string 43 }{ 44 { 45 limit: NewRegistrationsPerIPAddress, 46 desc: "valid IPv4 address", 47 id: "64.112.117.1", 48 }, 49 { 50 limit: NewRegistrationsPerIPAddress, 51 desc: "reserved IPv4 address", 52 id: "10.0.0.1", 53 err: "in a reserved address block", 54 }, 55 { 56 limit: NewRegistrationsPerIPAddress, 57 desc: "valid IPv6 address", 58 id: "2602:80a:6000::42:42", 59 }, 60 { 61 limit: NewRegistrationsPerIPAddress, 62 desc: "IPv6 address in non-canonical form", 63 id: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", 64 err: "must be in canonical form", 65 }, 66 { 67 limit: NewRegistrationsPerIPAddress, 68 desc: "empty string", 69 id: "", 70 err: "must be an IP address", 71 }, 72 { 73 limit: NewRegistrationsPerIPAddress, 74 desc: "one space", 75 id: " ", 76 err: "must be an IP address", 77 }, 78 { 79 limit: NewRegistrationsPerIPAddress, 80 desc: "invalid IPv4 address", 81 id: "10.0.0.9000", 82 err: "must be an IP address", 83 }, 84 { 85 limit: NewRegistrationsPerIPAddress, 86 desc: "invalid IPv6 address", 87 id: "2001:0db8:85a3:0000:0000:8a2e:0370:7334:9000", 88 err: "must be an IP address", 89 }, 90 { 91 limit: NewRegistrationsPerIPv6Range, 92 desc: "valid IPv6 address range", 93 id: "2602:80a:6000::/48", 94 }, 95 { 96 limit: NewRegistrationsPerIPv6Range, 97 desc: "IPv6 address range in non-canonical form", 98 id: "2602:080a:6000::/48", 99 err: "must be in canonical form", 100 }, 101 { 102 limit: NewRegistrationsPerIPv6Range, 103 desc: "IPv6 address range with low bits set", 104 id: "2602:080a:6000::1/48", 105 err: "must be in canonical form", 106 }, 107 { 108 limit: NewRegistrationsPerIPv6Range, 109 desc: "invalid IPv6 CIDR range", 110 id: "2001:0db8:0000::/128", 111 err: "must be /48", 112 }, 113 { 114 limit: NewRegistrationsPerIPv6Range, 115 desc: "invalid IPv6 CIDR", 116 id: "2001:0db8:0000::/48/48", 117 err: "must be an IPv6 CIDR range", 118 }, 119 { 120 limit: NewRegistrationsPerIPv6Range, 121 desc: "IPv4 CIDR when we expect IPv6 CIDR range", 122 id: "10.0.0.0/16", 123 err: "must be /48", 124 }, 125 { 126 limit: NewRegistrationsPerIPv6Range, 127 desc: "IPv4 CIDR with invalid long mask", 128 id: "10.0.0.0/48", 129 err: "must be an IPv6 CIDR range", 130 }, 131 { 132 limit: NewOrdersPerAccount, 133 desc: "valid regId", 134 id: "1234567890", 135 }, 136 { 137 limit: NewOrdersPerAccount, 138 desc: "invalid regId", 139 id: "lol", 140 err: "must be an ACME registration Id", 141 }, 142 { 143 limit: FailedAuthorizationsPerDomainPerAccount, 144 desc: "transaction: valid regId and domain", 145 id: "12345:example.com", 146 }, 147 { 148 limit: FailedAuthorizationsPerDomainPerAccount, 149 desc: "transaction: invalid regId", 150 id: "12ea5:example.com", 151 err: "invalid regId", 152 }, 153 { 154 limit: FailedAuthorizationsPerDomainPerAccount, 155 desc: "transaction: invalid domain", 156 id: "12345:examplecom", 157 err: "name needs at least one dot", 158 }, 159 { 160 limit: FailedAuthorizationsPerDomainPerAccount, 161 desc: "override: valid regId", 162 id: "12345", 163 }, 164 { 165 limit: FailedAuthorizationsPerDomainPerAccount, 166 desc: "override: invalid regId", 167 id: "12ea5", 168 err: "invalid regId", 169 }, 170 { 171 limit: FailedAuthorizationsForPausingPerDomainPerAccount, 172 desc: "transaction: valid regId and domain", 173 id: "12345:example.com", 174 }, 175 { 176 limit: FailedAuthorizationsForPausingPerDomainPerAccount, 177 desc: "transaction: invalid regId", 178 id: "12ea5:example.com", 179 err: "invalid regId", 180 }, 181 { 182 limit: FailedAuthorizationsForPausingPerDomainPerAccount, 183 desc: "transaction: invalid domain", 184 id: "12345:examplecom", 185 err: "name needs at least one dot", 186 }, 187 { 188 limit: FailedAuthorizationsForPausingPerDomainPerAccount, 189 desc: "override: valid regId", 190 id: "12345", 191 }, 192 { 193 limit: FailedAuthorizationsForPausingPerDomainPerAccount, 194 desc: "override: invalid regId", 195 id: "12ea5", 196 err: "invalid regId", 197 }, 198 { 199 limit: CertificatesPerDomainPerAccount, 200 desc: "transaction: valid regId and domain", 201 id: "12345:example.com", 202 }, 203 { 204 limit: CertificatesPerDomainPerAccount, 205 desc: "transaction: invalid regId", 206 id: "12ea5:example.com", 207 err: "invalid regId", 208 }, 209 { 210 limit: CertificatesPerDomainPerAccount, 211 desc: "transaction: invalid domain", 212 id: "12345:examplecom", 213 err: "name needs at least one dot", 214 }, 215 { 216 limit: CertificatesPerDomainPerAccount, 217 desc: "override: valid regId", 218 id: "12345", 219 }, 220 { 221 limit: CertificatesPerDomainPerAccount, 222 desc: "override: invalid regId", 223 id: "12ea5", 224 err: "invalid regId", 225 }, 226 { 227 limit: CertificatesPerDomain, 228 desc: "valid domain", 229 id: "example.com", 230 }, 231 { 232 limit: CertificatesPerDomain, 233 desc: "valid IPv4 address", 234 id: "64.112.117.1", 235 }, 236 { 237 limit: CertificatesPerDomain, 238 desc: "valid IPv6 address", 239 id: "2602:80a:6000::", 240 }, 241 { 242 limit: CertificatesPerDomain, 243 desc: "IPv6 address with subnet", 244 id: "2602:80a:6000::/64", 245 err: "nor an IP address", 246 }, 247 { 248 limit: CertificatesPerDomain, 249 desc: "malformed domain", 250 id: "example:.com", 251 err: "name contains an invalid character", 252 }, 253 { 254 limit: CertificatesPerDomain, 255 desc: "empty domain", 256 id: "", 257 err: "Identifier value (name) is empty", 258 }, 259 { 260 limit: CertificatesPerFQDNSet, 261 desc: "valid fqdnSet containing a single domain", 262 id: "example.com", 263 }, 264 { 265 limit: CertificatesPerFQDNSet, 266 desc: "valid fqdnSet containing a single IPv4 address", 267 id: "64.112.117.1", 268 }, 269 { 270 limit: CertificatesPerFQDNSet, 271 desc: "valid fqdnSet containing a single IPv6 address", 272 id: "2602:80a:6000::1", 273 }, 274 { 275 limit: CertificatesPerFQDNSet, 276 desc: "valid fqdnSet containing multiple domains", 277 id: "example.com,example.org", 278 }, 279 { 280 limit: CertificatesPerFQDNSet, 281 desc: "valid fqdnSet containing multiple domains and IPs", 282 id: "2602:80a:6000::1,64.112.117.1,example.com,example.org", 283 }, 284 } 285 286 for _, tc := range testCases { 287 t.Run(fmt.Sprintf("%s/%s", tc.limit, tc.desc), func(t *testing.T) { 288 t.Parallel() 289 err := validateIdForName(tc.limit, tc.id) 290 if tc.err != "" { 291 test.AssertError(t, err, "should have failed") 292 test.AssertContains(t, err.Error(), tc.err) 293 } else { 294 test.AssertNotError(t, err, "should have succeeded") 295 } 296 }) 297 } 298 } 299 300 func TestBuildBucketKey(t *testing.T) { 301 t.Parallel() 302 303 tests := []struct { 304 name Name 305 desc string 306 regId int64 307 singleIdent identifier.ACMEIdentifier 308 setOfIdents identifier.ACMEIdentifiers 309 subscriberIP netip.Addr 310 expectErrContains string 311 outputTest func(t *testing.T, key string) 312 }{ 313 // NewRegistrationsPerIPAddress 314 { 315 name: NewRegistrationsPerIPAddress, 316 desc: "valid subscriber IPv4 address", 317 subscriberIP: netip.MustParseAddr("1.2.3.4"), 318 outputTest: func(t *testing.T, key string) { 319 test.AssertEquals(t, fmt.Sprintf("%d:1.2.3.4", NewRegistrationsPerIPAddress), key) 320 }, 321 }, 322 { 323 name: NewRegistrationsPerIPAddress, 324 desc: "valid subscriber IPv6 address", 325 subscriberIP: netip.MustParseAddr("2001:db8::1"), 326 outputTest: func(t *testing.T, key string) { 327 test.AssertEquals(t, fmt.Sprintf("%d:2001:db8::1", NewRegistrationsPerIPAddress), key) 328 }, 329 }, 330 // NewRegistrationsPerIPv6Range 331 { 332 name: NewRegistrationsPerIPv6Range, 333 desc: "valid subscriber IPv6 address", 334 subscriberIP: netip.MustParseAddr("2001:db8:abcd:12::1"), 335 outputTest: func(t *testing.T, key string) { 336 test.AssertEquals(t, fmt.Sprintf("%d:2001:db8:abcd::/48", NewRegistrationsPerIPv6Range), key) 337 }, 338 }, 339 { 340 name: NewRegistrationsPerIPv6Range, 341 desc: "subscriber IPv4 given for subscriber IPv6 range limit", 342 subscriberIP: netip.MustParseAddr("1.2.3.4"), 343 expectErrContains: "requires an IPv6 address", 344 }, 345 346 // NewOrdersPerAccount 347 { 348 name: NewOrdersPerAccount, 349 desc: "valid registration ID", 350 regId: 1337, 351 outputTest: func(t *testing.T, key string) { 352 test.AssertEquals(t, fmt.Sprintf("%d:1337", NewOrdersPerAccount), key) 353 }, 354 }, 355 { 356 name: NewOrdersPerAccount, 357 desc: "registration ID missing", 358 expectErrContains: "regId is required", 359 }, 360 361 // CertificatesPerDomain 362 { 363 name: CertificatesPerDomain, 364 desc: "DNS identifier to eTLD+1", 365 singleIdent: identifier.NewDNS("www.example.com"), 366 outputTest: func(t *testing.T, key string) { 367 test.AssertEquals(t, fmt.Sprintf("%d:example.com", CertificatesPerDomain), key) 368 }, 369 }, 370 { 371 name: CertificatesPerDomain, 372 desc: "valid IPv4 address used as identifier", 373 singleIdent: identifier.NewIP(netip.MustParseAddr("5.6.7.8")), 374 outputTest: func(t *testing.T, key string) { 375 test.AssertEquals(t, fmt.Sprintf("%d:5.6.7.8/32", CertificatesPerDomain), key) 376 }, 377 }, 378 { 379 name: CertificatesPerDomain, 380 desc: "valid IPv6 address used as identifier", 381 singleIdent: identifier.NewIP(netip.MustParseAddr("2001:db8::1")), 382 outputTest: func(t *testing.T, key string) { 383 test.AssertEquals(t, fmt.Sprintf("%d:2001:db8::/64", CertificatesPerDomain), key) 384 }, 385 }, 386 { 387 name: CertificatesPerDomain, 388 desc: "identifier missing", 389 expectErrContains: "singleIdent is required", 390 }, 391 392 // CertificatesPerFQDNSet 393 { 394 name: CertificatesPerFQDNSet, 395 desc: "multiple valid DNS identifiers", 396 setOfIdents: identifier.NewDNSSlice([]string{"example.com", "example.org"}), 397 outputTest: func(t *testing.T, key string) { 398 if !strings.HasPrefix(key, fmt.Sprintf("%d:", CertificatesPerFQDNSet)) { 399 t.Errorf("expected key to start with %d: got %s", CertificatesPerFQDNSet, key) 400 } 401 }, 402 }, 403 { 404 name: CertificatesPerFQDNSet, 405 desc: "multiple valid DNS and IP identifiers", 406 setOfIdents: identifier.ACMEIdentifiers{identifier.NewDNS("example.net"), identifier.NewIP(netip.MustParseAddr("5.6.7.8")), identifier.NewIP(netip.MustParseAddr("2001:db8::1"))}, 407 outputTest: func(t *testing.T, key string) { 408 if !strings.HasPrefix(key, fmt.Sprintf("%d:", CertificatesPerFQDNSet)) { 409 t.Errorf("expected key to start with %d: got %s", CertificatesPerFQDNSet, key) 410 } 411 }, 412 }, 413 { 414 name: CertificatesPerFQDNSet, 415 desc: "identifiers missing", 416 expectErrContains: "setOfIdents is required", 417 }, 418 419 // CertificatesPerDomainPerAccount 420 { 421 name: CertificatesPerDomainPerAccount, 422 desc: "only registration ID", 423 regId: 1337, 424 outputTest: func(t *testing.T, key string) { 425 test.AssertEquals(t, fmt.Sprintf("%d:1337", CertificatesPerDomainPerAccount), key) 426 }, 427 }, 428 { 429 name: CertificatesPerDomainPerAccount, 430 desc: "registration ID and single DNS identifier provided", 431 regId: 1337, 432 singleIdent: identifier.NewDNS("example.com"), 433 outputTest: func(t *testing.T, key string) { 434 test.AssertEquals(t, fmt.Sprintf("%d:1337:example.com", CertificatesPerDomainPerAccount), key) 435 }, 436 }, 437 { 438 name: CertificatesPerDomainPerAccount, 439 desc: "single DNS identifier provided without registration ID", 440 singleIdent: identifier.NewDNS("example.com"), 441 expectErrContains: "regId is required", 442 }, 443 444 // FailedAuthorizationsPerDomainPerAccount 445 { 446 name: FailedAuthorizationsPerDomainPerAccount, 447 desc: "registration ID and single DNS identifier", 448 regId: 1337, 449 singleIdent: identifier.NewDNS("example.com"), 450 outputTest: func(t *testing.T, key string) { 451 test.AssertEquals(t, fmt.Sprintf("%d:1337:example.com", FailedAuthorizationsPerDomainPerAccount), key) 452 }, 453 }, 454 { 455 name: FailedAuthorizationsPerDomainPerAccount, 456 desc: "only registration ID", 457 regId: 1337, 458 outputTest: func(t *testing.T, key string) { 459 test.AssertEquals(t, fmt.Sprintf("%d:1337", FailedAuthorizationsPerDomainPerAccount), key) 460 }, 461 }, 462 463 // FailedAuthorizationsForPausingPerDomainPerAccount 464 { 465 name: FailedAuthorizationsForPausingPerDomainPerAccount, 466 desc: "registration ID and single DNS identifier", 467 regId: 1337, 468 singleIdent: identifier.NewDNS("example.com"), 469 outputTest: func(t *testing.T, key string) { 470 test.AssertEquals(t, fmt.Sprintf("%d:1337:example.com", FailedAuthorizationsForPausingPerDomainPerAccount), key) 471 }, 472 }, 473 { 474 name: FailedAuthorizationsForPausingPerDomainPerAccount, 475 desc: "only registration ID", 476 regId: 1337, 477 outputTest: func(t *testing.T, key string) { 478 test.AssertEquals(t, fmt.Sprintf("%d:1337", FailedAuthorizationsForPausingPerDomainPerAccount), key) 479 }, 480 }, 481 } 482 483 for _, tc := range tests { 484 t.Run(fmt.Sprintf("%s/%s", tc.name, tc.desc), func(t *testing.T) { 485 t.Parallel() 486 487 key, err := BuildBucketKey(tc.name, tc.regId, tc.singleIdent, tc.setOfIdents, tc.subscriberIP) 488 if tc.expectErrContains != "" { 489 test.AssertError(t, err, "expected error") 490 test.AssertContains(t, err.Error(), tc.expectErrContains) 491 return 492 } 493 test.AssertNotError(t, err, "unexpected error") 494 tc.outputTest(t, key) 495 }) 496 } 497 }