Google Safe Browsing V4 Improvements (#2504)
This PR has three primary contributions: 1. The existing code for using the V4 safe browsing API introduced in #2446 had some bugs that are fixed in this PR. 2. A gsb-test-srv is added to provide a mock Google Safebrowsing V4 server for integration testing purposes. 3. A short integration test is added to test end-to-end GSB lookup for an "unsafe" domain. For 1) most notably Boulder was assuming the new V4 library accepted a directory for its database persistence when it instead expects an existing file to be provided. Additionally the VA wasn't properly instantiating feature flags preventing the V4 api from being used by the VA. For 2) the test server is designed to have a fixed set of "bad" domains (Currently just honest.achmeds.discount.hosting.com). When asked for a database update by a client it will package the list of bad domains up & send them to the client. When the client is asked to do a URL lookup it will check the local database for a matching prefix, and if found, perform a lookup against the test server. The test server will process the lookup and increment a count for how many times the bad domain was asked about. For 3) the Boulder startservers.py was updated to start the gsb-test-srv and the VA is configured to talk to it using the V4 API. The integration test consists of attempting issuance for a domain pre-configured in the gsb-test-srv as a bad domain. If the issuance succeeds we know the GSB lookup code is faulty. If the issuance fails, we check that the gsb-test-srv received the correct number of lookups for the "bad" domain and fail if the expected isn't reality. Notes for reviewers: * The gsb-test-srv has to be started before anything will use it. Right now the v4 library handles database update request failures poorly and will not retry for 30min. See google/safebrowsing#44 for more information. * There's not an easy way to test for "good" domain lookups, only hits against the list. The design of the V4 API is such that a list of prefixes is delivered to the client in the db update phase and if the domain in question matches no prefixes then the lookup is deemed unneccesary and not performed. I experimented with sending 256 1 byte prefixes to try and trick the client to always do a lookup, but the min prefix size is 4 bytes and enumerating all possible prefixes seemed gross. * The test server has a /add endpoint that could be used by integration tests to add new domains to the block list, but it isn't being used presently. The trouble is that the client only updates its database every 30 minutes at present, and so adding a new domain will only take affect after the client updates the database. Resolves #2448
This commit is contained in:
parent
170e37c675
commit
15e73edc5a
|
@ -5,13 +5,22 @@ package main
|
|||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
safebrowsingv4 "github.com/google/safebrowsing"
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/va"
|
||||
safebrowsing "github.com/letsencrypt/go-safe-browsing-api"
|
||||
)
|
||||
|
||||
const (
|
||||
// Filename used for the v4 safebrowsing client's local database in the
|
||||
// configured GSB data directory. The file contents are a gzipped GOB encoding
|
||||
// of the client's in-memory cache.
|
||||
v4DbFilename = "safebrowsing.v4.cache.bin"
|
||||
)
|
||||
|
||||
var (
|
||||
NilConfigErr = errors.New("Google Safe Browsing config was nil")
|
||||
EmptyAPIKeyErr = errors.New("a Google Safe Browsing config was given but " +
|
||||
|
@ -23,6 +32,8 @@ var (
|
|||
BadDataDirErr = errors.New("a Google Safe Browsing data directory was " +
|
||||
"given but it cannot be opened")
|
||||
EmptyURLThreatErr = errors.New("Empty URLThreat from LookupURLs[0]")
|
||||
BadDBFileErr = errors.New("unable to create Google Safe Browsing v4 db " +
|
||||
"file in data directory")
|
||||
)
|
||||
|
||||
// configCheck returns an error if:
|
||||
|
@ -64,53 +75,66 @@ func (sb gsbAdapter) IsListed(url string) (string, error) {
|
|||
if err != nil {
|
||||
return "error", err
|
||||
}
|
||||
if len(threats) > 0 {
|
||||
// NOTE: We only return the _first_ URL threat's first ThreatType here. It's
|
||||
// possible a URL could return multiple threat's with distinct ThreatTypes,
|
||||
// but the va.SafeBrowser interface only returns 1 string that is compared
|
||||
// against "" to make a "safe or not" decision. We do not need more
|
||||
// granularity.
|
||||
if len(threats[0]) == 0 {
|
||||
return "error", EmptyURLThreatErr
|
||||
}
|
||||
return threats[0][0].ThreatType.String(), nil
|
||||
if len(threats) > 0 && threats[0] != nil {
|
||||
// Note: We don't bother to examine the threats for their ThreatType or
|
||||
// other information. The va.SafeBrowser interface expects a "hit" return
|
||||
// string that is compared against "" to make a "safe or not" decision. For
|
||||
// our purposes it is sufficient to return a fixed string instead of further
|
||||
// processing of the results.
|
||||
return "v4-gsb-hit", nil
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// gsbLogAdapter adapts a blog.Logger to the io.Writer interface used by the
|
||||
// Google safebrowsing client for a logger. All messages written to the Writer
|
||||
// by the library will be adapter to the logger's Info method.
|
||||
type gsbLogAdapter struct {
|
||||
log blog.Logger
|
||||
}
|
||||
|
||||
func (a gsbLogAdapter) Write(b []byte) (int, error) {
|
||||
a.log.Info(string(b))
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// newGoogleSafeBrowsingV4 constructs a va.SafeBrowsing instance using the new
|
||||
// Google upstream Safe Browsing version 4 client.
|
||||
func newGoogleSafeBrowsingV4(gsb *cmd.GoogleSafeBrowsingConfig) va.SafeBrowsing {
|
||||
func newGoogleSafeBrowsingV4(gsb *cmd.GoogleSafeBrowsingConfig, logger blog.Logger) (va.SafeBrowsing, error) {
|
||||
// If there is no GSB configuration, don't create a client
|
||||
if gsb == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
if err := configCheck(gsb); err != nil {
|
||||
cmd.FailOnError(err, "unable to create new safe browsing v4 client")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbFile := filepath.Join(gsb.DataDir, v4DbFilename)
|
||||
sb, err := safebrowsingv4.NewSafeBrowser(safebrowsingv4.Config{
|
||||
APIKey: gsb.APIKey,
|
||||
DBPath: gsb.DataDir,
|
||||
APIKey: gsb.APIKey,
|
||||
DBPath: dbFile,
|
||||
ServerURL: gsb.ServerURL,
|
||||
Logger: gsbLogAdapter{logger},
|
||||
})
|
||||
if err != nil {
|
||||
cmd.FailOnError(err, "unable to create new safe browsing v4 client")
|
||||
return nil, err
|
||||
}
|
||||
return gsbAdapter{sb}
|
||||
return gsbAdapter{sb}, nil
|
||||
}
|
||||
|
||||
// newGoogleSafeBrowsing constructs a va.SafeBrowsing instance using the legacy
|
||||
// letsencrypt fork of the go-safebrowsing-api client.
|
||||
func newGoogleSafeBrowsing(gsb *cmd.GoogleSafeBrowsingConfig) va.SafeBrowsing {
|
||||
func newGoogleSafeBrowsing(gsb *cmd.GoogleSafeBrowsingConfig) (va.SafeBrowsing, error) {
|
||||
// If there is no GSB configuration, don't create a client
|
||||
if gsb == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
if err := configCheck(gsb); err != nil {
|
||||
cmd.FailOnError(err, "unable to create new safe browsing client")
|
||||
return nil, err
|
||||
}
|
||||
sbc, err := safebrowsing.NewSafeBrowsing(gsb.APIKey, gsb.DataDir)
|
||||
if err != nil {
|
||||
cmd.FailOnError(err, "unable to create new safe browsing client")
|
||||
return nil, err
|
||||
}
|
||||
return sbc
|
||||
return sbc, nil
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ type config struct {
|
|||
|
||||
// Feature flag to enable enforcement of CAA SERVFAILs.
|
||||
CAASERVFAILExceptions string
|
||||
|
||||
Features map[string]bool
|
||||
}
|
||||
|
||||
Statsd cmd.StatsdConfig
|
||||
|
@ -68,6 +70,9 @@ func main() {
|
|||
err := cmd.ReadConfigFile(*configFile, &c)
|
||||
cmd.FailOnError(err, "Reading JSON config file into config structure")
|
||||
|
||||
err = features.Set(c.VA.Features)
|
||||
cmd.FailOnError(err, "Failed to set feature flags")
|
||||
|
||||
stats, logger := cmd.StatsAndLogging(c.Statsd, c.Syslog)
|
||||
scope := metrics.NewStatsdScope(stats, "VA")
|
||||
defer logger.AuditPanic()
|
||||
|
@ -93,10 +98,11 @@ func main() {
|
|||
// implements the v4 api instead of the legacy letsencrypt fork of
|
||||
// go-safebrowsing-api
|
||||
if features.Enabled(features.GoogleSafeBrowsingV4) {
|
||||
sbc = newGoogleSafeBrowsingV4(c.VA.GoogleSafeBrowsing)
|
||||
sbc, err = newGoogleSafeBrowsingV4(c.VA.GoogleSafeBrowsing, logger)
|
||||
} else {
|
||||
sbc = newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing)
|
||||
sbc, err = newGoogleSafeBrowsing(c.VA.GoogleSafeBrowsing)
|
||||
}
|
||||
cmd.FailOnError(err, "Failed to create Google Safe Browsing client")
|
||||
|
||||
var cdrClient *cdr.CAADistributedResolver
|
||||
if c.VA.CAADistributedResolver != nil {
|
||||
|
|
|
@ -286,8 +286,9 @@ type OCSPUpdaterConfig struct {
|
|||
// GoogleSafeBrowsingConfig is the JSON config struct for the VA's use of the
|
||||
// Google Safe Browsing API.
|
||||
type GoogleSafeBrowsingConfig struct {
|
||||
APIKey string
|
||||
DataDir string
|
||||
APIKey string
|
||||
DataDir string
|
||||
ServerURL string
|
||||
}
|
||||
|
||||
// SyslogConfig defines the config for syslogging.
|
||||
|
|
|
@ -16,6 +16,7 @@ boulder:
|
|||
- 4002:4002 # OCSP
|
||||
- 4003:4003 # OCSP
|
||||
- 4500:4500 # ct-test-srv
|
||||
- 6000:6000 # gsb-test-srv
|
||||
- 8000:8000 # debug ports
|
||||
- 8001:8001
|
||||
- 8002:8002
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
"insecure": true,
|
||||
"serviceQueue": "VA.server"
|
||||
},
|
||||
"GoogleSafeBrowsing": {
|
||||
"APIKey": "my-voice-is-my-passport",
|
||||
"DataDir": "/tmp",
|
||||
"ServerURL": "http://boulder:6000"
|
||||
},
|
||||
"features": {
|
||||
"GoogleSafeBrowsingV4": true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,416 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
gsb "github.com/letsencrypt/boulder/test/gsb-test-srv/proto"
|
||||
)
|
||||
|
||||
// testSrv implements a bare bones mock Google Safe Browsing server. The `hits`
|
||||
// and `list` fields are protected against concurrent updates using `mu`.
|
||||
type testSrv struct {
|
||||
apiKey string
|
||||
list safebrowsingList
|
||||
hits map[string]int
|
||||
mu *sync.RWMutex
|
||||
}
|
||||
|
||||
const (
|
||||
protoMime = "application/x-protobuf"
|
||||
)
|
||||
|
||||
// defaultUnsafeURLs is the list of URLs that we return a "unsafe" response for.
|
||||
var defaultUnsafeURLs = []string{
|
||||
"honest.achmeds.discount.hosting.com",
|
||||
}
|
||||
|
||||
// emptyThreatListUpdateResp is an empty threat list update response for padding
|
||||
// responses out to include the correct number of list updates clients expect
|
||||
var emptyThreatListUpdateResp = &gsb.FetchThreatListUpdatesResponse_ListUpdateResponse{
|
||||
ThreatType: gsb.ThreatType_MALWARE,
|
||||
PlatformType: gsb.PlatformType_ANY_PLATFORM,
|
||||
ThreatEntryType: gsb.ThreatEntryType_URL,
|
||||
ResponseType: gsb.FetchThreatListUpdatesResponse_ListUpdateResponse_FULL_UPDATE,
|
||||
/*
|
||||
* This is the SHA256 hash of `[]byte{}`, e.g. of an empty list of additions
|
||||
*/
|
||||
Checksum: &gsb.Checksum{
|
||||
Sha256: []byte{
|
||||
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8,
|
||||
0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
|
||||
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// unmarshalPB unmarshals a request body into a protocol buffer message
|
||||
func unmarshalPB(req *http.Request, pbReq proto.Message) error {
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := proto.Unmarshal(body, pbReq); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshalPB marshals a protocol buffer message into a response body
|
||||
func marshalPB(resp http.ResponseWriter, pbResp proto.Message) error {
|
||||
resp.Header().Set("Content-Type", protoMime)
|
||||
body, err := proto.Marshal(pbResp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := resp.Write(body); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// listEntry represents an entry on the safe browsing list. Each entry is a hash
|
||||
// constructed out of the URL.
|
||||
type listEntry struct {
|
||||
hash string
|
||||
url string
|
||||
}
|
||||
|
||||
// newListEntry creates a listEntry out of a URL
|
||||
func newListEntry(url string) listEntry {
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(url))
|
||||
return listEntry{
|
||||
hash: string(hash.Sum(nil)),
|
||||
url: url,
|
||||
}
|
||||
}
|
||||
|
||||
// safebrowsingList is a sorted slice of listEntries.
|
||||
type safebrowsingList []listEntry
|
||||
|
||||
// sha256 returns the hash of the overall list contents
|
||||
func (list safebrowsingList) sha256() []byte {
|
||||
hash := sha256.New()
|
||||
for _, entry := range list {
|
||||
hash.Write([]byte(entry.hash))
|
||||
}
|
||||
return hash.Sum(nil)
|
||||
}
|
||||
|
||||
// bytes returns the overall safebrowsing list's entries all coverted to bytes
|
||||
// and concatenated together
|
||||
func (list safebrowsingList) bytes() []byte {
|
||||
var buf []byte
|
||||
for _, entry := range list {
|
||||
buf = append(buf, []byte(entry.hash)...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// safebrowsingList implements the interface required for Sorting & Search
|
||||
func (list safebrowsingList) Len() int { return len(list) }
|
||||
func (list safebrowsingList) Less(i, j int) bool { return list[i].hash < list[j].hash }
|
||||
func (list safebrowsingList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
|
||||
|
||||
// sort() will sort a safebrowsingList in place with sort.Sort
|
||||
func (list safebrowsingList) sort() { sort.Sort(list) }
|
||||
|
||||
// findByHash searches an already sorted safebrowsingList and returns the entry
|
||||
// with hash equal to the provided hash, or nil if none is found
|
||||
func (list safebrowsingList) findByHash(h string) *listEntry {
|
||||
i := sort.Search(len(list), func(i int) bool {
|
||||
return list[i].hash >= h
|
||||
})
|
||||
if i < len(list) && list[i].hash == h {
|
||||
return &list[i]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// dbUpdateResponse creates a Google Safe Browsing threat list update response
|
||||
// that includes each of the test server's list entries
|
||||
func (t *testSrv) dbUpdateResponse() *gsb.FetchThreatListUpdatesResponse {
|
||||
// First we construct an overall update response to populate
|
||||
updateResp := &gsb.FetchThreatListUpdatesResponse{}
|
||||
|
||||
// Next, we create the full update type list update response, with an
|
||||
// initially blank list of threat entries to process as list additions
|
||||
addResponse := &gsb.FetchThreatListUpdatesResponse_ListUpdateResponse{
|
||||
// We use the MALWARE type, ignoring platform and sending URLs
|
||||
ThreatType: gsb.ThreatType_MALWARE,
|
||||
PlatformType: gsb.PlatformType_ANY_PLATFORM,
|
||||
ThreatEntryType: gsb.ThreatEntryType_URL,
|
||||
// We want this to be a "FULL UPDATE" to populate the intial DB contents
|
||||
ResponseType: gsb.FetchThreatListUpdatesResponse_ListUpdateResponse_FULL_UPDATE,
|
||||
Additions: []*gsb.ThreatEntrySet{
|
||||
&gsb.ThreatEntrySet{},
|
||||
},
|
||||
}
|
||||
|
||||
// Next, we create the threat entry additions, initially leaving the raw hashes empty
|
||||
additions := []*gsb.ThreatEntrySet{
|
||||
&gsb.ThreatEntrySet{
|
||||
// Our responses aren't compressed
|
||||
CompressionType: gsb.CompressionType_RAW,
|
||||
RawHashes: &gsb.RawHashes{
|
||||
// We send full SHA256 hashes as "prefixes"
|
||||
PrefixSize: sha256.Size,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Lock the mutex for reading the threat list
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
|
||||
// Convert the list to bytes
|
||||
hashes := t.list.bytes()
|
||||
// Populate the raw hashes with the list bytes
|
||||
additions[0].RawHashes.RawHashes = hashes
|
||||
// Update the add response to have the populated additions
|
||||
addResponse.Additions = additions
|
||||
// Update the add responses' checksum to be that of the overall list
|
||||
addResponse.Checksum = &gsb.Checksum{Sha256: t.list.sha256()}
|
||||
|
||||
/*
|
||||
* The `sblookup` client is hardcoded to expect exactly three list update
|
||||
* responses, one for each of the threat types it cares about. Boulder isn't
|
||||
* as picky, but its nice to be able to test this server using the `sblookup`
|
||||
* utility.
|
||||
*
|
||||
* To make this client happy we send two empty updates before the non-empty one
|
||||
* Its important to send these in the order empty, empty, non-empty because
|
||||
* each sblookup update response squashes the previous' contents (Unclear why)
|
||||
*/
|
||||
updateResp.ListUpdateResponses = []*gsb.FetchThreatListUpdatesResponse_ListUpdateResponse{
|
||||
emptyThreatListUpdateResp,
|
||||
emptyThreatListUpdateResp,
|
||||
addResponse,
|
||||
}
|
||||
return updateResp
|
||||
}
|
||||
|
||||
// threatListUpdateFetch handles a GSB client asking for a threat list update
|
||||
func (t *testSrv) threatListUpdateFetch(w http.ResponseWriter, r *http.Request) {
|
||||
// Unmarshal the request from the client - we ignore the contents for now and
|
||||
// unmarshal just to check the syntax of the request
|
||||
updateReq := &gsb.FetchThreatListUpdatesRequest{}
|
||||
err := unmarshalPB(r, updateReq)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Compute an update response based on the testSrv's list
|
||||
updateResp := t.dbUpdateResponse()
|
||||
// Marshal it as a response
|
||||
err = marshalPB(w, updateResp)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
log.Printf("Processed threatListUpdateFetch for client\n")
|
||||
}
|
||||
|
||||
// fullHashesFind handles a GSB client asking for a specific hash to be looked
|
||||
// up in the list because it matched a local prefix.
|
||||
func (t *testSrv) fullHashesFind(w http.ResponseWriter, r *http.Request) {
|
||||
// Unmarshal the request from the client - we use this to determine which hash
|
||||
// they were looking for
|
||||
findReq := &gsb.FindFullHashesRequest{}
|
||||
err := unmarshalPB(r, findReq)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// At a minimum we need a ThreatInfo with at least one ThreatEntries
|
||||
if findReq.ThreatInfo == nil || findReq.ThreatInfo.ThreatEntries == nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
te := findReq.ThreatInfo.ThreatEntries
|
||||
if len(te) < 1 {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
threat := te[0]
|
||||
|
||||
// We start by populating an empty hash lookup response
|
||||
resp := &gsb.FindFullHashesResponse{
|
||||
MinimumWaitDuration: &gsb.Duration{
|
||||
Seconds: 1,
|
||||
},
|
||||
NegativeCacheDuration: &gsb.Duration{
|
||||
Seconds: 1,
|
||||
},
|
||||
}
|
||||
|
||||
// Next we Lock mutex for reading the threat list and try to find the hash
|
||||
// being inquired about.
|
||||
t.mu.RLock()
|
||||
var match *listEntry
|
||||
match = t.list.findByHash(string(threat.Hash))
|
||||
// Restore read lock immediately
|
||||
t.mu.RUnlock()
|
||||
|
||||
if match != nil {
|
||||
// If there was a match we need to update the response to have a ThreatMatch
|
||||
resp.Matches = []*gsb.ThreatMatch{
|
||||
&gsb.ThreatMatch{
|
||||
ThreatType: gsb.ThreatType_MALWARE,
|
||||
PlatformType: gsb.PlatformType_ANY_PLATFORM,
|
||||
ThreatEntryType: gsb.ThreatEntryType_URL,
|
||||
Threat: &gsb.ThreatEntry{
|
||||
Hash: []byte(match.hash),
|
||||
Url: match.url,
|
||||
},
|
||||
CacheDuration: &gsb.Duration{
|
||||
Seconds: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
// We also have to lock the mutex for writing and update the server `hits`
|
||||
// to track that someone asked about an entry on the list
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
t.hits[match.url] += 1
|
||||
log.Printf("Lookup hit for %q. Count: %d\n", match.url, t.hits[match.url])
|
||||
}
|
||||
|
||||
// Finally we return the response to the client
|
||||
err = marshalPB(w, resp)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Processed fullHashesFind for client\n")
|
||||
}
|
||||
|
||||
// getHits returns a JSON object describing how many times each URL on the mock
|
||||
// safebrowsing list was asked about by a client. E.g.
|
||||
// ```
|
||||
// {
|
||||
// "evil.com": 2,
|
||||
// "example.com": 0
|
||||
// }
|
||||
// ```
|
||||
func (t *testSrv) getHits(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// Lock the mutex for reading
|
||||
t.mu.RLock()
|
||||
defer t.mu.RUnlock()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
body, err := json.Marshal(t.hits)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if _, err := w.Write(body); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Processed /hits request for client\n")
|
||||
}
|
||||
|
||||
// gsbHandler creates an http.HandlerFunc that wraps the `inner` handler. The
|
||||
// wrapper will check that the request is a POST, has the correct content-type,
|
||||
// and that the `key` GET parameter matches the server's API key.
|
||||
func (t *testSrv) gsbHandler(inner http.HandlerFunc) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// The HTTP method must be POST
|
||||
if r.Method != "POST" {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
// The Content-Type must be the protocol buffers mime type
|
||||
if r.Header.Get("Content-Type") != protoMime {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// There must be a "key" URL parameter with the correct API key
|
||||
// TODO(@cpu): Send back a protocol-correct bad auth response
|
||||
key := r.URL.Query().Get("key")
|
||||
if key != t.apiKey {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
inner(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// start() sets up the HTTP muxer and spawns a Go routine to ListenAndServe
|
||||
func (t *testSrv) start(listenAddr string) {
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/v4/threatListUpdates:fetch", t.gsbHandler(t.threatListUpdateFetch))
|
||||
mux.Handle("/v4/fullHashes:find", t.gsbHandler(t.fullHashesFind))
|
||||
mux.Handle("/hits", http.HandlerFunc(t.getHits))
|
||||
|
||||
go func() {
|
||||
err := http.ListenAndServe(listenAddr, mux)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// newTestServer constructs a testSrv instance with its list constructed from
|
||||
// the provided slice of strings.
|
||||
func newTestServer(apiKey string, unsafeURLs []string) testSrv {
|
||||
var initialList safebrowsingList
|
||||
for _, s := range unsafeURLs {
|
||||
// The safe browsing library looks up URLs with a trailing slash and expects
|
||||
// the DB contents/hashes to reflect that. We add the slash here as required
|
||||
if !strings.HasSuffix(s, "/") {
|
||||
s += "/"
|
||||
}
|
||||
initialList = append(initialList, newListEntry(s))
|
||||
}
|
||||
initialList.sort()
|
||||
|
||||
return testSrv{
|
||||
apiKey: apiKey,
|
||||
hits: make(map[string]int),
|
||||
mu: new(sync.RWMutex),
|
||||
list: initialList,
|
||||
}
|
||||
}
|
||||
|
||||
// main() processes command line flags, creates, and starts a `testSrv`
|
||||
func main() {
|
||||
key := flag.String("apikey", "", "API key for client access")
|
||||
listen := flag.String("listenAddress", ":6000", "Listen address for HTTP server")
|
||||
flag.Parse()
|
||||
|
||||
log.SetPrefix("gsb-test-srv: ")
|
||||
|
||||
if *key == "" {
|
||||
log.Fatal("Error: -apikey must not be empty\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
log.Printf("Starting GSB Test Server on %q\n", *listen)
|
||||
ts := newTestServer(*key, defaultUnsafeURLs)
|
||||
ts.start(*listen)
|
||||
|
||||
// Block on an empty channel
|
||||
forever := make(chan bool, 1)
|
||||
<-forever
|
||||
}
|
|
@ -0,0 +1,966 @@
|
|||
// Code generated by protoc-gen-go.
|
||||
// source: safebrowsing.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package safebrowsing_proto is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
safebrowsing.proto
|
||||
|
||||
It has these top-level messages:
|
||||
ThreatInfo
|
||||
ThreatMatch
|
||||
FindThreatMatchesRequest
|
||||
FindThreatMatchesResponse
|
||||
FetchThreatListUpdatesRequest
|
||||
FetchThreatListUpdatesResponse
|
||||
FindFullHashesRequest
|
||||
FindFullHashesResponse
|
||||
ClientInfo
|
||||
Checksum
|
||||
ThreatEntry
|
||||
ThreatEntrySet
|
||||
RawIndices
|
||||
RawHashes
|
||||
RiceDeltaEncoding
|
||||
ThreatEntryMetadata
|
||||
ThreatListDescriptor
|
||||
ListThreatListsResponse
|
||||
Duration
|
||||
*/
|
||||
package safebrowsing_proto
|
||||
|
||||
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
|
||||
|
||||
// Types of threats.
|
||||
type ThreatType int32
|
||||
|
||||
const (
|
||||
// Unknown.
|
||||
ThreatType_THREAT_TYPE_UNSPECIFIED ThreatType = 0
|
||||
// Malware threat type.
|
||||
ThreatType_MALWARE ThreatType = 1
|
||||
// Social engineering threat type.
|
||||
ThreatType_SOCIAL_ENGINEERING ThreatType = 2
|
||||
// Unwanted software threat type.
|
||||
ThreatType_UNWANTED_SOFTWARE ThreatType = 3
|
||||
// Potentially harmful application threat type.
|
||||
ThreatType_POTENTIALLY_HARMFUL_APPLICATION ThreatType = 4
|
||||
)
|
||||
|
||||
var ThreatType_name = map[int32]string{
|
||||
0: "THREAT_TYPE_UNSPECIFIED",
|
||||
1: "MALWARE",
|
||||
2: "SOCIAL_ENGINEERING",
|
||||
3: "UNWANTED_SOFTWARE",
|
||||
4: "POTENTIALLY_HARMFUL_APPLICATION",
|
||||
}
|
||||
var ThreatType_value = map[string]int32{
|
||||
"THREAT_TYPE_UNSPECIFIED": 0,
|
||||
"MALWARE": 1,
|
||||
"SOCIAL_ENGINEERING": 2,
|
||||
"UNWANTED_SOFTWARE": 3,
|
||||
"POTENTIALLY_HARMFUL_APPLICATION": 4,
|
||||
}
|
||||
|
||||
func (x ThreatType) String() string {
|
||||
return proto.EnumName(ThreatType_name, int32(x))
|
||||
}
|
||||
func (ThreatType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
// Types of platforms.
|
||||
type PlatformType int32
|
||||
|
||||
const (
|
||||
// Unknown platform.
|
||||
PlatformType_PLATFORM_TYPE_UNSPECIFIED PlatformType = 0
|
||||
// Threat posed to Windows.
|
||||
PlatformType_WINDOWS PlatformType = 1
|
||||
// Threat posed to Linux.
|
||||
PlatformType_LINUX PlatformType = 2
|
||||
// Threat posed to Android.
|
||||
PlatformType_ANDROID PlatformType = 3
|
||||
// Threat posed to OSX.
|
||||
PlatformType_OSX PlatformType = 4
|
||||
// Threat posed to iOS.
|
||||
PlatformType_IOS PlatformType = 5
|
||||
// Threat posed to at least one of the defined platforms.
|
||||
PlatformType_ANY_PLATFORM PlatformType = 6
|
||||
// Threat posed to all defined platforms.
|
||||
PlatformType_ALL_PLATFORMS PlatformType = 7
|
||||
// Threat posed to Chrome.
|
||||
PlatformType_CHROME PlatformType = 8
|
||||
)
|
||||
|
||||
var PlatformType_name = map[int32]string{
|
||||
0: "PLATFORM_TYPE_UNSPECIFIED",
|
||||
1: "WINDOWS",
|
||||
2: "LINUX",
|
||||
3: "ANDROID",
|
||||
4: "OSX",
|
||||
5: "IOS",
|
||||
6: "ANY_PLATFORM",
|
||||
7: "ALL_PLATFORMS",
|
||||
8: "CHROME",
|
||||
}
|
||||
var PlatformType_value = map[string]int32{
|
||||
"PLATFORM_TYPE_UNSPECIFIED": 0,
|
||||
"WINDOWS": 1,
|
||||
"LINUX": 2,
|
||||
"ANDROID": 3,
|
||||
"OSX": 4,
|
||||
"IOS": 5,
|
||||
"ANY_PLATFORM": 6,
|
||||
"ALL_PLATFORMS": 7,
|
||||
"CHROME": 8,
|
||||
}
|
||||
|
||||
func (x PlatformType) String() string {
|
||||
return proto.EnumName(PlatformType_name, int32(x))
|
||||
}
|
||||
func (PlatformType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
// The ways in which threat entry sets can be compressed.
|
||||
type CompressionType int32
|
||||
|
||||
const (
|
||||
// Unknown.
|
||||
CompressionType_COMPRESSION_TYPE_UNSPECIFIED CompressionType = 0
|
||||
// Raw, uncompressed data.
|
||||
CompressionType_RAW CompressionType = 1
|
||||
// Rice-Golomb encoded data.
|
||||
CompressionType_RICE CompressionType = 2
|
||||
)
|
||||
|
||||
var CompressionType_name = map[int32]string{
|
||||
0: "COMPRESSION_TYPE_UNSPECIFIED",
|
||||
1: "RAW",
|
||||
2: "RICE",
|
||||
}
|
||||
var CompressionType_value = map[string]int32{
|
||||
"COMPRESSION_TYPE_UNSPECIFIED": 0,
|
||||
"RAW": 1,
|
||||
"RICE": 2,
|
||||
}
|
||||
|
||||
func (x CompressionType) String() string {
|
||||
return proto.EnumName(CompressionType_name, int32(x))
|
||||
}
|
||||
func (CompressionType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
// Types of entries that pose threats. Threat lists are collections of entries
|
||||
// of a single type.
|
||||
type ThreatEntryType int32
|
||||
|
||||
const (
|
||||
// Unspecified.
|
||||
ThreatEntryType_THREAT_ENTRY_TYPE_UNSPECIFIED ThreatEntryType = 0
|
||||
// A URL.
|
||||
ThreatEntryType_URL ThreatEntryType = 1
|
||||
// An executable program.
|
||||
ThreatEntryType_EXECUTABLE ThreatEntryType = 2
|
||||
// An IP range.
|
||||
ThreatEntryType_IP_RANGE ThreatEntryType = 3
|
||||
)
|
||||
|
||||
var ThreatEntryType_name = map[int32]string{
|
||||
0: "THREAT_ENTRY_TYPE_UNSPECIFIED",
|
||||
1: "URL",
|
||||
2: "EXECUTABLE",
|
||||
3: "IP_RANGE",
|
||||
}
|
||||
var ThreatEntryType_value = map[string]int32{
|
||||
"THREAT_ENTRY_TYPE_UNSPECIFIED": 0,
|
||||
"URL": 1,
|
||||
"EXECUTABLE": 2,
|
||||
"IP_RANGE": 3,
|
||||
}
|
||||
|
||||
func (x ThreatEntryType) String() string {
|
||||
return proto.EnumName(ThreatEntryType_name, int32(x))
|
||||
}
|
||||
func (ThreatEntryType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
// The type of response sent to the client.
|
||||
type FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType int32
|
||||
|
||||
const (
|
||||
// Unknown.
|
||||
FetchThreatListUpdatesResponse_ListUpdateResponse_RESPONSE_TYPE_UNSPECIFIED FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType = 0
|
||||
// Partial updates are applied to the client's existing local database.
|
||||
FetchThreatListUpdatesResponse_ListUpdateResponse_PARTIAL_UPDATE FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType = 1
|
||||
// Full updates replace the client's entire local database. This means
|
||||
// that either the client was seriously out-of-date or the client is
|
||||
// believed to be corrupt.
|
||||
FetchThreatListUpdatesResponse_ListUpdateResponse_FULL_UPDATE FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType = 2
|
||||
)
|
||||
|
||||
var FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType_name = map[int32]string{
|
||||
0: "RESPONSE_TYPE_UNSPECIFIED",
|
||||
1: "PARTIAL_UPDATE",
|
||||
2: "FULL_UPDATE",
|
||||
}
|
||||
var FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType_value = map[string]int32{
|
||||
"RESPONSE_TYPE_UNSPECIFIED": 0,
|
||||
"PARTIAL_UPDATE": 1,
|
||||
"FULL_UPDATE": 2,
|
||||
}
|
||||
|
||||
func (x FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType) String() string {
|
||||
return proto.EnumName(FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType_name, int32(x))
|
||||
}
|
||||
func (FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{5, 0, 0}
|
||||
}
|
||||
|
||||
// The information regarding one or more threats that a client submits when
|
||||
// checking for matches in threat lists.
|
||||
type ThreatInfo struct {
|
||||
// The threat types to be checked.
|
||||
ThreatTypes []ThreatType `protobuf:"varint,1,rep,name=threat_types,json=threatTypes,enum=safebrowsing_proto.ThreatType" json:"threat_types,omitempty"`
|
||||
// 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"`
|
||||
// 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"`
|
||||
// The threat entries to be checked.
|
||||
ThreatEntries []*ThreatEntry `protobuf:"bytes,3,rep,name=threat_entries,json=threatEntries" json:"threat_entries,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatInfo) Reset() { *m = ThreatInfo{} }
|
||||
func (m *ThreatInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatInfo) ProtoMessage() {}
|
||||
func (*ThreatInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
func (m *ThreatInfo) GetThreatEntries() []*ThreatEntry {
|
||||
if m != nil {
|
||||
return m.ThreatEntries
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A match when checking a threat entry in the Safe Browsing threat lists.
|
||||
type ThreatMatch struct {
|
||||
// The threat type matching this threat.
|
||||
ThreatType ThreatType `protobuf:"varint,1,opt,name=threat_type,json=threatType,enum=safebrowsing_proto.ThreatType" json:"threat_type,omitempty"`
|
||||
// The platform type matching this threat.
|
||||
PlatformType PlatformType `protobuf:"varint,2,opt,name=platform_type,json=platformType,enum=safebrowsing_proto.PlatformType" json:"platform_type,omitempty"`
|
||||
// The threat entry type matching this threat.
|
||||
ThreatEntryType ThreatEntryType `protobuf:"varint,6,opt,name=threat_entry_type,json=threatEntryType,enum=safebrowsing_proto.ThreatEntryType" json:"threat_entry_type,omitempty"`
|
||||
// The threat matching this threat.
|
||||
Threat *ThreatEntry `protobuf:"bytes,3,opt,name=threat" json:"threat,omitempty"`
|
||||
// Optional metadata associated with this threat.
|
||||
ThreatEntryMetadata *ThreatEntryMetadata `protobuf:"bytes,4,opt,name=threat_entry_metadata,json=threatEntryMetadata" json:"threat_entry_metadata,omitempty"`
|
||||
// The cache lifetime for the returned match. Clients must not cache this
|
||||
// response for more than this duration to avoid false positives.
|
||||
CacheDuration *Duration `protobuf:"bytes,5,opt,name=cache_duration,json=cacheDuration" json:"cache_duration,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatMatch) Reset() { *m = ThreatMatch{} }
|
||||
func (m *ThreatMatch) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatMatch) ProtoMessage() {}
|
||||
func (*ThreatMatch) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
func (m *ThreatMatch) GetThreat() *ThreatEntry {
|
||||
if m != nil {
|
||||
return m.Threat
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ThreatMatch) GetThreatEntryMetadata() *ThreatEntryMetadata {
|
||||
if m != nil {
|
||||
return m.ThreatEntryMetadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ThreatMatch) GetCacheDuration() *Duration {
|
||||
if m != nil {
|
||||
return m.CacheDuration
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Request to check entries against lists.
|
||||
type FindThreatMatchesRequest struct {
|
||||
// The client metadata.
|
||||
Client *ClientInfo `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
|
||||
// The lists and entries to be checked for matches.
|
||||
ThreatInfo *ThreatInfo `protobuf:"bytes,2,opt,name=threat_info,json=threatInfo" json:"threat_info,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FindThreatMatchesRequest) Reset() { *m = FindThreatMatchesRequest{} }
|
||||
func (m *FindThreatMatchesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*FindThreatMatchesRequest) ProtoMessage() {}
|
||||
func (*FindThreatMatchesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
func (m *FindThreatMatchesRequest) GetClient() *ClientInfo {
|
||||
if m != nil {
|
||||
return m.Client
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FindThreatMatchesRequest) GetThreatInfo() *ThreatInfo {
|
||||
if m != nil {
|
||||
return m.ThreatInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Response type for requests to find threat matches.
|
||||
type FindThreatMatchesResponse struct {
|
||||
// The threat list matches.
|
||||
Matches []*ThreatMatch `protobuf:"bytes,1,rep,name=matches" json:"matches,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FindThreatMatchesResponse) Reset() { *m = FindThreatMatchesResponse{} }
|
||||
func (m *FindThreatMatchesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*FindThreatMatchesResponse) ProtoMessage() {}
|
||||
func (*FindThreatMatchesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
func (m *FindThreatMatchesResponse) GetMatches() []*ThreatMatch {
|
||||
if m != nil {
|
||||
return m.Matches
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Describes a Safe Browsing API update request. Clients can request updates for
|
||||
// multiple lists in a single request.
|
||||
// NOTE: Field index 2 is unused.
|
||||
type FetchThreatListUpdatesRequest struct {
|
||||
// The client metadata.
|
||||
Client *ClientInfo `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
|
||||
// The requested threat list updates.
|
||||
ListUpdateRequests []*FetchThreatListUpdatesRequest_ListUpdateRequest `protobuf:"bytes,3,rep,name=list_update_requests,json=listUpdateRequests" json:"list_update_requests,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesRequest) Reset() { *m = FetchThreatListUpdatesRequest{} }
|
||||
func (m *FetchThreatListUpdatesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*FetchThreatListUpdatesRequest) ProtoMessage() {}
|
||||
func (*FetchThreatListUpdatesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||
|
||||
func (m *FetchThreatListUpdatesRequest) GetClient() *ClientInfo {
|
||||
if m != nil {
|
||||
return m.Client
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesRequest) GetListUpdateRequests() []*FetchThreatListUpdatesRequest_ListUpdateRequest {
|
||||
if m != nil {
|
||||
return m.ListUpdateRequests
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A single list update request.
|
||||
type FetchThreatListUpdatesRequest_ListUpdateRequest struct {
|
||||
// The type of threat posed by entries present in the list.
|
||||
ThreatType ThreatType `protobuf:"varint,1,opt,name=threat_type,json=threatType,enum=safebrowsing_proto.ThreatType" json:"threat_type,omitempty"`
|
||||
// The type of platform at risk by entries present in the list.
|
||||
PlatformType PlatformType `protobuf:"varint,2,opt,name=platform_type,json=platformType,enum=safebrowsing_proto.PlatformType" json:"platform_type,omitempty"`
|
||||
// The types of entries present in the list.
|
||||
ThreatEntryType ThreatEntryType `protobuf:"varint,5,opt,name=threat_entry_type,json=threatEntryType,enum=safebrowsing_proto.ThreatEntryType" json:"threat_entry_type,omitempty"`
|
||||
// The current state of the client for the requested list (the encrypted
|
||||
// ClientState that was sent to the client from the previous update
|
||||
// request).
|
||||
State []byte `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"`
|
||||
// The constraints associated with this request.
|
||||
Constraints *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints `protobuf:"bytes,4,opt,name=constraints" json:"constraints,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) Reset() {
|
||||
*m = FetchThreatListUpdatesRequest_ListUpdateRequest{}
|
||||
}
|
||||
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) String() string {
|
||||
return proto.CompactTextString(m)
|
||||
}
|
||||
func (*FetchThreatListUpdatesRequest_ListUpdateRequest) ProtoMessage() {}
|
||||
func (*FetchThreatListUpdatesRequest_ListUpdateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{4, 0}
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest) GetConstraints() *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints {
|
||||
if m != nil {
|
||||
return m.Constraints
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The constraints for this update.
|
||||
type FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints struct {
|
||||
// The maximum size in number of entries. The update will not contain more
|
||||
// entries than this value. This should be a power of 2 between 2**10 and
|
||||
// 2**20. If zero, no update size limit is set.
|
||||
MaxUpdateEntries int32 `protobuf:"varint,1,opt,name=max_update_entries,json=maxUpdateEntries" json:"max_update_entries,omitempty"`
|
||||
// Sets the maximum number of entries that the client is willing to have
|
||||
// in the local database. This should be a power of 2 between 2**10 and
|
||||
// 2**20. If zero, no database size limit is set.
|
||||
MaxDatabaseEntries int32 `protobuf:"varint,2,opt,name=max_database_entries,json=maxDatabaseEntries" json:"max_database_entries,omitempty"`
|
||||
// Requests the list for a specific geographic location. If not set the
|
||||
// server may pick that value based on the user's IP address. Expects ISO
|
||||
// 3166-1 alpha-2 format.
|
||||
Region string `protobuf:"bytes,3,opt,name=region" json:"region,omitempty"`
|
||||
// The compression types supported by the client.
|
||||
SupportedCompressions []CompressionType `protobuf:"varint,4,rep,name=supported_compressions,json=supportedCompressions,enum=safebrowsing_proto.CompressionType" json:"supported_compressions,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) Reset() {
|
||||
*m = FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints{}
|
||||
}
|
||||
func (m *FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) String() string {
|
||||
return proto.CompactTextString(m)
|
||||
}
|
||||
func (*FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) ProtoMessage() {}
|
||||
func (*FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{4, 0, 0}
|
||||
}
|
||||
|
||||
// Response type for threat list update requests.
|
||||
type FetchThreatListUpdatesResponse struct {
|
||||
// The list updates requested by the clients.
|
||||
ListUpdateResponses []*FetchThreatListUpdatesResponse_ListUpdateResponse `protobuf:"bytes,1,rep,name=list_update_responses,json=listUpdateResponses" json:"list_update_responses,omitempty"`
|
||||
// The minimum duration the client must wait before issuing any update
|
||||
// request. If this field is not set clients may update as soon as they want.
|
||||
MinimumWaitDuration *Duration `protobuf:"bytes,2,opt,name=minimum_wait_duration,json=minimumWaitDuration" json:"minimum_wait_duration,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse) Reset() { *m = FetchThreatListUpdatesResponse{} }
|
||||
func (m *FetchThreatListUpdatesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*FetchThreatListUpdatesResponse) ProtoMessage() {}
|
||||
func (*FetchThreatListUpdatesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse) GetListUpdateResponses() []*FetchThreatListUpdatesResponse_ListUpdateResponse {
|
||||
if m != nil {
|
||||
return m.ListUpdateResponses
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse) GetMinimumWaitDuration() *Duration {
|
||||
if m != nil {
|
||||
return m.MinimumWaitDuration
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// An update to an individual list.
|
||||
type FetchThreatListUpdatesResponse_ListUpdateResponse struct {
|
||||
// The threat type for which data is returned.
|
||||
ThreatType ThreatType `protobuf:"varint,1,opt,name=threat_type,json=threatType,enum=safebrowsing_proto.ThreatType" json:"threat_type,omitempty"`
|
||||
// The format of the threats.
|
||||
ThreatEntryType ThreatEntryType `protobuf:"varint,2,opt,name=threat_entry_type,json=threatEntryType,enum=safebrowsing_proto.ThreatEntryType" json:"threat_entry_type,omitempty"`
|
||||
// The platform type for which data is returned.
|
||||
PlatformType PlatformType `protobuf:"varint,3,opt,name=platform_type,json=platformType,enum=safebrowsing_proto.PlatformType" json:"platform_type,omitempty"`
|
||||
// The type of response. This may indicate that an action is required by the
|
||||
// client when the response is received.
|
||||
ResponseType FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType `protobuf:"varint,4,opt,name=response_type,json=responseType,enum=safebrowsing_proto.FetchThreatListUpdatesResponse_ListUpdateResponse_ResponseType" json:"response_type,omitempty"`
|
||||
// A set of entries to add to a local threat type's list. Repeated to allow
|
||||
// for a combination of compressed and raw data to be sent in a single
|
||||
// response.
|
||||
Additions []*ThreatEntrySet `protobuf:"bytes,5,rep,name=additions" json:"additions,omitempty"`
|
||||
// A set of entries to remove from a local threat type's list. Repeated for
|
||||
// the same reason as above.
|
||||
Removals []*ThreatEntrySet `protobuf:"bytes,6,rep,name=removals" json:"removals,omitempty"`
|
||||
// The new client state, in encrypted format. Opaque to clients.
|
||||
NewClientState []byte `protobuf:"bytes,7,opt,name=new_client_state,json=newClientState,proto3" json:"new_client_state,omitempty"`
|
||||
// The expected SHA256 hash of the client state; that is, of the sorted list
|
||||
// of all hashes present in the database after applying the provided update.
|
||||
// If the client state doesn't match the expected state, the client must
|
||||
// disregard this update and retry later.
|
||||
Checksum *Checksum `protobuf:"bytes,8,opt,name=checksum" json:"checksum,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) Reset() {
|
||||
*m = FetchThreatListUpdatesResponse_ListUpdateResponse{}
|
||||
}
|
||||
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) String() string {
|
||||
return proto.CompactTextString(m)
|
||||
}
|
||||
func (*FetchThreatListUpdatesResponse_ListUpdateResponse) ProtoMessage() {}
|
||||
func (*FetchThreatListUpdatesResponse_ListUpdateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{5, 0}
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetAdditions() []*ThreatEntrySet {
|
||||
if m != nil {
|
||||
return m.Additions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetRemovals() []*ThreatEntrySet {
|
||||
if m != nil {
|
||||
return m.Removals
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FetchThreatListUpdatesResponse_ListUpdateResponse) GetChecksum() *Checksum {
|
||||
if m != nil {
|
||||
return m.Checksum
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Request to return full hashes matched by the provided hash prefixes.
|
||||
type FindFullHashesRequest struct {
|
||||
// The client metadata.
|
||||
Client *ClientInfo `protobuf:"bytes,1,opt,name=client" json:"client,omitempty"`
|
||||
// The current client states for each of the client's local threat lists.
|
||||
ClientStates [][]byte `protobuf:"bytes,2,rep,name=client_states,json=clientStates,proto3" json:"client_states,omitempty"`
|
||||
// The lists and hashes to be checked.
|
||||
ThreatInfo *ThreatInfo `protobuf:"bytes,3,opt,name=threat_info,json=threatInfo" json:"threat_info,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FindFullHashesRequest) Reset() { *m = FindFullHashesRequest{} }
|
||||
func (m *FindFullHashesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*FindFullHashesRequest) ProtoMessage() {}
|
||||
func (*FindFullHashesRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
|
||||
|
||||
func (m *FindFullHashesRequest) GetClient() *ClientInfo {
|
||||
if m != nil {
|
||||
return m.Client
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FindFullHashesRequest) GetThreatInfo() *ThreatInfo {
|
||||
if m != nil {
|
||||
return m.ThreatInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Response type for requests to find full hashes.
|
||||
type FindFullHashesResponse struct {
|
||||
// The full hashes that matched the requested prefixes.
|
||||
Matches []*ThreatMatch `protobuf:"bytes,1,rep,name=matches" json:"matches,omitempty"`
|
||||
// The minimum duration the client must wait before issuing any find hashes
|
||||
// request. If this field is not set, clients can issue a request as soon as
|
||||
// they want.
|
||||
MinimumWaitDuration *Duration `protobuf:"bytes,2,opt,name=minimum_wait_duration,json=minimumWaitDuration" json:"minimum_wait_duration,omitempty"`
|
||||
// For requested entities that did not match the threat list, how long to
|
||||
// cache the response.
|
||||
NegativeCacheDuration *Duration `protobuf:"bytes,3,opt,name=negative_cache_duration,json=negativeCacheDuration" json:"negative_cache_duration,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FindFullHashesResponse) Reset() { *m = FindFullHashesResponse{} }
|
||||
func (m *FindFullHashesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*FindFullHashesResponse) ProtoMessage() {}
|
||||
func (*FindFullHashesResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
|
||||
|
||||
func (m *FindFullHashesResponse) GetMatches() []*ThreatMatch {
|
||||
if m != nil {
|
||||
return m.Matches
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FindFullHashesResponse) GetMinimumWaitDuration() *Duration {
|
||||
if m != nil {
|
||||
return m.MinimumWaitDuration
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *FindFullHashesResponse) GetNegativeCacheDuration() *Duration {
|
||||
if m != nil {
|
||||
return m.NegativeCacheDuration
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// The client metadata associated with Safe Browsing API requests.
|
||||
type ClientInfo struct {
|
||||
// A client ID that (hopefully) uniquely identifies the client implementation
|
||||
// of the Safe Browsing API.
|
||||
ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId" json:"client_id,omitempty"`
|
||||
// The version of the client implementation.
|
||||
ClientVersion string `protobuf:"bytes,2,opt,name=client_version,json=clientVersion" json:"client_version,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ClientInfo) Reset() { *m = ClientInfo{} }
|
||||
func (m *ClientInfo) String() string { return proto.CompactTextString(m) }
|
||||
func (*ClientInfo) ProtoMessage() {}
|
||||
func (*ClientInfo) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
|
||||
|
||||
// The expected state of a client's local database.
|
||||
type Checksum struct {
|
||||
// The SHA256 hash of the client state; that is, of the sorted list of all
|
||||
// hashes present in the database.
|
||||
Sha256 []byte `protobuf:"bytes,1,opt,name=sha256,proto3" json:"sha256,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Checksum) Reset() { *m = Checksum{} }
|
||||
func (m *Checksum) String() string { return proto.CompactTextString(m) }
|
||||
func (*Checksum) ProtoMessage() {}
|
||||
func (*Checksum) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
|
||||
|
||||
// An individual threat; for example, a malicious URL or its hash
|
||||
// representation. Only one of these fields should be set.
|
||||
type ThreatEntry struct {
|
||||
// A hash prefix, consisting of the most significant 4-32 bytes of a SHA256
|
||||
// hash.
|
||||
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
|
||||
// A URL.
|
||||
Url string `protobuf:"bytes,2,opt,name=url" json:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatEntry) Reset() { *m = ThreatEntry{} }
|
||||
func (m *ThreatEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatEntry) ProtoMessage() {}
|
||||
func (*ThreatEntry) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
|
||||
|
||||
// A set of threats that should be added or removed from a client's local
|
||||
// database.
|
||||
type ThreatEntrySet struct {
|
||||
// The compression type for the entries in this set.
|
||||
CompressionType CompressionType `protobuf:"varint,1,opt,name=compression_type,json=compressionType,enum=safebrowsing_proto.CompressionType" json:"compression_type,omitempty"`
|
||||
// The raw SHA256-formatted entries.
|
||||
RawHashes *RawHashes `protobuf:"bytes,2,opt,name=raw_hashes,json=rawHashes" json:"raw_hashes,omitempty"`
|
||||
// The raw removal indices for a local list.
|
||||
RawIndices *RawIndices `protobuf:"bytes,3,opt,name=raw_indices,json=rawIndices" json:"raw_indices,omitempty"`
|
||||
// The encoded 4-byte prefixes of SHA256-formatted entries, using a
|
||||
// Golomb-Rice encoding.
|
||||
RiceHashes *RiceDeltaEncoding `protobuf:"bytes,4,opt,name=rice_hashes,json=riceHashes" json:"rice_hashes,omitempty"`
|
||||
// The encoded local, lexicographically-sorted list indices, using a
|
||||
// Golomb-Rice encoding. Used for sending compressed removal indices.
|
||||
RiceIndices *RiceDeltaEncoding `protobuf:"bytes,5,opt,name=rice_indices,json=riceIndices" json:"rice_indices,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatEntrySet) Reset() { *m = ThreatEntrySet{} }
|
||||
func (m *ThreatEntrySet) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatEntrySet) ProtoMessage() {}
|
||||
func (*ThreatEntrySet) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
|
||||
|
||||
func (m *ThreatEntrySet) GetRawHashes() *RawHashes {
|
||||
if m != nil {
|
||||
return m.RawHashes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ThreatEntrySet) GetRawIndices() *RawIndices {
|
||||
if m != nil {
|
||||
return m.RawIndices
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ThreatEntrySet) GetRiceHashes() *RiceDeltaEncoding {
|
||||
if m != nil {
|
||||
return m.RiceHashes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ThreatEntrySet) GetRiceIndices() *RiceDeltaEncoding {
|
||||
if m != nil {
|
||||
return m.RiceIndices
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A set of raw indices to remove from a local list.
|
||||
type RawIndices struct {
|
||||
// The indices to remove from a lexicographically-sorted local list.
|
||||
Indices []int32 `protobuf:"varint,1,rep,name=indices" json:"indices,omitempty"`
|
||||
}
|
||||
|
||||
func (m *RawIndices) Reset() { *m = RawIndices{} }
|
||||
func (m *RawIndices) String() string { return proto.CompactTextString(m) }
|
||||
func (*RawIndices) ProtoMessage() {}
|
||||
func (*RawIndices) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
|
||||
|
||||
// The uncompressed threat entries in hash format of a particular prefix length.
|
||||
// Hashes can be anywhere from 4 to 32 bytes in size. A large majority are 4
|
||||
// bytes, but some hashes are lengthened if they collide with the hash of a
|
||||
// popular URL.
|
||||
//
|
||||
// Used for sending ThreatEntrySet to clients that do not support compression,
|
||||
// or when sending non-4-byte hashes to clients that do support compression.
|
||||
type RawHashes struct {
|
||||
// The number of bytes for each prefix encoded below. This field can be
|
||||
// anywhere from 4 (shortest prefix) to 32 (full SHA256 hash).
|
||||
PrefixSize int32 `protobuf:"varint,1,opt,name=prefix_size,json=prefixSize" json:"prefix_size,omitempty"`
|
||||
// The hashes, all concatenated into one long string. Each hash has a prefix
|
||||
// size of |prefix_size| above. Hashes are sorted in lexicographic order.
|
||||
RawHashes []byte `protobuf:"bytes,2,opt,name=raw_hashes,json=rawHashes,proto3" json:"raw_hashes,omitempty"`
|
||||
}
|
||||
|
||||
func (m *RawHashes) Reset() { *m = RawHashes{} }
|
||||
func (m *RawHashes) String() string { return proto.CompactTextString(m) }
|
||||
func (*RawHashes) ProtoMessage() {}
|
||||
func (*RawHashes) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
|
||||
|
||||
// The Rice-Golomb encoded data. Used for sending compressed 4-byte hashes or
|
||||
// compressed removal indices.
|
||||
type RiceDeltaEncoding struct {
|
||||
// The offset of the first entry in the encoded data, or, if only a single
|
||||
// integer was encoded, that single integer's value.
|
||||
FirstValue int64 `protobuf:"varint,1,opt,name=first_value,json=firstValue" json:"first_value,omitempty"`
|
||||
// The Golomb-Rice parameter which is a number between 2 and 28. This field
|
||||
// is missing (that is, zero) if num_entries is zero.
|
||||
RiceParameter int32 `protobuf:"varint,2,opt,name=rice_parameter,json=riceParameter" json:"rice_parameter,omitempty"`
|
||||
// The number of entries that are delta encoded in the encoded data. If only a
|
||||
// single integer was encoded, this will be zero and the single value will be
|
||||
// stored in first_value.
|
||||
NumEntries int32 `protobuf:"varint,3,opt,name=num_entries,json=numEntries" json:"num_entries,omitempty"`
|
||||
// The encoded deltas that are encoded using the Golomb-Rice coder.
|
||||
EncodedData []byte `protobuf:"bytes,4,opt,name=encoded_data,json=encodedData,proto3" json:"encoded_data,omitempty"`
|
||||
}
|
||||
|
||||
func (m *RiceDeltaEncoding) Reset() { *m = RiceDeltaEncoding{} }
|
||||
func (m *RiceDeltaEncoding) String() string { return proto.CompactTextString(m) }
|
||||
func (*RiceDeltaEncoding) ProtoMessage() {}
|
||||
func (*RiceDeltaEncoding) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
|
||||
|
||||
// The metadata associated with a specific threat entry. The client is expected
|
||||
// to know the metadata key/value pairs associated with each threat type.
|
||||
type ThreatEntryMetadata struct {
|
||||
// The metadata entries.
|
||||
Entries []*ThreatEntryMetadata_MetadataEntry `protobuf:"bytes,1,rep,name=entries" json:"entries,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatEntryMetadata) Reset() { *m = ThreatEntryMetadata{} }
|
||||
func (m *ThreatEntryMetadata) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatEntryMetadata) ProtoMessage() {}
|
||||
func (*ThreatEntryMetadata) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
|
||||
|
||||
func (m *ThreatEntryMetadata) GetEntries() []*ThreatEntryMetadata_MetadataEntry {
|
||||
if m != nil {
|
||||
return m.Entries
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A single metadata entry.
|
||||
type ThreatEntryMetadata_MetadataEntry struct {
|
||||
// The metadata entry key.
|
||||
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
// The metadata entry value.
|
||||
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatEntryMetadata_MetadataEntry) Reset() { *m = ThreatEntryMetadata_MetadataEntry{} }
|
||||
func (m *ThreatEntryMetadata_MetadataEntry) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatEntryMetadata_MetadataEntry) ProtoMessage() {}
|
||||
func (*ThreatEntryMetadata_MetadataEntry) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor0, []int{15, 0}
|
||||
}
|
||||
|
||||
// Describes an individual threat list. A list is defined by three parameters:
|
||||
// the type of threat posed, the type of platform targeted by the threat, and
|
||||
// the type of entries in the list.
|
||||
type ThreatListDescriptor struct {
|
||||
// The threat type posed by the list's entries.
|
||||
ThreatType ThreatType `protobuf:"varint,1,opt,name=threat_type,json=threatType,enum=safebrowsing_proto.ThreatType" json:"threat_type,omitempty"`
|
||||
// The platform type targeted by the list's entries.
|
||||
PlatformType PlatformType `protobuf:"varint,2,opt,name=platform_type,json=platformType,enum=safebrowsing_proto.PlatformType" json:"platform_type,omitempty"`
|
||||
// The entry types contained in the list.
|
||||
ThreatEntryType ThreatEntryType `protobuf:"varint,3,opt,name=threat_entry_type,json=threatEntryType,enum=safebrowsing_proto.ThreatEntryType" json:"threat_entry_type,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ThreatListDescriptor) Reset() { *m = ThreatListDescriptor{} }
|
||||
func (m *ThreatListDescriptor) String() string { return proto.CompactTextString(m) }
|
||||
func (*ThreatListDescriptor) ProtoMessage() {}
|
||||
func (*ThreatListDescriptor) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
|
||||
|
||||
// A collection of lists available for download by the client.
|
||||
type ListThreatListsResponse struct {
|
||||
// The lists available for download by the client.
|
||||
ThreatLists []*ThreatListDescriptor `protobuf:"bytes,1,rep,name=threat_lists,json=threatLists" json:"threat_lists,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ListThreatListsResponse) Reset() { *m = ListThreatListsResponse{} }
|
||||
func (m *ListThreatListsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListThreatListsResponse) ProtoMessage() {}
|
||||
func (*ListThreatListsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} }
|
||||
|
||||
func (m *ListThreatListsResponse) GetThreatLists() []*ThreatListDescriptor {
|
||||
if m != nil {
|
||||
return m.ThreatLists
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A Duration represents a signed, fixed-length span of time represented
|
||||
// as a count of seconds and fractions of seconds at nanosecond
|
||||
// resolution. It is independent of any calendar and concepts like "day"
|
||||
// or "month". It is related to Timestamp in that the difference between
|
||||
// two Timestamp values is a Duration and it can be added or subtracted
|
||||
// from a Timestamp. Range is approximately +-10,000 years.
|
||||
type Duration struct {
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
// to +315,576,000,000 inclusive.
|
||||
Seconds int64 `protobuf:"varint,1,opt,name=seconds" json:"seconds,omitempty"`
|
||||
// Signed fractions of a second at nanosecond resolution of the span
|
||||
// of time. Durations less than one second are represented with a 0
|
||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||
// of one second or more, a non-zero value for the `nanos` field must be
|
||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||
// to +999,999,999 inclusive.
|
||||
Nanos int32 `protobuf:"varint,2,opt,name=nanos" json:"nanos,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Duration) Reset() { *m = Duration{} }
|
||||
func (m *Duration) String() string { return proto.CompactTextString(m) }
|
||||
func (*Duration) ProtoMessage() {}
|
||||
func (*Duration) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*ThreatInfo)(nil), "safebrowsing_proto.ThreatInfo")
|
||||
proto.RegisterType((*ThreatMatch)(nil), "safebrowsing_proto.ThreatMatch")
|
||||
proto.RegisterType((*FindThreatMatchesRequest)(nil), "safebrowsing_proto.FindThreatMatchesRequest")
|
||||
proto.RegisterType((*FindThreatMatchesResponse)(nil), "safebrowsing_proto.FindThreatMatchesResponse")
|
||||
proto.RegisterType((*FetchThreatListUpdatesRequest)(nil), "safebrowsing_proto.FetchThreatListUpdatesRequest")
|
||||
proto.RegisterType((*FetchThreatListUpdatesRequest_ListUpdateRequest)(nil), "safebrowsing_proto.FetchThreatListUpdatesRequest.ListUpdateRequest")
|
||||
proto.RegisterType((*FetchThreatListUpdatesRequest_ListUpdateRequest_Constraints)(nil), "safebrowsing_proto.FetchThreatListUpdatesRequest.ListUpdateRequest.Constraints")
|
||||
proto.RegisterType((*FetchThreatListUpdatesResponse)(nil), "safebrowsing_proto.FetchThreatListUpdatesResponse")
|
||||
proto.RegisterType((*FetchThreatListUpdatesResponse_ListUpdateResponse)(nil), "safebrowsing_proto.FetchThreatListUpdatesResponse.ListUpdateResponse")
|
||||
proto.RegisterType((*FindFullHashesRequest)(nil), "safebrowsing_proto.FindFullHashesRequest")
|
||||
proto.RegisterType((*FindFullHashesResponse)(nil), "safebrowsing_proto.FindFullHashesResponse")
|
||||
proto.RegisterType((*ClientInfo)(nil), "safebrowsing_proto.ClientInfo")
|
||||
proto.RegisterType((*Checksum)(nil), "safebrowsing_proto.Checksum")
|
||||
proto.RegisterType((*ThreatEntry)(nil), "safebrowsing_proto.ThreatEntry")
|
||||
proto.RegisterType((*ThreatEntrySet)(nil), "safebrowsing_proto.ThreatEntrySet")
|
||||
proto.RegisterType((*RawIndices)(nil), "safebrowsing_proto.RawIndices")
|
||||
proto.RegisterType((*RawHashes)(nil), "safebrowsing_proto.RawHashes")
|
||||
proto.RegisterType((*RiceDeltaEncoding)(nil), "safebrowsing_proto.RiceDeltaEncoding")
|
||||
proto.RegisterType((*ThreatEntryMetadata)(nil), "safebrowsing_proto.ThreatEntryMetadata")
|
||||
proto.RegisterType((*ThreatEntryMetadata_MetadataEntry)(nil), "safebrowsing_proto.ThreatEntryMetadata.MetadataEntry")
|
||||
proto.RegisterType((*ThreatListDescriptor)(nil), "safebrowsing_proto.ThreatListDescriptor")
|
||||
proto.RegisterType((*ListThreatListsResponse)(nil), "safebrowsing_proto.ListThreatListsResponse")
|
||||
proto.RegisterType((*Duration)(nil), "safebrowsing_proto.Duration")
|
||||
proto.RegisterEnum("safebrowsing_proto.ThreatType", ThreatType_name, ThreatType_value)
|
||||
proto.RegisterEnum("safebrowsing_proto.PlatformType", PlatformType_name, PlatformType_value)
|
||||
proto.RegisterEnum("safebrowsing_proto.CompressionType", CompressionType_name, CompressionType_value)
|
||||
proto.RegisterEnum("safebrowsing_proto.ThreatEntryType", ThreatEntryType_name, ThreatEntryType_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{
|
||||
// 1635 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xcc, 0x58, 0x4d, 0x8f, 0xdb, 0xc6,
|
||||
0x19, 0x2e, 0x45, 0x7d, 0xbe, 0xfa, 0x58, 0xee, 0xd8, 0x6b, 0x2b, 0x4e, 0x1c, 0x6f, 0x68, 0xa4,
|
||||
0x35, 0x8c, 0x62, 0x51, 0x38, 0x48, 0xd2, 0x16, 0x45, 0x5b, 0x56, 0xa2, 0xbc, 0x44, 0xb4, 0xa4,
|
||||
0x3a, 0x92, 0xbc, 0x76, 0x73, 0x20, 0x68, 0x6a, 0xd6, 0x22, 0x22, 0x91, 0x0a, 0x67, 0x64, 0x79,
|
||||
0xf3, 0x13, 0x7a, 0x2a, 0x50, 0xf4, 0xdc, 0x9e, 0x7b, 0x2d, 0xfa, 0x03, 0xfa, 0x33, 0x7a, 0xec,
|
||||
0x2f, 0x28, 0x7a, 0xee, 0x25, 0x98, 0xe1, 0x50, 0xa2, 0x3e, 0xd6, 0x96, 0xb3, 0x3e, 0xf8, 0x36,
|
||||
0xf3, 0xf2, 0x9d, 0x67, 0x5e, 0x3e, 0xef, 0x27, 0x09, 0x88, 0x7a, 0x17, 0xe4, 0x79, 0x1c, 0x2d,
|
||||
0x68, 0x10, 0xbe, 0x38, 0x99, 0xc5, 0x11, 0x8b, 0xd0, 0x9a, 0xcc, 0x15, 0x32, 0xfd, 0x1f, 0x39,
|
||||
0x80, 0xc1, 0x38, 0x26, 0x1e, 0xb3, 0xc2, 0x8b, 0x08, 0x19, 0x50, 0x63, 0x62, 0xe7, 0xb2, 0xcb,
|
||||
0x19, 0xa1, 0x4d, 0xe5, 0x58, 0x7d, 0xd0, 0x78, 0xf4, 0xf1, 0xc9, 0xf6, 0xc9, 0x93, 0xe4, 0xd4,
|
||||
0xe0, 0x72, 0x46, 0x70, 0x95, 0x2d, 0xd7, 0x14, 0x3d, 0x86, 0xc6, 0x6c, 0xe2, 0xb1, 0x8b, 0x28,
|
||||
0x9e, 0x4a, 0x90, 0x9c, 0x00, 0x39, 0xde, 0x05, 0xd2, 0x93, 0x9a, 0x02, 0xa6, 0x3e, 0xcb, 0xec,
|
||||
0x28, 0xfa, 0x3d, 0x20, 0x69, 0x0b, 0x09, 0x59, 0x7c, 0x29, 0xc1, 0xf2, 0x02, 0xec, 0xfe, 0xd5,
|
||||
0x16, 0x99, 0x5c, 0x59, 0xe0, 0x69, 0x6c, 0x5d, 0x40, 0x51, 0x07, 0x1a, 0x19, 0xc8, 0x80, 0xd0,
|
||||
0xa6, 0x7a, 0xac, 0x3e, 0xa8, 0x3e, 0xba, 0xf7, 0x06, 0x38, 0x5c, 0x5f, 0x41, 0x05, 0x84, 0xea,
|
||||
0xff, 0x52, 0xa1, 0x9a, 0x3c, 0x3e, 0xf3, 0x98, 0x3f, 0x46, 0xbf, 0x81, 0x6a, 0x86, 0xb6, 0xa6,
|
||||
0x72, 0xac, 0xec, 0xc1, 0x1a, 0xac, 0x58, 0x43, 0x26, 0xd4, 0xd7, 0x48, 0x6b, 0xe6, 0x04, 0xc4,
|
||||
0x9b, 0x39, 0xab, 0x65, 0x39, 0x43, 0x0e, 0x1c, 0x6e, 0x51, 0xd6, 0x2c, 0x0a, 0xa8, 0xbd, 0x18,
|
||||
0x3b, 0xd8, 0x60, 0x0c, 0x7d, 0x09, 0xc5, 0x44, 0xd4, 0x54, 0x8f, 0x95, 0x7d, 0x88, 0x92, 0xea,
|
||||
0xe8, 0x6b, 0x38, 0x5a, 0xb3, 0x64, 0x4a, 0x98, 0x37, 0xf2, 0x98, 0xd7, 0xcc, 0x0b, 0x9c, 0x9f,
|
||||
0xbc, 0x01, 0xe7, 0x4c, 0xaa, 0xe3, 0x1b, 0x6c, 0x5b, 0x88, 0x5a, 0xd0, 0xf0, 0x3d, 0x7f, 0x4c,
|
||||
0xdc, 0xd1, 0x3c, 0xf6, 0x58, 0x10, 0x85, 0xcd, 0x82, 0x40, 0xfd, 0x68, 0x17, 0x6a, 0x5b, 0xea,
|
||||
0xe0, 0xba, 0x38, 0x93, 0x6e, 0xf5, 0x3f, 0x2b, 0xd0, 0xec, 0x04, 0xe1, 0x28, 0xe3, 0x47, 0x42,
|
||||
0x31, 0xf9, 0x76, 0x4e, 0x28, 0x43, 0x5f, 0x40, 0xd1, 0x9f, 0x04, 0x24, 0x64, 0xc2, 0x97, 0xd5,
|
||||
0xdd, 0xbe, 0x6c, 0x09, 0x0d, 0x9e, 0x37, 0x58, 0x6a, 0x67, 0x02, 0x21, 0x08, 0x2f, 0x22, 0xe1,
|
||||
0xc5, 0xea, 0xeb, 0x02, 0x41, 0x1c, 0x96, 0x81, 0xc0, 0xd7, 0xfa, 0x13, 0xf8, 0x60, 0x87, 0x51,
|
||||
0x74, 0x16, 0x85, 0x94, 0xa0, 0x5f, 0x40, 0x69, 0x9a, 0x88, 0x44, 0x62, 0xbe, 0xd6, 0x1d, 0xe2,
|
||||
0x2c, 0x4e, 0xf5, 0xf5, 0xbf, 0x17, 0xe1, 0x6e, 0x87, 0x30, 0x7f, 0x9c, 0x3c, 0xed, 0x06, 0x94,
|
||||
0x0d, 0x67, 0x23, 0x8f, 0x5d, 0xff, 0x95, 0xe7, 0x70, 0x73, 0x12, 0x50, 0xe6, 0xce, 0x05, 0x9c,
|
||||
0x1b, 0x27, 0x70, 0x69, 0x66, 0xb5, 0x76, 0xa1, 0xbc, 0xd6, 0x90, 0x93, 0x95, 0x48, 0x4a, 0x30,
|
||||
0x9a, 0x6c, 0x8a, 0xe8, 0x9d, 0x7f, 0xe7, 0xe1, 0x70, 0x4b, 0xf3, 0xfd, 0x4e, 0xc4, 0xc2, 0x35,
|
||||
0x12, 0xf1, 0x26, 0x14, 0x28, 0xf3, 0x18, 0x11, 0x79, 0x58, 0xc3, 0xc9, 0x06, 0x7d, 0x0b, 0x55,
|
||||
0x3f, 0x0a, 0x29, 0x8b, 0xbd, 0x20, 0x64, 0x54, 0xe6, 0x96, 0xf3, 0x0e, 0x28, 0x3f, 0x69, 0xad,
|
||||
0x60, 0x71, 0xf6, 0x8e, 0x3b, 0xff, 0x51, 0xa0, 0x9a, 0x79, 0x88, 0x7e, 0x0a, 0x68, 0xea, 0xbd,
|
||||
0x4a, 0xbd, 0x9f, 0x96, 0x55, 0x4e, 0x7c, 0x01, 0x6b, 0x53, 0xef, 0x55, 0x02, 0x2b, 0x0b, 0x27,
|
||||
0xfa, 0x19, 0xdc, 0xe4, 0xda, 0x3c, 0x8b, 0x9f, 0x7b, 0x74, 0xa5, 0x9f, 0x13, 0xfa, 0x1c, 0xa9,
|
||||
0x2d, 0x1f, 0xa5, 0x27, 0x6e, 0x41, 0x31, 0x26, 0x2f, 0x78, 0x8e, 0xf3, 0x37, 0xaf, 0x60, 0xb9,
|
||||
0x43, 0x7f, 0x80, 0x5b, 0x74, 0x3e, 0x9b, 0x45, 0x31, 0x23, 0x23, 0xd7, 0x8f, 0xa6, 0xb3, 0x98,
|
||||
0x50, 0x1a, 0x44, 0xe1, 0x6b, 0x3b, 0x44, 0x6b, 0xa5, 0x27, 0x68, 0x3e, 0x5a, 0x42, 0x64, 0x9e,
|
||||
0x50, 0xfd, 0x4f, 0x25, 0xf8, 0xf8, 0x2a, 0xc2, 0x64, 0x2a, 0x5e, 0xc2, 0xd1, 0x7a, 0xd4, 0x27,
|
||||
0xf2, 0x34, 0x31, 0xcd, 0xb7, 0xf1, 0x41, 0x72, 0x74, 0xcd, 0x09, 0x89, 0x08, 0xdf, 0x98, 0x6c,
|
||||
0xc9, 0x28, 0xea, 0xc1, 0xd1, 0x34, 0x08, 0x83, 0xe9, 0x7c, 0xea, 0x2e, 0xbc, 0x80, 0xad, 0x8a,
|
||||
0x60, 0x6e, 0x8f, 0x22, 0x78, 0x43, 0x1e, 0x3d, 0xf7, 0x02, 0x96, 0x0a, 0xef, 0xfc, 0xad, 0x00,
|
||||
0x68, 0xfb, 0xf6, 0xeb, 0x27, 0xd3, 0xce, 0x2c, 0xc8, 0x5d, 0x23, 0x0b, 0xb6, 0xb2, 0x53, 0xfd,
|
||||
0x41, 0xd9, 0xb9, 0x80, 0x7a, 0xea, 0xb0, 0x04, 0x26, 0x2f, 0x60, 0xf0, 0x3b, 0x71, 0xda, 0x49,
|
||||
0xba, 0x48, 0x2e, 0x8e, 0x33, 0x3b, 0xf4, 0x5b, 0xa8, 0x78, 0xa3, 0x51, 0xc0, 0x44, 0x9c, 0x16,
|
||||
0x44, 0xa4, 0xe8, 0x6f, 0x20, 0xa2, 0x4f, 0x18, 0x5e, 0x1d, 0x42, 0xbf, 0x86, 0x72, 0x4c, 0xa6,
|
||||
0xd1, 0x4b, 0x6f, 0x42, 0x9b, 0xc5, 0xbd, 0x01, 0x96, 0x67, 0xd0, 0x03, 0xd0, 0x42, 0xb2, 0x70,
|
||||
0x93, 0xda, 0xed, 0x26, 0x25, 0xa5, 0x24, 0x4a, 0x4a, 0x23, 0x24, 0x8b, 0xa4, 0xbc, 0xf7, 0x45,
|
||||
0x6d, 0xf9, 0x39, 0x94, 0xfd, 0x31, 0xf1, 0xbf, 0xa1, 0xf3, 0x69, 0xb3, 0x7c, 0x75, 0x64, 0xb5,
|
||||
0xa4, 0x0e, 0x5e, 0x6a, 0xeb, 0x18, 0x6a, 0x59, 0x0e, 0xd0, 0x5d, 0xf8, 0x00, 0x9b, 0xfd, 0x9e,
|
||||
0x63, 0xf7, 0x4d, 0x77, 0xf0, 0xac, 0x67, 0xba, 0x43, 0xbb, 0xdf, 0x33, 0x5b, 0x56, 0xc7, 0x32,
|
||||
0xdb, 0xda, 0x8f, 0x10, 0x82, 0x46, 0xcf, 0xc0, 0x03, 0xcb, 0xe8, 0xba, 0xc3, 0x5e, 0xdb, 0x18,
|
||||
0x98, 0x9a, 0x82, 0x0e, 0xa0, 0xda, 0x19, 0x76, 0x97, 0x82, 0x9c, 0xfe, 0x4f, 0x05, 0x8e, 0x78,
|
||||
0x63, 0xec, 0xcc, 0x27, 0x93, 0x53, 0x8f, 0xbe, 0x83, 0x56, 0x7d, 0x1f, 0xea, 0x59, 0x16, 0x92,
|
||||
0x31, 0xb5, 0x86, 0x6b, 0xfe, 0x8a, 0x03, 0xba, 0xd9, 0xcf, 0xd5, 0xb7, 0xee, 0xe7, 0xff, 0x57,
|
||||
0xe0, 0xd6, 0xa6, 0xdd, 0xd7, 0xee, 0xe6, 0xef, 0xbe, 0x04, 0xa0, 0x01, 0xdc, 0x0e, 0xc9, 0x0b,
|
||||
0x8f, 0x05, 0x2f, 0x89, 0xbb, 0x31, 0x5b, 0xa9, 0x7b, 0x60, 0x1e, 0xa5, 0x87, 0x5b, 0x6b, 0x33,
|
||||
0x56, 0x0f, 0x60, 0xc5, 0x3c, 0xfa, 0x10, 0x2a, 0x92, 0xf1, 0x60, 0x24, 0x9c, 0x55, 0xc1, 0xe5,
|
||||
0x44, 0x60, 0x8d, 0xd0, 0xa7, 0xd0, 0x90, 0x0f, 0x5f, 0x92, 0x98, 0xa6, 0xef, 0x52, 0xc1, 0xd2,
|
||||
0x49, 0x4f, 0x12, 0xa1, 0xae, 0x43, 0x39, 0x8d, 0x38, 0xde, 0x1a, 0xe8, 0xd8, 0x7b, 0xf4, 0xf9,
|
||||
0x17, 0x02, 0xac, 0x86, 0xe5, 0x4e, 0xff, 0x2c, 0x1d, 0xce, 0x45, 0xfc, 0x23, 0x04, 0xf9, 0xb1,
|
||||
0x47, 0xc7, 0x52, 0x49, 0xac, 0x91, 0x06, 0xea, 0x3c, 0x9e, 0xc8, 0x2b, 0xf8, 0x52, 0xff, 0x5f,
|
||||
0x0e, 0x1a, 0xeb, 0x59, 0x83, 0x6c, 0xd0, 0x32, 0x8d, 0x25, 0x5b, 0x04, 0xf7, 0x6a, 0x2e, 0x07,
|
||||
0xfe, 0xba, 0x00, 0xfd, 0x0a, 0x20, 0xf6, 0x16, 0xee, 0x58, 0x84, 0x81, 0x74, 0xd5, 0xdd, 0x5d,
|
||||
0x48, 0xd8, 0x5b, 0xc8, 0x58, 0xa9, 0xc4, 0xe9, 0x92, 0x87, 0x22, 0x3f, 0x1d, 0x84, 0xa3, 0xc0,
|
||||
0x17, 0x1f, 0x2e, 0x57, 0x86, 0x22, 0xf6, 0x16, 0x56, 0xa2, 0x85, 0xf9, 0x85, 0x72, 0x8d, 0x3a,
|
||||
0x50, 0x8d, 0x03, 0x9f, 0xa4, 0xf7, 0x27, 0xc3, 0xc2, 0xa7, 0x3b, 0x01, 0x02, 0x9f, 0xb4, 0xc9,
|
||||
0x84, 0x79, 0x66, 0xe8, 0x47, 0xa3, 0x20, 0x7c, 0x81, 0x81, 0x9f, 0x94, 0x86, 0x9c, 0x42, 0x4d,
|
||||
0xe0, 0xa4, 0x96, 0x14, 0xde, 0x06, 0x48, 0x98, 0x20, 0x2d, 0xd2, 0x7f, 0x0c, 0xb0, 0xb2, 0x15,
|
||||
0x35, 0xa1, 0x94, 0x42, 0xf2, 0x7c, 0x28, 0xe0, 0x74, 0xab, 0x7f, 0x05, 0x95, 0x25, 0x25, 0xe8,
|
||||
0x1e, 0x54, 0x67, 0x31, 0xb9, 0x08, 0x5e, 0xb9, 0x34, 0xf8, 0x8e, 0xc8, 0x49, 0x03, 0x12, 0x51,
|
||||
0x3f, 0xf8, 0x8e, 0x97, 0x9b, 0x4d, 0x9a, 0x6b, 0x19, 0x1e, 0xf5, 0xbf, 0x2a, 0x70, 0xb8, 0x65,
|
||||
0x17, 0x47, 0xbd, 0x08, 0x62, 0xca, 0xdc, 0x97, 0xde, 0x64, 0x9e, 0xa0, 0xaa, 0x18, 0x84, 0xe8,
|
||||
0x09, 0x97, 0xf0, 0xf8, 0x14, 0x6f, 0x3d, 0xf3, 0x62, 0x6f, 0x4a, 0x18, 0x89, 0xe5, 0xcc, 0x52,
|
||||
0xe7, 0xd2, 0x5e, 0x2a, 0xe4, 0x38, 0xe1, 0x7c, 0x9a, 0xf9, 0xbc, 0x14, 0xd6, 0x85, 0xf3, 0x69,
|
||||
0x3a, 0xcf, 0x7c, 0x02, 0x35, 0xc2, 0x2f, 0x25, 0x23, 0x77, 0xf9, 0x3d, 0x54, 0xc3, 0x55, 0x29,
|
||||
0xe3, 0xd3, 0x0f, 0xb7, 0xf0, 0xc6, 0x8e, 0x6f, 0x21, 0xe4, 0x40, 0x69, 0x35, 0x5f, 0xf1, 0x82,
|
||||
0xf1, 0xf9, 0x9e, 0x5f, 0x51, 0x27, 0xe9, 0x22, 0xf9, 0x46, 0x4b, 0x51, 0xee, 0x7c, 0x09, 0xf5,
|
||||
0xb5, 0x27, 0x3c, 0x2d, 0xbe, 0x21, 0x97, 0x32, 0x53, 0xf8, 0x92, 0xcf, 0x9d, 0x09, 0x23, 0x09,
|
||||
0x8f, 0xc9, 0x46, 0xff, 0xaf, 0x02, 0x37, 0x57, 0x3d, 0xb1, 0x4d, 0xa8, 0x1f, 0x07, 0x33, 0x16,
|
||||
0xc5, 0xef, 0xf7, 0xfc, 0xad, 0xfe, 0xf0, 0xc9, 0x43, 0xbf, 0x80, 0xdb, 0xfc, 0x55, 0x57, 0x2f,
|
||||
0xbd, 0xaa, 0xe3, 0x5f, 0x2d, 0xff, 0x99, 0xf0, 0x69, 0x2d, 0xf5, 0xcd, 0x83, 0xab, 0xaf, 0x59,
|
||||
0xe7, 0x2c, 0xfd, 0x7b, 0x22, 0x40, 0xf5, 0x5f, 0x42, 0x79, 0x59, 0x93, 0x9b, 0x50, 0xa2, 0xc4,
|
||||
0x8f, 0xc2, 0x11, 0x95, 0xf1, 0x98, 0x6e, 0xb9, 0x57, 0x42, 0x2f, 0x8c, 0xd2, 0xb9, 0x39, 0xd9,
|
||||
0x3c, 0xfc, 0xa3, 0x92, 0xfe, 0xcb, 0x11, 0x1c, 0x7c, 0x08, 0xb7, 0x07, 0xa7, 0xd8, 0x34, 0x06,
|
||||
0xbb, 0x9a, 0x6e, 0x15, 0x4a, 0x67, 0x46, 0xf7, 0xdc, 0xc0, 0xbc, 0xdb, 0xde, 0x02, 0xd4, 0x77,
|
||||
0x5a, 0xbc, 0x01, 0x9b, 0xf6, 0x63, 0xcb, 0x36, 0x4d, 0x6c, 0xd9, 0x8f, 0xb5, 0x1c, 0x3a, 0x82,
|
||||
0xc3, 0xa1, 0x7d, 0x6e, 0xd8, 0x03, 0xb3, 0xed, 0xf6, 0x9d, 0xce, 0x40, 0xa8, 0xab, 0xe8, 0x3e,
|
||||
0xdc, 0xeb, 0x39, 0x03, 0xd3, 0xe6, 0x2d, 0xbb, 0xfb, 0xcc, 0x3d, 0x35, 0xf0, 0x59, 0x67, 0xd8,
|
||||
0x75, 0x8d, 0x5e, 0xaf, 0x6b, 0xb5, 0x8c, 0x81, 0xe5, 0xd8, 0x5a, 0xfe, 0xe1, 0x5f, 0x14, 0xa8,
|
||||
0x65, 0x1d, 0xc4, 0xa7, 0x80, 0x5e, 0xd7, 0x18, 0x74, 0x1c, 0x7c, 0x76, 0x85, 0x41, 0xe7, 0x96,
|
||||
0xdd, 0x76, 0xce, 0xfb, 0x9a, 0x82, 0x2a, 0x50, 0xe8, 0x5a, 0xf6, 0xf0, 0xa9, 0x96, 0xe3, 0x72,
|
||||
0xc3, 0x6e, 0x63, 0xc7, 0x6a, 0x6b, 0x2a, 0x2a, 0x81, 0xea, 0xf4, 0x9f, 0x6a, 0x79, 0xbe, 0xb0,
|
||||
0x9c, 0xbe, 0x56, 0x40, 0x1a, 0xd4, 0x0c, 0xfb, 0x99, 0x9b, 0x22, 0x6b, 0x45, 0x74, 0x08, 0x75,
|
||||
0xa3, 0xdb, 0x5d, 0x4a, 0xfa, 0x5a, 0x09, 0x01, 0x14, 0x5b, 0xa7, 0xd8, 0x39, 0x33, 0xb5, 0xf2,
|
||||
0xc3, 0x0e, 0x1c, 0x6c, 0x14, 0x6a, 0x74, 0x0c, 0x1f, 0xb5, 0x9c, 0xb3, 0x1e, 0x36, 0xfb, 0x7d,
|
||||
0xcb, 0xb1, 0x77, 0x19, 0x57, 0x02, 0x15, 0x1b, 0xe7, 0x9a, 0x82, 0xca, 0x90, 0xc7, 0x56, 0xcb,
|
||||
0xd4, 0x72, 0x0f, 0xbf, 0x86, 0x83, 0x8d, 0xa0, 0x41, 0x9f, 0xc0, 0x5d, 0x49, 0xb8, 0x69, 0x0f,
|
||||
0xf0, 0xb3, 0x2b, 0x80, 0x86, 0xb8, 0xab, 0x29, 0xa8, 0x01, 0x60, 0x3e, 0x35, 0x5b, 0xc3, 0x81,
|
||||
0xf1, 0xbb, 0xae, 0xa9, 0xe5, 0x50, 0x0d, 0xca, 0x56, 0xcf, 0xc5, 0x86, 0xfd, 0xd8, 0xd4, 0xd4,
|
||||
0xe7, 0x45, 0x11, 0x2e, 0x9f, 0x7d, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x26, 0x20, 0x49, 0x28, 0xc6,
|
||||
0x13, 0x00, 0x00,
|
||||
}
|
|
@ -0,0 +1,469 @@
|
|||
// Copied into the Boulder repo from https://github.com/google/safebrowsing/blob/fb5517391094054b6c87007fd85752f29e9b6075/internal/safebrowsing_proto/safebrowsing.proto
|
||||
//
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package safebrowsing_proto;
|
||||
|
||||
// The Safe Browsing APIs enable clients to check web resources (most commonly
|
||||
// URLs) against Google's constantly updated lists of unsafe web resources. The
|
||||
// Safe Browsing APIs (v4) feature the Update API and the Lookup API.
|
||||
//
|
||||
// The Update API is designed for our larger clients and includes the
|
||||
// FindFullHashes and FetchThreatListUpdates methods. The Update API requires
|
||||
// that clients maintain downloaded threat lists in a local database.
|
||||
//
|
||||
// First, clients match against their local lists to determine the state (safe
|
||||
// or unsafe) of a given web resource. Most commonly, lists are comprised of
|
||||
// hash prefixes of blacklisted URL expressions. To check a URL, clients
|
||||
// generate the hashes of a given URL and check for prefix collisions in their
|
||||
// local lists; if a prefix match is found, the client obtains the full hashes
|
||||
// associated with the matched hash prefix via the FindFullHashes method. The
|
||||
// client then compares the local full hash with the returned full hashes; a match
|
||||
// indicates that the URL is unsafe.
|
||||
//
|
||||
// Second, clients obtain updates to their local databases via the
|
||||
// FetchThreatListUpdates method, which takes the current state of the client
|
||||
// and returns an updated client state along with the changes that the client
|
||||
// should apply to their local threat lists.
|
||||
//
|
||||
// The Lookup API is designed for our smaller clients and allows them to match
|
||||
// resources directly against the Safe Browsing threat lists via the
|
||||
// FindThreatMatches method.
|
||||
//
|
||||
// Clients using either the Update API or the Lookup API can obtain a list of
|
||||
// the Safe Browsing threat lists available for download via the ListThreatLists
|
||||
// method.
|
||||
|
||||
// The information regarding one or more threats that a client submits when
|
||||
// checking for matches in threat lists.
|
||||
message ThreatInfo {
|
||||
// The threat types to be checked.
|
||||
repeated ThreatType threat_types = 1;
|
||||
|
||||
// The platform types to be checked.
|
||||
repeated PlatformType platform_types = 2;
|
||||
|
||||
// The entry types to be checked.
|
||||
repeated ThreatEntryType threat_entry_types = 4;
|
||||
|
||||
// The threat entries to be checked.
|
||||
repeated ThreatEntry threat_entries = 3;
|
||||
}
|
||||
|
||||
// A match when checking a threat entry in the Safe Browsing threat lists.
|
||||
message ThreatMatch {
|
||||
// The threat type matching this threat.
|
||||
ThreatType threat_type = 1;
|
||||
|
||||
// The platform type matching this threat.
|
||||
PlatformType platform_type = 2;
|
||||
|
||||
// The threat entry type matching this threat.
|
||||
ThreatEntryType threat_entry_type = 6;
|
||||
|
||||
// The threat matching this threat.
|
||||
ThreatEntry threat = 3;
|
||||
|
||||
// Optional metadata associated with this threat.
|
||||
ThreatEntryMetadata threat_entry_metadata = 4;
|
||||
|
||||
// The cache lifetime for the returned match. Clients must not cache this
|
||||
// response for more than this duration to avoid false positives.
|
||||
Duration cache_duration = 5;
|
||||
}
|
||||
|
||||
// Request to check entries against lists.
|
||||
message FindThreatMatchesRequest {
|
||||
// The client metadata.
|
||||
ClientInfo client = 1;
|
||||
|
||||
// The lists and entries to be checked for matches.
|
||||
ThreatInfo threat_info = 2;
|
||||
}
|
||||
|
||||
// Response type for requests to find threat matches.
|
||||
message FindThreatMatchesResponse {
|
||||
// The threat list matches.
|
||||
repeated ThreatMatch matches = 1;
|
||||
}
|
||||
|
||||
// Describes a Safe Browsing API update request. Clients can request updates for
|
||||
// multiple lists in a single request.
|
||||
// NOTE: Field index 2 is unused.
|
||||
message FetchThreatListUpdatesRequest {
|
||||
// The client metadata.
|
||||
ClientInfo client = 1;
|
||||
|
||||
// A single list update request.
|
||||
message ListUpdateRequest {
|
||||
// The type of threat posed by entries present in the list.
|
||||
ThreatType threat_type = 1;
|
||||
|
||||
// The type of platform at risk by entries present in the list.
|
||||
PlatformType platform_type = 2;
|
||||
|
||||
// The types of entries present in the list.
|
||||
ThreatEntryType threat_entry_type = 5;
|
||||
|
||||
// The current state of the client for the requested list (the encrypted
|
||||
// ClientState that was sent to the client from the previous update
|
||||
// request).
|
||||
bytes state = 3;
|
||||
|
||||
// The constraints for this update.
|
||||
message Constraints {
|
||||
// The maximum size in number of entries. The update will not contain more
|
||||
// entries than this value. This should be a power of 2 between 2**10 and
|
||||
// 2**20. If zero, no update size limit is set.
|
||||
int32 max_update_entries = 1;
|
||||
|
||||
// Sets the maximum number of entries that the client is willing to have
|
||||
// in the local database. This should be a power of 2 between 2**10 and
|
||||
// 2**20. If zero, no database size limit is set.
|
||||
int32 max_database_entries = 2;
|
||||
|
||||
// Requests the list for a specific geographic location. If not set the
|
||||
// server may pick that value based on the user's IP address. Expects ISO
|
||||
// 3166-1 alpha-2 format.
|
||||
string region = 3;
|
||||
|
||||
// The compression types supported by the client.
|
||||
repeated CompressionType supported_compressions = 4;
|
||||
}
|
||||
|
||||
// The constraints associated with this request.
|
||||
Constraints constraints = 4;
|
||||
}
|
||||
|
||||
// Index 2 is unused.
|
||||
|
||||
// The requested threat list updates.
|
||||
repeated ListUpdateRequest list_update_requests = 3;
|
||||
}
|
||||
|
||||
// Response type for threat list update requests.
|
||||
message FetchThreatListUpdatesResponse {
|
||||
// An update to an individual list.
|
||||
message ListUpdateResponse {
|
||||
// The threat type for which data is returned.
|
||||
ThreatType threat_type = 1;
|
||||
|
||||
// The format of the threats.
|
||||
ThreatEntryType threat_entry_type = 2;
|
||||
|
||||
// The platform type for which data is returned.
|
||||
PlatformType platform_type = 3;
|
||||
|
||||
// The type of response sent to the client.
|
||||
enum ResponseType {
|
||||
// Unknown.
|
||||
RESPONSE_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// Partial updates are applied to the client's existing local database.
|
||||
PARTIAL_UPDATE = 1;
|
||||
|
||||
// Full updates replace the client's entire local database. This means
|
||||
// that either the client was seriously out-of-date or the client is
|
||||
// believed to be corrupt.
|
||||
FULL_UPDATE = 2;
|
||||
}
|
||||
|
||||
// The type of response. This may indicate that an action is required by the
|
||||
// client when the response is received.
|
||||
ResponseType response_type = 4;
|
||||
|
||||
// A set of entries to add to a local threat type's list. Repeated to allow
|
||||
// for a combination of compressed and raw data to be sent in a single
|
||||
// response.
|
||||
repeated ThreatEntrySet additions = 5;
|
||||
|
||||
// A set of entries to remove from a local threat type's list. Repeated for
|
||||
// the same reason as above.
|
||||
repeated ThreatEntrySet removals = 6;
|
||||
|
||||
// The new client state, in encrypted format. Opaque to clients.
|
||||
bytes new_client_state = 7;
|
||||
|
||||
// The expected SHA256 hash of the client state; that is, of the sorted list
|
||||
// of all hashes present in the database after applying the provided update.
|
||||
// If the client state doesn't match the expected state, the client must
|
||||
// disregard this update and retry later.
|
||||
Checksum checksum = 8;
|
||||
}
|
||||
|
||||
// The list updates requested by the clients.
|
||||
repeated ListUpdateResponse list_update_responses = 1;
|
||||
|
||||
// The minimum duration the client must wait before issuing any update
|
||||
// request. If this field is not set clients may update as soon as they want.
|
||||
Duration minimum_wait_duration = 2;
|
||||
}
|
||||
|
||||
// Request to return full hashes matched by the provided hash prefixes.
|
||||
message FindFullHashesRequest {
|
||||
// The client metadata.
|
||||
ClientInfo client = 1;
|
||||
|
||||
// The current client states for each of the client's local threat lists.
|
||||
repeated bytes client_states = 2;
|
||||
|
||||
// The lists and hashes to be checked.
|
||||
ThreatInfo threat_info = 3;
|
||||
}
|
||||
|
||||
// Response type for requests to find full hashes.
|
||||
message FindFullHashesResponse {
|
||||
// The full hashes that matched the requested prefixes.
|
||||
repeated ThreatMatch matches = 1;
|
||||
|
||||
// The minimum duration the client must wait before issuing any find hashes
|
||||
// request. If this field is not set, clients can issue a request as soon as
|
||||
// they want.
|
||||
Duration minimum_wait_duration = 2;
|
||||
|
||||
// For requested entities that did not match the threat list, how long to
|
||||
// cache the response.
|
||||
Duration negative_cache_duration = 3;
|
||||
}
|
||||
|
||||
|
||||
// Types of threats.
|
||||
enum ThreatType {
|
||||
// Unknown.
|
||||
THREAT_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// Malware threat type.
|
||||
MALWARE = 1;
|
||||
|
||||
// Social engineering threat type.
|
||||
SOCIAL_ENGINEERING = 2;
|
||||
|
||||
// Unwanted software threat type.
|
||||
UNWANTED_SOFTWARE = 3;
|
||||
|
||||
// Potentially harmful application threat type.
|
||||
POTENTIALLY_HARMFUL_APPLICATION = 4;
|
||||
}
|
||||
|
||||
// Types of platforms.
|
||||
enum PlatformType {
|
||||
// Unknown platform.
|
||||
PLATFORM_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// Threat posed to Windows.
|
||||
WINDOWS = 1;
|
||||
|
||||
// Threat posed to Linux.
|
||||
LINUX = 2;
|
||||
|
||||
// Threat posed to Android.
|
||||
ANDROID = 3;
|
||||
|
||||
// Threat posed to OSX.
|
||||
OSX = 4;
|
||||
|
||||
// Threat posed to iOS.
|
||||
IOS = 5;
|
||||
|
||||
// Threat posed to at least one of the defined platforms.
|
||||
ANY_PLATFORM = 6;
|
||||
|
||||
// Threat posed to all defined platforms.
|
||||
ALL_PLATFORMS = 7;
|
||||
|
||||
// Threat posed to Chrome.
|
||||
CHROME = 8;
|
||||
}
|
||||
|
||||
// The client metadata associated with Safe Browsing API requests.
|
||||
message ClientInfo {
|
||||
// A client ID that (hopefully) uniquely identifies the client implementation
|
||||
// of the Safe Browsing API.
|
||||
string client_id = 1;
|
||||
|
||||
// The version of the client implementation.
|
||||
string client_version = 2;
|
||||
}
|
||||
|
||||
// The expected state of a client's local database.
|
||||
message Checksum {
|
||||
// The SHA256 hash of the client state; that is, of the sorted list of all
|
||||
// hashes present in the database.
|
||||
bytes sha256 = 1;
|
||||
}
|
||||
|
||||
// The ways in which threat entry sets can be compressed.
|
||||
enum CompressionType {
|
||||
// Unknown.
|
||||
COMPRESSION_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// Raw, uncompressed data.
|
||||
RAW = 1;
|
||||
|
||||
// Rice-Golomb encoded data.
|
||||
RICE = 2;
|
||||
}
|
||||
|
||||
// An individual threat; for example, a malicious URL or its hash
|
||||
// representation. Only one of these fields should be set.
|
||||
message ThreatEntry {
|
||||
// A hash prefix, consisting of the most significant 4-32 bytes of a SHA256
|
||||
// hash.
|
||||
bytes hash = 1;
|
||||
|
||||
// A URL.
|
||||
string url = 2;
|
||||
}
|
||||
|
||||
// Types of entries that pose threats. Threat lists are collections of entries
|
||||
// of a single type.
|
||||
enum ThreatEntryType {
|
||||
// Unspecified.
|
||||
THREAT_ENTRY_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// A URL.
|
||||
URL = 1;
|
||||
|
||||
// An executable program.
|
||||
EXECUTABLE = 2;
|
||||
|
||||
// An IP range.
|
||||
IP_RANGE = 3;
|
||||
}
|
||||
|
||||
// A set of threats that should be added or removed from a client's local
|
||||
// database.
|
||||
message ThreatEntrySet {
|
||||
// The compression type for the entries in this set.
|
||||
CompressionType compression_type = 1;
|
||||
|
||||
// At most one of the following fields should be set.
|
||||
|
||||
// The raw SHA256-formatted entries.
|
||||
RawHashes raw_hashes = 2;
|
||||
|
||||
// The raw removal indices for a local list.
|
||||
RawIndices raw_indices = 3;
|
||||
|
||||
// The encoded 4-byte prefixes of SHA256-formatted entries, using a
|
||||
// Golomb-Rice encoding.
|
||||
RiceDeltaEncoding rice_hashes = 4;
|
||||
|
||||
// The encoded local, lexicographically-sorted list indices, using a
|
||||
// Golomb-Rice encoding. Used for sending compressed removal indices.
|
||||
RiceDeltaEncoding rice_indices = 5;
|
||||
}
|
||||
|
||||
// A set of raw indices to remove from a local list.
|
||||
message RawIndices {
|
||||
// The indices to remove from a lexicographically-sorted local list.
|
||||
repeated int32 indices = 1;
|
||||
}
|
||||
|
||||
// The uncompressed threat entries in hash format of a particular prefix length.
|
||||
// Hashes can be anywhere from 4 to 32 bytes in size. A large majority are 4
|
||||
// bytes, but some hashes are lengthened if they collide with the hash of a
|
||||
// popular URL.
|
||||
//
|
||||
// Used for sending ThreatEntrySet to clients that do not support compression,
|
||||
// or when sending non-4-byte hashes to clients that do support compression.
|
||||
message RawHashes {
|
||||
// The number of bytes for each prefix encoded below. This field can be
|
||||
// anywhere from 4 (shortest prefix) to 32 (full SHA256 hash).
|
||||
int32 prefix_size = 1;
|
||||
|
||||
// The hashes, all concatenated into one long string. Each hash has a prefix
|
||||
// size of |prefix_size| above. Hashes are sorted in lexicographic order.
|
||||
bytes raw_hashes = 2;
|
||||
}
|
||||
|
||||
// The Rice-Golomb encoded data. Used for sending compressed 4-byte hashes or
|
||||
// compressed removal indices.
|
||||
message RiceDeltaEncoding {
|
||||
// The offset of the first entry in the encoded data, or, if only a single
|
||||
// integer was encoded, that single integer's value.
|
||||
int64 first_value = 1;
|
||||
|
||||
// The Golomb-Rice parameter which is a number between 2 and 28. This field
|
||||
// is missing (that is, zero) if num_entries is zero.
|
||||
int32 rice_parameter = 2;
|
||||
|
||||
// The number of entries that are delta encoded in the encoded data. If only a
|
||||
// single integer was encoded, this will be zero and the single value will be
|
||||
// stored in first_value.
|
||||
int32 num_entries = 3;
|
||||
|
||||
// The encoded deltas that are encoded using the Golomb-Rice coder.
|
||||
bytes encoded_data = 4;
|
||||
}
|
||||
|
||||
// The metadata associated with a specific threat entry. The client is expected
|
||||
// to know the metadata key/value pairs associated with each threat type.
|
||||
message ThreatEntryMetadata {
|
||||
// A single metadata entry.
|
||||
message MetadataEntry {
|
||||
// The metadata entry key.
|
||||
bytes key = 1;
|
||||
|
||||
// The metadata entry value.
|
||||
bytes value = 2;
|
||||
}
|
||||
|
||||
// The metadata entries.
|
||||
repeated MetadataEntry entries = 1;
|
||||
}
|
||||
|
||||
// Describes an individual threat list. A list is defined by three parameters:
|
||||
// the type of threat posed, the type of platform targeted by the threat, and
|
||||
// the type of entries in the list.
|
||||
message ThreatListDescriptor {
|
||||
// The threat type posed by the list's entries.
|
||||
ThreatType threat_type = 1;
|
||||
|
||||
// The platform type targeted by the list's entries.
|
||||
PlatformType platform_type = 2;
|
||||
|
||||
// The entry types contained in the list.
|
||||
ThreatEntryType threat_entry_type = 3;
|
||||
}
|
||||
|
||||
// A collection of lists available for download by the client.
|
||||
message ListThreatListsResponse {
|
||||
// The lists available for download by the client.
|
||||
repeated ThreatListDescriptor threat_lists = 1;
|
||||
}
|
||||
|
||||
// A Duration represents a signed, fixed-length span of time represented
|
||||
// as a count of seconds and fractions of seconds at nanosecond
|
||||
// resolution. It is independent of any calendar and concepts like "day"
|
||||
// or "month". It is related to Timestamp in that the difference between
|
||||
// two Timestamp values is a Duration and it can be added or subtracted
|
||||
// from a Timestamp. Range is approximately +-10,000 years.
|
||||
message Duration {
|
||||
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
// to +315,576,000,000 inclusive.
|
||||
int64 seconds = 1;
|
||||
|
||||
// Signed fractions of a second at nanosecond resolution of the span
|
||||
// of time. Durations less than one second are represented with a 0
|
||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||
// of one second or more, a non-zero value for the `nanos` field must be
|
||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||
// to +999,999,999 inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
|
@ -23,7 +23,7 @@ REVOCATION_FAILED = 2
|
|||
MAILER_FAILED = 3
|
||||
|
||||
class ExitStatus:
|
||||
OK, PythonFailure, NodeFailure, Error, OCSPFailure, CTFailure, IncorrectCommandLineArgs, RevokerFailure = range(8)
|
||||
OK, PythonFailure, NodeFailure, Error, OCSPFailure, CTFailure, IncorrectCommandLineArgs, RevokerFailure, GSBFailure = range(9)
|
||||
|
||||
JS_DIR = 'test/js'
|
||||
|
||||
|
@ -170,6 +170,23 @@ def verify_ct_submission(expectedSubmissions, url):
|
|||
die(ExitStatus.CTFailure)
|
||||
return 0
|
||||
|
||||
# verify_gsb_lookups will check a gsb-test-srv's at `server` to see that `url`
|
||||
# has received exactly `expected` lookup hits or will exit with ExistStatus.GSBFailure
|
||||
def verify_gsb_lookups(url, expected, server):
|
||||
resp = urllib2.urlopen(server)
|
||||
hitStr = resp.read()
|
||||
hits = json.loads(hitStr)
|
||||
|
||||
# The GSB test server tracks hits with a trailing / on the URL
|
||||
if not url.endswith("/"):
|
||||
url += "/"
|
||||
|
||||
actual = hits.get(url, 0)
|
||||
if actual != expected:
|
||||
print "Expected %d Google Safe Browsing lookups for %s, found %d" % (expected, url, actual)
|
||||
die(ExitStatus.GSBFailure)
|
||||
return 0
|
||||
|
||||
def run_node_test(domain, chall_type, expected_ct_submissions):
|
||||
email_addr = "js.integration.test@letsencrypt.org"
|
||||
cert_file = os.path.join(tempdir, "cert.der")
|
||||
|
@ -428,6 +445,18 @@ def main():
|
|||
print("\nIssued certificate for domain with bad CAA records")
|
||||
die(ExitStatus.NodeFailure)
|
||||
|
||||
if default_config_dir.startswith("test/config-next"):
|
||||
# Try to issue for a name that we know the gsb-test-srv rejects. If this
|
||||
# doesn't fail it is an error!
|
||||
if run_node_test("honest.achmeds.discount.hosting.com", challenge_types[0], expected_ct_submissions) != ISSUANCE_FAILED:
|
||||
print("\nIssued certificate for domain on Google Safe Browsing test server list")
|
||||
die(ExitStatus.GSBFailure)
|
||||
|
||||
# Verify that GSB was consulted for the domain by checking the
|
||||
# gsb-test-srv's `/hits` endpoint for the URL we tried to issue for. The
|
||||
# GSB server should have been consulted for this exact URL 1 time.
|
||||
verify_gsb_lookups("honest.achmeds.discount.hosting.com", 1, "http://localhost:6000/hits")
|
||||
|
||||
run_expired_authz_purger_test()
|
||||
|
||||
run_certificates_per_name_test()
|
||||
|
|
|
@ -48,6 +48,9 @@ def start(race_detection):
|
|||
global processes
|
||||
forward()
|
||||
progs = [
|
||||
# The gsb-test-srv needs to be started before the VA or its intial DB
|
||||
# update will fail and all subsequent lookups will be invalid
|
||||
'gsb-test-srv -apikey my-voice-is-my-passport',
|
||||
'boulder-sa --config %s' % os.path.join(default_config_dir, "sa.json"),
|
||||
'boulder-wfe --config %s' % os.path.join(default_config_dir, "wfe.json"),
|
||||
'boulder-ra --config %s' % os.path.join(default_config_dir, "ra.json"),
|
||||
|
|
Loading…
Reference in New Issue