boulder/va/gsb.go

63 lines
2.3 KiB
Go

// go:generate mockgen -source ./gsb.go -destination mock_gsb_test.go -package va SafeBrowsing
package va
import (
safebrowsingv4 "github.com/google/safebrowsing"
"golang.org/x/net/context"
bgrpc "github.com/letsencrypt/boulder/grpc"
vaPB "github.com/letsencrypt/boulder/va/proto"
)
// SafeBrowsing is an interface for a third-party safe browsing API client.
type SafeBrowsing interface {
// IsListed returns a non-empty string if the domain was bad. Specifically,
// it is which Google Safe Browsing list the domain was found on.
IsListed(ctx context.Context, url string) (list string, err error)
}
// SafeBrowsingV4 is an interface around the functions from Google
// safebrowsing's v4 API's *SafeBrowser type that we use. Using this interface
// allows mocking for tests
type SafeBrowsingV4 interface {
LookupURLsContext(ctx context.Context, urls []string) (threats [][]safebrowsingv4.URLThreat, err error)
}
// IsSafeDomain returns true if the domain given is determined to be safe by a
// third-party safe browsing API. It's meant be called by the RA before pending
// authorization creation. If no third-party client was provided, it fails open
// and increments a Skips metric.
func (va *ValidationAuthorityImpl) IsSafeDomain(ctx context.Context, req *vaPB.IsSafeDomainRequest) (*vaPB.IsDomainSafe, error) {
if req == nil || req.Domain == nil {
return nil, bgrpc.ErrMissingParameters
}
stats := va.stats.NewScope("IsSafeDomain")
stats.Inc("IsSafeDomain.Requests", 1)
if va.safeBrowsing == nil {
stats.Inc("IsSafeDomain.Skips", 1)
status := true
return &vaPB.IsDomainSafe{IsSafe: &status}, nil
}
var status bool
list, err := va.safeBrowsing.IsListed(ctx, *req.Domain)
if err != nil {
stats.Inc("IsSafeDomain.Errors", 1)
// In the event of an error checking the GSB status we allow the domain in
// question to be treated as safe to avoid coupling the availability of the
// VA to the GSB API. This is acceptable for Let's Encrypt because we do not
// have a hard commitment to GSB filtering in our CP/CPS.
status = true
} else {
stats.Inc("IsSafeDomain.Successes", 1)
status = (list == "")
if status {
stats.Inc("IsSafeDomain.Status.Good", 1)
} else {
stats.Inc("IsSafeDomain.Status.Bad", 1)
}
}
return &vaPB.IsDomainSafe{IsSafe: &status}, nil
}