Update github.com/google/safebrowsing and block on database health (#2837)

Update github.com/google/safebrowsing and block on database health before starting VA 
before starting `boulder-va`.

```
$ go test .
ok  	github.com/google/safebrowsing	4.510s

$ go test .
ok  	github.com/golang/protobuf/ptypes	0.002s
```

Fixes #2742.
This commit is contained in:
Roland Bracewell Shoemaker 2017-06-28 06:44:58 -07:00 committed by Daniel McCarney
parent 71f8ae0e87
commit f5bc9e892a
12 changed files with 793 additions and 216 deletions

8
Godeps/Godeps.json generated
View File

@ -114,6 +114,10 @@
"ImportPath": "github.com/golang/protobuf/proto",
"Rev": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317"
},
{
"ImportPath": "github.com/golang/protobuf/ptypes/duration",
"Rev": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317"
},
{
"ImportPath": "github.com/google/certificate-transparency-go",
"Rev": "0dac42a6ed448ba220ee315abfaa6d26fd5fc9bb"
@ -144,11 +148,11 @@
},
{
"ImportPath": "github.com/google/safebrowsing",
"Rev": "fc74adc270b82ff5a2f288fa84e40213eae713c5"
"Rev": "a8c029efb52bae66853e05241150ab338e98fbc7"
},
{
"ImportPath": "github.com/google/safebrowsing/internal/safebrowsing_proto",
"Rev": "fc74adc270b82ff5a2f288fa84e40213eae713c5"
"Rev": "a8c029efb52bae66853e05241150ab338e98fbc7"
},
{
"ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus",

View File

@ -3,9 +3,11 @@
package main
import (
"context"
"errors"
"os"
"path/filepath"
"time"
safebrowsingv4 "github.com/google/safebrowsing"
"github.com/letsencrypt/boulder/cmd"
@ -119,6 +121,12 @@ func newGoogleSafeBrowsingV4(gsb *cmd.GoogleSafeBrowsingConfig, logger blog.Logg
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*60)
defer cancel() // avoid leak
err = sb.WaitUntilReady(ctx)
if err != nil {
return nil, err
}
return gsbAdapter{sb}, nil
}

View File

@ -0,0 +1,114 @@
// Code generated by protoc-gen-go.
// source: github.com/golang/protobuf/ptypes/duration/duration.proto
// DO NOT EDIT!
/*
Package duration is a generated protocol buffer package.
It is generated from these files:
github.com/golang/protobuf/ptypes/duration/duration.proto
It has these top-level messages:
Duration
*/
package duration
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
//
type Duration struct {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
}
func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (*Duration) XXX_WellKnownType() string { return "Duration" }
func init() {
proto.RegisterType((*Duration)(nil), "google.protobuf.Duration")
}
func init() {
proto.RegisterFile("github.com/golang/protobuf/ptypes/duration/duration.proto", fileDescriptor0)
}
var fileDescriptor0 = []byte{
// 189 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xb2, 0x4c, 0xcf, 0x2c, 0xc9,
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0xcf, 0x49, 0xcc, 0x4b, 0xd7, 0x2f, 0x28,
0xca, 0x2f, 0xc9, 0x4f, 0x2a, 0x4d, 0xd3, 0x2f, 0x28, 0xa9, 0x2c, 0x48, 0x2d, 0xd6, 0x4f, 0x29,
0x2d, 0x4a, 0x2c, 0xc9, 0xcc, 0xcf, 0x83, 0x33, 0xf4, 0xc0, 0x2a, 0x84, 0xf8, 0xd3, 0xf3, 0xf3,
0xd3, 0x73, 0x52, 0xf5, 0x60, 0xea, 0x95, 0xac, 0xb8, 0x38, 0x5c, 0xa0, 0x4a, 0x84, 0x24, 0xb8,
0xd8, 0x8b, 0x53, 0x93, 0xf3, 0xf3, 0x52, 0x8a, 0x25, 0x18, 0x15, 0x18, 0x35, 0x98, 0x83, 0x60,
0x5c, 0x21, 0x11, 0x2e, 0xd6, 0xbc, 0xc4, 0xbc, 0xfc, 0x62, 0x09, 0x26, 0x05, 0x46, 0x0d, 0xd6,
0x20, 0x08, 0xc7, 0xa9, 0x86, 0x4b, 0x38, 0x39, 0x3f, 0x57, 0x0f, 0xcd, 0x48, 0x27, 0x5e, 0x98,
0x81, 0x01, 0x20, 0x91, 0x00, 0xc6, 0x28, 0x2d, 0xe2, 0xdd, 0xbb, 0x80, 0x91, 0x71, 0x11, 0x13,
0xb3, 0x7b, 0x80, 0xd3, 0x2a, 0x26, 0x39, 0x77, 0x88, 0xb9, 0x01, 0x50, 0xa5, 0x7a, 0xe1, 0xa9,
0x39, 0x39, 0xde, 0x79, 0xf9, 0xe5, 0x79, 0x21, 0x20, 0x2d, 0x49, 0x6c, 0x60, 0x33, 0x8c, 0x01,
0x01, 0x00, 0x00, 0xff, 0xff, 0x62, 0xfb, 0xb1, 0x51, 0x0e, 0x01, 0x00, 0x00,
}

View File

@ -0,0 +1,98 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto3";
package google.protobuf;
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
option go_package = "github.com/golang/protobuf/ptypes/duration";
option java_package = "com.google.protobuf";
option java_outer_classname = "DurationProto";
option java_multiple_files = true;
option java_generate_equals_and_hash = true;
option objc_class_prefix = "GPB";
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (durations.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
//
message Duration {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
int64 seconds = 1;
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
int32 nanos = 2;
}

View File

@ -1,10 +1,10 @@
language: go
go:
- 1.6
- 1.7
- 1.8
script:
- test -z "$(gofmt -s -l $(find . -name '*.go' -type f -print) | tee /dev/stderr)"
- go test -v ./...
- go test -race -v ./...
- go test -v $(go list ./... | grep -v vendor)
- go test -race -v $(go list ./... | grep -v vendor)

View File

@ -21,6 +21,7 @@ import (
"net/http"
"net/url"
"strings"
"time"
pb "github.com/google/safebrowsing/internal/safebrowsing_proto"
@ -40,14 +41,14 @@ type api interface {
// netAPI is an api object that talks to the server over HTTP.
type netAPI struct {
client http.Client
client *http.Client
url *url.URL
}
// newNetAPI creates a new netAPI object pointed at the provided root URL.
// For every request, it will use the provided API key.
// If the protocol is not specified in root, then this defaults to using HTTPS.
func newNetAPI(root string, key string) (*netAPI, error) {
func newNetAPI(root string, key string, timeout time.Duration) (*netAPI, error) {
if !strings.Contains(root, "://") {
root = "https://" + root
}
@ -60,7 +61,7 @@ func newNetAPI(root string, key string) (*netAPI, error) {
q.Set("key", key)
q.Set("alt", "proto")
u.RawQuery = q.Encode()
return &netAPI{url: u}, nil
return &netAPI{url: u, client: &http.Client{Timeout: timeout}}, nil
}
// doRequests performs a POST to requestPath. It uses the marshaled form of req

View File

@ -80,7 +80,12 @@ func (c *cache) Update(req *pb.FindFullHashesRequest, resp *pb.FindFullHashesRes
if c.pttls[fullHash] == nil {
c.pttls[fullHash] = make(map[ThreatDescriptor]time.Time)
}
dur := time.Duration(tm.GetCacheDuration().Seconds) * time.Second
var dur time.Duration
if tmCacheDur := tm.GetCacheDuration(); tmCacheDur != nil {
dur = time.Duration(tm.GetCacheDuration().Seconds) * time.Second
} else {
dur = 0
}
td := ThreatDescriptor{
ThreatType: ThreatType(tm.ThreatType),
PlatformType: PlatformType(tm.PlatformType),

View File

@ -20,6 +20,7 @@ import (
"encoding/gob"
"errors"
"log"
"math/rand"
"os"
"sync"
"time"
@ -30,7 +31,11 @@ import (
// jitter is the maximum amount of time that we expect an API list update to
// actually take. We add this time to the update period time to give some
// leeway before declaring the database as stale.
const jitter = 30 * time.Second
const (
maxRetryDelay = 24 * time.Hour
baseRetryDelay = 15 * time.Minute
jitter = 30 * time.Second
)
// database tracks the state of the threat lists published by the Safe Browsing
// API. Since the global blacklist is constantly changing, the contents of the
@ -63,8 +68,10 @@ type database struct {
tfl threatsForLookup
ml sync.RWMutex // Protects tfl, err, and last
err error // Last error encountered
last time.Time // Last time the threat list were synced
err error // Last error encountered
readyCh chan struct{} // Used for waiting until not in an error state.
last time.Time // Last time the threat list were synced
updateAPIErrors uint // Number of times we attempted to contact the api and failed
log *log.Logger
}
@ -94,11 +101,14 @@ type databaseFormat struct {
// Init initializes the database from the specified file in config.DBPath.
// It reports true if the database was successfully loaded.
func (db *database) Init(config *Config, logger *log.Logger) bool {
db.mu.Lock()
defer db.mu.Unlock()
db.setError(errors.New("not intialized"))
db.config = config
db.log = logger
if db.config.DBPath == "" {
db.log.Printf("no database file specified")
db.setError(errStale)
db.setError(errors.New("no database loaded"))
return false
}
dbf, err := loadDatabase(db.config.DBPath)
@ -112,7 +122,9 @@ func (db *database) Init(config *Config, logger *log.Logger) bool {
// superset of the specified configuration.
if db.config.now().Sub(dbf.Time) > (db.config.UpdatePeriod + jitter) {
db.log.Printf("database loaded is stale")
db.setError(errStale)
db.ml.Lock()
defer db.ml.Unlock()
db.setStale()
return false
}
tfuNew := make(threatsForUpdate)
@ -120,8 +132,8 @@ func (db *database) Init(config *Config, logger *log.Logger) bool {
if row, ok := dbf.Table[td]; ok {
tfuNew[td] = row
} else {
db.log.Printf("database configuration mismatch")
db.setError(errStale)
db.log.Printf("database configuration mismatch, missing %v", td)
db.setError(errors.New("database configuration mismatch"))
return false
}
}
@ -140,15 +152,39 @@ func (db *database) Status() error {
return db.err
}
if db.config.now().Sub(db.last) > (db.config.UpdatePeriod + jitter) {
return errStale
db.setStale()
return db.err
}
return nil
}
// UpdateLag reports the amount of time in between when we expected to run
// a database update and the current time
func (db *database) UpdateLag() time.Duration {
lag := db.SinceLastUpdate()
if lag < db.config.UpdatePeriod {
return 0
}
return lag - db.config.UpdatePeriod
}
// SinceLastUpdate gives the duration since the last database update
func (db *database) SinceLastUpdate() time.Duration {
db.ml.RLock()
defer db.ml.RUnlock()
return db.config.now().Sub(db.last)
}
// Ready returns a channel that's closed when the database is ready for queries.
func (db *database) Ready() <-chan struct{} {
return db.readyCh
}
// Update synchronizes the local threat lists with those maintained by the
// global Safe Browsing API servers. If the update is successful, Status should
// report a nil error.
func (db *database) Update(api api) {
func (db *database) Update(api api) (time.Duration, bool) {
db.mu.Lock()
defer db.mu.Unlock()
@ -183,23 +219,42 @@ func (db *database) Update(api api) {
last := db.config.now()
resp, err := api.ListUpdate(req)
if err != nil {
db.log.Printf("ListUpdate failure: %v", err)
db.log.Printf("ListUpdate failure (%d): %v", db.updateAPIErrors+1, err)
db.setError(err)
return
// backoff strategy: MIN((2**N-1 * 15 minutes) * (RAND + 1), 24 hours)
n := 1 << db.updateAPIErrors
delay := time.Duration(float64(n) * (rand.Float64() + 1) * float64(baseRetryDelay))
if delay > maxRetryDelay {
delay = maxRetryDelay
}
db.updateAPIErrors++
return delay, false
}
db.updateAPIErrors = 0
// add jitter to wait time to avoid all servers lining up
nextUpdateWait := db.config.UpdatePeriod + time.Duration(rand.Int31n(60)-30)*time.Second
if resp.MinimumWaitDuration != nil {
serverMinWait := time.Duration(resp.MinimumWaitDuration.Seconds)*time.Second + time.Duration(resp.MinimumWaitDuration.Nanos)
if serverMinWait > nextUpdateWait {
nextUpdateWait = serverMinWait
db.log.Printf("Server requested next update in %v", nextUpdateWait)
}
}
if len(resp.ListUpdateResponses) != numTypes {
db.setError(errors.New("safebrowsing: threat list count mismatch"))
db.log.Printf("invalid server response: got %d, want %d threat lists",
len(resp.ListUpdateResponses), numTypes)
db.setError(errors.New("safebrowsing: threat list count mismatch"))
return
return nextUpdateWait, false
}
// Update the threat database with the response.
db.generateThreatsForUpdate()
if err := db.tfu.update(resp); err != nil {
db.log.Printf("update failure: %v", err)
db.setError(err)
return
db.log.Printf("update failure: %v", err)
db.tfu = nil
return nextUpdateWait, false
}
dbf := databaseFormat{make(threatsForUpdate), last}
for td, phs := range db.tfu {
@ -215,6 +270,8 @@ func (db *database) Update(api api) {
db.log.Printf("save failure: %v", err)
}
}
return nextUpdateWait, true
}
// Lookup looks up the full hash in the threat list and returns a partial
@ -242,10 +299,38 @@ func (db *database) setError(err error) {
db.tfu = nil
db.ml.Lock()
if db.err == nil {
db.readyCh = make(chan struct{})
}
db.tfl, db.err, db.last = nil, err, time.Time{}
db.ml.Unlock()
}
// setStale sets the error state to a stale message, without clearing
// the database state.
//
// This assumes that the db.ml lock is already held.
func (db *database) setStale() {
if db.err == nil {
db.readyCh = make(chan struct{})
}
db.err = errStale
}
// clearError clears the db error state, and unblocks any callers of
// WaitUntilReady.
//
// This assumes that the db.mu lock is already held.
func (db *database) clearError() {
db.ml.Lock()
defer db.ml.Unlock()
if db.err != nil {
close(db.readyCh)
}
db.err = nil
}
// generateThreatsForUpdate regenerates the threatsForUpdate hashes from
// the threatsForLookup. We do this to avoid holding onto the hash lists for
// a long time, needlessly occupying lots of memory.
@ -284,10 +369,11 @@ func (db *database) generateThreatsForLookups(last time.Time) {
db.ml.Lock()
wasBad := db.err != nil
db.tfl, db.err, db.last = tfl, nil, last
db.tfl, db.last = tfl, last
db.ml.Unlock()
if wasBad {
db.clearError()
db.log.Printf("database is now healthy")
}
}
@ -424,7 +510,9 @@ func (tfu threatsForUpdate) update(resp *pb.FetchThreatListUpdatesResponse) erro
return err
}
phs.SHA256 = m.GetChecksum().Sha256
if cs := m.GetChecksum(); cs != nil {
phs.SHA256 = cs.Sha256
}
if !bytes.Equal(phs.SHA256, phs.Hashes.SHA256()) {
return errors.New("safebrowsing: threat list SHA256 mismatch")
}

View File

@ -27,13 +27,13 @@ It has these top-level messages:
ThreatEntryMetadata
ThreatListDescriptor
ListThreatListsResponse
Duration
*/
package safebrowsing_proto
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import google_protobuf "github.com/golang/protobuf/ptypes/duration"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@ -42,7 +42,9 @@ var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
const _ = proto.ProtoPackageIsVersion1
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// Types of threats.
type ThreatType int32
@ -229,11 +231,11 @@ func (FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType) EnumDescri
// checking for matches in threat lists.
type ThreatInfo struct {
// The threat types to be checked.
ThreatTypes []ThreatType `protobuf:"varint,1,rep,name=threat_types,json=threatTypes,enum=safebrowsing_proto.ThreatType" json:"threat_types,omitempty"`
ThreatTypes []ThreatType `protobuf:"varint,1,rep,packed,name=threat_types,json=threatTypes,enum=safebrowsing_proto.ThreatType" json:"threat_types,omitempty"`
// The platform types to be checked.
PlatformTypes []PlatformType `protobuf:"varint,2,rep,name=platform_types,json=platformTypes,enum=safebrowsing_proto.PlatformType" json:"platform_types,omitempty"`
PlatformTypes []PlatformType `protobuf:"varint,2,rep,packed,name=platform_types,json=platformTypes,enum=safebrowsing_proto.PlatformType" json:"platform_types,omitempty"`
// The entry types to be checked.
ThreatEntryTypes []ThreatEntryType `protobuf:"varint,4,rep,name=threat_entry_types,json=threatEntryTypes,enum=safebrowsing_proto.ThreatEntryType" json:"threat_entry_types,omitempty"`
ThreatEntryTypes []ThreatEntryType `protobuf:"varint,4,rep,packed,name=threat_entry_types,json=threatEntryTypes,enum=safebrowsing_proto.ThreatEntryType" json:"threat_entry_types,omitempty"`
// The threat entries to be checked.
ThreatEntries []*ThreatEntry `protobuf:"bytes,3,rep,name=threat_entries,json=threatEntries" json:"threat_entries,omitempty"`
}
@ -243,6 +245,27 @@ func (m *ThreatInfo) String() string { return proto.CompactTextString
func (*ThreatInfo) ProtoMessage() {}
func (*ThreatInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
func (m *ThreatInfo) GetThreatTypes() []ThreatType {
if m != nil {
return m.ThreatTypes
}
return nil
}
func (m *ThreatInfo) GetPlatformTypes() []PlatformType {
if m != nil {
return m.PlatformTypes
}
return nil
}
func (m *ThreatInfo) GetThreatEntryTypes() []ThreatEntryType {
if m != nil {
return m.ThreatEntryTypes
}
return nil
}
func (m *ThreatInfo) GetThreatEntries() []*ThreatEntry {
if m != nil {
return m.ThreatEntries
@ -264,7 +287,7 @@ type ThreatMatch struct {
ThreatEntryMetadata *ThreatEntryMetadata `protobuf:"bytes,4,opt,name=threat_entry_metadata,json=threatEntryMetadata" json:"threat_entry_metadata,omitempty"`
// The cache lifetime for the returned match. Clients must not cache this
// response for more than this duration to avoid false positives.
CacheDuration *Duration `protobuf:"bytes,5,opt,name=cache_duration,json=cacheDuration" json:"cache_duration,omitempty"`
CacheDuration *google_protobuf.Duration `protobuf:"bytes,5,opt,name=cache_duration,json=cacheDuration" json:"cache_duration,omitempty"`
}
func (m *ThreatMatch) Reset() { *m = ThreatMatch{} }
@ -272,6 +295,27 @@ func (m *ThreatMatch) String() string { return proto.CompactTextStrin
func (*ThreatMatch) ProtoMessage() {}
func (*ThreatMatch) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func (m *ThreatMatch) GetThreatType() ThreatType {
if m != nil {
return m.ThreatType
}
return ThreatType_THREAT_TYPE_UNSPECIFIED
}
func (m *ThreatMatch) GetPlatformType() PlatformType {
if m != nil {
return m.PlatformType
}
return PlatformType_PLATFORM_TYPE_UNSPECIFIED
}
func (m *ThreatMatch) GetThreatEntryType() ThreatEntryType {
if m != nil {
return m.ThreatEntryType
}
return ThreatEntryType_THREAT_ENTRY_TYPE_UNSPECIFIED
}
func (m *ThreatMatch) GetThreat() *ThreatEntry {
if m != nil {
return m.Threat
@ -286,7 +330,7 @@ func (m *ThreatMatch) GetThreatEntryMetadata() *ThreatEntryMetadata {
return nil
}
func (m *ThreatMatch) GetCacheDuration() *Duration {
func (m *ThreatMatch) GetCacheDuration() *google_protobuf.Duration {
if m != nil {
return m.CacheDuration
}
@ -394,6 +438,34 @@ func (*FetchThreatListUpdatesRequest_ListUpdateRequest) Descriptor() ([]byte, []
return fileDescriptor0, []int{4, 0}
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetThreatType() ThreatType {
if m != nil {
return m.ThreatType
}
return ThreatType_THREAT_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetPlatformType() PlatformType {
if m != nil {
return m.PlatformType
}
return PlatformType_PLATFORM_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetThreatEntryType() ThreatEntryType {
if m != nil {
return m.ThreatEntryType
}
return ThreatEntryType_THREAT_ENTRY_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetState() []byte {
if m != nil {
return m.State
}
return nil
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetConstraints() *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints {
if m != nil {
return m.Constraints
@ -416,7 +488,7 @@ type FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints struct {
// 3166-1 alpha-2 format.
Region string `protobuf:"bytes,3,opt,name=region" json:"region,omitempty"`
// The compression types supported by the client.
SupportedCompressions []CompressionType `protobuf:"varint,4,rep,name=supported_compressions,json=supportedCompressions,enum=safebrowsing_proto.CompressionType" json:"supported_compressions,omitempty"`
SupportedCompressions []CompressionType `protobuf:"varint,4,rep,packed,name=supported_compressions,json=supportedCompressions,enum=safebrowsing_proto.CompressionType" json:"supported_compressions,omitempty"`
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) Reset() {
@ -430,13 +502,41 @@ func (*FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) Descriptor()
return fileDescriptor0, []int{4, 0, 0}
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) GetMaxUpdateEntries() int32 {
if m != nil {
return m.MaxUpdateEntries
}
return 0
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) GetMaxDatabaseEntries() int32 {
if m != nil {
return m.MaxDatabaseEntries
}
return 0
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) GetRegion() string {
if m != nil {
return m.Region
}
return ""
}
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) GetSupportedCompressions() []CompressionType {
if m != nil {
return m.SupportedCompressions
}
return nil
}
// Response type for threat list update requests.
type FetchThreatListUpdatesResponse struct {
// The list updates requested by the clients.
ListUpdateResponses []*FetchThreatListUpdatesResponse_ListUpdateResponse `protobuf:"bytes,1,rep,name=list_update_responses,json=listUpdateResponses" json:"list_update_responses,omitempty"`
// The minimum duration the client must wait before issuing any update
// request. If this field is not set clients may update as soon as they want.
MinimumWaitDuration *Duration `protobuf:"bytes,2,opt,name=minimum_wait_duration,json=minimumWaitDuration" json:"minimum_wait_duration,omitempty"`
MinimumWaitDuration *google_protobuf.Duration `protobuf:"bytes,2,opt,name=minimum_wait_duration,json=minimumWaitDuration" json:"minimum_wait_duration,omitempty"`
}
func (m *FetchThreatListUpdatesResponse) Reset() { *m = FetchThreatListUpdatesResponse{} }
@ -451,7 +551,7 @@ func (m *FetchThreatListUpdatesResponse) GetListUpdateResponses() []*FetchThreat
return nil
}
func (m *FetchThreatListUpdatesResponse) GetMinimumWaitDuration() *Duration {
func (m *FetchThreatListUpdatesResponse) GetMinimumWaitDuration() *google_protobuf.Duration {
if m != nil {
return m.MinimumWaitDuration
}
@ -496,6 +596,34 @@ func (*FetchThreatListUpdatesResponse_ListUpdateResponse) Descriptor() ([]byte,
return fileDescriptor0, []int{5, 0}
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetThreatType() ThreatType {
if m != nil {
return m.ThreatType
}
return ThreatType_THREAT_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetThreatEntryType() ThreatEntryType {
if m != nil {
return m.ThreatEntryType
}
return ThreatEntryType_THREAT_ENTRY_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetPlatformType() PlatformType {
if m != nil {
return m.PlatformType
}
return PlatformType_PLATFORM_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetResponseType() FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType {
if m != nil {
return m.ResponseType
}
return FetchThreatListUpdatesResponse_ListUpdateResponse_RESPONSE_TYPE_UNSPECIFIED
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetAdditions() []*ThreatEntrySet {
if m != nil {
return m.Additions
@ -510,6 +638,13 @@ func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetRemovals() []*Thr
return nil
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetNewClientState() []byte {
if m != nil {
return m.NewClientState
}
return nil
}
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetChecksum() *Checksum {
if m != nil {
return m.Checksum
@ -539,6 +674,13 @@ func (m *FindFullHashesRequest) GetClient() *ClientInfo {
return nil
}
func (m *FindFullHashesRequest) GetClientStates() [][]byte {
if m != nil {
return m.ClientStates
}
return nil
}
func (m *FindFullHashesRequest) GetThreatInfo() *ThreatInfo {
if m != nil {
return m.ThreatInfo
@ -553,10 +695,10 @@ type FindFullHashesResponse struct {
// The minimum duration the client must wait before issuing any find hashes
// request. If this field is not set, clients can issue a request as soon as
// they want.
MinimumWaitDuration *Duration `protobuf:"bytes,2,opt,name=minimum_wait_duration,json=minimumWaitDuration" json:"minimum_wait_duration,omitempty"`
MinimumWaitDuration *google_protobuf.Duration `protobuf:"bytes,2,opt,name=minimum_wait_duration,json=minimumWaitDuration" json:"minimum_wait_duration,omitempty"`
// For requested entities that did not match the threat list, how long to
// cache the response.
NegativeCacheDuration *Duration `protobuf:"bytes,3,opt,name=negative_cache_duration,json=negativeCacheDuration" json:"negative_cache_duration,omitempty"`
NegativeCacheDuration *google_protobuf.Duration `protobuf:"bytes,3,opt,name=negative_cache_duration,json=negativeCacheDuration" json:"negative_cache_duration,omitempty"`
}
func (m *FindFullHashesResponse) Reset() { *m = FindFullHashesResponse{} }
@ -571,14 +713,14 @@ func (m *FindFullHashesResponse) GetMatches() []*ThreatMatch {
return nil
}
func (m *FindFullHashesResponse) GetMinimumWaitDuration() *Duration {
func (m *FindFullHashesResponse) GetMinimumWaitDuration() *google_protobuf.Duration {
if m != nil {
return m.MinimumWaitDuration
}
return nil
}
func (m *FindFullHashesResponse) GetNegativeCacheDuration() *Duration {
func (m *FindFullHashesResponse) GetNegativeCacheDuration() *google_protobuf.Duration {
if m != nil {
return m.NegativeCacheDuration
}
@ -599,6 +741,20 @@ func (m *ClientInfo) String() string { return proto.CompactTextString
func (*ClientInfo) ProtoMessage() {}
func (*ClientInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *ClientInfo) GetClientId() string {
if m != nil {
return m.ClientId
}
return ""
}
func (m *ClientInfo) GetClientVersion() string {
if m != nil {
return m.ClientVersion
}
return ""
}
// The expected state of a client's local database.
type Checksum struct {
// The SHA256 hash of the client state; that is, of the sorted list of all
@ -611,6 +767,13 @@ func (m *Checksum) String() string { return proto.CompactTextString(m
func (*Checksum) ProtoMessage() {}
func (*Checksum) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (m *Checksum) GetSha256() []byte {
if m != nil {
return m.Sha256
}
return nil
}
// An individual threat; for example, a malicious URL or its hash
// representation. Only one of these fields should be set.
type ThreatEntry struct {
@ -626,6 +789,20 @@ func (m *ThreatEntry) String() string { return proto.CompactTextStrin
func (*ThreatEntry) ProtoMessage() {}
func (*ThreatEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *ThreatEntry) GetHash() []byte {
if m != nil {
return m.Hash
}
return nil
}
func (m *ThreatEntry) GetUrl() string {
if m != nil {
return m.Url
}
return ""
}
// A set of threats that should be added or removed from a client's local
// database.
type ThreatEntrySet struct {
@ -648,6 +825,13 @@ func (m *ThreatEntrySet) String() string { return proto.CompactTextSt
func (*ThreatEntrySet) ProtoMessage() {}
func (*ThreatEntrySet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
func (m *ThreatEntrySet) GetCompressionType() CompressionType {
if m != nil {
return m.CompressionType
}
return CompressionType_COMPRESSION_TYPE_UNSPECIFIED
}
func (m *ThreatEntrySet) GetRawHashes() *RawHashes {
if m != nil {
return m.RawHashes
@ -679,7 +863,7 @@ func (m *ThreatEntrySet) GetRiceIndices() *RiceDeltaEncoding {
// A set of raw indices to remove from a local list.
type RawIndices struct {
// The indices to remove from a lexicographically-sorted local list.
Indices []int32 `protobuf:"varint,1,rep,name=indices" json:"indices,omitempty"`
Indices []int32 `protobuf:"varint,1,rep,packed,name=indices" json:"indices,omitempty"`
}
func (m *RawIndices) Reset() { *m = RawIndices{} }
@ -687,6 +871,13 @@ func (m *RawIndices) String() string { return proto.CompactTextString
func (*RawIndices) ProtoMessage() {}
func (*RawIndices) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
func (m *RawIndices) GetIndices() []int32 {
if m != nil {
return m.Indices
}
return nil
}
// The uncompressed threat entries in hash format of a particular prefix length.
// Hashes can be anywhere from 4 to 32 bytes in size. A large majority are 4
// bytes, but some hashes are lengthened if they collide with the hash of a
@ -708,6 +899,20 @@ func (m *RawHashes) String() string { return proto.CompactTextString(
func (*RawHashes) ProtoMessage() {}
func (*RawHashes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
func (m *RawHashes) GetPrefixSize() int32 {
if m != nil {
return m.PrefixSize
}
return 0
}
func (m *RawHashes) GetRawHashes() []byte {
if m != nil {
return m.RawHashes
}
return nil
}
// The Rice-Golomb encoded data. Used for sending compressed 4-byte hashes or
// compressed removal indices.
type RiceDeltaEncoding struct {
@ -730,6 +935,34 @@ func (m *RiceDeltaEncoding) String() string { return proto.CompactTex
func (*RiceDeltaEncoding) ProtoMessage() {}
func (*RiceDeltaEncoding) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
func (m *RiceDeltaEncoding) GetFirstValue() int64 {
if m != nil {
return m.FirstValue
}
return 0
}
func (m *RiceDeltaEncoding) GetRiceParameter() int32 {
if m != nil {
return m.RiceParameter
}
return 0
}
func (m *RiceDeltaEncoding) GetNumEntries() int32 {
if m != nil {
return m.NumEntries
}
return 0
}
func (m *RiceDeltaEncoding) GetEncodedData() []byte {
if m != nil {
return m.EncodedData
}
return nil
}
// The metadata associated with a specific threat entry. The client is expected
// to know the metadata key/value pairs associated with each threat type.
type ThreatEntryMetadata struct {
@ -764,6 +997,20 @@ func (*ThreatEntryMetadata_MetadataEntry) Descriptor() ([]byte, []int) {
return fileDescriptor0, []int{15, 0}
}
func (m *ThreatEntryMetadata_MetadataEntry) GetKey() []byte {
if m != nil {
return m.Key
}
return nil
}
func (m *ThreatEntryMetadata_MetadataEntry) GetValue() []byte {
if m != nil {
return m.Value
}
return nil
}
// Describes an individual threat list. A list is defined by three parameters:
// the type of threat posed, the type of platform targeted by the threat, and
// the type of entries in the list.
@ -781,6 +1028,27 @@ func (m *ThreatListDescriptor) String() string { return proto.Compact
func (*ThreatListDescriptor) ProtoMessage() {}
func (*ThreatListDescriptor) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
func (m *ThreatListDescriptor) GetThreatType() ThreatType {
if m != nil {
return m.ThreatType
}
return ThreatType_THREAT_TYPE_UNSPECIFIED
}
func (m *ThreatListDescriptor) GetPlatformType() PlatformType {
if m != nil {
return m.PlatformType
}
return PlatformType_PLATFORM_TYPE_UNSPECIFIED
}
func (m *ThreatListDescriptor) GetThreatEntryType() ThreatEntryType {
if m != nil {
return m.ThreatEntryType
}
return ThreatEntryType_THREAT_ENTRY_TYPE_UNSPECIFIED
}
// A collection of lists available for download by the client.
type ListThreatListsResponse struct {
// The lists available for download by the client.
@ -799,30 +1067,6 @@ func (m *ListThreatListsResponse) GetThreatLists() []*ThreatListDescriptor {
return nil
}
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
type Duration struct {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
}
func (m *Duration) Reset() { *m = Duration{} }
func (m *Duration) String() string { return proto.CompactTextString(m) }
func (*Duration) ProtoMessage() {}
func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
func init() {
proto.RegisterType((*ThreatInfo)(nil), "safebrowsing_proto.ThreatInfo")
proto.RegisterType((*ThreatMatch)(nil), "safebrowsing_proto.ThreatMatch")
@ -846,7 +1090,6 @@ func init() {
proto.RegisterType((*ThreatEntryMetadata_MetadataEntry)(nil), "safebrowsing_proto.ThreatEntryMetadata.MetadataEntry")
proto.RegisterType((*ThreatListDescriptor)(nil), "safebrowsing_proto.ThreatListDescriptor")
proto.RegisterType((*ListThreatListsResponse)(nil), "safebrowsing_proto.ListThreatListsResponse")
proto.RegisterType((*Duration)(nil), "safebrowsing_proto.Duration")
proto.RegisterEnum("safebrowsing_proto.ThreatType", ThreatType_name, ThreatType_value)
proto.RegisterEnum("safebrowsing_proto.PlatformType", PlatformType_name, PlatformType_value)
proto.RegisterEnum("safebrowsing_proto.CompressionType", CompressionType_name, CompressionType_value)
@ -854,108 +1097,111 @@ func init() {
proto.RegisterEnum("safebrowsing_proto.FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType", FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType_name, FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType_value)
}
func init() { proto.RegisterFile("safebrowsing.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 1628 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x58, 0x5b, 0x6f, 0xdb, 0x46,
0x16, 0x5e, 0x49, 0xd6, 0xed, 0x48, 0xb2, 0xe5, 0xf1, 0x25, 0x8e, 0x13, 0x27, 0x59, 0x06, 0xd9,
0x0d, 0x8c, 0x85, 0xb1, 0x48, 0x90, 0x64, 0x77, 0xb1, 0xd8, 0x2d, 0x2b, 0x51, 0x36, 0x11, 0x99,
0x52, 0x47, 0x72, 0x1c, 0xb7, 0x0f, 0x04, 0x23, 0xd1, 0x31, 0x11, 0xdd, 0x42, 0x52, 0x71, 0xdc,
0x9f, 0xd0, 0xa7, 0x02, 0x45, 0x9f, 0xdb, 0xe7, 0xbe, 0x16, 0xfd, 0x01, 0xfd, 0x19, 0x7d, 0xec,
0x2f, 0x28, 0xfa, 0xdc, 0x97, 0x9e, 0x19, 0xce, 0x88, 0xd4, 0xc5, 0x8e, 0x12, 0xfb, 0x21, 0x6f,
0x33, 0x67, 0xce, 0x7c, 0x73, 0xf8, 0xcd, 0xb9, 0x0d, 0x81, 0x78, 0xd6, 0xb1, 0xfd, 0xc2, 0xed,
0x9f, 0x7a, 0x4e, 0xef, 0xe5, 0xce, 0xc0, 0xed, 0xfb, 0x7d, 0x32, 0x26, 0x33, 0xb9, 0x4c, 0xf9,
0x31, 0x0e, 0xd0, 0x3c, 0x71, 0x6d, 0xcb, 0xd7, 0x7b, 0xc7, 0x7d, 0xa2, 0x42, 0xde, 0xe7, 0x33,
0xd3, 0x3f, 0x1b, 0xd8, 0xde, 0x46, 0xec, 0x4e, 0xe2, 0xfe, 0xe2, 0x83, 0x5b, 0x3b, 0xd3, 0x3b,
0x77, 0x82, 0x5d, 0x4d, 0x54, 0xa3, 0x39, 0x7f, 0x34, 0xf6, 0xc8, 0x2e, 0x2c, 0x0e, 0x3a, 0x96,
0x7f, 0xdc, 0x77, 0xbb, 0x02, 0x24, 0xce, 0x41, 0xee, 0xcc, 0x02, 0xa9, 0x0b, 0x4d, 0x0e, 0x53,
0x18, 0x44, 0x66, 0x1e, 0xf9, 0x0c, 0x88, 0xb0, 0xc5, 0xee, 0xf9, 0xee, 0x99, 0x00, 0x5b, 0xe0,
0x60, 0x77, 0xcf, 0xb7, 0x48, 0x63, 0xca, 0x1c, 0xaf, 0xe8, 0x8f, 0x0b, 0x3c, 0x52, 0x81, 0xc5,
0x08, 0xa4, 0x83, 0x70, 0x09, 0x84, 0xcb, 0x3d, 0xb8, 0xfd, 0x0e, 0x38, 0x5a, 0x08, 0xa1, 0x70,
0x97, 0xf2, 0x73, 0x02, 0x72, 0xc1, 0xf2, 0xbe, 0xe5, 0xb7, 0x4e, 0xc8, 0xff, 0x21, 0x17, 0xa1,
0x0d, 0x59, 0x8b, 0xcd, 0xc1, 0x1a, 0x84, 0xac, 0x11, 0x0d, 0x0a, 0x63, 0xa4, 0x21, 0x67, 0xb1,
0xb9, 0x38, 0xcb, 0x47, 0x39, 0x23, 0x35, 0x58, 0x9e, 0xa2, 0x6c, 0x23, 0xc5, 0xa1, 0xe6, 0x62,
0x6c, 0x69, 0x82, 0x31, 0xf2, 0x04, 0x52, 0x81, 0x08, 0x89, 0x8a, 0xcd, 0x43, 0x94, 0x50, 0x27,
0x5f, 0xc0, 0xda, 0x98, 0x25, 0x5d, 0xdb, 0xb7, 0xda, 0x96, 0x6f, 0xe1, 0xfd, 0x31, 0x9c, 0xbf,
0xbf, 0x03, 0x67, 0x5f, 0xa8, 0xd3, 0x15, 0x7f, 0x5a, 0x48, 0x4a, 0xb0, 0xd8, 0xb2, 0x5a, 0x27,
0xb6, 0xd9, 0x1e, 0xba, 0x96, 0xef, 0xf4, 0x7b, 0x1b, 0x49, 0x8e, 0x7a, 0x73, 0x16, 0x6a, 0x59,
0xe8, 0xd0, 0x02, 0xdf, 0x23, 0xa7, 0xca, 0x37, 0x31, 0xd8, 0xa8, 0x38, 0xbd, 0x76, 0xe4, 0x1e,
0x6d, 0x8f, 0xda, 0xaf, 0x87, 0xb6, 0xe7, 0x93, 0xc7, 0x90, 0x6a, 0x75, 0x1c, 0x34, 0x9d, 0xdf,
0x65, 0x6e, 0xf6, 0x5d, 0x96, 0xb8, 0x06, 0x8b, 0x1b, 0x2a, 0xb4, 0x23, 0x8e, 0xe0, 0xa0, 0x98,
0xdf, 0x62, 0xee, 0x22, 0x47, 0xe0, 0x9b, 0x85, 0x23, 0xb0, 0xb1, 0xf2, 0x0c, 0xae, 0xcf, 0x30,
0xca, 0x1b, 0xf4, 0x7b, 0x9e, 0x4d, 0xfe, 0x0d, 0xe9, 0x6e, 0x20, 0xe2, 0x81, 0x79, 0xe1, 0x75,
0xf0, 0xbd, 0x54, 0xea, 0x2b, 0x3f, 0xa4, 0x60, 0xab, 0x62, 0xe3, 0x38, 0x58, 0xad, 0x3a, 0x9e,
0x7f, 0x30, 0x40, 0x32, 0x2f, 0xff, 0xc9, 0x43, 0x58, 0xed, 0x20, 0x9a, 0x39, 0xe4, 0x70, 0xa6,
0x1b, 0xc0, 0xc9, 0xc8, 0x2a, 0xcd, 0x42, 0xb9, 0xd0, 0x90, 0x9d, 0x50, 0x24, 0x24, 0x94, 0x74,
0x26, 0x45, 0xde, 0xe6, 0x2f, 0x0b, 0xb0, 0x3c, 0xa5, 0xf9, 0x71, 0x07, 0x62, 0xf2, 0x12, 0x81,
0xb8, 0x0a, 0x49, 0xcf, 0xc7, 0x0f, 0xe5, 0x71, 0x98, 0xa7, 0xc1, 0x84, 0xbc, 0x86, 0x5c, 0x0b,
0x3d, 0xc3, 0x77, 0x2d, 0xa7, 0xe7, 0x7b, 0x22, 0xb6, 0x6a, 0x57, 0x40, 0xf9, 0x4e, 0x29, 0x84,
0xa5, 0xd1, 0x33, 0x36, 0x7f, 0x8d, 0x41, 0x2e, 0xb2, 0x48, 0xfe, 0x01, 0xa4, 0x6b, 0xbd, 0x95,
0xb7, 0x2f, 0xd3, 0x2a, 0x23, 0x3e, 0x49, 0x8b, 0xb8, 0x12, 0xc0, 0x8a, 0xc4, 0x49, 0xfe, 0x09,
0xab, 0x4c, 0x9b, 0x45, 0xf1, 0x0b, 0xcb, 0x0b, 0xf5, 0xe3, 0x5c, 0x9f, 0x21, 0x95, 0xc5, 0x92,
0xdc, 0xb1, 0x0e, 0x29, 0xd7, 0x7e, 0xc9, 0x62, 0x9c, 0x7d, 0x79, 0x96, 0x8a, 0x19, 0xf9, 0x1c,
0xd6, 0xbd, 0xe1, 0x60, 0xd0, 0x77, 0x7d, 0xbb, 0x6d, 0xb6, 0xfa, 0xdd, 0x81, 0x6b, 0x7b, 0x1e,
0x2e, 0x5c, 0x58, 0x21, 0x4a, 0xa1, 0x1e, 0xa7, 0x79, 0x6d, 0x04, 0x11, 0x59, 0xf1, 0x94, 0xaf,
0xd3, 0x70, 0xeb, 0x3c, 0xc2, 0x44, 0x28, 0x9e, 0xc1, 0xda, 0xb8, 0xd7, 0x07, 0x72, 0x19, 0x98,
0xda, 0xfb, 0xdc, 0x41, 0xb0, 0x75, 0xec, 0x12, 0x02, 0x11, 0x5d, 0xe9, 0x4c, 0xc9, 0x3c, 0x52,
0x87, 0xb5, 0xae, 0xd3, 0x73, 0xba, 0xc3, 0xae, 0x79, 0x6a, 0x39, 0x7e, 0x98, 0x04, 0xe3, 0x73,
0x24, 0xc1, 0x15, 0xb1, 0xf5, 0x10, 0x77, 0x4a, 0xe1, 0xe6, 0xf7, 0x49, 0x20, 0xd3, 0xa7, 0x5f,
0x3e, 0x98, 0x66, 0x46, 0x41, 0xfc, 0x12, 0x51, 0x30, 0x15, 0x9d, 0x89, 0x0f, 0x8a, 0xce, 0x53,
0x28, 0xc8, 0x0b, 0x0b, 0x60, 0x16, 0x38, 0x0c, 0xbd, 0x92, 0x4b, 0xdb, 0x91, 0x83, 0xe0, 0x60,
0x37, 0x32, 0x23, 0x9f, 0x40, 0xd6, 0x6a, 0xb7, 0x1d, 0x9f, 0xfb, 0x69, 0x92, 0x7b, 0x8a, 0xf2,
0x0e, 0x22, 0x1a, 0xb6, 0x4f, 0xc3, 0x4d, 0xe4, 0x7f, 0x90, 0x71, 0xed, 0x6e, 0xff, 0x8d, 0xd5,
0xf1, 0xb0, 0xb0, 0xcf, 0x0b, 0x30, 0xda, 0x43, 0xee, 0x43, 0xb1, 0x67, 0x9f, 0x9a, 0x41, 0xee,
0x36, 0x83, 0x94, 0x92, 0xe6, 0x29, 0x65, 0x11, 0xe5, 0x41, 0x7a, 0x6f, 0xf0, 0xdc, 0xf2, 0x2f,
0xc8, 0x60, 0xe5, 0x68, 0xbd, 0xf2, 0x86, 0xdd, 0x8d, 0xcc, 0xf9, 0x9e, 0x55, 0x12, 0x3a, 0x74,
0xa4, 0xad, 0x50, 0xc8, 0x47, 0x39, 0x20, 0x5b, 0x70, 0x9d, 0x6a, 0x8d, 0x7a, 0xcd, 0x68, 0x68,
0x66, 0xf3, 0xa8, 0xae, 0x99, 0x07, 0x46, 0xa3, 0xae, 0x95, 0xf4, 0x8a, 0xae, 0x95, 0x8b, 0x7f,
0x21, 0x04, 0x16, 0xeb, 0x2a, 0x6d, 0xea, 0x6a, 0xd5, 0x3c, 0xa8, 0x97, 0xd5, 0xa6, 0x56, 0x8c,
0x91, 0x25, 0xc8, 0x55, 0x0e, 0xaa, 0x23, 0x41, 0x5c, 0xf9, 0x29, 0x06, 0x6b, 0xac, 0x30, 0x56,
0x86, 0x9d, 0xce, 0x9e, 0xe5, 0x5d, 0x41, 0xa9, 0xbe, 0x0b, 0x85, 0x28, 0x0b, 0x41, 0x9b, 0x9a,
0xa7, 0xf9, 0x56, 0xc8, 0x81, 0x37, 0x59, 0xcf, 0x13, 0xef, 0x5d, 0xcf, 0xff, 0x88, 0xc1, 0xfa,
0xa4, 0xdd, 0x97, 0xae, 0xe6, 0x57, 0x9f, 0x02, 0x48, 0x13, 0xae, 0xf5, 0xec, 0x97, 0x38, 0x7e,
0x63, 0x9b, 0x13, 0xbd, 0x55, 0x62, 0x0e, 0xcc, 0x35, 0xb9, 0xb9, 0x34, 0xd6, 0x63, 0xd5, 0x01,
0x42, 0xe6, 0xc9, 0x0d, 0xc8, 0x0a, 0xc6, 0x9d, 0x36, 0xbf, 0xac, 0x2c, 0x3a, 0x4d, 0xb0, 0xdc,
0x26, 0xf7, 0xb0, 0xa7, 0x0b, 0x16, 0xdf, 0xd8, 0xae, 0x27, 0xbf, 0x25, 0x4b, 0xc5, 0x25, 0x3d,
0x0b, 0x84, 0x8a, 0x02, 0x19, 0xe9, 0x71, 0xac, 0x34, 0x78, 0x27, 0xd6, 0x83, 0x47, 0x8f, 0x39,
0x58, 0x9e, 0x8a, 0x99, 0xf2, 0x50, 0x36, 0xe7, 0xdc, 0xff, 0xd1, 0xbf, 0x16, 0x4e, 0x90, 0x79,
0xa1, 0xc4, 0xc7, 0xa4, 0x08, 0x89, 0xa1, 0xdb, 0x11, 0x47, 0xb0, 0xa1, 0xf2, 0x7b, 0x1c, 0x16,
0xc7, 0xa3, 0x86, 0x18, 0x50, 0x8c, 0x14, 0x96, 0x68, 0x12, 0x9c, 0xab, 0xb8, 0x2c, 0xb5, 0xc6,
0x05, 0xe4, 0xbf, 0x00, 0xae, 0x75, 0x6a, 0x9e, 0x70, 0x37, 0x10, 0x57, 0xb5, 0x35, 0x0b, 0x89,
0x5a, 0xa7, 0xc2, 0x57, 0xb2, 0xae, 0x1c, 0x32, 0x57, 0x64, 0xbb, 0xd1, 0x97, 0x9c, 0x16, 0x7f,
0xb8, 0x9c, 0xeb, 0x8a, 0xb8, 0x5d, 0x0f, 0xb4, 0x28, 0x3b, 0x50, 0x8c, 0xf1, 0xf1, 0x93, 0x73,
0x71, 0x20, 0xcf, 0x0f, 0x9a, 0x85, 0x7b, 0x33, 0x01, 0x50, 0xad, 0x6c, 0x77, 0x7c, 0x4b, 0xeb,
0xb5, 0xfa, 0x6d, 0x94, 0x23, 0x0e, 0x8a, 0x84, 0x21, 0x7b, 0x90, 0xe7, 0x38, 0xd2, 0x92, 0xe4,
0xfb, 0x00, 0x71, 0x13, 0x84, 0x45, 0xca, 0xdf, 0x00, 0x42, 0x5b, 0xc9, 0x06, 0xa4, 0x25, 0x24,
0x8b, 0x87, 0x24, 0x95, 0x53, 0xe5, 0x29, 0x64, 0x47, 0x94, 0x90, 0xdb, 0x90, 0x43, 0x56, 0x8f,
0x9d, 0xb7, 0xa6, 0xe7, 0x7c, 0x69, 0x8b, 0x4e, 0x03, 0x02, 0x51, 0x03, 0x25, 0x98, 0x6e, 0x26,
0x69, 0xce, 0x47, 0x78, 0x54, 0xbe, 0x8b, 0xc1, 0xf2, 0x94, 0x5d, 0x0c, 0xf5, 0xd8, 0x71, 0xb1,
0xa0, 0x63, 0x96, 0x1c, 0x06, 0xa8, 0x09, 0x0a, 0x5c, 0xf4, 0x8c, 0x49, 0x98, 0x7f, 0xf2, 0xaf,
0x1e, 0x58, 0xae, 0x85, 0x8f, 0x19, 0xdb, 0x15, 0x3d, 0x4b, 0x81, 0x49, 0xeb, 0x52, 0xc8, 0x70,
0x7a, 0x18, 0x95, 0xe1, 0xf3, 0x92, 0x5b, 0x87, 0x22, 0xd9, 0xcf, 0xfc, 0x15, 0xf2, 0x36, 0x3b,
0x14, 0xbb, 0x96, 0xd1, 0x7b, 0x28, 0x4f, 0x73, 0x42, 0xc6, 0xba, 0x1f, 0x66, 0xe1, 0xca, 0x8c,
0xb7, 0x10, 0x96, 0xd3, 0x74, 0xd8, 0x5f, 0xb1, 0x84, 0xf1, 0x68, 0xce, 0x57, 0xd4, 0x8e, 0x1c,
0x04, 0x6f, 0x34, 0x89, 0xb2, 0xf9, 0x04, 0x0a, 0x63, 0x2b, 0x2c, 0x2c, 0x5e, 0xd9, 0x67, 0x22,
0x52, 0xd8, 0x90, 0xf5, 0x9d, 0x01, 0x23, 0x01, 0x8f, 0xc1, 0x44, 0xf9, 0x2d, 0x06, 0xab, 0x61,
0x4d, 0x2c, 0xdb, 0x5e, 0xcb, 0x75, 0x06, 0x7e, 0xdf, 0xfd, 0xb8, 0xfb, 0xef, 0xc4, 0x87, 0x77,
0x1e, 0xca, 0x31, 0x5c, 0x63, 0x9f, 0x1a, 0x7e, 0x74, 0x98, 0xc7, 0x9f, 0x8e, 0xfe, 0x99, 0xb0,
0x6e, 0x4d, 0xde, 0xcd, 0xfd, 0xf3, 0x8f, 0x19, 0xe7, 0x4c, 0xfe, 0x3d, 0xe1, 0xa0, 0xca, 0x7f,
0x20, 0x33, 0xca, 0xc9, 0x18, 0x10, 0x9e, 0x8d, 0xbd, 0x77, 0xdb, 0x13, 0xfe, 0x28, 0xa7, 0xec,
0x56, 0x7a, 0x56, 0xaf, 0x2f, 0xfb, 0xe6, 0x60, 0xb2, 0xfd, 0x55, 0x4c, 0xfe, 0xcb, 0xe1, 0x1c,
0xdc, 0x80, 0x6b, 0xcd, 0x3d, 0xaa, 0xa9, 0xcd, 0x59, 0x45, 0x37, 0x07, 0xe9, 0x7d, 0xb5, 0x7a,
0xa8, 0x52, 0x56, 0x6d, 0xd7, 0x81, 0x34, 0x6a, 0x25, 0x56, 0x80, 0x35, 0x63, 0x57, 0x37, 0x34,
0x8d, 0xea, 0xc6, 0x6e, 0x31, 0x4e, 0xd6, 0x60, 0xf9, 0xc0, 0x38, 0x54, 0x8d, 0xa6, 0x56, 0x36,
0x1b, 0xb5, 0x4a, 0x93, 0xab, 0x27, 0xb0, 0x72, 0xde, 0xae, 0xd7, 0x9a, 0x9a, 0xc1, 0x4a, 0x76,
0xf5, 0xc8, 0xdc, 0x53, 0xe9, 0x3e, 0x16, 0x6b, 0x53, 0xad, 0xd7, 0xab, 0x7a, 0x49, 0x6d, 0xea,
0x35, 0xa3, 0xb8, 0xb0, 0xfd, 0x6d, 0x0c, 0xf2, 0xd1, 0x0b, 0x62, 0x5d, 0x40, 0xbd, 0xaa, 0x36,
0x2b, 0x35, 0xba, 0x7f, 0x8e, 0x41, 0x87, 0xba, 0x51, 0xae, 0x1d, 0x36, 0xd0, 0xa0, 0x2c, 0x24,
0xab, 0xba, 0x71, 0xf0, 0x1c, 0x6d, 0x40, 0xb9, 0x6a, 0x94, 0x69, 0x4d, 0x2f, 0xe3, 0xc9, 0x69,
0x48, 0xd4, 0x1a, 0xcf, 0x8b, 0x0b, 0x6c, 0xa0, 0xd7, 0x1a, 0xc5, 0x24, 0x7a, 0x6c, 0x5e, 0x35,
0x8e, 0x4c, 0x89, 0x5c, 0x4c, 0x91, 0x65, 0x28, 0xa0, 0x59, 0x23, 0x49, 0xa3, 0x98, 0x26, 0x00,
0xa9, 0xd2, 0x1e, 0xad, 0xed, 0x6b, 0xc5, 0xcc, 0x76, 0x05, 0x96, 0x26, 0x12, 0x35, 0xb9, 0x03,
0x37, 0x4b, 0xb5, 0xfd, 0x3a, 0xf6, 0x28, 0x0d, 0xb4, 0x7d, 0x96, 0x71, 0x78, 0x1c, 0x55, 0x0f,
0xd1, 0xb0, 0x0c, 0x2c, 0x50, 0xbd, 0x84, 0x0d, 0xc9, 0xb6, 0x03, 0x4b, 0x13, 0x4e, 0x83, 0xa1,
0xbd, 0x25, 0x08, 0x47, 0x6e, 0xe8, 0xd1, 0x39, 0xbd, 0xce, 0x01, 0x45, 0x9a, 0x9f, 0xcb, 0xd3,
0x10, 0x13, 0x0d, 0xfe, 0x54, 0x37, 0x54, 0xdc, 0x50, 0xd6, 0x77, 0xb5, 0x46, 0x13, 0x3f, 0x3a,
0x0f, 0x19, 0xbd, 0x6e, 0x52, 0xd5, 0xd8, 0x45, 0xbe, 0x5f, 0xa4, 0xb8, 0xf3, 0x3c, 0xfc, 0x33,
0x00, 0x00, 0xff, 0xff, 0x08, 0xe3, 0x60, 0x1f, 0xd4, 0x13, 0x00, 0x00,
// 1636 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4f, 0x8f, 0xdb, 0xc6,
0x15, 0x2f, 0xc5, 0x95, 0xb4, 0xfb, 0xf4, 0x67, 0xb9, 0x63, 0xaf, 0x2d, 0x6f, 0x62, 0x7b, 0x43,
0x23, 0xad, 0x61, 0x14, 0x4a, 0xe1, 0x20, 0x49, 0x0b, 0x14, 0x6d, 0x58, 0x89, 0xf2, 0x12, 0xd1,
0x92, 0xca, 0x48, 0xf2, 0xda, 0xcd, 0x81, 0xa0, 0xa9, 0xd1, 0x8a, 0x88, 0x44, 0x2a, 0x9c, 0x91,
0xe5, 0xcd, 0x47, 0x28, 0xd0, 0x53, 0xd1, 0x73, 0x7b, 0xee, 0xb5, 0xe8, 0xb5, 0xdf, 0xa3, 0xc7,
0x7e, 0x82, 0xa2, 0x87, 0xde, 0x8b, 0x19, 0x0e, 0x25, 0xea, 0xcf, 0x7a, 0xd7, 0x59, 0x1f, 0x72,
0x9b, 0x79, 0x7c, 0xf3, 0x9b, 0xc7, 0xdf, 0xfb, 0x4b, 0x02, 0xa2, 0xde, 0x90, 0xbc, 0x8a, 0xa3,
0x39, 0x0d, 0xc2, 0xf3, 0xfa, 0x34, 0x8e, 0x58, 0x84, 0x56, 0x64, 0xae, 0x90, 0x1d, 0x3d, 0x38,
0x8f, 0xa2, 0xf3, 0x31, 0xf9, 0x44, 0xec, 0x5e, 0xcd, 0x86, 0x9f, 0x0c, 0x66, 0xb1, 0xc7, 0x82,
0x28, 0x4c, 0xce, 0xe8, 0x7f, 0xcf, 0x01, 0xf4, 0x46, 0x31, 0xf1, 0x98, 0x15, 0x0e, 0x23, 0x64,
0x40, 0x99, 0x89, 0x9d, 0xcb, 0x2e, 0xa6, 0x84, 0xd6, 0x94, 0x63, 0xf5, 0x71, 0xf5, 0xe9, 0x83,
0xfa, 0x26, 0x72, 0x3d, 0x39, 0xd5, 0xbb, 0x98, 0x12, 0x5c, 0x62, 0x8b, 0x35, 0x45, 0xcf, 0xa0,
0x3a, 0x1d, 0x7b, 0x6c, 0x18, 0xc5, 0x13, 0x09, 0x92, 0x13, 0x20, 0xc7, 0xdb, 0x40, 0x3a, 0x52,
0x53, 0xc0, 0x54, 0xa6, 0x99, 0x1d, 0x45, 0x5f, 0x03, 0x92, 0xb6, 0x90, 0x90, 0xc5, 0x17, 0x12,
0x6c, 0x47, 0x80, 0x3d, 0xba, 0xdc, 0x22, 0x93, 0x2b, 0x0b, 0x3c, 0x8d, 0xad, 0x0a, 0x28, 0x6a,
0x41, 0x35, 0x03, 0x19, 0x10, 0x5a, 0x53, 0x8f, 0xd5, 0xc7, 0xa5, 0xa7, 0x0f, 0xaf, 0x80, 0xc3,
0x95, 0x25, 0x54, 0x40, 0xa8, 0xfe, 0x4f, 0x15, 0x4a, 0xc9, 0xe3, 0x53, 0x8f, 0xf9, 0x23, 0xf4,
0x5b, 0x28, 0x65, 0x68, 0xab, 0x29, 0xc7, 0xca, 0x35, 0x58, 0x83, 0x25, 0x6b, 0xc8, 0x84, 0xca,
0x0a, 0x69, 0xb5, 0x9c, 0x80, 0xb8, 0x9a, 0xb3, 0x72, 0x96, 0x33, 0xe4, 0xc0, 0xc1, 0x06, 0x65,
0xb5, 0x82, 0x80, 0xba, 0x16, 0x63, 0xfb, 0x6b, 0x8c, 0xa1, 0x2f, 0xa0, 0x90, 0x88, 0x6a, 0xea,
0xb1, 0x72, 0x1d, 0xa2, 0xa4, 0x3a, 0xfa, 0x06, 0x0e, 0x57, 0x2c, 0x99, 0x10, 0xe6, 0x0d, 0x3c,
0xe6, 0xd5, 0x76, 0x04, 0xce, 0xcf, 0xae, 0xc0, 0x39, 0x95, 0xea, 0xf8, 0x16, 0xdb, 0x14, 0xa2,
0x2f, 0xa1, 0xea, 0x7b, 0xfe, 0x88, 0xb8, 0x69, 0x30, 0xd7, 0xf2, 0x02, 0xf5, 0x5e, 0x3d, 0x89,
0xf6, 0x7a, 0x1a, 0xed, 0xf5, 0xa6, 0x54, 0xc0, 0x15, 0x71, 0x20, 0xdd, 0xea, 0x7f, 0x52, 0xa0,
0xd6, 0x0a, 0xc2, 0x41, 0xc6, 0x89, 0x84, 0x62, 0xf2, 0xdd, 0x8c, 0x50, 0x86, 0x3e, 0x87, 0x82,
0x3f, 0x0e, 0x48, 0xc8, 0x84, 0x23, 0x4b, 0xdb, 0x1d, 0xd9, 0x10, 0x1a, 0x3c, 0x69, 0xb0, 0xd4,
0xce, 0x44, 0x41, 0x10, 0x0e, 0x23, 0xe1, 0xc2, 0xd2, 0xdb, 0xa2, 0x40, 0x1c, 0x96, 0x51, 0xc0,
0xd7, 0xfa, 0x73, 0xb8, 0xb7, 0xc5, 0x28, 0x3a, 0x8d, 0x42, 0x4a, 0xd0, 0xaf, 0xa0, 0x38, 0x49,
0x44, 0x22, 0x2b, 0xdf, 0xea, 0x0b, 0x71, 0x16, 0xa7, 0xfa, 0xfa, 0xdf, 0x0a, 0x70, 0xbf, 0x45,
0x98, 0x3f, 0x4a, 0x9e, 0xb6, 0x03, 0xca, 0xfa, 0xd3, 0x81, 0xc7, 0x6e, 0xfe, 0xca, 0x33, 0xb8,
0x3d, 0x0e, 0x28, 0x73, 0x67, 0x02, 0xce, 0x8d, 0x13, 0xb8, 0x34, 0xad, 0x1a, 0xdb, 0x50, 0xde,
0x6a, 0x48, 0x7d, 0x29, 0x92, 0x12, 0x8c, 0xc6, 0xeb, 0x22, 0x7a, 0xf4, 0xaf, 0x1d, 0x38, 0xd8,
0xd0, 0xfc, 0x71, 0x67, 0x61, 0xfe, 0x06, 0x59, 0x78, 0x1b, 0xf2, 0x94, 0x79, 0x8c, 0x88, 0x24,
0x2c, 0xe3, 0x64, 0x83, 0xbe, 0x83, 0x92, 0x1f, 0x85, 0x94, 0xc5, 0x5e, 0x10, 0x32, 0x2a, 0x13,
0xcb, 0x79, 0x0f, 0x94, 0xd7, 0x1b, 0x4b, 0x58, 0x9c, 0xbd, 0xe3, 0xe8, 0xdf, 0x0a, 0x94, 0x32,
0x0f, 0xd1, 0xcf, 0x01, 0x4d, 0xbc, 0x37, 0xa9, 0xf7, 0xd3, 0x9a, 0xca, 0x89, 0xcf, 0x63, 0x6d,
0xe2, 0xbd, 0x49, 0x60, 0x65, 0xd5, 0x44, 0xbf, 0x80, 0xdb, 0x5c, 0x9b, 0xa7, 0xf0, 0x2b, 0x8f,
0x2e, 0xf5, 0x73, 0x42, 0x9f, 0x23, 0x35, 0xe5, 0xa3, 0xf4, 0xc4, 0x1d, 0x28, 0xc4, 0xe4, 0x9c,
0x27, 0x38, 0x7f, 0xf3, 0x3d, 0x2c, 0x77, 0xe8, 0xf7, 0x70, 0x87, 0xce, 0xa6, 0xd3, 0x28, 0x66,
0x64, 0xe0, 0xfa, 0xd1, 0x64, 0x1a, 0x13, 0x4a, 0x83, 0x28, 0x7c, 0x6b, 0x7b, 0x68, 0x2c, 0xf5,
0x04, 0xcd, 0x87, 0x0b, 0x88, 0xcc, 0x13, 0xaa, 0xff, 0xb1, 0x08, 0x0f, 0x2e, 0x23, 0x4c, 0xa6,
0xe2, 0x05, 0x1c, 0xae, 0x46, 0x7d, 0x22, 0x4f, 0x13, 0xd3, 0x7c, 0x17, 0x1f, 0x24, 0x47, 0x57,
0x9c, 0x90, 0x88, 0xf0, 0xad, 0xf1, 0x86, 0x8c, 0xa2, 0x53, 0x38, 0x9c, 0x04, 0x61, 0x30, 0x99,
0x4d, 0xdc, 0xb9, 0x17, 0xb0, 0x65, 0x05, 0xcc, 0x5d, 0x55, 0x01, 0x6f, 0xc9, 0x73, 0x67, 0x5e,
0xc0, 0x52, 0xe1, 0xd1, 0x5f, 0xf3, 0x80, 0x36, 0xaf, 0xbe, 0x79, 0x26, 0x6d, 0x4d, 0x81, 0xdc,
0x0d, 0x52, 0x60, 0x23, 0x35, 0xd5, 0x1f, 0x94, 0x9a, 0x73, 0xa8, 0xa4, 0xde, 0x4a, 0x60, 0x76,
0x04, 0x0c, 0x7e, 0x2f, 0x1e, 0xab, 0xa7, 0x8b, 0xe4, 0xe2, 0x38, 0xb3, 0x43, 0x5f, 0xc2, 0x9e,
0x37, 0x18, 0x04, 0x4c, 0x04, 0x69, 0x5e, 0x84, 0x89, 0x7e, 0x05, 0x11, 0x5d, 0xc2, 0xf0, 0xf2,
0x10, 0xfa, 0x0d, 0xec, 0xc6, 0x64, 0x12, 0xbd, 0xf6, 0xc6, 0xb4, 0x56, 0xb8, 0x36, 0xc0, 0xe2,
0x0c, 0x7a, 0x0c, 0x5a, 0x48, 0xe6, 0x6e, 0x52, 0xb8, 0xdd, 0xa4, 0x9e, 0x14, 0x45, 0x3d, 0xa9,
0x86, 0x64, 0x9e, 0xd4, 0xf6, 0xae, 0x28, 0x2c, 0xbf, 0x84, 0x5d, 0x7f, 0x44, 0xfc, 0x6f, 0xe9,
0x6c, 0x52, 0xdb, 0x15, 0x61, 0xf5, 0xe1, 0xd6, 0x7c, 0x92, 0x3a, 0x78, 0xa1, 0xad, 0x63, 0x28,
0x67, 0x39, 0x40, 0xf7, 0xe1, 0x1e, 0x36, 0xbb, 0x1d, 0xc7, 0xee, 0x9a, 0x6e, 0xef, 0x65, 0xc7,
0x74, 0xfb, 0x76, 0xb7, 0x63, 0x36, 0xac, 0x96, 0x65, 0x36, 0xb5, 0x9f, 0x20, 0x04, 0xd5, 0x8e,
0x81, 0x7b, 0x96, 0xd1, 0x76, 0xfb, 0x9d, 0xa6, 0xd1, 0x33, 0x35, 0x05, 0xed, 0x43, 0xa9, 0xd5,
0x6f, 0x2f, 0x04, 0x39, 0xfd, 0x1f, 0x0a, 0x1c, 0xf2, 0xae, 0xd8, 0x9a, 0x8d, 0xc7, 0x27, 0x1e,
0x7d, 0x0f, 0x7d, 0xfa, 0x11, 0x54, 0xb2, 0x2c, 0x24, 0x03, 0x6a, 0x19, 0x97, 0xfd, 0x25, 0x07,
0x74, 0xbd, 0x99, 0xab, 0xef, 0xdc, 0xcc, 0xff, 0xa7, 0xc0, 0x9d, 0x75, 0xbb, 0x6f, 0xdc, 0xca,
0xdf, 0x73, 0xfe, 0xa3, 0xaf, 0xe1, 0x6e, 0x48, 0xce, 0x3d, 0x16, 0xbc, 0x26, 0xee, 0xda, 0x48,
0xa5, 0x5e, 0x05, 0x78, 0x98, 0x9e, 0x6c, 0xac, 0x8c, 0x56, 0x1d, 0x80, 0x25, 0xe7, 0xe8, 0x03,
0xd8, 0x93, 0x5c, 0x07, 0x03, 0xe1, 0xa6, 0x3d, 0xbc, 0x9b, 0x08, 0xac, 0x01, 0xfa, 0x18, 0xaa,
0xf2, 0xe1, 0x6b, 0x12, 0xd3, 0xf4, 0x2d, 0xf6, 0xb0, 0x74, 0xcf, 0xf3, 0x44, 0xa8, 0xeb, 0xb0,
0x9b, 0xc6, 0x1a, 0xef, 0x08, 0x74, 0xe4, 0x3d, 0xfd, 0xec, 0x73, 0x01, 0x56, 0xc6, 0x72, 0xa7,
0x7f, 0x9a, 0x0e, 0xe4, 0x22, 0xf2, 0x11, 0x82, 0x9d, 0x91, 0x47, 0x47, 0x52, 0x49, 0xac, 0x91,
0x06, 0xea, 0x2c, 0x1e, 0xcb, 0x2b, 0xf8, 0x52, 0xff, 0x6f, 0x0e, 0xaa, 0xab, 0xf9, 0x82, 0x6c,
0xd0, 0x32, 0xfd, 0x24, 0x5b, 0xfe, 0xae, 0xd5, 0x53, 0xf6, 0xfd, 0x55, 0x01, 0xfa, 0x35, 0x40,
0xec, 0xcd, 0xdd, 0x91, 0x08, 0x00, 0xe9, 0xa4, 0xfb, 0xdb, 0x90, 0xb0, 0x37, 0x97, 0x51, 0xb2,
0x17, 0xa7, 0x4b, 0x1e, 0x84, 0xfc, 0x74, 0x10, 0x0e, 0x02, 0x5f, 0x7c, 0xac, 0x5c, 0x1a, 0x84,
0xd8, 0x9b, 0x5b, 0x89, 0x16, 0xe6, 0x17, 0xca, 0x35, 0x6a, 0x41, 0x29, 0x0e, 0x7c, 0x92, 0xde,
0x9f, 0xcc, 0x08, 0x1f, 0x6f, 0x05, 0x08, 0x7c, 0xd2, 0x24, 0x63, 0xe6, 0x99, 0xa1, 0x1f, 0x0d,
0x82, 0xf0, 0x1c, 0x03, 0x3f, 0x29, 0x0d, 0x39, 0x81, 0xb2, 0xc0, 0x49, 0x2d, 0xc9, 0xbf, 0x0b,
0x90, 0x30, 0x41, 0x5a, 0xa4, 0xff, 0x14, 0x60, 0x69, 0x2b, 0xaa, 0x41, 0x31, 0x85, 0xe4, 0x99,
0x90, 0xc7, 0xe9, 0x56, 0xff, 0x0a, 0xf6, 0x16, 0x94, 0xa0, 0x87, 0x50, 0x9a, 0xc6, 0x64, 0x18,
0xbc, 0x71, 0x69, 0xf0, 0x3d, 0x91, 0x03, 0x06, 0x24, 0xa2, 0x6e, 0xf0, 0x3d, 0x2f, 0x34, 0xeb,
0x34, 0x97, 0x33, 0x3c, 0xea, 0x7f, 0x51, 0xe0, 0x60, 0xc3, 0x2e, 0x8e, 0x3a, 0x0c, 0x62, 0xca,
0xdc, 0xd7, 0xde, 0x78, 0x96, 0xa0, 0xaa, 0x18, 0x84, 0xe8, 0x39, 0x97, 0xf0, 0xf8, 0x14, 0x6f,
0x3d, 0xf5, 0x62, 0x6f, 0x42, 0x18, 0x89, 0xe5, 0xa8, 0x52, 0xe1, 0xd2, 0x4e, 0x2a, 0xe4, 0x38,
0xe1, 0x6c, 0x92, 0xf9, 0xa4, 0x14, 0xd6, 0x85, 0xb3, 0x49, 0x3a, 0xc6, 0x7c, 0x04, 0x65, 0xc2,
0x2f, 0x25, 0x03, 0x77, 0xf1, 0x0d, 0x54, 0xc6, 0x25, 0x29, 0xe3, 0x43, 0x0f, 0xb7, 0xf0, 0xd6,
0x96, 0xef, 0x1f, 0xe4, 0x40, 0x71, 0x39, 0x56, 0xf1, 0x52, 0xf1, 0xd9, 0x35, 0xbf, 0x9c, 0xea,
0xe9, 0x22, 0xf9, 0x2e, 0x4b, 0x51, 0x8e, 0xbe, 0x80, 0xca, 0xca, 0x13, 0x9e, 0x16, 0xdf, 0x92,
0x0b, 0x99, 0x29, 0x7c, 0xc9, 0xc7, 0xcd, 0x84, 0x91, 0x84, 0xc7, 0x64, 0xa3, 0xff, 0x47, 0x81,
0xdb, 0xcb, 0x6e, 0xd8, 0x24, 0xd4, 0x8f, 0x83, 0x29, 0x8b, 0xe2, 0x1f, 0xf7, 0xd8, 0xad, 0xfe,
0xf0, 0x99, 0x43, 0x1f, 0xc2, 0x5d, 0xfe, 0xaa, 0xcb, 0x97, 0x5e, 0x56, 0xf0, 0xaf, 0x16, 0xff,
0x49, 0xf8, 0x90, 0x96, 0xfa, 0xe6, 0xf1, 0xe5, 0xd7, 0xac, 0x72, 0x96, 0xfe, 0x31, 0x11, 0xa0,
0x4f, 0xfe, 0xa0, 0xa4, 0xff, 0x60, 0xc4, 0x7b, 0x7c, 0x00, 0x77, 0x7b, 0x27, 0xd8, 0x34, 0x7a,
0xdb, 0x5a, 0x66, 0x09, 0x8a, 0xa7, 0x46, 0xfb, 0xcc, 0xc0, 0xbc, 0x57, 0xde, 0x01, 0xd4, 0x75,
0x1a, 0xbc, 0x7d, 0x9a, 0xf6, 0x33, 0xcb, 0x36, 0x4d, 0x6c, 0xd9, 0xcf, 0xb4, 0x1c, 0x3a, 0x84,
0x83, 0xbe, 0x7d, 0x66, 0xd8, 0x3d, 0xb3, 0xe9, 0x76, 0x9d, 0x56, 0x4f, 0xa8, 0xab, 0xe8, 0x11,
0x3c, 0xec, 0x38, 0x3d, 0xd3, 0xe6, 0x0d, 0xb7, 0xfd, 0xd2, 0x3d, 0x31, 0xf0, 0x69, 0xab, 0xdf,
0x76, 0x8d, 0x4e, 0xa7, 0x6d, 0x35, 0x8c, 0x9e, 0xe5, 0xd8, 0xda, 0xce, 0x93, 0x3f, 0x2b, 0x50,
0xce, 0x92, 0xcc, 0x7b, 0x78, 0xa7, 0x6d, 0xf4, 0x5a, 0x0e, 0x3e, 0xbd, 0xc4, 0xa0, 0x33, 0xcb,
0x6e, 0x3a, 0x67, 0x5d, 0x4d, 0x41, 0x7b, 0x90, 0x6f, 0x5b, 0x76, 0xff, 0x85, 0x96, 0xe3, 0x72,
0xc3, 0x6e, 0x62, 0xc7, 0x6a, 0x6a, 0x2a, 0x2a, 0x82, 0xea, 0x74, 0x5f, 0x68, 0x3b, 0x7c, 0x61,
0x39, 0x5d, 0x2d, 0x8f, 0x34, 0x28, 0x1b, 0xf6, 0x4b, 0x37, 0x45, 0xd6, 0x0a, 0xe8, 0x00, 0x2a,
0x46, 0xbb, 0xbd, 0x90, 0x74, 0xb5, 0x22, 0x02, 0x28, 0x34, 0x4e, 0xb0, 0x73, 0x6a, 0x6a, 0xbb,
0x4f, 0x5a, 0xb0, 0xbf, 0x56, 0x6c, 0xd1, 0x31, 0x7c, 0xd8, 0x70, 0x4e, 0x3b, 0xd8, 0xec, 0x76,
0x2d, 0xc7, 0xde, 0x66, 0x5c, 0x11, 0x54, 0x6c, 0x9c, 0x69, 0x0a, 0xda, 0x85, 0x1d, 0x6c, 0x35,
0x4c, 0x2d, 0xf7, 0xe4, 0x1b, 0xd8, 0x5f, 0x73, 0x3c, 0xfa, 0x08, 0xee, 0x4b, 0xc2, 0x4d, 0xbb,
0x87, 0x5f, 0x5e, 0x02, 0xd4, 0xc7, 0x6d, 0x4d, 0x41, 0x55, 0x00, 0xf3, 0x85, 0xd9, 0xe8, 0xf7,
0x8c, 0xdf, 0xb5, 0x4d, 0x2d, 0x87, 0xca, 0xb0, 0x6b, 0x75, 0x5c, 0x6c, 0xd8, 0xcf, 0x4c, 0x4d,
0x7d, 0x55, 0x10, 0x2e, 0xff, 0xf4, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x68, 0x6b, 0x92, 0x80,
0x9e, 0x13, 0x00, 0x00,
}

View File

@ -14,6 +14,8 @@
syntax = "proto3";
import "google/protobuf/duration.proto";
package safebrowsing_proto;
// The Safe Browsing APIs enable clients to check web resources (most commonly
@ -81,7 +83,7 @@ message ThreatMatch {
// The cache lifetime for the returned match. Clients must not cache this
// response for more than this duration to avoid false positives.
Duration cache_duration = 5;
google.protobuf.Duration cache_duration = 5;
}
// Request to check entries against lists.
@ -208,7 +210,7 @@ message FetchThreatListUpdatesResponse {
// The minimum duration the client must wait before issuing any update
// request. If this field is not set clients may update as soon as they want.
Duration minimum_wait_duration = 2;
google.protobuf.Duration minimum_wait_duration = 2;
}
// Request to return full hashes matched by the provided hash prefixes.
@ -231,11 +233,11 @@ message FindFullHashesResponse {
// The minimum duration the client must wait before issuing any find hashes
// request. If this field is not set, clients can issue a request as soon as
// they want.
Duration minimum_wait_duration = 2;
google.protobuf.Duration minimum_wait_duration = 2;
// For requested entities that did not match the threat list, how long to
// cache the response.
Duration negative_cache_duration = 3;
google.protobuf.Duration negative_cache_duration = 3;
}
@ -444,24 +446,3 @@ message ListThreatListsResponse {
// The lists available for download by the client.
repeated ThreatListDescriptor threat_lists = 1;
}
// A Duration represents a signed, fixed-length span of time represented
// as a count of seconds and fractions of seconds at nanosecond
// resolution. It is independent of any calendar and concepts like "day"
// or "month". It is related to Timestamp in that the difference between
// two Timestamp values is a Duration and it can be added or subtracted
// from a Timestamp. Range is approximately +-10,000 years.
message Duration {
// Signed seconds of the span of time. Must be from -315,576,000,000
// to +315,576,000,000 inclusive.
int64 seconds = 1;
// Signed fractions of a second at nanosecond resolution of the span
// of time. Durations less than one second are represented with a 0
// `seconds` field and a positive or negative `nanos` field. For durations
// of one second or more, a non-zero value for the `nanos` field must be
// of the same sign as the `seconds` field. Must be from -999,999,999
// to +999,999,999 inclusive.
int32 nanos = 2;
}

View File

@ -72,6 +72,7 @@
package safebrowsing
import (
"context"
"errors"
"io"
"io/ioutil"
@ -94,6 +95,10 @@ const (
// strings to send with every API call.
DefaultID = "GoSafeBrowser"
DefaultVersion = "1.0.0"
// DefaultRequestTimeout is the default amount of time a single
// api request can take.
DefaultRequestTimeout = time.Minute
)
// Errors specific to this package.
@ -207,6 +212,9 @@ type Config struct {
// If empty, it defaults to DefaultThreatLists.
ThreatLists []ThreatDescriptor
// RequestTimeout determines the timeout value for the http client.
RequestTimeout time.Duration
// Logger is an io.Writer that allows SafeBrowser to write debug information
// intended for human consumption.
// If empty, no logs will be written.
@ -231,6 +239,9 @@ func (c *Config) setDefaults() bool {
if c.UpdatePeriod <= 0 {
c.UpdatePeriod = DefaultUpdatePeriod
}
if c.RequestTimeout <= 0 {
c.RequestTimeout = DefaultRequestTimeout
}
if c.compressionTypes == nil {
c.compressionTypes = []pb.CompressionType{pb.CompressionType_RAW, pb.CompressionType_RICE}
}
@ -251,8 +262,8 @@ func (c Config) copy() Config {
// local database and caching that would normally be needed to interact
// with the API server.
type SafeBrowser struct {
stats Stats // Must be first for 64-bit alignment on non 64-bit systems.
config Config
stats Stats
api api
db database
c cache
@ -267,10 +278,11 @@ type SafeBrowser struct {
// Stats records statistics regarding SafeBrowser's operation.
type Stats struct {
QueriesByDatabase int64 // Number of queries satisfied by the database alone
QueriesByCache int64 // Number of queries satisfied by the cache alone
QueriesByAPI int64 // Number of queries satisfied by an API call
QueriesFail int64 // Number of queries that could not be satisfied
QueriesByDatabase int64 // Number of queries satisfied by the database alone
QueriesByCache int64 // Number of queries satisfied by the cache alone
QueriesByAPI int64 // Number of queries satisfied by an API call
QueriesFail int64 // Number of queries that could not be satisfied
DatabaseUpdateLag time.Duration // Duration since last *missed* update. 0 if next update is in the future.
}
// NewSafeBrowser creates a new SafeBrowser.
@ -286,7 +298,7 @@ func NewSafeBrowser(conf Config) (*SafeBrowser, error) {
// Create the SafeBrowsing object.
if conf.api == nil {
var err error
conf.api, err = newNetAPI(conf.ServerURL, conf.APIKey)
conf.api, err = newNetAPI(conf.ServerURL, conf.APIKey, conf.RequestTimeout)
if err != nil {
return nil, err
}
@ -316,14 +328,19 @@ func NewSafeBrowser(conf Config) (*SafeBrowser, error) {
}
sb.log = log.New(w, "safebrowsing: ", log.Ldate|log.Ltime|log.Lshortfile)
delay := time.Duration(0)
// If database file is provided, use that to initialize.
if !sb.db.Init(&sb.config, sb.log) {
sb.db.Update(sb.api)
delay, _ = sb.db.Update(sb.api)
} else {
if age := sb.db.SinceLastUpdate(); age < sb.config.UpdatePeriod {
delay = sb.config.UpdatePeriod - age
}
}
// Start the background list updater.
sb.done = make(chan bool)
go sb.updater(conf.UpdatePeriod)
go sb.updater(delay)
return sb, nil
}
@ -337,10 +354,28 @@ func (sb *SafeBrowser) Status() (Stats, error) {
QueriesByCache: atomic.LoadInt64(&sb.stats.QueriesByCache),
QueriesByAPI: atomic.LoadInt64(&sb.stats.QueriesByAPI),
QueriesFail: atomic.LoadInt64(&sb.stats.QueriesFail),
DatabaseUpdateLag: sb.db.UpdateLag(),
}
return stats, sb.db.Status()
}
// WaitUntilReady blocks until the database is not in an error state.
// Returns nil when the database is ready. Returns an error if the provided
// context is canceled or if the SafeBrowser instance is Closed.
func (sb *SafeBrowser) WaitUntilReady(ctx context.Context) error {
if atomic.LoadUint32(&sb.closed) == 1 {
return errClosed
}
select {
case <-sb.db.Ready():
return nil
case <-ctx.Done():
return ctx.Err()
case <-sb.done:
return errClosed
}
}
// LookupURLs looks up the provided URLs. It returns a list of threats, one for
// every URL requested, and an error if any occurred. It is safe to call this
// method concurrently.
@ -492,16 +527,17 @@ func (sb *SafeBrowser) LookupURLs(urls []string) (threats [][]URLThreat, err err
// updater is a blocking method that periodically updates the local database.
// This should be run as a separate goroutine and will be automatically stopped
// when sb.Close is called.
func (sb *SafeBrowser) updater(period time.Duration) {
ticker := time.NewTicker(period)
defer ticker.Stop()
func (sb *SafeBrowser) updater(delay time.Duration) {
for {
sb.log.Printf("Next update in %v", delay)
select {
case <-ticker.C:
sb.log.Printf("background threat list update")
sb.c.Purge()
sb.db.Update(sb.api)
case <-time.After(delay):
var ok bool
if delay, ok = sb.db.Update(sb.api); ok {
sb.log.Printf("background threat list updated")
sb.c.Purge()
}
case <-sb.done:
return
}

View File

@ -426,13 +426,9 @@ func generateLookupHosts(urlStr string) ([]string, error) {
return nil, err
}
// handle IPv4 and IPv6 addresses.
u, err := url.Parse(urlStr)
if err != nil {
return nil, err
}
ip := net.ParseIP(strings.Trim(u.Host, "[]"))
ip := net.ParseIP(strings.Trim(host, "[]"))
if ip != nil {
return []string{u.Host}, nil
return []string{host}, nil
}
hostComponents := strings.Split(host, ".")