Last active
August 3, 2025 13:15
-
-
Save pyt0xic/95c6a511755e6652f05eea868f600d31 to your computer and use it in GitHub Desktop.
Revisions
-
pyt0xic created this gist
Aug 3, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,512 @@ package main import ( "bytes" "encoding/json" "fmt" "io" "log" "net/http" "os" "strconv" "time" "github.com/joho/godotenv" ) const ( refragAPIEndpoint = "https://api.refrag.gg/auth/sign_in" refragStartServerEndpoint = "https://api.refrag.gg/cs_servers/start_new_server" refragRunningServersEndpoint = "https://api.refrag.gg/cs_servers/running" refragOrigin = "https://play.refrag.gg" outputFilename = "refrag_login_data.json" ) // LoginRequest represents the login request payload type LoginRequest struct { Email string `json:"email"` Password string `json:"password"` Remember bool `json:"remember"` } // LoginResponse represents the API response data type LoginResponse struct { Data struct { Email string `json:"email"` Provider string `json:"provider"` UID string `json:"uid"` MatchAuthToken string `json:"match_auth_token"` ID int `json:"id"` AllowPasswordChange bool `json:"allow_password_change"` Name any `json:"name"` Nickname any `json:"nickname"` Image any `json:"image"` TeamID any `json:"team_id"` SteamID string `json:"steam_id"` IsBetaTester any `json:"is_beta_tester"` HasScrimAccess bool `json:"has_scrim_access"` AdminAccess bool `json:"admin_access"` CustomProAccess bool `json:"custom_pro_access"` WarmupKillCount int `json:"warmup_kill_count"` EmailSignUp bool `json:"email_sign_up"` ServerSettings []ServerSettings `json:"server_settings"` CustomCompetitor any `json:"custom_competitor"` CustomPlayer any `json:"custom_player"` CustomTeam any `json:"custom_team"` FaceitNickname string `json:"faceit_nickname"` UUID string `json:"uuid"` Username any `json:"username"` DiscordID any `json:"discord_id"` DiscordTag any `json:"discord_tag"` ReceiveEmailForNotifications bool `json:"receive_email_for_notifications"` ReceiveEmailForAccessCodes bool `json:"receive_email_for_access_codes"` OnboardedStepsCompleted int `json:"onboarded_steps_completed"` SashID int `json:"sash_id"` Level int `json:"level"` FaceitPlayerID any `json:"faceit_player_id"` CommunityMod bool `json:"community_mod"` SteamProfileJSON SteamProfile `json:"steam_profile_json"` // Other fields omitted for brevity } `json:"data"` } type ServerSettings struct { Modules []Module `json:"modules"` ModName string `json:"mod_name"` } type Module struct { Module string `json:"module"` Settings string `json:"settings"` } type SteamProfile struct { Avatar string `json:"avatar"` GameID string `json:"gameid"` SteamID string `json:"steamid"` Realname string `json:"realname"` Avatarfull string `json:"avatarfull"` Avatarhash string `json:"avatarhash"` Profileurl string `json:"profileurl"` Personaname string `json:"personaname"` Timecreated int `json:"timecreated"` Avatarmedium string `json:"avatarmedium"` Lobbysteamid string `json:"lobbysteamid"` Personastate int `json:"personastate"` Profilestate int `json:"profilestate"` Gameextrainfo string `json:"gameextrainfo"` Primaryclanid string `json:"primaryclanid"` Loccountrycode string `json:"loccountrycode"` Commentpermission int `json:"commentpermission"` Personastateflags int `json:"personastateflags"` Communityvisibilitystate int `json:"communityvisibilitystate"` } // AuthHeaders holds the authentication headers received from the API type AuthHeaders struct { AccessToken string `json:"access_token"` Authorization string `json:"authorization"` Client string `json:"client"` Expiry string `json:"expiry"` UID string `json:"uid"` } // SavedData represents the complete data structure to save to file type SavedData struct { Response LoginResponse `json:"response"` Headers AuthHeaders `json:"headers"` } // StartServerRequest represents the payload for starting a new server type StartServerRequest struct { ServerLocationID int `json:"server_location_id"` Game string `json:"game"` BetaServer bool `json:"betaServer"` SecureServer bool `json:"secureServer"` IsAssessment bool `json:"is_assessment"` LaunchSettings LaunchSettings `json:"launch_settings"` } type LaunchSettings struct { Mod string `json:"mod"` Map string `json:"map"` } // ServerResponse represents a server in the API responses type ServerResponse struct { ID int `json:"id"` IP string `json:"ip"` Port int `json:"port"` Status string `json:"status"` Password string `json:"password"` VACSecure bool `json:"vac_secure"` ActiveMap string `json:"active_map"` ActiveMod string `json:"active_mod"` ConnectedPlayers any `json:"connected_players"` IsAssessment bool `json:"is_assessment"` Game string `json:"game"` RawIP string `json:"raw_ip"` IsScrim bool `json:"is_scrim"` ServerLocation string `json:"server_location"` StartedBy User `json:"started_by"` Team Team `json:"team"` } type User struct { ID int `json:"id"` SteamProfile SteamProfile `json:"steam_profile"` } type Team struct { Name string `json:"name"` ID int `json:"id"` } func main() { fmt.Println("Logging in to refrag.gg...") // Load credentials from env vars or .env file email, password, err := loadCredentials() if err != nil { log.Fatal(err) } // Log in to the API response, headers, err := loginToRefrag(email, password) if err != nil { log.Fatal("Login failed: ", err) } // Save the data to file if err := saveLoginResponseData(response, headers); err != nil { log.Fatal("Failed to save response data: ", err) } // Print success message with auth headers printLoginSuccess(headers) // Load server parameters from environment variables mapName, mod, locationID, err := loadServerParameters() if err != nil { log.Fatal(err) } // Start a new server server, err := StartServer(headers, locationID, "cs2", mod, mapName) if err != nil { log.Fatal("Failed to start server: ", err) } fmt.Printf("Server started! Connect: %s:%d (Password: %s)\n", server.IP, server.Port, server.Password) // Loop until password is available maxAttempts := 30 // Avoid infinite loops time.Sleep(3 * time.Second) for i := 0; i < maxAttempts; i++ { // Sleep for 3 seconds at the start of each iteration fmt.Printf("Waiting for 3 seconds (attempt %d/%d)...\n", i+1, maxAttempts) time.Sleep(3 * time.Second) // Get running servers servers, err := GetRunningServers(headers) if err != nil { log.Printf("Failed to get running servers: %v. Retrying...", err) continue } fmt.Printf("Running Servers (%d):\n", len(servers)) // Look for our server var foundServer bool for _, srv := range servers { fmt.Printf(" %s:%d - %s on %s (Status: %s, Password: %s)\n", srv.IP, srv.Port, srv.ActiveMod, srv.ActiveMap, srv.Status, srv.Password) // If this is our server and password is available if srv.ID == server.ID && srv.Password != "" && srv.Status == "online" { fmt.Printf("\nServer is ready! Connect: %s:%d (Password: %s)\n", srv.IP, srv.Port, srv.Password) fmt.Printf("\nconnect %s:%d; password %s\n", srv.IP, srv.Port, srv.Password) return } } if !foundServer { fmt.Println("Our server is not in the list. It might be still starting up...") } else { fmt.Println("Server found but password not yet available.") } } fmt.Println("Maximum attempts reached. Please check server status manually.") } // loadCredentials loads REFRAG_EMAIL and REFRAG_PASSWORD from environment or .env file func loadCredentials() (email, password string, err error) { // Load .env file if it exists if err := godotenv.Load(); err != nil { fmt.Println("No .env file found, using environment variables directly") } // Get credentials from environment variables email = os.Getenv("REFRAG_EMAIL") password = os.Getenv("REFRAG_PASSWORD") if email == "" || password == "" { return "", "", fmt.Errorf("REFRAG_EMAIL and REFRAG_PASSWORD environment variables must be set") } return email, password, nil } // loadServerParameters loads REFRAG_MAP, REFRAG_MOD, and REFRAG_LOCATION_ID from environment variables func loadServerParameters() (mapName, mod string, locationID int, err error) { mapName = os.Getenv("REFRAG_MAP") mod = os.Getenv("REFRAG_MOD") locationIDStr := os.Getenv("REFRAG_LOCATION_ID") if mapName == "" { mapName = "de_ancient" // Default map } if mod == "" { mod = "retakes" // Default mod } if locationIDStr == "" { locationID = 16 // Default location ID (change as needed) } else { locationID, err = strconv.Atoi(locationIDStr) if err != nil { return "", "", 0, fmt.Errorf("invalid REFRAG_LOCATION_ID: %w", err) } } return mapName, mod, locationID, nil } // loginToRefrag attempts to login to the Refrag API and returns the response and auth headers func loginToRefrag(email, password string) (*LoginResponse, *AuthHeaders, error) { // Create login request payload loginData := LoginRequest{ Email: email, Password: password, Remember: false, } // Convert to JSON jsonData, err := json.Marshal(loginData) if err != nil { return nil, nil, fmt.Errorf("failed to marshal JSON: %w", err) } // Create and configure the HTTP request req, err := http.NewRequest(http.MethodPost, refragAPIEndpoint, bytes.NewBuffer(jsonData)) if err != nil { return nil, nil, fmt.Errorf("failed to create request: %w", err) } // Set headers setLoginRequestHeaders(req) // Send the request client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() // Read the response body body, err := io.ReadAll(resp.Body) if err != nil { return nil, nil, fmt.Errorf("failed to read response: %w", err) } // Parse the JSON response var loginResponse LoginResponse err = json.Unmarshal(body, &loginResponse) if err != nil { return nil, nil, fmt.Errorf("failed to parse JSON response: %w", err) } // Extract authentication headers headers := &AuthHeaders{ AccessToken: resp.Header.Get("access-token"), Authorization: resp.Header.Get("authorization"), Client: resp.Header.Get("client"), Expiry: resp.Header.Get("expiry"), UID: resp.Header.Get("uid"), } return &loginResponse, headers, nil } // setLoginRequestHeaders adds all required headers to the HTTP request func setLoginRequestHeaders(req *http.Request) { req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0") req.Header.Set("Accept", "application/json, text/plain, */*") req.Header.Set("Accept-Language", "en-US,en;q=0.5") req.Header.Set("Content-Type", "application/json") req.Header.Set("Origin", refragOrigin) req.Header.Set("DNT", "1") req.Header.Set("Connection", "keep-alive") req.Header.Set("Referer", refragOrigin+"/") req.Header.Set("Sec-Fetch-Dest", "empty") req.Header.Set("Sec-Fetch-Mode", "cors") req.Header.Set("Sec-Fetch-Site", "same-site") req.Header.Set("Priority", "u=0") req.Header.Set("TE", "trailers") } // saveLoginResponseData saves the login response and headers to a JSON file func saveLoginResponseData(response *LoginResponse, headers *AuthHeaders) error { savedData := SavedData{ Response: *response, Headers: *headers, } // Convert to JSON for storage outputJSON, err := json.MarshalIndent(savedData, "", " ") if err != nil { return fmt.Errorf("failed to create output JSON: %w", err) } // Save to file err = os.WriteFile(outputFilename, outputJSON, 0644) if err != nil { return fmt.Errorf("failed to write to file: %w", err) } return nil } // printLoginSuccess prints the successful login information func printLoginSuccess(headers *AuthHeaders) { fmt.Println("Login successful!") fmt.Println("Access Token:", headers.AccessToken) fmt.Println("Authorization:", headers.Authorization) fmt.Println("Client:", headers.Client) fmt.Println("Expiry:", headers.Expiry) fmt.Println("UID:", headers.UID) fmt.Println("Response data saved to", outputFilename) } // StartServer starts a new server with the given parameters func StartServer(auth *AuthHeaders, locationID int, game string, mod string, mapName string) (*ServerResponse, error) { fmt.Println("Starting a new server...") // Create server request payload requestData := StartServerRequest{ ServerLocationID: locationID, Game: game, BetaServer: false, SecureServer: false, IsAssessment: false, LaunchSettings: LaunchSettings{ Mod: mod, Map: mapName, }, } // Convert to JSON jsonData, err := json.Marshal(requestData) if err != nil { return nil, fmt.Errorf("failed to marshal JSON: %w", err) } // Create and configure the HTTP request req, err := http.NewRequest(http.MethodPost, refragStartServerEndpoint, bytes.NewBuffer(jsonData)) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } // Set headers setRefragRequestHeaders(req, auth) req.Header.Set("X-GAME", game) req.Header.Set("X-TEAM-ID", "272803") // This could be made dynamic if needed // Send the request client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() // Read the response body body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } // Parse the JSON response var serverResponse ServerResponse err = json.Unmarshal(body, &serverResponse) if err != nil { return nil, fmt.Errorf("failed to parse JSON response: %w", err) } return &serverResponse, nil } // GetRunningServers retrieves all currently running servers func GetRunningServers(auth *AuthHeaders) ([]ServerResponse, error) { fmt.Println("Getting running servers...") // Create and configure the HTTP request req, err := http.NewRequest(http.MethodGet, refragRunningServersEndpoint, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } // Set headers setRefragRequestHeaders(req, auth) req.Header.Set("X-GAME", "cs2") req.Header.Set("X-TEAM-ID", "272803") // This could be made dynamic if needed // Send the request client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } defer resp.Body.Close() // Read the response body body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("failed to read response: %w", err) } // Parse the JSON response var servers []ServerResponse err = json.Unmarshal(body, &servers) if err != nil { return nil, fmt.Errorf("failed to parse JSON response: %w", err) } return servers, nil } // setRefragRequestHeaders sets the necessary authentication headers for Refrag API requests func setRefragRequestHeaders(req *http.Request, auth *AuthHeaders) { req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0") req.Header.Set("Accept", "application/json, text/plain, */*") req.Header.Set("Accept-Language", "en-US,en;q=0.5") req.Header.Set("Content-Type", "application/json") req.Header.Set("Origin", refragOrigin) req.Header.Set("DNT", "1") req.Header.Set("Connection", "keep-alive") req.Header.Set("Referer", refragOrigin+"/") req.Header.Set("Sec-Fetch-Dest", "empty") req.Header.Set("Sec-Fetch-Mode", "cors") req.Header.Set("Sec-Fetch-Site", "same-site") req.Header.Set("Priority", "u=0") req.Header.Set("TE", "trailers") // Authentication headers req.Header.Set("Token-Type", "Bearer") req.Header.Set("Access-Token", auth.AccessToken) req.Header.Set("Client", auth.Client) req.Header.Set("Uid", auth.UID) req.Header.Set("Expiry", auth.Expiry) }