diff --git a/.gitignore b/.gitignore index 502a89ea7a6..c4cb181db06 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,7 @@ test/coverage test/secrets/badkeyrevoker_dburl test/secrets/cert_checker_dburl test/secrets/incidents_dburl +test/secrets/admin_dburl test/secrets/revoker_dburl test/secrets/sa_dburl test/secrets/sa_ro_dburl diff --git a/cmd/admin/admin.go b/cmd/admin/admin.go index 8816546537d..3416653e49c 100644 --- a/cmd/admin/admin.go +++ b/cmd/admin/admin.go @@ -23,6 +23,7 @@ type admin struct { rac adminRAClient sac adminSAClient saroc sapb.StorageAuthorityReadOnlyClient + saac saAdminClient clk clock.Clock log blog.Logger @@ -43,6 +44,15 @@ type adminSAClient interface { UnpauseAccount(context.Context, *sapb.RegistrationID, ...grpc.CallOption) (*sapb.Count, error) } +// saAdminClient defines the StorageAuthorityAdmin methods that the admin tool +// relies on. This is a separate gRPC service so that admin authorization for +// admin-only methods does not also grant the broader StorageAuthority surface. +type saAdminClient interface { + AddSerialsToIncident(context.Context, ...grpc.CallOption) (grpc.ClientStreamingClient[sapb.AddSerialsToIncidentRequest, emptypb.Empty], error) + CreateIncident(context.Context, *sapb.CreateIncidentRequest, ...grpc.CallOption) (*sapb.Incident, error) + UpdateIncident(context.Context, *sapb.UpdateIncidentRequest, ...grpc.CallOption) (*emptypb.Empty, error) +} + // newAdmin constructs a new admin object on the heap and returns a pointer to // it. func newAdmin(configFile string, dryRun bool) (*admin, error) { @@ -84,13 +94,16 @@ func newAdmin(configFile string, dryRun bool) (*admin, error) { saroc := sapb.NewStorageAuthorityReadOnlyClient(saConn) var sac adminSAClient = dryRunSAC{log: logger} + var saAdmin saAdminClient = dryRunSAAdmin{log: logger} if !dryRun { sac = sapb.NewStorageAuthorityClient(saConn) + saAdmin = sapb.NewStorageAuthorityAdminClient(saConn) } return &admin{ rac: rac, sac: sac, + saac: saAdmin, saroc: saroc, clk: clk, log: logger, diff --git a/cmd/admin/dryrun.go b/cmd/admin/dryrun.go index 13c15f062e4..c2446add344 100644 --- a/cmd/admin/dryrun.go +++ b/cmd/admin/dryrun.go @@ -62,3 +62,41 @@ func (d dryRunSAC) UnpauseAccount(_ context.Context, req *sapb.RegistrationID, _ d.log.Infof("dry-run: Unpause account %d", req.Id) return &sapb.Count{Count: 1}, nil } + +type dryRunSAAdmin struct { + log blog.Logger +} + +var _ saAdminClient = (*dryRunSAAdmin)(nil) + +func (d dryRunSAAdmin) CreateIncident(_ context.Context, req *sapb.CreateIncidentRequest, _ ...grpc.CallOption) (*sapb.Incident, error) { + d.log.Infof("dry-run: Create incident %q (url=%q, renewBy=%s)", req.SerialTable, req.Url, req.RenewBy.AsTime()) + return &sapb.Incident{SerialTable: req.SerialTable, Url: req.Url, RenewBy: req.RenewBy, Enabled: false}, nil +} + +func (d dryRunSAAdmin) UpdateIncident(_ context.Context, req *sapb.UpdateIncidentRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) { + d.log.Infof("dry-run: Update incident %q url=%q renewBy=%v enabled=%v", req.SerialTable, req.Url, req.RenewBy, req.Enabled) + return &emptypb.Empty{}, nil +} + +func (d dryRunSAAdmin) AddSerialsToIncident(_ context.Context, _ ...grpc.CallOption) (grpc.ClientStreamingClient[sapb.AddSerialsToIncidentRequest, emptypb.Empty], error) { + return &dryRunAddSerialsStream{log: d.log}, nil +} + +type dryRunAddSerialsStream struct { + grpc.ClientStream + log blog.Logger + incident string + count int +} + +func (d *dryRunAddSerialsStream) Send(req *sapb.AddSerialsToIncidentRequest) error { + d.incident = req.SerialTable + d.count += len(req.Serial) + return nil +} + +func (d *dryRunAddSerialsStream) CloseAndRecv() (*emptypb.Empty, error) { + d.log.Infof("dry-run: Add %d serials to incident %q", d.count, d.incident) + return &emptypb.Empty{}, nil +} diff --git a/cmd/admin/incident.go b/cmd/admin/incident.go new file mode 100644 index 00000000000..2f6a5c5ad34 --- /dev/null +++ b/cmd/admin/incident.go @@ -0,0 +1,272 @@ +package main + +import ( + "bufio" + "context" + "errors" + "flag" + "fmt" + "os" + "strconv" + "strings" + "sync/atomic" + "text/tabwriter" + "time" + + "golang.org/x/sync/errgroup" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/letsencrypt/boulder/sa" + sapb "github.com/letsencrypt/boulder/sa/proto" +) + +type subcommandCreateIncident struct { + incident string + url string + renewBy string +} + +var _ subcommand = (*subcommandCreateIncident)(nil) + +func (*subcommandCreateIncident) Desc() string { + return "Create a new incident table and metadata row (starts disabled)." +} + +func (s *subcommandCreateIncident) Flags(f *flag.FlagSet) { + f.StringVar(&s.incident, "incident", "", "Incident name (must start with 'incident_'; required)") + f.StringVar(&s.url, "url", "", "URL describing the incident (required)") + f.StringVar(&s.renewBy, "renew-by", "", "RFC3339 timestamp by which affected certs should be renewed (required)") +} + +func (s *subcommandCreateIncident) Run(ctx context.Context, a *admin) error { + if s.incident == "" || s.url == "" || s.renewBy == "" { + return errors.New("-incident, -url, and -renew-by are all required") + } + if !sa.ValidIncidentTableRegexp.MatchString(s.incident) { + return fmt.Errorf("invalid incident %q (must match %s)", s.incident, sa.ValidIncidentTableRegexp) + } + renewBy, err := time.Parse(time.RFC3339, s.renewBy) + if err != nil { + return fmt.Errorf("parsing -renew-by as RFC3339: %w", err) + } + + inc, err := a.saac.CreateIncident(ctx, &sapb.CreateIncidentRequest{ + SerialTable: s.incident, + Url: s.url, + RenewBy: timestamppb.New(renewBy), + }) + if err != nil { + return fmt.Errorf("creating incident: %w", err) + } + a.log.Infof("Created incident %q url=%q renewBy=%s enabled=%t", + inc.SerialTable, inc.Url, inc.RenewBy.AsTime(), inc.Enabled) + return nil +} + +type subcommandListIncidents struct{} + +var _ subcommand = (*subcommandListIncidents)(nil) + +func (*subcommandListIncidents) Desc() string { + return "List all incidents and their enabled status." +} + +func (*subcommandListIncidents) Flags(_ *flag.FlagSet) {} + +func (*subcommandListIncidents) Run(ctx context.Context, a *admin) error { + resp, err := a.saroc.ListIncidents(ctx, &emptypb.Empty{}) + if err != nil { + return fmt.Errorf("listing incidents: %w", err) + } + w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) + fmt.Fprintln(w, "NAME\tENABLED\tRENEW BY\tURL") + for _, inc := range resp.Incidents { + fmt.Fprintf(w, "%s\t%t\t%s\t%s\n", + inc.SerialTable, inc.Enabled, + inc.RenewBy.AsTime().Format(time.RFC3339), inc.Url) + } + return w.Flush() +} + +type subcommandUpdateIncident struct { + incident string + url string + renewBy string + enable string +} + +var _ subcommand = (*subcommandUpdateIncident)(nil) + +func (*subcommandUpdateIncident) Desc() string { + return "Update the url, renew-by, and/or enable fields of an existing incident." +} + +func (s *subcommandUpdateIncident) Flags(f *flag.FlagSet) { + f.StringVar(&s.incident, "incident", "", "Incident name (must start with 'incident_'; required)") + f.StringVar(&s.url, "url", "", "URL describing the incident (leave unset to keep the existing value)") + f.StringVar(&s.renewBy, "renew-by", "", "RFC3339 timestamp by which affected certs should be renewed (leave unset to keep the existing value)") + f.StringVar(&s.enable, "enable", "", `"true" to enable, "false" to disable (leave unset to keep the existing value)`) +} + +func (s *subcommandUpdateIncident) Run(ctx context.Context, a *admin) error { + if s.incident == "" { + return errors.New("-incident is required") + } + if !sa.ValidIncidentTableRegexp.MatchString(s.incident) { + return fmt.Errorf("invalid incident %q (must match %s)", s.incident, sa.ValidIncidentTableRegexp) + } + if s.url == "" && s.renewBy == "" && s.enable == "" { + return errors.New("at least one of -url, -renew-by, or -enable must be set") + } + req := &sapb.UpdateIncidentRequest{SerialTable: s.incident, Url: s.url} + if s.renewBy != "" { + t, err := time.Parse(time.RFC3339, s.renewBy) + if err != nil { + return fmt.Errorf("parsing -renew-by as RFC3339: %w", err) + } + req.RenewBy = timestamppb.New(t) + } + if s.enable != "" { + v, err := strconv.ParseBool(s.enable) + if err != nil { + return fmt.Errorf("parsing -enable as bool: %w", err) + } + req.Enabled = &v + } + _, err := a.saac.UpdateIncident(ctx, req) + if err != nil { + return fmt.Errorf("updating incident %q: %w", s.incident, err) + } + a.log.Infof("Updated incident %q", s.incident) + return nil +} + +type subcommandLoadIncidentSerials struct { + incident string + serialsFile string + parallelism uint +} + +var _ subcommand = (*subcommandLoadIncidentSerials)(nil) + +func (*subcommandLoadIncidentSerials) Desc() string { + return "Load serials from a file into an existing incident." +} + +func (s *subcommandLoadIncidentSerials) Flags(f *flag.FlagSet) { + f.StringVar(&s.incident, "incident", "", "Incident name (must start with 'incident_'; required)") + f.StringVar(&s.serialsFile, "serials-file", "", "File of hex serials, one per line (required)") + f.UintVar(&s.parallelism, "parallelism", 10, "Parallel workers, each with its own stream to the SA") +} + +// serialsBatchMax is the number of serials each worker accumulates before +// emitting one Send on its gRPC stream. Sized to match the SA's flush batch so +// each Recv on the server roughly maps to one transaction. Each message is +// ~320KB at full batch (10000 × ~32-byte serials), well under the gRPC default +// 4MB max. +const serialsBatchMax = 10000 + +func (s *subcommandLoadIncidentSerials) Run(ctx context.Context, a *admin) error { + if s.incident == "" || s.serialsFile == "" { + return errors.New("-incident and -serials-file are required") + } + if !sa.ValidIncidentTableRegexp.MatchString(s.incident) { + return fmt.Errorf("invalid incident %q", s.incident) + } + if s.parallelism == 0 { + return errors.New("-parallelism must be > 0") + } + + file, err := os.Open(s.serialsFile) + if err != nil { + return fmt.Errorf("opening serials file: %w", err) + } + defer file.Close() + + a.log.Infof("Loading serials from %q into incident %q with parallelism=%d.", + s.serialsFile, s.incident, s.parallelism) + + var totalSent atomic.Uint64 + work := make(chan string, s.parallelism) + g, gctx := errgroup.WithContext(ctx) + + g.Go(func() error { + defer close(work) + scanner := bufio.NewScanner(file) + lineNum := 0 + for scanner.Scan() { + lineNum++ + raw := scanner.Text() + if strings.TrimSpace(raw) == "" { + continue + } + cleaned, err := cleanSerials([]string{raw}) + if err != nil { + return fmt.Errorf("line %d: %w", lineNum, err) + } + select { + case work <- cleaned[0]: + case <-gctx.Done(): + return gctx.Err() + } + } + return scanner.Err() + }) + + for range s.parallelism { + g.Go(func() error { + stream, err := a.saac.AddSerialsToIncident(gctx) + if err != nil { + return fmt.Errorf("opening stream: %w", err) + } + var buf []string + flushSerials := func() error { + if len(buf) == 0 { + return nil + } + err := stream.Send(&sapb.AddSerialsToIncidentRequest{ + SerialTable: s.incident, + Serial: buf, + }) + if err != nil { + buf = buf[:0] + return err + } + n := totalSent.Add(uint64(len(buf))) + prev := n - uint64(len(buf)) + if prev/100000 != n/100000 { + a.log.Infof("Sent %d serials total", n) + } + buf = buf[:0] + return nil + } + for serial := range work { + buf = append(buf, serial) + if len(buf) >= serialsBatchMax { + err := flushSerials() + if err != nil { + return fmt.Errorf("sending batch: %w", err) + } + } + } + err = flushSerials() + if err != nil { + return fmt.Errorf("sending final batch: %w", err) + } + _, err = stream.CloseAndRecv() + if err != nil { + return fmt.Errorf("closing stream: %w", err) + } + return nil + }) + } + + err = g.Wait() + if err != nil { + return fmt.Errorf("loading serials: %w", err) + } + a.log.Infof("Done. Sent %d serials from %q into incident %q.", + totalSent.Load(), s.serialsFile, s.incident) + return nil +} diff --git a/cmd/admin/incident_test.go b/cmd/admin/incident_test.go new file mode 100644 index 00000000000..5f7512749f0 --- /dev/null +++ b/cmd/admin/incident_test.go @@ -0,0 +1,215 @@ +package main + +import ( + "context" + "os" + "path" + "strings" + "testing" + "time" + + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + + blog "github.com/letsencrypt/boulder/log" + sapb "github.com/letsencrypt/boulder/sa/proto" + "github.com/letsencrypt/boulder/test" +) + +// fakeAddSerialsStream implements the client-streaming client returned by +// mockSAAdmin.AddSerialsToIncident. It records every Send(req). +type fakeAddSerialsStream struct { + grpc.ClientStream + sent []*sapb.AddSerialsToIncidentRequest +} + +func (s *fakeAddSerialsStream) Send(req *sapb.AddSerialsToIncidentRequest) error { + s.sent = append(s.sent, req) + return nil +} + +func (s *fakeAddSerialsStream) CloseAndRecv() (*emptypb.Empty, error) { + return &emptypb.Empty{}, nil +} + +// mockSAROIncidents implements just enough of StorageAuthorityReadOnlyClient +// to support the incident-related admin tests. +type mockSAROIncidents struct { + sapb.StorageAuthorityReadOnlyClient + listResp *sapb.Incidents +} + +func (m *mockSAROIncidents) ListIncidents(_ context.Context, _ *emptypb.Empty, _ ...grpc.CallOption) (*sapb.Incidents, error) { + return m.listResp, nil +} + +// mockSAAdmin implements the StorageAuthorityAdmin client interface and +// records the requests received on each method. +type mockSAAdmin struct { + sapb.StorageAuthorityAdminClient + createReqs []*sapb.CreateIncidentRequest + updateReqs []*sapb.UpdateIncidentRequest + addStream *fakeAddSerialsStream +} + +func (m *mockSAAdmin) UpdateIncident(_ context.Context, req *sapb.UpdateIncidentRequest, _ ...grpc.CallOption) (*emptypb.Empty, error) { + m.updateReqs = append(m.updateReqs, req) + return &emptypb.Empty{}, nil +} + +func (m *mockSAAdmin) CreateIncident(_ context.Context, req *sapb.CreateIncidentRequest, _ ...grpc.CallOption) (*sapb.Incident, error) { + m.createReqs = append(m.createReqs, req) + return &sapb.Incident{Id: 1, SerialTable: req.SerialTable, Url: req.Url, RenewBy: req.RenewBy}, nil +} + +func (m *mockSAAdmin) AddSerialsToIncident(_ context.Context, _ ...grpc.CallOption) (grpc.ClientStreamingClient[sapb.AddSerialsToIncidentRequest, emptypb.Empty], error) { + m.addStream = &fakeAddSerialsStream{} + return m.addStream, nil +} + +func TestCreateIncidentSubcommand(t *testing.T) { + t.Parallel() + msa := &mockSAAdmin{} + a := &admin{saac: msa, log: blog.NewMock()} + + s := &subcommandCreateIncident{ + incident: "incident_abc", + url: "https://example.com/foo", + renewBy: "2030-01-01T00:00:00Z", + } + err := s.Run(context.Background(), a) + test.AssertNotError(t, err, "create-incident") + test.AssertEquals(t, len(msa.createReqs), 1) + test.AssertEquals(t, msa.createReqs[0].SerialTable, "incident_abc") +} + +func TestCreateIncidentSubcommandValidation(t *testing.T) { + t.Parallel() + + cases := []struct { + name string + sub subcommandCreateIncident + expectErrContains string + }{ + { + name: "missing flags", + sub: subcommandCreateIncident{}, + expectErrContains: "required", + }, + { + name: "bad incident", + sub: subcommandCreateIncident{incident: "bad name", url: "u", renewBy: "2030-01-01T00:00:00Z"}, + expectErrContains: "invalid incident", + }, + { + name: "bad renewBy", + sub: subcommandCreateIncident{incident: "incident_x", url: "u", renewBy: "tomorrow"}, + expectErrContains: "renew-by", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + msa := &mockSAAdmin{} + a := &admin{saac: msa, log: blog.NewMock()} + err := tc.sub.Run(context.Background(), a) + test.AssertError(t, err, "expected error") + test.AssertContains(t, err.Error(), tc.expectErrContains) + test.AssertEquals(t, len(msa.createReqs), 0) + }) + } +} + +func TestListIncidentsSubcommand(t *testing.T) { + t.Parallel() + saroc := &mockSAROIncidents{ + listResp: &sapb.Incidents{ + Incidents: []*sapb.Incident{ + {Id: 1, SerialTable: "incident_one", Url: "https://example.com/1", Enabled: true, RenewBy: timestamppb.New(time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC))}, + {Id: 2, SerialTable: "incident_two", Url: "https://example.com/2", Enabled: false, RenewBy: timestamppb.New(time.Date(2030, 6, 1, 0, 0, 0, 0, time.UTC))}, + }, + }, + } + a := &admin{saroc: saroc, log: blog.NewMock()} + err := (&subcommandListIncidents{}).Run(context.Background(), a) + test.AssertNotError(t, err, "list-incidents") +} + +func TestUpdateIncidentSubcommand(t *testing.T) { + t.Parallel() + msa := &mockSAAdmin{} + a := &admin{saac: msa, log: blog.NewMock()} + + err := (&subcommandUpdateIncident{incident: "incident_foo", url: "https://example.com/new"}).Run(context.Background(), a) + test.AssertNotError(t, err, "update url only") + test.AssertEquals(t, len(msa.updateReqs), 1) + test.AssertEquals(t, msa.updateReqs[0].SerialTable, "incident_foo") + test.AssertEquals(t, msa.updateReqs[0].Url, "https://example.com/new") + test.Assert(t, msa.updateReqs[0].RenewBy == nil, "RenewBy should be nil when -renew-by is unset") + test.Assert(t, msa.updateReqs[0].Enabled == nil, "Enabled should be nil when -enable is unset") + + err = (&subcommandUpdateIncident{incident: "incident_foo", renewBy: "2030-06-01T00:00:00Z"}).Run(context.Background(), a) + test.AssertNotError(t, err, "update renewBy only") + test.AssertEquals(t, len(msa.updateReqs), 2) + test.AssertEquals(t, msa.updateReqs[1].Url, "") + test.Assert(t, msa.updateReqs[1].RenewBy != nil, "RenewBy should be set") + test.Assert(t, msa.updateReqs[1].Enabled == nil, "Enabled should be nil when -enable is unset") + + err = (&subcommandUpdateIncident{incident: "incident_foo", enable: "true"}).Run(context.Background(), a) + test.AssertNotError(t, err, "update enable=true") + test.AssertEquals(t, len(msa.updateReqs), 3) + test.Assert(t, msa.updateReqs[2].Enabled != nil, "Enabled should be set") + test.AssertEquals(t, *msa.updateReqs[2].Enabled, true) + + err = (&subcommandUpdateIncident{incident: "incident_foo", enable: "false"}).Run(context.Background(), a) + test.AssertNotError(t, err, "update enable=false") + test.AssertEquals(t, len(msa.updateReqs), 4) + test.Assert(t, msa.updateReqs[3].Enabled != nil, "Enabled should be set") + test.AssertEquals(t, *msa.updateReqs[3].Enabled, false) + + err = (&subcommandUpdateIncident{incident: "incident_foo", enable: "yes"}).Run(context.Background(), a) + test.AssertError(t, err, "expected error for malformed -enable") + + err = (&subcommandUpdateIncident{incident: "incident_foo"}).Run(context.Background(), a) + test.AssertError(t, err, "expected error when no fields set") + + err = (&subcommandUpdateIncident{url: "https://example.com/new"}).Run(context.Background(), a) + test.AssertError(t, err, "expected error for missing -incident") + + err = (&subcommandUpdateIncident{incident: "bad name", url: "https://example.com/new"}).Run(context.Background(), a) + test.AssertError(t, err, "expected error for malformed incident") +} + +func TestLoadIncidentSerialsSubcommand(t *testing.T) { + t.Parallel() + + a1 := strings.Repeat("a", 32) + b1 := strings.Repeat("b", 32) + c1 := strings.Repeat("Cc", 16) + + serialsFile := path.Join(t.TempDir(), "serials.txt") + err := os.WriteFile(serialsFile, []byte(a1+"\n"+b1+"\n"+c1+"\n"), 0o600) + test.AssertNotError(t, err, "writing serials file") + + msa := &mockSAAdmin{} + a := &admin{saac: msa, log: blog.NewMock()} + + s := &subcommandLoadIncidentSerials{ + incident: "incident_bulk", + serialsFile: serialsFile, + parallelism: 1, + } + err = s.Run(context.Background(), a) + test.AssertNotError(t, err, "load-incident-serials") + // Three serials all fit in one wire batch, so we expect a single Send. + test.AssertEquals(t, len(msa.addStream.sent), 1) + test.AssertEquals(t, msa.addStream.sent[0].SerialTable, "incident_bulk") + + got := map[string]bool{} + for _, s := range msa.addStream.sent[0].Serial { + got[s] = true + } + test.Assert(t, got[a1], "expected "+a1) + test.Assert(t, got[b1], "expected "+b1) + test.Assert(t, got[c1], "expected "+c1) +} diff --git a/cmd/admin/main.go b/cmd/admin/main.go index 4b37d00c709..cfdc4573b5e 100644 --- a/cmd/admin/main.go +++ b/cmd/admin/main.go @@ -74,6 +74,10 @@ func main() { "dump-limit-overrides": &subcommandDumpEnabledOverrides{}, "toggle-limit-override": &subcommandToggleOverride{}, "add-limit-override": &subcommandAddOverride{}, + "create-incident": &subcommandCreateIncident{}, + "list-incidents": &subcommandListIncidents{}, + "update-incident": &subcommandUpdateIncident{}, + "load-incident-serials": &subcommandLoadIncidentSerials{}, } defaultUsage := flag.Usage diff --git a/cmd/boulder-sa/main.go b/cmd/boulder-sa/main.go index 2a14ccb9539..b9edeb3db3e 100644 --- a/cmd/boulder-sa/main.go +++ b/cmd/boulder-sa/main.go @@ -18,9 +18,10 @@ import ( type Config struct { SA struct { cmd.ServiceConfig - DB cmd.DBConfig - ReadOnlyDB cmd.DBConfig `validate:"-"` - IncidentsDB cmd.DBConfig `validate:"-"` + DB cmd.DBConfig + ReadOnlyDB cmd.DBConfig `validate:"-"` + IncidentsDB cmd.DBConfig `validate:"-"` + IncidentsWriteDB cmd.DBConfig `validate:"-"` Features features.Config @@ -77,6 +78,12 @@ func main() { cmd.FailOnError(err, "While initializing dbIncidentsMap") } + dbIncidentsWriteMap := dbIncidentsMap + if c.SA.IncidentsWriteDB != (cmd.DBConfig{}) { + dbIncidentsWriteMap, err = sa.InitWrappedDb(c.SA.IncidentsWriteDB, scope, logger) + cmd.FailOnError(err, "While initializing dbIncidentsWriteMap") + } + clk := clock.New() tls, err := c.SA.TLS.Load(scope) @@ -89,9 +96,13 @@ func main() { sai, err := sa.NewSQLStorageAuthorityWrapping(saroi, dbMap, scope) cmd.FailOnError(err, "Failed to create SA impl") + saai, err := sa.NewSQLStorageAuthorityAdmin(dbMap, dbIncidentsWriteMap, logger) + cmd.FailOnError(err, "Failed to create SA admin impl") + start, err := bgrpc.NewServer(c.SA.GRPC, logger).WithCheckInterval(c.SA.HealthCheckInterval.Duration).Add( &sapb.StorageAuthorityReadOnly_ServiceDesc, saroi).Add( - &sapb.StorageAuthority_ServiceDesc, sai).Build( + &sapb.StorageAuthority_ServiceDesc, sai).Add( + &sapb.StorageAuthorityAdmin_ServiceDesc, saai).Build( tls, scope, clk) cmd.FailOnError(err, "Unable to setup SA gRPC server") diff --git a/go.mod b/go.mod index 3cd0bc4113f..d6126ede5e6 100644 --- a/go.mod +++ b/go.mod @@ -39,6 +39,7 @@ require ( go.yaml.in/yaml/v3 v3.0.4 golang.org/x/crypto v0.48.0 golang.org/x/net v0.51.0 + golang.org/x/sync v0.19.0 golang.org/x/term v0.40.0 golang.org/x/text v0.34.0 golang.org/x/time v0.11.0 @@ -86,7 +87,6 @@ require ( go.opentelemetry.io/otel/metric v1.40.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect golang.org/x/mod v0.32.0 // indirect - golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/tools v0.41.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect diff --git a/mocks/sa.go b/mocks/sa.go index 59fc5d00fcc..4d43346f16b 100644 --- a/mocks/sa.go +++ b/mocks/sa.go @@ -374,6 +374,11 @@ func (sa *StorageAuthorityReadOnly) IncidentsForSerial(ctx context.Context, req return &sapb.Incidents{}, nil } +// ListIncidents is a mock. +func (sa *StorageAuthorityReadOnly) ListIncidents(_ context.Context, _ *emptypb.Empty, _ ...grpc.CallOption) (*sapb.Incidents, error) { + return &sapb.Incidents{}, nil +} + // ReplacementOrderExists is a mock. func (sa *StorageAuthorityReadOnly) ReplacementOrderExists(ctx context.Context, req *sapb.Serial, _ ...grpc.CallOption) (*sapb.Exists, error) { return nil, nil diff --git a/sa/db/02-users.sql b/sa/db/02-users.sql index 7af5f9127d9..5da15c10dab 100644 --- a/sa/db/02-users.sql +++ b/sa/db/02-users.sql @@ -24,7 +24,7 @@ GRANT INSERT,SELECT ON serials TO 'sa'@'%'; GRANT SELECT,INSERT ON precertificates TO 'sa'@'%'; GRANT SELECT,INSERT ON keyHashToSerial TO 'sa'@'%'; GRANT SELECT,INSERT ON blockedKeys TO 'sa'@'%'; -GRANT SELECT ON incidents TO 'sa'@'%'; +GRANT SELECT,INSERT,UPDATE ON incidents TO 'sa'@'%'; GRANT SELECT,INSERT,UPDATE ON crlShards TO 'sa'@'%'; GRANT SELECT,INSERT,UPDATE ON revokedCertificates TO 'sa'@'%'; GRANT SELECT,INSERT,UPDATE ON replacementOrders TO 'sa'@'%'; @@ -85,10 +85,12 @@ GRANT ALL PRIVILEGES ON * to 'test_setup'@'%'; USE incidents_sa; CREATE USER IF NOT EXISTS 'incidents_sa'@'%'; +CREATE USER IF NOT EXISTS 'incidents_sa_admin'@'%'; CREATE USER IF NOT EXISTS 'test_setup'@'%'; -- Storage Authority GRANT SELECT ON * TO 'incidents_sa'@'%'; +GRANT SELECT,CREATE,INSERT ON * TO 'incidents_sa_admin'@'%'; -- Test setup and teardown GRANT ALL PRIVILEGES ON * to 'test_setup'@'%'; diff --git a/sa/db/02-users_next.sql b/sa/db/02-users_next.sql index 1290fd6e852..3cb90cf8e9b 100644 --- a/sa/db/02-users_next.sql +++ b/sa/db/02-users_next.sql @@ -24,7 +24,7 @@ GRANT INSERT,SELECT ON serials TO 'sa'@'%'; GRANT SELECT,INSERT ON precertificates TO 'sa'@'%'; GRANT SELECT,INSERT ON keyHashToSerial TO 'sa'@'%'; GRANT SELECT,INSERT ON blockedKeys TO 'sa'@'%'; -GRANT SELECT ON incidents TO 'sa'@'%'; +GRANT SELECT,INSERT,UPDATE ON incidents TO 'sa'@'%'; GRANT SELECT,INSERT,UPDATE ON crlShards TO 'sa'@'%'; GRANT SELECT,INSERT,UPDATE ON revokedCertificates TO 'sa'@'%'; GRANT SELECT,INSERT,UPDATE ON replacementOrders TO 'sa'@'%'; @@ -85,10 +85,12 @@ GRANT ALL PRIVILEGES ON * to 'test_setup'@'%'; USE incidents_sa_next; CREATE USER IF NOT EXISTS 'incidents_sa'@'%'; +CREATE USER IF NOT EXISTS 'incidents_sa_admin'@'%'; CREATE USER IF NOT EXISTS 'test_setup'@'%'; -- Storage Authority GRANT SELECT ON * TO 'incidents_sa'@'%'; +GRANT SELECT,CREATE,INSERT ON * TO 'incidents_sa_admin'@'%'; -- Test setup and teardown GRANT ALL PRIVILEGES ON * to 'test_setup'@'%'; diff --git a/sa/proto/sa.pb.go b/sa/proto/sa.pb.go index dee8ad16be4..be50e81891f 100644 --- a/sa/proto/sa.pb.go +++ b/sa/proto/sa.pb.go @@ -1985,6 +1985,190 @@ func (x *SerialsForIncidentRequest) GetIncidentTable() string { return "" } +type CreateIncidentRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SerialTable string `protobuf:"bytes,1,opt,name=serialTable,proto3" json:"serialTable,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + RenewBy *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=renewBy,proto3" json:"renewBy,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateIncidentRequest) Reset() { + *x = CreateIncidentRequest{} + mi := &file_sa_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateIncidentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateIncidentRequest) ProtoMessage() {} + +func (x *CreateIncidentRequest) ProtoReflect() protoreflect.Message { + mi := &file_sa_proto_msgTypes[34] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateIncidentRequest.ProtoReflect.Descriptor instead. +func (*CreateIncidentRequest) Descriptor() ([]byte, []int) { + return file_sa_proto_rawDescGZIP(), []int{34} +} + +func (x *CreateIncidentRequest) GetSerialTable() string { + if x != nil { + return x.SerialTable + } + return "" +} + +func (x *CreateIncidentRequest) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *CreateIncidentRequest) GetRenewBy() *timestamppb.Timestamp { + if x != nil { + return x.RenewBy + } + return nil +} + +// UpdateIncidentRequest updates a subset of the metadata fields on the +// incidents row identified by serialTable. An empty url, nil renewBy, and +// nil enabled all mean "leave that field alone"; at least one of them must +// be set. +type UpdateIncidentRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SerialTable string `protobuf:"bytes,1,opt,name=serialTable,proto3" json:"serialTable,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + RenewBy *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=renewBy,proto3" json:"renewBy,omitempty"` + Enabled *bool `protobuf:"varint,4,opt,name=enabled,proto3,oneof" json:"enabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateIncidentRequest) Reset() { + *x = UpdateIncidentRequest{} + mi := &file_sa_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateIncidentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateIncidentRequest) ProtoMessage() {} + +func (x *UpdateIncidentRequest) ProtoReflect() protoreflect.Message { + mi := &file_sa_proto_msgTypes[35] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateIncidentRequest.ProtoReflect.Descriptor instead. +func (*UpdateIncidentRequest) Descriptor() ([]byte, []int) { + return file_sa_proto_rawDescGZIP(), []int{35} +} + +func (x *UpdateIncidentRequest) GetSerialTable() string { + if x != nil { + return x.SerialTable + } + return "" +} + +func (x *UpdateIncidentRequest) GetUrl() string { + if x != nil { + return x.Url + } + return "" +} + +func (x *UpdateIncidentRequest) GetRenewBy() *timestamppb.Timestamp { + if x != nil { + return x.RenewBy + } + return nil +} + +func (x *UpdateIncidentRequest) GetEnabled() bool { + if x != nil && x.Enabled != nil { + return *x.Enabled + } + return false +} + +type AddSerialsToIncidentRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + SerialTable string `protobuf:"bytes,1,opt,name=serialTable,proto3" json:"serialTable,omitempty"` + Serial []string `protobuf:"bytes,2,rep,name=serial,proto3" json:"serial,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *AddSerialsToIncidentRequest) Reset() { + *x = AddSerialsToIncidentRequest{} + mi := &file_sa_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddSerialsToIncidentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddSerialsToIncidentRequest) ProtoMessage() {} + +func (x *AddSerialsToIncidentRequest) ProtoReflect() protoreflect.Message { + mi := &file_sa_proto_msgTypes[36] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddSerialsToIncidentRequest.ProtoReflect.Descriptor instead. +func (*AddSerialsToIncidentRequest) Descriptor() ([]byte, []int) { + return file_sa_proto_rawDescGZIP(), []int{36} +} + +func (x *AddSerialsToIncidentRequest) GetSerialTable() string { + if x != nil { + return x.SerialTable + } + return "" +} + +func (x *AddSerialsToIncidentRequest) GetSerial() []string { + if x != nil { + return x.Serial + } + return nil +} + type IncidentSerial struct { state protoimpl.MessageState `protogen:"open.v1"` // Next unused field number: 6 @@ -1998,7 +2182,7 @@ type IncidentSerial struct { func (x *IncidentSerial) Reset() { *x = IncidentSerial{} - mi := &file_sa_proto_msgTypes[34] + mi := &file_sa_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2010,7 +2194,7 @@ func (x *IncidentSerial) String() string { func (*IncidentSerial) ProtoMessage() {} func (x *IncidentSerial) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[34] + mi := &file_sa_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2023,7 +2207,7 @@ func (x *IncidentSerial) ProtoReflect() protoreflect.Message { // Deprecated: Use IncidentSerial.ProtoReflect.Descriptor instead. func (*IncidentSerial) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{34} + return file_sa_proto_rawDescGZIP(), []int{37} } func (x *IncidentSerial) GetSerial() string { @@ -2066,7 +2250,7 @@ type GetRevokedCertsByShardRequest struct { func (x *GetRevokedCertsByShardRequest) Reset() { *x = GetRevokedCertsByShardRequest{} - mi := &file_sa_proto_msgTypes[35] + mi := &file_sa_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2078,7 +2262,7 @@ func (x *GetRevokedCertsByShardRequest) String() string { func (*GetRevokedCertsByShardRequest) ProtoMessage() {} func (x *GetRevokedCertsByShardRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[35] + mi := &file_sa_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2091,7 +2275,7 @@ func (x *GetRevokedCertsByShardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRevokedCertsByShardRequest.ProtoReflect.Descriptor instead. func (*GetRevokedCertsByShardRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{35} + return file_sa_proto_rawDescGZIP(), []int{38} } func (x *GetRevokedCertsByShardRequest) GetIssuerNameID() int64 { @@ -2133,7 +2317,7 @@ type RevocationStatus struct { func (x *RevocationStatus) Reset() { *x = RevocationStatus{} - mi := &file_sa_proto_msgTypes[36] + mi := &file_sa_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2145,7 +2329,7 @@ func (x *RevocationStatus) String() string { func (*RevocationStatus) ProtoMessage() {} func (x *RevocationStatus) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[36] + mi := &file_sa_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2158,7 +2342,7 @@ func (x *RevocationStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use RevocationStatus.ProtoReflect.Descriptor instead. func (*RevocationStatus) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{36} + return file_sa_proto_rawDescGZIP(), []int{39} } func (x *RevocationStatus) GetStatus() int64 { @@ -2194,7 +2378,7 @@ type LeaseCRLShardRequest struct { func (x *LeaseCRLShardRequest) Reset() { *x = LeaseCRLShardRequest{} - mi := &file_sa_proto_msgTypes[37] + mi := &file_sa_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2206,7 +2390,7 @@ func (x *LeaseCRLShardRequest) String() string { func (*LeaseCRLShardRequest) ProtoMessage() {} func (x *LeaseCRLShardRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[37] + mi := &file_sa_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2219,7 +2403,7 @@ func (x *LeaseCRLShardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaseCRLShardRequest.ProtoReflect.Descriptor instead. func (*LeaseCRLShardRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{37} + return file_sa_proto_rawDescGZIP(), []int{40} } func (x *LeaseCRLShardRequest) GetIssuerNameID() int64 { @@ -2260,7 +2444,7 @@ type LeaseCRLShardResponse struct { func (x *LeaseCRLShardResponse) Reset() { *x = LeaseCRLShardResponse{} - mi := &file_sa_proto_msgTypes[38] + mi := &file_sa_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2272,7 +2456,7 @@ func (x *LeaseCRLShardResponse) String() string { func (*LeaseCRLShardResponse) ProtoMessage() {} func (x *LeaseCRLShardResponse) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[38] + mi := &file_sa_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2285,7 +2469,7 @@ func (x *LeaseCRLShardResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LeaseCRLShardResponse.ProtoReflect.Descriptor instead. func (*LeaseCRLShardResponse) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{38} + return file_sa_proto_rawDescGZIP(), []int{41} } func (x *LeaseCRLShardResponse) GetIssuerNameID() int64 { @@ -2314,7 +2498,7 @@ type UpdateCRLShardRequest struct { func (x *UpdateCRLShardRequest) Reset() { *x = UpdateCRLShardRequest{} - mi := &file_sa_proto_msgTypes[39] + mi := &file_sa_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2326,7 +2510,7 @@ func (x *UpdateCRLShardRequest) String() string { func (*UpdateCRLShardRequest) ProtoMessage() {} func (x *UpdateCRLShardRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[39] + mi := &file_sa_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2339,7 +2523,7 @@ func (x *UpdateCRLShardRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateCRLShardRequest.ProtoReflect.Descriptor instead. func (*UpdateCRLShardRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{39} + return file_sa_proto_rawDescGZIP(), []int{42} } func (x *UpdateCRLShardRequest) GetIssuerNameID() int64 { @@ -2379,7 +2563,7 @@ type Identifiers struct { func (x *Identifiers) Reset() { *x = Identifiers{} - mi := &file_sa_proto_msgTypes[40] + mi := &file_sa_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2391,7 +2575,7 @@ func (x *Identifiers) String() string { func (*Identifiers) ProtoMessage() {} func (x *Identifiers) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[40] + mi := &file_sa_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2404,7 +2588,7 @@ func (x *Identifiers) ProtoReflect() protoreflect.Message { // Deprecated: Use Identifiers.ProtoReflect.Descriptor instead. func (*Identifiers) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{40} + return file_sa_proto_rawDescGZIP(), []int{43} } func (x *Identifiers) GetIdentifiers() []*proto.Identifier { @@ -2424,7 +2608,7 @@ type PauseRequest struct { func (x *PauseRequest) Reset() { *x = PauseRequest{} - mi := &file_sa_proto_msgTypes[41] + mi := &file_sa_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2436,7 +2620,7 @@ func (x *PauseRequest) String() string { func (*PauseRequest) ProtoMessage() {} func (x *PauseRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[41] + mi := &file_sa_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2449,7 +2633,7 @@ func (x *PauseRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseRequest.ProtoReflect.Descriptor instead. func (*PauseRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{41} + return file_sa_proto_rawDescGZIP(), []int{44} } func (x *PauseRequest) GetRegistrationID() int64 { @@ -2476,7 +2660,7 @@ type PauseIdentifiersResponse struct { func (x *PauseIdentifiersResponse) Reset() { *x = PauseIdentifiersResponse{} - mi := &file_sa_proto_msgTypes[42] + mi := &file_sa_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2488,7 +2672,7 @@ func (x *PauseIdentifiersResponse) String() string { func (*PauseIdentifiersResponse) ProtoMessage() {} func (x *PauseIdentifiersResponse) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[42] + mi := &file_sa_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2501,7 +2685,7 @@ func (x *PauseIdentifiersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseIdentifiersResponse.ProtoReflect.Descriptor instead. func (*PauseIdentifiersResponse) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{42} + return file_sa_proto_rawDescGZIP(), []int{45} } func (x *PauseIdentifiersResponse) GetPaused() int64 { @@ -2528,7 +2712,7 @@ type UpdateRegistrationKeyRequest struct { func (x *UpdateRegistrationKeyRequest) Reset() { *x = UpdateRegistrationKeyRequest{} - mi := &file_sa_proto_msgTypes[43] + mi := &file_sa_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2540,7 +2724,7 @@ func (x *UpdateRegistrationKeyRequest) String() string { func (*UpdateRegistrationKeyRequest) ProtoMessage() {} func (x *UpdateRegistrationKeyRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[43] + mi := &file_sa_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2553,7 +2737,7 @@ func (x *UpdateRegistrationKeyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateRegistrationKeyRequest.ProtoReflect.Descriptor instead. func (*UpdateRegistrationKeyRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{43} + return file_sa_proto_rawDescGZIP(), []int{46} } func (x *UpdateRegistrationKeyRequest) GetRegistrationID() int64 { @@ -2584,7 +2768,7 @@ type RateLimitOverride struct { func (x *RateLimitOverride) Reset() { *x = RateLimitOverride{} - mi := &file_sa_proto_msgTypes[44] + mi := &file_sa_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2596,7 +2780,7 @@ func (x *RateLimitOverride) String() string { func (*RateLimitOverride) ProtoMessage() {} func (x *RateLimitOverride) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[44] + mi := &file_sa_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2609,7 +2793,7 @@ func (x *RateLimitOverride) ProtoReflect() protoreflect.Message { // Deprecated: Use RateLimitOverride.ProtoReflect.Descriptor instead. func (*RateLimitOverride) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{44} + return file_sa_proto_rawDescGZIP(), []int{47} } func (x *RateLimitOverride) GetLimitEnum() int64 { @@ -2664,7 +2848,7 @@ type AddRateLimitOverrideRequest struct { func (x *AddRateLimitOverrideRequest) Reset() { *x = AddRateLimitOverrideRequest{} - mi := &file_sa_proto_msgTypes[45] + mi := &file_sa_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2676,7 +2860,7 @@ func (x *AddRateLimitOverrideRequest) String() string { func (*AddRateLimitOverrideRequest) ProtoMessage() {} func (x *AddRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[45] + mi := &file_sa_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2689,7 +2873,7 @@ func (x *AddRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AddRateLimitOverrideRequest.ProtoReflect.Descriptor instead. func (*AddRateLimitOverrideRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{45} + return file_sa_proto_rawDescGZIP(), []int{48} } func (x *AddRateLimitOverrideRequest) GetOverride() *RateLimitOverride { @@ -2717,7 +2901,7 @@ type AddRateLimitOverrideResponse struct { func (x *AddRateLimitOverrideResponse) Reset() { *x = AddRateLimitOverrideResponse{} - mi := &file_sa_proto_msgTypes[46] + mi := &file_sa_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2729,7 +2913,7 @@ func (x *AddRateLimitOverrideResponse) String() string { func (*AddRateLimitOverrideResponse) ProtoMessage() {} func (x *AddRateLimitOverrideResponse) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[46] + mi := &file_sa_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2742,7 +2926,7 @@ func (x *AddRateLimitOverrideResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AddRateLimitOverrideResponse.ProtoReflect.Descriptor instead. func (*AddRateLimitOverrideResponse) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{46} + return file_sa_proto_rawDescGZIP(), []int{49} } func (x *AddRateLimitOverrideResponse) GetInserted() bool { @@ -2776,7 +2960,7 @@ type EnableRateLimitOverrideRequest struct { func (x *EnableRateLimitOverrideRequest) Reset() { *x = EnableRateLimitOverrideRequest{} - mi := &file_sa_proto_msgTypes[47] + mi := &file_sa_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2788,7 +2972,7 @@ func (x *EnableRateLimitOverrideRequest) String() string { func (*EnableRateLimitOverrideRequest) ProtoMessage() {} func (x *EnableRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[47] + mi := &file_sa_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2801,7 +2985,7 @@ func (x *EnableRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use EnableRateLimitOverrideRequest.ProtoReflect.Descriptor instead. func (*EnableRateLimitOverrideRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{47} + return file_sa_proto_rawDescGZIP(), []int{50} } func (x *EnableRateLimitOverrideRequest) GetLimitEnum() int64 { @@ -2828,7 +3012,7 @@ type DisableRateLimitOverrideRequest struct { func (x *DisableRateLimitOverrideRequest) Reset() { *x = DisableRateLimitOverrideRequest{} - mi := &file_sa_proto_msgTypes[48] + mi := &file_sa_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2840,7 +3024,7 @@ func (x *DisableRateLimitOverrideRequest) String() string { func (*DisableRateLimitOverrideRequest) ProtoMessage() {} func (x *DisableRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[48] + mi := &file_sa_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2853,7 +3037,7 @@ func (x *DisableRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DisableRateLimitOverrideRequest.ProtoReflect.Descriptor instead. func (*DisableRateLimitOverrideRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{48} + return file_sa_proto_rawDescGZIP(), []int{51} } func (x *DisableRateLimitOverrideRequest) GetLimitEnum() int64 { @@ -2880,7 +3064,7 @@ type GetRateLimitOverrideRequest struct { func (x *GetRateLimitOverrideRequest) Reset() { *x = GetRateLimitOverrideRequest{} - mi := &file_sa_proto_msgTypes[49] + mi := &file_sa_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2892,7 +3076,7 @@ func (x *GetRateLimitOverrideRequest) String() string { func (*GetRateLimitOverrideRequest) ProtoMessage() {} func (x *GetRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[49] + mi := &file_sa_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2905,7 +3089,7 @@ func (x *GetRateLimitOverrideRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetRateLimitOverrideRequest.ProtoReflect.Descriptor instead. func (*GetRateLimitOverrideRequest) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{49} + return file_sa_proto_rawDescGZIP(), []int{52} } func (x *GetRateLimitOverrideRequest) GetLimitEnum() int64 { @@ -2933,7 +3117,7 @@ type RateLimitOverrideResponse struct { func (x *RateLimitOverrideResponse) Reset() { *x = RateLimitOverrideResponse{} - mi := &file_sa_proto_msgTypes[50] + mi := &file_sa_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2945,7 +3129,7 @@ func (x *RateLimitOverrideResponse) String() string { func (*RateLimitOverrideResponse) ProtoMessage() {} func (x *RateLimitOverrideResponse) ProtoReflect() protoreflect.Message { - mi := &file_sa_proto_msgTypes[50] + mi := &file_sa_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2958,7 +3142,7 @@ func (x *RateLimitOverrideResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RateLimitOverrideResponse.ProtoReflect.Descriptor instead. func (*RateLimitOverrideResponse) Descriptor() ([]byte, []int) { - return file_sa_proto_rawDescGZIP(), []int{50} + return file_sa_proto_rawDescGZIP(), []int{53} } func (x *RateLimitOverrideResponse) GetOverride() *RateLimitOverride { @@ -3258,336 +3442,368 @@ var file_sa_proto_rawDesc = string([]byte{ 0x73, 0x46, 0x6f, 0x72, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x69, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x69, 0x6e, 0x63, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0xb4, 0x01, 0x0a, 0x0e, 0x49, 0x6e, - 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, - 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, - 0x72, 0x64, 0x65, 0x72, 0x49, 0x44, 0x12, 0x42, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x6f, - 0x74, 0x69, 0x63, 0x65, 0x53, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, - 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, 0x53, 0x65, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, - 0x22, 0xe1, 0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, - 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, - 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x40, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x64, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, - 0x65, 0x64, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x73, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x69, - 0x72, 0x65, 0x73, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, - 0x64, 0x49, 0x64, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, - 0x64, 0x49, 0x64, 0x78, 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x6f, 0x6b, - 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x64, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x15, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x6e, 0x65, 0x77, + 0x42, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x42, 0x79, 0x22, 0xac, 0x01, + 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x34, 0x0a, 0x07, 0x72, + 0x65, 0x6e, 0x65, 0x77, 0x42, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x64, 0x44, 0x61, 0x74, 0x65, 0x22, 0xb0, 0x01, 0x0a, 0x14, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x43, - 0x52, 0x4c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x72, 0x65, 0x6e, 0x65, 0x77, 0x42, + 0x79, 0x12, 0x1d, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x88, 0x01, 0x01, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x57, 0x0a, 0x1b, + 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x54, 0x6f, 0x49, 0x6e, 0x63, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0xb4, 0x01, 0x0a, 0x0e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x72, 0x64, 0x65, + 0x72, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x6f, 0x72, 0x64, 0x65, 0x72, + 0x49, 0x44, 0x12, 0x42, 0x0a, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, 0x63, 0x65, + 0x53, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x6f, 0x74, 0x69, + 0x63, 0x65, 0x53, 0x65, 0x6e, 0x74, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0xe1, 0x01, 0x0a, + 0x1d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, + 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, - 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x72, - 0x64, 0x49, 0x64, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x68, 0x61, 0x72, 0x64, - 0x49, 0x64, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x68, - 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x22, 0x57, 0x0a, 0x15, 0x4c, 0x65, 0x61, 0x73, - 0x65, 0x43, 0x52, 0x4c, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, - 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, - 0x78, 0x22, 0xcf, 0x01, 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x52, 0x4c, 0x53, - 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, - 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, - 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x12, 0x3a, 0x0a, 0x0a, 0x74, - 0x68, 0x69, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x74, 0x68, 0x69, - 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x49, 0x44, 0x12, 0x40, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x42, 0x65, 0x66, + 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x42, 0x65, + 0x66, 0x6f, 0x72, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, + 0x66, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x41, + 0x66, 0x74, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, + 0x22, 0x8e, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, + 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x44, 0x61, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x44, 0x61, 0x74, + 0x65, 0x22, 0xb0, 0x01, 0x0a, 0x14, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x52, 0x4c, 0x53, 0x68, + 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, + 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x20, + 0x0a, 0x0b, 0x6d, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x69, 0x6e, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, + 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x53, 0x68, 0x61, 0x72, 0x64, 0x49, + 0x64, 0x78, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x6e, 0x74, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x05, 0x75, + 0x6e, 0x74, 0x69, 0x6c, 0x22, 0x57, 0x0a, 0x15, 0x4c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x52, 0x4c, + 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, + 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, + 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x22, 0xcf, 0x01, + 0x0a, 0x15, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x52, 0x4c, 0x53, 0x68, 0x61, 0x72, 0x64, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x69, 0x73, 0x73, 0x75, 0x65, + 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x69, + 0x73, 0x73, 0x75, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x49, 0x44, 0x12, 0x1a, 0x0a, 0x08, 0x73, + 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, + 0x68, 0x61, 0x72, 0x64, 0x49, 0x64, 0x78, 0x12, 0x3a, 0x0a, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x22, 0x41, 0x0a, 0x0b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x6a, 0x0a, 0x0c, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, - 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x32, - 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x74, 0x68, 0x69, 0x73, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x3a, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x22, + 0x41, 0x0a, 0x0b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x32, + 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, - 0x72, 0x73, 0x22, 0x4e, 0x0a, 0x18, 0x50, 0x61, 0x75, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, - 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x61, 0x75, 0x73, - 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x70, 0x61, 0x75, 0x73, - 0x65, 0x64, 0x22, 0x58, 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x72, 0x73, 0x22, 0x6a, 0x0a, 0x0c, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x6a, 0x77, - 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6a, 0x77, 0x6b, 0x22, 0xc8, 0x01, 0x0a, - 0x11, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, - 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, - 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x18, - 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, - 0x6f, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x75, 0x72, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x62, 0x75, 0x72, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x1b, 0x41, 0x64, 0x64, 0x52, 0x61, - 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, - 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, - 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, - 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, - 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, - 0x87, 0x01, 0x0a, 0x1c, 0x41, 0x64, 0x64, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, - 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, - 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x32, 0x0a, 0x0b, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x10, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x4e, + 0x0a, 0x18, 0x50, 0x61, 0x75, 0x73, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, + 0x75, 0x73, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x70, 0x61, 0x75, 0x73, + 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x70, 0x61, 0x75, 0x73, 0x65, 0x64, 0x22, 0x58, + 0x0a, 0x1c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, + 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x10, 0x0a, 0x03, 0x6a, 0x77, 0x6b, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6a, 0x77, 0x6b, 0x22, 0xc8, 0x01, 0x0a, 0x11, 0x52, 0x61, 0x74, + 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, + 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x06, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, + 0x05, 0x62, 0x75, 0x72, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x62, 0x75, + 0x72, 0x73, 0x74, 0x22, 0x66, 0x0a, 0x1b, 0x41, 0x64, 0x64, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x08, 0x6f, 0x76, 0x65, + 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x22, 0x87, 0x01, 0x0a, 0x1c, + 0x41, 0x64, 0x64, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, + 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, + 0x65, 0x64, 0x12, 0x31, 0x0a, 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, + 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x08, 0x65, 0x78, 0x69, + 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x5c, 0x0a, 0x1e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x45, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, + 0x4b, 0x65, 0x79, 0x22, 0x5d, 0x0a, 0x1f, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, - 0x08, 0x65, 0x78, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x5c, 0x0a, 0x1e, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, - 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, - 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, - 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x5d, 0x0a, 0x1f, 0x44, 0x69, 0x73, 0x61, 0x62, - 0x6c, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, - 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, - 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x63, - 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x22, 0x59, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x52, 0x61, 0x74, - 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, - 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, - 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, - 0x79, 0x22, 0xa2, 0x01, 0x0a, 0x19, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x31, 0x0a, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, - 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, - 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x09, - 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x32, 0xb3, 0x0d, 0x0a, 0x18, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x61, 0x64, 0x4f, - 0x6e, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x45, 0x78, - 0x69, 0x73, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, - 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, - 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x1a, - 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x73, 0x46, 0x6f, 0x72, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x12, 0x14, 0x2e, 0x73, 0x61, - 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, - 0x32, 0x1a, 0x13, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, - 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x15, 0x47, - 0x65, 0x74, 0x4c, 0x69, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, - 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x2e, - 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x17, 0x2e, 0x63, 0x6f, 0x72, 0x65, - 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x12, 0x10, 0x2e, 0x73, 0x61, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, - 0x00, 0x12, 0x3e, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x6f, 0x72, - 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, - 0x64, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, - 0x00, 0x12, 0x3b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, - 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x3c, - 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, - 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x13, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, - 0x14, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x65, - 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, - 0x64, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, - 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x52, 0x4c, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x35, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0a, 0x2e, - 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x53, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x00, 0x12, - 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x41, - 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, - 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2f, 0x0a, 0x0f, 0x47, 0x65, - 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x0c, 0x2e, - 0x73, 0x61, 0x2e, 0x53, 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, 0x2e, 0x73, 0x61, - 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x17, 0x47, - 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x56, - 0x61, 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, - 0x57, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x12, - 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4f, - 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, + 0x6e, 0x75, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, + 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, + 0x65, 0x79, 0x22, 0x59, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, + 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x45, 0x6e, 0x75, 0x6d, 0x12, + 0x1c, 0x0a, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x22, 0xa2, 0x01, + 0x0a, 0x19, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, + 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x08, 0x6f, + 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, + 0x72, 0x69, 0x64, 0x65, 0x52, 0x08, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x38, 0x0a, 0x09, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x41, 0x74, 0x32, 0xed, 0x0d, 0x0a, 0x18, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, + 0x37, 0x0a, 0x0d, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, + 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x69, + 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, + 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x1a, 0x46, 0x51, 0x44, 0x4e, + 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x46, 0x6f, 0x72, + 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, + 0x22, 0x00, 0x12, 0x40, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x12, 0x14, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x32, 0x1a, 0x13, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4c, 0x69, + 0x6e, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x11, 0x2e, 0x63, + 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, + 0x00, 0x12, 0x3d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x17, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, + 0x12, 0x2b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x10, 0x2e, 0x73, + 0x61, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, 0x3e, 0x0a, + 0x10, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, + 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, + 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, 0x3b, 0x0a, + 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x14, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x4b, + 0x65, 0x79, 0x12, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x57, 0x65, 0x62, 0x4b, + 0x65, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, + 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x73, 0x61, + 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, + 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x21, 0x2e, + 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, 0x65, 0x72, + 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x0e, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x22, 0x00, 0x30, 0x01, 0x12, 0x35, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x13, 0x47, + 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x0c, 0x2e, 0x73, 0x61, 0x2e, 0x53, + 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x32, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x12, 0x49, - 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x0d, 0x2e, - 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x00, 0x12, 0x28, - 0x0a, 0x0a, 0x4b, 0x65, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x0c, 0x2e, 0x73, - 0x61, 0x2e, 0x53, 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, - 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6c, - 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x0a, - 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x12, - 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x46, 0x6f, 0x72, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, - 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x46, - 0x6f, 0x72, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3d, 0x0a, 0x16, 0x43, 0x68, 0x65, - 0x63, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x50, 0x61, 0x75, - 0x73, 0x65, 0x64, 0x12, 0x10, 0x2e, 0x73, 0x61, 0x2e, 0x50, 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, - 0x61, 0x75, 0x73, 0x65, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, - 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x0f, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x61, - 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, - 0x1f, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, - 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1d, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x59, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, - 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, - 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1d, 0x2e, 0x73, 0x61, 0x2e, 0x52, - 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x32, 0xfa, 0x19, 0x0a, - 0x10, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, - 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x69, 0x73, - 0x74, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x45, - 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x73, - 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x48, 0x0a, 0x1a, 0x46, 0x51, - 0x44, 0x4e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x46, - 0x6f, 0x72, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x12, 0x14, 0x2e, 0x73, 0x61, 0x2e, 0x41, - 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x32, 0x1a, - 0x13, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, + 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x1c, 0x47, + 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x12, 0x21, 0x2e, 0x73, 0x61, + 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, + 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, + 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x0a, 0x2e, + 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x0d, 0x2e, 0x73, 0x61, 0x2e, 0x49, + 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x00, 0x12, 0x28, 0x0a, 0x0a, 0x4b, 0x65, + 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x0c, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x50, + 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, + 0x74, 0x73, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x69, + 0x64, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, + 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x00, 0x12, 0x32, + 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4f, 0x72, 0x64, + 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, + 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x46, 0x6f, 0x72, + 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x73, 0x46, 0x6f, 0x72, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, + 0x3d, 0x0a, 0x16, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x73, 0x50, 0x61, 0x75, 0x73, 0x65, 0x64, 0x12, 0x10, 0x2e, 0x73, 0x61, 0x2e, 0x50, + 0x61, 0x75, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x73, 0x61, + 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x00, 0x12, 0x3d, + 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x75, 0x73, 0x65, 0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x0f, 0x2e, 0x73, 0x61, 0x2e, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x22, 0x00, 0x12, 0x58, 0x0a, + 0x14, 0x47, 0x65, 0x74, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, + 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1f, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x61, + 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, + 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x59, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x45, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1d, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x30, 0x01, 0x32, 0xb4, 0x1a, 0x0a, 0x10, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x12, 0x37, 0x0a, 0x0d, 0x46, 0x51, 0x44, 0x4e, 0x53, + 0x65, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x73, 0x61, 0x2e, 0x46, 0x51, + 0x44, 0x4e, 0x53, 0x65, 0x74, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, + 0x12, 0x48, 0x0a, 0x1a, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x73, 0x46, 0x6f, 0x72, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x12, 0x18, + 0x2e, 0x73, 0x61, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x46, 0x51, 0x44, 0x4e, 0x53, 0x65, 0x74, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x73, 0x22, 0x00, 0x12, 0x40, 0x0a, 0x11, 0x47, 0x65, + 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x12, + 0x14, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x44, 0x32, 0x1a, 0x13, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x0e, + 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x0a, + 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, + 0x38, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4c, 0x69, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x11, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x15, 0x47, 0x65, 0x74, - 0x4c, 0x69, 0x6e, 0x74, 0x50, 0x72, 0x65, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x65, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x11, - 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, - 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x17, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, - 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x10, - 0x2e, 0x73, 0x61, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x0b, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, - 0x3e, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x61, - 0x6d, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, - 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x0b, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, - 0x3b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x14, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, - 0x79, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x2e, 0x73, 0x61, 0x2e, 0x4a, 0x53, 0x4f, 0x4e, 0x57, 0x65, - 0x62, 0x4b, 0x65, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, - 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x13, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, - 0x73, 0x61, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, - 0x6b, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, - 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, - 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x35, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0a, 0x2e, 0x73, 0x61, - 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, - 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x00, 0x12, 0x39, 0x0a, - 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x0c, 0x2e, 0x73, 0x61, - 0x2e, 0x53, 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, - 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x32, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x57, 0x0a, - 0x1c, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x12, 0x21, 0x2e, - 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, - 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x12, 0x49, 0x6e, 0x63, - 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, - 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x0d, 0x2e, 0x73, 0x61, - 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x00, 0x12, 0x28, 0x0a, 0x0a, - 0x4b, 0x65, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x0c, 0x2e, 0x73, 0x61, 0x2e, - 0x53, 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, - 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, + 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x14, 0x47, 0x65, 0x74, + 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x17, 0x2e, + 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x12, 0x10, 0x2e, 0x73, 0x61, 0x2e, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, + 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x73, 0x61, 0x2e, 0x47, + 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x4f, 0x72, + 0x64, 0x65, 0x72, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x63, + 0x6f, 0x72, 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x00, 0x12, 0x3c, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x0e, 0x2e, 0x73, 0x61, 0x2e, + 0x4a, 0x53, 0x4f, 0x4e, 0x57, 0x65, 0x62, 0x4b, 0x65, 0x79, 0x1a, 0x12, 0x2e, 0x63, 0x6f, 0x72, + 0x65, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x00, + 0x12, 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, + 0x69, 0x61, 0x6c, 0x1a, 0x14, 0x2e, 0x73, 0x61, 0x2e, 0x52, 0x65, 0x76, 0x6f, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x00, 0x12, 0x4f, 0x0a, 0x16, 0x47, + 0x65, 0x74, 0x52, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, + 0x53, 0x68, 0x61, 0x72, 0x64, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x43, 0x65, 0x72, 0x74, 0x73, 0x42, 0x79, 0x53, 0x68, 0x61, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0e, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, + 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x00, 0x30, 0x01, 0x12, 0x35, 0x0a, 0x11, + 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x12, 0x2e, + 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, + 0x73, 0x42, 0x79, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x73, 0x61, 0x2e, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x1a, 0x0a, + 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, 0x2f, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x42, 0x79, 0x4b, 0x65, + 0x79, 0x12, 0x0c, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, + 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x00, 0x30, 0x01, 0x12, + 0x52, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x32, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, + 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, + 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0x00, 0x12, 0x57, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x32, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, + 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x16, + 0x47, 0x65, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x2e, 0x73, 0x61, 0x2e, 0x47, 0x65, 0x74, 0x4f, + 0x72, 0x64, 0x65, 0x72, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x73, 0x61, 0x2e, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x00, 0x12, + 0x31, 0x0a, 0x12, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x46, 0x6f, 0x72, 0x53, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x1a, 0x0d, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, + 0x22, 0x00, 0x12, 0x28, 0x0a, 0x0a, 0x4b, 0x65, 0x79, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, + 0x12, 0x0c, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x50, 0x4b, 0x49, 0x48, 0x61, 0x73, 0x68, 0x1a, 0x0a, + 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x0d, + 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0d, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, + 0x65, 0x6e, 0x74, 0x73, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x16, 0x52, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x12, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x1a, 0x0a, 0x2e, 0x73, 0x61, 0x2e, 0x45, 0x78, 0x69, 0x73, 0x74, 0x73, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x12, 0x53, 0x65, @@ -3715,10 +3931,25 @@ var file_sa_proto_rawDesc = string([]byte{ 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x61, 0x74, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64, 0x65, 0x72, 0x2f, 0x73, 0x61, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x32, 0xf0, 0x01, 0x0a, 0x15, 0x53, 0x74, + 0x6f, 0x72, 0x61, 0x67, 0x65, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x41, 0x64, + 0x6d, 0x69, 0x6e, 0x12, 0x3b, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x63, + 0x69, 0x64, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x73, 0x61, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x0c, 0x2e, 0x73, 0x61, 0x2e, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x22, 0x00, + 0x12, 0x45, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x12, 0x19, 0x2e, 0x73, 0x61, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, + 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x14, 0x41, 0x64, 0x64, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6c, 0x73, 0x54, 0x6f, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x12, + 0x1f, 0x2e, 0x73, 0x61, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x73, 0x54, + 0x6f, 0x49, 0x6e, 0x63, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x28, 0x01, 0x42, 0x29, 0x5a, 0x27, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x74, 0x73, 0x65, + 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64, 0x65, 0x72, 0x2f, 0x73, + 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( @@ -3733,7 +3964,7 @@ func file_sa_proto_rawDescGZIP() []byte { return file_sa_proto_rawDescData } -var file_sa_proto_msgTypes = make([]protoimpl.MessageInfo, 51) +var file_sa_proto_msgTypes = make([]protoimpl.MessageInfo, 54) var file_sa_proto_goTypes = []any{ (*RegistrationID)(nil), // 0: sa.RegistrationID (*JSONWebKey)(nil), // 1: sa.JSONWebKey @@ -3769,239 +4000,254 @@ var file_sa_proto_goTypes = []any{ (*Incident)(nil), // 31: sa.Incident (*Incidents)(nil), // 32: sa.Incidents (*SerialsForIncidentRequest)(nil), // 33: sa.SerialsForIncidentRequest - (*IncidentSerial)(nil), // 34: sa.IncidentSerial - (*GetRevokedCertsByShardRequest)(nil), // 35: sa.GetRevokedCertsByShardRequest - (*RevocationStatus)(nil), // 36: sa.RevocationStatus - (*LeaseCRLShardRequest)(nil), // 37: sa.LeaseCRLShardRequest - (*LeaseCRLShardResponse)(nil), // 38: sa.LeaseCRLShardResponse - (*UpdateCRLShardRequest)(nil), // 39: sa.UpdateCRLShardRequest - (*Identifiers)(nil), // 40: sa.Identifiers - (*PauseRequest)(nil), // 41: sa.PauseRequest - (*PauseIdentifiersResponse)(nil), // 42: sa.PauseIdentifiersResponse - (*UpdateRegistrationKeyRequest)(nil), // 43: sa.UpdateRegistrationKeyRequest - (*RateLimitOverride)(nil), // 44: sa.RateLimitOverride - (*AddRateLimitOverrideRequest)(nil), // 45: sa.AddRateLimitOverrideRequest - (*AddRateLimitOverrideResponse)(nil), // 46: sa.AddRateLimitOverrideResponse - (*EnableRateLimitOverrideRequest)(nil), // 47: sa.EnableRateLimitOverrideRequest - (*DisableRateLimitOverrideRequest)(nil), // 48: sa.DisableRateLimitOverrideRequest - (*GetRateLimitOverrideRequest)(nil), // 49: sa.GetRateLimitOverrideRequest - (*RateLimitOverrideResponse)(nil), // 50: sa.RateLimitOverrideResponse - (*proto.Identifier)(nil), // 51: core.Identifier - (*timestamppb.Timestamp)(nil), // 52: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 53: google.protobuf.Duration - (*proto.ProblemDetails)(nil), // 54: core.ProblemDetails - (*proto.Authorization)(nil), // 55: core.Authorization - (*proto.ValidationRecord)(nil), // 56: core.ValidationRecord - (*emptypb.Empty)(nil), // 57: google.protobuf.Empty - (*proto.Registration)(nil), // 58: core.Registration - (*proto.Certificate)(nil), // 59: core.Certificate - (*proto.CertificateStatus)(nil), // 60: core.CertificateStatus - (*proto.Order)(nil), // 61: core.Order - (*proto.CRLEntry)(nil), // 62: core.CRLEntry + (*CreateIncidentRequest)(nil), // 34: sa.CreateIncidentRequest + (*UpdateIncidentRequest)(nil), // 35: sa.UpdateIncidentRequest + (*AddSerialsToIncidentRequest)(nil), // 36: sa.AddSerialsToIncidentRequest + (*IncidentSerial)(nil), // 37: sa.IncidentSerial + (*GetRevokedCertsByShardRequest)(nil), // 38: sa.GetRevokedCertsByShardRequest + (*RevocationStatus)(nil), // 39: sa.RevocationStatus + (*LeaseCRLShardRequest)(nil), // 40: sa.LeaseCRLShardRequest + (*LeaseCRLShardResponse)(nil), // 41: sa.LeaseCRLShardResponse + (*UpdateCRLShardRequest)(nil), // 42: sa.UpdateCRLShardRequest + (*Identifiers)(nil), // 43: sa.Identifiers + (*PauseRequest)(nil), // 44: sa.PauseRequest + (*PauseIdentifiersResponse)(nil), // 45: sa.PauseIdentifiersResponse + (*UpdateRegistrationKeyRequest)(nil), // 46: sa.UpdateRegistrationKeyRequest + (*RateLimitOverride)(nil), // 47: sa.RateLimitOverride + (*AddRateLimitOverrideRequest)(nil), // 48: sa.AddRateLimitOverrideRequest + (*AddRateLimitOverrideResponse)(nil), // 49: sa.AddRateLimitOverrideResponse + (*EnableRateLimitOverrideRequest)(nil), // 50: sa.EnableRateLimitOverrideRequest + (*DisableRateLimitOverrideRequest)(nil), // 51: sa.DisableRateLimitOverrideRequest + (*GetRateLimitOverrideRequest)(nil), // 52: sa.GetRateLimitOverrideRequest + (*RateLimitOverrideResponse)(nil), // 53: sa.RateLimitOverrideResponse + (*proto.Identifier)(nil), // 54: core.Identifier + (*timestamppb.Timestamp)(nil), // 55: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 56: google.protobuf.Duration + (*proto.ProblemDetails)(nil), // 57: core.ProblemDetails + (*proto.Authorization)(nil), // 58: core.Authorization + (*proto.ValidationRecord)(nil), // 59: core.ValidationRecord + (*emptypb.Empty)(nil), // 60: google.protobuf.Empty + (*proto.Registration)(nil), // 61: core.Registration + (*proto.Certificate)(nil), // 62: core.Certificate + (*proto.CertificateStatus)(nil), // 63: core.CertificateStatus + (*proto.Order)(nil), // 64: core.Order + (*proto.CRLEntry)(nil), // 65: core.CRLEntry } var file_sa_proto_depIdxs = []int32{ - 51, // 0: sa.GetValidAuthorizationsRequest.identifiers:type_name -> core.Identifier - 52, // 1: sa.GetValidAuthorizationsRequest.validUntil:type_name -> google.protobuf.Timestamp - 52, // 2: sa.SerialMetadata.created:type_name -> google.protobuf.Timestamp - 52, // 3: sa.SerialMetadata.expires:type_name -> google.protobuf.Timestamp - 52, // 4: sa.Range.earliest:type_name -> google.protobuf.Timestamp - 52, // 5: sa.Range.latest:type_name -> google.protobuf.Timestamp - 52, // 6: sa.Timestamps.timestamps:type_name -> google.protobuf.Timestamp - 51, // 7: sa.CountInvalidAuthorizationsRequest.identifier:type_name -> core.Identifier + 54, // 0: sa.GetValidAuthorizationsRequest.identifiers:type_name -> core.Identifier + 55, // 1: sa.GetValidAuthorizationsRequest.validUntil:type_name -> google.protobuf.Timestamp + 55, // 2: sa.SerialMetadata.created:type_name -> google.protobuf.Timestamp + 55, // 3: sa.SerialMetadata.expires:type_name -> google.protobuf.Timestamp + 55, // 4: sa.Range.earliest:type_name -> google.protobuf.Timestamp + 55, // 5: sa.Range.latest:type_name -> google.protobuf.Timestamp + 55, // 6: sa.Timestamps.timestamps:type_name -> google.protobuf.Timestamp + 54, // 7: sa.CountInvalidAuthorizationsRequest.identifier:type_name -> core.Identifier 6, // 8: sa.CountInvalidAuthorizationsRequest.range:type_name -> sa.Range - 51, // 9: sa.CountFQDNSetsRequest.identifiers:type_name -> core.Identifier - 53, // 10: sa.CountFQDNSetsRequest.window:type_name -> google.protobuf.Duration - 51, // 11: sa.FQDNSetExistsRequest.identifiers:type_name -> core.Identifier - 52, // 12: sa.AddSerialRequest.created:type_name -> google.protobuf.Timestamp - 52, // 13: sa.AddSerialRequest.expires:type_name -> google.protobuf.Timestamp - 52, // 14: sa.AddCertificateRequest.issued:type_name -> google.protobuf.Timestamp - 52, // 15: sa.NewOrderRequest.expires:type_name -> google.protobuf.Timestamp - 51, // 16: sa.NewOrderRequest.identifiers:type_name -> core.Identifier - 51, // 17: sa.NewAuthzRequest.identifier:type_name -> core.Identifier - 52, // 18: sa.NewAuthzRequest.expires:type_name -> google.protobuf.Timestamp + 54, // 9: sa.CountFQDNSetsRequest.identifiers:type_name -> core.Identifier + 56, // 10: sa.CountFQDNSetsRequest.window:type_name -> google.protobuf.Duration + 54, // 11: sa.FQDNSetExistsRequest.identifiers:type_name -> core.Identifier + 55, // 12: sa.AddSerialRequest.created:type_name -> google.protobuf.Timestamp + 55, // 13: sa.AddSerialRequest.expires:type_name -> google.protobuf.Timestamp + 55, // 14: sa.AddCertificateRequest.issued:type_name -> google.protobuf.Timestamp + 55, // 15: sa.NewOrderRequest.expires:type_name -> google.protobuf.Timestamp + 54, // 16: sa.NewOrderRequest.identifiers:type_name -> core.Identifier + 54, // 17: sa.NewAuthzRequest.identifier:type_name -> core.Identifier + 55, // 18: sa.NewAuthzRequest.expires:type_name -> google.protobuf.Timestamp 16, // 19: sa.NewOrderAndAuthzsRequest.newOrder:type_name -> sa.NewOrderRequest 17, // 20: sa.NewOrderAndAuthzsRequest.newAuthzs:type_name -> sa.NewAuthzRequest - 54, // 21: sa.SetOrderErrorRequest.error:type_name -> core.ProblemDetails - 51, // 22: sa.GetOrderForNamesRequest.identifiers:type_name -> core.Identifier - 51, // 23: sa.GetAuthorizationsRequest.identifiers:type_name -> core.Identifier - 52, // 24: sa.GetAuthorizationsRequest.validUntil:type_name -> google.protobuf.Timestamp - 55, // 25: sa.Authorizations.authzs:type_name -> core.Authorization - 52, // 26: sa.RevokeCertificateRequest.date:type_name -> google.protobuf.Timestamp - 52, // 27: sa.RevokeCertificateRequest.backdate:type_name -> google.protobuf.Timestamp - 52, // 28: sa.FinalizeAuthorizationRequest.expires:type_name -> google.protobuf.Timestamp - 56, // 29: sa.FinalizeAuthorizationRequest.validationRecords:type_name -> core.ValidationRecord - 54, // 30: sa.FinalizeAuthorizationRequest.validationError:type_name -> core.ProblemDetails - 52, // 31: sa.FinalizeAuthorizationRequest.attemptedAt:type_name -> google.protobuf.Timestamp - 52, // 32: sa.AddBlockedKeyRequest.added:type_name -> google.protobuf.Timestamp - 52, // 33: sa.Incident.renewBy:type_name -> google.protobuf.Timestamp + 57, // 21: sa.SetOrderErrorRequest.error:type_name -> core.ProblemDetails + 54, // 22: sa.GetOrderForNamesRequest.identifiers:type_name -> core.Identifier + 54, // 23: sa.GetAuthorizationsRequest.identifiers:type_name -> core.Identifier + 55, // 24: sa.GetAuthorizationsRequest.validUntil:type_name -> google.protobuf.Timestamp + 58, // 25: sa.Authorizations.authzs:type_name -> core.Authorization + 55, // 26: sa.RevokeCertificateRequest.date:type_name -> google.protobuf.Timestamp + 55, // 27: sa.RevokeCertificateRequest.backdate:type_name -> google.protobuf.Timestamp + 55, // 28: sa.FinalizeAuthorizationRequest.expires:type_name -> google.protobuf.Timestamp + 59, // 29: sa.FinalizeAuthorizationRequest.validationRecords:type_name -> core.ValidationRecord + 57, // 30: sa.FinalizeAuthorizationRequest.validationError:type_name -> core.ProblemDetails + 55, // 31: sa.FinalizeAuthorizationRequest.attemptedAt:type_name -> google.protobuf.Timestamp + 55, // 32: sa.AddBlockedKeyRequest.added:type_name -> google.protobuf.Timestamp + 55, // 33: sa.Incident.renewBy:type_name -> google.protobuf.Timestamp 31, // 34: sa.Incidents.incidents:type_name -> sa.Incident - 52, // 35: sa.IncidentSerial.lastNoticeSent:type_name -> google.protobuf.Timestamp - 52, // 36: sa.GetRevokedCertsByShardRequest.revokedBefore:type_name -> google.protobuf.Timestamp - 52, // 37: sa.GetRevokedCertsByShardRequest.expiresAfter:type_name -> google.protobuf.Timestamp - 52, // 38: sa.RevocationStatus.revokedDate:type_name -> google.protobuf.Timestamp - 52, // 39: sa.LeaseCRLShardRequest.until:type_name -> google.protobuf.Timestamp - 52, // 40: sa.UpdateCRLShardRequest.thisUpdate:type_name -> google.protobuf.Timestamp - 52, // 41: sa.UpdateCRLShardRequest.nextUpdate:type_name -> google.protobuf.Timestamp - 51, // 42: sa.Identifiers.identifiers:type_name -> core.Identifier - 51, // 43: sa.PauseRequest.identifiers:type_name -> core.Identifier - 53, // 44: sa.RateLimitOverride.period:type_name -> google.protobuf.Duration - 44, // 45: sa.AddRateLimitOverrideRequest.override:type_name -> sa.RateLimitOverride - 44, // 46: sa.AddRateLimitOverrideResponse.existing:type_name -> sa.RateLimitOverride - 44, // 47: sa.RateLimitOverrideResponse.override:type_name -> sa.RateLimitOverride - 52, // 48: sa.RateLimitOverrideResponse.updatedAt:type_name -> google.protobuf.Timestamp - 11, // 49: sa.StorageAuthorityReadOnly.FQDNSetExists:input_type -> sa.FQDNSetExistsRequest - 10, // 50: sa.StorageAuthorityReadOnly.FQDNSetTimestampsForWindow:input_type -> sa.CountFQDNSetsRequest - 26, // 51: sa.StorageAuthorityReadOnly.GetAuthorization2:input_type -> sa.AuthorizationID2 - 4, // 52: sa.StorageAuthorityReadOnly.GetCertificate:input_type -> sa.Serial - 4, // 53: sa.StorageAuthorityReadOnly.GetLintPrecertificate:input_type -> sa.Serial - 4, // 54: sa.StorageAuthorityReadOnly.GetCertificateStatus:input_type -> sa.Serial - 15, // 55: sa.StorageAuthorityReadOnly.GetOrder:input_type -> sa.OrderRequest - 21, // 56: sa.StorageAuthorityReadOnly.GetOrderForNames:input_type -> sa.GetOrderForNamesRequest - 0, // 57: sa.StorageAuthorityReadOnly.GetRegistration:input_type -> sa.RegistrationID - 1, // 58: sa.StorageAuthorityReadOnly.GetRegistrationByKey:input_type -> sa.JSONWebKey - 4, // 59: sa.StorageAuthorityReadOnly.GetRevocationStatus:input_type -> sa.Serial - 35, // 60: sa.StorageAuthorityReadOnly.GetRevokedCertsByShard:input_type -> sa.GetRevokedCertsByShardRequest - 4, // 61: sa.StorageAuthorityReadOnly.GetSerialMetadata:input_type -> sa.Serial - 0, // 62: sa.StorageAuthorityReadOnly.GetSerialsByAccount:input_type -> sa.RegistrationID - 30, // 63: sa.StorageAuthorityReadOnly.GetSerialsByKey:input_type -> sa.SPKIHash - 3, // 64: sa.StorageAuthorityReadOnly.GetValidAuthorizations2:input_type -> sa.GetValidAuthorizationsRequest - 20, // 65: sa.StorageAuthorityReadOnly.GetValidOrderAuthorizations2:input_type -> sa.GetOrderAuthorizationsRequest - 20, // 66: sa.StorageAuthorityReadOnly.GetOrderAuthorizations:input_type -> sa.GetOrderAuthorizationsRequest - 4, // 67: sa.StorageAuthorityReadOnly.IncidentsForSerial:input_type -> sa.Serial - 30, // 68: sa.StorageAuthorityReadOnly.KeyBlocked:input_type -> sa.SPKIHash - 4, // 69: sa.StorageAuthorityReadOnly.ReplacementOrderExists:input_type -> sa.Serial - 33, // 70: sa.StorageAuthorityReadOnly.SerialsForIncident:input_type -> sa.SerialsForIncidentRequest - 41, // 71: sa.StorageAuthorityReadOnly.CheckIdentifiersPaused:input_type -> sa.PauseRequest - 0, // 72: sa.StorageAuthorityReadOnly.GetPausedIdentifiers:input_type -> sa.RegistrationID - 49, // 73: sa.StorageAuthorityReadOnly.GetRateLimitOverride:input_type -> sa.GetRateLimitOverrideRequest - 57, // 74: sa.StorageAuthorityReadOnly.GetEnabledRateLimitOverrides:input_type -> google.protobuf.Empty - 11, // 75: sa.StorageAuthority.FQDNSetExists:input_type -> sa.FQDNSetExistsRequest - 10, // 76: sa.StorageAuthority.FQDNSetTimestampsForWindow:input_type -> sa.CountFQDNSetsRequest - 26, // 77: sa.StorageAuthority.GetAuthorization2:input_type -> sa.AuthorizationID2 - 4, // 78: sa.StorageAuthority.GetCertificate:input_type -> sa.Serial - 4, // 79: sa.StorageAuthority.GetLintPrecertificate:input_type -> sa.Serial - 4, // 80: sa.StorageAuthority.GetCertificateStatus:input_type -> sa.Serial - 15, // 81: sa.StorageAuthority.GetOrder:input_type -> sa.OrderRequest - 21, // 82: sa.StorageAuthority.GetOrderForNames:input_type -> sa.GetOrderForNamesRequest - 0, // 83: sa.StorageAuthority.GetRegistration:input_type -> sa.RegistrationID - 1, // 84: sa.StorageAuthority.GetRegistrationByKey:input_type -> sa.JSONWebKey - 4, // 85: sa.StorageAuthority.GetRevocationStatus:input_type -> sa.Serial - 35, // 86: sa.StorageAuthority.GetRevokedCertsByShard:input_type -> sa.GetRevokedCertsByShardRequest - 4, // 87: sa.StorageAuthority.GetSerialMetadata:input_type -> sa.Serial - 0, // 88: sa.StorageAuthority.GetSerialsByAccount:input_type -> sa.RegistrationID - 30, // 89: sa.StorageAuthority.GetSerialsByKey:input_type -> sa.SPKIHash - 3, // 90: sa.StorageAuthority.GetValidAuthorizations2:input_type -> sa.GetValidAuthorizationsRequest - 20, // 91: sa.StorageAuthority.GetValidOrderAuthorizations2:input_type -> sa.GetOrderAuthorizationsRequest - 20, // 92: sa.StorageAuthority.GetOrderAuthorizations:input_type -> sa.GetOrderAuthorizationsRequest - 4, // 93: sa.StorageAuthority.IncidentsForSerial:input_type -> sa.Serial - 30, // 94: sa.StorageAuthority.KeyBlocked:input_type -> sa.SPKIHash - 4, // 95: sa.StorageAuthority.ReplacementOrderExists:input_type -> sa.Serial - 33, // 96: sa.StorageAuthority.SerialsForIncident:input_type -> sa.SerialsForIncidentRequest - 41, // 97: sa.StorageAuthority.CheckIdentifiersPaused:input_type -> sa.PauseRequest - 0, // 98: sa.StorageAuthority.GetPausedIdentifiers:input_type -> sa.RegistrationID - 49, // 99: sa.StorageAuthority.GetRateLimitOverride:input_type -> sa.GetRateLimitOverrideRequest - 57, // 100: sa.StorageAuthority.GetEnabledRateLimitOverrides:input_type -> google.protobuf.Empty - 29, // 101: sa.StorageAuthority.AddBlockedKey:input_type -> sa.AddBlockedKeyRequest - 14, // 102: sa.StorageAuthority.AddCertificate:input_type -> sa.AddCertificateRequest - 14, // 103: sa.StorageAuthority.AddPrecertificate:input_type -> sa.AddCertificateRequest - 13, // 104: sa.StorageAuthority.AddSerial:input_type -> sa.AddSerialRequest - 26, // 105: sa.StorageAuthority.DeactivateAuthorization2:input_type -> sa.AuthorizationID2 - 0, // 106: sa.StorageAuthority.DeactivateRegistration:input_type -> sa.RegistrationID - 28, // 107: sa.StorageAuthority.FinalizeAuthorization2:input_type -> sa.FinalizeAuthorizationRequest - 22, // 108: sa.StorageAuthority.FinalizeOrder:input_type -> sa.FinalizeOrderRequest - 18, // 109: sa.StorageAuthority.NewOrderAndAuthzs:input_type -> sa.NewOrderAndAuthzsRequest - 58, // 110: sa.StorageAuthority.NewRegistration:input_type -> core.Registration - 27, // 111: sa.StorageAuthority.RevokeCertificate:input_type -> sa.RevokeCertificateRequest - 19, // 112: sa.StorageAuthority.SetOrderError:input_type -> sa.SetOrderErrorRequest - 15, // 113: sa.StorageAuthority.SetOrderProcessing:input_type -> sa.OrderRequest - 43, // 114: sa.StorageAuthority.UpdateRegistrationKey:input_type -> sa.UpdateRegistrationKeyRequest - 27, // 115: sa.StorageAuthority.UpdateRevokedCertificate:input_type -> sa.RevokeCertificateRequest - 37, // 116: sa.StorageAuthority.LeaseCRLShard:input_type -> sa.LeaseCRLShardRequest - 39, // 117: sa.StorageAuthority.UpdateCRLShard:input_type -> sa.UpdateCRLShardRequest - 41, // 118: sa.StorageAuthority.PauseIdentifiers:input_type -> sa.PauseRequest - 0, // 119: sa.StorageAuthority.UnpauseAccount:input_type -> sa.RegistrationID - 45, // 120: sa.StorageAuthority.AddRateLimitOverride:input_type -> sa.AddRateLimitOverrideRequest - 48, // 121: sa.StorageAuthority.DisableRateLimitOverride:input_type -> sa.DisableRateLimitOverrideRequest - 47, // 122: sa.StorageAuthority.EnableRateLimitOverride:input_type -> sa.EnableRateLimitOverrideRequest - 12, // 123: sa.StorageAuthorityReadOnly.FQDNSetExists:output_type -> sa.Exists - 8, // 124: sa.StorageAuthorityReadOnly.FQDNSetTimestampsForWindow:output_type -> sa.Timestamps - 55, // 125: sa.StorageAuthorityReadOnly.GetAuthorization2:output_type -> core.Authorization - 59, // 126: sa.StorageAuthorityReadOnly.GetCertificate:output_type -> core.Certificate - 59, // 127: sa.StorageAuthorityReadOnly.GetLintPrecertificate:output_type -> core.Certificate - 60, // 128: sa.StorageAuthorityReadOnly.GetCertificateStatus:output_type -> core.CertificateStatus - 61, // 129: sa.StorageAuthorityReadOnly.GetOrder:output_type -> core.Order - 61, // 130: sa.StorageAuthorityReadOnly.GetOrderForNames:output_type -> core.Order - 58, // 131: sa.StorageAuthorityReadOnly.GetRegistration:output_type -> core.Registration - 58, // 132: sa.StorageAuthorityReadOnly.GetRegistrationByKey:output_type -> core.Registration - 36, // 133: sa.StorageAuthorityReadOnly.GetRevocationStatus:output_type -> sa.RevocationStatus - 62, // 134: sa.StorageAuthorityReadOnly.GetRevokedCertsByShard:output_type -> core.CRLEntry - 5, // 135: sa.StorageAuthorityReadOnly.GetSerialMetadata:output_type -> sa.SerialMetadata - 4, // 136: sa.StorageAuthorityReadOnly.GetSerialsByAccount:output_type -> sa.Serial - 4, // 137: sa.StorageAuthorityReadOnly.GetSerialsByKey:output_type -> sa.Serial - 24, // 138: sa.StorageAuthorityReadOnly.GetValidAuthorizations2:output_type -> sa.Authorizations - 24, // 139: sa.StorageAuthorityReadOnly.GetValidOrderAuthorizations2:output_type -> sa.Authorizations - 24, // 140: sa.StorageAuthorityReadOnly.GetOrderAuthorizations:output_type -> sa.Authorizations - 32, // 141: sa.StorageAuthorityReadOnly.IncidentsForSerial:output_type -> sa.Incidents - 12, // 142: sa.StorageAuthorityReadOnly.KeyBlocked:output_type -> sa.Exists - 12, // 143: sa.StorageAuthorityReadOnly.ReplacementOrderExists:output_type -> sa.Exists - 34, // 144: sa.StorageAuthorityReadOnly.SerialsForIncident:output_type -> sa.IncidentSerial - 40, // 145: sa.StorageAuthorityReadOnly.CheckIdentifiersPaused:output_type -> sa.Identifiers - 40, // 146: sa.StorageAuthorityReadOnly.GetPausedIdentifiers:output_type -> sa.Identifiers - 50, // 147: sa.StorageAuthorityReadOnly.GetRateLimitOverride:output_type -> sa.RateLimitOverrideResponse - 50, // 148: sa.StorageAuthorityReadOnly.GetEnabledRateLimitOverrides:output_type -> sa.RateLimitOverrideResponse - 12, // 149: sa.StorageAuthority.FQDNSetExists:output_type -> sa.Exists - 8, // 150: sa.StorageAuthority.FQDNSetTimestampsForWindow:output_type -> sa.Timestamps - 55, // 151: sa.StorageAuthority.GetAuthorization2:output_type -> core.Authorization - 59, // 152: sa.StorageAuthority.GetCertificate:output_type -> core.Certificate - 59, // 153: sa.StorageAuthority.GetLintPrecertificate:output_type -> core.Certificate - 60, // 154: sa.StorageAuthority.GetCertificateStatus:output_type -> core.CertificateStatus - 61, // 155: sa.StorageAuthority.GetOrder:output_type -> core.Order - 61, // 156: sa.StorageAuthority.GetOrderForNames:output_type -> core.Order - 58, // 157: sa.StorageAuthority.GetRegistration:output_type -> core.Registration - 58, // 158: sa.StorageAuthority.GetRegistrationByKey:output_type -> core.Registration - 36, // 159: sa.StorageAuthority.GetRevocationStatus:output_type -> sa.RevocationStatus - 62, // 160: sa.StorageAuthority.GetRevokedCertsByShard:output_type -> core.CRLEntry - 5, // 161: sa.StorageAuthority.GetSerialMetadata:output_type -> sa.SerialMetadata - 4, // 162: sa.StorageAuthority.GetSerialsByAccount:output_type -> sa.Serial - 4, // 163: sa.StorageAuthority.GetSerialsByKey:output_type -> sa.Serial - 24, // 164: sa.StorageAuthority.GetValidAuthorizations2:output_type -> sa.Authorizations - 24, // 165: sa.StorageAuthority.GetValidOrderAuthorizations2:output_type -> sa.Authorizations - 24, // 166: sa.StorageAuthority.GetOrderAuthorizations:output_type -> sa.Authorizations - 32, // 167: sa.StorageAuthority.IncidentsForSerial:output_type -> sa.Incidents - 12, // 168: sa.StorageAuthority.KeyBlocked:output_type -> sa.Exists - 12, // 169: sa.StorageAuthority.ReplacementOrderExists:output_type -> sa.Exists - 34, // 170: sa.StorageAuthority.SerialsForIncident:output_type -> sa.IncidentSerial - 40, // 171: sa.StorageAuthority.CheckIdentifiersPaused:output_type -> sa.Identifiers - 40, // 172: sa.StorageAuthority.GetPausedIdentifiers:output_type -> sa.Identifiers - 50, // 173: sa.StorageAuthority.GetRateLimitOverride:output_type -> sa.RateLimitOverrideResponse - 50, // 174: sa.StorageAuthority.GetEnabledRateLimitOverrides:output_type -> sa.RateLimitOverrideResponse - 57, // 175: sa.StorageAuthority.AddBlockedKey:output_type -> google.protobuf.Empty - 57, // 176: sa.StorageAuthority.AddCertificate:output_type -> google.protobuf.Empty - 57, // 177: sa.StorageAuthority.AddPrecertificate:output_type -> google.protobuf.Empty - 57, // 178: sa.StorageAuthority.AddSerial:output_type -> google.protobuf.Empty - 57, // 179: sa.StorageAuthority.DeactivateAuthorization2:output_type -> google.protobuf.Empty - 58, // 180: sa.StorageAuthority.DeactivateRegistration:output_type -> core.Registration - 57, // 181: sa.StorageAuthority.FinalizeAuthorization2:output_type -> google.protobuf.Empty - 57, // 182: sa.StorageAuthority.FinalizeOrder:output_type -> google.protobuf.Empty - 61, // 183: sa.StorageAuthority.NewOrderAndAuthzs:output_type -> core.Order - 58, // 184: sa.StorageAuthority.NewRegistration:output_type -> core.Registration - 57, // 185: sa.StorageAuthority.RevokeCertificate:output_type -> google.protobuf.Empty - 57, // 186: sa.StorageAuthority.SetOrderError:output_type -> google.protobuf.Empty - 57, // 187: sa.StorageAuthority.SetOrderProcessing:output_type -> google.protobuf.Empty - 58, // 188: sa.StorageAuthority.UpdateRegistrationKey:output_type -> core.Registration - 57, // 189: sa.StorageAuthority.UpdateRevokedCertificate:output_type -> google.protobuf.Empty - 38, // 190: sa.StorageAuthority.LeaseCRLShard:output_type -> sa.LeaseCRLShardResponse - 57, // 191: sa.StorageAuthority.UpdateCRLShard:output_type -> google.protobuf.Empty - 42, // 192: sa.StorageAuthority.PauseIdentifiers:output_type -> sa.PauseIdentifiersResponse - 7, // 193: sa.StorageAuthority.UnpauseAccount:output_type -> sa.Count - 46, // 194: sa.StorageAuthority.AddRateLimitOverride:output_type -> sa.AddRateLimitOverrideResponse - 57, // 195: sa.StorageAuthority.DisableRateLimitOverride:output_type -> google.protobuf.Empty - 57, // 196: sa.StorageAuthority.EnableRateLimitOverride:output_type -> google.protobuf.Empty - 123, // [123:197] is the sub-list for method output_type - 49, // [49:123] is the sub-list for method input_type - 49, // [49:49] is the sub-list for extension type_name - 49, // [49:49] is the sub-list for extension extendee - 0, // [0:49] is the sub-list for field type_name + 55, // 35: sa.CreateIncidentRequest.renewBy:type_name -> google.protobuf.Timestamp + 55, // 36: sa.UpdateIncidentRequest.renewBy:type_name -> google.protobuf.Timestamp + 55, // 37: sa.IncidentSerial.lastNoticeSent:type_name -> google.protobuf.Timestamp + 55, // 38: sa.GetRevokedCertsByShardRequest.revokedBefore:type_name -> google.protobuf.Timestamp + 55, // 39: sa.GetRevokedCertsByShardRequest.expiresAfter:type_name -> google.protobuf.Timestamp + 55, // 40: sa.RevocationStatus.revokedDate:type_name -> google.protobuf.Timestamp + 55, // 41: sa.LeaseCRLShardRequest.until:type_name -> google.protobuf.Timestamp + 55, // 42: sa.UpdateCRLShardRequest.thisUpdate:type_name -> google.protobuf.Timestamp + 55, // 43: sa.UpdateCRLShardRequest.nextUpdate:type_name -> google.protobuf.Timestamp + 54, // 44: sa.Identifiers.identifiers:type_name -> core.Identifier + 54, // 45: sa.PauseRequest.identifiers:type_name -> core.Identifier + 56, // 46: sa.RateLimitOverride.period:type_name -> google.protobuf.Duration + 47, // 47: sa.AddRateLimitOverrideRequest.override:type_name -> sa.RateLimitOverride + 47, // 48: sa.AddRateLimitOverrideResponse.existing:type_name -> sa.RateLimitOverride + 47, // 49: sa.RateLimitOverrideResponse.override:type_name -> sa.RateLimitOverride + 55, // 50: sa.RateLimitOverrideResponse.updatedAt:type_name -> google.protobuf.Timestamp + 11, // 51: sa.StorageAuthorityReadOnly.FQDNSetExists:input_type -> sa.FQDNSetExistsRequest + 10, // 52: sa.StorageAuthorityReadOnly.FQDNSetTimestampsForWindow:input_type -> sa.CountFQDNSetsRequest + 26, // 53: sa.StorageAuthorityReadOnly.GetAuthorization2:input_type -> sa.AuthorizationID2 + 4, // 54: sa.StorageAuthorityReadOnly.GetCertificate:input_type -> sa.Serial + 4, // 55: sa.StorageAuthorityReadOnly.GetLintPrecertificate:input_type -> sa.Serial + 4, // 56: sa.StorageAuthorityReadOnly.GetCertificateStatus:input_type -> sa.Serial + 15, // 57: sa.StorageAuthorityReadOnly.GetOrder:input_type -> sa.OrderRequest + 21, // 58: sa.StorageAuthorityReadOnly.GetOrderForNames:input_type -> sa.GetOrderForNamesRequest + 0, // 59: sa.StorageAuthorityReadOnly.GetRegistration:input_type -> sa.RegistrationID + 1, // 60: sa.StorageAuthorityReadOnly.GetRegistrationByKey:input_type -> sa.JSONWebKey + 4, // 61: sa.StorageAuthorityReadOnly.GetRevocationStatus:input_type -> sa.Serial + 38, // 62: sa.StorageAuthorityReadOnly.GetRevokedCertsByShard:input_type -> sa.GetRevokedCertsByShardRequest + 4, // 63: sa.StorageAuthorityReadOnly.GetSerialMetadata:input_type -> sa.Serial + 0, // 64: sa.StorageAuthorityReadOnly.GetSerialsByAccount:input_type -> sa.RegistrationID + 30, // 65: sa.StorageAuthorityReadOnly.GetSerialsByKey:input_type -> sa.SPKIHash + 3, // 66: sa.StorageAuthorityReadOnly.GetValidAuthorizations2:input_type -> sa.GetValidAuthorizationsRequest + 20, // 67: sa.StorageAuthorityReadOnly.GetValidOrderAuthorizations2:input_type -> sa.GetOrderAuthorizationsRequest + 20, // 68: sa.StorageAuthorityReadOnly.GetOrderAuthorizations:input_type -> sa.GetOrderAuthorizationsRequest + 4, // 69: sa.StorageAuthorityReadOnly.IncidentsForSerial:input_type -> sa.Serial + 30, // 70: sa.StorageAuthorityReadOnly.KeyBlocked:input_type -> sa.SPKIHash + 60, // 71: sa.StorageAuthorityReadOnly.ListIncidents:input_type -> google.protobuf.Empty + 4, // 72: sa.StorageAuthorityReadOnly.ReplacementOrderExists:input_type -> sa.Serial + 33, // 73: sa.StorageAuthorityReadOnly.SerialsForIncident:input_type -> sa.SerialsForIncidentRequest + 44, // 74: sa.StorageAuthorityReadOnly.CheckIdentifiersPaused:input_type -> sa.PauseRequest + 0, // 75: sa.StorageAuthorityReadOnly.GetPausedIdentifiers:input_type -> sa.RegistrationID + 52, // 76: sa.StorageAuthorityReadOnly.GetRateLimitOverride:input_type -> sa.GetRateLimitOverrideRequest + 60, // 77: sa.StorageAuthorityReadOnly.GetEnabledRateLimitOverrides:input_type -> google.protobuf.Empty + 11, // 78: sa.StorageAuthority.FQDNSetExists:input_type -> sa.FQDNSetExistsRequest + 10, // 79: sa.StorageAuthority.FQDNSetTimestampsForWindow:input_type -> sa.CountFQDNSetsRequest + 26, // 80: sa.StorageAuthority.GetAuthorization2:input_type -> sa.AuthorizationID2 + 4, // 81: sa.StorageAuthority.GetCertificate:input_type -> sa.Serial + 4, // 82: sa.StorageAuthority.GetLintPrecertificate:input_type -> sa.Serial + 4, // 83: sa.StorageAuthority.GetCertificateStatus:input_type -> sa.Serial + 15, // 84: sa.StorageAuthority.GetOrder:input_type -> sa.OrderRequest + 21, // 85: sa.StorageAuthority.GetOrderForNames:input_type -> sa.GetOrderForNamesRequest + 0, // 86: sa.StorageAuthority.GetRegistration:input_type -> sa.RegistrationID + 1, // 87: sa.StorageAuthority.GetRegistrationByKey:input_type -> sa.JSONWebKey + 4, // 88: sa.StorageAuthority.GetRevocationStatus:input_type -> sa.Serial + 38, // 89: sa.StorageAuthority.GetRevokedCertsByShard:input_type -> sa.GetRevokedCertsByShardRequest + 4, // 90: sa.StorageAuthority.GetSerialMetadata:input_type -> sa.Serial + 0, // 91: sa.StorageAuthority.GetSerialsByAccount:input_type -> sa.RegistrationID + 30, // 92: sa.StorageAuthority.GetSerialsByKey:input_type -> sa.SPKIHash + 3, // 93: sa.StorageAuthority.GetValidAuthorizations2:input_type -> sa.GetValidAuthorizationsRequest + 20, // 94: sa.StorageAuthority.GetValidOrderAuthorizations2:input_type -> sa.GetOrderAuthorizationsRequest + 20, // 95: sa.StorageAuthority.GetOrderAuthorizations:input_type -> sa.GetOrderAuthorizationsRequest + 4, // 96: sa.StorageAuthority.IncidentsForSerial:input_type -> sa.Serial + 30, // 97: sa.StorageAuthority.KeyBlocked:input_type -> sa.SPKIHash + 60, // 98: sa.StorageAuthority.ListIncidents:input_type -> google.protobuf.Empty + 4, // 99: sa.StorageAuthority.ReplacementOrderExists:input_type -> sa.Serial + 33, // 100: sa.StorageAuthority.SerialsForIncident:input_type -> sa.SerialsForIncidentRequest + 44, // 101: sa.StorageAuthority.CheckIdentifiersPaused:input_type -> sa.PauseRequest + 0, // 102: sa.StorageAuthority.GetPausedIdentifiers:input_type -> sa.RegistrationID + 52, // 103: sa.StorageAuthority.GetRateLimitOverride:input_type -> sa.GetRateLimitOverrideRequest + 60, // 104: sa.StorageAuthority.GetEnabledRateLimitOverrides:input_type -> google.protobuf.Empty + 29, // 105: sa.StorageAuthority.AddBlockedKey:input_type -> sa.AddBlockedKeyRequest + 14, // 106: sa.StorageAuthority.AddCertificate:input_type -> sa.AddCertificateRequest + 14, // 107: sa.StorageAuthority.AddPrecertificate:input_type -> sa.AddCertificateRequest + 13, // 108: sa.StorageAuthority.AddSerial:input_type -> sa.AddSerialRequest + 26, // 109: sa.StorageAuthority.DeactivateAuthorization2:input_type -> sa.AuthorizationID2 + 0, // 110: sa.StorageAuthority.DeactivateRegistration:input_type -> sa.RegistrationID + 28, // 111: sa.StorageAuthority.FinalizeAuthorization2:input_type -> sa.FinalizeAuthorizationRequest + 22, // 112: sa.StorageAuthority.FinalizeOrder:input_type -> sa.FinalizeOrderRequest + 18, // 113: sa.StorageAuthority.NewOrderAndAuthzs:input_type -> sa.NewOrderAndAuthzsRequest + 61, // 114: sa.StorageAuthority.NewRegistration:input_type -> core.Registration + 27, // 115: sa.StorageAuthority.RevokeCertificate:input_type -> sa.RevokeCertificateRequest + 19, // 116: sa.StorageAuthority.SetOrderError:input_type -> sa.SetOrderErrorRequest + 15, // 117: sa.StorageAuthority.SetOrderProcessing:input_type -> sa.OrderRequest + 46, // 118: sa.StorageAuthority.UpdateRegistrationKey:input_type -> sa.UpdateRegistrationKeyRequest + 27, // 119: sa.StorageAuthority.UpdateRevokedCertificate:input_type -> sa.RevokeCertificateRequest + 40, // 120: sa.StorageAuthority.LeaseCRLShard:input_type -> sa.LeaseCRLShardRequest + 42, // 121: sa.StorageAuthority.UpdateCRLShard:input_type -> sa.UpdateCRLShardRequest + 44, // 122: sa.StorageAuthority.PauseIdentifiers:input_type -> sa.PauseRequest + 0, // 123: sa.StorageAuthority.UnpauseAccount:input_type -> sa.RegistrationID + 48, // 124: sa.StorageAuthority.AddRateLimitOverride:input_type -> sa.AddRateLimitOverrideRequest + 51, // 125: sa.StorageAuthority.DisableRateLimitOverride:input_type -> sa.DisableRateLimitOverrideRequest + 50, // 126: sa.StorageAuthority.EnableRateLimitOverride:input_type -> sa.EnableRateLimitOverrideRequest + 34, // 127: sa.StorageAuthorityAdmin.CreateIncident:input_type -> sa.CreateIncidentRequest + 35, // 128: sa.StorageAuthorityAdmin.UpdateIncident:input_type -> sa.UpdateIncidentRequest + 36, // 129: sa.StorageAuthorityAdmin.AddSerialsToIncident:input_type -> sa.AddSerialsToIncidentRequest + 12, // 130: sa.StorageAuthorityReadOnly.FQDNSetExists:output_type -> sa.Exists + 8, // 131: sa.StorageAuthorityReadOnly.FQDNSetTimestampsForWindow:output_type -> sa.Timestamps + 58, // 132: sa.StorageAuthorityReadOnly.GetAuthorization2:output_type -> core.Authorization + 62, // 133: sa.StorageAuthorityReadOnly.GetCertificate:output_type -> core.Certificate + 62, // 134: sa.StorageAuthorityReadOnly.GetLintPrecertificate:output_type -> core.Certificate + 63, // 135: sa.StorageAuthorityReadOnly.GetCertificateStatus:output_type -> core.CertificateStatus + 64, // 136: sa.StorageAuthorityReadOnly.GetOrder:output_type -> core.Order + 64, // 137: sa.StorageAuthorityReadOnly.GetOrderForNames:output_type -> core.Order + 61, // 138: sa.StorageAuthorityReadOnly.GetRegistration:output_type -> core.Registration + 61, // 139: sa.StorageAuthorityReadOnly.GetRegistrationByKey:output_type -> core.Registration + 39, // 140: sa.StorageAuthorityReadOnly.GetRevocationStatus:output_type -> sa.RevocationStatus + 65, // 141: sa.StorageAuthorityReadOnly.GetRevokedCertsByShard:output_type -> core.CRLEntry + 5, // 142: sa.StorageAuthorityReadOnly.GetSerialMetadata:output_type -> sa.SerialMetadata + 4, // 143: sa.StorageAuthorityReadOnly.GetSerialsByAccount:output_type -> sa.Serial + 4, // 144: sa.StorageAuthorityReadOnly.GetSerialsByKey:output_type -> sa.Serial + 24, // 145: sa.StorageAuthorityReadOnly.GetValidAuthorizations2:output_type -> sa.Authorizations + 24, // 146: sa.StorageAuthorityReadOnly.GetValidOrderAuthorizations2:output_type -> sa.Authorizations + 24, // 147: sa.StorageAuthorityReadOnly.GetOrderAuthorizations:output_type -> sa.Authorizations + 32, // 148: sa.StorageAuthorityReadOnly.IncidentsForSerial:output_type -> sa.Incidents + 12, // 149: sa.StorageAuthorityReadOnly.KeyBlocked:output_type -> sa.Exists + 32, // 150: sa.StorageAuthorityReadOnly.ListIncidents:output_type -> sa.Incidents + 12, // 151: sa.StorageAuthorityReadOnly.ReplacementOrderExists:output_type -> sa.Exists + 37, // 152: sa.StorageAuthorityReadOnly.SerialsForIncident:output_type -> sa.IncidentSerial + 43, // 153: sa.StorageAuthorityReadOnly.CheckIdentifiersPaused:output_type -> sa.Identifiers + 43, // 154: sa.StorageAuthorityReadOnly.GetPausedIdentifiers:output_type -> sa.Identifiers + 53, // 155: sa.StorageAuthorityReadOnly.GetRateLimitOverride:output_type -> sa.RateLimitOverrideResponse + 53, // 156: sa.StorageAuthorityReadOnly.GetEnabledRateLimitOverrides:output_type -> sa.RateLimitOverrideResponse + 12, // 157: sa.StorageAuthority.FQDNSetExists:output_type -> sa.Exists + 8, // 158: sa.StorageAuthority.FQDNSetTimestampsForWindow:output_type -> sa.Timestamps + 58, // 159: sa.StorageAuthority.GetAuthorization2:output_type -> core.Authorization + 62, // 160: sa.StorageAuthority.GetCertificate:output_type -> core.Certificate + 62, // 161: sa.StorageAuthority.GetLintPrecertificate:output_type -> core.Certificate + 63, // 162: sa.StorageAuthority.GetCertificateStatus:output_type -> core.CertificateStatus + 64, // 163: sa.StorageAuthority.GetOrder:output_type -> core.Order + 64, // 164: sa.StorageAuthority.GetOrderForNames:output_type -> core.Order + 61, // 165: sa.StorageAuthority.GetRegistration:output_type -> core.Registration + 61, // 166: sa.StorageAuthority.GetRegistrationByKey:output_type -> core.Registration + 39, // 167: sa.StorageAuthority.GetRevocationStatus:output_type -> sa.RevocationStatus + 65, // 168: sa.StorageAuthority.GetRevokedCertsByShard:output_type -> core.CRLEntry + 5, // 169: sa.StorageAuthority.GetSerialMetadata:output_type -> sa.SerialMetadata + 4, // 170: sa.StorageAuthority.GetSerialsByAccount:output_type -> sa.Serial + 4, // 171: sa.StorageAuthority.GetSerialsByKey:output_type -> sa.Serial + 24, // 172: sa.StorageAuthority.GetValidAuthorizations2:output_type -> sa.Authorizations + 24, // 173: sa.StorageAuthority.GetValidOrderAuthorizations2:output_type -> sa.Authorizations + 24, // 174: sa.StorageAuthority.GetOrderAuthorizations:output_type -> sa.Authorizations + 32, // 175: sa.StorageAuthority.IncidentsForSerial:output_type -> sa.Incidents + 12, // 176: sa.StorageAuthority.KeyBlocked:output_type -> sa.Exists + 32, // 177: sa.StorageAuthority.ListIncidents:output_type -> sa.Incidents + 12, // 178: sa.StorageAuthority.ReplacementOrderExists:output_type -> sa.Exists + 37, // 179: sa.StorageAuthority.SerialsForIncident:output_type -> sa.IncidentSerial + 43, // 180: sa.StorageAuthority.CheckIdentifiersPaused:output_type -> sa.Identifiers + 43, // 181: sa.StorageAuthority.GetPausedIdentifiers:output_type -> sa.Identifiers + 53, // 182: sa.StorageAuthority.GetRateLimitOverride:output_type -> sa.RateLimitOverrideResponse + 53, // 183: sa.StorageAuthority.GetEnabledRateLimitOverrides:output_type -> sa.RateLimitOverrideResponse + 60, // 184: sa.StorageAuthority.AddBlockedKey:output_type -> google.protobuf.Empty + 60, // 185: sa.StorageAuthority.AddCertificate:output_type -> google.protobuf.Empty + 60, // 186: sa.StorageAuthority.AddPrecertificate:output_type -> google.protobuf.Empty + 60, // 187: sa.StorageAuthority.AddSerial:output_type -> google.protobuf.Empty + 60, // 188: sa.StorageAuthority.DeactivateAuthorization2:output_type -> google.protobuf.Empty + 61, // 189: sa.StorageAuthority.DeactivateRegistration:output_type -> core.Registration + 60, // 190: sa.StorageAuthority.FinalizeAuthorization2:output_type -> google.protobuf.Empty + 60, // 191: sa.StorageAuthority.FinalizeOrder:output_type -> google.protobuf.Empty + 64, // 192: sa.StorageAuthority.NewOrderAndAuthzs:output_type -> core.Order + 61, // 193: sa.StorageAuthority.NewRegistration:output_type -> core.Registration + 60, // 194: sa.StorageAuthority.RevokeCertificate:output_type -> google.protobuf.Empty + 60, // 195: sa.StorageAuthority.SetOrderError:output_type -> google.protobuf.Empty + 60, // 196: sa.StorageAuthority.SetOrderProcessing:output_type -> google.protobuf.Empty + 61, // 197: sa.StorageAuthority.UpdateRegistrationKey:output_type -> core.Registration + 60, // 198: sa.StorageAuthority.UpdateRevokedCertificate:output_type -> google.protobuf.Empty + 41, // 199: sa.StorageAuthority.LeaseCRLShard:output_type -> sa.LeaseCRLShardResponse + 60, // 200: sa.StorageAuthority.UpdateCRLShard:output_type -> google.protobuf.Empty + 45, // 201: sa.StorageAuthority.PauseIdentifiers:output_type -> sa.PauseIdentifiersResponse + 7, // 202: sa.StorageAuthority.UnpauseAccount:output_type -> sa.Count + 49, // 203: sa.StorageAuthority.AddRateLimitOverride:output_type -> sa.AddRateLimitOverrideResponse + 60, // 204: sa.StorageAuthority.DisableRateLimitOverride:output_type -> google.protobuf.Empty + 60, // 205: sa.StorageAuthority.EnableRateLimitOverride:output_type -> google.protobuf.Empty + 31, // 206: sa.StorageAuthorityAdmin.CreateIncident:output_type -> sa.Incident + 60, // 207: sa.StorageAuthorityAdmin.UpdateIncident:output_type -> google.protobuf.Empty + 60, // 208: sa.StorageAuthorityAdmin.AddSerialsToIncident:output_type -> google.protobuf.Empty + 130, // [130:209] is the sub-list for method output_type + 51, // [51:130] is the sub-list for method input_type + 51, // [51:51] is the sub-list for extension type_name + 51, // [51:51] is the sub-list for extension extendee + 0, // [0:51] is the sub-list for field type_name } func init() { file_sa_proto_init() } @@ -4009,15 +4255,16 @@ func file_sa_proto_init() { if File_sa_proto != nil { return } + file_sa_proto_msgTypes[35].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_sa_proto_rawDesc), len(file_sa_proto_rawDesc)), NumEnums: 0, - NumMessages: 51, + NumMessages: 54, NumExtensions: 0, - NumServices: 2, + NumServices: 3, }, GoTypes: file_sa_proto_goTypes, DependencyIndexes: file_sa_proto_depIdxs, diff --git a/sa/proto/sa.proto b/sa/proto/sa.proto index b40090539c4..a589278ed4d 100644 --- a/sa/proto/sa.proto +++ b/sa/proto/sa.proto @@ -30,6 +30,7 @@ service StorageAuthorityReadOnly { rpc GetOrderAuthorizations(GetOrderAuthorizationsRequest) returns (Authorizations) {} rpc IncidentsForSerial(Serial) returns (Incidents) {} rpc KeyBlocked(SPKIHash) returns (Exists) {} + rpc ListIncidents(google.protobuf.Empty) returns (Incidents) {} rpc ReplacementOrderExists(Serial) returns (Exists) {} rpc SerialsForIncident (SerialsForIncidentRequest) returns (stream IncidentSerial) {} rpc CheckIdentifiersPaused (PauseRequest) returns (Identifiers) {} @@ -61,6 +62,7 @@ service StorageAuthority { rpc GetOrderAuthorizations(GetOrderAuthorizationsRequest) returns (Authorizations) {} rpc IncidentsForSerial(Serial) returns (Incidents) {} rpc KeyBlocked(SPKIHash) returns (Exists) {} + rpc ListIncidents(google.protobuf.Empty) returns (Incidents) {} rpc ReplacementOrderExists(Serial) returns (Exists) {} rpc SerialsForIncident (SerialsForIncidentRequest) returns (stream IncidentSerial) {} rpc CheckIdentifiersPaused (PauseRequest) returns (Identifiers) {} @@ -93,6 +95,13 @@ service StorageAuthority { rpc EnableRateLimitOverride(EnableRateLimitOverrideRequest) returns (google.protobuf.Empty) {} } +// StorageAuthorityAdmin exposes those SA methods exclusive to the admin tool. +service StorageAuthorityAdmin { + rpc CreateIncident(CreateIncidentRequest) returns (Incident) {} + rpc UpdateIncident(UpdateIncidentRequest) returns (google.protobuf.Empty) {} + rpc AddSerialsToIncident(stream AddSerialsToIncidentRequest) returns (google.protobuf.Empty) {} +} + message RegistrationID { int64 id = 1; } @@ -350,6 +359,28 @@ message SerialsForIncidentRequest { string incidentTable = 1; } +message CreateIncidentRequest { + string serialTable = 1; + string url = 2; + google.protobuf.Timestamp renewBy = 3; +} + +// UpdateIncidentRequest updates a subset of the metadata fields on the +// incidents row identified by serialTable. An empty url, nil renewBy, and +// nil enabled all mean "leave that field alone"; at least one of them must +// be set. +message UpdateIncidentRequest { + string serialTable = 1; + string url = 2; + google.protobuf.Timestamp renewBy = 3; + optional bool enabled = 4; +} + +message AddSerialsToIncidentRequest { + string serialTable = 1; + repeated string serial = 2; +} + message IncidentSerial { // Next unused field number: 6 string serial = 1; diff --git a/sa/proto/sa_grpc.pb.go b/sa/proto/sa_grpc.pb.go index 3c0df67c261..4896b53ac73 100644 --- a/sa/proto/sa_grpc.pb.go +++ b/sa/proto/sa_grpc.pb.go @@ -41,6 +41,7 @@ const ( StorageAuthorityReadOnly_GetOrderAuthorizations_FullMethodName = "/sa.StorageAuthorityReadOnly/GetOrderAuthorizations" StorageAuthorityReadOnly_IncidentsForSerial_FullMethodName = "/sa.StorageAuthorityReadOnly/IncidentsForSerial" StorageAuthorityReadOnly_KeyBlocked_FullMethodName = "/sa.StorageAuthorityReadOnly/KeyBlocked" + StorageAuthorityReadOnly_ListIncidents_FullMethodName = "/sa.StorageAuthorityReadOnly/ListIncidents" StorageAuthorityReadOnly_ReplacementOrderExists_FullMethodName = "/sa.StorageAuthorityReadOnly/ReplacementOrderExists" StorageAuthorityReadOnly_SerialsForIncident_FullMethodName = "/sa.StorageAuthorityReadOnly/SerialsForIncident" StorageAuthorityReadOnly_CheckIdentifiersPaused_FullMethodName = "/sa.StorageAuthorityReadOnly/CheckIdentifiersPaused" @@ -75,6 +76,7 @@ type StorageAuthorityReadOnlyClient interface { GetOrderAuthorizations(ctx context.Context, in *GetOrderAuthorizationsRequest, opts ...grpc.CallOption) (*Authorizations, error) IncidentsForSerial(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Incidents, error) KeyBlocked(ctx context.Context, in *SPKIHash, opts ...grpc.CallOption) (*Exists, error) + ListIncidents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Incidents, error) ReplacementOrderExists(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Exists, error) SerialsForIncident(ctx context.Context, in *SerialsForIncidentRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IncidentSerial], error) CheckIdentifiersPaused(ctx context.Context, in *PauseRequest, opts ...grpc.CallOption) (*Identifiers, error) @@ -318,6 +320,16 @@ func (c *storageAuthorityReadOnlyClient) KeyBlocked(ctx context.Context, in *SPK return out, nil } +func (c *storageAuthorityReadOnlyClient) ListIncidents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Incidents, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Incidents) + err := c.cc.Invoke(ctx, StorageAuthorityReadOnly_ListIncidents_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *storageAuthorityReadOnlyClient) ReplacementOrderExists(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Exists, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Exists) @@ -422,6 +434,7 @@ type StorageAuthorityReadOnlyServer interface { GetOrderAuthorizations(context.Context, *GetOrderAuthorizationsRequest) (*Authorizations, error) IncidentsForSerial(context.Context, *Serial) (*Incidents, error) KeyBlocked(context.Context, *SPKIHash) (*Exists, error) + ListIncidents(context.Context, *emptypb.Empty) (*Incidents, error) ReplacementOrderExists(context.Context, *Serial) (*Exists, error) SerialsForIncident(*SerialsForIncidentRequest, grpc.ServerStreamingServer[IncidentSerial]) error CheckIdentifiersPaused(context.Context, *PauseRequest) (*Identifiers, error) @@ -498,6 +511,9 @@ func (UnimplementedStorageAuthorityReadOnlyServer) IncidentsForSerial(context.Co func (UnimplementedStorageAuthorityReadOnlyServer) KeyBlocked(context.Context, *SPKIHash) (*Exists, error) { return nil, status.Errorf(codes.Unimplemented, "method KeyBlocked not implemented") } +func (UnimplementedStorageAuthorityReadOnlyServer) ListIncidents(context.Context, *emptypb.Empty) (*Incidents, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListIncidents not implemented") +} func (UnimplementedStorageAuthorityReadOnlyServer) ReplacementOrderExists(context.Context, *Serial) (*Exists, error) { return nil, status.Errorf(codes.Unimplemented, "method ReplacementOrderExists not implemented") } @@ -877,6 +893,24 @@ func _StorageAuthorityReadOnly_KeyBlocked_Handler(srv interface{}, ctx context.C return interceptor(ctx, in, info, handler) } +func _StorageAuthorityReadOnly_ListIncidents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageAuthorityReadOnlyServer).ListIncidents(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StorageAuthorityReadOnly_ListIncidents_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageAuthorityReadOnlyServer).ListIncidents(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _StorageAuthorityReadOnly_ReplacementOrderExists_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Serial) if err := dec(in); err != nil { @@ -1046,6 +1080,10 @@ var StorageAuthorityReadOnly_ServiceDesc = grpc.ServiceDesc{ MethodName: "KeyBlocked", Handler: _StorageAuthorityReadOnly_KeyBlocked_Handler, }, + { + MethodName: "ListIncidents", + Handler: _StorageAuthorityReadOnly_ListIncidents_Handler, + }, { MethodName: "ReplacementOrderExists", Handler: _StorageAuthorityReadOnly_ReplacementOrderExists_Handler, @@ -1114,6 +1152,7 @@ const ( StorageAuthority_GetOrderAuthorizations_FullMethodName = "/sa.StorageAuthority/GetOrderAuthorizations" StorageAuthority_IncidentsForSerial_FullMethodName = "/sa.StorageAuthority/IncidentsForSerial" StorageAuthority_KeyBlocked_FullMethodName = "/sa.StorageAuthority/KeyBlocked" + StorageAuthority_ListIncidents_FullMethodName = "/sa.StorageAuthority/ListIncidents" StorageAuthority_ReplacementOrderExists_FullMethodName = "/sa.StorageAuthority/ReplacementOrderExists" StorageAuthority_SerialsForIncident_FullMethodName = "/sa.StorageAuthority/SerialsForIncident" StorageAuthority_CheckIdentifiersPaused_FullMethodName = "/sa.StorageAuthority/CheckIdentifiersPaused" @@ -1171,6 +1210,7 @@ type StorageAuthorityClient interface { GetOrderAuthorizations(ctx context.Context, in *GetOrderAuthorizationsRequest, opts ...grpc.CallOption) (*Authorizations, error) IncidentsForSerial(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Incidents, error) KeyBlocked(ctx context.Context, in *SPKIHash, opts ...grpc.CallOption) (*Exists, error) + ListIncidents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Incidents, error) ReplacementOrderExists(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Exists, error) SerialsForIncident(ctx context.Context, in *SerialsForIncidentRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IncidentSerial], error) CheckIdentifiersPaused(ctx context.Context, in *PauseRequest, opts ...grpc.CallOption) (*Identifiers, error) @@ -1437,6 +1477,16 @@ func (c *storageAuthorityClient) KeyBlocked(ctx context.Context, in *SPKIHash, o return out, nil } +func (c *storageAuthorityClient) ListIncidents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Incidents, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Incidents) + err := c.cc.Invoke(ctx, StorageAuthority_ListIncidents_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *storageAuthorityClient) ReplacementOrderExists(ctx context.Context, in *Serial, opts ...grpc.CallOption) (*Exists, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Exists) @@ -1762,6 +1812,7 @@ type StorageAuthorityServer interface { GetOrderAuthorizations(context.Context, *GetOrderAuthorizationsRequest) (*Authorizations, error) IncidentsForSerial(context.Context, *Serial) (*Incidents, error) KeyBlocked(context.Context, *SPKIHash) (*Exists, error) + ListIncidents(context.Context, *emptypb.Empty) (*Incidents, error) ReplacementOrderExists(context.Context, *Serial) (*Exists, error) SerialsForIncident(*SerialsForIncidentRequest, grpc.ServerStreamingServer[IncidentSerial]) error CheckIdentifiersPaused(context.Context, *PauseRequest) (*Identifiers, error) @@ -1861,6 +1912,9 @@ func (UnimplementedStorageAuthorityServer) IncidentsForSerial(context.Context, * func (UnimplementedStorageAuthorityServer) KeyBlocked(context.Context, *SPKIHash) (*Exists, error) { return nil, status.Errorf(codes.Unimplemented, "method KeyBlocked not implemented") } +func (UnimplementedStorageAuthorityServer) ListIncidents(context.Context, *emptypb.Empty) (*Incidents, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListIncidents not implemented") +} func (UnimplementedStorageAuthorityServer) ReplacementOrderExists(context.Context, *Serial) (*Exists, error) { return nil, status.Errorf(codes.Unimplemented, "method ReplacementOrderExists not implemented") } @@ -2305,6 +2359,24 @@ func _StorageAuthority_KeyBlocked_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _StorageAuthority_ListIncidents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageAuthorityServer).ListIncidents(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StorageAuthority_ListIncidents_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageAuthorityServer).ListIncidents(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _StorageAuthority_ReplacementOrderExists_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(Serial) if err := dec(in); err != nil { @@ -2870,6 +2942,10 @@ var StorageAuthority_ServiceDesc = grpc.ServiceDesc{ MethodName: "KeyBlocked", Handler: _StorageAuthority_KeyBlocked_Handler, }, + { + MethodName: "ListIncidents", + Handler: _StorageAuthority_ListIncidents_Handler, + }, { MethodName: "ReplacementOrderExists", Handler: _StorageAuthority_ReplacementOrderExists_Handler, @@ -3004,3 +3080,179 @@ var StorageAuthority_ServiceDesc = grpc.ServiceDesc{ }, Metadata: "sa.proto", } + +const ( + StorageAuthorityAdmin_CreateIncident_FullMethodName = "/sa.StorageAuthorityAdmin/CreateIncident" + StorageAuthorityAdmin_UpdateIncident_FullMethodName = "/sa.StorageAuthorityAdmin/UpdateIncident" + StorageAuthorityAdmin_AddSerialsToIncident_FullMethodName = "/sa.StorageAuthorityAdmin/AddSerialsToIncident" +) + +// StorageAuthorityAdminClient is the client API for StorageAuthorityAdmin service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// StorageAuthorityAdmin exposes those SA methods exclusive to the admin tool. +type StorageAuthorityAdminClient interface { + CreateIncident(ctx context.Context, in *CreateIncidentRequest, opts ...grpc.CallOption) (*Incident, error) + UpdateIncident(ctx context.Context, in *UpdateIncidentRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) + AddSerialsToIncident(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[AddSerialsToIncidentRequest, emptypb.Empty], error) +} + +type storageAuthorityAdminClient struct { + cc grpc.ClientConnInterface +} + +func NewStorageAuthorityAdminClient(cc grpc.ClientConnInterface) StorageAuthorityAdminClient { + return &storageAuthorityAdminClient{cc} +} + +func (c *storageAuthorityAdminClient) CreateIncident(ctx context.Context, in *CreateIncidentRequest, opts ...grpc.CallOption) (*Incident, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Incident) + err := c.cc.Invoke(ctx, StorageAuthorityAdmin_CreateIncident_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageAuthorityAdminClient) UpdateIncident(ctx context.Context, in *UpdateIncidentRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, StorageAuthorityAdmin_UpdateIncident_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *storageAuthorityAdminClient) AddSerialsToIncident(ctx context.Context, opts ...grpc.CallOption) (grpc.ClientStreamingClient[AddSerialsToIncidentRequest, emptypb.Empty], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &StorageAuthorityAdmin_ServiceDesc.Streams[0], StorageAuthorityAdmin_AddSerialsToIncident_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[AddSerialsToIncidentRequest, emptypb.Empty]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StorageAuthorityAdmin_AddSerialsToIncidentClient = grpc.ClientStreamingClient[AddSerialsToIncidentRequest, emptypb.Empty] + +// StorageAuthorityAdminServer is the server API for StorageAuthorityAdmin service. +// All implementations must embed UnimplementedStorageAuthorityAdminServer +// for forward compatibility. +// +// StorageAuthorityAdmin exposes those SA methods exclusive to the admin tool. +type StorageAuthorityAdminServer interface { + CreateIncident(context.Context, *CreateIncidentRequest) (*Incident, error) + UpdateIncident(context.Context, *UpdateIncidentRequest) (*emptypb.Empty, error) + AddSerialsToIncident(grpc.ClientStreamingServer[AddSerialsToIncidentRequest, emptypb.Empty]) error + mustEmbedUnimplementedStorageAuthorityAdminServer() +} + +// UnimplementedStorageAuthorityAdminServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedStorageAuthorityAdminServer struct{} + +func (UnimplementedStorageAuthorityAdminServer) CreateIncident(context.Context, *CreateIncidentRequest) (*Incident, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateIncident not implemented") +} +func (UnimplementedStorageAuthorityAdminServer) UpdateIncident(context.Context, *UpdateIncidentRequest) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateIncident not implemented") +} +func (UnimplementedStorageAuthorityAdminServer) AddSerialsToIncident(grpc.ClientStreamingServer[AddSerialsToIncidentRequest, emptypb.Empty]) error { + return status.Errorf(codes.Unimplemented, "method AddSerialsToIncident not implemented") +} +func (UnimplementedStorageAuthorityAdminServer) mustEmbedUnimplementedStorageAuthorityAdminServer() {} +func (UnimplementedStorageAuthorityAdminServer) testEmbeddedByValue() {} + +// UnsafeStorageAuthorityAdminServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to StorageAuthorityAdminServer will +// result in compilation errors. +type UnsafeStorageAuthorityAdminServer interface { + mustEmbedUnimplementedStorageAuthorityAdminServer() +} + +func RegisterStorageAuthorityAdminServer(s grpc.ServiceRegistrar, srv StorageAuthorityAdminServer) { + // If the following call pancis, it indicates UnimplementedStorageAuthorityAdminServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&StorageAuthorityAdmin_ServiceDesc, srv) +} + +func _StorageAuthorityAdmin_CreateIncident_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateIncidentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageAuthorityAdminServer).CreateIncident(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StorageAuthorityAdmin_CreateIncident_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageAuthorityAdminServer).CreateIncident(ctx, req.(*CreateIncidentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StorageAuthorityAdmin_UpdateIncident_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateIncidentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StorageAuthorityAdminServer).UpdateIncident(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: StorageAuthorityAdmin_UpdateIncident_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StorageAuthorityAdminServer).UpdateIncident(ctx, req.(*UpdateIncidentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _StorageAuthorityAdmin_AddSerialsToIncident_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StorageAuthorityAdminServer).AddSerialsToIncident(&grpc.GenericServerStream[AddSerialsToIncidentRequest, emptypb.Empty]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type StorageAuthorityAdmin_AddSerialsToIncidentServer = grpc.ClientStreamingServer[AddSerialsToIncidentRequest, emptypb.Empty] + +// StorageAuthorityAdmin_ServiceDesc is the grpc.ServiceDesc for StorageAuthorityAdmin service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var StorageAuthorityAdmin_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "sa.StorageAuthorityAdmin", + HandlerType: (*StorageAuthorityAdminServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "CreateIncident", + Handler: _StorageAuthorityAdmin_CreateIncident_Handler, + }, + { + MethodName: "UpdateIncident", + Handler: _StorageAuthorityAdmin_UpdateIncident_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "AddSerialsToIncident", + Handler: _StorageAuthorityAdmin_AddSerialsToIncident_Handler, + ClientStreams: true, + }, + }, + Metadata: "sa.proto", +} diff --git a/sa/sa_test.go b/sa/sa_test.go index fc1edb45592..b57af1ddcbf 100644 --- a/sa/sa_test.go +++ b/sa/sa_test.go @@ -2869,6 +2869,40 @@ func TestIncidentsForSerial(t *testing.T) { test.AssertEquals(t, len(result.Incidents), 1) } +func TestListIncidents(t *testing.T) { + sa, _ := initSA(t) + + testSADbMap, err := DBMapForTest(vars.DBConnSAFullPerms) + test.AssertNotError(t, err, "Couldn't create test dbMap") + + resp, err := sa.ListIncidents(context.Background(), &emptypb.Empty{}) + test.AssertNotError(t, err, "ListIncidents on empty incidents table") + test.AssertEquals(t, len(resp.Incidents), 0) + + err = testSADbMap.Insert(ctx, &incidentModel{ + SerialTable: "incident_foo", + URL: "https://example.com/foo", + RenewBy: sa.clk.Now().Add(time.Hour * 24 * 7), + Enabled: false, + }) + test.AssertNotError(t, err, "inserting first incident") + err = testSADbMap.Insert(ctx, &incidentModel{ + SerialTable: "incident_bar", + URL: "https://example.com/bar", + RenewBy: sa.clk.Now().Add(time.Hour * 24 * 14), + Enabled: true, + }) + test.AssertNotError(t, err, "inserting second incident") + + resp, err = sa.ListIncidents(context.Background(), &emptypb.Empty{}) + test.AssertNotError(t, err, "ListIncidents") + test.AssertEquals(t, len(resp.Incidents), 2) + test.AssertEquals(t, resp.Incidents[0].SerialTable, "incident_foo") + test.AssertEquals(t, resp.Incidents[0].Enabled, false) + test.AssertEquals(t, resp.Incidents[1].SerialTable, "incident_bar") + test.AssertEquals(t, resp.Incidents[1].Enabled, true) +} + func TestSerialsForIncident(t *testing.T) { sa, _ := initSA(t) diff --git a/sa/saa.go b/sa/saa.go new file mode 100644 index 00000000000..79792f0d110 --- /dev/null +++ b/sa/saa.go @@ -0,0 +1,235 @@ +package sa + +import ( + "context" + "errors" + "fmt" + "io" + "strings" + + "google.golang.org/protobuf/types/known/emptypb" + + "github.com/letsencrypt/boulder/core" + "github.com/letsencrypt/boulder/db" + berrors "github.com/letsencrypt/boulder/errors" + blog "github.com/letsencrypt/boulder/log" + sapb "github.com/letsencrypt/boulder/sa/proto" +) + +// incidentSerialsBatchSize is the number of rows accumulated before flushing a +// single INSERT transaction during AddSerialsToIncident. +const incidentSerialsBatchSize = 10000 + +// SQLStorageAuthorityAdmin implements the StorageAuthorityAdmin service. +type SQLStorageAuthorityAdmin struct { + sapb.UnsafeStorageAuthorityAdminServer + + dbMap *db.WrappedMap + dbIncidentsWriteMap *db.WrappedMap + log blog.Logger +} + +var _ sapb.StorageAuthorityAdminServer = (*SQLStorageAuthorityAdmin)(nil) + +// NewSQLStorageAuthorityAdmin constructs an *SQLStorageAuthorityAdmin. +func NewSQLStorageAuthorityAdmin(dbMap *db.WrappedMap, dbIncidentsWriteMap *db.WrappedMap, logger blog.Logger) (*SQLStorageAuthorityAdmin, error) { + return &SQLStorageAuthorityAdmin{ + dbMap: dbMap, + dbIncidentsWriteMap: dbIncidentsWriteMap, + log: logger, + }, nil +} + +// CreateIncident creates a new per-incident serials table and records its +// metadata row. The new incident starts with enabled=false. +func (ssa *SQLStorageAuthorityAdmin) CreateIncident(ctx context.Context, req *sapb.CreateIncidentRequest) (*sapb.Incident, error) { + if core.IsAnyNilOrZero(req.SerialTable, req.Url, req.RenewBy) { + return nil, errIncompleteRequest + } + if !ValidIncidentTableRegexp.MatchString(req.SerialTable) { + return nil, fmt.Errorf("malformed incident %q", req.SerialTable) + } + + // The incidents table has no UNIQUE constraint on serialTable, so check for + // existing rows application-side. There is a small TOCTOU window if two + // CreateIncident calls race on the same name; the admin tool is + // operator-driven and single-user in practice, so we accept it. + var exists bool + err := ssa.dbMap.SelectOne(ctx, &exists, + `SELECT EXISTS (SELECT id FROM incidents WHERE serialTable = ? LIMIT 1)`, + req.SerialTable) + if err != nil { + return nil, fmt.Errorf("checking for existing incident: %w", err) + } + if exists { + return nil, berrors.DuplicateError("incident %q already exists", req.SerialTable) + } + + // Safety note: req.SerialTable is interpolated directly into DDL, which + // cannot be parameterized in MySQL. The regex check above restricts it to + // [a-zA-Z0-9_]. IF NOT EXISTS makes this step idempotent so that a crash + // between DDL and the metadata INSERT below can be recovered by rerunning. + _, err = ssa.dbIncidentsWriteMap.ExecContext(ctx, fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s ( + serial varchar(255) NOT NULL, + registrationID bigint(20) unsigned NULL, + orderID bigint(20) unsigned NULL, + lastNoticeSent datetime NULL, + PRIMARY KEY (serial), + KEY registrationID_idx (registrationID), + KEY orderID_idx (orderID) + ) CHARSET=utf8mb4`, req.SerialTable)) + if err != nil { + return nil, fmt.Errorf("creating incident %q: %w", req.SerialTable, err) + } + + incident := &incidentModel{ + SerialTable: req.SerialTable, + URL: req.Url, + RenewBy: req.RenewBy.AsTime(), + Enabled: false, + } + err = ssa.dbMap.Insert(ctx, incident) + if err != nil { + return nil, fmt.Errorf("inserting incident metadata row for %q: %w", req.SerialTable, err) + } + + pb := incidentModelToPB(*incident) + + return &pb, nil +} + +// UpdateIncident updates the url, renewBy, and/or enabled fields on the +// incidents metadata row identified by serialTable. An empty req.Url, nil +// req.RenewBy, and nil req.Enabled all leave their respective fields +// unchanged. At least one of them must be set. +func (ssa *SQLStorageAuthorityAdmin) UpdateIncident(ctx context.Context, req *sapb.UpdateIncidentRequest) (*emptypb.Empty, error) { + if core.IsAnyNilOrZero(req.SerialTable) { + return nil, errIncompleteRequest + } + if req.Url == "" && req.RenewBy == nil && req.Enabled == nil { + return nil, errors.New("at least one of url, renewBy, or enabled must be set") + } + + var sets []string + var args []any + if req.Url != "" { + sets = append(sets, "url = ?") + args = append(args, req.Url) + } + if req.RenewBy != nil { + sets = append(sets, "renewBy = ?") + args = append(args, req.RenewBy.AsTime()) + } + if req.Enabled != nil { + sets = append(sets, "enabled = ?") + args = append(args, *req.Enabled) + } + args = append(args, req.SerialTable) + + res, err := ssa.dbMap.ExecContext(ctx, + fmt.Sprintf("UPDATE incidents SET %s WHERE serialTable = ?", strings.Join(sets, ", ")), + args...) + if err != nil { + return nil, fmt.Errorf("updating incident %q: %w", req.SerialTable, err) + } + affected, err := res.RowsAffected() + if err != nil { + return nil, fmt.Errorf("reading rows affected: %w", err) + } + if affected == 0 { + return nil, berrors.NotFoundError("no incident found with serialTable %q", req.SerialTable) + } + + return &emptypb.Empty{}, nil +} + +// AddSerialsToIncident streams serials into an existing per-incident table. The +// client sends a batch of serials per message. The server accumulates up to +// incidentSerialsBatchSize across messages and inserts each batch in a single +// transaction. Only the serial field is populated; other metadata is left NULL. +func (ssa *SQLStorageAuthorityAdmin) AddSerialsToIncident(stream sapb.StorageAuthorityAdmin_AddSerialsToIncidentServer) error { + ctx := stream.Context() + + var incidentTable string + var buf []string + + flush := func() error { + if len(buf) == 0 { + return nil + } + + // Safety note: incidentTable is interpolated directly into the query + // text, which cannot be parameterized for an identifier. It was + // validated against ValidIncidentTableRegexp when the first message + // arrived, so it contains only [a-zA-Z0-9_]. + valuesPlaceholders := strings.TrimRight(strings.Repeat("(?, NULL, NULL, NULL),", len(buf)), ",") + insertArgs := make([]any, len(buf)) + for i, s := range buf { + insertArgs[i] = s + } + + // INSERT IGNORE no-ops duplicate-key violations from concurrent or + // repeated inserts, avoiding the next-key locks ON DUPLICATE KEY UPDATE + // would take. Only the serial PK can fire today; revisit if the schema + // gains a FK, CHECK, or NOT NULL column we do not populate. + query := fmt.Sprintf( + "INSERT IGNORE INTO %s (serial, registrationID, orderID, lastNoticeSent) VALUES %s", + incidentTable, valuesPlaceholders, + ) + var inserted int64 + _, err := db.WithTransaction(ctx, ssa.dbIncidentsWriteMap, func(tx db.Executor) (any, error) { + res, err := tx.ExecContext(ctx, query, insertArgs...) + if err != nil { + return nil, err + } + inserted, err = res.RowsAffected() + return nil, err + }) + if err != nil { + return fmt.Errorf("inserting batch into %q: %w", incidentTable, err) + } + ssa.log.Infof("AddSerialsToIncident %q: batch of %d, %d inserted", incidentTable, len(buf), inserted) + buf = nil + return nil + } + + for { + req, err := stream.Recv() + if err != nil { + if err == io.EOF { + break + } + return err + } + + if incidentTable == "" { + if !ValidIncidentTableRegexp.MatchString(req.SerialTable) { + return fmt.Errorf("malformed incident %q", req.SerialTable) + } + incidentTable = req.SerialTable + } else if req.SerialTable != incidentTable { + return fmt.Errorf("serialTable changed mid-stream: %q -> %q", incidentTable, req.SerialTable) + } + + for _, serial := range req.Serial { + if serial == "" { + return errors.New("empty serial in stream") + } + buf = append(buf, serial) + + if len(buf) >= incidentSerialsBatchSize { + err := flush() + if err != nil { + return err + } + } + } + } + + err := flush() + if err != nil { + return err + } + + return stream.SendAndClose(&emptypb.Empty{}) +} diff --git a/sa/saa_test.go b/sa/saa_test.go new file mode 100644 index 00000000000..b1b26e01775 --- /dev/null +++ b/sa/saa_test.go @@ -0,0 +1,337 @@ +package sa + +import ( + "context" + "crypto/rand" + "encoding/hex" + "fmt" + "io" + "testing" + "time" + + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/timestamppb" + + "github.com/letsencrypt/boulder/db" + berrors "github.com/letsencrypt/boulder/errors" + sapb "github.com/letsencrypt/boulder/sa/proto" + "github.com/letsencrypt/boulder/test" + "github.com/letsencrypt/boulder/test/vars" +) + +// randomIncidentTable returns an incident_ name suitable for use as a +// per-incident table. Callers should register a t.Cleanup to DROP the table. +func randomIncidentTable(t *testing.T) string { + t.Helper() + var b [8]byte + _, err := rand.Read(b[:]) + if err != nil { + t.Fatalf("generating random incident name: %s", err) + } + return "incident_" + hex.EncodeToString(b[:]) +} + +// fakeClientStreamingServer is a minimal ServerStream-flavoured fake for +// testing client-streaming RPCs. It drains `input` via Recv() and records +// whatever the handler passes to SendAndClose(). +type fakeClientStreamingServer[Req, Res any] struct { + grpc.ServerStream + input []*Req + cursor int + sent *Res +} + +func (s *fakeClientStreamingServer[Req, Res]) Recv() (*Req, error) { + if s.cursor >= len(s.input) { + return nil, io.EOF + } + m := s.input[s.cursor] + s.cursor++ + return m, nil +} + +func (s *fakeClientStreamingServer[Req, Res]) SendAndClose(m *Res) error { + s.sent = m + return nil +} + +func (s *fakeClientStreamingServer[Req, Res]) Context() context.Context { + return context.Background() +} + +// initSAAdmin constructs an SQLStorageAuthorityAdmin and returns it alongside +// the boulder_sa and incidents_sa read maps for use in test assertions. +func initSAAdmin(t *testing.T) (*SQLStorageAuthorityAdmin, *db.WrappedMap, *db.WrappedMap) { + t.Helper() + + dbMap, err := DBMapForTest(vars.DBConnSA) + if err != nil { + t.Fatalf("Failed to create dbMap: %s", err) + } + dbIncidentsMap, err := DBMapForTest(vars.DBConnIncidents) + if err != nil { + t.Fatalf("Failed to create dbIncidentsMap: %s", err) + } + dbIncidentsWriteMap, err := DBMapForTest(vars.DBConnIncidentsAdmin) + if err != nil { + t.Fatalf("Failed to create dbIncidentsWriteMap: %s", err) + } + + saa, err := NewSQLStorageAuthorityAdmin(dbMap, dbIncidentsWriteMap, log) + if err != nil { + t.Fatalf("Failed to create SA admin impl: %s", err) + } + + t.Cleanup(test.ResetBoulderTestDatabase(t)) + return saa, dbMap, dbIncidentsMap +} + +func TestCreateIncident(t *testing.T) { + saa, _, _ := initSAAdmin(t) + t.Cleanup(test.ResetIncidentsTestDatabase(t)) + + testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms) + test.AssertNotError(t, err, "Couldn't create test dbMap") + + serialTable := randomIncidentTable(t) + t.Cleanup(func() { + _, err := testIncidentsDbMap.ExecContext(ctx, fmt.Sprintf("DROP TABLE IF EXISTS %s", serialTable)) + if err != nil { + t.Errorf("dropping incident table %q: %s", serialTable, err) + } + }) + + renewBy := time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC) + + inc, err := saa.CreateIncident(ctx, &sapb.CreateIncidentRequest{ + SerialTable: serialTable, + Url: "https://example.com/i1", + RenewBy: timestamppb.New(renewBy), + }) + test.AssertNotError(t, err, "CreateIncident") + test.Assert(t, inc.Id != 0, "expected non-zero id") + test.AssertEquals(t, inc.SerialTable, serialTable) + test.AssertEquals(t, inc.Enabled, false) + + stream := &fakeClientStreamingServer[sapb.AddSerialsToIncidentRequest, emptypb.Empty]{ + input: []*sapb.AddSerialsToIncidentRequest{ + {SerialTable: serialTable, Serial: []string{"aa11"}}, + }, + } + err = saa.AddSerialsToIncident(stream) + test.AssertNotError(t, err, "AddSerialsToIncident on new table") +} + +func TestCreateIncidentDuplicate(t *testing.T) { + saa, _, _ := initSAAdmin(t) + t.Cleanup(test.ResetIncidentsTestDatabase(t)) + + testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms) + test.AssertNotError(t, err, "Couldn't create test dbMap") + + serialTable := randomIncidentTable(t) + t.Cleanup(func() { + _, err := testIncidentsDbMap.ExecContext(ctx, fmt.Sprintf("DROP TABLE IF EXISTS %s", serialTable)) + if err != nil { + t.Errorf("dropping incident table %q: %s", serialTable, err) + } + }) + + req := &sapb.CreateIncidentRequest{ + SerialTable: serialTable, + Url: "https://example.com/dup", + RenewBy: timestamppb.New(time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC)), + } + _, err = saa.CreateIncident(ctx, req) + test.AssertNotError(t, err, "first CreateIncident") + + _, err = saa.CreateIncident(ctx, req) + test.AssertErrorIs(t, err, berrors.Duplicate) +} + +func TestCreateIncidentMalformedName(t *testing.T) { + saa, _, _ := initSAAdmin(t) + + cases := []struct { + name string + input string + }{ + {name: "wrong prefix", input: "something_foo"}, + {name: "empty suffix", input: "incident_"}, + {name: "bad chars", input: "incident_has spaces"}, + {name: "sql injection", input: "incident_foo; DROP TABLE users;--"}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := saa.CreateIncident(ctx, &sapb.CreateIncidentRequest{ + SerialTable: tc.input, + Url: "https://example.com/x", + RenewBy: timestamppb.New(time.Now().Add(time.Hour)), + }) + test.AssertError(t, err, "expected error for malformed name") + }) + } +} + +func TestAddSerialsToIncident(t *testing.T) { + saa, _, dbIncidentsMap := initSAAdmin(t) + t.Cleanup(test.ResetIncidentsTestDatabase(t)) + + testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms) + test.AssertNotError(t, err, "Couldn't create test dbMap") + + serialTable := randomIncidentTable(t) + t.Cleanup(func() { + _, err := testIncidentsDbMap.ExecContext(ctx, fmt.Sprintf("DROP TABLE IF EXISTS %s", serialTable)) + if err != nil { + t.Errorf("dropping incident table %q: %s", serialTable, err) + } + }) + + _, err = saa.CreateIncident(ctx, &sapb.CreateIncidentRequest{ + SerialTable: serialTable, + Url: "https://example.com/x", + RenewBy: timestamppb.New(time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC)), + }) + test.AssertNotError(t, err, "CreateIncident") + + err = saa.AddSerialsToIncident(&fakeClientStreamingServer[sapb.AddSerialsToIncidentRequest, emptypb.Empty]{}) + test.AssertNotError(t, err, "AddSerialsToIncident with empty stream") + + // Include a within-batch duplicate ("aa11" twice) to exercise INSERT + // IGNORE. This is the unit-testable proxy for cross-worker races, which + // can't be reproduced with a single handler. + stream := &fakeClientStreamingServer[sapb.AddSerialsToIncidentRequest, emptypb.Empty]{ + input: []*sapb.AddSerialsToIncidentRequest{ + {SerialTable: serialTable, Serial: []string{"aa11", "bb22", "aa11", "cc33"}}, + }, + } + err = saa.AddSerialsToIncident(stream) + test.AssertNotError(t, err, "AddSerialsToIncident with within-batch duplicate") + + // Rerunning with the same serials must be a no-op: INSERT IGNORE silently + // skips the already-present rows. + rerun := &fakeClientStreamingServer[sapb.AddSerialsToIncidentRequest, emptypb.Empty]{ + input: []*sapb.AddSerialsToIncidentRequest{ + {SerialTable: serialTable, Serial: []string{"aa11", "bb22", "cc33"}}, + }, + } + err = saa.AddSerialsToIncident(rerun) + test.AssertNotError(t, err, "AddSerialsToIncident rerun") + + var got []incidentSerialModel + _, err = dbIncidentsMap.Select(ctx, &got, + fmt.Sprintf(`SELECT serial, registrationID, orderID, lastNoticeSent FROM %s`, serialTable)) + test.AssertNotError(t, err, "selecting inserted rows") + test.AssertEquals(t, len(got), 3) + + for _, r := range got { + test.Assert(t, r.RegistrationID == nil, "registrationID should be NULL for "+r.Serial) + test.Assert(t, r.OrderID == nil, "orderID should be NULL for "+r.Serial) + test.Assert(t, r.LastNoticeSent == nil, "lastNoticeSent should be NULL for "+r.Serial) + } +} + +func TestUpdateIncident(t *testing.T) { + saa, dbMap, _ := initSAAdmin(t) + t.Cleanup(test.ResetIncidentsTestDatabase(t)) + + testIncidentsDbMap, err := DBMapForTest(vars.DBConnIncidentsFullPerms) + test.AssertNotError(t, err, "Couldn't create test dbMap") + + serialTable := randomIncidentTable(t) + t.Cleanup(func() { + _, err := testIncidentsDbMap.ExecContext(ctx, fmt.Sprintf("DROP TABLE IF EXISTS %s", serialTable)) + if err != nil { + t.Errorf("dropping incident table %q: %s", serialTable, err) + } + }) + + originalRenewBy := time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC) + _, err = saa.CreateIncident(ctx, &sapb.CreateIncidentRequest{ + SerialTable: serialTable, + Url: "https://example.com/v1", + RenewBy: timestamppb.New(originalRenewBy), + }) + test.AssertNotError(t, err, "CreateIncident") + + _, err = saa.UpdateIncident(ctx, &sapb.UpdateIncidentRequest{ + SerialTable: serialTable, + Url: "https://example.com/v2", + }) + test.AssertNotError(t, err, "UpdateIncident url-only") + + var got incidentModel + err = dbMap.SelectOne(ctx, &got, `SELECT id, serialTable, url, renewBy, enabled FROM incidents WHERE serialTable = ?`, serialTable) + test.AssertNotError(t, err, "reading back row") + test.AssertEquals(t, got.URL, "https://example.com/v2") + test.Assert(t, got.RenewBy.Equal(originalRenewBy), "renewBy should be unchanged") + + newRenewBy := time.Date(2031, 6, 1, 0, 0, 0, 0, time.UTC) + _, err = saa.UpdateIncident(ctx, &sapb.UpdateIncidentRequest{ + SerialTable: serialTable, + RenewBy: timestamppb.New(newRenewBy), + }) + test.AssertNotError(t, err, "UpdateIncident renewBy-only") + err = dbMap.SelectOne(ctx, &got, `SELECT id, serialTable, url, renewBy, enabled FROM incidents WHERE serialTable = ?`, serialTable) + test.AssertNotError(t, err, "reading back row") + test.AssertEquals(t, got.URL, "https://example.com/v2") + test.Assert(t, got.RenewBy.Equal(newRenewBy), "renewBy should be updated") + test.AssertEquals(t, got.Enabled, false) + + enableTrue := true + _, err = saa.UpdateIncident(ctx, &sapb.UpdateIncidentRequest{ + SerialTable: serialTable, + Enabled: &enableTrue, + }) + test.AssertNotError(t, err, "UpdateIncident enabled=true") + err = dbMap.SelectOne(ctx, &got, `SELECT id, serialTable, url, renewBy, enabled FROM incidents WHERE serialTable = ?`, serialTable) + test.AssertNotError(t, err, "reading back row") + test.AssertEquals(t, got.URL, "https://example.com/v2") + test.Assert(t, got.RenewBy.Equal(newRenewBy), "renewBy should be unchanged") + test.AssertEquals(t, got.Enabled, true) + + enableFalse := false + _, err = saa.UpdateIncident(ctx, &sapb.UpdateIncidentRequest{ + SerialTable: serialTable, + Enabled: &enableFalse, + }) + test.AssertNotError(t, err, "UpdateIncident enabled=false") + err = dbMap.SelectOne(ctx, &got, `SELECT id, serialTable, url, renewBy, enabled FROM incidents WHERE serialTable = ?`, serialTable) + test.AssertNotError(t, err, "reading back row") + test.AssertEquals(t, got.Enabled, false) + + _, err = saa.UpdateIncident(ctx, &sapb.UpdateIncidentRequest{SerialTable: serialTable}) + test.AssertError(t, err, "expected error when no fields set") + + _, err = saa.UpdateIncident(ctx, &sapb.UpdateIncidentRequest{ + SerialTable: "incident_does_not_exist", + Enabled: &enableTrue, + }) + test.AssertErrorIs(t, err, berrors.NotFound) +} + +func TestAddSerialsToIncidentMalformedName(t *testing.T) { + saa, _, _ := initSAAdmin(t) + stream := &fakeClientStreamingServer[sapb.AddSerialsToIncidentRequest, emptypb.Empty]{ + input: []*sapb.AddSerialsToIncidentRequest{ + {SerialTable: "not_an_incident_table", Serial: []string{"aa"}}, + }, + } + err := saa.AddSerialsToIncident(stream) + test.AssertError(t, err, "expected error for malformed incident") +} + +func TestAddSerialsToIncidentMidStreamRetargeting(t *testing.T) { + saa, _, _ := initSAAdmin(t) + stream := &fakeClientStreamingServer[sapb.AddSerialsToIncidentRequest, emptypb.Empty]{ + input: []*sapb.AddSerialsToIncidentRequest{ + {SerialTable: "incident_one", Serial: []string{"aa11"}}, + {SerialTable: "incident_two", Serial: []string{"bb22"}}, + }, + } + err := saa.AddSerialsToIncident(stream) + test.AssertError(t, err, "expected error for mid-stream serialTable change") + test.AssertContains(t, err.Error(), "serialTable changed mid-stream") +} diff --git a/sa/saro.go b/sa/saro.go index ac414a1db24..17ff56f7fa0 100644 --- a/sa/saro.go +++ b/sa/saro.go @@ -28,7 +28,7 @@ import ( ) var ( - validIncidentTableRegexp = regexp.MustCompile(`^incident_[0-9a-zA-Z_]{1,100}$`) + ValidIncidentTableRegexp = regexp.MustCompile(`^incident_[0-9a-zA-Z_]{1,100}$`) ) // SQLStorageAuthorityRO defines a read-only subset of a Storage Authority @@ -738,6 +738,24 @@ func (ssa *SQLStorageAuthorityRO) IncidentsForSerial(ctx context.Context, req *s return &sapb.Incidents{Incidents: incidentsForSerial}, nil } +// ListIncidents returns every incidents row (enabled or disabled), ordered by id. +func (ssa *SQLStorageAuthorityRO) ListIncidents(ctx context.Context, _ *emptypb.Empty) (*sapb.Incidents, error) { + var incidents []incidentModel + _, err := ssa.dbReadOnlyMap.Select(ctx, &incidents, `SELECT * FROM incidents ORDER BY id`) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return &sapb.Incidents{}, nil + } + return nil, err + } + pbs := make([]*sapb.Incident, len(incidents)) + for i, inc := range incidents { + pb := incidentModelToPB(inc) + pbs[i] = &pb + } + return &sapb.Incidents{Incidents: pbs}, nil +} + // SerialsForIncident queries the provided incident table and returns the // resulting rows as a stream of `*sapb.IncidentSerial`s. An `io.EOF` error // signals that there are no more serials to send. If the incident table in @@ -750,7 +768,7 @@ func (ssa *SQLStorageAuthorityRO) SerialsForIncident(req *sapb.SerialsForInciden } // Check that `req.IncidentTable` is a valid incident table name. - if !validIncidentTableRegexp.MatchString(req.IncidentTable) { + if !ValidIncidentTableRegexp.MatchString(req.IncidentTable) { return fmt.Errorf("malformed table name %q", req.IncidentTable) } diff --git a/test/config-next/proxysql/admin_dburl b/test/config-next/proxysql/admin_dburl new file mode 100644 index 00000000000..1878771632a --- /dev/null +++ b/test/config-next/proxysql/admin_dburl @@ -0,0 +1 @@ +incidents_sa_admin@tcp(boulder-proxysql:6033)/incidents_sa?readTimeout=14s&timeout=1s diff --git a/test/config-next/sa.json b/test/config-next/sa.json index 3f87d207a38..293b30e814a 100644 --- a/test/config-next/sa.json +++ b/test/config-next/sa.json @@ -12,6 +12,10 @@ "dbConnectFile": "test/secrets/incidents_dburl", "maxOpenConns": 100 }, + "incidentsWriteDB": { + "dbConnectFile": "test/secrets/admin_dburl", + "maxOpenConns": 100 + }, "lagFactor": "200ms", "tls": { "caCertFile": "test/certs/ipki/minica.pem", @@ -37,6 +41,11 @@ "ra.boulder" ] }, + "sa.StorageAuthorityAdmin": { + "clientNames": [ + "admin.boulder" + ] + }, "grpc.health.v1.Health": { "clientNames": [ "health-checker.boulder", diff --git a/test/config-next/vitess/admin_dburl b/test/config-next/vitess/admin_dburl new file mode 100644 index 00000000000..60f05588489 --- /dev/null +++ b/test/config-next/vitess/admin_dburl @@ -0,0 +1 @@ +incidents_sa_admin@tcp(boulder-vitess:33577)/incidents_sa?readTimeout=14s&timeout=1s diff --git a/test/config/proxysql/admin_dburl b/test/config/proxysql/admin_dburl new file mode 100644 index 00000000000..1878771632a --- /dev/null +++ b/test/config/proxysql/admin_dburl @@ -0,0 +1 @@ +incidents_sa_admin@tcp(boulder-proxysql:6033)/incidents_sa?readTimeout=14s&timeout=1s diff --git a/test/config/vitess/admin_dburl b/test/config/vitess/admin_dburl new file mode 100644 index 00000000000..60f05588489 --- /dev/null +++ b/test/config/vitess/admin_dburl @@ -0,0 +1 @@ +incidents_sa_admin@tcp(boulder-vitess:33577)/incidents_sa?readTimeout=14s&timeout=1s diff --git a/test/entrypoint.sh b/test/entrypoint.sh index f24758e2afe..510e7f1c9c4 100755 --- a/test/entrypoint.sh +++ b/test/entrypoint.sh @@ -14,6 +14,7 @@ DB_URL_FILES=( badkeyrevoker_dburl cert_checker_dburl incidents_dburl + admin_dburl revoker_dburl sa_dburl sa_ro_dburl diff --git a/test/proxysql/proxysql.cnf b/test/proxysql/proxysql.cnf index e8c7a68272a..18cc6732934 100644 --- a/test/proxysql/proxysql.cnf +++ b/test/proxysql/proxysql.cnf @@ -100,6 +100,9 @@ mysql_users = }, { username = "incidents_sa"; + }, + { + username = "incidents_sa_admin"; } ); mysql_query_rules = diff --git a/test/vars/vars.go b/test/vars/vars.go index 238db4085fd..0970bd8bc87 100644 --- a/test/vars/vars.go +++ b/test/vars/vars.go @@ -26,6 +26,8 @@ var ( DBInfoSchemaRoot = dsn("root", "information_schema") // DBConnIncidents is the incidents database connection. DBConnIncidents = dsn("incidents_sa", "incidents_sa") + // DBConnIncidentsAdmin is the incidents database connection with create/write perms. + DBConnIncidentsAdmin = dsn("incidents_sa_admin", "incidents_sa") // DBConnIncidentsFullPerms is the incidents database connection with full perms. DBConnIncidentsFullPerms = dsn("test_setup", "incidents_sa") )