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:
		
							parent
							
								
									71f8ae0e87
								
							
						
					
					
						commit
						f5bc9e892a
					
				|  | @ -114,6 +114,10 @@ | ||||||
| 			"ImportPath": "github.com/golang/protobuf/proto", | 			"ImportPath": "github.com/golang/protobuf/proto", | ||||||
| 			"Rev": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317" | 			"Rev": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317" | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			"ImportPath": "github.com/golang/protobuf/ptypes/duration", | ||||||
|  | 			"Rev": "c9c7427a2a70d2eb3bafa0ab2dc163e45f143317" | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/google/certificate-transparency-go", | 			"ImportPath": "github.com/google/certificate-transparency-go", | ||||||
| 			"Rev": "0dac42a6ed448ba220ee315abfaa6d26fd5fc9bb" | 			"Rev": "0dac42a6ed448ba220ee315abfaa6d26fd5fc9bb" | ||||||
|  | @ -144,11 +148,11 @@ | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/google/safebrowsing", | 			"ImportPath": "github.com/google/safebrowsing", | ||||||
| 			"Rev": "fc74adc270b82ff5a2f288fa84e40213eae713c5" | 			"Rev": "a8c029efb52bae66853e05241150ab338e98fbc7" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/google/safebrowsing/internal/safebrowsing_proto", | 			"ImportPath": "github.com/google/safebrowsing/internal/safebrowsing_proto", | ||||||
| 			"Rev": "fc74adc270b82ff5a2f288fa84e40213eae713c5" | 			"Rev": "a8c029efb52bae66853e05241150ab338e98fbc7" | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", | 			"ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", | ||||||
|  |  | ||||||
|  | @ -3,9 +3,11 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	safebrowsingv4 "github.com/google/safebrowsing" | 	safebrowsingv4 "github.com/google/safebrowsing" | ||||||
| 	"github.com/letsencrypt/boulder/cmd" | 	"github.com/letsencrypt/boulder/cmd" | ||||||
|  | @ -119,6 +121,12 @@ func newGoogleSafeBrowsingV4(gsb *cmd.GoogleSafeBrowsingConfig, logger blog.Logg | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		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 | 	return gsbAdapter{sb}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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, | ||||||
|  | } | ||||||
|  | @ -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; | ||||||
|  | } | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| language: go | language: go | ||||||
| 
 | 
 | ||||||
| go: | go: | ||||||
|   - 1.6 |  | ||||||
|   - 1.7 |   - 1.7 | ||||||
|  |   - 1.8 | ||||||
| 
 | 
 | ||||||
| script: | script: | ||||||
|   - test -z "$(gofmt -s -l $(find . -name '*.go' -type f -print) | tee /dev/stderr)" |   - test -z "$(gofmt -s -l $(find . -name '*.go' -type f -print) | tee /dev/stderr)" | ||||||
|   - go test -v ./... |   - go test -v $(go list ./... | grep -v vendor) | ||||||
|   - go test -race -v ./... |   - go test -race -v $(go list ./... | grep -v vendor) | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	pb "github.com/google/safebrowsing/internal/safebrowsing_proto" | 	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.
 | // netAPI is an api object that talks to the server over HTTP.
 | ||||||
| type netAPI struct { | type netAPI struct { | ||||||
| 	client http.Client | 	client *http.Client | ||||||
| 	url    *url.URL | 	url    *url.URL | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // newNetAPI creates a new netAPI object pointed at the provided root URL.
 | // newNetAPI creates a new netAPI object pointed at the provided root URL.
 | ||||||
| // For every request, it will use the provided API key.
 | // For every request, it will use the provided API key.
 | ||||||
| // If the protocol is not specified in root, then this defaults to using HTTPS.
 | // 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, "://") { | 	if !strings.Contains(root, "://") { | ||||||
| 		root = "https://" + root | 		root = "https://" + root | ||||||
| 	} | 	} | ||||||
|  | @ -60,7 +61,7 @@ func newNetAPI(root string, key string) (*netAPI, error) { | ||||||
| 	q.Set("key", key) | 	q.Set("key", key) | ||||||
| 	q.Set("alt", "proto") | 	q.Set("alt", "proto") | ||||||
| 	u.RawQuery = q.Encode() | 	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
 | // doRequests performs a POST to requestPath. It uses the marshaled form of req
 | ||||||
|  |  | ||||||
|  | @ -80,7 +80,12 @@ func (c *cache) Update(req *pb.FindFullHashesRequest, resp *pb.FindFullHashesRes | ||||||
| 		if c.pttls[fullHash] == nil { | 		if c.pttls[fullHash] == nil { | ||||||
| 			c.pttls[fullHash] = make(map[ThreatDescriptor]time.Time) | 			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{ | 		td := ThreatDescriptor{ | ||||||
| 			ThreatType:      ThreatType(tm.ThreatType), | 			ThreatType:      ThreatType(tm.ThreatType), | ||||||
| 			PlatformType:    PlatformType(tm.PlatformType), | 			PlatformType:    PlatformType(tm.PlatformType), | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ import ( | ||||||
| 	"encoding/gob" | 	"encoding/gob" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"log" | 	"log" | ||||||
|  | 	"math/rand" | ||||||
| 	"os" | 	"os" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  | @ -30,7 +31,11 @@ import ( | ||||||
| // jitter is the maximum amount of time that we expect an API list update to
 | // 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
 | // actually take. We add this time to the update period time to give some
 | ||||||
| // leeway before declaring the database as stale.
 | // 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
 | // 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
 | // API. Since the global blacklist is constantly changing, the contents of the
 | ||||||
|  | @ -63,8 +68,10 @@ type database struct { | ||||||
| 	tfl threatsForLookup | 	tfl threatsForLookup | ||||||
| 	ml  sync.RWMutex // Protects tfl, err, and last
 | 	ml  sync.RWMutex // Protects tfl, err, and last
 | ||||||
| 
 | 
 | ||||||
| 	err  error     // Last error encountered
 | 	err             error         // Last error encountered
 | ||||||
| 	last time.Time // Last time the threat list were synced
 | 	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 | 	log *log.Logger | ||||||
| } | } | ||||||
|  | @ -94,11 +101,14 @@ type databaseFormat struct { | ||||||
| // Init initializes the database from the specified file in config.DBPath.
 | // Init initializes the database from the specified file in config.DBPath.
 | ||||||
| // It reports true if the database was successfully loaded.
 | // It reports true if the database was successfully loaded.
 | ||||||
| func (db *database) Init(config *Config, logger *log.Logger) bool { | 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.config = config | ||||||
| 	db.log = logger | 	db.log = logger | ||||||
| 	if db.config.DBPath == "" { | 	if db.config.DBPath == "" { | ||||||
| 		db.log.Printf("no database file specified") | 		db.log.Printf("no database file specified") | ||||||
| 		db.setError(errStale) | 		db.setError(errors.New("no database loaded")) | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	dbf, err := loadDatabase(db.config.DBPath) | 	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.
 | 	// superset of the specified configuration.
 | ||||||
| 	if db.config.now().Sub(dbf.Time) > (db.config.UpdatePeriod + jitter) { | 	if db.config.now().Sub(dbf.Time) > (db.config.UpdatePeriod + jitter) { | ||||||
| 		db.log.Printf("database loaded is stale") | 		db.log.Printf("database loaded is stale") | ||||||
| 		db.setError(errStale) | 		db.ml.Lock() | ||||||
|  | 		defer db.ml.Unlock() | ||||||
|  | 		db.setStale() | ||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
| 	tfuNew := make(threatsForUpdate) | 	tfuNew := make(threatsForUpdate) | ||||||
|  | @ -120,8 +132,8 @@ func (db *database) Init(config *Config, logger *log.Logger) bool { | ||||||
| 		if row, ok := dbf.Table[td]; ok { | 		if row, ok := dbf.Table[td]; ok { | ||||||
| 			tfuNew[td] = row | 			tfuNew[td] = row | ||||||
| 		} else { | 		} else { | ||||||
| 			db.log.Printf("database configuration mismatch") | 			db.log.Printf("database configuration mismatch, missing %v", td) | ||||||
| 			db.setError(errStale) | 			db.setError(errors.New("database configuration mismatch")) | ||||||
| 			return false | 			return false | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -140,15 +152,39 @@ func (db *database) Status() error { | ||||||
| 		return db.err | 		return db.err | ||||||
| 	} | 	} | ||||||
| 	if db.config.now().Sub(db.last) > (db.config.UpdatePeriod + jitter) { | 	if db.config.now().Sub(db.last) > (db.config.UpdatePeriod + jitter) { | ||||||
| 		return errStale | 		db.setStale() | ||||||
|  | 		return db.err | ||||||
| 	} | 	} | ||||||
| 	return nil | 	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
 | // Update synchronizes the local threat lists with those maintained by the
 | ||||||
| // global Safe Browsing API servers. If the update is successful, Status should
 | // global Safe Browsing API servers. If the update is successful, Status should
 | ||||||
| // report a nil error.
 | // report a nil error.
 | ||||||
| func (db *database) Update(api api) { | func (db *database) Update(api api) (time.Duration, bool) { | ||||||
| 	db.mu.Lock() | 	db.mu.Lock() | ||||||
| 	defer db.mu.Unlock() | 	defer db.mu.Unlock() | ||||||
| 
 | 
 | ||||||
|  | @ -183,23 +219,42 @@ func (db *database) Update(api api) { | ||||||
| 	last := db.config.now() | 	last := db.config.now() | ||||||
| 	resp, err := api.ListUpdate(req) | 	resp, err := api.ListUpdate(req) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		db.log.Printf("ListUpdate failure: %v", err) | 		db.log.Printf("ListUpdate failure (%d): %v", db.updateAPIErrors+1, err) | ||||||
| 		db.setError(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 { | 	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", | 		db.log.Printf("invalid server response: got %d, want %d threat lists", | ||||||
| 			len(resp.ListUpdateResponses), numTypes) | 			len(resp.ListUpdateResponses), numTypes) | ||||||
| 		db.setError(errors.New("safebrowsing: threat list count mismatch")) | 		return nextUpdateWait, false | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Update the threat database with the response.
 | 	// Update the threat database with the response.
 | ||||||
| 	db.generateThreatsForUpdate() | 	db.generateThreatsForUpdate() | ||||||
| 	if err := db.tfu.update(resp); err != nil { | 	if err := db.tfu.update(resp); err != nil { | ||||||
| 		db.log.Printf("update failure: %v", err) |  | ||||||
| 		db.setError(err) | 		db.setError(err) | ||||||
| 		return | 		db.log.Printf("update failure: %v", err) | ||||||
|  | 		db.tfu = nil | ||||||
|  | 		return nextUpdateWait, false | ||||||
| 	} | 	} | ||||||
| 	dbf := databaseFormat{make(threatsForUpdate), last} | 	dbf := databaseFormat{make(threatsForUpdate), last} | ||||||
| 	for td, phs := range db.tfu { | 	for td, phs := range db.tfu { | ||||||
|  | @ -215,6 +270,8 @@ func (db *database) Update(api api) { | ||||||
| 			db.log.Printf("save failure: %v", err) | 			db.log.Printf("save failure: %v", err) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	return nextUpdateWait, true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Lookup looks up the full hash in the threat list and returns a partial
 | // 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.tfu = nil | ||||||
| 
 | 
 | ||||||
| 	db.ml.Lock() | 	db.ml.Lock() | ||||||
|  | 	if db.err == nil { | ||||||
|  | 		db.readyCh = make(chan struct{}) | ||||||
|  | 	} | ||||||
| 	db.tfl, db.err, db.last = nil, err, time.Time{} | 	db.tfl, db.err, db.last = nil, err, time.Time{} | ||||||
| 	db.ml.Unlock() | 	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
 | // generateThreatsForUpdate regenerates the threatsForUpdate hashes from
 | ||||||
| // the threatsForLookup. We do this to avoid holding onto the hash lists for
 | // the threatsForLookup. We do this to avoid holding onto the hash lists for
 | ||||||
| // a long time, needlessly occupying lots of memory.
 | // a long time, needlessly occupying lots of memory.
 | ||||||
|  | @ -284,10 +369,11 @@ func (db *database) generateThreatsForLookups(last time.Time) { | ||||||
| 
 | 
 | ||||||
| 	db.ml.Lock() | 	db.ml.Lock() | ||||||
| 	wasBad := db.err != nil | 	wasBad := db.err != nil | ||||||
| 	db.tfl, db.err, db.last = tfl, nil, last | 	db.tfl, db.last = tfl, last | ||||||
| 	db.ml.Unlock() | 	db.ml.Unlock() | ||||||
| 
 | 
 | ||||||
| 	if wasBad { | 	if wasBad { | ||||||
|  | 		db.clearError() | ||||||
| 		db.log.Printf("database is now healthy") | 		db.log.Printf("database is now healthy") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -424,7 +510,9 @@ func (tfu threatsForUpdate) update(resp *pb.FetchThreatListUpdatesResponse) erro | ||||||
| 			return err | 			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()) { | 		if !bytes.Equal(phs.SHA256, phs.Hashes.SHA256()) { | ||||||
| 			return errors.New("safebrowsing: threat list SHA256 mismatch") | 			return errors.New("safebrowsing: threat list SHA256 mismatch") | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
							
								
								
									
										532
									
								
								vendor/github.com/google/safebrowsing/internal/safebrowsing_proto/safebrowsing.pb.go
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										532
									
								
								vendor/github.com/google/safebrowsing/internal/safebrowsing_proto/safebrowsing.pb.go
								
								
									generated
								
								
									vendored
								
								
							|  | @ -27,13 +27,13 @@ It has these top-level messages: | ||||||
| 	ThreatEntryMetadata | 	ThreatEntryMetadata | ||||||
| 	ThreatListDescriptor | 	ThreatListDescriptor | ||||||
| 	ListThreatListsResponse | 	ListThreatListsResponse | ||||||
| 	Duration |  | ||||||
| */ | */ | ||||||
| package safebrowsing_proto | package safebrowsing_proto | ||||||
| 
 | 
 | ||||||
| import proto "github.com/golang/protobuf/proto" | import proto "github.com/golang/protobuf/proto" | ||||||
| import fmt "fmt" | import fmt "fmt" | ||||||
| import math "math" | import math "math" | ||||||
|  | import google_protobuf "github.com/golang/protobuf/ptypes/duration" | ||||||
| 
 | 
 | ||||||
| // Reference imports to suppress errors if they are not otherwise used.
 | // Reference imports to suppress errors if they are not otherwise used.
 | ||||||
| var _ = proto.Marshal | var _ = proto.Marshal | ||||||
|  | @ -42,7 +42,9 @@ var _ = math.Inf | ||||||
| 
 | 
 | ||||||
| // This is a compile-time assertion to ensure that this generated file
 | // This is a compile-time assertion to ensure that this generated file
 | ||||||
| // is compatible with the proto package it is being compiled against.
 | // 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.
 | // Types of threats.
 | ||||||
| type ThreatType int32 | type ThreatType int32 | ||||||
|  | @ -229,11 +231,11 @@ func (FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType) EnumDescri | ||||||
| // checking for matches in threat lists.
 | // checking for matches in threat lists.
 | ||||||
| type ThreatInfo struct { | type ThreatInfo struct { | ||||||
| 	// The threat types to be checked.
 | 	// 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.
 | 	// 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.
 | 	// 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.
 | 	// The threat entries to be checked.
 | ||||||
| 	ThreatEntries []*ThreatEntry `protobuf:"bytes,3,rep,name=threat_entries,json=threatEntries" json:"threat_entries,omitempty"` | 	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) ProtoMessage()               {} | ||||||
| func (*ThreatInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } | 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 { | func (m *ThreatInfo) GetThreatEntries() []*ThreatEntry { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.ThreatEntries | 		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"` | 	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
 | 	// The cache lifetime for the returned match. Clients must not cache this
 | ||||||
| 	// response for more than this duration to avoid false positives.
 | 	// 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{} } | func (m *ThreatMatch) Reset()                    { *m = ThreatMatch{} } | ||||||
|  | @ -272,6 +295,27 @@ func (m *ThreatMatch) String() string            { return proto.CompactTextStrin | ||||||
| func (*ThreatMatch) ProtoMessage()               {} | func (*ThreatMatch) ProtoMessage()               {} | ||||||
| func (*ThreatMatch) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } | 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 { | func (m *ThreatMatch) GetThreat() *ThreatEntry { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Threat | 		return m.Threat | ||||||
|  | @ -286,7 +330,7 @@ func (m *ThreatMatch) GetThreatEntryMetadata() *ThreatEntryMetadata { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *ThreatMatch) GetCacheDuration() *Duration { | func (m *ThreatMatch) GetCacheDuration() *google_protobuf.Duration { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.CacheDuration | 		return m.CacheDuration | ||||||
| 	} | 	} | ||||||
|  | @ -394,6 +438,34 @@ func (*FetchThreatListUpdatesRequest_ListUpdateRequest) Descriptor() ([]byte, [] | ||||||
| 	return fileDescriptor0, []int{4, 0} | 	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 { | func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetConstraints() *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Constraints | 		return m.Constraints | ||||||
|  | @ -416,7 +488,7 @@ type FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints struct { | ||||||
| 	// 3166-1 alpha-2 format.
 | 	// 3166-1 alpha-2 format.
 | ||||||
| 	Region string `protobuf:"bytes,3,opt,name=region" json:"region,omitempty"` | 	Region string `protobuf:"bytes,3,opt,name=region" json:"region,omitempty"` | ||||||
| 	// The compression types supported by the client.
 | 	// 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() { | func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) Reset() { | ||||||
|  | @ -430,13 +502,41 @@ func (*FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) Descriptor() | ||||||
| 	return fileDescriptor0, []int{4, 0, 0} | 	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.
 | // Response type for threat list update requests.
 | ||||||
| type FetchThreatListUpdatesResponse struct { | type FetchThreatListUpdatesResponse struct { | ||||||
| 	// The list updates requested by the clients.
 | 	// 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"` | 	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
 | 	// 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.
 | 	// 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{} } | func (m *FetchThreatListUpdatesResponse) Reset()                    { *m = FetchThreatListUpdatesResponse{} } | ||||||
|  | @ -451,7 +551,7 @@ func (m *FetchThreatListUpdatesResponse) GetListUpdateResponses() []*FetchThreat | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *FetchThreatListUpdatesResponse) GetMinimumWaitDuration() *Duration { | func (m *FetchThreatListUpdatesResponse) GetMinimumWaitDuration() *google_protobuf.Duration { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.MinimumWaitDuration | 		return m.MinimumWaitDuration | ||||||
| 	} | 	} | ||||||
|  | @ -496,6 +596,34 @@ func (*FetchThreatListUpdatesResponse_ListUpdateResponse) Descriptor() ([]byte, | ||||||
| 	return fileDescriptor0, []int{5, 0} | 	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 { | func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetAdditions() []*ThreatEntrySet { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Additions | 		return m.Additions | ||||||
|  | @ -510,6 +638,13 @@ func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetRemovals() []*Thr | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetNewClientState() []byte { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.NewClientState | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetChecksum() *Checksum { | func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetChecksum() *Checksum { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.Checksum | 		return m.Checksum | ||||||
|  | @ -539,6 +674,13 @@ func (m *FindFullHashesRequest) GetClient() *ClientInfo { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (m *FindFullHashesRequest) GetClientStates() [][]byte { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.ClientStates | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (m *FindFullHashesRequest) GetThreatInfo() *ThreatInfo { | func (m *FindFullHashesRequest) GetThreatInfo() *ThreatInfo { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.ThreatInfo | 		return m.ThreatInfo | ||||||
|  | @ -553,10 +695,10 @@ type FindFullHashesResponse struct { | ||||||
| 	// The minimum duration the client must wait before issuing any find hashes
 | 	// 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
 | 	// request. If this field is not set, clients can issue a request as soon as
 | ||||||
| 	// they want.
 | 	// 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
 | 	// For requested entities that did not match the threat list, how long to
 | ||||||
| 	// cache the response.
 | 	// 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{} } | func (m *FindFullHashesResponse) Reset()                    { *m = FindFullHashesResponse{} } | ||||||
|  | @ -571,14 +713,14 @@ func (m *FindFullHashesResponse) GetMatches() []*ThreatMatch { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *FindFullHashesResponse) GetMinimumWaitDuration() *Duration { | func (m *FindFullHashesResponse) GetMinimumWaitDuration() *google_protobuf.Duration { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.MinimumWaitDuration | 		return m.MinimumWaitDuration | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *FindFullHashesResponse) GetNegativeCacheDuration() *Duration { | func (m *FindFullHashesResponse) GetNegativeCacheDuration() *google_protobuf.Duration { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.NegativeCacheDuration | 		return m.NegativeCacheDuration | ||||||
| 	} | 	} | ||||||
|  | @ -599,6 +741,20 @@ func (m *ClientInfo) String() string            { return proto.CompactTextString | ||||||
| func (*ClientInfo) ProtoMessage()               {} | func (*ClientInfo) ProtoMessage()               {} | ||||||
| func (*ClientInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } | 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.
 | // The expected state of a client's local database.
 | ||||||
| type Checksum struct { | type Checksum struct { | ||||||
| 	// The SHA256 hash of the client state; that is, of the sorted list of all
 | 	// 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) ProtoMessage()               {} | ||||||
| func (*Checksum) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } | 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
 | // An individual threat; for example, a malicious URL or its hash
 | ||||||
| // representation. Only one of these fields should be set.
 | // representation. Only one of these fields should be set.
 | ||||||
| type ThreatEntry struct { | type ThreatEntry struct { | ||||||
|  | @ -626,6 +789,20 @@ func (m *ThreatEntry) String() string            { return proto.CompactTextStrin | ||||||
| func (*ThreatEntry) ProtoMessage()               {} | func (*ThreatEntry) ProtoMessage()               {} | ||||||
| func (*ThreatEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } | 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
 | // A set of threats that should be added or removed from a client's local
 | ||||||
| // database.
 | // database.
 | ||||||
| type ThreatEntrySet struct { | type ThreatEntrySet struct { | ||||||
|  | @ -648,6 +825,13 @@ func (m *ThreatEntrySet) String() string            { return proto.CompactTextSt | ||||||
| func (*ThreatEntrySet) ProtoMessage()               {} | func (*ThreatEntrySet) ProtoMessage()               {} | ||||||
| func (*ThreatEntrySet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } | 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 { | func (m *ThreatEntrySet) GetRawHashes() *RawHashes { | ||||||
| 	if m != nil { | 	if m != nil { | ||||||
| 		return m.RawHashes | 		return m.RawHashes | ||||||
|  | @ -679,7 +863,7 @@ func (m *ThreatEntrySet) GetRiceIndices() *RiceDeltaEncoding { | ||||||
| // A set of raw indices to remove from a local list.
 | // A set of raw indices to remove from a local list.
 | ||||||
| type RawIndices struct { | type RawIndices struct { | ||||||
| 	// The indices to remove from a lexicographically-sorted local list.
 | 	// 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{} } | func (m *RawIndices) Reset()                    { *m = RawIndices{} } | ||||||
|  | @ -687,6 +871,13 @@ func (m *RawIndices) String() string            { return proto.CompactTextString | ||||||
| func (*RawIndices) ProtoMessage()               {} | func (*RawIndices) ProtoMessage()               {} | ||||||
| func (*RawIndices) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } | 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.
 | // 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
 | // 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
 | // 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) ProtoMessage()               {} | ||||||
| func (*RawHashes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } | 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
 | // The Rice-Golomb encoded data. Used for sending compressed 4-byte hashes or
 | ||||||
| // compressed removal indices.
 | // compressed removal indices.
 | ||||||
| type RiceDeltaEncoding struct { | type RiceDeltaEncoding struct { | ||||||
|  | @ -730,6 +935,34 @@ func (m *RiceDeltaEncoding) String() string            { return proto.CompactTex | ||||||
| func (*RiceDeltaEncoding) ProtoMessage()               {} | func (*RiceDeltaEncoding) ProtoMessage()               {} | ||||||
| func (*RiceDeltaEncoding) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } | 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
 | // The metadata associated with a specific threat entry. The client is expected
 | ||||||
| // to know the metadata key/value pairs associated with each threat type.
 | // to know the metadata key/value pairs associated with each threat type.
 | ||||||
| type ThreatEntryMetadata struct { | type ThreatEntryMetadata struct { | ||||||
|  | @ -764,6 +997,20 @@ func (*ThreatEntryMetadata_MetadataEntry) Descriptor() ([]byte, []int) { | ||||||
| 	return fileDescriptor0, []int{15, 0} | 	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:
 | // 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 threat posed, the type of platform targeted by the threat, and
 | ||||||
| // the type of entries in the list.
 | // the type of entries in the list.
 | ||||||
|  | @ -781,6 +1028,27 @@ func (m *ThreatListDescriptor) String() string            { return proto.Compact | ||||||
| func (*ThreatListDescriptor) ProtoMessage()               {} | func (*ThreatListDescriptor) ProtoMessage()               {} | ||||||
| func (*ThreatListDescriptor) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } | 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.
 | // A collection of lists available for download by the client.
 | ||||||
| type ListThreatListsResponse struct { | type ListThreatListsResponse struct { | ||||||
| 	// The lists available for download by the client.
 | 	// The lists available for download by the client.
 | ||||||
|  | @ -799,30 +1067,6 @@ func (m *ListThreatListsResponse) GetThreatLists() []*ThreatListDescriptor { | ||||||
| 	return nil | 	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() { | func init() { | ||||||
| 	proto.RegisterType((*ThreatInfo)(nil), "safebrowsing_proto.ThreatInfo") | 	proto.RegisterType((*ThreatInfo)(nil), "safebrowsing_proto.ThreatInfo") | ||||||
| 	proto.RegisterType((*ThreatMatch)(nil), "safebrowsing_proto.ThreatMatch") | 	proto.RegisterType((*ThreatMatch)(nil), "safebrowsing_proto.ThreatMatch") | ||||||
|  | @ -846,7 +1090,6 @@ func init() { | ||||||
| 	proto.RegisterType((*ThreatEntryMetadata_MetadataEntry)(nil), "safebrowsing_proto.ThreatEntryMetadata.MetadataEntry") | 	proto.RegisterType((*ThreatEntryMetadata_MetadataEntry)(nil), "safebrowsing_proto.ThreatEntryMetadata.MetadataEntry") | ||||||
| 	proto.RegisterType((*ThreatListDescriptor)(nil), "safebrowsing_proto.ThreatListDescriptor") | 	proto.RegisterType((*ThreatListDescriptor)(nil), "safebrowsing_proto.ThreatListDescriptor") | ||||||
| 	proto.RegisterType((*ListThreatListsResponse)(nil), "safebrowsing_proto.ListThreatListsResponse") | 	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.ThreatType", ThreatType_name, ThreatType_value) | ||||||
| 	proto.RegisterEnum("safebrowsing_proto.PlatformType", PlatformType_name, PlatformType_value) | 	proto.RegisterEnum("safebrowsing_proto.PlatformType", PlatformType_name, PlatformType_value) | ||||||
| 	proto.RegisterEnum("safebrowsing_proto.CompressionType", CompressionType_name, CompressionType_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) | 	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{ | var fileDescriptor0 = []byte{ | ||||||
| 	// 1628 bytes of a gzipped FileDescriptorProto
 | 	// 1636 bytes of a gzipped FileDescriptorProto
 | ||||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x58, 0x5b, 0x6f, 0xdb, 0x46, | 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x4f, 0x8f, 0xdb, 0xc6, | ||||||
| 	0x16, 0x5e, 0x49, 0xd6, 0xed, 0x48, 0xb2, 0xe5, 0xf1, 0x25, 0x8e, 0x13, 0x27, 0x59, 0x06, 0xd9, | 	0x15, 0x2f, 0xc5, 0x95, 0xb4, 0xfb, 0xf4, 0x67, 0xb9, 0x63, 0xaf, 0x2d, 0x6f, 0x62, 0x7b, 0x43, | ||||||
| 	0x0d, 0x8c, 0x85, 0xb1, 0x48, 0x90, 0x64, 0x77, 0xb1, 0xd8, 0x2d, 0x2b, 0x51, 0x36, 0x11, 0x99, | 	0x23, 0xad, 0x61, 0x14, 0x4a, 0xe1, 0x20, 0x49, 0x0b, 0x14, 0x6d, 0x58, 0x89, 0xf2, 0x12, 0xd1, | ||||||
| 	0x52, 0x47, 0x72, 0x1c, 0xb7, 0x0f, 0x04, 0x23, 0xd1, 0x31, 0x11, 0xdd, 0x42, 0x52, 0x71, 0xdc, | 	0x92, 0xca, 0x48, 0xf2, 0xda, 0xcd, 0x81, 0xa0, 0xa9, 0xd1, 0x8a, 0x88, 0x44, 0x2a, 0x9c, 0x91, | ||||||
| 	0x9f, 0xd0, 0xa7, 0x02, 0x45, 0x9f, 0xdb, 0xe7, 0xbe, 0x16, 0xfd, 0x01, 0xfd, 0x19, 0x7d, 0xec, | 	0xe5, 0xcd, 0x47, 0x28, 0xd0, 0x53, 0xd1, 0x73, 0x7b, 0xee, 0xb5, 0xe8, 0xb5, 0xdf, 0xa3, 0xc7, | ||||||
| 	0x2f, 0x28, 0xfa, 0xdc, 0x97, 0x9e, 0x19, 0xce, 0x88, 0xd4, 0xc5, 0x8e, 0x12, 0xfb, 0x21, 0x6f, | 	0x7e, 0x82, 0xa2, 0x87, 0xde, 0x8b, 0x19, 0x0e, 0x25, 0xea, 0xcf, 0x7a, 0xd7, 0x59, 0x1f, 0x72, | ||||||
| 	0x33, 0x67, 0xce, 0x7c, 0x73, 0xf8, 0xcd, 0xb9, 0x0d, 0x81, 0x78, 0xd6, 0xb1, 0xfd, 0xc2, 0xed, | 	0x9b, 0x79, 0x7c, 0xf3, 0x9b, 0xc7, 0xdf, 0xfb, 0x4b, 0x02, 0xa2, 0xde, 0x90, 0xbc, 0x8a, 0xa3, | ||||||
| 	0x9f, 0x7a, 0x4e, 0xef, 0xe5, 0xce, 0xc0, 0xed, 0xfb, 0x7d, 0x32, 0x26, 0x33, 0xb9, 0x4c, 0xf9, | 	0x39, 0x0d, 0xc2, 0xf3, 0xfa, 0x34, 0x8e, 0x58, 0x84, 0x56, 0x64, 0xae, 0x90, 0x1d, 0x3d, 0x38, | ||||||
| 	0x31, 0x0e, 0xd0, 0x3c, 0x71, 0x6d, 0xcb, 0xd7, 0x7b, 0xc7, 0x7d, 0xa2, 0x42, 0xde, 0xe7, 0x33, | 	0x8f, 0xa2, 0xf3, 0x31, 0xf9, 0x44, 0xec, 0x5e, 0xcd, 0x86, 0x9f, 0x0c, 0x66, 0xb1, 0xc7, 0x82, | ||||||
| 	0xd3, 0x3f, 0x1b, 0xd8, 0xde, 0x46, 0xec, 0x4e, 0xe2, 0xfe, 0xe2, 0x83, 0x5b, 0x3b, 0xd3, 0x3b, | 	0x28, 0x4c, 0xce, 0xe8, 0x7f, 0xcf, 0x01, 0xf4, 0x46, 0x31, 0xf1, 0x98, 0x15, 0x0e, 0x23, 0x64, | ||||||
| 	0x77, 0x82, 0x5d, 0x4d, 0x54, 0xa3, 0x39, 0x7f, 0x34, 0xf6, 0xc8, 0x2e, 0x2c, 0x0e, 0x3a, 0x96, | 	0x40, 0x99, 0x89, 0x9d, 0xcb, 0x2e, 0xa6, 0x84, 0xd6, 0x94, 0x63, 0xf5, 0x71, 0xf5, 0xe9, 0x83, | ||||||
| 	0x7f, 0xdc, 0x77, 0xbb, 0x02, 0x24, 0xce, 0x41, 0xee, 0xcc, 0x02, 0xa9, 0x0b, 0x4d, 0x0e, 0x53, | 	0xfa, 0x26, 0x72, 0x3d, 0x39, 0xd5, 0xbb, 0x98, 0x12, 0x5c, 0x62, 0x8b, 0x35, 0x45, 0xcf, 0xa0, | ||||||
| 	0x18, 0x44, 0x66, 0x1e, 0xf9, 0x0c, 0x88, 0xb0, 0xc5, 0xee, 0xf9, 0xee, 0x99, 0x00, 0x5b, 0xe0, | 	0x3a, 0x1d, 0x7b, 0x6c, 0x18, 0xc5, 0x13, 0x09, 0x92, 0x13, 0x20, 0xc7, 0xdb, 0x40, 0x3a, 0x52, | ||||||
| 	0x60, 0x77, 0xcf, 0xb7, 0x48, 0x63, 0xca, 0x1c, 0xaf, 0xe8, 0x8f, 0x0b, 0x3c, 0x52, 0x81, 0xc5, | 	0x53, 0xc0, 0x54, 0xa6, 0x99, 0x1d, 0x45, 0x5f, 0x03, 0x92, 0xb6, 0x90, 0x90, 0xc5, 0x17, 0x12, | ||||||
| 	0x08, 0xa4, 0x83, 0x70, 0x09, 0x84, 0xcb, 0x3d, 0xb8, 0xfd, 0x0e, 0x38, 0x5a, 0x08, 0xa1, 0x70, | 	0x6c, 0x47, 0x80, 0x3d, 0xba, 0xdc, 0x22, 0x93, 0x2b, 0x0b, 0x3c, 0x8d, 0xad, 0x0a, 0x28, 0x6a, | ||||||
| 	0x97, 0xf2, 0x73, 0x02, 0x72, 0xc1, 0xf2, 0xbe, 0xe5, 0xb7, 0x4e, 0xc8, 0xff, 0x21, 0x17, 0xa1, | 	0x41, 0x35, 0x03, 0x19, 0x10, 0x5a, 0x53, 0x8f, 0xd5, 0xc7, 0xa5, 0xa7, 0x0f, 0xaf, 0x80, 0xc3, | ||||||
| 	0x0d, 0x59, 0x8b, 0xcd, 0xc1, 0x1a, 0x84, 0xac, 0x11, 0x0d, 0x0a, 0x63, 0xa4, 0x21, 0x67, 0xb1, | 	0x95, 0x25, 0x54, 0x40, 0xa8, 0xfe, 0x4f, 0x15, 0x4a, 0xc9, 0xe3, 0x53, 0x8f, 0xf9, 0x23, 0xf4, | ||||||
| 	0xb9, 0x38, 0xcb, 0x47, 0x39, 0x23, 0x35, 0x58, 0x9e, 0xa2, 0x6c, 0x23, 0xc5, 0xa1, 0xe6, 0x62, | 	0x5b, 0x28, 0x65, 0x68, 0xab, 0x29, 0xc7, 0xca, 0x35, 0x58, 0x83, 0x25, 0x6b, 0xc8, 0x84, 0xca, | ||||||
| 	0x6c, 0x69, 0x82, 0x31, 0xf2, 0x04, 0x52, 0x81, 0x08, 0x89, 0x8a, 0xcd, 0x43, 0x94, 0x50, 0x27, | 	0x0a, 0x69, 0xb5, 0x9c, 0x80, 0xb8, 0x9a, 0xb3, 0x72, 0x96, 0x33, 0xe4, 0xc0, 0xc1, 0x06, 0x65, | ||||||
| 	0x5f, 0xc0, 0xda, 0x98, 0x25, 0x5d, 0xdb, 0xb7, 0xda, 0x96, 0x6f, 0xe1, 0xfd, 0x31, 0x9c, 0xbf, | 	0xb5, 0x82, 0x80, 0xba, 0x16, 0x63, 0xfb, 0x6b, 0x8c, 0xa1, 0x2f, 0xa0, 0x90, 0x88, 0x6a, 0xea, | ||||||
| 	0xbf, 0x03, 0x67, 0x5f, 0xa8, 0xd3, 0x15, 0x7f, 0x5a, 0x48, 0x4a, 0xb0, 0xd8, 0xb2, 0x5a, 0x27, | 	0xb1, 0x72, 0x1d, 0xa2, 0xa4, 0x3a, 0xfa, 0x06, 0x0e, 0x57, 0x2c, 0x99, 0x10, 0xe6, 0x0d, 0x3c, | ||||||
| 	0xb6, 0xd9, 0x1e, 0xba, 0x96, 0xef, 0xf4, 0x7b, 0x1b, 0x49, 0x8e, 0x7a, 0x73, 0x16, 0x6a, 0x59, | 	0xe6, 0xd5, 0x76, 0x04, 0xce, 0xcf, 0xae, 0xc0, 0x39, 0x95, 0xea, 0xf8, 0x16, 0xdb, 0x14, 0xa2, | ||||||
| 	0xe8, 0xd0, 0x02, 0xdf, 0x23, 0xa7, 0xca, 0x37, 0x31, 0xd8, 0xa8, 0x38, 0xbd, 0x76, 0xe4, 0x1e, | 	0x2f, 0xa1, 0xea, 0x7b, 0xfe, 0x88, 0xb8, 0x69, 0x30, 0xd7, 0xf2, 0x02, 0xf5, 0x5e, 0x3d, 0x89, | ||||||
| 	0x6d, 0x8f, 0xda, 0xaf, 0x87, 0xb6, 0xe7, 0x93, 0xc7, 0x90, 0x6a, 0x75, 0x1c, 0x34, 0x9d, 0xdf, | 	0xf6, 0x7a, 0x1a, 0xed, 0xf5, 0xa6, 0x54, 0xc0, 0x15, 0x71, 0x20, 0xdd, 0xea, 0x7f, 0x52, 0xa0, | ||||||
| 	0x65, 0x6e, 0xf6, 0x5d, 0x96, 0xb8, 0x06, 0x8b, 0x1b, 0x2a, 0xb4, 0x23, 0x8e, 0xe0, 0xa0, 0x98, | 	0xd6, 0x0a, 0xc2, 0x41, 0xc6, 0x89, 0x84, 0x62, 0xf2, 0xdd, 0x8c, 0x50, 0x86, 0x3e, 0x87, 0x82, | ||||||
| 	0xdf, 0x62, 0xee, 0x22, 0x47, 0xe0, 0x9b, 0x85, 0x23, 0xb0, 0xb1, 0xf2, 0x0c, 0xae, 0xcf, 0x30, | 	0x3f, 0x0e, 0x48, 0xc8, 0x84, 0x23, 0x4b, 0xdb, 0x1d, 0xd9, 0x10, 0x1a, 0x3c, 0x69, 0xb0, 0xd4, | ||||||
| 	0xca, 0x1b, 0xf4, 0x7b, 0x9e, 0x4d, 0xfe, 0x0d, 0xe9, 0x6e, 0x20, 0xe2, 0x81, 0x79, 0xe1, 0x75, | 	0xce, 0x44, 0x41, 0x10, 0x0e, 0x23, 0xe1, 0xc2, 0xd2, 0xdb, 0xa2, 0x40, 0x1c, 0x96, 0x51, 0xc0, | ||||||
| 	0xf0, 0xbd, 0x54, 0xea, 0x2b, 0x3f, 0xa4, 0x60, 0xab, 0x62, 0xe3, 0x38, 0x58, 0xad, 0x3a, 0x9e, | 	0xd7, 0xfa, 0x73, 0xb8, 0xb7, 0xc5, 0x28, 0x3a, 0x8d, 0x42, 0x4a, 0xd0, 0xaf, 0xa0, 0x38, 0x49, | ||||||
| 	0x7f, 0x30, 0x40, 0x32, 0x2f, 0xff, 0xc9, 0x43, 0x58, 0xed, 0x20, 0x9a, 0x39, 0xe4, 0x70, 0xa6, | 	0x44, 0x22, 0x2b, 0xdf, 0xea, 0x0b, 0x71, 0x16, 0xa7, 0xfa, 0xfa, 0xdf, 0x0a, 0x70, 0xbf, 0x45, | ||||||
| 	0x1b, 0xc0, 0xc9, 0xc8, 0x2a, 0xcd, 0x42, 0xb9, 0xd0, 0x90, 0x9d, 0x50, 0x24, 0x24, 0x94, 0x74, | 	0x98, 0x3f, 0x4a, 0x9e, 0xb6, 0x03, 0xca, 0xfa, 0xd3, 0x81, 0xc7, 0x6e, 0xfe, 0xca, 0x33, 0xb8, | ||||||
| 	0x26, 0x45, 0xde, 0xe6, 0x2f, 0x0b, 0xb0, 0x3c, 0xa5, 0xf9, 0x71, 0x07, 0x62, 0xf2, 0x12, 0x81, | 	0x3d, 0x0e, 0x28, 0x73, 0x67, 0x02, 0xce, 0x8d, 0x13, 0xb8, 0x34, 0xad, 0x1a, 0xdb, 0x50, 0xde, | ||||||
| 	0xb8, 0x0a, 0x49, 0xcf, 0xc7, 0x0f, 0xe5, 0x71, 0x98, 0xa7, 0xc1, 0x84, 0xbc, 0x86, 0x5c, 0x0b, | 	0x6a, 0x48, 0x7d, 0x29, 0x92, 0x12, 0x8c, 0xc6, 0xeb, 0x22, 0x7a, 0xf4, 0xaf, 0x1d, 0x38, 0xd8, | ||||||
| 	0x3d, 0xc3, 0x77, 0x2d, 0xa7, 0xe7, 0x7b, 0x22, 0xb6, 0x6a, 0x57, 0x40, 0xf9, 0x4e, 0x29, 0x84, | 	0xd0, 0xfc, 0x71, 0x67, 0x61, 0xfe, 0x06, 0x59, 0x78, 0x1b, 0xf2, 0x94, 0x79, 0x8c, 0x88, 0x24, | ||||||
| 	0xa5, 0xd1, 0x33, 0x36, 0x7f, 0x8d, 0x41, 0x2e, 0xb2, 0x48, 0xfe, 0x01, 0xa4, 0x6b, 0xbd, 0x95, | 	0x2c, 0xe3, 0x64, 0x83, 0xbe, 0x83, 0x92, 0x1f, 0x85, 0x94, 0xc5, 0x5e, 0x10, 0x32, 0x2a, 0x13, | ||||||
| 	0xb7, 0x2f, 0xd3, 0x2a, 0x23, 0x3e, 0x49, 0x8b, 0xb8, 0x12, 0xc0, 0x8a, 0xc4, 0x49, 0xfe, 0x09, | 	0xcb, 0x79, 0x0f, 0x94, 0xd7, 0x1b, 0x4b, 0x58, 0x9c, 0xbd, 0xe3, 0xe8, 0xdf, 0x0a, 0x94, 0x32, | ||||||
| 	0xab, 0x4c, 0x9b, 0x45, 0xf1, 0x0b, 0xcb, 0x0b, 0xf5, 0xe3, 0x5c, 0x9f, 0x21, 0x95, 0xc5, 0x92, | 	0x0f, 0xd1, 0xcf, 0x01, 0x4d, 0xbc, 0x37, 0xa9, 0xf7, 0xd3, 0x9a, 0xca, 0x89, 0xcf, 0x63, 0x6d, | ||||||
| 	0xdc, 0xb1, 0x0e, 0x29, 0xd7, 0x7e, 0xc9, 0x62, 0x9c, 0x7d, 0x79, 0x96, 0x8a, 0x19, 0xf9, 0x1c, | 	0xe2, 0xbd, 0x49, 0x60, 0x65, 0xd5, 0x44, 0xbf, 0x80, 0xdb, 0x5c, 0x9b, 0xa7, 0xf0, 0x2b, 0x8f, | ||||||
| 	0xd6, 0xbd, 0xe1, 0x60, 0xd0, 0x77, 0x7d, 0xbb, 0x6d, 0xb6, 0xfa, 0xdd, 0x81, 0x6b, 0x7b, 0x1e, | 	0x2e, 0xf5, 0x73, 0x42, 0x9f, 0x23, 0x35, 0xe5, 0xa3, 0xf4, 0xc4, 0x1d, 0x28, 0xc4, 0xe4, 0x9c, | ||||||
| 	0x2e, 0x5c, 0x58, 0x21, 0x4a, 0xa1, 0x1e, 0xa7, 0x79, 0x6d, 0x04, 0x11, 0x59, 0xf1, 0x94, 0xaf, | 	0x27, 0x38, 0x7f, 0xf3, 0x3d, 0x2c, 0x77, 0xe8, 0xf7, 0x70, 0x87, 0xce, 0xa6, 0xd3, 0x28, 0x66, | ||||||
| 	0xd3, 0x70, 0xeb, 0x3c, 0xc2, 0x44, 0x28, 0x9e, 0xc1, 0xda, 0xb8, 0xd7, 0x07, 0x72, 0x19, 0x98, | 	0x64, 0xe0, 0xfa, 0xd1, 0x64, 0x1a, 0x13, 0x4a, 0x83, 0x28, 0x7c, 0x6b, 0x7b, 0x68, 0x2c, 0xf5, | ||||||
| 	0xda, 0xfb, 0xdc, 0x41, 0xb0, 0x75, 0xec, 0x12, 0x02, 0x11, 0x5d, 0xe9, 0x4c, 0xc9, 0x3c, 0x52, | 	0x04, 0xcd, 0x87, 0x0b, 0x88, 0xcc, 0x13, 0xaa, 0xff, 0xb1, 0x08, 0x0f, 0x2e, 0x23, 0x4c, 0xa6, | ||||||
| 	0x87, 0xb5, 0xae, 0xd3, 0x73, 0xba, 0xc3, 0xae, 0x79, 0x6a, 0x39, 0x7e, 0x98, 0x04, 0xe3, 0x73, | 	0xe2, 0x05, 0x1c, 0xae, 0x46, 0x7d, 0x22, 0x4f, 0x13, 0xd3, 0x7c, 0x17, 0x1f, 0x24, 0x47, 0x57, | ||||||
| 	0x24, 0xc1, 0x15, 0xb1, 0xf5, 0x10, 0x77, 0x4a, 0xe1, 0xe6, 0xf7, 0x49, 0x20, 0xd3, 0xa7, 0x5f, | 	0x9c, 0x90, 0x88, 0xf0, 0xad, 0xf1, 0x86, 0x8c, 0xa2, 0x53, 0x38, 0x9c, 0x04, 0x61, 0x30, 0x99, | ||||||
| 	0x3e, 0x98, 0x66, 0x46, 0x41, 0xfc, 0x12, 0x51, 0x30, 0x15, 0x9d, 0x89, 0x0f, 0x8a, 0xce, 0x53, | 	0x4d, 0xdc, 0xb9, 0x17, 0xb0, 0x65, 0x05, 0xcc, 0x5d, 0x55, 0x01, 0x6f, 0xc9, 0x73, 0x67, 0x5e, | ||||||
| 	0x28, 0xc8, 0x0b, 0x0b, 0x60, 0x16, 0x38, 0x0c, 0xbd, 0x92, 0x4b, 0xdb, 0x91, 0x83, 0xe0, 0x60, | 	0xc0, 0x52, 0xe1, 0xd1, 0x5f, 0xf3, 0x80, 0x36, 0xaf, 0xbe, 0x79, 0x26, 0x6d, 0x4d, 0x81, 0xdc, | ||||||
| 	0x37, 0x32, 0x23, 0x9f, 0x40, 0xd6, 0x6a, 0xb7, 0x1d, 0x9f, 0xfb, 0x69, 0x92, 0x7b, 0x8a, 0xf2, | 	0x0d, 0x52, 0x60, 0x23, 0x35, 0xd5, 0x1f, 0x94, 0x9a, 0x73, 0xa8, 0xa4, 0xde, 0x4a, 0x60, 0x76, | ||||||
| 	0x0e, 0x22, 0x1a, 0xb6, 0x4f, 0xc3, 0x4d, 0xe4, 0x7f, 0x90, 0x71, 0xed, 0x6e, 0xff, 0x8d, 0xd5, | 	0x04, 0x0c, 0x7e, 0x2f, 0x1e, 0xab, 0xa7, 0x8b, 0xe4, 0xe2, 0x38, 0xb3, 0x43, 0x5f, 0xc2, 0x9e, | ||||||
| 	0xf1, 0xb0, 0xb0, 0xcf, 0x0b, 0x30, 0xda, 0x43, 0xee, 0x43, 0xb1, 0x67, 0x9f, 0x9a, 0x41, 0xee, | 	0x37, 0x18, 0x04, 0x4c, 0x04, 0x69, 0x5e, 0x84, 0x89, 0x7e, 0x05, 0x11, 0x5d, 0xc2, 0xf0, 0xf2, | ||||||
| 	0x36, 0x83, 0x94, 0x92, 0xe6, 0x29, 0x65, 0x11, 0xe5, 0x41, 0x7a, 0x6f, 0xf0, 0xdc, 0xf2, 0x2f, | 	0x10, 0xfa, 0x0d, 0xec, 0xc6, 0x64, 0x12, 0xbd, 0xf6, 0xc6, 0xb4, 0x56, 0xb8, 0x36, 0xc0, 0xe2, | ||||||
| 	0xc8, 0x60, 0xe5, 0x68, 0xbd, 0xf2, 0x86, 0xdd, 0x8d, 0xcc, 0xf9, 0x9e, 0x55, 0x12, 0x3a, 0x74, | 	0x0c, 0x7a, 0x0c, 0x5a, 0x48, 0xe6, 0x6e, 0x52, 0xb8, 0xdd, 0xa4, 0x9e, 0x14, 0x45, 0x3d, 0xa9, | ||||||
| 	0xa4, 0xad, 0x50, 0xc8, 0x47, 0x39, 0x20, 0x5b, 0x70, 0x9d, 0x6a, 0x8d, 0x7a, 0xcd, 0x68, 0x68, | 	0x86, 0x64, 0x9e, 0xd4, 0xf6, 0xae, 0x28, 0x2c, 0xbf, 0x84, 0x5d, 0x7f, 0x44, 0xfc, 0x6f, 0xe9, | ||||||
| 	0x66, 0xf3, 0xa8, 0xae, 0x99, 0x07, 0x46, 0xa3, 0xae, 0x95, 0xf4, 0x8a, 0xae, 0x95, 0x8b, 0x7f, | 	0x6c, 0x52, 0xdb, 0x15, 0x61, 0xf5, 0xe1, 0xd6, 0x7c, 0x92, 0x3a, 0x78, 0xa1, 0xad, 0x63, 0x28, | ||||||
| 	0x21, 0x04, 0x16, 0xeb, 0x2a, 0x6d, 0xea, 0x6a, 0xd5, 0x3c, 0xa8, 0x97, 0xd5, 0xa6, 0x56, 0x8c, | 	0x67, 0x39, 0x40, 0xf7, 0xe1, 0x1e, 0x36, 0xbb, 0x1d, 0xc7, 0xee, 0x9a, 0x6e, 0xef, 0x65, 0xc7, | ||||||
| 	0x91, 0x25, 0xc8, 0x55, 0x0e, 0xaa, 0x23, 0x41, 0x5c, 0xf9, 0x29, 0x06, 0x6b, 0xac, 0x30, 0x56, | 	0x74, 0xfb, 0x76, 0xb7, 0x63, 0x36, 0xac, 0x96, 0x65, 0x36, 0xb5, 0x9f, 0x20, 0x04, 0xd5, 0x8e, | ||||||
| 	0x86, 0x9d, 0xce, 0x9e, 0xe5, 0x5d, 0x41, 0xa9, 0xbe, 0x0b, 0x85, 0x28, 0x0b, 0x41, 0x9b, 0x9a, | 	0x81, 0x7b, 0x96, 0xd1, 0x76, 0xfb, 0x9d, 0xa6, 0xd1, 0x33, 0x35, 0x05, 0xed, 0x43, 0xa9, 0xd5, | ||||||
| 	0xa7, 0xf9, 0x56, 0xc8, 0x81, 0x37, 0x59, 0xcf, 0x13, 0xef, 0x5d, 0xcf, 0xff, 0x88, 0xc1, 0xfa, | 	0x6f, 0x2f, 0x04, 0x39, 0xfd, 0x1f, 0x0a, 0x1c, 0xf2, 0xae, 0xd8, 0x9a, 0x8d, 0xc7, 0x27, 0x1e, | ||||||
| 	0xa4, 0xdd, 0x97, 0xae, 0xe6, 0x57, 0x9f, 0x02, 0x48, 0x13, 0xae, 0xf5, 0xec, 0x97, 0x38, 0x7e, | 	0x7d, 0x0f, 0x7d, 0xfa, 0x11, 0x54, 0xb2, 0x2c, 0x24, 0x03, 0x6a, 0x19, 0x97, 0xfd, 0x25, 0x07, | ||||||
| 	0x63, 0x9b, 0x13, 0xbd, 0x55, 0x62, 0x0e, 0xcc, 0x35, 0xb9, 0xb9, 0x34, 0xd6, 0x63, 0xd5, 0x01, | 	0x74, 0xbd, 0x99, 0xab, 0xef, 0xdc, 0xcc, 0xff, 0xa7, 0xc0, 0x9d, 0x75, 0xbb, 0x6f, 0xdc, 0xca, | ||||||
| 	0x42, 0xe6, 0xc9, 0x0d, 0xc8, 0x0a, 0xc6, 0x9d, 0x36, 0xbf, 0xac, 0x2c, 0x3a, 0x4d, 0xb0, 0xdc, | 	0xdf, 0x73, 0xfe, 0xa3, 0xaf, 0xe1, 0x6e, 0x48, 0xce, 0x3d, 0x16, 0xbc, 0x26, 0xee, 0xda, 0x48, | ||||||
| 	0x26, 0xf7, 0xb0, 0xa7, 0x0b, 0x16, 0xdf, 0xd8, 0xae, 0x27, 0xbf, 0x25, 0x4b, 0xc5, 0x25, 0x3d, | 	0xa5, 0x5e, 0x05, 0x78, 0x98, 0x9e, 0x6c, 0xac, 0x8c, 0x56, 0x1d, 0x80, 0x25, 0xe7, 0xe8, 0x03, | ||||||
| 	0x0b, 0x84, 0x8a, 0x02, 0x19, 0xe9, 0x71, 0xac, 0x34, 0x78, 0x27, 0xd6, 0x83, 0x47, 0x8f, 0x39, | 	0xd8, 0x93, 0x5c, 0x07, 0x03, 0xe1, 0xa6, 0x3d, 0xbc, 0x9b, 0x08, 0xac, 0x01, 0xfa, 0x18, 0xaa, | ||||||
| 	0x58, 0x9e, 0x8a, 0x99, 0xf2, 0x50, 0x36, 0xe7, 0xdc, 0xff, 0xd1, 0xbf, 0x16, 0x4e, 0x90, 0x79, | 	0xf2, 0xe1, 0x6b, 0x12, 0xd3, 0xf4, 0x2d, 0xf6, 0xb0, 0x74, 0xcf, 0xf3, 0x44, 0xa8, 0xeb, 0xb0, | ||||||
| 	0xa1, 0xc4, 0xc7, 0xa4, 0x08, 0x89, 0xa1, 0xdb, 0x11, 0x47, 0xb0, 0xa1, 0xf2, 0x7b, 0x1c, 0x16, | 	0x9b, 0xc6, 0x1a, 0xef, 0x08, 0x74, 0xe4, 0x3d, 0xfd, 0xec, 0x73, 0x01, 0x56, 0xc6, 0x72, 0xa7, | ||||||
| 	0xc7, 0xa3, 0x86, 0x18, 0x50, 0x8c, 0x14, 0x96, 0x68, 0x12, 0x9c, 0xab, 0xb8, 0x2c, 0xb5, 0xc6, | 	0x7f, 0x9a, 0x0e, 0xe4, 0x22, 0xf2, 0x11, 0x82, 0x9d, 0x91, 0x47, 0x47, 0x52, 0x49, 0xac, 0x91, | ||||||
| 	0x05, 0xe4, 0xbf, 0x00, 0xae, 0x75, 0x6a, 0x9e, 0x70, 0x37, 0x10, 0x57, 0xb5, 0x35, 0x0b, 0x89, | 	0x06, 0xea, 0x2c, 0x1e, 0xcb, 0x2b, 0xf8, 0x52, 0xff, 0x6f, 0x0e, 0xaa, 0xab, 0xf9, 0x82, 0x6c, | ||||||
| 	0x5a, 0xa7, 0xc2, 0x57, 0xb2, 0xae, 0x1c, 0x32, 0x57, 0x64, 0xbb, 0xd1, 0x97, 0x9c, 0x16, 0x7f, | 	0xd0, 0x32, 0xfd, 0x24, 0x5b, 0xfe, 0xae, 0xd5, 0x53, 0xf6, 0xfd, 0x55, 0x01, 0xfa, 0x35, 0x40, | ||||||
| 	0xb8, 0x9c, 0xeb, 0x8a, 0xb8, 0x5d, 0x0f, 0xb4, 0x28, 0x3b, 0x50, 0x8c, 0xf1, 0xf1, 0x93, 0x73, | 	0xec, 0xcd, 0xdd, 0x91, 0x08, 0x00, 0xe9, 0xa4, 0xfb, 0xdb, 0x90, 0xb0, 0x37, 0x97, 0x51, 0xb2, | ||||||
| 	0x71, 0x20, 0xcf, 0x0f, 0x9a, 0x85, 0x7b, 0x33, 0x01, 0x50, 0xad, 0x6c, 0x77, 0x7c, 0x4b, 0xeb, | 	0x17, 0xa7, 0x4b, 0x1e, 0x84, 0xfc, 0x74, 0x10, 0x0e, 0x02, 0x5f, 0x7c, 0xac, 0x5c, 0x1a, 0x84, | ||||||
| 	0xb5, 0xfa, 0x6d, 0x94, 0x23, 0x0e, 0x8a, 0x84, 0x21, 0x7b, 0x90, 0xe7, 0x38, 0xd2, 0x92, 0xe4, | 	0xd8, 0x9b, 0x5b, 0x89, 0x16, 0xe6, 0x17, 0xca, 0x35, 0x6a, 0x41, 0x29, 0x0e, 0x7c, 0x92, 0xde, | ||||||
| 	0xfb, 0x00, 0x71, 0x13, 0x84, 0x45, 0xca, 0xdf, 0x00, 0x42, 0x5b, 0xc9, 0x06, 0xa4, 0x25, 0x24, | 	0x9f, 0xcc, 0x08, 0x1f, 0x6f, 0x05, 0x08, 0x7c, 0xd2, 0x24, 0x63, 0xe6, 0x99, 0xa1, 0x1f, 0x0d, | ||||||
| 	0x8b, 0x87, 0x24, 0x95, 0x53, 0xe5, 0x29, 0x64, 0x47, 0x94, 0x90, 0xdb, 0x90, 0x43, 0x56, 0x8f, | 	0x82, 0xf0, 0x1c, 0x03, 0x3f, 0x29, 0x0d, 0x39, 0x81, 0xb2, 0xc0, 0x49, 0x2d, 0xc9, 0xbf, 0x0b, | ||||||
| 	0x9d, 0xb7, 0xa6, 0xe7, 0x7c, 0x69, 0x8b, 0x4e, 0x03, 0x02, 0x51, 0x03, 0x25, 0x98, 0x6e, 0x26, | 	0x90, 0x30, 0x41, 0x5a, 0xa4, 0xff, 0x14, 0x60, 0x69, 0x2b, 0xaa, 0x41, 0x31, 0x85, 0xe4, 0x99, | ||||||
| 	0x69, 0xce, 0x47, 0x78, 0x54, 0xbe, 0x8b, 0xc1, 0xf2, 0x94, 0x5d, 0x0c, 0xf5, 0xd8, 0x71, 0xb1, | 	0x90, 0xc7, 0xe9, 0x56, 0xff, 0x0a, 0xf6, 0x16, 0x94, 0xa0, 0x87, 0x50, 0x9a, 0xc6, 0x64, 0x18, | ||||||
| 	0xa0, 0x63, 0x96, 0x1c, 0x06, 0xa8, 0x09, 0x0a, 0x5c, 0xf4, 0x8c, 0x49, 0x98, 0x7f, 0xf2, 0xaf, | 	0xbc, 0x71, 0x69, 0xf0, 0x3d, 0x91, 0x03, 0x06, 0x24, 0xa2, 0x6e, 0xf0, 0x3d, 0x2f, 0x34, 0xeb, | ||||||
| 	0x1e, 0x58, 0xae, 0x85, 0x8f, 0x19, 0xdb, 0x15, 0x3d, 0x4b, 0x81, 0x49, 0xeb, 0x52, 0xc8, 0x70, | 	0x34, 0x97, 0x33, 0x3c, 0xea, 0x7f, 0x51, 0xe0, 0x60, 0xc3, 0x2e, 0x8e, 0x3a, 0x0c, 0x62, 0xca, | ||||||
| 	0x7a, 0x18, 0x95, 0xe1, 0xf3, 0x92, 0x5b, 0x87, 0x22, 0xd9, 0xcf, 0xfc, 0x15, 0xf2, 0x36, 0x3b, | 	0xdc, 0xd7, 0xde, 0x78, 0x96, 0xa0, 0xaa, 0x18, 0x84, 0xe8, 0x39, 0x97, 0xf0, 0xf8, 0x14, 0x6f, | ||||||
| 	0x14, 0xbb, 0x96, 0xd1, 0x7b, 0x28, 0x4f, 0x73, 0x42, 0xc6, 0xba, 0x1f, 0x66, 0xe1, 0xca, 0x8c, | 	0x3d, 0xf5, 0x62, 0x6f, 0x42, 0x18, 0x89, 0xe5, 0xa8, 0x52, 0xe1, 0xd2, 0x4e, 0x2a, 0xe4, 0x38, | ||||||
| 	0xb7, 0x10, 0x96, 0xd3, 0x74, 0xd8, 0x5f, 0xb1, 0x84, 0xf1, 0x68, 0xce, 0x57, 0xd4, 0x8e, 0x1c, | 	0xe1, 0x6c, 0x92, 0xf9, 0xa4, 0x14, 0xd6, 0x85, 0xb3, 0x49, 0x3a, 0xc6, 0x7c, 0x04, 0x65, 0xc2, | ||||||
| 	0x04, 0x6f, 0x34, 0x89, 0xb2, 0xf9, 0x04, 0x0a, 0x63, 0x2b, 0x2c, 0x2c, 0x5e, 0xd9, 0x67, 0x22, | 	0x2f, 0x25, 0x03, 0x77, 0xf1, 0x0d, 0x54, 0xc6, 0x25, 0x29, 0xe3, 0x43, 0x0f, 0xb7, 0xf0, 0xd6, | ||||||
| 	0x52, 0xd8, 0x90, 0xf5, 0x9d, 0x01, 0x23, 0x01, 0x8f, 0xc1, 0x44, 0xf9, 0x2d, 0x06, 0xab, 0x61, | 	0x96, 0xef, 0x1f, 0xe4, 0x40, 0x71, 0x39, 0x56, 0xf1, 0x52, 0xf1, 0xd9, 0x35, 0xbf, 0x9c, 0xea, | ||||||
| 	0x4d, 0x2c, 0xdb, 0x5e, 0xcb, 0x75, 0x06, 0x7e, 0xdf, 0xfd, 0xb8, 0xfb, 0xef, 0xc4, 0x87, 0x77, | 	0xe9, 0x22, 0xf9, 0x2e, 0x4b, 0x51, 0x8e, 0xbe, 0x80, 0xca, 0xca, 0x13, 0x9e, 0x16, 0xdf, 0x92, | ||||||
| 	0x1e, 0xca, 0x31, 0x5c, 0x63, 0x9f, 0x1a, 0x7e, 0x74, 0x98, 0xc7, 0x9f, 0x8e, 0xfe, 0x99, 0xb0, | 	0x0b, 0x99, 0x29, 0x7c, 0xc9, 0xc7, 0xcd, 0x84, 0x91, 0x84, 0xc7, 0x64, 0xa3, 0xff, 0x47, 0x81, | ||||||
| 	0x6e, 0x4d, 0xde, 0xcd, 0xfd, 0xf3, 0x8f, 0x19, 0xe7, 0x4c, 0xfe, 0x3d, 0xe1, 0xa0, 0xca, 0x7f, | 	0xdb, 0xcb, 0x6e, 0xd8, 0x24, 0xd4, 0x8f, 0x83, 0x29, 0x8b, 0xe2, 0x1f, 0xf7, 0xd8, 0xad, 0xfe, | ||||||
| 	0x20, 0x33, 0xca, 0xc9, 0x18, 0x10, 0x9e, 0x8d, 0xbd, 0x77, 0xdb, 0x13, 0xfe, 0x28, 0xa7, 0xec, | 	0xf0, 0x99, 0x43, 0x1f, 0xc2, 0x5d, 0xfe, 0xaa, 0xcb, 0x97, 0x5e, 0x56, 0xf0, 0xaf, 0x16, 0xff, | ||||||
| 	0x56, 0x7a, 0x56, 0xaf, 0x2f, 0xfb, 0xe6, 0x60, 0xb2, 0xfd, 0x55, 0x4c, 0xfe, 0xcb, 0xe1, 0x1c, | 	0x49, 0xf8, 0x90, 0x96, 0xfa, 0xe6, 0xf1, 0xe5, 0xd7, 0xac, 0x72, 0x96, 0xfe, 0x31, 0x11, 0xa0, | ||||||
| 	0xdc, 0x80, 0x6b, 0xcd, 0x3d, 0xaa, 0xa9, 0xcd, 0x59, 0x45, 0x37, 0x07, 0xe9, 0x7d, 0xb5, 0x7a, | 	0x4f, 0xfe, 0xa0, 0xa4, 0xff, 0x60, 0xc4, 0x7b, 0x7c, 0x00, 0x77, 0x7b, 0x27, 0xd8, 0x34, 0x7a, | ||||||
| 	0xa8, 0x52, 0x56, 0x6d, 0xd7, 0x81, 0x34, 0x6a, 0x25, 0x56, 0x80, 0x35, 0x63, 0x57, 0x37, 0x34, | 	0xdb, 0x5a, 0x66, 0x09, 0x8a, 0xa7, 0x46, 0xfb, 0xcc, 0xc0, 0xbc, 0x57, 0xde, 0x01, 0xd4, 0x75, | ||||||
| 	0x8d, 0xea, 0xc6, 0x6e, 0x31, 0x4e, 0xd6, 0x60, 0xf9, 0xc0, 0x38, 0x54, 0x8d, 0xa6, 0x56, 0x36, | 	0x1a, 0xbc, 0x7d, 0x9a, 0xf6, 0x33, 0xcb, 0x36, 0x4d, 0x6c, 0xd9, 0xcf, 0xb4, 0x1c, 0x3a, 0x84, | ||||||
| 	0x1b, 0xb5, 0x4a, 0x93, 0xab, 0x27, 0xb0, 0x72, 0xde, 0xae, 0xd7, 0x9a, 0x9a, 0xc1, 0x4a, 0x76, | 	0x83, 0xbe, 0x7d, 0x66, 0xd8, 0x3d, 0xb3, 0xe9, 0x76, 0x9d, 0x56, 0x4f, 0xa8, 0xab, 0xe8, 0x11, | ||||||
| 	0xf5, 0xc8, 0xdc, 0x53, 0xe9, 0x3e, 0x16, 0x6b, 0x53, 0xad, 0xd7, 0xab, 0x7a, 0x49, 0x6d, 0xea, | 	0x3c, 0xec, 0x38, 0x3d, 0xd3, 0xe6, 0x0d, 0xb7, 0xfd, 0xd2, 0x3d, 0x31, 0xf0, 0x69, 0xab, 0xdf, | ||||||
| 	0x35, 0xa3, 0xb8, 0xb0, 0xfd, 0x6d, 0x0c, 0xf2, 0xd1, 0x0b, 0x62, 0x5d, 0x40, 0xbd, 0xaa, 0x36, | 	0x76, 0x8d, 0x4e, 0xa7, 0x6d, 0x35, 0x8c, 0x9e, 0xe5, 0xd8, 0xda, 0xce, 0x93, 0x3f, 0x2b, 0x50, | ||||||
| 	0x2b, 0x35, 0xba, 0x7f, 0x8e, 0x41, 0x87, 0xba, 0x51, 0xae, 0x1d, 0x36, 0xd0, 0xa0, 0x2c, 0x24, | 	0xce, 0x92, 0xcc, 0x7b, 0x78, 0xa7, 0x6d, 0xf4, 0x5a, 0x0e, 0x3e, 0xbd, 0xc4, 0xa0, 0x33, 0xcb, | ||||||
| 	0xab, 0xba, 0x71, 0xf0, 0x1c, 0x6d, 0x40, 0xb9, 0x6a, 0x94, 0x69, 0x4d, 0x2f, 0xe3, 0xc9, 0x69, | 	0x6e, 0x3a, 0x67, 0x5d, 0x4d, 0x41, 0x7b, 0x90, 0x6f, 0x5b, 0x76, 0xff, 0x85, 0x96, 0xe3, 0x72, | ||||||
| 	0x48, 0xd4, 0x1a, 0xcf, 0x8b, 0x0b, 0x6c, 0xa0, 0xd7, 0x1a, 0xc5, 0x24, 0x7a, 0x6c, 0x5e, 0x35, | 	0xc3, 0x6e, 0x62, 0xc7, 0x6a, 0x6a, 0x2a, 0x2a, 0x82, 0xea, 0x74, 0x5f, 0x68, 0x3b, 0x7c, 0x61, | ||||||
| 	0x8e, 0x4c, 0x89, 0x5c, 0x4c, 0x91, 0x65, 0x28, 0xa0, 0x59, 0x23, 0x49, 0xa3, 0x98, 0x26, 0x00, | 	0x39, 0x5d, 0x2d, 0x8f, 0x34, 0x28, 0x1b, 0xf6, 0x4b, 0x37, 0x45, 0xd6, 0x0a, 0xe8, 0x00, 0x2a, | ||||||
| 	0xa9, 0xd2, 0x1e, 0xad, 0xed, 0x6b, 0xc5, 0xcc, 0x76, 0x05, 0x96, 0x26, 0x12, 0x35, 0xb9, 0x03, | 	0x46, 0xbb, 0xbd, 0x90, 0x74, 0xb5, 0x22, 0x02, 0x28, 0x34, 0x4e, 0xb0, 0x73, 0x6a, 0x6a, 0xbb, | ||||||
| 	0x37, 0x4b, 0xb5, 0xfd, 0x3a, 0xf6, 0x28, 0x0d, 0xb4, 0x7d, 0x96, 0x71, 0x78, 0x1c, 0x55, 0x0f, | 	0x4f, 0x5a, 0xb0, 0xbf, 0x56, 0x6c, 0xd1, 0x31, 0x7c, 0xd8, 0x70, 0x4e, 0x3b, 0xd8, 0xec, 0x76, | ||||||
| 	0xd1, 0xb0, 0x0c, 0x2c, 0x50, 0xbd, 0x84, 0x0d, 0xc9, 0xb6, 0x03, 0x4b, 0x13, 0x4e, 0x83, 0xa1, | 	0x2d, 0xc7, 0xde, 0x66, 0x5c, 0x11, 0x54, 0x6c, 0x9c, 0x69, 0x0a, 0xda, 0x85, 0x1d, 0x6c, 0x35, | ||||||
| 	0xbd, 0x25, 0x08, 0x47, 0x6e, 0xe8, 0xd1, 0x39, 0xbd, 0xce, 0x01, 0x45, 0x9a, 0x9f, 0xcb, 0xd3, | 	0x4c, 0x2d, 0xf7, 0xe4, 0x1b, 0xd8, 0x5f, 0x73, 0x3c, 0xfa, 0x08, 0xee, 0x4b, 0xc2, 0x4d, 0xbb, | ||||||
| 	0x10, 0x13, 0x0d, 0xfe, 0x54, 0x37, 0x54, 0xdc, 0x50, 0xd6, 0x77, 0xb5, 0x46, 0x13, 0x3f, 0x3a, | 	0x87, 0x5f, 0x5e, 0x02, 0xd4, 0xc7, 0x6d, 0x4d, 0x41, 0x55, 0x00, 0xf3, 0x85, 0xd9, 0xe8, 0xf7, | ||||||
| 	0x0f, 0x19, 0xbd, 0x6e, 0x52, 0xd5, 0xd8, 0x45, 0xbe, 0x5f, 0xa4, 0xb8, 0xf3, 0x3c, 0xfc, 0x33, | 	0x8c, 0xdf, 0xb5, 0x4d, 0x2d, 0x87, 0xca, 0xb0, 0x6b, 0x75, 0x5c, 0x6c, 0xd8, 0xcf, 0x4c, 0x4d, | ||||||
| 	0x00, 0x00, 0xff, 0xff, 0x08, 0xe3, 0x60, 0x1f, 0xd4, 0x13, 0x00, 0x00, | 	0x7d, 0x55, 0x10, 0x2e, 0xff, 0xf4, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x68, 0x6b, 0x92, 0x80, | ||||||
|  | 	0x9e, 0x13, 0x00, 0x00, | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								vendor/github.com/google/safebrowsing/internal/safebrowsing_proto/safebrowsing.proto
								
								
									generated
								
								
									vendored
								
								
							
							
						
						
									
										31
									
								
								vendor/github.com/google/safebrowsing/internal/safebrowsing_proto/safebrowsing.proto
								
								
									generated
								
								
									vendored
								
								
							|  | @ -14,6 +14,8 @@ | ||||||
| 
 | 
 | ||||||
| syntax = "proto3"; | syntax = "proto3"; | ||||||
| 
 | 
 | ||||||
|  | import "google/protobuf/duration.proto"; | ||||||
|  | 
 | ||||||
| package safebrowsing_proto; | package safebrowsing_proto; | ||||||
| 
 | 
 | ||||||
| // The Safe Browsing APIs enable clients to check web resources (most commonly | // 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 |   // The cache lifetime for the returned match. Clients must not cache this | ||||||
|   // response for more than this duration to avoid false positives. |   // 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. | // Request to check entries against lists. | ||||||
|  | @ -208,7 +210,7 @@ message FetchThreatListUpdatesResponse { | ||||||
| 
 | 
 | ||||||
|   // The minimum duration the client must wait before issuing any update |   // 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. |   // 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. | // 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 |   // 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 |   // request. If this field is not set, clients can issue a request as soon as | ||||||
|   // they want. |   // 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 |   // For requested entities that did not match the threat list, how long to | ||||||
|   // cache the response. |   // 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. |   // The lists available for download by the client. | ||||||
|   repeated ThreatListDescriptor threat_lists = 1; |   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; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -72,6 +72,7 @@ | ||||||
| package safebrowsing | package safebrowsing | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"io" | 	"io" | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
|  | @ -94,6 +95,10 @@ const ( | ||||||
| 	// strings to send with every API call.
 | 	// strings to send with every API call.
 | ||||||
| 	DefaultID      = "GoSafeBrowser" | 	DefaultID      = "GoSafeBrowser" | ||||||
| 	DefaultVersion = "1.0.0" | 	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.
 | // Errors specific to this package.
 | ||||||
|  | @ -207,6 +212,9 @@ type Config struct { | ||||||
| 	// If empty, it defaults to DefaultThreatLists.
 | 	// If empty, it defaults to DefaultThreatLists.
 | ||||||
| 	ThreatLists []ThreatDescriptor | 	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
 | 	// Logger is an io.Writer that allows SafeBrowser to write debug information
 | ||||||
| 	// intended for human consumption.
 | 	// intended for human consumption.
 | ||||||
| 	// If empty, no logs will be written.
 | 	// If empty, no logs will be written.
 | ||||||
|  | @ -231,6 +239,9 @@ func (c *Config) setDefaults() bool { | ||||||
| 	if c.UpdatePeriod <= 0 { | 	if c.UpdatePeriod <= 0 { | ||||||
| 		c.UpdatePeriod = DefaultUpdatePeriod | 		c.UpdatePeriod = DefaultUpdatePeriod | ||||||
| 	} | 	} | ||||||
|  | 	if c.RequestTimeout <= 0 { | ||||||
|  | 		c.RequestTimeout = DefaultRequestTimeout | ||||||
|  | 	} | ||||||
| 	if c.compressionTypes == nil { | 	if c.compressionTypes == nil { | ||||||
| 		c.compressionTypes = []pb.CompressionType{pb.CompressionType_RAW, pb.CompressionType_RICE} | 		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
 | // local database and caching that would normally be needed to interact
 | ||||||
| // with the API server.
 | // with the API server.
 | ||||||
| type SafeBrowser struct { | type SafeBrowser struct { | ||||||
|  | 	stats  Stats // Must be first for 64-bit alignment on non 64-bit systems.
 | ||||||
| 	config Config | 	config Config | ||||||
| 	stats  Stats |  | ||||||
| 	api    api | 	api    api | ||||||
| 	db     database | 	db     database | ||||||
| 	c      cache | 	c      cache | ||||||
|  | @ -267,10 +278,11 @@ type SafeBrowser struct { | ||||||
| 
 | 
 | ||||||
| // Stats records statistics regarding SafeBrowser's operation.
 | // Stats records statistics regarding SafeBrowser's operation.
 | ||||||
| type Stats struct { | type Stats struct { | ||||||
| 	QueriesByDatabase int64 // Number of queries satisfied by the database alone
 | 	QueriesByDatabase int64         // Number of queries satisfied by the database alone
 | ||||||
| 	QueriesByCache    int64 // Number of queries satisfied by the cache alone
 | 	QueriesByCache    int64         // Number of queries satisfied by the cache alone
 | ||||||
| 	QueriesByAPI      int64 // Number of queries satisfied by an API call
 | 	QueriesByAPI      int64         // Number of queries satisfied by an API call
 | ||||||
| 	QueriesFail       int64 // Number of queries that could not be satisfied
 | 	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.
 | // NewSafeBrowser creates a new SafeBrowser.
 | ||||||
|  | @ -286,7 +298,7 @@ func NewSafeBrowser(conf Config) (*SafeBrowser, error) { | ||||||
| 	// Create the SafeBrowsing object.
 | 	// Create the SafeBrowsing object.
 | ||||||
| 	if conf.api == nil { | 	if conf.api == nil { | ||||||
| 		var err error | 		var err error | ||||||
| 		conf.api, err = newNetAPI(conf.ServerURL, conf.APIKey) | 		conf.api, err = newNetAPI(conf.ServerURL, conf.APIKey, conf.RequestTimeout) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			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) | 	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 database file is provided, use that to initialize.
 | ||||||
| 	if !sb.db.Init(&sb.config, sb.log) { | 	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.
 | 	// Start the background list updater.
 | ||||||
| 	sb.done = make(chan bool) | 	sb.done = make(chan bool) | ||||||
| 	go sb.updater(conf.UpdatePeriod) | 	go sb.updater(delay) | ||||||
| 	return sb, nil | 	return sb, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -337,10 +354,28 @@ func (sb *SafeBrowser) Status() (Stats, error) { | ||||||
| 		QueriesByCache:    atomic.LoadInt64(&sb.stats.QueriesByCache), | 		QueriesByCache:    atomic.LoadInt64(&sb.stats.QueriesByCache), | ||||||
| 		QueriesByAPI:      atomic.LoadInt64(&sb.stats.QueriesByAPI), | 		QueriesByAPI:      atomic.LoadInt64(&sb.stats.QueriesByAPI), | ||||||
| 		QueriesFail:       atomic.LoadInt64(&sb.stats.QueriesFail), | 		QueriesFail:       atomic.LoadInt64(&sb.stats.QueriesFail), | ||||||
|  | 		DatabaseUpdateLag: sb.db.UpdateLag(), | ||||||
| 	} | 	} | ||||||
| 	return stats, sb.db.Status() | 	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
 | // 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
 | // every URL requested, and an error if any occurred. It is safe to call this
 | ||||||
| // method concurrently.
 | // 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.
 | // updater is a blocking method that periodically updates the local database.
 | ||||||
| // This should be run as a separate goroutine and will be automatically stopped
 | // This should be run as a separate goroutine and will be automatically stopped
 | ||||||
| // when sb.Close is called.
 | // when sb.Close is called.
 | ||||||
| func (sb *SafeBrowser) updater(period time.Duration) { | func (sb *SafeBrowser) updater(delay time.Duration) { | ||||||
| 	ticker := time.NewTicker(period) |  | ||||||
| 	defer ticker.Stop() |  | ||||||
| 
 |  | ||||||
| 	for { | 	for { | ||||||
|  | 		sb.log.Printf("Next update in %v", delay) | ||||||
| 		select { | 		select { | ||||||
| 		case <-ticker.C: | 		case <-time.After(delay): | ||||||
| 			sb.log.Printf("background threat list update") | 			var ok bool | ||||||
| 			sb.c.Purge() | 			if delay, ok = sb.db.Update(sb.api); ok { | ||||||
| 			sb.db.Update(sb.api) | 				sb.log.Printf("background threat list updated") | ||||||
|  | 				sb.c.Purge() | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
| 		case <-sb.done: | 		case <-sb.done: | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | @ -426,13 +426,9 @@ func generateLookupHosts(urlStr string) ([]string, error) { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	// handle IPv4 and IPv6 addresses.
 | 	// handle IPv4 and IPv6 addresses.
 | ||||||
| 	u, err := url.Parse(urlStr) | 	ip := net.ParseIP(strings.Trim(host, "[]")) | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	ip := net.ParseIP(strings.Trim(u.Host, "[]")) |  | ||||||
| 	if ip != nil { | 	if ip != nil { | ||||||
| 		return []string{u.Host}, nil | 		return []string{host}, nil | ||||||
| 	} | 	} | ||||||
| 	hostComponents := strings.Split(host, ".") | 	hostComponents := strings.Split(host, ".") | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue