Documentation
¶
Overview ¶
Package internetdata is the official Go client library for the InternetData API: licensed IP and network datasets, downloaded as CSV.GZ or MMDB.
Start with New and Client.Database.List. Every database published today is licensed, so pass WithAPIKey a key carrying the db.download scope; the option is optional because what this API serves without one is a product decision rather than the client's to refuse.
Index ¶
- Constants
- Variables
- type AuthorizationURLOptions
- type Checksums
- type Client
- type Database
- type DatabaseAPI
- func (d *DatabaseAPI) Checksums(ctx context.Context, id string, format Format) (*Checksums, error)
- func (d *DatabaseAPI) Download(ctx context.Context, id string, format Format, dst io.Writer) (int64, error)
- func (d *DatabaseAPI) DownloadBytes(ctx context.Context, id string, format Format) ([]byte, error)
- func (d *DatabaseAPI) DownloadFile(ctx context.Context, id string, format Format, path string) (int64, error)
- func (d *DatabaseAPI) DownloadURL(ctx context.Context, id string, format Format) (string, error)
- func (d *DatabaseAPI) Downloads(ctx context.Context, limit int) ([]DownloadAttempt, error)
- func (d *DatabaseAPI) List(ctx context.Context) ([]Database, error)
- func (d *DatabaseAPI) Metadata(ctx context.Context, id string) (*DatabaseMetadata, error)
- type DatabaseMetadata
- type DatabaseMetadataColumn
- type DatabaseVersion
- type Date
- type DeviceAuthorization
- type DeviceAuthorizationOptions
- type DownloadAttempt
- type DownloadOutcome
- type Error
- type ErrorKind
- type Format
- type LicenseType
- type OauthAPI
- func (o *OauthAPI) AuthorizationURL(clientID, redirectURI, codeChallenge string, opts AuthorizationURLOptions) (string, error)
- func (o *OauthAPI) CreatePkce() Pkce
- func (o *OauthAPI) DeviceAuthorization(ctx context.Context, clientID string, opts DeviceAuthorizationOptions) (*DeviceAuthorization, error)
- func (o *OauthAPI) ExchangeAuthorizationCode(ctx context.Context, clientID, code, codeVerifier, redirectURI string) (*TokenResponse, error)
- func (o *OauthAPI) ExchangeDeviceCode(ctx context.Context, clientID, deviceCode string) (*TokenResponse, error)
- func (o *OauthAPI) ExchangeRefreshToken(ctx context.Context, clientID, refreshToken string) (*TokenResponse, error)
- func (o *OauthAPI) Metadata(ctx context.Context) (*OauthMetadata, error)
- func (o *OauthAPI) PkceChallenge(verifier string) string
- func (o *OauthAPI) PollDeviceToken(ctx context.Context, clientID string, device *DeviceAuthorization) (*TokenResponse, error)
- func (o *OauthAPI) Revoke(ctx context.Context, clientID, token string) error
- type OauthError
- type OauthMetadata
- type Option
- type Pkce
- type Standing
- type TokenResponse
Constants ¶
const ( StandingLicensed = api.StandingLicensed StandingExpired = api.StandingExpired StandingUnlicensed = api.StandingUnlicensed )
Standing tells you whether a database is yours today, was, or has never been bought.
const ( LicenseTypeEvaluation = api.Evaluation LicenseTypeStandard = api.Standard LicenseTypeRedistribute = api.Redistribute )
LicenseType is nil rather than one of these when there is no license at all, so read the pointer before comparing it.
const ( DownloadOutcomeOK = api.DownloadOutcomeOk DownloadOutcomeDenied = api.DownloadOutcomeDenied DownloadOutcomeExpired = api.DownloadOutcomeExpired DownloadOutcomeUnknown = api.DownloadOutcomeUnknown )
const DefaultBaseURL = "https://internetdata.io"
DefaultBaseURL is the production API. Override it with WithBaseURL.
Variables ¶
var ( ErrOauthAccessDenied = errors.New("internetdata: the person denied the sign-in") ErrOauthExpiredToken = errors.New("internetdata: the sign-in code expired") )
The two refusals a device sign-in ends on, matched with errors.Is against what an OauthAPI call returns.
Functions ¶
This section is empty.
Types ¶
type AuthorizationURLOptions ¶ added in v2.5.0
type AuthorizationURLOptions struct {
// Scope is one space-delimited string, sent as given. The server narrows it
// to what the client may ask for.
Scope string
// State comes back on the redirect unchanged, so the caller can tell the
// answer is to its own request.
State string
// Resource is the API the tokens are meant for.
Resource string
}
AuthorizationURLOptions is what an authorization URL asks for beyond what every one carries. An empty field is left out of the URL.
type Checksums ¶
type Checksums struct {
MD5 string `json:"md5"`
SHA1 string `json:"sha1"`
SHA256 string `json:"sha256"`
SHA512 string `json:"sha512"`
}
Checksums are the digests of one published file.
Spelled out rather than aliased to the generated struct, whose Md5 and Sha256 are not the names a Go caller expects, and which every other InternetData and VPNDetection SDK writes the same way.
type Client ¶
type Client struct {
// Database is the licensed database catalog and its downloads. Every
// database call hangs off it rather than off the client, which is how the
// VPNDetection SDKs read too, so one program holding both clients spells the
// two the same way.
Database *DatabaseAPI
// Oauth is the device sign-in, which hands a program one of a person's API
// keys. Its requests never carry this client's key.
Oauth *OauthAPI
}
Client is a client for the InternetData API. It is safe for concurrent use.
Nothing it answers is cached. What your organization may see depends on the key, so a listing held from one client is not an answer for another, and a catalog is small enough that re-reading it costs less than being wrong about whose it was.
type Database ¶
Database is one database FAMILY, with your organization's license beside it. LicenseType, Starts and Expires are nil when there is no license.
type DatabaseAPI ¶
type DatabaseAPI struct {
// contains filtered or unexported fields
}
DatabaseAPI is the licensed database catalog and its downloads, reached through Client.Database.
Spelled DatabaseAPI rather than Database because Database is already this API's own shape for one database family, and it is what the other InternetData SDKs call this type.
func (*DatabaseAPI) Checksums ¶
Checksums are the digests of one published file, for verifying a download. All four the exporter writes are returned, because which of them a caller wants is not this library's decision.
func (*DatabaseAPI) Download ¶
func (d *DatabaseAPI) Download( ctx context.Context, id string, format Format, dst io.Writer, ) (int64, error)
Download streams one database file into dst and returns the bytes written.
Nothing beyond a single chunk is ever held in memory, whatever the file weighs. The transfer takes its deadline from ctx rather than from the HTTP client's Timeout, which would cap the whole body: 30 seconds is a sane bound on a catalog read and the wrong one on a gigabyte.
A failure DURING the transfer is returned as it happened rather than wrapped in an *Error: a reset socket and a full disk are different problems, and only one of them is ours.
func (*DatabaseAPI) DownloadBytes ¶
DownloadBytes downloads one database file and hands back its bytes.
This holds the ENTIRE file in memory, and the catalog spans five orders of magnitude, from bogon_asn_v1 at a few hundred bytes to the largest IP feeds at several gigabytes. Metadata publishes a Size per format; read it first, or use Download or DownloadFile for anything you have not measured.
func (*DatabaseAPI) DownloadFile ¶
func (d *DatabaseAPI) DownloadFile( ctx context.Context, id string, format Format, path string, ) (int64, error)
DownloadFile writes one database file to path and returns the bytes written.
The bytes land in a neighboring .part file that is renamed on completion, so a transfer that dies half way leaves no truncated file that reads as a whole database, and a failed refresh cannot destroy the copy already there. Otherwise identical to Download.
func (*DatabaseAPI) DownloadURL ¶
DownloadURL is the time-limited URL for one database file.
The API answers 302 to object storage and the redirect is NOT followed: the URL is returned so a caller can decide how to transfer a file that runs to gigabytes, hand it to a downloader, or pass it on without passing on the API key. The link is presigned and so authorizes itself; it authorizes the START of a transfer, so one already running is not interrupted when it lapses.
func (*DatabaseAPI) Downloads ¶
func (d *DatabaseAPI) Downloads(ctx context.Context, limit int) ([]DownloadAttempt, error)
Downloads is your organization's recent download attempts, newest first. A limit of zero or less takes the API's own default of 50, and it is clamped to 200.
Refusals are listed too: a denial is what answers "it stopped working", and its absence answers nothing.
func (*DatabaseAPI) List ¶
func (d *DatabaseAPI) List(ctx context.Context) ([]Database, error)
List is the published catalog, with your organization's license beside each family. A license covers a family, while a download names one of its versions, so the ids the download and checksum calls take come from Database.Versions.
This is the server's answer for this key, so a listing held from one key is not an answer for another.
func (*DatabaseAPI) Metadata ¶
func (d *DatabaseAPI) Metadata(ctx context.Context, id string) (*DatabaseMetadata, error)
Metadata is what is inside one database: its columns per format, sample rows, the row count and the byte size of each file. It carries Updated and Entries without downloading anything, so poll it to decide whether today's build is worth fetching, and read Size to budget a transfer before starting one.
One document describes every format the database is built in, which is why there is no format argument.
type DatabaseMetadata ¶
type DatabaseMetadata = api.DatabaseMetadata
DatabaseMetadata is the build document the exporter writes, served through unchanged.
type DatabaseMetadataColumn ¶
type DatabaseMetadataColumn = api.DatabaseMetadataColumn
DatabaseMetadataColumn is one column of one format's schema.
type DatabaseVersion ¶
type DatabaseVersion = api.DatabaseVersion
DatabaseVersion is one published version of a family. Its ID is what the download, checksum and metadata calls take. Old versions are frozen rather than migrated, so both stay downloadable.
type DeviceAuthorization ¶ added in v2.3.0
type DeviceAuthorization struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURI string `json:"verification_uri"`
VerificationURIComplete *string `json:"verification_uri_complete,omitempty"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval"`
}
DeviceAuthorization is a started device sign-in. ExpiresIn and Interval are seconds.
type DeviceAuthorizationOptions ¶ added in v2.3.0
type DeviceAuthorizationOptions struct {
// Scope is one space-delimited string, sent as given. The server narrows it
// to what the client may ask for.
Scope string
// Resource is the API the tokens are meant for.
Resource string
}
DeviceAuthorizationOptions narrows a device sign-in. An empty field is left out of the request rather than sent empty.
type DownloadAttempt ¶
DownloadAttempt is one entry of the download history, refusals included. Bytes is the object size at redirect time rather than bytes delivered: the transfer runs straight from object storage, so how much of it was taken is not observed.
type DownloadOutcome ¶
type DownloadOutcome = api.DownloadOutcome
DownloadOutcome is how one download attempt ended.
type Error ¶
type Error struct {
Kind ErrorKind
// Message is the API's own result code, or a transport failure's text. The
// codes are deliberately not an enum on the wire, so one added later stays
// readable to a client built today.
Message string
// StatusCode is the HTTP status, or 0 when no response was received.
StatusCode int
// RetryAfter is how long the server asked us to wait. Zero when it did not
// ask, which on a 429 means an allowance is spent rather than throttled.
RetryAfter time.Duration
// contains filtered or unexported fields
}
Error is what every failure from this package unwraps to. Recover it with errors.As and branch on Kind.
type ErrorKind ¶
type ErrorKind string
ErrorKind says why a request failed.
KindRateLimited and KindQuotaExceeded both arrive as HTTP 429 and are NOT the same thing. A rate limit is the API protecting itself, carries Retry-After, and retrying works. A spent quota carries no such header and retrying will not help until the window rolls over or the limit is raised. The header is the only thing that distinguishes them.
type Format ¶
type Format string
Format is a format a database is published in. Not every one is built in every format: the _provider catalogs are keyed by provider id rather than by IP range, so no MMDB exists for them, and asking for one is an error rather than an empty answer. DatabaseVersion.Formats says which exist.
func (Format) Valid ¶ added in v2.1.0
Valid reports whether f is a format the API publishes.
Format is a defined string type, so Format("zip") compiles: the constants above document the vocabulary without closing it. Callers taking a format from a flag, a config file or a model should check it here.
type LicenseType ¶
type LicenseType = api.DatabaseLicenseType
LicenseType is what a license permits you to do with the data.
type OauthAPI ¶ added in v2.3.0
type OauthAPI struct {
// contains filtered or unexported fields
}
OauthAPI signs a person in on their own machine with the OAuth device flow, so a program can be handed one of their API keys instead of asking them to paste it, or through a browser redirect with the authorization code flow. Reached through Client.Oauth.
Every call takes a client ID, which is issued on request from support@internetdata.io. None of these requests carries the client's API key, and none needs one.
func (*OauthAPI) AuthorizationURL ¶ added in v2.5.0
func (o *OauthAPI) AuthorizationURL( clientID, redirectURI, codeChallenge string, opts AuthorizationURLOptions, ) (string, error)
AuthorizationURL is the URL to open in the person's browser for the authorization code flow. It makes no request. Once they decide, the server redirects to redirectURI with a code for ExchangeAuthorizationCode (and the state, when one was given), or with an error.
A required value that is empty or not UTF-8 is refused with a bad_request *Error.
func (*OauthAPI) CreatePkce ¶ added in v2.5.0
CreatePkce makes a fresh PKCE pair for one sign-in, from 32 bytes of the system's secure random source.
func (*OauthAPI) DeviceAuthorization ¶ added in v2.3.0
func (o *OauthAPI) DeviceAuthorization( ctx context.Context, clientID string, opts DeviceAuthorizationOptions, ) (*DeviceAuthorization, error)
DeviceAuthorization starts a device sign-in: show the person UserCode and VerificationURI, then hand the answer to PollDeviceToken. It consumes nothing, so it is retried like any read; a refusal such as slow_down comes back as an *OauthError.
func (*OauthAPI) ExchangeAuthorizationCode ¶ added in v2.5.0
func (o *OauthAPI) ExchangeAuthorizationCode( ctx context.Context, clientID, code, codeVerifier, redirectURI string, ) (*TokenResponse, error)
ExchangeAuthorizationCode trades the code a sign-in's redirect brought back for tokens. codeVerifier is the PKCE verifier whose challenge went into the authorization URL, and redirectURI that URL's, exactly.
Never retried: the server spends the code on first read, before it checks the verifier, so a retry could only be refused.
func (*OauthAPI) ExchangeDeviceCode ¶ added in v2.3.0
func (o *OauthAPI) ExchangeDeviceCode(ctx context.Context, clientID, deviceCode string) (*TokenResponse, error)
ExchangeDeviceCode asks once whether the person has approved a device sign-in. Until they do the answer is an *OauthError coded authorization_pending; PollDeviceToken is the loop around it.
Never retried: an approved code is spent by the answer that carries the tokens, so a retry after a lost response could only lose them.
func (*OauthAPI) ExchangeRefreshToken ¶ added in v2.3.0
func (o *OauthAPI) ExchangeRefreshToken( ctx context.Context, clientID, refreshToken string, ) (*TokenResponse, error)
ExchangeRefreshToken trades a refresh token for a new pair. The old one is spent whatever happens next, so this is never retried. A refresh names the API key the person picked (ApikeyID) but never reveals it again (Apikey).
func (*OauthAPI) Metadata ¶ added in v2.3.0
func (o *OauthAPI) Metadata(ctx context.Context) (*OauthMetadata, error)
Metadata is the authorization server's discovery document. Nothing else here needs it: every request is built from the client's base URL.
func (*OauthAPI) PkceChallenge ¶ added in v2.5.0
PkceChallenge is the S256 challenge for a PKCE verifier: its SHA-256, as unpadded base64url.
func (*OauthAPI) PollDeviceToken ¶ added in v2.3.0
func (o *OauthAPI) PollDeviceToken( ctx context.Context, clientID string, device *DeviceAuthorization, ) (*TokenResponse, error)
PollDeviceToken waits for the person to approve a device sign-in and returns its tokens.
It waits device.Interval seconds (5 when that is below 1) before EVERY request, the first included, and adds 5 more for the rest of the call each time the server answers slow_down. No wait runs past device.ExpiresIn, counted from this call: one that would ends at it, with no request after. It stops at the first answer that is neither pending nor slow_down: a denial satisfies errors.Is(err, ErrOauthAccessDenied), an expired code errors.Is(err, ErrOauthExpiredToken), and so does running out of device.ExpiresIn, with a StatusCode of 0. Canceling ctx stops the wait and any request in flight.
type OauthError ¶ added in v2.3.0
type OauthError struct {
// ErrorCode is the server's code, such as authorization_pending or
// invalid_grant. A code this library has never seen is kept as sent.
ErrorCode string
// ErrorDescription is the server's explanation, or empty when it sent none.
ErrorDescription string
// StatusCode is the HTTP status, or 0 when the refusal was reached locally:
// PollDeviceToken running past the code's lifetime.
StatusCode int
}
OauthError is the authorization server refusing a request: a 4xx whose body names an OAuth error code. It is never worth retrying as it stands.
errors.As to *Error also works, through Unwrap, with a Kind that follows the status; a 401 here means an unregistered client ID, never the API key.
func (*OauthError) Error ¶ added in v2.3.0
func (e *OauthError) Error() string
func (*OauthError) Is ¶ added in v2.3.0
func (e *OauthError) Is(target error) bool
Is answers errors.Is for ErrOauthAccessDenied and ErrOauthExpiredToken.
func (*OauthError) Unwrap ¶ added in v2.3.0
func (e *OauthError) Unwrap() error
Unwrap is the same refusal as an *Error, whose Kind follows the status and is bad_request when the refusal was local.
type OauthMetadata ¶ added in v2.3.0
type OauthMetadata struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
DeviceAuthorizationEndpoint *string `json:"device_authorization_endpoint,omitempty"`
RevocationEndpoint *string `json:"revocation_endpoint,omitempty"`
ScopesSupported *[]string `json:"scopes_supported,omitempty"`
ResponseTypesSupported *[]string `json:"response_types_supported,omitempty"`
GrantTypesSupported *[]string `json:"grant_types_supported,omitempty"`
CodeChallengeMethodsSupported *[]string `json:"code_challenge_methods_supported,omitempty"`
TokenEndpointAuthMethodsSupported *[]string `json:"token_endpoint_auth_methods_supported,omitempty"`
AuthorizationResponseIssParameterSupported *bool `json:"authorization_response_iss_parameter_supported,omitempty"`
ClientIDMetadataDocumentSupported *bool `json:"client_id_metadata_document_supported,omitempty"`
ServiceDocumentation *string `json:"service_documentation,omitempty"`
}
OauthMetadata is the authorization server's discovery document. An optional member the server did not send is nil.
type Option ¶
type Option func(*config) error
Option configures a Client.
func WithAPIKey ¶
WithAPIKey authenticates as the key's organization, which is what decides which databases are listed at all and which of them may be downloaded.
The key comes from the console and needs the db.download scope. Keys are default-deny, so an existing key does not reach these endpoints until the scope is added to it.
func WithBaseURL ¶
WithBaseURL points the client at a different deployment of the API.
func WithHTTPClient ¶
WithHTTPClient supplies the HTTP client to send with, for a custom transport, proxy or timeout. Without it the SDK uses a client with a 30 second timeout.
The client is copied rather than mutated, and the copy adds a CheckRedirect that defers to yours (see DatabaseAPI.DownloadURL). A dataset transfer runs on a second copy with Timeout cleared, and is bounded by its context instead.
func WithRetries ¶
WithRetries sets how many further attempts a transient failure gets. Default 2.
type Pkce ¶ added in v2.5.0
type Pkce struct {
// Verifier is 32 random bytes as 43 characters of unpadded base64url.
Verifier string
// Challenge is the verifier's SHA-256, as unpadded base64url.
Challenge string
// Method is always S256, the only method the server accepts.
Method string
}
Pkce is one sign-in's PKCE pair: Challenge goes in the authorization URL, Verifier to ExchangeAuthorizationCode.
type TokenResponse ¶ added in v2.3.0
type TokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken *string `json:"refresh_token,omitempty"`
Scope *string `json:"scope,omitempty"`
ApikeyID *string `json:"mslm:apikey_id,omitempty"`
Apikey *string `json:"mslm:apikey,omitempty"`
}
TokenResponse is what a completed sign-in or a refresh hands back.
ApikeyID is set when the person picked one of their API keys and may still reveal it. Apikey, the key itself, additionally needs a sign-in rather than a refresh and a key whose secret can be read back, so ApikeyID without Apikey is normal. An empty Scope is present, not nil.