Skip to main content

Installation

go get github.com/oathnet/oathnet-go
Requirements: Go 1.21+

Quick Start

package main

import (
    "context"
    "fmt"
    "log"
    "github.com/oathnet/oathnet-go/pkg/oathnet"
)

func main() {
    // Initialize client with API key (required)
    client, err := oathnet.NewClient("your-api-key")
    if err != nil {
        log.Fatal(err)
    }

    // Search breaches
    ctx := context.Background()
    result, err := client.Search.Breach(ctx, "[email protected]", nil)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("Found %d results\n", result.Data.ResultsFound)
    for _, record := range result.Data.Results {
        fmt.Printf("%s: %s\n", record.Email, record.Password)
    }
}

Authentication

import "github.com/oathnet/oathnet-go/pkg/oathnet"

// Explicit API key (required)
client, err := oathnet.NewClient("your-api-key")

// With options
client, err := oathnet.NewClient("your-api-key",
    oathnet.WithBaseURL("https://oathnet.org/api"),
    oathnet.WithTimeout(30 * time.Second),
)

Search Service

ctx := context.Background()

// Basic search
result, err := client.Search.Breach(ctx, "[email protected]", nil)
if err != nil {
    log.Fatal(err)
}

// With options
opts := &oathnet.BreachSearchOptions{
    DBNames: "linkedin_2012,adobe_2013",
}
result, err := client.Search.Breach(ctx, "[email protected]", opts)

// Access results
fmt.Printf("Total: %d\n", result.Data.ResultsFound)
fmt.Printf("Shown: %d\n", result.Data.ResultsShown)

for _, record := range result.Data.Results {
    fmt.Printf("Email: %s\n", record.Email)
    fmt.Printf("Password: %s\n", record.Password)
    fmt.Printf("Database: %s\n", record.DBName)
}

// Pagination
if result.Data.Cursor != "" {
    nextOpts := &oathnet.BreachSearchOptions{
        Cursor: result.Data.Cursor,
    }
    nextPage, _ := client.Search.Breach(ctx, "[email protected]", nextOpts)
}

Initialize Session

// Create a search session for quota optimization
result, err := client.Search.InitSession(ctx, "[email protected]")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Session ID: %s\n", result.Data.Session.ID)
fmt.Printf("Search Type: %s\n", result.Data.Session.SearchType)
fmt.Printf("Expires: %s\n", result.Data.Session.ExpiresAt)
// Basic search
result, err := client.Stealer.Search(ctx, "[email protected]", nil)

// Advanced filtering
opts := &oathnet.StealerSearchOptions{
    Domains:   []string{"google.com", "facebook.com"},
    HasLogID:  true,
    PageSize:  50,
}
result, err := client.Stealer.Search(ctx, "[email protected]", opts)

// Access items
for _, item := range result.Data.Items {
    fmt.Printf("URL: %s\n", item.URL)
    fmt.Printf("Username: %s\n", item.Username)
    fmt.Printf("Password: %s\n", item.Password)
    fmt.Printf("Log ID: %s\n", item.LogID)
}

// Pagination
if result.Data.NextCursor != "" {
    nextOpts := &oathnet.StealerSearchOptions{
        Cursor: result.Data.NextCursor,
    }
    nextPage, _ := client.Stealer.Search(ctx, "[email protected]", nextOpts)
}

// Subdomain extraction
subResult, err := client.Stealer.Subdomain(ctx, "example.com", nil)
fmt.Printf("Found %d subdomains\n", subResult.Data.Count)
for _, sub := range subResult.Data.Subdomains {
    fmt.Printf("  %s\n", sub)
}

Victims

// Search victims
result, err := client.Victims.Search(ctx, "[email protected]", nil)

for _, victim := range result.Data.Items {
    fmt.Printf("Log ID: %s\n", victim.LogID)
    fmt.Printf("Users: %v\n", victim.DeviceUsers)
    fmt.Printf("Documents: %d\n", victim.TotalDocs)
}

// Get manifest
manifest, err := client.Victims.GetManifest(ctx, "log_id_here")
fmt.Printf("Total Files: %d\n", manifest.Data.TotalFiles)
fmt.Printf("Total Size: %d bytes\n", manifest.Data.TotalSize)

for _, file := range manifest.Data.Files[:10] {
    fmt.Printf("  %s (%d bytes)\n", file.RelativePath, file.Size)
}

// Get file content
file, err := client.Victims.GetFile(ctx, "log_id", "file_id")
fmt.Println(file.Data.Content)

// Download archive
err = client.Victims.DownloadArchive(ctx, "log_id", "./victim_archive.zip")
Search within stealer log files using regex or wildcard patterns.
// Create a file search job
result, err := client.FileSearch.Create(ctx, "password", &oathnet.FileSearchOptions{
    LogIDs:     []string{"log_id_1", "log_id_2"},
    SearchMode: "literal",  // literal, regex, or wildcard
})
jobID := result.Data.JobID
fmt.Printf("Job ID: %s\n", jobID)

// Check job status
status, err := client.FileSearch.GetStatus(ctx, jobID)
fmt.Printf("Status: %s\n", status.Data.Status)
if status.Data.Summary != nil {
    fmt.Printf("Files scanned: %d\n", status.Data.Summary.FilesScanned)
    fmt.Printf("Matches: %d\n", status.Data.Summary.Matches)
}

// Wait for completion and get results
searchResult, err := client.FileSearch.Search(ctx, "password", &oathnet.FileSearchOptions{
    LogIDs:     []string{"log_id_1", "log_id_2"},
    SearchMode: "literal",
}, 300*time.Second)

for _, match := range searchResult.Data.Matches {
    fmt.Printf("File: %s\n", match.FileName)
    fmt.Printf("Log ID: %s\n", match.LogID)
    fmt.Printf("Match: %s\n", match.MatchText)
}

Exports

Export large datasets asynchronously.
// Create an export job
result, err := client.Exports.Create(ctx, "stealer", &oathnet.ExportOptions{
    Limit:  100,      // minimum 100
    Format: "jsonl",  // jsonl or csv
})
jobID := result.Data.JobID
fmt.Printf("Export Job ID: %s\n", jobID)

// Check export status
status, err := client.Exports.GetStatus(ctx, jobID)
fmt.Printf("Status: %s\n", status.Data.Status)
if status.Data.Progress != nil {
    fmt.Printf("Progress: %.1f%%\n", status.Data.Progress.Percent)
}

// Wait for completion
completed, err := client.Exports.WaitForCompletion(ctx, jobID, 600*time.Second)
if completed.Data.Status == "completed" {
    // Download the export file
    err = client.Exports.Download(ctx, jobID, "./export.jsonl")
}

OSINT Lookups

// IP Info
ipInfo, err := client.OSINT.IPInfo(ctx, "8.8.8.8")
fmt.Printf("Location: %s, %s\n", ipInfo.Data.City, ipInfo.Data.Country)
fmt.Printf("ISP: %s\n", ipInfo.Data.ISP)
fmt.Printf("Proxy: %v\n", ipInfo.Data.Proxy)

// Steam
steam, err := client.OSINT.Steam(ctx, "76561198012345678")
fmt.Printf("Username: %s\n", steam.Data.Username)
fmt.Printf("Avatar: %s\n", steam.Data.Avatar)

// Xbox
xbox, err := client.OSINT.Xbox(ctx, "GamerTag123")
fmt.Printf("Username: %s\n", xbox.Data.Username)
fmt.Printf("Avatar: %s\n", xbox.Data.Avatar)

// Discord User Info
discord, err := client.OSINT.DiscordUserinfo(ctx, "123456789012345678")
fmt.Printf("Username: %s\n", discord.Data.Username)
fmt.Printf("Global Name: %s\n", discord.Data.GlobalName)
fmt.Printf("Created: %s\n", discord.Data.CreationDate)

// Discord Username History
history, err := client.OSINT.DiscordUsernameHistory(ctx, "123456789012345678")
for _, entry := range history.Data.History {
    if len(entry.Name) > 0 && len(entry.Time) > 0 {
        fmt.Printf("%s at %s\n", entry.Name[0], entry.Time[0])
    }
}

// Discord to Roblox
robloxLink, err := client.OSINT.DiscordToRoblox(ctx, "123456789012345678")
if robloxLink.Data.RobloxID != "" {
    fmt.Printf("Linked Roblox: %s\n", robloxLink.Data.RobloxID)
}

// Roblox User Info
roblox, err := client.OSINT.RobloxUserinfo(ctx, &oathnet.RobloxOptions{
    UserID: "123456789",
})
// Or by username:
roblox2, _ := client.OSINT.RobloxUserinfo(ctx, &oathnet.RobloxOptions{
    Username: "PlayerName",
})
fmt.Printf("Username: %s\n", roblox.Data.Username)
fmt.Printf("Display Name: %s\n", roblox.Data.DisplayName)

// Holehe - Email account detection
holehe, err := client.OSINT.Holehe(ctx, "[email protected]")
fmt.Printf("Found on %d services:\n", len(holehe.Data.Domains))
for _, domain := range holehe.Data.Domains {
    fmt.Printf("  %s\n", domain)
}

// GHunt - Google account lookup
ghunt, err := client.OSINT.GHunt(ctx, "[email protected]")
if ghunt.Data.Found {
    fmt.Printf("Name: %s\n", ghunt.Data.Profile.Name)
}

// Subdomain extraction
subdomains, err := client.OSINT.ExtractSubdomain(ctx, "example.com", true)
for _, sub := range subdomains.Data.Subdomains {
    fmt.Println(sub)
}

// Minecraft username history
mc, err := client.OSINT.MinecraftHistory(ctx, "PlayerName")
for _, entry := range mc.Data.History {
    fmt.Printf("%s - %s\n", entry.Username, entry.ChangedAt)
}

Utility Service

// Database name autocomplete
result, err := client.Utility.DBNameAutocomplete(ctx, "link")
for _, name := range result.Data {
    fmt.Println(name)  // linkedin_2012, linkedin_2021, etc.
}

Error Handling

import "github.com/oathnet/oathnet-go/pkg/oathnet"

result, err := client.Search.Breach(ctx, "[email protected]", nil)
if err != nil {
    switch e := err.(type) {
    case *oathnet.AuthenticationError:
        fmt.Println("Invalid API key")
    case *oathnet.QuotaExceededError:
        fmt.Println("Daily quota exceeded")
    case *oathnet.RateLimitError:
        fmt.Printf("Rate limited. Retry after %d seconds\n", e.RetryAfter)
    case *oathnet.NotFoundError:
        fmt.Println("Resource not found")
    case *oathnet.ValidationError:
        fmt.Printf("Invalid input: %s\n", e.Message)
    case *oathnet.OathNetError:
        fmt.Printf("API error: %s\n", e.Message)
    default:
        fmt.Printf("Unknown error: %v\n", err)
    }
    return
}

Context Support

// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()

result, err := client.Search.Breach(ctx, "[email protected]", nil)

// With cancellation
ctx, cancel := context.WithCancel(context.Background())

go func() {
    time.Sleep(5 * time.Second)
    cancel()  // Cancel after 5 seconds
}()

result, err := client.Search.Breach(ctx, "[email protected]", nil)
if err == context.Canceled {
    fmt.Println("Request was cancelled")
}

Configuration Options

import (
    "time"
    "github.com/oathnet/oathnet-go/pkg/oathnet"
)

client, err := oathnet.NewClient("your-api-key",
    oathnet.WithBaseURL("https://oathnet.org/api"),
    oathnet.WithTimeout(60 * time.Second),
)