diff options
Diffstat (limited to 'g4f/Provider/npm/node_modules/funcaptcha')
30 files changed, 3011 insertions, 0 deletions
diff --git a/g4f/Provider/npm/node_modules/funcaptcha/LICENSE b/g4f/Provider/npm/node_modules/funcaptcha/LICENSE new file mode 100644 index 00000000..0e80dc9d --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/LICENSE @@ -0,0 +1,43 @@ +Copyright (c) 2023 noahcoolboy + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject +to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +"Commons Clause" License Condition v1.0 + +The Software is provided to you by the Licensor under the License, +as defined below, subject to the following condition. + +Without limiting other conditions in the License, the grant of +rights under the License will not include, and the License does not +grant to you, the right to Sell the Software. + +For purposes of the foregoing, "Sell" means practicing any or all +of the rights granted to you under the License to provide to third +parties, for a fee or other consideration (including without +limitation fees for hosting or consulting/ support services related +to the Software), a product or service whose value derives, entirely +or substantially, from the functionality of the Software. Any license +notice or attribution required by the License must also include +this Commons Clause License Condition notice. + +Software: All funcaptcha's associated files. +License: MIT +Licensor: noahcoolboy diff --git a/g4f/Provider/npm/node_modules/funcaptcha/README.md b/g4f/Provider/npm/node_modules/funcaptcha/README.md new file mode 100644 index 00000000..6ef1595a --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/README.md @@ -0,0 +1,115 @@ +# funcaptcha +A library used to interact with funcaptchas. +## Installation +This package is available on npm. +Simply run: `npm install funcaptcha` +## Usage And Documentation +Require the library like any other +```js +const fun = require("funcaptcha") +``` + +You must first fetch a token using getToken +```js +const token = await fun.getToken({ + pkey: "476068BF-9607-4799-B53D-966BE98E2B81", // The public key + surl: "https://roblox-api.arkoselabs.com", // OPTIONAL: Some websites can have a custom service URL + data: { // OPTIONAL + blob: "blob" // Some websites can have custom data passed: here it is data[blob] + }, + headers: { // OPTIONAL + // You can pass custom headers if you have to, but keep + // in mind to pass a user agent when doing that + "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36' + }, + site: "https://www.roblox.com/login", // The site which contains the funcaptcha + proxy: "http://127.0.0.1:8888" // OPTIONAL: A proxy to fetch the token, usually not required + // NOTE: The proxy will only be used for fetching the token, and not future requests such as getting images and answering captchas +}) +``` + +You can then create a new session +```js +// Token, in this case, may either be a string (if you already know it) or an object you received from getToken (it will strip the token out of the object) +const session = new fun.Session(token, { + proxy: "http://127.0.0.1:8888", // OPTIONAL: A proxy used to get images and answer captchas, usually not required + userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36" // OPTIONAL: Custom user agent for all future requests +}) + +// If you would like to let a user solve the captcha in their browser +// NOTE: Embed URLs will not work unless put in an iframe. +console.log(session.getEmbedUrl()) + +// Suppressed captchas are instantly valid an do not require for you to load a challenge (it will error) +// These can occur when using a trusted IP and good fingerprint +// You can check if a captcha is suppressed by doing the following: +console.log(session.tokenInfo.sup == "1") +``` + +One session can get you 10 funcaptcha challenges, you will have to get another session after that. +```js +let challenge = await session.getChallenge() +// Please view https://pastebin.com/raw/Gi6yKwyD to see all the data you can find +console.log(challenge.gameType) // Gets the game type (ball, tiles, matchkey, etc...) +console.log(challenge.variant) // The game variant, eg: apple, rotated, maze, dice_pair, dart, card, 3d_rollball_animals, etc... +console.log(challenge.instruction) // Self explanatory +console.log(challenge.waves) // Wave count +console.log(challenge.wave) // Current wave number + +// You can then use these functions +await challenge.getImage() + +// For game type 1, where you have to rotate a circle to put the image in the correct orientation +// In this game type, the angle increment can vary. It can be found with challenge.increment +await challenge.answer(3) // Usually 0-6, but can be 0-5 or 0-6 depending on challenge.increment (clockwise) +await challenge.answer(51.4) // You can input the raw angle as well (clockwise, negative for counter clockwise) + +// For game type 3, where you have to pick one of 6 tiles +await challenge.answer(2) // 0-5, please see https://github.com/noahcoolboy/roblox-funcaptcha/raw/master/img.gif + +// For game type 4, where you pick an image from a selection of images which matches the prompt compared to the image on the left +// The answer should be between 0 and challenge.difficulty +await challenge.answer(2) // Pick the third image +``` + +## Full Example +```js +const fs = require("fs") +const fun = require("funcaptcha") +const readline = require("readline") +let rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}) + +function ask(question) { + return new Promise((resolve, reject) => { + rl.question(question, (answer) => { + resolve(answer) + }) + }) +} + +fun.getToken({ + pkey: "69A21A01-CC7B-B9C6-0F9A-E7FA06677FFC", +}).then(async token => { + let session = new fun.Session(token) + let challenge = await session.getChallenge() + console.log(challenge.data.game_data.game_variant) + console.log(challenge.data.game_data.customGUI.api_breaker) + + for(let x = 0; x < challenge.data.game_data.waves; x++) { + fs.writeFileSync(`${x}.gif`, await challenge.getImage()) + console.log(await challenge.answer(parseInt(await ask("Answer: ")))) + } + console.log("Done!") +}) +``` + + +## Support Me +Care to support my work? +* BTC: 38pbL2kX2f6oXGVvc6WFF2BY9VpUCLH7FG +* LTC: M81EXhLSRXNKigqNuz5r7nanAvXmJmjFht +* XRP: rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg:865667163 +* Ko-Fi (PayPal): [noahcoolboy](https://ko-fi.com/noahcoolboy) diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/api.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/api.d.ts new file mode 100644 index 00000000..94e7b22e --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/api.d.ts @@ -0,0 +1,28 @@ +export interface GetTokenOptions { + pkey: string; + surl?: string; + data?: { + [key: string]: string; + }; + headers?: { + [key: string]: string; + }; + site?: string; + location?: string; + proxy?: string; + language?: string; +} +export interface GetTokenResult { + challenge_url: string; + challenge_url_cdn: string; + challenge_url_cdn_sri: string; + disable_default_styling: boolean | null; + iframe_height: number | null; + iframe_width: number | null; + kbio: boolean; + mbio: boolean; + noscript: string; + tbio: boolean; + token: string; +} +export declare function getToken(options: GetTokenOptions): Promise<GetTokenResult>; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/api.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/api.js new file mode 100644 index 00000000..b1cee39c --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/api.js @@ -0,0 +1,45 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getToken = void 0; +const http_1 = require("./http"); +const util_1 = require("./util"); +async function getToken(options) { + options = { + surl: "https://client-api.arkoselabs.com", + data: {}, + ...options, + }; + if (!options.headers) + options.headers = { "User-Agent": util_1.default.DEFAULT_USER_AGENT }; + else if (!Object.keys(options.headers).map(v => v.toLowerCase()).includes("user-agent")) + options.headers["User-Agent"] = util_1.default.DEFAULT_USER_AGENT; + options.headers["Accept-Language"] = "en-US,en;q=0.9"; + options.headers["Sec-Fetch-Site"] = "same-origin"; + options.headers["Accept"] = "*/*"; + options.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"; + options.headers["sec-fetch-mode"] = "cors"; + if (options.site) { + options.headers["Origin"] = options.surl; + options.headers["Referer"] = `${options.surl}/v2/${options.pkey}/1.5.5/enforcement.fbfc14b0d793c6ef8359e0e4b4a91f67.html`; + } + let ua = options.headers[Object.keys(options.headers).find(v => v.toLowerCase() == "user-agent")]; + let res = await (0, http_1.default)(options.surl, { + method: "POST", + path: "/fc/gt2/public_key/" + options.pkey, + body: util_1.default.constructFormData({ + bda: util_1.default.getBda(ua, options), + public_key: options.pkey, + site: options.site ? new URL(options.site).origin : undefined, + userbrowser: ua, + capi_version: "1.5.5", + capi_mode: "inline", + style_theme: "default", + rnd: Math.random().toString(), + ...Object.fromEntries(Object.keys(options.data).map(v => ["data[" + v + "]", options.data[v]])), + language: options.language || "en", + }), + headers: options.headers, + }, options.proxy); + return JSON.parse(res.body.toString()); +} +exports.getToken = getToken; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/challenge.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/challenge.d.ts new file mode 100644 index 00000000..07b6c754 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/challenge.d.ts @@ -0,0 +1,82 @@ +/// <reference types="node" /> +import { TokenInfo } from "./session"; +interface ChallengeOptions { + userAgent?: string; + proxy?: string; +} +interface ChallengeData { + token: string; + tokenInfo: TokenInfo; + session_token: string; + challengeID: string; + challengeURL: string; + game_data: { + gameType: number; + customGUI: { + is_using_api_breaker_v2: boolean; + _guiFontColr: string; + _challenge_imgs: string[]; + api_breaker: string; + encrypted_mode: number; + example_images: { + correct: string; + incorrect: string; + }; + }; + waves: number; + game_variant?: string; + game_difficulty?: number; + puzzle_name?: string; + instruction_string?: string; + }; + game_sid: string; + lang: string; + string_table: { + [key: string]: string; + }; + string_table_prefixes: string[]; +} +interface AnswerResponse { + response: "not answered" | "answered"; + solved?: boolean; + incorrect_guess?: number; + score?: number; + decryption_key?: string; + time_end?: number; + time_end_seconds?: number; +} +export declare abstract class Challenge { + data: ChallengeData; + imgs: Promise<Buffer>[]; + wave: number; + protected key: Promise<string>; + protected userAgent: string; + protected proxy: string; + constructor(data: ChallengeData, challengeOptions: ChallengeOptions); + getImage(): Promise<Buffer>; + protected getKey(): Promise<string>; + abstract answer(answer: number): Promise<AnswerResponse>; + get gameType(): number; + get variant(): string; + get instruction(): string; + get waves(): number; +} +export declare class Challenge1 extends Challenge { + private answerHistory; + increment: any; + constructor(data: ChallengeData, challengeOptions: ChallengeOptions); + private round; + answer(answer: number): Promise<AnswerResponse>; +} +export declare class Challenge3 extends Challenge { + private answerHistory; + constructor(data: ChallengeData, challengeOptions: ChallengeOptions); + answer(tile: number): Promise<AnswerResponse>; +} +export declare class Challenge4 extends Challenge { + private answerHistory; + constructor(data: ChallengeData, challengeOptions: ChallengeOptions); + answer(index: number): Promise<AnswerResponse>; + get difficulty(): number; +} +export {}; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/challenge.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/challenge.js new file mode 100644 index 00000000..787ef4cd --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/challenge.js @@ -0,0 +1,194 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Challenge4 = exports.Challenge3 = exports.Challenge1 = exports.Challenge = void 0; +const http_1 = require("./http"); +const util_1 = require("./util"); +const crypt_1 = require("./crypt"); +const console_1 = require("console"); +class Challenge { + constructor(data, challengeOptions) { + this.wave = 0; + this.data = data; + this.userAgent = challengeOptions.userAgent; + this.proxy = challengeOptions.proxy; + // Preload images + this.imgs = data.game_data.customGUI._challenge_imgs.map(async (v) => { + let req = await (0, http_1.default)(v, { + method: "GET", + path: undefined, + headers: { + "User-Agent": this.userAgent, + "Referer": this.data.tokenInfo.surl + }, + }); + return req.body; + }); + if (data.game_data.customGUI.encrypted_mode) { + // Preload decryption key + this.key = this.getKey(); + } + } + async getImage() { + let img = await this.imgs[this.wave]; + try { + JSON.parse(img.toString()); // Image is encrypted + img = Buffer.from(await crypt_1.default.decrypt(img.toString(), await this.getKey()), "base64"); + } + catch (err) { + // Image is not encrypted + // All good! + } + return img; + } + async getKey() { + if (this.key) + return await this.key; + let response = await (0, http_1.default)(this.data.tokenInfo.surl, { + method: "POST", + path: "/fc/ekey/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "Referer": this.data.tokenInfo.surl, + }, + body: util_1.default.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + }), + }, this.proxy); + this.key = JSON.parse(response.body.toString()).decryption_key; + return this.key; + } + get gameType() { + return this.data.game_data.gameType; + } + get variant() { + return this.data.game_data.game_variant || this.data.game_data.instruction_string; + } + get instruction() { + return this.data.string_table[`${this.data.game_data.gameType}.instructions-${this.variant}`] || this.data.string_table[`${this.data.game_data.gameType}.touch_done_info${this.data.game_data.game_variant ? `_${this.data.game_data.game_variant}` : ""}`]; + } + get waves() { + return this.data.game_data.waves; + } +} +exports.Challenge = Challenge; +class Challenge1 extends Challenge { + constructor(data, challengeOptions) { + super(data, challengeOptions); + this.answerHistory = []; + // But WHY?! + let clr = data.game_data.customGUI._guiFontColr; + this.increment = parseInt(clr ? clr.replace("#", "").substring(3) : "28", 16); + this.increment = this.increment > 113 ? this.increment / 10 : this.increment; + } + round(num) { + return (Math.round(num * 10) / 10).toFixed(2); + } + async answer(answer) { + if (answer >= 0 && answer <= Math.round(360 / 51.4) - 1) + this.answerHistory.push(this.round(answer * this.increment)); + else + this.answerHistory.push(this.round(answer)); + let encrypted = await crypt_1.default.encrypt(this.answerHistory.toString(), this.data.session_token); + let req = await (0, http_1.default)(this.data.tokenInfo.surl, { + method: "POST", + path: "/fc/ca/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "Referer": this.data.challengeURL + }, + body: util_1.default.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + guess: encrypted, + }), + }, this.proxy); + let reqData = JSON.parse(req.body.toString()); + this.key = reqData.decryption_key || ""; + this.wave++; + return reqData; + } +} +exports.Challenge1 = Challenge1; +class Challenge3 extends Challenge { + constructor(data, challengeOptions) { + super(data, challengeOptions); + this.answerHistory = []; + } + async answer(tile) { + (0, console_1.assert)(tile >= 0 && tile <= 5, "Tile must be between 0 and 5"); + let pos = util_1.default.tileToLoc(tile); + this.answerHistory.push(util_1.default.solveBreaker(!!this.data.game_data.customGUI.is_using_api_breaker_v2, this.data.game_data.customGUI.api_breaker, 3, pos)); + let encrypted = await crypt_1.default.encrypt(JSON.stringify(this.answerHistory), this.data.session_token); + let requestedId = await crypt_1.default.encrypt(JSON.stringify({}), `REQUESTED${this.data.session_token}ID`); + let { cookie: tCookie, value: tValue } = util_1.default.getTimestamp(); + let req = await (0, http_1.default)(this.data.tokenInfo.surl, { + method: "POST", + path: "/fc/ca/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "X-Newrelic-Timestamp": tValue, + "X-Requested-ID": requestedId, + "Cookie": tCookie, + "Referer": this.data.challengeURL + }, + body: util_1.default.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + guess: encrypted, + analytics_tier: this.data.tokenInfo.at, + sid: this.data.tokenInfo.r, + bio: this.data.tokenInfo.mbio && "eyJtYmlvIjoiMTI1MCwwLDE0NywyMDQ7MTg5NCwwLDE1MSwyMDA7MTk2MCwxLDE1MiwxOTk7MjAyOSwyLDE1MiwxOTk7MjU3NSwwLDE1NSwxOTU7MjU4NSwwLDE1NiwxOTA7MjU5NSwwLDE1OCwxODU7MjYwNCwwLDE1OSwxODA7MjYxMywwLDE2MCwxNzU7MjYyMSwwLDE2MSwxNzA7MjYzMCwwLDE2MywxNjU7MjY0MCwwLDE2NCwxNjA7MjY1MCwwLDE2NSwxNTU7MjY2NCwwLDE2NiwxNTA7MjY3NywwLDE2NiwxNDQ7MjY5NCwwLDE2NywxMzk7MjcyMCwwLDE2NywxMzM7Mjc1NCwwLDE2NywxMjc7Mjc4MywwLDE2NywxMjE7MjgxMiwwLDE2NywxMTU7Mjg0MywwLDE2NywxMDk7Mjg2MywwLDE2NywxMDM7Mjg3NSwwLDE2Niw5ODsyOTA1LDAsMTY1LDkzOzMyMzIsMCwxNjUsOTk7MzI2MiwwLDE2NSwxMDU7MzI5OSwwLDE2NCwxMTA7MzM0MCwwLDE2MSwxMTU7MzM3MiwwLDE1NywxMjA7MzM5NSwwLDE1MywxMjQ7MzQwOCwwLDE0OCwxMjc7MzQyMCwwLDE0MywxMzA7MzQyOSwwLDEzOCwxMzE7MzQ0MSwwLDEzMywxMzQ7MzQ1MCwwLDEyOCwxMzU7MzQ2MSwwLDEyMywxMzg7MzQ3NiwwLDExOCwxNDA7MzQ4OSwwLDExMywxNDI7MzUwMywwLDEwOCwxNDM7MzUxOCwwLDEwMywxNDQ7MzUzNCwwLDk4LDE0NTszNTU2LDAsOTMsMTQ2OzM2MTUsMCw4OCwxNDg7MzY2MiwwLDgzLDE1MTszNjgzLDAsNzgsMTU0OzM3MDEsMCw3MywxNTc7MzcyNSwwLDY5LDE2MTszNzkzLDEsNjgsMTYyOzM4NTEsMiw2OCwxNjI7IiwidGJpbyI6IiIsImtiaW8iOiIifQ==" + }), + }, this.proxy); + let reqData = JSON.parse(req.body.toString()); + this.key = reqData.decryption_key || ""; + this.wave++; + return reqData; + } +} +exports.Challenge3 = Challenge3; +class Challenge4 extends Challenge { + constructor(data, challengeOptions) { + super(data, challengeOptions); + this.answerHistory = []; + } + async answer(index) { + (0, console_1.assert)(index >= 0 && index <= this.data.game_data.game_difficulty - 1, "Index must be between 0 and " + (this.data.game_data.game_difficulty - 1)); + this.answerHistory.push(util_1.default.solveBreaker(!!this.data.game_data.customGUI.is_using_api_breaker_v2, this.data.game_data.customGUI.api_breaker, 4, { index })); + let encrypted = await crypt_1.default.encrypt(JSON.stringify(this.answerHistory), this.data.session_token); + let requestedId = await crypt_1.default.encrypt(JSON.stringify({}), `REQUESTED${this.data.session_token}ID`); + let { cookie: tCookie, value: tValue } = util_1.default.getTimestamp(); + let req = await (0, http_1.default)(this.data.tokenInfo.surl, { + method: "POST", + path: "/fc/ca/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "X-Newrelic-Timestamp": tValue, + "X-Requested-ID": requestedId, + "Cookie": tCookie, + "Referer": this.data.challengeURL + }, + body: util_1.default.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + guess: encrypted, + analytics_tier: this.data.tokenInfo.at, + sid: this.data.tokenInfo.r, + bio: this.data.tokenInfo.mbio && "eyJtYmlvIjoiMTI1MCwwLDE0NywyMDQ7MTg5NCwwLDE1MSwyMDA7MTk2MCwxLDE1MiwxOTk7MjAyOSwyLDE1MiwxOTk7MjU3NSwwLDE1NSwxOTU7MjU4NSwwLDE1NiwxOTA7MjU5NSwwLDE1OCwxODU7MjYwNCwwLDE1OSwxODA7MjYxMywwLDE2MCwxNzU7MjYyMSwwLDE2MSwxNzA7MjYzMCwwLDE2MywxNjU7MjY0MCwwLDE2NCwxNjA7MjY1MCwwLDE2NSwxNTU7MjY2NCwwLDE2NiwxNTA7MjY3NywwLDE2NiwxNDQ7MjY5NCwwLDE2NywxMzk7MjcyMCwwLDE2NywxMzM7Mjc1NCwwLDE2NywxMjc7Mjc4MywwLDE2NywxMjE7MjgxMiwwLDE2NywxMTU7Mjg0MywwLDE2NywxMDk7Mjg2MywwLDE2NywxMDM7Mjg3NSwwLDE2Niw5ODsyOTA1LDAsMTY1LDkzOzMyMzIsMCwxNjUsOTk7MzI2MiwwLDE2NSwxMDU7MzI5OSwwLDE2NCwxMTA7MzM0MCwwLDE2MSwxMTU7MzM3MiwwLDE1NywxMjA7MzM5NSwwLDE1MywxMjQ7MzQwOCwwLDE0OCwxMjc7MzQyMCwwLDE0MywxMzA7MzQyOSwwLDEzOCwxMzE7MzQ0MSwwLDEzMywxMzQ7MzQ1MCwwLDEyOCwxMzU7MzQ2MSwwLDEyMywxMzg7MzQ3NiwwLDExOCwxNDA7MzQ4OSwwLDExMywxNDI7MzUwMywwLDEwOCwxNDM7MzUxOCwwLDEwMywxNDQ7MzUzNCwwLDk4LDE0NTszNTU2LDAsOTMsMTQ2OzM2MTUsMCw4OCwxNDg7MzY2MiwwLDgzLDE1MTszNjgzLDAsNzgsMTU0OzM3MDEsMCw3MywxNTc7MzcyNSwwLDY5LDE2MTszNzkzLDEsNjgsMTYyOzM4NTEsMiw2OCwxNjI7IiwidGJpbyI6IiIsImtiaW8iOiIifQ==" + }), + }, this.proxy); + let reqData = JSON.parse(req.body.toString()); + this.key = reqData.decryption_key || ""; + this.wave++; + return reqData; + } + get difficulty() { + return this.data.game_data.game_difficulty; + } +} +exports.Challenge4 = Challenge4; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/crypt.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/crypt.d.ts new file mode 100644 index 00000000..52ef9579 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/crypt.d.ts @@ -0,0 +1,7 @@ +declare function encrypt(data: string, key: string): string; +declare function decrypt(rawData: string, key: string): string; +declare const _default: { + encrypt: typeof encrypt; + decrypt: typeof decrypt; +}; +export default _default; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/crypt.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/crypt.js new file mode 100644 index 00000000..67cd671c --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/crypt.js @@ -0,0 +1,51 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const crypto_1 = require("crypto"); +function encrypt(data, key) { + let salt = ""; + let salted = ""; + let dx = Buffer.alloc(0); + // Generate salt, as 8 random lowercase letters + salt = String.fromCharCode(...Array(8).fill(0).map(_ => Math.floor(Math.random() * 26) + 97)); + // Our final key and iv come from the key and salt being repeatedly hashed + // dx = md5(md5(md5(key + salt) + key + salt) + key + salt) + // For each round of hashing, we append the result to salted, resulting in a 96 character string + // The first 64 characters are the key, and the last 32 are the iv + for (let x = 0; x < 3; x++) { + dx = (0, crypto_1.createHash)("md5") + .update(Buffer.concat([ + Buffer.from(dx), + Buffer.from(key), + Buffer.from(salt), + ])) + .digest(); + salted += dx.toString("hex"); + } + let aes = (0, crypto_1.createCipheriv)("aes-256-cbc", Buffer.from(salted.substring(0, 64), "hex"), // Key + Buffer.from(salted.substring(64, 64 + 32), "hex") // IV + ); + return JSON.stringify({ + ct: aes.update(data, null, "base64") + aes.final("base64"), + iv: salted.substring(64, 64 + 32), + s: Buffer.from(salt).toString("hex"), + }); +} +function decrypt(rawData, key) { + let data = JSON.parse(rawData); + // We get our decryption key by doing the inverse of the encryption process + let dk = Buffer.concat([Buffer.from(key), Buffer.from(data.s, "hex")]); + let arr = [Buffer.from((0, crypto_1.createHash)("md5").update(dk).digest()).toString("hex")]; + let result = arr[0]; + for (let x = 1; x < 3; x++) { + arr.push(Buffer.from((0, crypto_1.createHash)("md5") + .update(Buffer.concat([Buffer.from(arr[x - 1], "hex"), dk])) + .digest()).toString("hex")); + result += arr[x]; + } + let aes = (0, crypto_1.createDecipheriv)("aes-256-cbc", Buffer.from(result.substring(0, 64), "hex"), Buffer.from(data.iv, "hex")); + return aes.update(data.ct, "base64", "utf8") + aes.final("utf8"); +} +exports.default = { + encrypt, + decrypt, +}; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/fingerprint.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/fingerprint.d.ts new file mode 100644 index 00000000..422954bc --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/fingerprint.d.ts @@ -0,0 +1,63 @@ +declare const baseFingerprint: { + DNT: string; + L: string; + D: number; + PR: number; + S: number[]; + AS: number[]; + TO: number; + SS: boolean; + LS: boolean; + IDB: boolean; + B: boolean; + ODB: boolean; + CPUC: string; + PK: string; + CFP: string; + FR: boolean; + FOS: boolean; + FB: boolean; + JSF: string[]; + P: string[]; + T: (number | boolean)[]; + H: number; + SWF: boolean; +}; +declare function getFingerprint(): { + DNT: string; + L: string; + D: number; + PR: number; + S: number[]; + AS: number[]; + TO: number; + SS: boolean; + LS: boolean; + IDB: boolean; + B: boolean; + ODB: boolean; + CPUC: string; + PK: string; + CFP: string; + FR: boolean; + FOS: boolean; + FB: boolean; + JSF: string[]; + P: string[]; + T: (number | boolean)[]; + H: number; + SWF: boolean; +}; +declare function prepareF(fingerprint: any): string; +declare function prepareFe(fingerprint: any): any[]; +declare function getEnhancedFingerprint(fp: typeof baseFingerprint, ua: string, opts: any): { + key: string; + value: any; +}[]; +declare const _default: { + getFingerprint: typeof getFingerprint; + prepareF: typeof prepareF; + prepareFe: typeof prepareFe; + getEnhancedFingerprint: typeof getEnhancedFingerprint; +}; +export default _default; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/fingerprint.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/fingerprint.js new file mode 100644 index 00000000..b36ee5d1 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/fingerprint.js @@ -0,0 +1,304 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const murmur_1 = require("./murmur"); +const crypto_1 = require("crypto"); +const baseFingerprint = { + DNT: "unknown", + L: "en-US", + D: 24, + PR: 1, + S: [1920, 1200], + AS: [1920, 1200], + TO: 9999, + SS: true, + LS: true, + IDB: true, + B: false, + ODB: true, + CPUC: "unknown", + PK: "Win32", + CFP: `canvas winding:yes~canvas fp:data:image/png;base64,${Buffer.from(Math.random().toString()).toString("base64")}`, + FR: false, + FOS: false, + FB: false, + JSF: [ + "Andale Mono", + "Arial", + "Arial Black", + "Arial Hebrew", + "Arial MT", + "Arial Narrow", + "Arial Rounded MT Bold", + "Arial Unicode MS", + "Bitstream Vera Sans Mono", + "Book Antiqua", + "Bookman Old Style", + "Calibri", + "Cambria", + "Cambria Math", + "Century", + "Century Gothic", + "Century Schoolbook", + "Comic Sans", + "Comic Sans MS", + "Consolas", + "Courier", + "Courier New", + "Garamond", + "Geneva", + "Georgia", + "Helvetica", + "Helvetica Neue", + "Impact", + "Lucida Bright", + "Lucida Calligraphy", + "Lucida Console", + "Lucida Fax", + "LUCIDA GRANDE", + "Lucida Handwriting", + "Lucida Sans", + "Lucida Sans Typewriter", + "Lucida Sans Unicode", + "Microsoft Sans Serif", + "Monaco", + "Monotype Corsiva", + "MS Gothic", + "MS Outlook", + "MS PGothic", + "MS Reference Sans Serif", + "MS Sans Serif", + "MS Serif", + "MYRIAD", + "MYRIAD PRO", + "Palatino", + "Palatino Linotype", + "Segoe Print", + "Segoe Script", + "Segoe UI", + "Segoe UI Light", + "Segoe UI Semibold", + "Segoe UI Symbol", + "Tahoma", + "Times", + "Times New Roman", + "Times New Roman PS", + "Trebuchet MS", + "Verdana", + "Wingdings", + "Wingdings 2", + "Wingdings 3", + ], + P: [ + "Chrome PDF Plugin::Portable Document Format::application/x-google-chrome-pdf~pdf", + "Chrome PDF Viewer::::application/pdf~pdf", + "Native Client::::application/x-nacl~,application/x-pnacl~", + ], + T: [0, false, false], + H: 24, + SWF: false, // Flash support +}; +const languages = [ + "af", "af-ZA", "ar", "ar-AE", "ar-BH", "ar-DZ", "ar-EG", "ar-IQ", "ar-JO", "ar-KW", "ar-LB", "ar-LY", "ar-MA", "ar-OM", "ar-QA", "ar-SA", + "ar-SY", "ar-TN", "ar-YE", "az", "az-AZ", "az-AZ", "be", "be-BY", "bg", "bg-BG", "bs-BA", "ca", "ca-ES", "cs", "cs-CZ", "cy", + "cy-GB", "da", "da-DK", "de", "de-AT", "de-CH", "de-DE", "de-LI", "de-LU", "dv", "dv-MV", "el", "el-GR", "en", "en-AU", "en-BZ", + "en-CA", "en-CB", "en-GB", "en-IE", "en-JM", "en-NZ", "en-PH", "en-TT", "en-US", "en-ZA", "en-ZW", "eo", "es", "es-AR", "es-BO", "es-CL", + "es-CO", "es-CR", "es-DO", "es-EC", "es-ES", "es-ES", "es-GT", "es-HN", "es-MX", "es-NI", "es-PA", "es-PE", "es-PR", "es-PY", "es-SV", "es-UY", + "es-VE", "et", "et-EE", "eu", "eu-ES", "fa", "fa-IR", "fi", "fi-FI", "fo", "fo-FO", "fr", "fr-BE", "fr-CA", "fr-CH", "fr-FR", + "fr-LU", "fr-MC", "gl", "gl-ES", "gu", "gu-IN", "he", "he-IL", "hi", "hi-IN", "hr", "hr-BA", "hr-HR", "hu", "hu-HU", "hy", + "hy-AM", "id", "id-ID", "is", "is-IS", "it", "it-CH", "it-IT", "ja", "ja-JP", "ka", "ka-GE", "kk", "kk-KZ", "kn", "kn-IN", + "ko", "ko-KR", "kok", "kok-IN", "ky", "ky-KG", "lt", "lt-LT", "lv", "lv-LV", "mi", "mi-NZ", "mk", "mk-MK", "mn", "mn-MN", + "mr", "mr-IN", "ms", "ms-BN", "ms-MY", "mt", "mt-MT", "nb", "nb-NO", "nl", "nl-BE", "nl-NL", "nn-NO", "ns", "ns-ZA", "pa", + "pa-IN", "pl", "pl-PL", "ps", "ps-AR", "pt", "pt-BR", "pt-PT", "qu", "qu-BO", "qu-EC", "qu-PE", "ro", "ro-RO", "ru", "ru-RU", + "sa", "sa-IN", "se", "se-FI", "se-FI", "se-FI", "se-NO", "se-NO", "se-NO", "se-SE", "se-SE", "se-SE", "sk", "sk-SK", "sl", "sl-SI", + "sq", "sq-AL", "sr-BA", "sr-BA", "sr-SP", "sr-SP", "sv", "sv-FI", "sv-SE", "sw", "sw-KE", "syr", "syr-SY", "ta", "ta-IN", "te", + "te-IN", "th", "th-TH", "tl", "tl-PH", "tn", "tn-ZA", "tr", "tr-TR", "tt", "tt-RU", "ts", "uk", "uk-UA", "ur", "ur-PK", + "uz", "uz-UZ", "uz-UZ", "vi", "vi-VN", "xh", "xh-ZA", "zh", "zh-CN", "zh-HK", "zh-MO", "zh-SG", "zh-TW", "zu", "zu-ZA" +]; +let screenRes = [ + [1920, 1080], + [1920, 1200], + [2048, 1080], + [2560, 1440], + [1366, 768], + [1440, 900], + [1536, 864], + [1680, 1050], + [1280, 1024], + [1280, 800], + [1280, 720], + [1600, 1200], + [1600, 900], +]; +function randomScreenRes() { + return screenRes[Math.floor(Math.random() * screenRes.length)]; +} +// Get fingerprint +function getFingerprint() { + let fingerprint = { ...baseFingerprint }; // Create a copy of the base fingerprint + // Randomization time! + fingerprint["DNT"] = "unknown"; + fingerprint["L"] = languages[Math.floor(Math.random() * languages.length)]; + fingerprint["D"] = [8, 24][Math.floor(Math.random() * 2)]; + fingerprint["PR"] = Math.round(Math.random() * 100) / 100 * 2 + 0.5; + fingerprint["S"] = randomScreenRes(); + fingerprint["AS"] = fingerprint.S; + fingerprint["TO"] = (Math.floor(Math.random() * 24) - 12) * 60; + fingerprint["SS"] = Math.random() > 0.5; + fingerprint["LS"] = Math.random() > 0.5; + fingerprint["IDB"] = Math.random() > 0.5; + fingerprint["B"] = Math.random() > 0.5; + fingerprint["ODB"] = Math.random() > 0.5; + fingerprint["CPUC"] = "unknown"; + fingerprint["PK"] = "Win32"; + fingerprint["CFP"] = "canvas winding:yes~canvas fp:data:image/png;base64," + (0, crypto_1.randomBytes)(128).toString("base64"); + fingerprint["FR"] = false; // Fake Resolution + fingerprint["FOS"] = false; // Fake Operating System + fingerprint["FB"] = false; // Fake Browser + fingerprint["JSF"] = fingerprint["JSF"].filter(() => Math.random() > 0.5); + fingerprint["P"] = fingerprint["P"].filter(() => Math.random() > 0.5); + fingerprint["T"] = [ + Math.floor(Math.random() * 8), + Math.random() > 0.5, + Math.random() > 0.5, + ]; + fingerprint["H"] = 2 ** Math.floor(Math.random() * 6); + fingerprint["SWF"] = fingerprint["SWF"]; // RIP Flash + return fingerprint; +} +function prepareF(fingerprint) { + let f = []; + let keys = Object.keys(fingerprint); + for (let i = 0; i < keys.length; i++) { + if (fingerprint[keys[i]].join) + f.push(fingerprint[keys[i]].join(";")); + else + f.push(fingerprint[keys[i]]); + } + return f.join("~~~"); +} +function prepareFe(fingerprint) { + let fe = []; + let keys = Object.keys(fingerprint); + for (let i = 0; i < keys.length; i++) { + switch (keys[i]) { + case "CFP": + fe.push(`${keys[i]}:${cfpHash(fingerprint[keys[i]])}`); + break; + case "P": + fe.push(`${keys[i]}:${fingerprint[keys[i]].map((v) => v.split("::")[0])}`); + break; + default: + fe.push(`${keys[i]}:${fingerprint[keys[i]]}`); + break; + } + } + return fe; +} +function cfpHash(H8W) { + var l8W, U8W; + if (!H8W) + return ""; + if (Array.prototype.reduce) + return H8W.split("").reduce(function (p8W, z8W) { + p8W = (p8W << 5) - p8W + z8W.charCodeAt(0); + return p8W & p8W; + }, 0); + l8W = 0; + if (H8W.length === 0) + return l8W; + for (var k8W = 0; k8W < H8W.length; k8W++) { + U8W = H8W.charCodeAt(k8W); + l8W = (l8W << 5) - l8W + U8W; + l8W = l8W & l8W; + } + return l8W; +} +let baseEnhancedFingerprint = { + "webgl_extensions": "ANGLE_instanced_arrays;EXT_blend_minmax;EXT_color_buffer_half_float;EXT_disjoint_timer_query;EXT_float_blend;EXT_frag_depth;EXT_shader_texture_lod;EXT_texture_compression_bptc;EXT_texture_compression_rgtc;EXT_texture_filter_anisotropic;EXT_sRGB;KHR_parallel_shader_compile;OES_element_index_uint;OES_fbo_render_mipmap;OES_standard_derivatives;OES_texture_float;OES_texture_float_linear;OES_texture_half_float;OES_texture_half_float_linear;OES_vertex_array_object;WEBGL_color_buffer_float;WEBGL_compressed_texture_s3tc;WEBGL_compressed_texture_s3tc_srgb;WEBGL_debug_renderer_info;WEBGL_debug_shaders;WEBGL_depth_texture;WEBGL_draw_buffers;WEBGL_lose_context;WEBGL_multi_draw", + "webgl_extensions_hash": "58a5a04a5bef1a78fa88d5c5098bd237", + "webgl_renderer": "WebKit WebGL", + "webgl_vendor": "WebKit", + "webgl_version": "WebGL 1.0 (OpenGL ES 2.0 Chromium)", + "webgl_shading_language_version": "WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)", + "webgl_aliased_line_width_range": "[1, 1]", + "webgl_aliased_point_size_range": "[1, 1023]", + "webgl_antialiasing": "yes", + "webgl_bits": "8,8,24,8,8,0", + "webgl_max_params": "16,64,16384,4096,8192,32,8192,31,16,32,4096", + "webgl_max_viewport_dims": "[8192, 8192]", + "webgl_unmasked_vendor": "Google Inc. (Google)", + "webgl_unmasked_renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)", + "webgl_vsf_params": "23,127,127,23,127,127,23,127,127", + "webgl_vsi_params": "0,31,30,0,31,30,0,31,30", + "webgl_fsf_params": "23,127,127,23,127,127,23,127,127", + "webgl_fsi_params": "0,31,30,0,31,30,0,31,30", + "webgl_hash_webgl": null, + "user_agent_data_brands": "Chromium,Google Chrome,Not=A?Brand", + "user_agent_data_mobile": null, + "navigator_connection_downlink": null, + "navigator_connection_downlink_max": null, + "network_info_rtt": null, + "network_info_save_data": false, + "network_info_rtt_type": null, + "screen_pixel_depth": 24, + "navigator_device_memory": 0.5, + "navigator_languages": "en-US,fr-BE,fr,en-BE,en", + "window_inner_width": 0, + "window_inner_height": 0, + "window_outer_width": 2195, + "window_outer_height": 1195, + "browser_detection_firefox": false, + "browser_detection_brave": false, + "audio_codecs": "{\"ogg\":\"probably\",\"mp3\":\"probably\",\"wav\":\"probably\",\"m4a\":\"maybe\",\"aac\":\"probably\"}", + "video_codecs": "{\"ogg\":\"probably\",\"h264\":\"probably\",\"webm\":\"probably\",\"mpeg4v\":\"\",\"mpeg4a\":\"\",\"theora\":\"\"}", + "media_query_dark_mode": true, + "headless_browser_phantom": false, + "headless_browser_selenium": false, + "headless_browser_nightmare_js": false, + "document__referrer": "https://www.roblox.com/", + "window__ancestor_origins": [ + "https://www.roblox.com", + ], + "window__tree_index": [ + 0 + ], + "window__tree_structure": "[[]]", + "window__location_href": "https://roblox-api.arkoselabs.com/v2/1.5.5/enforcement.fbfc14b0d793c6ef8359e0e4b4a91f67.html#476068BF-9607-4799-B53D-966BE98E2B81", + "client_config__sitedata_location_href": "https://www.roblox.com/arkose/iframe", + "client_config__surl": "https://roblox-api.arkoselabs.com", + "client_config__language": null, + "navigator_battery_charging": true, + "audio_fingerprint": "124.04347527516074" +}; +function getEnhancedFingerprint(fp, ua, opts) { + let fingerprint = { ...baseEnhancedFingerprint }; + fingerprint.webgl_extensions = fingerprint.webgl_extensions.split(";").filter(_ => Math.random() > 0.5).join(";"); + fingerprint.webgl_extensions_hash = (0, murmur_1.default)(fingerprint.webgl_extensions, 0); + fingerprint.screen_pixel_depth = fp.D; + fingerprint.navigator_languages = fp.L; + fingerprint.window_outer_height = fp.S[0]; + fingerprint.window_outer_width = fp.S[1]; + fingerprint.window_inner_height = fp.S[0]; + fingerprint.window_inner_width = fp.S[1]; + fingerprint.screen_pixel_depth = fp.D; + fingerprint.browser_detection_firefox = !!ua.match(/Firefox\/\d+/); + fingerprint.browser_detection_brave = !!ua.match(/Brave\/\d+/); + fingerprint.media_query_dark_mode = Math.random() > 0.9; + fingerprint.webgl_hash_webgl = (0, murmur_1.default)(Object.entries(fingerprint).filter(([k, v]) => k.startsWith("webgl_") && k != "webgl_hash_webgl").map(([k, v]) => v).join(","), 0); + fingerprint.client_config__language = opts.language || null; + fingerprint.window__location_href = `${opts.surl}/v2/1.5.5/enforcement.fbfc14b0d793c6ef8359e0e4b4a91f67.html#${opts.pkey}`; + if (opts.site) { + fingerprint.document__referrer = opts.site; + fingerprint.window__ancestor_origins = [opts.site]; + fingerprint.client_config__sitedata_location_href = opts.site; + } + fingerprint.client_config__surl = opts.surl || "https://client-api.arkoselabs.com"; + fingerprint.audio_fingerprint = (124.04347527516074 + Math.random() * 0.001 - 0.0005).toString(); + return Object.entries(fingerprint).map(([k, v]) => ({ key: k, value: v })); +} +exports.default = { + getFingerprint, + prepareF, + prepareFe, + getEnhancedFingerprint, +}; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/http.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/http.d.ts new file mode 100644 index 00000000..5c2e9393 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/http.d.ts @@ -0,0 +1,7 @@ +/// <reference types="node" /> +import { RequestOptions } from "undici/types/dispatcher"; +declare function req(url: string, options: RequestOptions, proxy?: string): Promise<{ + headers: import("undici/types/header").IncomingHttpHeaders; + body: Buffer; +}>; +export default req; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/http.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/http.js new file mode 100644 index 00000000..92b8d8bd --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/http.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const undici_1 = require("undici"); +async function req(url, options, proxy) { + let auth = undefined; + if (proxy) { + let proxyUrl = new URL(proxy); + if (proxyUrl.username && proxyUrl.password) { + auth = Buffer.from(proxyUrl.username + ":" + proxyUrl.password).toString("base64"); + } + } + let dispatcher = proxy ? new undici_1.ProxyAgent({ + uri: proxy, + auth + }) : undefined; + let req = await (0, undici_1.request)(url, { + ...options, + dispatcher, + }); + return { + headers: req.headers, + body: Buffer.from(await req.body.arrayBuffer()), + }; +} +exports.default = req; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/index.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/index.d.ts new file mode 100644 index 00000000..97b1212a --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/index.d.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./session"; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/index.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/index.js new file mode 100644 index 00000000..81e37d85 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/index.js @@ -0,0 +1,18 @@ +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __exportStar = (this && this.__exportStar) || function(m, exports) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +__exportStar(require("./api"), exports); +__exportStar(require("./session"), exports); diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/murmur.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/murmur.d.ts new file mode 100644 index 00000000..0c5e9925 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/murmur.d.ts @@ -0,0 +1,2 @@ +declare var x64hash128: (t: any, r: any) => string; +export default x64hash128; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/murmur.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/murmur.js new file mode 100644 index 00000000..4abbc655 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/murmur.js @@ -0,0 +1,186 @@ +"use strict"; +// MurmurHash3 related functions +// https://github.com/markogresak/fingerprintjs2/blob/master/src/x64hash128.js +Object.defineProperty(exports, "__esModule", { value: true }); +// Given two 64bit ints (as an array of two 32bit ints) returns the two +// added together as a 64bit int (as an array of two 32bit ints). +var x64Add = function (t, r) { + (t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]), + (r = [r[0] >>> 16, 65535 & r[0], r[1] >>> 16, 65535 & r[1]]); + var e = [0, 0, 0, 0]; + return ((e[3] += t[3] + r[3]), + (e[2] += e[3] >>> 16), + (e[3] &= 65535), + (e[2] += t[2] + r[2]), + (e[1] += e[2] >>> 16), + (e[2] &= 65535), + (e[1] += t[1] + r[1]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[0] += t[0] + r[0]), + (e[0] &= 65535), + [(e[0] << 16) | e[1], (e[2] << 16) | e[3]]); +}, +// Given two 64bit ints (as an array of two 32bit ints) returns the two +// multiplied together as a 64bit int (as an array of two 32bit ints). +x64Multiply = function (t, r) { + (t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]), + (r = [r[0] >>> 16, 65535 & r[0], r[1] >>> 16, 65535 & r[1]]); + var e = [0, 0, 0, 0]; + return ((e[3] += t[3] * r[3]), + (e[2] += e[3] >>> 16), + (e[3] &= 65535), + (e[2] += t[2] * r[3]), + (e[1] += e[2] >>> 16), + (e[2] &= 65535), + (e[2] += t[3] * r[2]), + (e[1] += e[2] >>> 16), + (e[2] &= 65535), + (e[1] += t[1] * r[3]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[1] += t[2] * r[2]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[1] += t[3] * r[1]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[0] += t[0] * r[3] + t[1] * r[2] + t[2] * r[1] + t[3] * r[0]), + (e[0] &= 65535), + [(e[0] << 16) | e[1], (e[2] << 16) | e[3]]); +}, +// Given a 64bit int (as an array of two 32bit ints) and an int +// representing a number of bit positions, returns the 64bit int (as an +// array of two 32bit ints) rotated left by that number of positions. +x64Rotl = function (t, r) { + return 32 === (r %= 64) + ? [t[1], t[0]] + : r < 32 + ? [ + (t[0] << r) | (t[1] >>> (32 - r)), + (t[1] << r) | (t[0] >>> (32 - r)), + ] + : ((r -= 32), + [ + (t[1] << r) | (t[0] >>> (32 - r)), + (t[0] << r) | (t[1] >>> (32 - r)), + ]); +}, +// Given a 64bit int (as an array of two 32bit ints) and an int +// representing a number of bit positions, returns the 64bit int (as an +// array of two 32bit ints) shifted left by that number of positions. +x64LeftShift = function (t, r) { + return 0 === (r %= 64) + ? t + : r < 32 + ? [(t[0] << r) | (t[1] >>> (32 - r)), t[1] << r] + : [t[1] << (r - 32), 0]; +}, +// Given two 64bit ints (as an array of two 32bit ints) returns the two +// xored together as a 64bit int (as an array of two 32bit ints). +x64Xor = function (t, r) { + return [t[0] ^ r[0], t[1] ^ r[1]]; +}, +// Given a block, returns murmurHash3's final x64 mix of that block. +// (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the +// only place where we need to right shift 64bit ints.) +x64Fmix = function (t) { + return ((t = x64Xor(t, [0, t[0] >>> 1])), + (t = x64Multiply(t, [4283543511, 3981806797])), + (t = x64Xor(t, [0, t[0] >>> 1])), + (t = x64Multiply(t, [3301882366, 444984403])), + (t = x64Xor(t, [0, t[0] >>> 1]))); +}, +// Given a string and an optional seed as an int, returns a 128 bit +// hash using the x64 flavor of MurmurHash3, as an unsigned hex. +x64hash128 = function (t, r) { + r = r || 0; + for (var e = (t = t || "").length % 16, o = t.length - e, x = [0, r], c = [0, r], h = [0, 0], a = [0, 0], d = [2277735313, 289559509], i = [1291169091, 658871167], l = 0; l < o; l += 16) + (h = [ + (255 & t.charCodeAt(l + 4)) | + ((255 & t.charCodeAt(l + 5)) << 8) | + ((255 & t.charCodeAt(l + 6)) << 16) | + ((255 & t.charCodeAt(l + 7)) << 24), + (255 & t.charCodeAt(l)) | + ((255 & t.charCodeAt(l + 1)) << 8) | + ((255 & t.charCodeAt(l + 2)) << 16) | + ((255 & t.charCodeAt(l + 3)) << 24), + ]), + (a = [ + (255 & t.charCodeAt(l + 12)) | + ((255 & t.charCodeAt(l + 13)) << 8) | + ((255 & t.charCodeAt(l + 14)) << 16) | + ((255 & t.charCodeAt(l + 15)) << 24), + (255 & t.charCodeAt(l + 8)) | + ((255 & t.charCodeAt(l + 9)) << 8) | + ((255 & t.charCodeAt(l + 10)) << 16) | + ((255 & t.charCodeAt(l + 11)) << 24), + ]), + (h = x64Multiply(h, d)), + (h = x64Rotl(h, 31)), + (h = x64Multiply(h, i)), + (x = x64Xor(x, h)), + (x = x64Rotl(x, 27)), + (x = x64Add(x, c)), + (x = x64Add(x64Multiply(x, [0, 5]), [0, 1390208809])), + (a = x64Multiply(a, i)), + (a = x64Rotl(a, 33)), + (a = x64Multiply(a, d)), + (c = x64Xor(c, a)), + (c = x64Rotl(c, 31)), + (c = x64Add(c, x)), + (c = x64Add(x64Multiply(c, [0, 5]), [0, 944331445])); + switch (((h = [0, 0]), (a = [0, 0]), e)) { + case 15: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 14)], 48)); + case 14: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 13)], 40)); + case 13: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 12)], 32)); + case 12: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 11)], 24)); + case 11: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 10)], 16)); + case 10: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 9)], 8)); + case 9: + (a = x64Xor(a, [0, t.charCodeAt(l + 8)])), + (a = x64Multiply(a, i)), + (a = x64Rotl(a, 33)), + (a = x64Multiply(a, d)), + (c = x64Xor(c, a)); + case 8: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 7)], 56)); + case 7: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 6)], 48)); + case 6: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 5)], 40)); + case 5: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 4)], 32)); + case 4: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 3)], 24)); + case 3: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 2)], 16)); + case 2: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 1)], 8)); + case 1: + (h = x64Xor(h, [0, t.charCodeAt(l)])), + (h = x64Multiply(h, d)), + (h = x64Rotl(h, 31)), + (h = x64Multiply(h, i)), + (x = x64Xor(x, h)); + } + return ((x = x64Xor(x, [0, t.length])), + (c = x64Xor(c, [0, t.length])), + (x = x64Add(x, c)), + (c = x64Add(c, x)), + (x = x64Fmix(x)), + (c = x64Fmix(c)), + (x = x64Add(x, c)), + (c = x64Add(c, x)), + ("00000000" + (x[0] >>> 0).toString(16)).slice(-8) + + ("00000000" + (x[1] >>> 0).toString(16)).slice(-8) + + ("00000000" + (c[0] >>> 0).toString(16)).slice(-8) + + ("00000000" + (c[1] >>> 0).toString(16)).slice(-8)); +}; +exports.default = x64hash128; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/session.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/session.d.ts new file mode 100644 index 00000000..d40a10c9 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/session.d.ts @@ -0,0 +1,36 @@ +import { GetTokenResult } from "./api"; +import { Challenge } from "./challenge"; +export interface TokenInfo { + token: string; + r: string; + metabgclr: string; + mainbgclr: string; + guitextcolor: string; + metaiconclr: string; + meta_height: string; + meta_width: string; + meta: string; + pk: string; + dc: string; + at: string; + cdn_url: string; + lurl: string; + surl: string; + smurl: string; + kbio: boolean; + mbio: boolean; + tbio: boolean; +} +export interface SessionOptions { + userAgent?: string; + proxy?: string; +} +export declare class Session { + token: string; + tokenInfo: TokenInfo; + private userAgent; + private proxy; + constructor(token: string | GetTokenResult, sessionOptions?: SessionOptions); + getChallenge(): Promise<Challenge>; + getEmbedUrl(): string; +} diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/session.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/session.js new file mode 100644 index 00000000..e2216d3b --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/session.js @@ -0,0 +1,77 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Session = void 0; +const challenge_1 = require("./challenge"); +const http_1 = require("./http"); +const util_1 = require("./util"); +let parseToken = (token) => Object.fromEntries(token + .split("|") + .map((v) => v.split("=").map((v) => decodeURIComponent(v)))); +class Session { + constructor(token, sessionOptions) { + var _a; + if (typeof token === "string") { + this.token = token; + } + else { + this.token = token.token; + } + if (!this.token.startsWith("token=")) + this.token = "token=" + this.token; + this.tokenInfo = parseToken(this.token); + this.tokenInfo.mbio = typeof (token) !== "string" ? (_a = token.mbio) !== null && _a !== void 0 ? _a : false : false; + this.userAgent = (sessionOptions === null || sessionOptions === void 0 ? void 0 : sessionOptions.userAgent) || util_1.default.DEFAULT_USER_AGENT; + this.proxy = sessionOptions === null || sessionOptions === void 0 ? void 0 : sessionOptions.proxy; + } + async getChallenge() { + let res = await (0, http_1.default)(this.tokenInfo.surl, { + path: "/fc/gfct/", + method: "POST", + body: util_1.default.constructFormData({ + sid: this.tokenInfo.r, + render_type: "canvas", + token: this.tokenInfo.token, + analytics_tier: this.tokenInfo.at, + "data%5Bstatus%5D": "init", + lang: "en", + apiBreakerVersion: "green" + }), + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "Accept-Language": "en-US,en;q=0.9", + "Sec-Fetch-Site": "same-origin", + "Referer": this.getEmbedUrl() + }, + }, this.proxy); + let data = JSON.parse(res.body.toString()); + data.token = this.token; + data.tokenInfo = this.tokenInfo; + if (data.game_data.gameType == 1) { + return new challenge_1.Challenge1(data, { + proxy: this.proxy, + userAgent: this.userAgent, + }); + } + else if (data.game_data.gameType == 3) { + return new challenge_1.Challenge3(data, { + proxy: this.proxy, + userAgent: this.userAgent, + }); + } + else if (data.game_data.gameType == 4) { + return new challenge_1.Challenge4(data, { + proxy: this.proxy, + userAgent: this.userAgent, + }); + } + else { + throw new Error("Unsupported game type: " + data.game_data.gameType); + } + //return res.body.toString() + } + getEmbedUrl() { + return `${this.tokenInfo.surl}/fc/gc/?${util_1.default.constructFormData(this.tokenInfo)}`; + } +} +exports.Session = Session; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/util.d.ts b/g4f/Provider/npm/node_modules/funcaptcha/lib/util.d.ts new file mode 100644 index 00000000..e269a428 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/util.d.ts @@ -0,0 +1,190 @@ +interface TimestampData { + cookie: string; + value: string; +} +interface TileLoc { + x: number; + y: number; + px: number; + py: number; +} +declare function tileToLoc(tile: number): TileLoc; +declare function constructFormData(data: {}): string; +declare function random(): string; +declare function getTimestamp(): TimestampData; +declare function getBda(userAgent: string, opts: object): string; +declare function solveBreaker(v2: boolean, breaker: { + value: string[]; + key: string; +} | string, gameType: number, value: object): any; +declare const _default: { + DEFAULT_USER_AGENT: string; + tileToLoc: typeof tileToLoc; + constructFormData: typeof constructFormData; + getBda: typeof getBda; + apiBreakers: { + v1: { + 3: { + default: (c: any) => any; + method_1: (c: any) => { + x: any; + y: any; + }; + method_2: (c: any) => { + x: any; + y: number; + }; + method_3: (c: any) => { + a: any; + b: any; + }; + method_4: (c: any) => any[]; + method_5: (c: any) => number[]; + }; + 4: { + default: (c: any) => any; + }; + }; + v2: { + 3: { + value: { + alpha: (c: any) => { + x: any; + y: number; + px: any; + py: any; + }; + beta: (c: any) => { + x: any; + y: any; + py: any; + px: any; + }; + gamma: (c: any) => { + x: any; + y: number; + px: any; + py: any; + }; + delta: (c: any) => { + x: any; + y: any; + px: any; + py: any; + }; + epsilon: (c: any) => { + x: number; + y: number; + px: any; + py: any; + }; + zeta: (c: any) => { + x: any; + y: any; + px: any; + py: any; + }; + method_1: (c: any) => { + x: any; + y: any; + px: any; + py: any; + }; + method_2: (c: any) => { + x: any; + y: number; + px: any; + py: any; + }; + method_3: (c: any) => { + x: number; + y: number; + px: any; + py: any; + }; + }; + key: { + alpha: (c: any) => any[]; + beta: (c: any) => string; + gamma: (c: any) => string; + delta: (c: any) => any[]; + epsilon: (c: any) => { + answer: { + x: any; + y: any; + px: any; + py: any; + }; + }; + zeta: (c: any) => any[]; + method_1: (c: any) => { + a: any; + b: any; + px: any; + py: any; + }; + method_2: (c: any) => any[]; + method_3: (c: any) => any[]; + }; + }; + 4: { + value: { + alpha: (c: any) => { + index: number; + }; + beta: (c: any) => { + index: number; + }; + gamma: (c: any) => { + index: number; + }; + delta: (c: any) => { + index: number; + }; + epsilon: (c: any) => { + index: number; + }; + zeta: (c: any) => { + index: any; + }; + va: (c: any) => { + index: any; + }; + vb: (c: any) => { + index: number; + }; + vc: (c: any) => { + index: number; + }; + vd: (c: any) => { + index: number; + }; + }; + key: { + alpha: (c: any) => any[]; + beta: (c: any) => { + size: number; + id: any; + limit: number; + req_timestamp: number; + }; + gamma: (c: any) => any; + delta: (c: any) => { + index: any; + }; + epsilon: (c: any) => any; + zeta: (c: any) => any[]; + ka: (c: any) => any; + kb: (c: any) => any[]; + kc: (c: any) => { + guess: any; + }; + }; + }; + }; + }; + getTimestamp: typeof getTimestamp; + random: typeof random; + solveBreaker: typeof solveBreaker; +}; +export default _default; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/lib/util.js b/g4f/Provider/npm/node_modules/funcaptcha/lib/util.js new file mode 100644 index 00000000..99070515 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/lib/util.js @@ -0,0 +1,172 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const fingerprint_1 = require("./fingerprint"); +const murmur_1 = require("./murmur"); +const crypt_1 = require("./crypt"); +const DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"; +let apiBreakers = { + v1: { + 3: { + default: (c) => c, + method_1: (c) => ({ x: c.y, y: c.x }), + method_2: (c) => ({ x: c.x, y: (c.y + c.x) * c.x }), + method_3: (c) => ({ a: c.x, b: c.y }), + method_4: (c) => [c.x, c.y], + method_5: (c) => [c.y, c.x].map((v) => Math.sqrt(v)), + }, + 4: { + default: (c) => c + } + }, + v2: { + 3: { + value: { + alpha: (c) => ({ x: c.x, y: (c.y + c.x) * c.x, px: c.px, py: c.py }), + beta: (c) => ({ x: c.y, y: c.x, py: c.px, px: c.py }), + gamma: (c) => ({ x: c.y + 1, y: -c.x, px: c.px, py: c.py }), + delta: (c) => ({ x: c.y + 0.25, y: c.x + 0.5, px: c.px, py: c.py }), + epsilon: (c) => ({ x: c.x * 0.5, y: c.y * 5, px: c.px, py: c.py }), + zeta: (c) => ({ x: c.x + 1, y: c.y + 2, px: c.px, py: c.py }), + method_1: (c) => ({ x: c.x, y: c.y, px: c.px, py: c.py }), + method_2: (c) => ({ x: c.y, y: (c.y + c.x) * c.x, px: c.px, py: c.py }), + method_3: (c) => ({ x: Math.sqrt(c.x), y: Math.sqrt(c.y), px: c.px, py: c.py }), + }, + key: { + alpha: (c) => [c.y, c.px, c.py, c.x], + beta: (c) => JSON.stringify({ x: c.x, y: c.y, px: c.px, py: c.py }), + gamma: (c) => [c.x, c.y, c.px, c.py].join(" "), + delta: (c) => [1, c.x, 2, c.y, 3, c.px, 4, c.py], + epsilon: (c) => ({ answer: { x: c.x, y: c.y, px: c.px, py: c.py } }), + zeta: (c) => [c.x, [c.y, [c.px, [c.py]]]], + method_1: (c) => ({ a: c.x, b: c.y, px: c.px, py: c.py }), + method_2: (c) => [c.x, c.y], + method_3: (c) => [c.y, c.x], + } + }, + 4: { + value: { + // @ts-ignore + alpha: (c) => ({ index: String(c.index) + 1 - 2 }), + beta: (c) => ({ index: -c.index }), + gamma: (c) => ({ index: 3 * (3 - c.index) }), + delta: (c) => ({ index: 7 * c.index }), + epsilon: (c) => ({ index: 2 * c.index }), + zeta: (c) => ({ index: c.index ? 100 / c.index : c.index }), + va: (c) => ({ index: c.index + 3 }), + vb: (c) => ({ index: -c.index }), + vc: (c) => ({ index: 10 - c.index }), + vd: (c) => ({ index: 3 * c.index }), + }, + key: { + alpha: (c) => [Math.round(100 * Math.random()), c.index, Math.round(100 * Math.random())], + beta: (c) => ({ size: 50 - c.index, id: c.index, limit: 10 * c.index, req_timestamp: Date.now() }), + gamma: (c) => c.index, + delta: (c) => ({ index: c.index }), + epsilon: (c) => { + const arr = []; + const len = Math.round(5 * Math.random()) + 1; + const rand = Math.round(Math.random() * len); + for (let i = 0; i < len; i++) { + arr.push(i === rand ? c.index : Math.round(10 * Math.random())); + } + arr.push(rand); + return arr; + }, + zeta: (c) => Array(Math.round(5 * Math.random()) + 1).concat(c.index), + ka: (c) => c.index, + kb: (c) => [c.index], + kc: (c) => ({ guess: c.index }), + } + } + } +}; +function tileToLoc(tile) { + let xClick = (tile % 3) * 100 + (tile % 3) * 3 + 3 + 10 + Math.floor(Math.random() * 80); + let yClick = Math.floor(tile / 3) * 100 + Math.floor(tile / 3) * 3 + 3 + 10 + Math.floor(Math.random() * 80); + return { + x: xClick, + y: yClick, + px: xClick / 300, + py: yClick / 200, + }; +} +function constructFormData(data) { + return Object.keys(data) + .filter((v) => data[v] !== undefined) + .map((k) => `${k}=${encodeURIComponent(data[k])}`) + .join("&"); +} +function random() { + return Array(32) + .fill(0) + .map(() => "0123456789abcdef"[Math.floor(Math.random() * 16)]) + .join(""); +} +function getTimestamp() { + const time = (new Date()).getTime().toString(); + const value = `${time.substring(0, 7)}00${time.substring(7, 13)}`; + return { cookie: `timestamp=${value};path=/;secure;samesite=none`, value }; +} +function getBda(userAgent, opts) { + let fp = fingerprint_1.default.getFingerprint(); + let fe = fingerprint_1.default.prepareFe(fp); + let bda = [ + { key: "api_type", value: "js" }, + { key: "p", value: 1 }, + { key: "f", value: (0, murmur_1.default)(fingerprint_1.default.prepareF(fingerprint_1.default), 31) }, + { + key: "n", + value: Buffer.from(Math.round(Date.now() / (1000 - 0)).toString()).toString("base64"), + }, + { key: "wh", value: `${random()}|${random()}` }, + { + "key": "enhanced_fp", + "value": fingerprint_1.default.getEnhancedFingerprint(fp, userAgent, opts) + }, + { key: "fe", value: fe }, + { key: "ife_hash", value: (0, murmur_1.default)(fe.join(", "), 38) }, + { key: "cs", value: 1 }, + { + key: "jsbd", + value: JSON.stringify({ + HL: 4, + DT: "", + NWD: "false", + DOTO: 1, + DMTO: 1, + }), + }, + ]; + let time = new Date().getTime() / 1000; + let key = userAgent + Math.round(time - (time % 21600)); + let s = JSON.stringify(bda); + let encrypted = crypt_1.default.encrypt(s, key); + return Buffer.from(encrypted).toString("base64"); +} +function solveBreaker(v2, breaker = "default", gameType, value) { + if (!v2 && typeof breaker === "string") + return (apiBreakers.v1[gameType][breaker || "default"] || ((v) => v))(value); + if (typeof breaker !== "string") { + let b = apiBreakers.v2[gameType]; + let v = breaker.value.reduce((acc, cur) => { + if (b.value[cur]) + return b.value[cur](acc); + else + return cur; + }, value); + return b.key[breaker.key](v); + } + else { + return value; + } +} +exports.default = { + DEFAULT_USER_AGENT, + tileToLoc, + constructFormData, + getBda, + apiBreakers, + getTimestamp, + random, + solveBreaker +}; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/package.json b/g4f/Provider/npm/node_modules/funcaptcha/package.json new file mode 100644 index 00000000..0757938a --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/package.json @@ -0,0 +1,27 @@ +{ + "name": "funcaptcha", + "version": "1.1.7", + "description": "A library used to interact with funcaptchas.", + "author": "noahcoolboy", + "license": "MIT", + "keywords": [ + "funcaptcha" + ], + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "rimraf lib && tsc", + "test": "node test/test.js", + "benchmark": "node test/benchmark.js", + "roblox": "node test/roblox.js" + }, + "dependencies": { + "undici": "^5.22.0" + }, + "devDependencies": { + "@types/node": "^17.0.42", + "rimraf": "^3.0.2", + "typescript": "^4.7.4" + }, + "repository": "github:noahcoolboy/funcaptcha" +} diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/api.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/api.ts new file mode 100644 index 00000000..6582750d --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/api.ts @@ -0,0 +1,85 @@ +import request from "./http"; +import util from "./util"; + +export interface GetTokenOptions { + pkey: string; + // Service URL + surl?: string; + data?: { [key: string]: string }; + headers?: { [key: string]: string }; + site?: string; + // Page URL + location?: string; + proxy?: string; + language?: string; +} + +export interface GetTokenResult { + challenge_url: string; + challenge_url_cdn: string; + challenge_url_cdn_sri: string; + disable_default_styling: boolean | null; + iframe_height: number | null; + iframe_width: number | null; + // Enable keyboard biometrics + kbio: boolean; + // Enable mouse biometrics + mbio: boolean; + noscript: string; + // Enable touch biometrics + tbio: boolean; + // The token for the funcaptcha. Can be used 10 times before having to get a new token. + token: string; +} + +export async function getToken( + options: GetTokenOptions +): Promise<GetTokenResult> { + options = { + surl: "https://client-api.arkoselabs.com", + data: {}, + ...options, + }; + + if (!options.headers) + options.headers = { "User-Agent": util.DEFAULT_USER_AGENT }; + else if (!Object.keys(options.headers).map(v => v.toLowerCase()).includes("user-agent")) + options.headers["User-Agent"] = util.DEFAULT_USER_AGENT; + + options.headers["Accept-Language"] = "en-US,en;q=0.9"; + options.headers["Sec-Fetch-Site"] = "same-origin"; + options.headers["Accept"] = "*/*"; + options.headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"; + options.headers["sec-fetch-mode"] = "cors" + + if (options.site) { + options.headers["Origin"] = options.surl + options.headers["Referer"] = `${options.surl}/v2/${options.pkey}/1.5.5/enforcement.fbfc14b0d793c6ef8359e0e4b4a91f67.html` + } + + let ua = options.headers[Object.keys(options.headers).find(v => v.toLowerCase() == "user-agent")] + + let res = await request( + options.surl, + { + method: "POST", + path: "/fc/gt2/public_key/" + options.pkey, + body: util.constructFormData({ + bda: util.getBda(ua, options), + public_key: options.pkey, + site: options.site ? new URL(options.site).origin : undefined, + userbrowser: ua, + capi_version: "1.5.5", + capi_mode: "inline", + style_theme: "default", + rnd: Math.random().toString(), + ...Object.fromEntries(Object.keys(options.data).map(v => ["data[" + v + "]", options.data[v]])), + language: options.language || "en", + }), + headers: options.headers, + }, + options.proxy + ); + + return JSON.parse(res.body.toString()); +} diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/challenge.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/challenge.ts new file mode 100644 index 00000000..40090c4a --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/challenge.ts @@ -0,0 +1,296 @@ +import request from "./http"; +import { TokenInfo } from "./session"; +import util from "./util"; +import crypt from "./crypt"; +import { assert } from "console"; + +interface ChallengeOptions { + userAgent?: string; + proxy?: string; +} + +interface ChallengeData { + token: string; + tokenInfo: TokenInfo; + session_token: string; + challengeID: string; + challengeURL: string; + game_data: { + gameType: number; + customGUI: { + is_using_api_breaker_v2: boolean; + _guiFontColr: string; + _challenge_imgs: string[]; + api_breaker: string; + encrypted_mode: number; + example_images: { + correct: string; + incorrect: string; + } + }; + waves: number; + game_variant?: string; // For gametype 3 + game_difficulty?: number; + puzzle_name?: string; // For gametype 4 + instruction_string?: string; // For gametype 4 + }; + game_sid: string; + lang: string; + string_table: { + [key: string]: string; + }, + string_table_prefixes: string[] +} + +interface AnswerResponse { + response: "not answered" | "answered"; + solved?: boolean; + incorrect_guess?: number; + score?: number; + decryption_key?: string; + time_end?: number; + time_end_seconds?: number; +} + +export abstract class Challenge { + public data: ChallengeData; + public imgs: Promise<Buffer>[]; + public wave: number = 0; + protected key: Promise<string>; + protected userAgent: string; + protected proxy: string; + + constructor(data: ChallengeData, challengeOptions: ChallengeOptions) { + this.data = data; + this.userAgent = challengeOptions.userAgent; + this.proxy = challengeOptions.proxy; + + // Preload images + this.imgs = data.game_data.customGUI._challenge_imgs.map(async (v) => { + let req = await request(v, { + method: "GET", + path: undefined, + headers: { + "User-Agent": this.userAgent, + "Referer": this.data.tokenInfo.surl + }, + }); + return req.body; + }); + + if(data.game_data.customGUI.encrypted_mode) { + // Preload decryption key + this.key = this.getKey(); + } + } + + async getImage(): Promise<Buffer> { + let img = await this.imgs[this.wave]; + try { + JSON.parse(img.toString()); // Image is encrypted + img = Buffer.from( + await crypt.decrypt(img.toString(), await this.getKey()), + "base64" + ); + } catch (err) { + // Image is not encrypted + // All good! + } + return img; + } + + protected async getKey() { + if (this.key) return await this.key; + let response = await request( + this.data.tokenInfo.surl, + { + method: "POST", + path: "/fc/ekey/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "Referer": this.data.tokenInfo.surl, + }, + body: util.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + }), + }, + this.proxy + ); + this.key = JSON.parse(response.body.toString()).decryption_key; + return this.key; + } + + abstract answer(answer: number): Promise<AnswerResponse>; + + get gameType() { + return this.data.game_data.gameType; + } + + get variant() { + return this.data.game_data.game_variant || this.data.game_data.instruction_string; + } + + get instruction() { + return this.data.string_table[`${this.data.game_data.gameType}.instructions-${this.variant}`] || this.data.string_table[`${this.data.game_data.gameType}.touch_done_info${this.data.game_data.game_variant ? `_${this.data.game_data.game_variant}` : ""}`]; + } + + get waves() { + return this.data.game_data.waves; + } +} + +export class Challenge1 extends Challenge { + private answerHistory = []; + public increment; + + constructor(data: ChallengeData, challengeOptions: ChallengeOptions) { + super(data, challengeOptions); + + // But WHY?! + let clr = data.game_data.customGUI._guiFontColr + this.increment = parseInt(clr ? clr.replace("#", "").substring(3) : "28", 16) + this.increment = this.increment > 113 ? this.increment / 10 : this.increment + } + + private round(num: number): string { + return (Math.round(num * 10) / 10).toFixed(2); + } + + async answer(answer: number): Promise<AnswerResponse> { + if(answer >= 0 && answer <= Math.round(360 / 51.4) - 1) + this.answerHistory.push(this.round(answer * this.increment)); + else + this.answerHistory.push(this.round(answer)) + + let encrypted = await crypt.encrypt( + this.answerHistory.toString(), + this.data.session_token + ); + let req = await request( + this.data.tokenInfo.surl, + { + method: "POST", + path: "/fc/ca/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "Referer": this.data.challengeURL + }, + body: util.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + guess: encrypted, + }), + }, + this.proxy + ); + let reqData = JSON.parse(req.body.toString()); + this.key = reqData.decryption_key || ""; + this.wave++; + return reqData; + } +} + +export class Challenge3 extends Challenge { + private answerHistory = []; + + constructor(data: ChallengeData, challengeOptions: ChallengeOptions) { + super(data, challengeOptions); + } + + async answer(tile: number): Promise<AnswerResponse> { + assert(tile >= 0 && tile <= 5, "Tile must be between 0 and 5"); + + let pos = util.tileToLoc(tile); + this.answerHistory.push(util.solveBreaker(!!this.data.game_data.customGUI.is_using_api_breaker_v2, this.data.game_data.customGUI.api_breaker, 3, pos)) + + let encrypted = await crypt.encrypt( + JSON.stringify(this.answerHistory), + this.data.session_token + ); + let requestedId = await crypt.encrypt(JSON.stringify({}), `REQUESTED${this.data.session_token}ID`); + let { cookie: tCookie, value: tValue } = util.getTimestamp(); + let req = await request( + this.data.tokenInfo.surl, + { + method: "POST", + path: "/fc/ca/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "X-Newrelic-Timestamp": tValue, + "X-Requested-ID": requestedId, + "Cookie": tCookie, + "Referer": this.data.challengeURL + }, + body: util.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + guess: encrypted, + analytics_tier: this.data.tokenInfo.at, + sid: this.data.tokenInfo.r, + bio: this.data.tokenInfo.mbio && "eyJtYmlvIjoiMTI1MCwwLDE0NywyMDQ7MTg5NCwwLDE1MSwyMDA7MTk2MCwxLDE1MiwxOTk7MjAyOSwyLDE1MiwxOTk7MjU3NSwwLDE1NSwxOTU7MjU4NSwwLDE1NiwxOTA7MjU5NSwwLDE1OCwxODU7MjYwNCwwLDE1OSwxODA7MjYxMywwLDE2MCwxNzU7MjYyMSwwLDE2MSwxNzA7MjYzMCwwLDE2MywxNjU7MjY0MCwwLDE2NCwxNjA7MjY1MCwwLDE2NSwxNTU7MjY2NCwwLDE2NiwxNTA7MjY3NywwLDE2NiwxNDQ7MjY5NCwwLDE2NywxMzk7MjcyMCwwLDE2NywxMzM7Mjc1NCwwLDE2NywxMjc7Mjc4MywwLDE2NywxMjE7MjgxMiwwLDE2NywxMTU7Mjg0MywwLDE2NywxMDk7Mjg2MywwLDE2NywxMDM7Mjg3NSwwLDE2Niw5ODsyOTA1LDAsMTY1LDkzOzMyMzIsMCwxNjUsOTk7MzI2MiwwLDE2NSwxMDU7MzI5OSwwLDE2NCwxMTA7MzM0MCwwLDE2MSwxMTU7MzM3MiwwLDE1NywxMjA7MzM5NSwwLDE1MywxMjQ7MzQwOCwwLDE0OCwxMjc7MzQyMCwwLDE0MywxMzA7MzQyOSwwLDEzOCwxMzE7MzQ0MSwwLDEzMywxMzQ7MzQ1MCwwLDEyOCwxMzU7MzQ2MSwwLDEyMywxMzg7MzQ3NiwwLDExOCwxNDA7MzQ4OSwwLDExMywxNDI7MzUwMywwLDEwOCwxNDM7MzUxOCwwLDEwMywxNDQ7MzUzNCwwLDk4LDE0NTszNTU2LDAsOTMsMTQ2OzM2MTUsMCw4OCwxNDg7MzY2MiwwLDgzLDE1MTszNjgzLDAsNzgsMTU0OzM3MDEsMCw3MywxNTc7MzcyNSwwLDY5LDE2MTszNzkzLDEsNjgsMTYyOzM4NTEsMiw2OCwxNjI7IiwidGJpbyI6IiIsImtiaW8iOiIifQ==" + }), + }, + this.proxy + ); + let reqData = JSON.parse(req.body.toString()); + this.key = reqData.decryption_key || ""; + this.wave++; + return reqData; + } +} + +export class Challenge4 extends Challenge { + private answerHistory = []; + + constructor(data: ChallengeData, challengeOptions: ChallengeOptions) { + super(data, challengeOptions); + } + + async answer(index: number): Promise<AnswerResponse> { + assert(index >= 0 && index <= this.data.game_data.game_difficulty - 1, "Index must be between 0 and " + (this.data.game_data.game_difficulty - 1)); + this.answerHistory.push(util.solveBreaker(!!this.data.game_data.customGUI.is_using_api_breaker_v2, this.data.game_data.customGUI.api_breaker, 4, { index })) + + let encrypted = await crypt.encrypt( + JSON.stringify(this.answerHistory), + this.data.session_token + ); + let requestedId = await crypt.encrypt(JSON.stringify({}), `REQUESTED${this.data.session_token}ID`); + let { cookie: tCookie, value: tValue } = util.getTimestamp(); + let req = await request( + this.data.tokenInfo.surl, + { + method: "POST", + path: "/fc/ca/", + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "X-Newrelic-Timestamp": tValue, + "X-Requested-ID": requestedId, + "Cookie": tCookie, + "Referer": this.data.challengeURL + }, + body: util.constructFormData({ + session_token: this.data.session_token, + game_token: this.data.challengeID, + guess: encrypted, + analytics_tier: this.data.tokenInfo.at, + sid: this.data.tokenInfo.r, + bio: this.data.tokenInfo.mbio && "eyJtYmlvIjoiMTI1MCwwLDE0NywyMDQ7MTg5NCwwLDE1MSwyMDA7MTk2MCwxLDE1MiwxOTk7MjAyOSwyLDE1MiwxOTk7MjU3NSwwLDE1NSwxOTU7MjU4NSwwLDE1NiwxOTA7MjU5NSwwLDE1OCwxODU7MjYwNCwwLDE1OSwxODA7MjYxMywwLDE2MCwxNzU7MjYyMSwwLDE2MSwxNzA7MjYzMCwwLDE2MywxNjU7MjY0MCwwLDE2NCwxNjA7MjY1MCwwLDE2NSwxNTU7MjY2NCwwLDE2NiwxNTA7MjY3NywwLDE2NiwxNDQ7MjY5NCwwLDE2NywxMzk7MjcyMCwwLDE2NywxMzM7Mjc1NCwwLDE2NywxMjc7Mjc4MywwLDE2NywxMjE7MjgxMiwwLDE2NywxMTU7Mjg0MywwLDE2NywxMDk7Mjg2MywwLDE2NywxMDM7Mjg3NSwwLDE2Niw5ODsyOTA1LDAsMTY1LDkzOzMyMzIsMCwxNjUsOTk7MzI2MiwwLDE2NSwxMDU7MzI5OSwwLDE2NCwxMTA7MzM0MCwwLDE2MSwxMTU7MzM3MiwwLDE1NywxMjA7MzM5NSwwLDE1MywxMjQ7MzQwOCwwLDE0OCwxMjc7MzQyMCwwLDE0MywxMzA7MzQyOSwwLDEzOCwxMzE7MzQ0MSwwLDEzMywxMzQ7MzQ1MCwwLDEyOCwxMzU7MzQ2MSwwLDEyMywxMzg7MzQ3NiwwLDExOCwxNDA7MzQ4OSwwLDExMywxNDI7MzUwMywwLDEwOCwxNDM7MzUxOCwwLDEwMywxNDQ7MzUzNCwwLDk4LDE0NTszNTU2LDAsOTMsMTQ2OzM2MTUsMCw4OCwxNDg7MzY2MiwwLDgzLDE1MTszNjgzLDAsNzgsMTU0OzM3MDEsMCw3MywxNTc7MzcyNSwwLDY5LDE2MTszNzkzLDEsNjgsMTYyOzM4NTEsMiw2OCwxNjI7IiwidGJpbyI6IiIsImtiaW8iOiIifQ==" + }), + }, + this.proxy + ); + let reqData = JSON.parse(req.body.toString()); + this.key = reqData.decryption_key || ""; + this.wave++; + return reqData; + } + + get difficulty(): number { + return this.data.game_data.game_difficulty; + } +}
\ No newline at end of file diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/crypt.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/crypt.ts new file mode 100644 index 00000000..fb883660 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/crypt.ts @@ -0,0 +1,78 @@ +import { createHash, createCipheriv, createDecipheriv } from "crypto"; + +interface EncryptionData { + ct: string; + iv: string; + s: string; +} + +function encrypt(data: string, key: string): string { + let salt = ""; + let salted = ""; + let dx = Buffer.alloc(0); + + // Generate salt, as 8 random lowercase letters + salt = String.fromCharCode(...Array(8).fill(0).map(_ => Math.floor(Math.random() * 26) + 97)) + + // Our final key and iv come from the key and salt being repeatedly hashed + // dx = md5(md5(md5(key + salt) + key + salt) + key + salt) + // For each round of hashing, we append the result to salted, resulting in a 96 character string + // The first 64 characters are the key, and the last 32 are the iv + for (let x = 0; x < 3; x++) { + dx = createHash("md5") + .update( + Buffer.concat([ + Buffer.from(dx), + Buffer.from(key), + Buffer.from(salt), + ]) + ) + .digest(); + + salted += dx.toString("hex"); + } + + let aes = createCipheriv( + "aes-256-cbc", + Buffer.from(salted.substring(0, 64), "hex"), // Key + Buffer.from(salted.substring(64, 64 + 32), "hex") // IV + ); + + return JSON.stringify({ + ct: aes.update(data, null, "base64") + aes.final("base64"), + iv: salted.substring(64, 64 + 32), + s: Buffer.from(salt).toString("hex"), + }); +} + +function decrypt(rawData: string, key: string): string { + let data: EncryptionData = JSON.parse(rawData); + + // We get our decryption key by doing the inverse of the encryption process + let dk = Buffer.concat([Buffer.from(key), Buffer.from(data.s, "hex")]); + let arr = [Buffer.from(createHash("md5").update(dk).digest()).toString("hex")]; + let result = arr[0]; + + for (let x = 1; x < 3; x++) { + arr.push( + Buffer.from( + createHash("md5") + .update(Buffer.concat([Buffer.from(arr[x - 1], "hex"), dk])) + .digest() + ).toString("hex") + ); + result += arr[x]; + } + + let aes = createDecipheriv( + "aes-256-cbc", + Buffer.from(result.substring(0, 64), "hex"), + Buffer.from(data.iv, "hex") + ); + return aes.update(data.ct, "base64", "utf8") + aes.final("utf8"); +} + +export default { + encrypt, + decrypt, +}; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/fingerprint.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/fingerprint.ts new file mode 100644 index 00000000..b4d24ea2 --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/fingerprint.ts @@ -0,0 +1,321 @@ +import x64hash128 from "./murmur"; +import { randomBytes } from "crypto"; + +const baseFingerprint = { + DNT: "unknown", // Do not track On/Off | Previous Value: 1 + L: "en-US", // Browser language + D: 24, // Screen color depth (in bits) + PR: 1, // Pixel ratio + S: [1920, 1200], // Screen resolution + AS: [1920, 1200], // Available screen resolution + TO: 9999, // Timezone offset + SS: true, // Screen orientation (landscape/portrait) + LS: true, // Local storage available + IDB: true, // IndexedDB available + B: false, // addBehaviour support + ODB: true, // OpenDatabase support + CPUC: "unknown", // CPU Class + PK: "Win32", // Platform + CFP: `canvas winding:yes~canvas fp:data:image/png;base64,${Buffer.from( + Math.random().toString() + ).toString("base64")}`, // Canvas fingerprint (if canvas is supported) + FR: false, // Fake screen resolution? + FOS: false, // Fake OS? + FB: false, // Fake Browser? + JSF: [ + "Andale Mono", + "Arial", + "Arial Black", + "Arial Hebrew", + "Arial MT", + "Arial Narrow", + "Arial Rounded MT Bold", + "Arial Unicode MS", + "Bitstream Vera Sans Mono", + "Book Antiqua", + "Bookman Old Style", + "Calibri", + "Cambria", + "Cambria Math", + "Century", + "Century Gothic", + "Century Schoolbook", + "Comic Sans", + "Comic Sans MS", + "Consolas", + "Courier", + "Courier New", + "Garamond", + "Geneva", + "Georgia", + "Helvetica", + "Helvetica Neue", + "Impact", + "Lucida Bright", + "Lucida Calligraphy", + "Lucida Console", + "Lucida Fax", + "LUCIDA GRANDE", + "Lucida Handwriting", + "Lucida Sans", + "Lucida Sans Typewriter", + "Lucida Sans Unicode", + "Microsoft Sans Serif", + "Monaco", + "Monotype Corsiva", + "MS Gothic", + "MS Outlook", + "MS PGothic", + "MS Reference Sans Serif", + "MS Sans Serif", + "MS Serif", + "MYRIAD", + "MYRIAD PRO", + "Palatino", + "Palatino Linotype", + "Segoe Print", + "Segoe Script", + "Segoe UI", + "Segoe UI Light", + "Segoe UI Semibold", + "Segoe UI Symbol", + "Tahoma", + "Times", + "Times New Roman", + "Times New Roman PS", + "Trebuchet MS", + "Verdana", + "Wingdings", + "Wingdings 2", + "Wingdings 3", + ], // Available fonts + P: [ + "Chrome PDF Plugin::Portable Document Format::application/x-google-chrome-pdf~pdf", + "Chrome PDF Viewer::::application/pdf~pdf", + "Native Client::::application/x-nacl~,application/x-pnacl~", + ], // Plugins + T: [0, false, false], // Touch screen (maxTouchPoints, TouchEvent event listener support, ontouchstart support) + H: 24, // Cpu threads + SWF: false, // Flash support +}; + +const languages = [ + "af", "af-ZA", "ar", "ar-AE", "ar-BH", "ar-DZ", "ar-EG", "ar-IQ", "ar-JO", "ar-KW", "ar-LB", "ar-LY", "ar-MA", "ar-OM", "ar-QA", "ar-SA", + "ar-SY", "ar-TN", "ar-YE", "az", "az-AZ", "az-AZ", "be", "be-BY", "bg", "bg-BG", "bs-BA", "ca", "ca-ES", "cs", "cs-CZ", "cy", + "cy-GB", "da", "da-DK", "de", "de-AT", "de-CH", "de-DE", "de-LI", "de-LU", "dv", "dv-MV", "el", "el-GR", "en", "en-AU", "en-BZ", + "en-CA", "en-CB", "en-GB", "en-IE", "en-JM", "en-NZ", "en-PH", "en-TT", "en-US", "en-ZA", "en-ZW", "eo", "es", "es-AR", "es-BO", "es-CL", + "es-CO", "es-CR", "es-DO", "es-EC", "es-ES", "es-ES", "es-GT", "es-HN", "es-MX", "es-NI", "es-PA", "es-PE", "es-PR", "es-PY", "es-SV", "es-UY", + "es-VE", "et", "et-EE", "eu", "eu-ES", "fa", "fa-IR", "fi", "fi-FI", "fo", "fo-FO", "fr", "fr-BE", "fr-CA", "fr-CH", "fr-FR", + "fr-LU", "fr-MC", "gl", "gl-ES", "gu", "gu-IN", "he", "he-IL", "hi", "hi-IN", "hr", "hr-BA", "hr-HR", "hu", "hu-HU", "hy", + "hy-AM", "id", "id-ID", "is", "is-IS", "it", "it-CH", "it-IT", "ja", "ja-JP", "ka", "ka-GE", "kk", "kk-KZ", "kn", "kn-IN", + "ko", "ko-KR", "kok", "kok-IN", "ky", "ky-KG", "lt", "lt-LT", "lv", "lv-LV", "mi", "mi-NZ", "mk", "mk-MK", "mn", "mn-MN", + "mr", "mr-IN", "ms", "ms-BN", "ms-MY", "mt", "mt-MT", "nb", "nb-NO", "nl", "nl-BE", "nl-NL", "nn-NO", "ns", "ns-ZA", "pa", + "pa-IN", "pl", "pl-PL", "ps", "ps-AR", "pt", "pt-BR", "pt-PT", "qu", "qu-BO", "qu-EC", "qu-PE", "ro", "ro-RO", "ru", "ru-RU", + "sa", "sa-IN", "se", "se-FI", "se-FI", "se-FI", "se-NO", "se-NO", "se-NO", "se-SE", "se-SE", "se-SE", "sk", "sk-SK", "sl", "sl-SI", + "sq", "sq-AL", "sr-BA", "sr-BA", "sr-SP", "sr-SP", "sv", "sv-FI", "sv-SE", "sw", "sw-KE", "syr", "syr-SY", "ta", "ta-IN", "te", + "te-IN", "th", "th-TH", "tl", "tl-PH", "tn", "tn-ZA", "tr", "tr-TR", "tt", "tt-RU", "ts", "uk", "uk-UA", "ur", "ur-PK", + "uz", "uz-UZ", "uz-UZ", "vi", "vi-VN", "xh", "xh-ZA", "zh", "zh-CN", "zh-HK", "zh-MO", "zh-SG", "zh-TW", "zu", "zu-ZA" +]; + +let screenRes = [ + [1920, 1080], + [1920, 1200], + [2048, 1080], + [2560, 1440], + [1366, 768], + [1440, 900], + [1536, 864], + [1680, 1050], + [1280, 1024], + [1280, 800], + [1280, 720], + [1600, 1200], + [1600, 900], +]; +function randomScreenRes() { + return screenRes[Math.floor(Math.random() * screenRes.length)]; +} + +// Get fingerprint +function getFingerprint() { + let fingerprint = { ...baseFingerprint }; // Create a copy of the base fingerprint + + // Randomization time! + fingerprint["DNT"] = "unknown"; + fingerprint["L"] = languages[Math.floor(Math.random() * languages.length)]; + fingerprint["D"] = [8, 24][ + Math.floor(Math.random() * 2) + ]; + fingerprint["PR"] = Math.round(Math.random() * 100) / 100 * 2 + 0.5; + fingerprint["S"] = randomScreenRes(); + fingerprint["AS"] = fingerprint.S; + fingerprint["TO"] = (Math.floor(Math.random() * 24) - 12) * 60; + fingerprint["SS"] = Math.random() > 0.5; + fingerprint["LS"] = Math.random() > 0.5; + fingerprint["IDB"] = Math.random() > 0.5; + fingerprint["B"] = Math.random() > 0.5; + fingerprint["ODB"] = Math.random() > 0.5; + fingerprint["CPUC"] = "unknown"; + fingerprint["PK"] = "Win32" + fingerprint["CFP"] = "canvas winding:yes~canvas fp:data:image/png;base64," + randomBytes(128).toString("base64"); + fingerprint["FR"] = false; // Fake Resolution + fingerprint["FOS"] = false; // Fake Operating System + fingerprint["FB"] = false; // Fake Browser + fingerprint["JSF"] = fingerprint["JSF"].filter(() => Math.random() > 0.5); + fingerprint["P"] = fingerprint["P"].filter(() => Math.random() > 0.5); + fingerprint["T"] = [ + Math.floor(Math.random() * 8), + Math.random() > 0.5, + Math.random() > 0.5, + ]; + fingerprint["H"] = 2 ** Math.floor(Math.random() * 6); + fingerprint["SWF"] = fingerprint["SWF"]; // RIP Flash + + return fingerprint; +} + +function prepareF(fingerprint) { + let f = []; + let keys = Object.keys(fingerprint); + for (let i = 0; i < keys.length; i++) { + if (fingerprint[keys[i]].join) f.push(fingerprint[keys[i]].join(";")); + else f.push(fingerprint[keys[i]]); + } + return f.join("~~~"); +} + +function prepareFe(fingerprint) { + let fe = []; + let keys = Object.keys(fingerprint); + for (let i = 0; i < keys.length; i++) { + switch (keys[i]) { + case "CFP": + fe.push(`${keys[i]}:${cfpHash(fingerprint[keys[i]])}`); + break; + case "P": + fe.push( + `${keys[i]}:${fingerprint[keys[i]].map( + (v) => v.split("::")[0] + )}` + ); + break; + default: + fe.push(`${keys[i]}:${fingerprint[keys[i]]}`); + break; + } + } + return fe; +} + +function cfpHash(H8W) { + var l8W, U8W; + if (!H8W) return ""; + if (Array.prototype.reduce) + return H8W.split("").reduce(function (p8W, z8W) { + p8W = (p8W << 5) - p8W + z8W.charCodeAt(0); + return p8W & p8W; + }, 0); + l8W = 0; + if (H8W.length === 0) return l8W; + for (var k8W = 0; k8W < H8W.length; k8W++) { + U8W = H8W.charCodeAt(k8W); + l8W = (l8W << 5) - l8W + U8W; + l8W = l8W & l8W; + } + return l8W; +} + +let baseEnhancedFingerprint = { + "webgl_extensions": "ANGLE_instanced_arrays;EXT_blend_minmax;EXT_color_buffer_half_float;EXT_disjoint_timer_query;EXT_float_blend;EXT_frag_depth;EXT_shader_texture_lod;EXT_texture_compression_bptc;EXT_texture_compression_rgtc;EXT_texture_filter_anisotropic;EXT_sRGB;KHR_parallel_shader_compile;OES_element_index_uint;OES_fbo_render_mipmap;OES_standard_derivatives;OES_texture_float;OES_texture_float_linear;OES_texture_half_float;OES_texture_half_float_linear;OES_vertex_array_object;WEBGL_color_buffer_float;WEBGL_compressed_texture_s3tc;WEBGL_compressed_texture_s3tc_srgb;WEBGL_debug_renderer_info;WEBGL_debug_shaders;WEBGL_depth_texture;WEBGL_draw_buffers;WEBGL_lose_context;WEBGL_multi_draw", + "webgl_extensions_hash": "58a5a04a5bef1a78fa88d5c5098bd237", + "webgl_renderer": "WebKit WebGL", + "webgl_vendor": "WebKit", + "webgl_version": "WebGL 1.0 (OpenGL ES 2.0 Chromium)", + "webgl_shading_language_version": "WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)", + "webgl_aliased_line_width_range": "[1, 1]", + "webgl_aliased_point_size_range": "[1, 1023]", + "webgl_antialiasing": "yes", + "webgl_bits": "8,8,24,8,8,0", + "webgl_max_params": "16,64,16384,4096,8192,32,8192,31,16,32,4096", + "webgl_max_viewport_dims": "[8192, 8192]", + "webgl_unmasked_vendor": "Google Inc. (Google)", + "webgl_unmasked_renderer": "ANGLE (Google, Vulkan 1.3.0 (SwiftShader Device (Subzero) (0x0000C0DE)), SwiftShader driver)", + "webgl_vsf_params": "23,127,127,23,127,127,23,127,127", + "webgl_vsi_params": "0,31,30,0,31,30,0,31,30", + "webgl_fsf_params": "23,127,127,23,127,127,23,127,127", + "webgl_fsi_params": "0,31,30,0,31,30,0,31,30", + "webgl_hash_webgl": null, + "user_agent_data_brands": "Chromium,Google Chrome,Not=A?Brand", + "user_agent_data_mobile": null, + "navigator_connection_downlink": null, + "navigator_connection_downlink_max": null, + "network_info_rtt": null, + "network_info_save_data": false, + "network_info_rtt_type": null, + "screen_pixel_depth": 24, + "navigator_device_memory": 0.5, + "navigator_languages": "en-US,fr-BE,fr,en-BE,en", + "window_inner_width": 0, + "window_inner_height": 0, + "window_outer_width": 2195, + "window_outer_height": 1195, + "browser_detection_firefox": false, + "browser_detection_brave": false, + "audio_codecs": "{\"ogg\":\"probably\",\"mp3\":\"probably\",\"wav\":\"probably\",\"m4a\":\"maybe\",\"aac\":\"probably\"}", + "video_codecs": "{\"ogg\":\"probably\",\"h264\":\"probably\",\"webm\":\"probably\",\"mpeg4v\":\"\",\"mpeg4a\":\"\",\"theora\":\"\"}", + "media_query_dark_mode": true, + "headless_browser_phantom": false, + "headless_browser_selenium": false, + "headless_browser_nightmare_js": false, + "document__referrer": "https://www.roblox.com/", + "window__ancestor_origins": [ + "https://www.roblox.com", + ], + "window__tree_index": [ + 0 + ], + "window__tree_structure": "[[]]", + "window__location_href": "https://roblox-api.arkoselabs.com/v2/1.5.5/enforcement.fbfc14b0d793c6ef8359e0e4b4a91f67.html#476068BF-9607-4799-B53D-966BE98E2B81", + "client_config__sitedata_location_href": "https://www.roblox.com/arkose/iframe", + "client_config__surl": "https://roblox-api.arkoselabs.com", + "client_config__language": null, + "navigator_battery_charging": true, + "audio_fingerprint": "124.04347527516074" +} +function getEnhancedFingerprint(fp: typeof baseFingerprint, ua: string, opts: any) { + let fingerprint = { ...baseEnhancedFingerprint }; + + fingerprint.webgl_extensions = fingerprint.webgl_extensions.split(";").filter(_ => Math.random() > 0.5).join(";"); + fingerprint.webgl_extensions_hash = x64hash128(fingerprint.webgl_extensions, 0); + fingerprint.screen_pixel_depth = fp.D; + fingerprint.navigator_languages = fp.L; + fingerprint.window_outer_height = fp.S[0]; + fingerprint.window_outer_width = fp.S[1]; + fingerprint.window_inner_height = fp.S[0]; + fingerprint.window_inner_width = fp.S[1]; + fingerprint.screen_pixel_depth = fp.D; + fingerprint.browser_detection_firefox = !!ua.match(/Firefox\/\d+/) + fingerprint.browser_detection_brave = !!ua.match(/Brave\/\d+/) + fingerprint.media_query_dark_mode = Math.random() > 0.9; + fingerprint.webgl_hash_webgl = x64hash128(Object.entries(fingerprint).filter(([k, v]) => k.startsWith("webgl_") && k != "webgl_hash_webgl").map(([k, v]) => v).join(","), 0); + + fingerprint.client_config__language = opts.language || null; + fingerprint.window__location_href = `${opts.surl}/v2/1.5.5/enforcement.fbfc14b0d793c6ef8359e0e4b4a91f67.html#${opts.pkey}` + if (opts.site) { + fingerprint.document__referrer = opts.site; + fingerprint.window__ancestor_origins = [opts.site]; + fingerprint.client_config__sitedata_location_href = opts.site; + } + + fingerprint.client_config__surl = opts.surl || "https://client-api.arkoselabs.com"; + fingerprint.audio_fingerprint = (124.04347527516074 + Math.random() * 0.001 - 0.0005).toString(); + + return Object.entries(fingerprint).map(([k, v]) => ({ key: k, value: v })); +} + +export default { + getFingerprint, + prepareF, + prepareFe, + getEnhancedFingerprint, +}; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/http.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/http.ts new file mode 100644 index 00000000..e0fa3acb --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/http.ts @@ -0,0 +1,28 @@ +import { request, ProxyAgent } from "undici"; +// @ts-ignore +import { RequestOptions } from "undici/types/dispatcher"; + +async function req(url: string, options: RequestOptions, proxy?: string) { + let auth = undefined; + if (proxy) { + let proxyUrl = new URL(proxy); + if(proxyUrl.username && proxyUrl.password) { + auth = Buffer.from(proxyUrl.username + ":" + proxyUrl.password).toString("base64") + } + } + let dispatcher = proxy ? new ProxyAgent({ + uri: proxy, + auth + }) : undefined; + + let req = await request(url, { + ...options, + dispatcher, + }); + return { + headers: req.headers, + body: Buffer.from(await req.body.arrayBuffer()), + }; +} + +export default req; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/index.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/index.ts new file mode 100644 index 00000000..97b1212a --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/index.ts @@ -0,0 +1,2 @@ +export * from "./api"; +export * from "./session"; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/murmur.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/murmur.ts new file mode 100644 index 00000000..32750f3d --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/murmur.ts @@ -0,0 +1,205 @@ +// MurmurHash3 related functions +// https://github.com/markogresak/fingerprintjs2/blob/master/src/x64hash128.js + +// Given two 64bit ints (as an array of two 32bit ints) returns the two +// added together as a 64bit int (as an array of two 32bit ints). +var x64Add = function (t, r) { + (t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]), + (r = [r[0] >>> 16, 65535 & r[0], r[1] >>> 16, 65535 & r[1]]); + var e = [0, 0, 0, 0]; + return ( + (e[3] += t[3] + r[3]), + (e[2] += e[3] >>> 16), + (e[3] &= 65535), + (e[2] += t[2] + r[2]), + (e[1] += e[2] >>> 16), + (e[2] &= 65535), + (e[1] += t[1] + r[1]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[0] += t[0] + r[0]), + (e[0] &= 65535), + [(e[0] << 16) | e[1], (e[2] << 16) | e[3]] + ); + }, + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // multiplied together as a 64bit int (as an array of two 32bit ints). + x64Multiply = function (t, r) { + (t = [t[0] >>> 16, 65535 & t[0], t[1] >>> 16, 65535 & t[1]]), + (r = [r[0] >>> 16, 65535 & r[0], r[1] >>> 16, 65535 & r[1]]); + var e = [0, 0, 0, 0]; + return ( + (e[3] += t[3] * r[3]), + (e[2] += e[3] >>> 16), + (e[3] &= 65535), + (e[2] += t[2] * r[3]), + (e[1] += e[2] >>> 16), + (e[2] &= 65535), + (e[2] += t[3] * r[2]), + (e[1] += e[2] >>> 16), + (e[2] &= 65535), + (e[1] += t[1] * r[3]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[1] += t[2] * r[2]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[1] += t[3] * r[1]), + (e[0] += e[1] >>> 16), + (e[1] &= 65535), + (e[0] += t[0] * r[3] + t[1] * r[2] + t[2] * r[1] + t[3] * r[0]), + (e[0] &= 65535), + [(e[0] << 16) | e[1], (e[2] << 16) | e[3]] + ); + }, + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) rotated left by that number of positions. + x64Rotl = function (t, r) { + return 32 === (r %= 64) + ? [t[1], t[0]] + : r < 32 + ? [ + (t[0] << r) | (t[1] >>> (32 - r)), + (t[1] << r) | (t[0] >>> (32 - r)), + ] + : ((r -= 32), + [ + (t[1] << r) | (t[0] >>> (32 - r)), + (t[0] << r) | (t[1] >>> (32 - r)), + ]); + }, + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) shifted left by that number of positions. + x64LeftShift = function (t, r) { + return 0 === (r %= 64) + ? t + : r < 32 + ? [(t[0] << r) | (t[1] >>> (32 - r)), t[1] << r] + : [t[1] << (r - 32), 0]; + }, + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // xored together as a 64bit int (as an array of two 32bit ints). + x64Xor = function (t, r) { + return [t[0] ^ r[0], t[1] ^ r[1]]; + }, + // Given a block, returns murmurHash3's final x64 mix of that block. + // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the + // only place where we need to right shift 64bit ints.) + x64Fmix = function (t) { + return ( + (t = x64Xor(t, [0, t[0] >>> 1])), + (t = x64Multiply(t, [4283543511, 3981806797])), + (t = x64Xor(t, [0, t[0] >>> 1])), + (t = x64Multiply(t, [3301882366, 444984403])), + (t = x64Xor(t, [0, t[0] >>> 1])) + ); + }, + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x64 flavor of MurmurHash3, as an unsigned hex. + x64hash128 = function (t, r) { + r = r || 0; + for ( + var e = (t = t || "").length % 16, + o = t.length - e, + x = [0, r], + c = [0, r], + h = [0, 0], + a = [0, 0], + d = [2277735313, 289559509], + i = [1291169091, 658871167], + l = 0; + l < o; + l += 16 + ) + (h = [ + (255 & t.charCodeAt(l + 4)) | + ((255 & t.charCodeAt(l + 5)) << 8) | + ((255 & t.charCodeAt(l + 6)) << 16) | + ((255 & t.charCodeAt(l + 7)) << 24), + (255 & t.charCodeAt(l)) | + ((255 & t.charCodeAt(l + 1)) << 8) | + ((255 & t.charCodeAt(l + 2)) << 16) | + ((255 & t.charCodeAt(l + 3)) << 24), + ]), + (a = [ + (255 & t.charCodeAt(l + 12)) | + ((255 & t.charCodeAt(l + 13)) << 8) | + ((255 & t.charCodeAt(l + 14)) << 16) | + ((255 & t.charCodeAt(l + 15)) << 24), + (255 & t.charCodeAt(l + 8)) | + ((255 & t.charCodeAt(l + 9)) << 8) | + ((255 & t.charCodeAt(l + 10)) << 16) | + ((255 & t.charCodeAt(l + 11)) << 24), + ]), + (h = x64Multiply(h, d)), + (h = x64Rotl(h, 31)), + (h = x64Multiply(h, i)), + (x = x64Xor(x, h)), + (x = x64Rotl(x, 27)), + (x = x64Add(x, c)), + (x = x64Add(x64Multiply(x, [0, 5]), [0, 1390208809])), + (a = x64Multiply(a, i)), + (a = x64Rotl(a, 33)), + (a = x64Multiply(a, d)), + (c = x64Xor(c, a)), + (c = x64Rotl(c, 31)), + (c = x64Add(c, x)), + (c = x64Add(x64Multiply(c, [0, 5]), [0, 944331445])); + switch (((h = [0, 0]), (a = [0, 0]), e)) { + case 15: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 14)], 48)); + case 14: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 13)], 40)); + case 13: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 12)], 32)); + case 12: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 11)], 24)); + case 11: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 10)], 16)); + case 10: + a = x64Xor(a, x64LeftShift([0, t.charCodeAt(l + 9)], 8)); + case 9: + (a = x64Xor(a, [0, t.charCodeAt(l + 8)])), + (a = x64Multiply(a, i)), + (a = x64Rotl(a, 33)), + (a = x64Multiply(a, d)), + (c = x64Xor(c, a)); + case 8: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 7)], 56)); + case 7: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 6)], 48)); + case 6: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 5)], 40)); + case 5: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 4)], 32)); + case 4: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 3)], 24)); + case 3: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 2)], 16)); + case 2: + h = x64Xor(h, x64LeftShift([0, t.charCodeAt(l + 1)], 8)); + case 1: + (h = x64Xor(h, [0, t.charCodeAt(l)])), + (h = x64Multiply(h, d)), + (h = x64Rotl(h, 31)), + (h = x64Multiply(h, i)), + (x = x64Xor(x, h)); + } + return ( + (x = x64Xor(x, [0, t.length])), + (c = x64Xor(c, [0, t.length])), + (x = x64Add(x, c)), + (c = x64Add(c, x)), + (x = x64Fmix(x)), + (c = x64Fmix(c)), + (x = x64Add(x, c)), + (c = x64Add(c, x)), + ("00000000" + (x[0] >>> 0).toString(16)).slice(-8) + + ("00000000" + (x[1] >>> 0).toString(16)).slice(-8) + + ("00000000" + (c[0] >>> 0).toString(16)).slice(-8) + + ("00000000" + (c[1] >>> 0).toString(16)).slice(-8) + ); + }; +export default x64hash128; diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/session.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/session.ts new file mode 100644 index 00000000..9244daae --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/session.ts @@ -0,0 +1,125 @@ +import { GetTokenResult } from "./api"; +import { Challenge, Challenge1, Challenge3, Challenge4 } from "./challenge"; +import http from "./http"; +import util from "./util"; + +export interface TokenInfo { + token: string; + r: string; + metabgclr: string; + mainbgclr: string; + guitextcolor: string; + metaiconclr: string; + meta_height: string; + meta_width: string; + meta: string; + pk: string; + dc: string; + at: string; + cdn_url: string; + lurl: string; + surl: string; + smurl: string; + // Enable keyboard biometrics + kbio: boolean; + // Enable mouse biometrics + mbio: boolean; + // Enable touch biometrics + tbio: boolean; +} + +export interface SessionOptions { + userAgent?: string; + proxy?: string; +} + +let parseToken = (token: string): TokenInfo => + Object.fromEntries( + token + .split("|") + .map((v) => v.split("=").map((v) => decodeURIComponent(v))) + ); + +export class Session { + public token: string; + public tokenInfo: TokenInfo; + private userAgent: string; + private proxy: string; + + constructor( + token: string | GetTokenResult, + sessionOptions?: SessionOptions + ) { + if (typeof token === "string") { + this.token = token; + } else { + this.token = token.token; + } + if (!this.token.startsWith("token=")) + this.token = "token=" + this.token; + + this.tokenInfo = parseToken(this.token); + this.tokenInfo.mbio = typeof(token) !== "string" ? token.mbio ?? false : false + this.userAgent = sessionOptions?.userAgent || util.DEFAULT_USER_AGENT; + this.proxy = sessionOptions?.proxy; + } + + async getChallenge(): Promise<Challenge> { + let res = await http( + this.tokenInfo.surl, + { + path: "/fc/gfct/", + method: "POST", + body: util.constructFormData({ + sid: this.tokenInfo.r, + render_type: "canvas", + token: this.tokenInfo.token, + analytics_tier: this.tokenInfo.at, + "data%5Bstatus%5D": "init", + lang: "en", + apiBreakerVersion: "green" + }), + headers: { + "User-Agent": this.userAgent, + "Content-Type": "application/x-www-form-urlencoded", + "Accept-Language": "en-US,en;q=0.9", + "Sec-Fetch-Site": "same-origin", + "Referer": this.getEmbedUrl() + }, + }, + this.proxy + ); + + let data = JSON.parse(res.body.toString()); + data.token = this.token; + data.tokenInfo = this.tokenInfo; + + if (data.game_data.gameType == 1) { + return new Challenge1(data, { + proxy: this.proxy, + userAgent: this.userAgent, + }); + } else if (data.game_data.gameType == 3) { + return new Challenge3(data, { + proxy: this.proxy, + userAgent: this.userAgent, + }); + } else if (data.game_data.gameType == 4) { + return new Challenge4(data, { + proxy: this.proxy, + userAgent: this.userAgent, + }); + } else { + throw new Error( + "Unsupported game type: " + data.game_data.gameType + ); + } + //return res.body.toString() + } + + getEmbedUrl(): string { + return `${this.tokenInfo.surl}/fc/gc/?${util.constructFormData( + this.tokenInfo + )}`; + } +} diff --git a/g4f/Provider/npm/node_modules/funcaptcha/src/util.ts b/g4f/Provider/npm/node_modules/funcaptcha/src/util.ts new file mode 100644 index 00000000..da9412ac --- /dev/null +++ b/g4f/Provider/npm/node_modules/funcaptcha/src/util.ts @@ -0,0 +1,197 @@ +import fingerprint from "./fingerprint"; +import murmur from "./murmur"; +import crypt from "./crypt"; + +interface TimestampData { + cookie: string; + value: string; +} + +const DEFAULT_USER_AGENT = + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36"; + +let apiBreakers = { + v1: { + 3: { + default: (c) => c, + method_1: (c) => ({ x: c.y, y: c.x }), + method_2: (c) => ({ x: c.x, y: (c.y + c.x) * c.x }), + method_3: (c) => ({ a: c.x, b: c.y }), + method_4: (c) => [c.x, c.y], + method_5: (c) => [c.y, c.x].map((v) => Math.sqrt(v)), + }, + 4: { + default: (c) => c + } + }, + v2: { + 3: { + value: { + alpha: (c) => ({ x: c.x, y: (c.y + c.x) * c.x, px: c.px, py: c.py }), + beta: (c) => ({ x: c.y, y: c.x, py: c.px, px: c.py }), + gamma: (c) => ({ x: c.y + 1, y: -c.x, px: c.px, py: c.py }), + delta: (c) => ({ x: c.y + 0.25, y: c.x + 0.5, px: c.px, py: c.py }), + epsilon: (c) => ({ x: c.x * 0.5, y: c.y * 5, px: c.px, py: c.py }), + zeta: (c) => ({ x: c.x + 1, y: c.y + 2, px: c.px, py: c.py }), + method_1: (c) => ({ x: c.x, y: c.y, px: c.px, py: c.py }), + method_2: (c) => ({ x: c.y, y: (c.y + c.x) * c.x, px: c.px, py: c.py }), + method_3: (c) => ({ x: Math.sqrt(c.x), y: Math.sqrt(c.y), px: c.px, py: c.py }), + }, + key: { + alpha: (c) => [c.y, c.px, c.py, c.x], + beta: (c) => JSON.stringify({ x: c.x, y: c.y, px: c.px, py: c.py }), + gamma: (c) => [c.x, c.y, c.px, c.py].join(" "), + delta: (c) => [1, c.x, 2, c.y, 3, c.px, 4, c.py], + epsilon: (c) => ({ answer: { x: c.x, y: c.y, px: c.px, py: c.py } }), + zeta: (c) => [c.x, [c.y, [c.px, [c.py]]]], + method_1: (c) => ({ a: c.x, b: c.y, px: c.px, py: c.py }), + method_2: (c) => [c.x, c.y], + method_3: (c) => [c.y, c.x], + } + }, + 4: { + value: { + // @ts-ignore + alpha: (c) => ({ index: String(c.index) + 1 - 2 }), + beta: (c) => ({ index: -c.index }), + gamma: (c) => ({ index: 3 * (3 - c.index) }), + delta: (c) => ({ index: 7 * c.index }), + epsilon: (c) => ({ index: 2 * c.index }), + zeta: (c) => ({ index: c.index ? 100 / c.index : c.index }), + va: (c) => ({ index: c.index + 3 }), + vb: (c) => ({ index: -c.index }), + vc: (c) => ({ index: 10 - c.index }), + vd: (c) => ({ index: 3 * c.index }), + }, + key: { + alpha: (c) => [Math.round(100 * Math.random()), c.index, Math.round(100 * Math.random())], + beta: (c) => ({ size: 50 - c.index, id: c.index, limit: 10 * c.index, req_timestamp: Date.now() }), + gamma: (c) => c.index, + delta: (c) => ({ index: c.index }), + epsilon: (c) => { + const arr: any = []; + const len = Math.round(5 * Math.random()) + 1; + const rand = Math.round(Math.random() * len); + for (let i = 0; i < len; i++) { + arr.push(i === rand ? c.index : Math.round(10 * Math.random())); + } + arr.push(rand); + return arr; + }, + zeta: (c) => Array(Math.round(5 * Math.random()) + 1).concat(c.index), + ka: (c) => c.index, + kb: (c) => [c.index], + kc: (c) => ({ guess: c.index }), + } + } + } +} + +interface TileLoc { + x: number; + y: number; + px: number; + py: number; +} +function tileToLoc(tile: number): TileLoc { + let xClick = (tile % 3) * 100 + (tile % 3) * 3 + 3 + 10 + Math.floor(Math.random() * 80); + let yClick = Math.floor(tile / 3) * 100 + Math.floor(tile / 3) * 3 + 3 + 10 + Math.floor(Math.random() * 80); + return { + x: xClick, + y: yClick, + px: xClick / 300, + py: yClick / 200, + } +} + +function constructFormData(data: {}): string { + return Object.keys(data) + .filter((v) => data[v] !== undefined) + .map((k) => `${k}=${encodeURIComponent(data[k])}`) + .join("&"); +} + +function random(): string { + return Array(32) + .fill(0) + .map(() => "0123456789abcdef"[Math.floor(Math.random() * 16)]) + .join(""); +} + +function getTimestamp(): TimestampData { + const time = (new Date()).getTime().toString() + const value = `${time.substring(0, 7)}00${time.substring(7, 13)}` + + return { cookie: `timestamp=${value};path=/;secure;samesite=none`, value } +} + +function getBda(userAgent: string, opts: object): string { + let fp = fingerprint.getFingerprint(); + let fe = fingerprint.prepareFe(fp); + + let bda = [ + { key: "api_type", value: "js" }, + { key: "p", value: 1 }, + { key: "f", value: murmur(fingerprint.prepareF(fingerprint), 31) }, + { + key: "n", + value: Buffer.from( + Math.round(Date.now() / (1000 - 0)).toString() + ).toString("base64"), + }, + { key: "wh", value: `${random()}|${random()}` }, + { + "key": "enhanced_fp", + "value": fingerprint.getEnhancedFingerprint(fp, userAgent, opts) + }, + { key: "fe", value: fe }, + { key: "ife_hash", value: murmur(fe.join(", "), 38) }, + { key: "cs", value: 1 }, + { + key: "jsbd", + value: JSON.stringify({ + HL: 4, + DT: "", + NWD: "false", + DOTO: 1, + DMTO: 1, + }), + }, + ]; + + let time = new Date().getTime() / 1000; + let key = userAgent + Math.round(time - (time % 21600)); + + let s = JSON.stringify(bda); + let encrypted = crypt.encrypt(s, key); + return Buffer.from(encrypted).toString("base64"); +} + +function solveBreaker(v2: boolean, breaker: { value: string[], key: string } | string = "default", gameType: number, value: object) { + if (!v2 && typeof breaker === "string") + return (apiBreakers.v1[gameType][breaker || "default"] || ((v: any) => v))(value) + + if (typeof breaker !== "string") { + let b = apiBreakers.v2[gameType] + let v = breaker.value.reduce((acc, cur) => { + if (b.value[cur]) + return b.value[cur](acc) + else + return cur + }, value) + return b.key[breaker.key](v) + } else { + return value + } +} + +export default { + DEFAULT_USER_AGENT, + tileToLoc, + constructFormData, + getBda, + apiBreakers, + getTimestamp, + random, + solveBreaker +}; |