github.com/letsencrypt/boulder@v0.20251208.0/cmd/admin/overrides_toggle.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"flag"
     7  	"fmt"
     8  	"net/netip"
     9  	"strings"
    10  
    11  	"github.com/letsencrypt/boulder/identifier"
    12  	"github.com/letsencrypt/boulder/policy"
    13  	rl "github.com/letsencrypt/boulder/ratelimits"
    14  	sapb "github.com/letsencrypt/boulder/sa/proto"
    15  )
    16  
    17  type subcommandToggleOverride struct {
    18  	enabled          bool
    19  	limit            string
    20  	regId            int64
    21  	singleIdentifier string
    22  	setOfIdentifiers string
    23  	subscriberIP     string
    24  }
    25  
    26  func (*subcommandToggleOverride) Desc() string {
    27  	return "Enable or disable a rate limit override."
    28  }
    29  
    30  func (c *subcommandToggleOverride) Flags(f *flag.FlagSet) {
    31  	f.BoolVar(&c.enabled, "enabled", false, "true to enable, false to disable (default: false)")
    32  	f.StringVar(&c.limit, "limit", "", "ratelimit name (required)")
    33  	f.Int64Var(&c.regId, "regId", 0, "a single registration/account ID")
    34  	f.StringVar(&c.singleIdentifier, "singleIdentifier", "", "a single identifier (e.g. example.com or www.example.com or 55.66.77.88 or 2602:80a:6000::1)")
    35  	f.StringVar(&c.setOfIdentifiers, "setOfIdentifiers", "", "comma-separated list of unique identifiers (e.g. example.com,www.example.com,55.66.77.88,2602:80a:6000::1)")
    36  	f.StringVar(&c.subscriberIP, "subscriberIP", "", "a single IPv4/IPv6 address the subscriber uses for requests")
    37  }
    38  
    39  func (c *subcommandToggleOverride) Run(ctx context.Context, a *admin) error {
    40  	if c.limit == "" {
    41  		return errors.New("--limit is required")
    42  	}
    43  	name, ok := rl.StringToName[c.limit]
    44  	if !ok {
    45  		return fmt.Errorf("unknown limit name %q, must be one in %s", c.limit, rl.LimitNames)
    46  	}
    47  
    48  	var subscriberIP netip.Addr
    49  	var err error
    50  	if c.subscriberIP != "" {
    51  		subscriberIP, err = netip.ParseAddr(c.subscriberIP)
    52  		if err != nil {
    53  			return fmt.Errorf("invalid subscriberIP %q", err)
    54  		}
    55  		err := policy.ValidIP(c.subscriberIP)
    56  		if err != nil {
    57  			return fmt.Errorf("invalid subscriberIP %q: %w", c.subscriberIP, err)
    58  		}
    59  	}
    60  
    61  	singleIdent := identifier.FromString(c.singleIdentifier)
    62  	err = validateIdentifiers(singleIdent)
    63  	if err != nil {
    64  		return fmt.Errorf("invalid singleIdentifier: %w", err)
    65  	}
    66  
    67  	var setOfIdents identifier.ACMEIdentifiers
    68  	if c.setOfIdentifiers != "" {
    69  		setOfIdents = identifier.FromStringSlice(strings.Split(c.setOfIdentifiers, ","))
    70  		err := validateIdentifiers(setOfIdents...)
    71  		if err != nil {
    72  			return fmt.Errorf("invalid setOfIdentifiers: %w", err)
    73  		}
    74  	}
    75  
    76  	bucketKey, err := rl.BuildBucketKey(name, c.regId, singleIdent, setOfIdents, subscriberIP)
    77  	if err != nil {
    78  		return fmt.Errorf("building bucket key for limit %s: %s", name, err)
    79  	}
    80  
    81  	if c.enabled {
    82  		_, err := a.sac.EnableRateLimitOverride(ctx, &sapb.EnableRateLimitOverrideRequest{
    83  			LimitEnum: int64(name),
    84  			BucketKey: bucketKey,
    85  		})
    86  		if err != nil {
    87  			return fmt.Errorf("enabling override for limit %s key %q: %s", name, bucketKey, err)
    88  		}
    89  		a.log.Infof("Enabled override for limit %s key %q\n", name, bucketKey)
    90  		return nil
    91  	}
    92  
    93  	_, err = a.sac.DisableRateLimitOverride(ctx, &sapb.DisableRateLimitOverrideRequest{
    94  		LimitEnum: int64(name),
    95  		BucketKey: bucketKey,
    96  	})
    97  	if err != nil {
    98  		return fmt.Errorf("disabling override for limit %s key %q: %s", name, bucketKey, err)
    99  	}
   100  	a.log.Infof("Disabled override for limit %s key %q\n", name, bucketKey)
   101  	return nil
   102  }