xposedornot

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2026 License: MIT Imports: 13 Imported by: 0

README

XposedOrNot

xposedornot-go

Official Go SDK for the XposedOrNot API
Check if your email or password has been exposed in data breaches

Go Reference Go Version


Note: This SDK uses the free public API from XposedOrNot.com - a free service to check if your email has been compromised in data breaches. A Plus API with enhanced features is available with an API key. Visit the XposedOrNot website to learn more.


Table of Contents


Features

  • Simple API - Idiomatic Go client with functional options pattern
  • Context Support - All methods accept context.Context for cancellation and timeouts
  • Free and Plus APIs - Use the free API or unlock detailed results with an API key
  • Detailed Analytics - Get breach details, risk scores, metrics, and paste exposures
  • Error Handling - Typed error values compatible with errors.As
  • Password Privacy - Passwords are hashed locally; only a short prefix is sent (k-anonymity)
  • Rate Limiting - Built-in client-side rate limiting with automatic retry on 429 responses
  • Secure - HTTPS enforced on all base URLs by default

Installation

go get github.com/XposedOrNot/XposedOrNot-Go

Requirements

  • Go 1.21 or higher

Quick Start

package main

import (
	"context"
	"fmt"
	"log"

	xon "github.com/XposedOrNot/XposedOrNot-Go"
)

func main() {
	client, err := xon.NewClient()
	if err != nil {
		log.Fatal(err)
	}

	// Check if an email has been breached
	free, _, err := client.CheckEmail(context.Background(), "test@example.com")
	if err != nil {
		log.Fatal(err)
	}

	if len(free.Breaches) > 0 {
		fmt.Printf("Email found in %d breaches:\n", len(free.Breaches))
		for _, b := range free.Breaches {
			fmt.Printf("  - %s\n", b)
		}
	} else {
		fmt.Println("Good news! Email not found in any known breaches.")
	}
}

API Reference

Constructor

client, err := xon.NewClient(opts ...xon.ClientOption)

Create a new client with functional options. See Configuration Options for all available options.

Methods

CheckEmail(ctx, email)

Check if an email address has been exposed in any data breaches. Returns the free API response or the Plus API response depending on whether an API key is configured.

// Free API (no API key)
free, _, err := client.CheckEmail(ctx, "user@example.com")
if err != nil {
	log.Fatal(err)
}
fmt.Println("Breaches:", free.Breaches)
// Plus API (with API key)
client, _ := xon.NewClient(xon.WithAPIKey("your-api-key"))

_, plus, err := client.CheckEmail(ctx, "user@example.com")
if err != nil {
	log.Fatal(err)
}
for _, b := range plus.Breaches {
	fmt.Printf("Breach: %s, Date: %s, Records: %d\n",
		b.BreachID, b.BreachedDate, b.XposedRecords)
}

Signature:

func (c *Client) CheckEmail(ctx context.Context, email string) (*CheckEmailFreeResponse, *CheckEmailPlusResponse, error)
Return Value Type Description
free *CheckEmailFreeResponse Populated when no API key is set (Plus response is nil)
plus *CheckEmailPlusResponse Populated when an API key is set (Free response is nil)
err error Non-nil on validation failure, network error, or API error

GetBreaches(ctx, domain)

Retrieve a list of all known data breaches. Pass a non-empty domain string to filter results by domain.

// Get all breaches
all, err := client.GetBreaches(ctx, "")
if err != nil {
	log.Fatal(err)
}
fmt.Println("Total known breaches:", len(all.ExposedBreaches))

// Filter by domain
adobe, err := client.GetBreaches(ctx, "adobe.com")
if err != nil {
	log.Fatal(err)
}
fmt.Println("Adobe breaches:", len(adobe.ExposedBreaches))

Signature:

func (c *Client) GetBreaches(ctx context.Context, domain string) (*GetBreachesResponse, error)
Parameter Type Description
ctx context.Context Context for cancellation and timeouts
domain string Filter by domain (pass "" for all breaches)

Returns: *GetBreachesResponse containing a slice of ExposedBreach with fields including BreachID, BreachedDate, Domain, Industry, ExposedData, ExposedRecords, and Verified.


BreachAnalytics(ctx, email)

Get detailed breach analytics for an email address, including breach details, summary statistics, metrics breakdowns, and paste exposures.

analytics, err := client.BreachAnalytics(ctx, "user@example.com")
if err != nil {
	log.Fatal(err)
}

fmt.Println("Breach details:", len(analytics.ExposedBreaches.BreachesDetails))
fmt.Println("Site:", analytics.BreachesSummary.Site)
fmt.Println("Total breaches:", analytics.BreachesSummary.TotalBreaches)
fmt.Println("Most recent:", analytics.BreachesSummary.MostRecentBreach)

Signature:

func (c *Client) BreachAnalytics(ctx context.Context, email string) (*BreachAnalyticsResponse, error)
Parameter Type Description
ctx context.Context Context for cancellation and timeouts
email string Email address to analyze

Returns: *BreachAnalyticsResponse with the following fields:

Field Type Description
ExposedBreaches ExposedBreachesWrapper Detailed list of each breach
BreachesSummary BreachesSummary Summary stats (total breaches, date range, risk)
BreachMetrics BreachMetrics Breakdowns by industry, password strength, year, and data type
PastesSummary PasteSummary Paste exposure summary
ExposedPastes []interface{} Raw paste exposure entries

CheckPassword(ctx, password)

Check whether a password has appeared in known data breaches. The password is hashed locally using Keccak-512 and only the first 10 characters of the hex digest are sent to the API. This k-anonymity approach ensures the full password never leaves your machine.

resp, err := client.CheckPassword(ctx, "password123")
if err != nil {
	log.Fatal(err)
}

if resp.SearchPassAnon.Count != "0" {
	fmt.Printf("Password has been exposed %s time(s)\n", resp.SearchPassAnon.Count)
} else {
	fmt.Println("Password not found in known breaches")
}

Signature:

func (c *Client) CheckPassword(ctx context.Context, password string) (*CheckPasswordResponse, error)
Parameter Type Description
ctx context.Context Context for cancellation and timeouts
password string The plaintext password to check (hashed locally before sending)

Error Handling

All errors returned by the client are typed. Use errors.As to check for specific error conditions:

import "errors"

free, _, err := client.CheckEmail(ctx, "test@example.com")
if err != nil {
	var notFound *xon.ErrNotFound
	var validationErr *xon.ErrValidation
	var rateLimitErr *xon.ErrRateLimit
	var authErr *xon.ErrAuthentication
	var networkErr *xon.ErrNetwork
	var apiErr *xon.ErrAPI

	switch {
	case errors.As(err, &notFound):
		fmt.Println("Email not found in any breaches")
	case errors.As(err, &validationErr):
		fmt.Printf("Invalid input: %s\n", validationErr.Message)
	case errors.As(err, &rateLimitErr):
		fmt.Println("Rate limit exceeded, try again later")
	case errors.As(err, &authErr):
		fmt.Println("Invalid API key")
	case errors.As(err, &networkErr):
		fmt.Printf("Network error: %v\n", networkErr.Unwrap())
	case errors.As(err, &apiErr):
		fmt.Printf("API error (status %d): %s\n", apiErr.StatusCode, apiErr.Body)
	default:
		fmt.Printf("Unexpected error: %v\n", err)
	}
}

Error Types

Error Type Description
*ErrValidation Invalid input (e.g., malformed email address)
*ErrNotFound Requested resource not found (HTTP 404)
*ErrRateLimit API rate limit exceeded after all retries (HTTP 429)
*ErrAuthentication Missing or invalid API key (HTTP 401/403)
*ErrNetwork Network-level failure (DNS, connection, timeout)
*ErrAPI Unexpected API error with status code and body

Rate Limits

Free API Plus API (with API key)
Client-side limiting 1 request per second (automatic) None
Server-side limiting Standard limits apply Higher limits
429 retry behavior Exponential backoff (1s, 2s, 4s) Exponential backoff (1s, 2s, 4s)

The client automatically retries on HTTP 429 responses with exponential backoff, up to the configured maximum retries (default: 3).

Configuration Options

All options are passed to NewClient as functional options:

client, err := xon.NewClient(
	xon.WithAPIKey("your-api-key"),
	xon.WithTimeout(15 * time.Second),
	xon.WithMaxRetries(5),
)
Option Default Description
WithAPIKey(key) "" Set API key for Plus API access
WithTimeout(d) 30s HTTP client timeout
WithBaseURL(url) https://api.xposedornot.com Override the free API base URL
WithPlusBaseURL(url) https://plus-api.xposedornot.com Override the Plus API base URL
WithPasswordBaseURL(url) https://passwords.xposedornot.com/api Override the password API base URL
WithMaxRetries(n) 3 Maximum retries on HTTP 429 responses
WithCustomHeaders(h) nil Additional headers included in every request
WithAllowInsecure() false Disable HTTPS enforcement (testing only)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Development Setup

# Clone the repository
git clone https://github.com/XposedOrNot/XposedOrNot-Go.git
cd XposedOrNot-Go

# Run tests
go test ./...

# Run tests with coverage
go test -cover ./...

# Run tests with race detector
go test -race ./...

# Vet
go vet ./...

License

MIT - see the LICENSE file for details.


Made with care by XposedOrNot

Documentation

Overview

Package xposedornot provides a Go client for the XposedOrNot API, which allows checking whether email addresses and passwords have been exposed in known data breaches.

The client supports both the free API and the commercial Plus API. Use NewClient with functional options to configure the client:

// Free API usage
client, err := xposedornot.NewClient()
if err != nil {
    log.Fatal(err)
}

// Plus API usage with API key
client, err := xposedornot.NewClient(
    xposedornot.WithAPIKey("your-api-key"),
    xposedornot.WithTimeout(30 * time.Second),
)
if err != nil {
    log.Fatal(err)
}

All methods accept a context.Context for cancellation and timeout control.

The free API is rate-limited to 1 request per second on the client side. Plus API users with an API key bypass this rate limit.

The client automatically retries on HTTP 429 (Too Many Requests) responses with exponential backoff (1s, 2s, 4s) up to 3 retries by default.

Error handling uses typed errors that can be checked with errors.Is and errors.As:

_, _, err := client.CheckEmail(ctx, "test@example.com")
var notFound *xposedornot.ErrNotFound
if errors.As(err, &notFound) {
    // email not found in any breaches
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BreachAnalyticsResponse

type BreachAnalyticsResponse struct {
	ExposedBreaches ExposedBreachesWrapper `json:"ExposedBreaches"`
	BreachesSummary BreachesSummary        `json:"BreachesSummary"`
	BreachMetrics   BreachMetrics          `json:"BreachMetrics"`
	PastesSummary   PasteSummary           `json:"PastesSummary"`
	ExposedPastes   []interface{}          `json:"ExposedPastes"`
}

BreachAnalyticsResponse is the response from the breach-analytics endpoint.

type BreachDetail

type BreachDetail struct {
	Breach        string `json:"breach"`
	Details       string `json:"details"`
	Domain        string `json:"domain"`
	Industry      string `json:"industry"`
	PasswordRisk  string `json:"password_risk"`
	References    string `json:"references"`
	Searchable    string `json:"searchable"`
	Verified      string `json:"verified"`
	XposedData    string `json:"xposed_data"`
	XposedDate    string `json:"xposed_date"`
	XposedRecords int    `json:"xposed_records"`
}

BreachDetail represents a single breach detail in breach analytics.

type BreachMetrics

type BreachMetrics struct {
	Industry         []interface{} `json:"industry"`
	PasswordStrength []interface{} `json:"passwords_strength"`
	YearlyBreaches   []interface{} `json:"yearwise_details"`
	XposedData       []interface{} `json:"xposed_data"`
}

BreachMetrics contains metrics derived from breach analytics.

type BreachesSummary

type BreachesSummary struct {
	Site             string `json:"site"`
	TotalBreaches    string `json:"total_breaches,omitempty"`
	MostRecentBreach string `json:"most_recent_breach,omitempty"`
	FirstBreach      string `json:"first_breach,omitempty"`
	ExposedData      string `json:"exposed_data,omitempty"`
	PasswordRisk     string `json:"password_risk,omitempty"`
}

BreachesSummary contains summary information about an email's breaches.

type CheckEmailFreeResponse

type CheckEmailFreeResponse struct {
	Breaches [][]string `json:"breaches"`
}

CheckEmailFreeResponse is the response from the free check-email endpoint.

type CheckEmailPlusResponse

type CheckEmailPlusResponse struct {
	Status   string       `json:"status"`
	Email    string       `json:"email"`
	Breaches []PlusBreach `json:"breaches"`
}

CheckEmailPlusResponse is the response from the Plus API check-email endpoint.

type CheckPasswordResponse

type CheckPasswordResponse struct {
	SearchPassAnon PasswordAnonResult `json:"SearchPassAnon"`
}

CheckPasswordResponse is the response from the password check endpoint.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is an API client for the XposedOrNot service.

func NewClient

func NewClient(opts ...ClientOption) (*Client, error)

NewClient creates a new XposedOrNot API client with the given options. It returns an error if any base URL does not use HTTPS, unless WithAllowInsecure() is set.

func (*Client) BreachAnalytics

func (c *Client) BreachAnalytics(ctx context.Context, email string) (*BreachAnalyticsResponse, error)

BreachAnalytics retrieves detailed breach analytics for the given email address, including breach details, summary, metrics, and paste information.

func (*Client) CheckEmail

CheckEmail checks whether the given email address has been exposed in any known data breaches. If the client has an API key configured, it uses the Plus API and returns a detailed response; otherwise it uses the free API.

For the free API, only CheckEmailFreeResponse is populated (second return value is nil). For the Plus API, only CheckEmailPlusResponse is populated (first return value is nil).

func (*Client) CheckPassword

func (c *Client) CheckPassword(ctx context.Context, password string) (*CheckPasswordResponse, error)

CheckPassword checks whether the given password has been exposed in known data breaches. The password is hashed locally using the original Keccak-512 algorithm, and only the first 10 characters of the hex digest are sent to the API, preserving privacy through k-anonymity.

func (*Client) GetBreaches

func (c *Client) GetBreaches(ctx context.Context, domain string) (*GetBreachesResponse, error)

GetBreaches retrieves a list of known data breaches. If domain is non-empty, results are filtered to breaches affecting that domain.

type ClientOption

type ClientOption func(*Client)

ClientOption is a functional option for configuring the Client.

func WithAPIKey

func WithAPIKey(key string) ClientOption

WithAPIKey sets the API key for the Plus API. When set, requests to the Plus API include the x-api-key header and client-side rate limiting is disabled.

func WithAllowInsecure

func WithAllowInsecure() ClientOption

WithAllowInsecure disables the HTTPS enforcement check on base URLs. This is intended for testing purposes only.

func WithBaseURL

func WithBaseURL(url string) ClientOption

WithBaseURL overrides the default free API base URL.

func WithCustomHeaders

func WithCustomHeaders(headers map[string]string) ClientOption

WithCustomHeaders sets additional headers to include in every request.

func WithMaxRetries

func WithMaxRetries(n int) ClientOption

WithMaxRetries sets the maximum number of retries on 429 responses. Default is 3.

func WithPasswordBaseURL

func WithPasswordBaseURL(url string) ClientOption

WithPasswordBaseURL overrides the default password API base URL.

func WithPlusBaseURL

func WithPlusBaseURL(url string) ClientOption

WithPlusBaseURL overrides the default Plus API base URL.

func WithTimeout

func WithTimeout(d time.Duration) ClientOption

WithTimeout sets the HTTP client timeout.

type ErrAPI

type ErrAPI struct {
	StatusCode int
	Body       string
}

ErrAPI is returned when the API returns an unexpected error response that does not map to a more specific error type.

func (*ErrAPI) Error

func (e *ErrAPI) Error() string

type ErrAuthentication

type ErrAuthentication struct {
	Message string
}

ErrAuthentication is returned when the API returns a 401 or 403 response, typically due to a missing or invalid API key.

func (*ErrAuthentication) Error

func (e *ErrAuthentication) Error() string

type ErrNetwork

type ErrNetwork struct {
	Err error
}

ErrNetwork is returned when a network-level error occurs, such as a connection timeout or DNS resolution failure.

func (*ErrNetwork) Error

func (e *ErrNetwork) Error() string

func (*ErrNetwork) Unwrap

func (e *ErrNetwork) Unwrap() error

type ErrNotFound

type ErrNotFound struct {
	Resource string
}

ErrNotFound is returned when the requested resource is not found (404).

func (*ErrNotFound) Error

func (e *ErrNotFound) Error() string

type ErrRateLimit

type ErrRateLimit struct {
	Message string
}

ErrRateLimit is returned when the API returns a 429 Too Many Requests response after all retries have been exhausted.

func (*ErrRateLimit) Error

func (e *ErrRateLimit) Error() string

type ErrValidation

type ErrValidation struct {
	Field   string
	Message string
}

ErrValidation is returned when input validation fails on the client side, such as an invalid email address format.

func (*ErrValidation) Error

func (e *ErrValidation) Error() string

type ExposedBreach

type ExposedBreach struct {
	BreachID       string   `json:"breachID"`
	BreachedDate   string   `json:"breachedDate"`
	Domain         string   `json:"domain"`
	Industry       string   `json:"industry"`
	ExposedData    []string `json:"exposedData"`
	ExposedRecords int      `json:"exposedRecords"`
	Verified       bool     `json:"verified"`
	References     string   `json:"references"`
	Details        string   `json:"details"`
	PasswordRisk   string   `json:"password_risk"`
}

ExposedBreach represents a single breach from the breaches listing endpoint.

type ExposedBreachesWrapper

type ExposedBreachesWrapper struct {
	BreachesDetails []BreachDetail `json:"breaches_details"`
}

ExposedBreachesWrapper wraps breach details in the analytics response.

type GetBreachesResponse

type GetBreachesResponse struct {
	ExposedBreaches []ExposedBreach `json:"exposedBreaches"`
}

GetBreachesResponse is the response from the breaches listing endpoint.

type PasswordAnonResult

type PasswordAnonResult struct {
	Anon  string `json:"anon"`
	Char  string `json:"char"`
	Count string `json:"count"`
}

PasswordAnonResult contains the anonymized password check result.

type PasteSummary

type PasteSummary struct {
	Count     int    `json:"cnt"`
	Domain    string `json:"domain"`
	FirstSeen string `json:"first_seen,omitempty"`
	LastSeen  string `json:"last_seen,omitempty"`
}

PasteSummary contains paste-related summary information.

type PlusBreach

type PlusBreach struct {
	BreachID      string `json:"breach_id"`
	BreachedDate  string `json:"breached_date"`
	PasswordRisk  string `json:"password_risk"`
	Searchable    string `json:"searchable"`
	XposedData    string `json:"xposed_data"`
	XposedRecords int    `json:"xposed_records"`
	XposureDesc   string `json:"xposure_desc"`
	Domain        string `json:"domain"`
}

PlusBreach represents a single breach entry from the Plus API.

Directories

Path Synopsis
examples
basic command
plus_api command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL