Initial sanitized code sync
This commit is contained in:
323
config/config.go
Normal file
323
config/config.go
Normal file
@@ -0,0 +1,323 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Proxy ProxyConfig `yaml:"proxy"`
|
||||
Email EmailConfig `yaml:"email"`
|
||||
Card CardConfig `yaml:"card"`
|
||||
Stripe StripeConfig `yaml:"stripe"`
|
||||
Captcha CaptchaConfig `yaml:"captcha"`
|
||||
Account AccountConfig `yaml:"account"`
|
||||
Team TeamConfig `yaml:"team"`
|
||||
Output OutputConfig `yaml:"output"`
|
||||
Batch BatchConfig `yaml:"batch"`
|
||||
}
|
||||
|
||||
type BatchConfig struct {
|
||||
Count int `yaml:"count"` // number of accounts to create (0 = auto-detect from card codes)
|
||||
}
|
||||
|
||||
type CaptchaConfig struct {
|
||||
Provider string `yaml:"provider"` // "hcaptchasolver"
|
||||
APIKey string `yaml:"api_key"`
|
||||
Proxy string `yaml:"proxy"` // fixed HTTP proxy for captcha solver
|
||||
}
|
||||
|
||||
type ProxyConfig struct {
|
||||
URL string `yaml:"url"`
|
||||
B2Proxy B2ProxyConfig `yaml:"b2proxy"`
|
||||
}
|
||||
|
||||
type B2ProxyConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
APIBase string `yaml:"api_base"` // e.g. http://global.rrp.b2proxy.com:8089
|
||||
Zone string `yaml:"zone"` // e.g. "custom"
|
||||
PType int `yaml:"ptype"` // e.g. 1
|
||||
Proto string `yaml:"proto"` // "socks5" or "http"
|
||||
SessTime int `yaml:"sess_time"` // sticky session minutes, default 5
|
||||
}
|
||||
|
||||
type EmailConfig struct {
|
||||
Provider string `yaml:"provider"`
|
||||
MailGateway MailGatewayConfig `yaml:"mailgateway"`
|
||||
Outlook OutlookEmailConfig `yaml:"outlook"`
|
||||
}
|
||||
|
||||
type OutlookEmailConfig struct {
|
||||
AccountsFile string `yaml:"accounts_file"` // path to file with email----password----client_id----refresh_token
|
||||
POP3Server string `yaml:"pop3_server"` // default: outlook.office365.com
|
||||
POP3Port int `yaml:"pop3_port"` // default: 995
|
||||
}
|
||||
|
||||
type MailGatewayConfig struct {
|
||||
BaseURL string `yaml:"base_url"`
|
||||
APIKey string `yaml:"api_key"`
|
||||
Provider string `yaml:"provider"` // e.g. "gptmail"
|
||||
}
|
||||
|
||||
type CardConfig struct {
|
||||
Provider string `yaml:"provider"` // "static", "file", "api"
|
||||
Static StaticCardConfig `yaml:"static"`
|
||||
File FileCardConfig `yaml:"file"`
|
||||
API APICardConfig `yaml:"api"`
|
||||
Pool CardPoolConfig `yaml:"pool"`
|
||||
}
|
||||
|
||||
type StaticCardConfig struct {
|
||||
Cards []CardEntry `yaml:"cards"`
|
||||
}
|
||||
|
||||
type FileCardConfig struct {
|
||||
Path string `yaml:"path"` // path to card TXT file
|
||||
DefaultCountry string `yaml:"default_country"` // default country code e.g. JP
|
||||
DefaultCurrency string `yaml:"default_currency"` // default currency e.g. JPY
|
||||
}
|
||||
|
||||
type APICardConfig struct {
|
||||
BaseURL string `yaml:"base_url"` // e.g. https://yyl.ncet.top
|
||||
Codes []string `yaml:"codes"` // redeem codes list
|
||||
CodesFile string `yaml:"codes_file"` // or path to file with one code per line
|
||||
DefaultName string `yaml:"default_name"` // default cardholder name
|
||||
DefaultCountry string `yaml:"default_country"` // default country code e.g. US
|
||||
DefaultCurrency string `yaml:"default_currency"` // default currency e.g. USD
|
||||
DefaultAddress string `yaml:"default_address"` // default billing address
|
||||
DefaultCity string `yaml:"default_city"` // default billing city
|
||||
DefaultState string `yaml:"default_state"` // default billing state
|
||||
DefaultPostalCode string `yaml:"default_postal_code"` // default billing ZIP code
|
||||
}
|
||||
|
||||
type CardEntry struct {
|
||||
Number string `yaml:"number"`
|
||||
ExpMonth string `yaml:"exp_month"`
|
||||
ExpYear string `yaml:"exp_year"`
|
||||
CVC string `yaml:"cvc"`
|
||||
Name string `yaml:"name"`
|
||||
Country string `yaml:"country"`
|
||||
Currency string `yaml:"currency"`
|
||||
Address string `yaml:"address"`
|
||||
City string `yaml:"city"`
|
||||
State string `yaml:"state"`
|
||||
PostalCode string `yaml:"postal_code"`
|
||||
}
|
||||
|
||||
type CardPoolConfig struct {
|
||||
TTLMinutes int `yaml:"ttl_minutes"` // card validity in minutes (default: 60)
|
||||
MultiBind bool `yaml:"multi_bind"` // allow reusing cards multiple times
|
||||
MaxBinds int `yaml:"max_binds"` // max uses per card (0 = unlimited when multi_bind=true)
|
||||
}
|
||||
|
||||
type StripeConfig struct {
|
||||
BuildHash string `yaml:"build_hash"`
|
||||
TagVersion string `yaml:"tag_version"`
|
||||
StripeVersion string `yaml:"stripe_version"`
|
||||
FingerprintDir string `yaml:"fingerprint_dir"` // directory with browser fingerprint JSON files
|
||||
Aimizy AimizyConfig `yaml:"aimizy"`
|
||||
}
|
||||
|
||||
type AimizyConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
BaseURL string `yaml:"base_url"` // default: https://team.aimizy.com
|
||||
}
|
||||
|
||||
type AccountConfig struct {
|
||||
PasswordLength int `yaml:"password_length"`
|
||||
Locale string `yaml:"locale"`
|
||||
}
|
||||
|
||||
type TeamConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
WorkspacePrefix string `yaml:"workspace_prefix"`
|
||||
SeatQuantity int `yaml:"seat_quantity"`
|
||||
Coupon string `yaml:"coupon"`
|
||||
InviteCount int `yaml:"invite_count"` // number of members to invite (0 = skip)
|
||||
}
|
||||
|
||||
type OutputConfig struct {
|
||||
Dir string `yaml:"dir"`
|
||||
}
|
||||
|
||||
// ExpectedCountry returns the country code associated with the current card configuration.
|
||||
// Falls back to "US" if no country is configured.
|
||||
func (c *CardConfig) ExpectedCountry() string {
|
||||
switch c.Provider {
|
||||
case "static", "":
|
||||
if len(c.Static.Cards) > 0 && c.Static.Cards[0].Country != "" {
|
||||
return c.Static.Cards[0].Country
|
||||
}
|
||||
case "api":
|
||||
if c.API.DefaultCountry != "" {
|
||||
return c.API.DefaultCountry
|
||||
}
|
||||
case "file":
|
||||
if c.File.DefaultCountry != "" {
|
||||
return c.File.DefaultCountry
|
||||
}
|
||||
}
|
||||
return "US"
|
||||
}
|
||||
|
||||
func Load(path string) (*Config, error) {
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read config file: %w", err)
|
||||
}
|
||||
|
||||
cfg := &Config{}
|
||||
if err := yaml.Unmarshal(data, cfg); err != nil {
|
||||
return nil, fmt.Errorf("parse config: %w", err)
|
||||
}
|
||||
|
||||
// Outlook email defaults (YAML-only provider)
|
||||
if cfg.Email.Outlook.POP3Server == "" {
|
||||
cfg.Email.Outlook.POP3Server = "outlook.office365.com"
|
||||
}
|
||||
if cfg.Email.Outlook.POP3Port == 0 {
|
||||
cfg.Email.Outlook.POP3Port = 995
|
||||
}
|
||||
|
||||
applyDefaults(cfg)
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// configRow mirrors internal/db.SystemConfig without importing internal/.
|
||||
type configRow struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// LoadFromDB builds a Config by reading the system_configs table.
|
||||
// It applies the same defaults as Load() for any missing values.
|
||||
func LoadFromDB(d *gorm.DB) (*Config, error) {
|
||||
var rows []configRow
|
||||
if err := d.Table("system_configs").Select("key, value").Find(&rows).Error; err != nil {
|
||||
return nil, fmt.Errorf("query configs: %w", err)
|
||||
}
|
||||
m := make(map[string]string, len(rows))
|
||||
for _, r := range rows {
|
||||
m[r.Key] = r.Value
|
||||
}
|
||||
|
||||
cfg := &Config{}
|
||||
|
||||
// Proxy
|
||||
cfg.Proxy.URL = m["proxy.url"]
|
||||
cfg.Proxy.B2Proxy.Enabled = m["proxy.b2proxy.enabled"] == "true"
|
||||
cfg.Proxy.B2Proxy.APIBase = m["proxy.b2proxy.api_base"]
|
||||
cfg.Proxy.B2Proxy.Zone = m["proxy.b2proxy.zone"]
|
||||
cfg.Proxy.B2Proxy.Proto = m["proxy.b2proxy.proto"]
|
||||
cfg.Proxy.B2Proxy.SessTime, _ = strconv.Atoi(m["proxy.b2proxy.sess_time"])
|
||||
|
||||
// Email
|
||||
cfg.Email.Provider = "mailgateway"
|
||||
cfg.Email.MailGateway.BaseURL = m["email.gateway.base_url"]
|
||||
cfg.Email.MailGateway.APIKey = m["email.gateway.api_key"]
|
||||
cfg.Email.MailGateway.Provider = m["email.gateway.provider"]
|
||||
|
||||
// Card — DB mode uses DBCardProvider, not static/file/api
|
||||
cfg.Card.Provider = "db"
|
||||
cfg.Card.API.BaseURL = m["card.api_base_url"]
|
||||
cfg.Card.API.DefaultName = m["card.default_name"]
|
||||
cfg.Card.API.DefaultCountry = m["card.default_country"]
|
||||
cfg.Card.API.DefaultCurrency = m["card.default_currency"]
|
||||
cfg.Card.API.DefaultAddress = m["card.default_address"]
|
||||
cfg.Card.API.DefaultCity = m["card.default_city"]
|
||||
cfg.Card.API.DefaultState = m["card.default_state"]
|
||||
cfg.Card.API.DefaultPostalCode = m["card.default_postal_code"]
|
||||
cfg.Card.Pool.MaxBinds, _ = strconv.Atoi(m["card.max_binds"])
|
||||
|
||||
// Stripe
|
||||
cfg.Stripe.BuildHash = m["stripe.build_hash"]
|
||||
cfg.Stripe.TagVersion = m["stripe.tag_version"]
|
||||
cfg.Stripe.FingerprintDir = m["stripe.fingerprint_dir"]
|
||||
|
||||
// Captcha
|
||||
cfg.Captcha.Provider = m["captcha.provider"]
|
||||
cfg.Captcha.APIKey = m["captcha.api_key"]
|
||||
cfg.Captcha.Proxy = m["captcha.proxy"]
|
||||
|
||||
// Account
|
||||
cfg.Account.PasswordLength, _ = strconv.Atoi(m["account.password_length"])
|
||||
cfg.Account.Locale = m["account.locale"]
|
||||
|
||||
// Team
|
||||
cfg.Team.Enabled = m["team.enabled"] == "true"
|
||||
cfg.Team.WorkspacePrefix = m["team.workspace_prefix"]
|
||||
cfg.Team.SeatQuantity, _ = strconv.Atoi(m["team.seat_quantity"])
|
||||
cfg.Team.Coupon = m["team.coupon"]
|
||||
cfg.Team.InviteCount, _ = strconv.Atoi(m["team.invite_count"])
|
||||
|
||||
// Output
|
||||
cfg.Output.Dir = "./output"
|
||||
|
||||
// Apply same defaults as Load()
|
||||
applyDefaults(cfg)
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func applyDefaults(cfg *Config) {
|
||||
if cfg.Stripe.BuildHash == "" {
|
||||
cfg.Stripe.BuildHash = "ede17ac9fd"
|
||||
}
|
||||
if cfg.Stripe.TagVersion == "" {
|
||||
cfg.Stripe.TagVersion = "4.5.43"
|
||||
}
|
||||
if cfg.Stripe.StripeVersion == "" {
|
||||
cfg.Stripe.StripeVersion = "2025-03-31.basil"
|
||||
}
|
||||
if cfg.Account.PasswordLength == 0 {
|
||||
cfg.Account.PasswordLength = 16
|
||||
}
|
||||
if cfg.Account.Locale == "" {
|
||||
cfg.Account.Locale = "en-GB"
|
||||
}
|
||||
if cfg.Team.WorkspacePrefix == "" {
|
||||
cfg.Team.WorkspacePrefix = "Team"
|
||||
}
|
||||
if cfg.Team.SeatQuantity == 0 {
|
||||
cfg.Team.SeatQuantity = 5
|
||||
}
|
||||
if cfg.Team.Coupon == "" {
|
||||
cfg.Team.Coupon = "team-1-month-free"
|
||||
}
|
||||
if cfg.Output.Dir == "" {
|
||||
cfg.Output.Dir = "./output"
|
||||
}
|
||||
if cfg.Email.MailGateway.Provider == "" {
|
||||
cfg.Email.MailGateway.Provider = "gptmail"
|
||||
}
|
||||
if cfg.Captcha.Provider == "" {
|
||||
cfg.Captcha.Provider = "hcaptchasolver"
|
||||
}
|
||||
if cfg.Stripe.FingerprintDir == "" {
|
||||
cfg.Stripe.FingerprintDir = "./fingerprints"
|
||||
}
|
||||
if cfg.Proxy.B2Proxy.APIBase == "" {
|
||||
cfg.Proxy.B2Proxy.APIBase = "http://global.rrp.b2proxy.com:8089"
|
||||
}
|
||||
if cfg.Proxy.B2Proxy.Zone == "" {
|
||||
cfg.Proxy.B2Proxy.Zone = "custom"
|
||||
}
|
||||
if cfg.Proxy.B2Proxy.PType == 0 {
|
||||
cfg.Proxy.B2Proxy.PType = 1
|
||||
}
|
||||
if cfg.Proxy.B2Proxy.Proto == "" {
|
||||
cfg.Proxy.B2Proxy.Proto = "socks5"
|
||||
}
|
||||
if cfg.Proxy.B2Proxy.SessTime == 0 {
|
||||
cfg.Proxy.B2Proxy.SessTime = 5
|
||||
}
|
||||
if cfg.Stripe.Aimizy.BaseURL == "" {
|
||||
cfg.Stripe.Aimizy.BaseURL = "https://team.aimizy.com"
|
||||
}
|
||||
if cfg.Card.Pool.MaxBinds == 0 {
|
||||
cfg.Card.Pool.MaxBinds = 1
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user