Installation
Copy
go get github.com/oathnet/oathnet-go
Quick Start
Copy
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
Copy
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
Breach Search
Copy
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
Copy
// 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)
V2 Stealer Search
Copy
// 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
Copy
// 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")
File Search
Search within stealer log files using regex or wildcard patterns.Copy
// 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.Copy
// 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
Copy
// 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
Copy
// 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
Copy
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
Copy
// 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
Copy
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),
)