Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
minicx | 175cc1376a | |
minicx | 12aae08fb8 | |
minicx | 80df4af3b9 | |
minicx | fe8a7ee92f | |
minicx | 88b34acc45 | |
minicx | 22361c3cb2 | |
minicx | d02929d114 |
|
@ -1,13 +1,19 @@
|
|||
build
|
||||
// env files
|
||||
.vscode
|
||||
node_modules
|
||||
test.ts
|
||||
|
||||
// yarn files
|
||||
yarn-error.log
|
||||
yarn.lock
|
||||
|
||||
// npm files
|
||||
package-lock.json
|
||||
db.json
|
||||
|
||||
// project files
|
||||
test.ts
|
||||
db.sqlite
|
||||
build
|
||||
errors.log
|
||||
info.log
|
||||
data.json
|
||||
settings.json
|
||||
yarn-error.log
|
||||
yarn.lock
|
||||
db.json1
|
||||
settings.json
|
69
README.md
69
README.md
|
@ -1,31 +1,50 @@
|
|||
<div align="center">
|
||||
<h1><b>HK_BOT🤖</b></h1>
|
||||
<a href="https://hits.sh/git.disroot.org/minicx/hk_bot/"><img alt="Hits" src="https://hits.sh/git.disroot.org/minicx/hk_bot.svg"/></a>
|
||||
<a href="https://git.disroot.org/minicx/hk_bot/LiCENSE"><img src="https://shields.io/badge/license-MIT-green" alt='License'/></a>
|
||||
<a href="https://git.disroot.org/minicx/hk_bot/src/commit/0c7f8c9e6c43f0f3784b39b7fbf8b3cea1c27832/LICENSE"><img src="https://shields.io/badge/license-MIT-green" alt='License'/></a>
|
||||
</div>
|
||||
|
||||
|
||||
# List of content
|
||||
* [Installing](#installing)
|
||||
* [Prerequirements](#prerequirements)
|
||||
* [Cloning repo](#cloning-repo)
|
||||
* [Installing all dependencies](#installing-all-dependencies)
|
||||
* [Starting](#starting)
|
||||
* [Format of Faucet wallets](#format-of-faucet-https-faucetpay-io-wallets)
|
||||
* [Settings](#settings)
|
||||
|
||||
# Installing
|
||||
1. #### Prerequirements
|
||||
You need to install this packages:
|
||||
* `NodeJS>=14.x` version
|
||||
* `Docker`
|
||||
* `yarn` or `npm`
|
||||
#### Linux:
|
||||
After installing packages, you must add your user at `docker` group to have access to `docker`'s commands without root(**Without this the script will not work ❗**)
|
||||
|
||||
|
||||
|
||||
2. #### Cloning repo
|
||||
|
||||
1. #### Cloning repo
|
||||
To do this run `git clone https://git.disroot.org/minicx/hk_bot.git`
|
||||
3. #### Installing all dependencies
|
||||
|
||||
To do this run `git clone https://git.disroot.org/minicx/hk_bot.git`
|
||||
2. #### Installing all dependencies
|
||||
Run in `hk_bot` directory `npm install --production` or `yarn install --production`
|
||||
4. #### Starting
|
||||
|
||||
Run in `hk_bot` directory `npm install` or `yarn install`
|
||||
3. #### Starting
|
||||
Run `npm start` or `yarn start`
|
||||
|
||||
Run `npm start` or `yarn start`
|
||||
<details>
|
||||
<summary>Other commands</summary>
|
||||
|
||||
<details>
|
||||
<summary>Other commands</summary>
|
||||
| Command | Description |
|
||||
| ------- | ------------------------------------------------------------------ |
|
||||
| build | just compile all `.ts` files to `build` directory into `.js` |
|
||||
|
||||
| Command | Description |
|
||||
| ------- | ------------------------------------------------------------------ |
|
||||
| build | just compile all `.ts` files to `build` directory into `.js` |
|
||||
</details>
|
||||
|
||||
</details>
|
||||
|
||||
# Format of [Faucet](https://faucetpay.io) wallets data
|
||||
# Format of [Faucet](https://faucetpay.io) wallets
|
||||
|
||||
* **❗ The script currently does not use the email or password of the faucet account ❗**
|
||||
* **JSON file must be in root of `hk_bot` directory**
|
||||
|
@ -45,8 +64,26 @@
|
|||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
</details>
|
||||
|
||||
# Settings
|
||||
|
||||
Script will create `settings.json` file
|
||||
|
||||
from there you can change some settings
|
||||
| Setting | Description |
|
||||
| ------- | ------------------------------------------------------------------ |
|
||||
| logLevel | Sets level of logs |
|
||||
| pararels | This setting affects the number of running groups of accounts |
|
||||
| mainCrypto | Temp setting |
|
||||
| minimalToWithdraw | This setting sets the minimum balance at which the withdrawal will be made |
|
||||
| maxRefferals | This setting affects the maximum depth of the referral tree |
|
||||
| botMessages | This setting specifies the messages the script is searching for |
|
||||
| botButtons | This setting specifies the text buttons that are available in `hk_bot` |
|
||||
| telegramLinks | This setting sets the links to the bot and the groups you need to join in order to use it |
|
||||
| sleepTime | This setting sets the delay time |
|
||||
| shuffleAccounts | This setting determines whether or not accounts will be migrated (this is needed to simulate a live user) |
|
||||
| bypassMode | This parameter manages that the script will bypass the timer on timed ad pages |
|
||||
|
||||
# Creator and contributors
|
||||
<div align='center'>
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
import prompt from "prompts";
|
||||
import { TelegramWorker } from "./classes/Telegram";
|
||||
import * as telegram from "telegram";
|
||||
import fs from "fs";
|
||||
import { logger } from "./logger";
|
||||
import { db, JSONFaucetMails } from "./classes/Database";
|
||||
import { LogLevel } from "telegram/extensions/Logger";
|
||||
import { settings } from "./classes/Settings";
|
||||
import { isUndefined } from "lodash";
|
||||
|
||||
export const addAccounts = async (): Promise<void> => {
|
||||
// need rework this shit
|
||||
let apiId: number | undefined = undefined;
|
||||
let apiHash: string | undefined = undefined;
|
||||
let workers = await db.getWorkers();
|
||||
if (workers.length != 0) {
|
||||
const usePrevData = await prompt({
|
||||
type: "confirm",
|
||||
name: "confirmed",
|
||||
message: "Use apiId and apiHash from last added worker?",
|
||||
});
|
||||
if (usePrevData.confirmed == true) {
|
||||
apiId = workers[workers.length - 1].apiID;
|
||||
apiHash = workers[workers.length - 1].apiHash;
|
||||
}
|
||||
}
|
||||
if (isUndefined(apiId) || isUndefined(apiHash)) {
|
||||
const api = await prompt([
|
||||
{
|
||||
type: "number",
|
||||
name: "apiId",
|
||||
message: "ApiId?",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "apiHash",
|
||||
message: "ApiHash?",
|
||||
},
|
||||
],{onCancel(prompt, answers) {
|
||||
// there cancel
|
||||
},});
|
||||
apiId = Number(api.apiId);
|
||||
apiHash = api.apiHash;
|
||||
}
|
||||
const jsonFiles: prompt.Choice[] = [];
|
||||
for (const file of fs.readdirSync("./")) {
|
||||
if (file.search(".json") != -1 && file != "settings.json") {
|
||||
const jsonFile = new JSONFaucetMails(file);
|
||||
try {
|
||||
await jsonFile.load();
|
||||
} catch (e) {
|
||||
jsonFiles.push({
|
||||
title: file,
|
||||
description: "invalid json file",
|
||||
value: file,
|
||||
disabled: true,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
jsonFiles.push({
|
||||
title: file,
|
||||
description: "json file",
|
||||
value: file,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (jsonFiles.length == 0) {
|
||||
throw new Error("There is no valid `.json` file");
|
||||
}
|
||||
const walletsFile = (
|
||||
await prompt({
|
||||
type: "select",
|
||||
name: "file",
|
||||
message: "Choose wallets json file",
|
||||
choices: jsonFiles,
|
||||
})
|
||||
).file;
|
||||
await db.findWallet(walletsFile);
|
||||
|
||||
mainLoop: while (true) {
|
||||
workers = await db.getWorkers();
|
||||
const answers = await prompt([
|
||||
{
|
||||
type: "text",
|
||||
name: "number",
|
||||
message: "Phone number?",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "password",
|
||||
message: "2FA Password?",
|
||||
},
|
||||
]);
|
||||
for (const worker of workers) {
|
||||
if (worker.phoneNumber == answers.number) {
|
||||
logger.warn("You already added this number");
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
const session = new telegram.sessions.StringSession("");
|
||||
const telegramWorker = new TelegramWorker(
|
||||
session,
|
||||
apiId!,
|
||||
apiHash!.trim(),
|
||||
{
|
||||
deviceModel: "Samsung SM-G980",
|
||||
connectionRetries: 5,
|
||||
systemVersion: "10",
|
||||
}
|
||||
);
|
||||
telegramWorker.setLogLevel(LogLevel.ERROR);
|
||||
await telegramWorker.start({
|
||||
phoneNumber: async () => answers.number.replace(/ /g, "").trim(),
|
||||
password: async () => answers.password.replace(/ /g, "").trim(),
|
||||
phoneCode: async () =>
|
||||
(
|
||||
await prompt({
|
||||
type: "number",
|
||||
name: "code",
|
||||
message: "Enter recieved code",
|
||||
})
|
||||
).code.toString(),
|
||||
onError: (err) => {
|
||||
logger.error(`Error due singning into telegram worker\n${err}`);
|
||||
throw err;
|
||||
},
|
||||
});
|
||||
if ((await telegramWorker.isUserAuthorized()) === true) {
|
||||
const worker: telegram.Api.User | telegram.Api.InputPeerUser =
|
||||
await telegramWorker.getMe(false);
|
||||
if (worker instanceof telegram.Api.User) {
|
||||
await db.addUser(
|
||||
{
|
||||
password: answers.password,
|
||||
phoneNumber: answers.number,
|
||||
apiHash: apiHash!,
|
||||
telegramID: Number(worker.id),
|
||||
apiID: apiId!,
|
||||
stringSession: String(telegramWorker.session.save()),
|
||||
refferal: await db.findRefferal(settings.maxRefferals),
|
||||
},
|
||||
walletsFile
|
||||
);
|
||||
} else {
|
||||
logger.error("Wrong type of worker?");
|
||||
}
|
||||
} else {
|
||||
logger.error("telegramWorker not authorized");
|
||||
}
|
||||
if (
|
||||
(
|
||||
await prompt({
|
||||
type: "confirm",
|
||||
name: "continue",
|
||||
message: "continue?",
|
||||
})
|
||||
).continue != true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,932 +0,0 @@
|
|||
import Hero from "@ulixee/hero";
|
||||
import * as telegram from "telegram";
|
||||
import { sleep } from "telegram/Helpers";
|
||||
import { AccountInterface } from "./interfaces/databaseInterface";
|
||||
import { prevTaskInterface } from "./interfaces/otherInterfaces";
|
||||
import logger from "./logger";
|
||||
import {
|
||||
CaptchaError,
|
||||
getMessagesByEntity,
|
||||
NoNewMessagesError,
|
||||
waitNewMessages,
|
||||
} from "./utils";
|
||||
import { settings } from "./database";
|
||||
import { isNull } from "lodash";
|
||||
|
||||
export const vertification = async function (hero: Hero, url: string) {
|
||||
await hero.goto(url, { timeoutMs: 2_000_000 });
|
||||
await hero.waitForLoad("AllContentLoaded", { timeoutMs: 1180_000 });
|
||||
const captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
if (captchaButton != null) {
|
||||
let verify = hero.document.querySelector("body > section > h2");
|
||||
while (
|
||||
isNull(verify) != true &&
|
||||
(await verify.textContent)!.includes("All right!") == false
|
||||
) {
|
||||
const isCaptchaPassed = hero.document.querySelector(
|
||||
"input[id='recaptcha-token']"
|
||||
);
|
||||
if (
|
||||
isNull(isCaptchaPassed) ||
|
||||
(await isCaptchaPassed.$isVisible) == false
|
||||
) {
|
||||
await hero.interact({
|
||||
click: {
|
||||
element: captchaButton,
|
||||
verification: "exactElement",
|
||||
},
|
||||
});
|
||||
await sleep(5000);
|
||||
verify = hero.document.querySelector("body > section > h2");
|
||||
} else {
|
||||
logger.error("Captcha detected");
|
||||
throw new CaptchaError("Auhtung captcha detected");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Cant find captcha button");
|
||||
}
|
||||
};
|
||||
|
||||
export const doSitesTasks = async function (
|
||||
client: telegram.TelegramClient,
|
||||
worker: AccountInterface,
|
||||
hero: Hero,
|
||||
botEntity: telegram.Api.Chat | telegram.Api.User,
|
||||
tasksSelector: telegram.Api.Message
|
||||
) {
|
||||
const taskSitesButton = tasksSelector.buttons![1][0];
|
||||
const prevTask: prevTaskInterface = {
|
||||
task: tasksSelector,
|
||||
lastMessage: tasksSelector,
|
||||
};
|
||||
mainLoop: while (true) {
|
||||
await sleep(2000);
|
||||
await taskSitesButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const task = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: prevTask.lastMessage.id,
|
||||
// search: (await settings.botMessages()).tasksSelector,
|
||||
})
|
||||
)[0];
|
||||
|
||||
if (task.buttonCount == 2) {
|
||||
logger.debug(`New ad task | ${worker.phoneNumber}`);
|
||||
|
||||
const urlButton = task.buttons![0][0];
|
||||
const skipButton = task.buttons![0][1];
|
||||
await hero.goto(urlButton.url!, { timeoutMs: 2_000_000 });
|
||||
await hero.waitForLoad("AllContentLoaded", { timeoutMs: 1180_000 });
|
||||
|
||||
let captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
|
||||
if (
|
||||
isNull(captchaButton) &&
|
||||
(await hero.activeTab.url).includes("hkbots")
|
||||
) {
|
||||
if (prevTask.task.message == task.message) {
|
||||
logger.warn(
|
||||
`Same tasks detected on ${worker.phoneNumber}... Skipping due captcha isnt detected......`
|
||||
);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(client, worker, botEntity, task.id);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
} else {
|
||||
prevTask.task = task;
|
||||
logger.warn(
|
||||
`Captcha isnt detected... | ${worker.phoneNumber}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
prevTask.task = task;
|
||||
if ((await hero.activeTab.url).includes("hkbots")) {
|
||||
if ((await captchaButton.$isClickable) != true) {
|
||||
// timer page
|
||||
logger.warn(`Found timer... | ${worker.phoneNumber}`);
|
||||
if (settings.bypassMode == true) {
|
||||
logger.warn(
|
||||
`Bypassing timer... | ${worker.phoneNumber}`
|
||||
);
|
||||
try {
|
||||
await hero.executeJs(
|
||||
"document.getElementById('form').setAttribute('style', '')"
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error(`Something went wrong due bypass`);
|
||||
}
|
||||
} else {
|
||||
while (
|
||||
hero.document.querySelector("i[id='timer']") !=
|
||||
null &&
|
||||
(await captchaButton.$isClickable) != true
|
||||
) {
|
||||
await sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
while ((await hero.activeTab.url) == urlButton.url!) {
|
||||
if ((+new Date() - +now) / 1000 > 2 * 60) {
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
task.id
|
||||
);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
logger.warn(
|
||||
`Anomaly activity in browser. Please checkout`
|
||||
);
|
||||
continue mainLoop;
|
||||
} else {
|
||||
const isCaptchaPassed = hero.document.querySelector(
|
||||
"input[id='recaptcha-token']"
|
||||
);
|
||||
if (
|
||||
isNull(isCaptchaPassed) ||
|
||||
(await isCaptchaPassed.$isVisible) == false
|
||||
) {
|
||||
if (await captchaButton.$isClickable) {
|
||||
try {
|
||||
await hero.interact({
|
||||
click: {
|
||||
element: captchaButton,
|
||||
verification: "exactElement",
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
`Some error due clicking | ${worker.phoneNumber}`
|
||||
);
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
await sleep(1000);
|
||||
captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
} else {
|
||||
logger.error(
|
||||
`Captcha detected | ${worker.phoneNumber}`
|
||||
);
|
||||
throw new Error("Captcha detected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
await waitNewMessages(client, worker, botEntity, task.id);
|
||||
const afterTask: telegram.Api.Message = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
limit: 100,
|
||||
})
|
||||
).filter((value) => {
|
||||
return value.message.includes(
|
||||
settings.botMessages.taskComplete
|
||||
);
|
||||
})[0];
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
if (afterTask != null) {
|
||||
// need update
|
||||
if (
|
||||
afterTask.message.includes(
|
||||
settings.botMessages.taskComplete
|
||||
) == true
|
||||
) {
|
||||
logger.info(
|
||||
`Site task complete | ${worker.phoneNumber}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
task.message.includes(settings.botMessages.taskOver) == true
|
||||
) {
|
||||
logger.info(`Ad tasks completed | ${worker.phoneNumber}`);
|
||||
break;
|
||||
} else {
|
||||
logger.error(`Check out last message of ${worker.phoneNumber}`);
|
||||
throw new Error(`Check out last message of ${worker.phoneNumber}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const doChatsTasks = async function (
|
||||
client: telegram.TelegramClient,
|
||||
worker: AccountInterface,
|
||||
hero: Hero,
|
||||
botEntity: telegram.Api.Chat | telegram.Api.User,
|
||||
tasksSelector: telegram.Api.Message
|
||||
) {
|
||||
const taskChatsButton = tasksSelector.buttons![1][1];
|
||||
const prevTask: prevTaskInterface = {
|
||||
task: tasksSelector,
|
||||
lastMessage: tasksSelector,
|
||||
};
|
||||
mainLoop: while (true) {
|
||||
await sleep(2000);
|
||||
await taskChatsButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const task = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: prevTask.lastMessage.id,
|
||||
// search: (await settings.botMessages()).tasksSelector,
|
||||
})
|
||||
)[0];
|
||||
if (task.buttonCount == 3) {
|
||||
logger.info(`New chat task | ${worker.phoneNumber}`);
|
||||
|
||||
const urlButton = task.buttons![0][0];
|
||||
const confirmButton = task.buttons![0][1];
|
||||
const skipButton = task.buttons![0][2];
|
||||
|
||||
let groupLink = "";
|
||||
if (urlButton.url?.includes("hkbot") == true) {
|
||||
await hero.goto(urlButton.url, { timeoutMs: 2_000_000 });
|
||||
await hero.waitForLoad("AllContentLoaded", {
|
||||
timeoutMs: 1180_000,
|
||||
});
|
||||
let captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
if (isNull(captchaButton)) {
|
||||
if (prevTask.task.message == task.message) {
|
||||
logger.warn(
|
||||
`Same tasks detected on ${worker.phoneNumber}... Skipping due captcha isnt detected......`
|
||||
);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
task.id
|
||||
);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
} else {
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = task;
|
||||
logger.warn(
|
||||
`Captcha isnt detected... | ${worker.phoneNumber}`
|
||||
);
|
||||
}
|
||||
continue mainLoop;
|
||||
}
|
||||
const now = new Date();
|
||||
while (
|
||||
captchaButton != null &&
|
||||
(await hero.activeTab.url) == urlButton.url!
|
||||
) {
|
||||
if ((+new Date() - +now) / 1000 > 2 * 60) {
|
||||
if ((await captchaButton.$isClickable) == false) {
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
task.id
|
||||
);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
continue mainLoop;
|
||||
}
|
||||
|
||||
logger.warn(
|
||||
`Anomaly activity in browser. Please checkout`
|
||||
);
|
||||
await hero.reload();
|
||||
}
|
||||
const isCaptchaPassed = hero.document.querySelector(
|
||||
"input[id='recaptcha-token']"
|
||||
);
|
||||
if (
|
||||
isCaptchaPassed == null ||
|
||||
(await isCaptchaPassed.$isVisible) == false
|
||||
) {
|
||||
if (await captchaButton.$isClickable) {
|
||||
try {
|
||||
await hero.interact({
|
||||
click: {
|
||||
element: captchaButton,
|
||||
verification: "exactElement",
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
`Some error due clicking | ${worker.phoneNumber}`
|
||||
);
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
await sleep(1000);
|
||||
captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
} else {
|
||||
logger.error("Captcha detected");
|
||||
throw new CaptchaError("Auhtung captcha detected");
|
||||
}
|
||||
}
|
||||
groupLink = await hero.url;
|
||||
} else {
|
||||
groupLink = urlButton.url!;
|
||||
}
|
||||
// https://gram.js.org/tl/messages/GetFullChat
|
||||
// hash checking
|
||||
let group: telegram.Api.Channel | undefined;
|
||||
if (
|
||||
!/(^\w+:|^)\/\/(?:t|telegram)\.(?:me|dog)\/(joinchat\/|\+)([\w-]+)/i.test(
|
||||
groupLink
|
||||
)
|
||||
) {
|
||||
groupLink = groupLink.replace(
|
||||
/(^\w+:|^)\/\/(?:t|telegram)\.(?:me|dog)\//i,
|
||||
""
|
||||
);
|
||||
try {
|
||||
group = (
|
||||
(await client.invoke(
|
||||
new telegram.Api.channels.JoinChannel({
|
||||
channel: groupLink,
|
||||
})
|
||||
)) as telegram.Api.Updates
|
||||
).chats[0] as telegram.Api.Channel;
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof telegram.errors.RPCError) {
|
||||
switch (err.errorMessage) {
|
||||
case "CHANNELS_TOO_MUCH":
|
||||
logger.warn(
|
||||
`Too much groups | ${worker.phoneNumber}`
|
||||
);
|
||||
return;
|
||||
|
||||
case "USER_ALREADY_PARTICIPANT":
|
||||
logger.warn(
|
||||
`Already in group | ${worker.phoneNumber}`
|
||||
);
|
||||
group = (
|
||||
await client.invoke(
|
||||
new telegram.Api.channels.GetChannels({
|
||||
id: [groupLink],
|
||||
})
|
||||
)
|
||||
)[0];
|
||||
break;
|
||||
default:
|
||||
logger.warn(
|
||||
`Something wrong with chat ${err.errorMessage} | ${worker.phoneNumber}`
|
||||
);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
task.id
|
||||
);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// hash
|
||||
groupLink = groupLink.replace(
|
||||
/(^\w+:|^)\/\/(?:t|telegram)\.(?:me|dog)\/(joinchat\/|\+)/i,
|
||||
""
|
||||
);
|
||||
try {
|
||||
group = (
|
||||
(await client.invoke(
|
||||
new telegram.Api.messages.ImportChatInvite({
|
||||
hash: groupLink,
|
||||
})
|
||||
)) as telegram.Api.Updates
|
||||
).chats[0] as telegram.Api.Channel;
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof telegram.errors.RPCError) {
|
||||
switch (err.errorMessage) {
|
||||
case "CHANNELS_TOO_MUCH":
|
||||
logger.warn(
|
||||
`Too much groups | ${worker.phoneNumber}`
|
||||
);
|
||||
return;
|
||||
|
||||
case "USER_ALREADY_PARTICIPANT":
|
||||
logger.warn(
|
||||
`Already in group | ${worker.phoneNumber}`
|
||||
);
|
||||
group = (
|
||||
(await client.invoke(
|
||||
new telegram.Api.messages.CheckChatInvite(
|
||||
{
|
||||
hash: groupLink,
|
||||
}
|
||||
)
|
||||
)) as telegram.Api.ChatInviteAlready
|
||||
).chat as telegram.Api.Channel;
|
||||
break;
|
||||
default:
|
||||
logger.warn(
|
||||
`Something wrong with chat ${err.errorMessage} | ${worker.phoneNumber}`
|
||||
);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
task.id
|
||||
);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await confirmButton.click({ sharePhone: false });
|
||||
await waitNewMessages(client, worker, botEntity, task.id);
|
||||
const afterTask = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
limit: 100,
|
||||
})
|
||||
).filter((value) => {
|
||||
if (
|
||||
value.message.includes(settings.botMessages.notInGroup) ||
|
||||
value.message.includes(settings.botMessages.taskComplete)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})[0];
|
||||
const lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage =
|
||||
lastMessage !== undefined ? lastMessage : afterTask;
|
||||
if (
|
||||
afterTask.message.includes(settings.botMessages.taskComplete) ==
|
||||
true
|
||||
) {
|
||||
worker.completedGroupsTasks.push({
|
||||
timeToLeave:
|
||||
+new Date() +
|
||||
Number(afterTask.message.replace(/\D/g, "")) *
|
||||
3600 *
|
||||
1_000,
|
||||
groupID: await client.getPeerId(group!),
|
||||
});
|
||||
logger.info(`Chat task complete | ${worker.phoneNumber}`);
|
||||
continue;
|
||||
} else if (
|
||||
afterTask.message.includes(settings.botMessages.notInGroup) ==
|
||||
true
|
||||
) {
|
||||
logger.warn(`User joined but hk says not. Skipping...`);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(client, worker, botEntity, task.id);
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: task.id,
|
||||
// search: (await settings.botMessages()).tasksSelector,
|
||||
})
|
||||
)[0];
|
||||
worker.completedGroupsTasks.push({
|
||||
timeToLeave: 1,
|
||||
groupID: await client.getPeerId(group!),
|
||||
});
|
||||
} else {
|
||||
logger.debug(`Anomaly | ${worker.phoneNumber}`);
|
||||
logger.debug(task.message);
|
||||
}
|
||||
} else if (
|
||||
task.message.includes(settings.botMessages.taskOver) == true
|
||||
) {
|
||||
logger.info(`Chats tasks completed | ${worker.phoneNumber}`);
|
||||
break;
|
||||
} else {
|
||||
logger.error(`Check out last message of ${worker.phoneNumber}`);
|
||||
throw new Error(`Check out last message of ${worker.phoneNumber}`);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const doBotTasks = async function (
|
||||
client: telegram.TelegramClient,
|
||||
worker: AccountInterface,
|
||||
hero: Hero,
|
||||
botEntity: telegram.Api.Chat | telegram.Api.User,
|
||||
tasksSelector: telegram.Api.Message
|
||||
) {
|
||||
const taskBotsButton = tasksSelector.buttons![1][2];
|
||||
const prevTask: prevTaskInterface = {
|
||||
task: tasksSelector,
|
||||
lastMessage: tasksSelector,
|
||||
};
|
||||
mainLoop: while (true) {
|
||||
await sleep(2000);
|
||||
await taskBotsButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
let task: telegram.Api.Message;
|
||||
[prevTask.lastMessage, task] = await client.getMessages(botEntity, {
|
||||
minId: prevTask.lastMessage.id,
|
||||
limit: 2,
|
||||
});
|
||||
if (task === undefined) {
|
||||
task = prevTask.lastMessage;
|
||||
}
|
||||
if (task.buttonCount == 3) {
|
||||
logger.info(`New bot task | ${worker.phoneNumber}`);
|
||||
|
||||
const urlButton = task.buttons![0][0];
|
||||
const skipButton = task.buttons![0][1];
|
||||
let botLink = "@";
|
||||
if (urlButton.url?.includes("hkbot") == true) {
|
||||
await hero.goto(urlButton.url, { timeoutMs: 2_000_000 });
|
||||
await hero.waitForLoad("AllContentLoaded", {
|
||||
timeoutMs: 1180_000,
|
||||
});
|
||||
let captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
if (isNull(captchaButton)) {
|
||||
if (prevTask.task.message == task.message) {
|
||||
logger.warn(
|
||||
`Same tasks detected on ${worker.phoneNumber}... Skipping due captcha isnt detected......`
|
||||
);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
} else {
|
||||
logger.warn(
|
||||
`Captcha isnt detected... | ${worker.phoneNumber}`
|
||||
);
|
||||
}
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const cancelMessage = await client.sendMessage(botEntity, {
|
||||
message: "/cancel",
|
||||
});
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
cancelMessage.id
|
||||
);
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: cancelMessage.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
continue mainLoop;
|
||||
}
|
||||
const now = new Date();
|
||||
while (
|
||||
captchaButton != null &&
|
||||
(await hero.activeTab.url) == urlButton.url!
|
||||
) {
|
||||
if ((+new Date() - +now) / 1000 > 2 * 60) {
|
||||
if ((await captchaButton.$isClickable) == false) {
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const cancelMessage = await client.sendMessage(
|
||||
botEntity,
|
||||
{ message: "/cancel" }
|
||||
);
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
cancelMessage.id
|
||||
);
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: cancelMessage.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
continue mainLoop;
|
||||
}
|
||||
logger.warn(
|
||||
`Anomaly activity in browser. Please checkout`
|
||||
);
|
||||
await hero.reload();
|
||||
}
|
||||
const isCaptchaPassed = hero.document.querySelector(
|
||||
"input[id='recaptcha-token']"
|
||||
);
|
||||
if (
|
||||
isCaptchaPassed == null ||
|
||||
(await isCaptchaPassed.$isVisible) == false
|
||||
) {
|
||||
if (await captchaButton.$isClickable) {
|
||||
try {
|
||||
await hero.interact({
|
||||
click: {
|
||||
element: captchaButton,
|
||||
verification: "exactElement",
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
logger.warn(
|
||||
`Some error due clicking | ${worker.phoneNumber}`
|
||||
);
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
await sleep(1000);
|
||||
captchaButton = hero.document.querySelector(
|
||||
"button.g-recaptcha.btn.btn-primary"
|
||||
);
|
||||
} else {
|
||||
logger.error("Captcha detected");
|
||||
throw new CaptchaError("Auhtung captcha detected");
|
||||
}
|
||||
}
|
||||
botLink += (await hero.url)
|
||||
.replace(/(^\w+:|^)\/\/(?:t|telegram)\.(?:me|dog)\//i, "")!
|
||||
.replace(/(?:\?start=)[A-Za-z0-9]+/i, "")!;
|
||||
} else {
|
||||
botLink += urlButton.url
|
||||
?.replace(/(^\w+:|^)\/\/(?:t|telegram)\.(?:me|dog)\//i, "")!
|
||||
.replace(/(?:\?start=)[A-Za-z0-9]+/i, "")!;
|
||||
}
|
||||
await client.invoke(
|
||||
new telegram.Api.contacts.Unblock({
|
||||
id: botLink,
|
||||
})
|
||||
);
|
||||
try {
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botLink,
|
||||
(
|
||||
await client.sendMessage(botLink, { message: "/start" })
|
||||
).id
|
||||
);
|
||||
} catch (err) {
|
||||
if (err instanceof NoNewMessagesError) {
|
||||
logger.warn(
|
||||
`Target bot doesnt work | ${worker.phoneNumber}`
|
||||
);
|
||||
logger.debug(err.message);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const cancelMessage = await client.sendMessage(botEntity, {
|
||||
message: "/cancel",
|
||||
});
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
cancelMessage.id
|
||||
);
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: cancelMessage.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
continue mainLoop;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
let forwardMessage: telegram.Api.Message;
|
||||
try {
|
||||
forwardMessage = (await (
|
||||
await getMessagesByEntity(client, botLink, botLink, {
|
||||
limit: 1000,
|
||||
})
|
||||
)[0].forwardTo(botEntity))![0];
|
||||
} catch (err) {
|
||||
if (err instanceof telegram.errors.RPCError) {
|
||||
client.invoke(
|
||||
new telegram.Api.messages.DeleteHistory({
|
||||
justClear: true,
|
||||
peer: botLink,
|
||||
})
|
||||
);
|
||||
client.invoke(
|
||||
new telegram.Api.contacts.Block({
|
||||
id: botLink,
|
||||
})
|
||||
);
|
||||
|
||||
logger.warn(
|
||||
`Error when forwarding a message. Skipping task... | ${worker.phoneNumber}`
|
||||
);
|
||||
logger.debug(err.message);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const cancelMessage = await client.sendMessage(botEntity, {
|
||||
message: "/cancel",
|
||||
});
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
cancelMessage.id
|
||||
);
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: cancelMessage.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
continue mainLoop;
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const afterTask = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: prevTask.lastMessage.id,
|
||||
limit: 10,
|
||||
})
|
||||
).filter((value) => {
|
||||
if (
|
||||
value.message.includes(settings.botMessages.taskComplete) ||
|
||||
value.message.includes(settings.botMessages.oldMessage)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})[0];
|
||||
if (afterTask !== undefined) {
|
||||
if (
|
||||
afterTask.message.includes(
|
||||
settings.botMessages.taskComplete
|
||||
) == true
|
||||
) {
|
||||
await client.invoke(
|
||||
new telegram.Api.messages.DeleteHistory({
|
||||
justClear: true,
|
||||
peer: botLink,
|
||||
})
|
||||
);
|
||||
await client.invoke(
|
||||
new telegram.Api.contacts.Block({
|
||||
id: botLink,
|
||||
})
|
||||
);
|
||||
logger.info(`Bot task complete | ${worker.phoneNumber}`);
|
||||
} else if (
|
||||
afterTask.message.includes(settings.botMessages.oldMessage)
|
||||
) {
|
||||
logger.warn(
|
||||
`Forwarded message was old | ${worker.phoneNumber}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
client.invoke(
|
||||
new telegram.Api.messages.DeleteHistory({
|
||||
justClear: true,
|
||||
peer: botLink,
|
||||
})
|
||||
);
|
||||
client.invoke(
|
||||
new telegram.Api.contacts.Block({
|
||||
id: botLink,
|
||||
})
|
||||
);
|
||||
|
||||
logger.warn(
|
||||
`Message that i found is unknown | ${worker.phoneNumber}`
|
||||
);
|
||||
await skipButton.click({ sharePhone: false });
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
prevTask.lastMessage.id
|
||||
);
|
||||
const cancelMessage = await client.sendMessage(botEntity, {
|
||||
message: "/cancel",
|
||||
});
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
cancelMessage.id
|
||||
);
|
||||
prevTask.lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: cancelMessage.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
continue mainLoop;
|
||||
}
|
||||
|
||||
const cancelMessage = await client.sendMessage(botEntity, {
|
||||
message: "/cancel",
|
||||
});
|
||||
await waitNewMessages(client, worker, botEntity, cancelMessage.id);
|
||||
const lastMessage = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: cancelMessage.id,
|
||||
})
|
||||
)[0];
|
||||
prevTask.task = task;
|
||||
prevTask.lastMessage =
|
||||
lastMessage !== undefined ? lastMessage : afterTask;
|
||||
continue;
|
||||
} else if (
|
||||
task.message.includes(settings.botMessages.taskOver) == true
|
||||
) {
|
||||
logger.info(`Bots tasks completed | ${worker.phoneNumber}`);
|
||||
break;
|
||||
} else {
|
||||
logger.error(`Check out last message of ${worker.phoneNumber}`);
|
||||
throw new Error(`Check out last message of ${worker.phoneNumber}`);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
import { JsonDB, Config } from "node-json-db";
|
||||
import { Knex } from "knex";
|
||||
import knex from "knex";
|
||||
|
||||
export abstract class JSONDatabase {
|
||||
protected readonly rawDB: JsonDB;
|
||||
protected isLoaded: boolean = false;
|
||||
constructor(file: string) {
|
||||
this.rawDB = new JsonDB(new Config(file, false, true, "/"));
|
||||
return new Proxy(this, {
|
||||
get(target, name, reciever) {
|
||||
if (
|
||||
target.isLoaded ||
|
||||
!(name in Object.getOwnPropertyNames(target))
|
||||
) {
|
||||
return target[name];
|
||||
} else {
|
||||
throw new Error("Database is not loaded");
|
||||
}
|
||||
},
|
||||
set(target, name, newValue, reciever) {
|
||||
if (target.isLoaded || name == "isLoaded") {
|
||||
target[name] = newValue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
async load() {
|
||||
this.isLoaded = true;
|
||||
await this.rawDB.load();
|
||||
}
|
||||
}
|
||||
export abstract class SQLDatabase {
|
||||
protected readonly rawDB: Knex<any, unknown[]>;
|
||||
constructor(file: string) {
|
||||
this.rawDB = knex({
|
||||
client: "better-sqlite3",
|
||||
connection: {
|
||||
filename: file,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
import Miner from "@ulixee/miner";
|
||||
import findFreePorts from "find-free-ports";
|
||||
import { IGroupPorts, IUsedIPInterface } from "../interfaces/IExecutorHelper";
|
||||
import { IWorker } from "../interfaces/IWorker";
|
||||
import { db } from "./Database";
|
||||
import { settings } from "./Settings";
|
||||
import Docker from "dockerode";
|
||||
import { dockerWrapper } from "./Docker";
|
||||
import { logger } from "../logger";
|
||||
import { sleep } from "telegram/Helpers";
|
||||
import TorControl from "tor-control";
|
||||
import { getIP } from "../utils";
|
||||
import { isEqual } from "lodash";
|
||||
import { HeroWrapper } from "./HeroWrapper";
|
||||
|
||||
export const executor = new (class Executor {
|
||||
protected usedIPs: IUsedIPInterface[] = [];
|
||||
|
||||
async proccessWorkers() {
|
||||
const workers = await db.getWorkers();
|
||||
if (settings.shuffleAccounts) {
|
||||
workers.sort(() => Math.random() - 0.5);
|
||||
}
|
||||
const workersGroups: Array<IWorker[]> = [];
|
||||
for (const worker of workers) {
|
||||
this.usedIPs.push({
|
||||
worker: worker,
|
||||
usedIps: [],
|
||||
current: "",
|
||||
});
|
||||
}
|
||||
for (let i = 0; i != settings.pararels; i++) {
|
||||
// spliting the workers into a groups
|
||||
const startIndex =
|
||||
i * Math.ceil(workers.length / settings.pararels);
|
||||
const _workers = workers.slice(
|
||||
startIndex,
|
||||
startIndex + Math.ceil(workers.length / settings.pararels)
|
||||
);
|
||||
if (_workers.length > 0) {
|
||||
workersGroups.push(_workers);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const pararels: Promise<void>[] = [];
|
||||
const miner = new Miner();
|
||||
await miner.listen({ port: (await findFreePorts(1))[0] });
|
||||
const dockerPorts = await findFreePorts(workersGroups.length * 3);
|
||||
|
||||
// creating docker containers
|
||||
let containers: Docker.Container[] = [];
|
||||
{
|
||||
const promises: Promise<Docker.Container>[] = [];
|
||||
for (let i = 0; i != workersGroups.length; i++) {
|
||||
promises.push(
|
||||
dockerWrapper.createTorDocker(
|
||||
dockerPorts[i * 3],
|
||||
dockerPorts[i * 3 + 1],
|
||||
dockerPorts[i * 3 + 2]
|
||||
)
|
||||
);
|
||||
}
|
||||
containers = (await Promise.allSettled(promises)).map((value) => {
|
||||
if (value.status=='fulfilled'){
|
||||
return value.value;
|
||||
} else{
|
||||
throw new Error(value.reason)
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
//
|
||||
for (let i = 0; i != workersGroups.length; i++) {
|
||||
pararels.push(
|
||||
this.proccessGroupWorkers(workersGroups[i], {
|
||||
http: dockerPorts[i * 3],
|
||||
socks: dockerPorts[i * 3 + 1],
|
||||
control: dockerPorts[i * 3 + 2],
|
||||
miner: await miner.port,
|
||||
})
|
||||
);
|
||||
}
|
||||
const results = await Promise.allSettled(pararels);
|
||||
for (const result of results) {
|
||||
if (result.status == "rejected") {
|
||||
logger.warn(`Promise is canceled due ${result.reason}`);
|
||||
}
|
||||
}
|
||||
|
||||
await dockerWrapper.closeOpenedDockers(containers);
|
||||
await miner.close(true);
|
||||
}
|
||||
|
||||
protected async proccessGroupWorkers(
|
||||
workerGroup: IWorker[],
|
||||
ports: IGroupPorts
|
||||
) {
|
||||
workersLoop: for (const worker of workerGroup) {
|
||||
logger.info(
|
||||
`Current worker:${worker.phoneNumber}\nBalance:${worker.balance}`
|
||||
);
|
||||
{
|
||||
let tor: any;
|
||||
try {
|
||||
tor = new TorControl({
|
||||
host: "127.0.0.1",
|
||||
port: ports.control,
|
||||
password: "qwerty", // Your password for tor-control
|
||||
persistent: false, // Keep connection (persistent)
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Cant connect to tor control via ${ports.control}\n${err}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
function isFree(currentIP: string) {
|
||||
for (const usedIP of this.usedIPs) {
|
||||
if (
|
||||
usedIP.usedIps.indexOf(currentIP) != -1 ||
|
||||
usedIP.current == currentIP
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
while (true) {
|
||||
const currentIP = await getIP(ports.http);
|
||||
if (currentIP != null) {
|
||||
if (isFree(currentIP)) {
|
||||
this.usedIPs.filter((value) => {
|
||||
return isEqual(worker, value.worker);
|
||||
})[0].current = currentIP;
|
||||
this.usedIPs
|
||||
.filter((value) => {
|
||||
return isEqual(worker, value.worker);
|
||||
})[0]
|
||||
.usedIps.push(currentIP);
|
||||
break;
|
||||
} else {
|
||||
await tor.signalNewnym();
|
||||
await sleep(3_000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const currentIP = this.usedIPs.filter((value) => {
|
||||
return isEqual(worker, value.worker);
|
||||
})[0].current;
|
||||
|
||||
const browser = new HeroWrapper(
|
||||
worker.browserFingerprint,
|
||||
worker.phoneNumber,
|
||||
ports.miner,
|
||||
ports.socks,
|
||||
currentIP
|
||||
);
|
||||
}
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,266 @@
|
|||
import { isEqual } from "lodash";
|
||||
import { logger } from "../logger";
|
||||
|
||||
import {
|
||||
IWorker,
|
||||
IWorkerCompletedGroupTask,
|
||||
IWorkerDatabase,
|
||||
} from "../interfaces/IWorker";
|
||||
import type { SetOptional } from "type-fest";
|
||||
import { FingerprintGenerator } from "fingerprint-generator";
|
||||
import { IFaucetMail } from "../interfaces/IFaucetMail";
|
||||
import { JSONDatabase, SQLDatabase } from "./AbstractDatabase";
|
||||
|
||||
export class JSONFaucetMails extends JSONDatabase {
|
||||
async getWallets(): Promise<IFaucetMail[]> {
|
||||
const rawWallets = await this.rawDB.getData("/");
|
||||
const wallets: IFaucetMail[] = [];
|
||||
for (const rawWallet of Object.keys(rawWallets)) {
|
||||
try {
|
||||
const wallet: IFaucetMail = {
|
||||
faucet: {
|
||||
username: rawWallets[rawWallet].faucetpay.username,
|
||||
password: rawWallets[rawWallet].faucetpay.password,
|
||||
},
|
||||
mail: {
|
||||
address: rawWallet,
|
||||
password: rawWallets[rawWallet].mail_passphrase,
|
||||
},
|
||||
};
|
||||
wallets.push(wallet);
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return wallets;
|
||||
}
|
||||
}
|
||||
|
||||
export const db = new (class SQLWorkerDatabase extends SQLDatabase {
|
||||
constructor() {
|
||||
super("db.sqlite");
|
||||
this.rawDB.schema.hasTable("workers").then((result) => {
|
||||
if (result != true) {
|
||||
this.rawDB.schema
|
||||
.createTable("workers", (table) => {
|
||||
table
|
||||
.string("phoneNumber", 12)
|
||||
.notNullable()
|
||||
.primary()
|
||||
.unique(),
|
||||
table.integer("telegramID").notNullable().unique(),
|
||||
table.bigInteger("apiID").notNullable(),
|
||||
table.string("apiHash").notNullable(),
|
||||
table.string("password").notNullable(),
|
||||
table.jsonb("faucetMail").notNullable().unique(),
|
||||
table
|
||||
.string("stringSession")
|
||||
.notNullable()
|
||||
.unique(),
|
||||
table.float("balance").notNullable().defaultTo(0.0),
|
||||
table.boolean("canBeRefferal").notNullable(),
|
||||
table
|
||||
.jsonb("browserFingerprint")
|
||||
.notNullable()
|
||||
.unique()
|
||||
.comment(
|
||||
"I save it in json data, so as not to create another table"
|
||||
),
|
||||
table.integer("refferal").defaultTo(null),
|
||||
table
|
||||
.boolean("troubled")
|
||||
.notNullable()
|
||||
.comment("if worker has maximum groups");
|
||||
})
|
||||
.then(() => {
|
||||
logger.debug(
|
||||
"Created `workers` table into `db.sqlite`"
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.rawDB.schema.hasTable("completedGroupsTasks").then((result) => {
|
||||
if (result != true) {
|
||||
this.rawDB.schema
|
||||
.createTable("completedGroupsTasks", (table) => {
|
||||
table.increments("id").primary().unique(),
|
||||
table.string("worker", 12).notNullable(),
|
||||
table.string("groupID").notNullable(),
|
||||
table.timestamp("timeToLeave").notNullable();
|
||||
})
|
||||
.then(() => {
|
||||
logger.debug(
|
||||
"Created `completedGroupsTasks` table into `db.sqlite`"
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
convertWorker(worker: IWorker): IWorkerDatabase {
|
||||
let convertedWorker: IWorkerDatabase = structuredClone(
|
||||
worker
|
||||
) as unknown as IWorkerDatabase;
|
||||
Object.keys(worker).forEach(function (key, index) {
|
||||
if (worker[key] === Object(worker[key])) {
|
||||
convertedWorker[key] = JSON.stringify(worker[key]);
|
||||
} else {
|
||||
convertedWorker[key] = worker[key];
|
||||
}
|
||||
});
|
||||
delete convertedWorker["completedGroupsTasks"];
|
||||
delete convertedWorker["withdraws"];
|
||||
return convertedWorker;
|
||||
}
|
||||
async getCompletedGroups(
|
||||
worker: Pick<IWorker, "phoneNumber">
|
||||
): Promise<IWorkerCompletedGroupTask[]> {
|
||||
return await this.rawDB("completedGroupsTasks")
|
||||
.where({ worker: worker.phoneNumber })
|
||||
.select("timeToLeave", "groupID");
|
||||
}
|
||||
async getWorkers(): Promise<IWorker[]> {
|
||||
try {
|
||||
return Promise.all(
|
||||
(
|
||||
await this.rawDB.select().from<IWorkerDatabase>("workers")
|
||||
).map(async (worker) => {
|
||||
Object.keys(worker).forEach(function (key, index) {
|
||||
try {
|
||||
worker[key] = JSON.parse(worker[key]);
|
||||
} catch (e) {
|
||||
// normal prop
|
||||
}
|
||||
});
|
||||
worker["withdraws"] = [];
|
||||
const completedGroupsTasks = await this.getCompletedGroups(
|
||||
worker
|
||||
);
|
||||
worker["completedGroupsTasks"] = completedGroupsTasks;
|
||||
|
||||
return worker as unknown as IWorker;
|
||||
})
|
||||
);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
async findRefferal(maxRefferals: number): Promise<number | null> {
|
||||
let refferal: number | null = null;
|
||||
const workers = await this.getWorkers();
|
||||
if (workers.length > 0) {
|
||||
for (const mainWorker of workers) {
|
||||
let counter = 0;
|
||||
if (mainWorker.canBeRefferal == true) {
|
||||
const _workers = workers.filter((worker, workerIndex) => {
|
||||
return workerIndex !== workers.indexOf(mainWorker);
|
||||
});
|
||||
for (const _worker of _workers) {
|
||||
if (_worker.refferal == mainWorker.telegramID) {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter < maxRefferals) {
|
||||
refferal = Number(mainWorker.telegramID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return refferal;
|
||||
}
|
||||
|
||||
async addCompletedGroups(
|
||||
worker: Pick<IWorker, "phoneNumber">,
|
||||
group: IWorkerCompletedGroupTask
|
||||
) {
|
||||
await this.rawDB("completedGroupsTasks").insert({
|
||||
worker: worker.phoneNumber,
|
||||
groupID: group.groupID,
|
||||
timeToLeave: group.timeToLeave,
|
||||
});
|
||||
}
|
||||
|
||||
async addUser(
|
||||
worker: Omit<
|
||||
IWorker,
|
||||
| "balance"
|
||||
| "withdraws"
|
||||
| "completedGroupsTasks"
|
||||
| "canBeRefferal"
|
||||
| "browserFingerprint"
|
||||
| "faucetMail"
|
||||
| "troubled"
|
||||
>,
|
||||
wallets_json: string
|
||||
): Promise<void> {
|
||||
const fingerprintGenerator = new FingerprintGenerator();
|
||||
const fingerprint = fingerprintGenerator.getFingerprint({
|
||||
devices: ["desktop"],
|
||||
browsers: ["chrome"],
|
||||
}).fingerprint;
|
||||
|
||||
const faucet: IFaucetMail | undefined = await this.findWallet(
|
||||
wallets_json
|
||||
);
|
||||
if (faucet === undefined) {
|
||||
logger.error("Add new faucet accounts");
|
||||
throw new Error("Add new faucet accounts");
|
||||
} else {
|
||||
const canBeRefferal: boolean = Math.random() < 0.5;
|
||||
|
||||
const _worker: IWorker = {
|
||||
phoneNumber: worker.phoneNumber,
|
||||
telegramID: worker.telegramID,
|
||||
apiID: worker.apiID,
|
||||
apiHash: worker.apiHash,
|
||||
password: worker.password,
|
||||
faucetMail: faucet,
|
||||
stringSession: worker.stringSession,
|
||||
balance: 0.0,
|
||||
withdraws: [],
|
||||
completedGroupsTasks: [],
|
||||
canBeRefferal: canBeRefferal,
|
||||
refferal: worker.refferal,
|
||||
browserFingerprint: fingerprint,
|
||||
troubled: false,
|
||||
};
|
||||
await this.rawDB("workers").insert(this.convertWorker(_worker));
|
||||
}
|
||||
}
|
||||
async findWallet(walletsJson: string): Promise<IFaucetMail | undefined> {
|
||||
const walletsJsonDB = new JSONFaucetMails(walletsJson);
|
||||
await walletsJsonDB.load();
|
||||
const wallets = await walletsJsonDB.getWallets();
|
||||
if (Object.keys(wallets).length == 0) {
|
||||
logger.error("File which you choose doesnt have anything");
|
||||
throw new Error("File which you choose doesnt have anything");
|
||||
}
|
||||
const workers = await this.getWorkers();
|
||||
let faucetWallet: IFaucetMail | undefined = undefined;
|
||||
for (const wallet in wallets) {
|
||||
let flag = false;
|
||||
if (workers.length > 0) {
|
||||
for (const worker of workers) {
|
||||
if (worker.faucetMail.mail.address == wallet) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag == false) {
|
||||
faucetWallet = {
|
||||
faucet: {
|
||||
username: wallets[wallet].faucet.username,
|
||||
password: wallets[wallet].faucet.password,
|
||||
},
|
||||
mail: {
|
||||
address: wallet,
|
||||
password: wallets[wallet].mail.password,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
return faucetWallet;
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,116 @@
|
|||
import Docker from "dockerode";
|
||||
import cliProgress from "cli-progress";
|
||||
import { settings } from "./Settings";
|
||||
import { sleep } from "telegram/Helpers";
|
||||
import { logger } from "../logger";
|
||||
|
||||
export const dockerWrapper= new class DockerController{
|
||||
protected multibar = new cliProgress.MultiBar({
|
||||
hideCursor: true,
|
||||
barsize: 50,
|
||||
barCompleteChar: "❌",
|
||||
barIncompleteChar: "✔️",
|
||||
clearOnComplete: true,
|
||||
format: `{status} | {bar} | {value}/{total}sec timeout`,
|
||||
});
|
||||
async closeOpenedDockers(containers: Docker.Container[]){
|
||||
logger.debug("Closing opened docker containers ");
|
||||
for (const container of containers) {
|
||||
try {
|
||||
await container.remove({ force: true, v: true });
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
async createTorDocker(proxyPort: number,socksPort: number,controlPort: number,timeout = 200): Promise<Docker.Container>{
|
||||
timeout *= 2;
|
||||
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
|
||||
let isPulled = false;
|
||||
mainLoop: for (const image of await docker.listImages()) {
|
||||
const tags = image.RepoTags;
|
||||
if (tags !== undefined)
|
||||
for (const repoTag of tags) {
|
||||
if (repoTag.search("dperson/torproxy:latest") != -1) {
|
||||
isPulled = true;
|
||||
break mainLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPulled != true) {
|
||||
await docker.pull("dperson/torproxy:latest");
|
||||
}
|
||||
|
||||
const options: Docker.ContainerCreateOptions = {
|
||||
Image: "dperson/torproxy:latest",
|
||||
Env: ["PASSWORD=qwerty", "LOCATION=US", "TOR_NewCircuitPeriod=50"],
|
||||
ExposedPorts: {},
|
||||
HostConfig: {
|
||||
PortBindings: {
|
||||
"8118/tcp": [
|
||||
{
|
||||
HostPort: `${proxyPort}`,
|
||||
},
|
||||
],
|
||||
"9050/tcp": [
|
||||
{
|
||||
HostPort: `${socksPort}`,
|
||||
},
|
||||
],
|
||||
"9051/tcp": [
|
||||
{
|
||||
HostPort: `${controlPort}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
Healthcheck: {
|
||||
Interval: 2 * 1_000_000_000,
|
||||
Timeout: 50 * 1_000_000_000,
|
||||
StartPeriod: 50 * 1_000_000_000,
|
||||
// Test:['CMD_SHELL',`curl -sx localhost:8118 'https://check.torproject.org/' | grep -qm1 Congratulations`]
|
||||
},
|
||||
};
|
||||
const container = await docker.createContainer(options);
|
||||
try{
|
||||
await container.start();
|
||||
} catch (e){
|
||||
logger.error(`Some error when starting docker container\n${e}`)
|
||||
throw e
|
||||
}
|
||||
|
||||
const progressBar = this.multibar.create(timeout / 2, 0, {
|
||||
status: `Starting docker${
|
||||
settings.logLevel == "debug"
|
||||
? ` ${proxyPort} ${socksPort} ${controlPort}`
|
||||
: ""
|
||||
}`,
|
||||
});
|
||||
while ((await container.inspect())!.State.Health!.Status != "healthy") {
|
||||
const state = (await container.inspect())!.State.Health!.Status;
|
||||
if (progressBar.getProgress() >= timeout) {
|
||||
await container.remove({force:true,v:true});
|
||||
progressBar.update(timeout / 2, { status: "Failed" });
|
||||
progressBar.stop();
|
||||
throw new Error(`Docker ${container.id} is broken`);
|
||||
}
|
||||
if (state == "unhealthy") {
|
||||
await container.remove({force:true,v:true});
|
||||
progressBar.update(timeout / 2, {
|
||||
status: "Docker is unhealthy...",
|
||||
});
|
||||
progressBar.stop();
|
||||
return await this.createTorDocker(
|
||||
proxyPort,
|
||||
socksPort,
|
||||
controlPort,
|
||||
timeout / 2
|
||||
);
|
||||
}
|
||||
progressBar.increment();
|
||||
await sleep(2000);
|
||||
}
|
||||
progressBar.update(0, { status: "Started" });
|
||||
progressBar.stop();
|
||||
|
||||
return container;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
import Miner from "@ulixee/miner";
|
||||
import Hero from "@ulixee/hero";
|
||||
import ExecuteJsPlugin from "@ulixee/execute-js-plugin";
|
||||
import { Fingerprint } from "fingerprint-generator";
|
||||
import { logger } from "../logger";
|
||||
|
||||
export class HeroWrapper {
|
||||
rawHero: Hero;
|
||||
|
||||
constructor(settings: {
|
||||
fingerprint: Fingerprint;
|
||||
name: string;
|
||||
minerPort: number;
|
||||
socksPort: number;
|
||||
currentIP: string;
|
||||
}) {
|
||||
this.rawHero = new Hero({
|
||||
userProfile: {
|
||||
deviceProfile: {
|
||||
deviceMemory: settings.fingerprint.navigator.deviceMemory,
|
||||
},
|
||||
},
|
||||
name: settings.name,
|
||||
connectionToCore: {
|
||||
host: `ws://127.0.0.1:${settings.minerPort}`,
|
||||
},
|
||||
showChrome: true, // to debug
|
||||
userAgent: settings.fingerprint.navigator.userAgent,
|
||||
viewport: settings.fingerprint.screen,
|
||||
locale: settings.fingerprint.navigator.language,
|
||||
upstreamProxyUrl: `socks5://127.0.0.1:${settings.socksPort}`,
|
||||
upstreamProxyIpMask: {
|
||||
ipLookupService: "icanhazip.com",
|
||||
proxyIp: settings.currentIP,
|
||||
},
|
||||
});
|
||||
this.rawHero.use(ExecuteJsPlugin);
|
||||
}
|
||||
async close() {
|
||||
await this.rawHero.close();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
import { JSONDatabase } from "./AbstractDatabase";
|
||||
import { ISettings } from "../interfaces/ISettings";
|
||||
import { logger } from "../logger";
|
||||
export const settings = new (class Settings
|
||||
extends JSONDatabase
|
||||
implements ISettings
|
||||
{
|
||||
logLevel: "debug" | "info" | "error" = "debug";
|
||||
pararels: number = 3;
|
||||
mainCrypto: "TRX" = "TRX";
|
||||
minimalToWithdraw: number = 0.003;
|
||||
maxRefferals: number = 5;
|
||||
// to find
|
||||
botMessages = {
|
||||
verification: "To continue using this bot,",
|
||||
tasksSelector: "Choose an option to start earning your TRX",
|
||||
taskOver: "Sorry, there are no new ads available.",
|
||||
taskComplete: "Success, ",
|
||||
notInGroup: "not entered the chat",
|
||||
oldMessage: "forwarded is old",
|
||||
};
|
||||
// to send
|
||||
botButtons = {
|
||||
earn: "❇️ Earn cryptocurrency",
|
||||
balance: "💰 Balance",
|
||||
withdraw: "📤 Withdraw",
|
||||
};
|
||||
// to join
|
||||
telegramLinks = {
|
||||
botLink: "@hkearn_trx_bot",
|
||||
groupsToJoin: ["@hkearn_transactions", "@hkearn_updates"],
|
||||
};
|
||||
sleepTime = {
|
||||
afterDoing: [3600, 7200],
|
||||
betweenSessions: [35, 70],
|
||||
};
|
||||
shuffleAccounts: boolean = true;
|
||||
bypassMode: boolean = false;
|
||||
|
||||
constructor() {
|
||||
super("settings.json");
|
||||
}
|
||||
async load(): Promise<void> {
|
||||
await super.load();
|
||||
const settings = await this.rawDB.getObject<ISettings>("/");
|
||||
|
||||
const defaults = {};
|
||||
Object.getOwnPropertyNames(this).forEach((name) => {
|
||||
if (name != "rawDB" && name != "isLoaded") {
|
||||
defaults[name] = this[name];
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(settings).length == 0) {
|
||||
logger.warn("Setup config first...");
|
||||
await this.rawDB.push("/", defaults, true);
|
||||
await this.rawDB.save();
|
||||
} else {
|
||||
mainLoop: for (const setting of Object.keys(defaults)) {
|
||||
if (
|
||||
settings[setting] === undefined ||
|
||||
typeof settings[setting] != typeof defaults[setting]
|
||||
) {
|
||||
this[setting] = defaults[setting];
|
||||
logger.warn(
|
||||
`Setting '${setting}' corrupted or undefined. Check out it...`
|
||||
);
|
||||
} else {
|
||||
if (typeof settings[setting] == "object") {
|
||||
for (const attr of Object.keys(defaults[setting])) {
|
||||
if (
|
||||
Object.keys(settings[setting]).indexOf(attr) ==
|
||||
-1
|
||||
) {
|
||||
this[setting] = defaults[setting];
|
||||
logger.warn(
|
||||
`Setting '${setting}' corrupted. Check out it...`
|
||||
);
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
this[setting] = settings[setting];
|
||||
}
|
||||
}
|
||||
logger.level = this.logLevel;
|
||||
}
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,71 @@
|
|||
import * as telegram from "telegram";
|
||||
import { EntityLike } from "telegram/define";
|
||||
import { isEqual, isUndefined } from "lodash";
|
||||
import { BadRequestError, TimedOutError } from "telegram/errors";
|
||||
|
||||
export class TelegramWorker extends telegram.TelegramClient {
|
||||
async getMessagesByEntity(
|
||||
entity: EntityLike,
|
||||
getMessagesParams?: Omit<
|
||||
Partial<telegram.client.message.IterMessagesParams>,
|
||||
"fromUser"
|
||||
>
|
||||
): Promise<telegram.helpers.TotalList<telegram.Api.Message>> {
|
||||
/*
|
||||
Getting messages from entity
|
||||
In original TelegramClient its not working
|
||||
*/
|
||||
const messages = new telegram.helpers.TotalList<telegram.Api.Message>();
|
||||
for (const message of await super.getMessages(
|
||||
entity,
|
||||
getMessagesParams
|
||||
)) {
|
||||
if (isEqual(message.sender, entity)) {
|
||||
messages.push(message);
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
async waitForNewMassages(
|
||||
entity: EntityLike,
|
||||
lastMessage: telegram.Api.Message,
|
||||
timeout: number = 20
|
||||
): Promise<telegram.Api.Message> {
|
||||
const start = new Date();
|
||||
const params = { minId: lastMessage.id, limit: 2147483647 };
|
||||
let lastMessages = await this.getMessagesByEntity(entity, params);
|
||||
while (lastMessages.length == 0) {
|
||||
if ((+new Date() - +start) / 1000 >= timeout) {
|
||||
throw new TimedOutError(
|
||||
"No new messages",
|
||||
new telegram.Api.messages.GetMessages({})
|
||||
);
|
||||
}
|
||||
lastMessages = await this.getMessagesByEntity(entity, params);
|
||||
}
|
||||
return lastMessage;
|
||||
}
|
||||
async isBannedByClient(entity: telegram.Api.User): Promise<boolean> {
|
||||
if (isUndefined(entity.username) != true) {
|
||||
const blockedUsers = (
|
||||
await super.invoke(
|
||||
new telegram.Api.contacts.GetBlocked({ limit: 2147483647 })
|
||||
)
|
||||
).users as telegram.Api.User[];
|
||||
for (const blockedUser of blockedUsers) {
|
||||
if (
|
||||
isUndefined(blockedUser.username) != false &&
|
||||
blockedUser.username == entity.username!.replace("@", "")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
throw new BadRequestError(
|
||||
"Entity has no nickname",
|
||||
new telegram.Api.contacts.GetBlocked({ limit: 2147483647 })
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
272
database.ts
272
database.ts
|
@ -1,272 +0,0 @@
|
|||
import { JsonDB, Config } from "node-json-db";
|
||||
import { FingerprintGenerator } from "fingerprint-generator";
|
||||
import logger from "./logger";
|
||||
import * as interfacesDB from "./interfaces/databaseInterface";
|
||||
import * as interfacesSettings from "./interfaces/settingsInterface";
|
||||
import { arrayWithoutElementAtIndex } from "./utils";
|
||||
|
||||
export class Database {
|
||||
public readonly default: interfacesDB.DatabaseInterface = {
|
||||
accounts: [],
|
||||
};
|
||||
private json: JsonDB;
|
||||
constructor() {
|
||||
this.json = new JsonDB(new Config("db.json", false, true, "/"));
|
||||
this.json.getData("/").then((result) => {
|
||||
if (Object.keys(result).length == 0) {
|
||||
this.json
|
||||
.push("/", this.default, true)
|
||||
.catch((err) => logger.error(`${err} due setting defaults`))
|
||||
.then(() => {
|
||||
logger.info("Setting DB to defaults...");
|
||||
});
|
||||
this.save();
|
||||
}
|
||||
});
|
||||
}
|
||||
async findWallet(
|
||||
walletsFile: string
|
||||
): Promise<interfacesDB.faucetMailInterface | undefined> {
|
||||
const wallets_json = new JsonDB(
|
||||
new Config(walletsFile, true, true, "/")
|
||||
);
|
||||
const wallets = await wallets_json.getData("/");
|
||||
if (Object.keys(wallets).length == 0) {
|
||||
logger.error("File which you choose doesnt have anything");
|
||||
throw new Error("File which you choose doesnt have anything");
|
||||
}
|
||||
const accounts = await this.getUsers();
|
||||
let faucetWallet: interfacesDB.faucetMailInterface | undefined =
|
||||
undefined;
|
||||
for (const _wallet in wallets) {
|
||||
let flag = false;
|
||||
if (accounts.length > 0) {
|
||||
for (const account of accounts) {
|
||||
if (account.faucetMail.mail.address == _wallet) {
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag == false) {
|
||||
faucetWallet = {
|
||||
faucet: {
|
||||
username: wallets[_wallet].faucetpay.username,
|
||||
password: wallets[_wallet].faucetpay.password,
|
||||
},
|
||||
mail: {
|
||||
address: _wallet,
|
||||
password: wallets[_wallet].mail_passphrase,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
return faucetWallet;
|
||||
}
|
||||
async findRefferal(maxRefferals: number): Promise<number | null> {
|
||||
let refferal: number | null = null;
|
||||
const accounts = await this.getUsers();
|
||||
if (accounts.length > 0) {
|
||||
for (const mainAccount of accounts) {
|
||||
let counter = 0;
|
||||
if (mainAccount.canBeRefferal == true) {
|
||||
const _accounts = arrayWithoutElementAtIndex(
|
||||
accounts,
|
||||
accounts.indexOf(mainAccount)
|
||||
);
|
||||
for (const _account of _accounts) {
|
||||
if (_account.refferal == mainAccount.telegramID) {
|
||||
counter += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter < maxRefferals) {
|
||||
refferal = Number(mainAccount.telegramID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return refferal;
|
||||
}
|
||||
async save() {
|
||||
await this.json.save(true);
|
||||
}
|
||||
async updateUser(account: interfacesDB.AccountInterface) {
|
||||
const index = await this.json.getIndex(
|
||||
"/accounts",
|
||||
account.phoneNumber,
|
||||
"phoneNumber"
|
||||
);
|
||||
logger.debug(`Index in database is ${index} of ${account.phoneNumber}`);
|
||||
await this.json.push(`/accounts[${index}]`, account, true);
|
||||
}
|
||||
async addUser(
|
||||
account: Omit<
|
||||
interfacesDB.AccountInterface,
|
||||
| "balance"
|
||||
| "withdraws"
|
||||
| "completedGroupsTasks"
|
||||
| "canBeRefferal"
|
||||
| "browserFingerprint"
|
||||
| "faucetMail"
|
||||
>,
|
||||
wallets_json: string
|
||||
): Promise<void> {
|
||||
const fingerprintGenerator = new FingerprintGenerator();
|
||||
const fingerprint = fingerprintGenerator.getFingerprint({
|
||||
devices: ["desktop"],
|
||||
browsers: ["chrome"],
|
||||
}).fingerprint;
|
||||
|
||||
const faucet: interfacesDB.faucetMailInterface | undefined =
|
||||
await this.findWallet(wallets_json);
|
||||
if (faucet === undefined) {
|
||||
logger.error("Add new faucet accounts");
|
||||
throw new Error("Add new faucet accounts");
|
||||
} else {
|
||||
const canBeRefferal: boolean = Math.random() < 0.5;
|
||||
|
||||
const _account: interfacesDB.AccountInterface = {
|
||||
phoneNumber: account.phoneNumber,
|
||||
telegramID: account.telegramID,
|
||||
apiID: account.apiID,
|
||||
apiHash: account.apiHash,
|
||||
password: account.password,
|
||||
faucetMail: faucet,
|
||||
stringSession: account.stringSession,
|
||||
balance: 0.0,
|
||||
withdraws: [],
|
||||
completedGroupsTasks: [],
|
||||
canBeRefferal: canBeRefferal,
|
||||
refferal: account.refferal,
|
||||
browserFingerprint: fingerprint,
|
||||
};
|
||||
await this.json.push(`/accounts[]`, _account);
|
||||
}
|
||||
await this.save();
|
||||
}
|
||||
|
||||
async getUsers(): Promise<interfacesDB.AccountInterface[]> {
|
||||
try {
|
||||
return await this.json.getObject<interfacesDB.AccountInterface[]>(
|
||||
"/accounts"
|
||||
);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Settings implements interfacesSettings.settingsInterface {
|
||||
public readonly default: interfacesSettings.settingsInterface = {
|
||||
logLevel: "debug",
|
||||
pararels: 2,
|
||||
mainCrypto: "TRX",
|
||||
minimalToWithdraw: 0.0003,
|
||||
maxRefferals: 3,
|
||||
botMessages: {
|
||||
verification: "To continue using this bot,",
|
||||
tasksSelector: "Choose an option to start earning your TRX",
|
||||
taskOver: "Sorry, there are no new ads available.",
|
||||
taskComplete: "Success, ",
|
||||
notInGroup: "not entered the chat",
|
||||
oldMessage: "forwarded is old",
|
||||
},
|
||||
botButtons: {
|
||||
earn: "❇️ Earn cryptocurrency",
|
||||
balance: "💰 Balance",
|
||||
withdraw: "📤 Withdraw",
|
||||
},
|
||||
telegramLinks: {
|
||||
botLink: "@hkearn_trx_bot",
|
||||
groupsToJoin: ["@hkearn_transactions", "@hkearn_updates"],
|
||||
},
|
||||
bypassMode: false,
|
||||
sleepTime: {
|
||||
afterDoing: [1 * 3600, 2 * 3600],
|
||||
betweenSessions: [35, 70],
|
||||
},
|
||||
shuffleAccounts: true,
|
||||
};
|
||||
logLevel: "debug" | "info" | "error";
|
||||
mainCrypto: "TRX";
|
||||
minimalToWithdraw: number;
|
||||
maxRefferals: number;
|
||||
botMessages: {
|
||||
verification: string;
|
||||
tasksSelector: string;
|
||||
taskOver: string;
|
||||
taskComplete: string;
|
||||
notInGroup: string;
|
||||
oldMessage: string;
|
||||
};
|
||||
botButtons: { earn: string; balance: string; withdraw: string };
|
||||
telegramLinks: { botLink: string; groupsToJoin: string[] };
|
||||
bypassMode: boolean;
|
||||
pararels: number;
|
||||
sleepTime: {
|
||||
afterDoing: number[];
|
||||
betweenSessions: number[];
|
||||
};
|
||||
shuffleAccounts: boolean;
|
||||
private json: JsonDB;
|
||||
constructor() {
|
||||
this.json = new JsonDB(new Config("settings.json", false, true, "/"));
|
||||
this.json
|
||||
.getObject<interfacesSettings.settingsInterface>("/")
|
||||
.then((result) => {
|
||||
if (Object.keys(result).length == 0) {
|
||||
logger.warn("Setup config first...");
|
||||
|
||||
this.json
|
||||
.push("/", this.default, true)
|
||||
.catch((err) =>
|
||||
logger.error(`${err} due setting defaults`)
|
||||
)
|
||||
.then(() => {
|
||||
this.json.save(true).then(() => {
|
||||
throw new Error("Config doesn't setup");
|
||||
});
|
||||
});
|
||||
} else {
|
||||
mainLoop: for (const setting of Object.keys(this.default)) {
|
||||
if (
|
||||
result[setting] === undefined ||
|
||||
typeof result[setting] !=
|
||||
typeof this.default[setting]
|
||||
) {
|
||||
this[setting] = this.default[setting];
|
||||
logger.warn(
|
||||
`Setting '${setting}' corrupted or undefined. Check out it...`
|
||||
);
|
||||
} else {
|
||||
if (typeof result[setting] == "object") {
|
||||
for (const attr of Object.keys(
|
||||
this.default[setting]
|
||||
)) {
|
||||
if (
|
||||
Object.keys(result[setting]).indexOf(
|
||||
attr
|
||||
) == -1
|
||||
) {
|
||||
this[setting] = this.default[setting];
|
||||
logger.warn(
|
||||
`Setting '${setting}' corrupted. Check out it...`
|
||||
);
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
this[setting] = result[setting];
|
||||
}
|
||||
}
|
||||
logger.level = this.logLevel;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const database = new Database();
|
||||
const settings = new Settings();
|
||||
export { database, settings };
|
718
index.ts
718
index.ts
|
@ -1,688 +1,26 @@
|
|||
import fs = require("fs");
|
||||
import { database as db, settings } from "./database";
|
||||
import prompt from "prompts";
|
||||
import logger from "./logger";
|
||||
import * as telegram from "telegram";
|
||||
import { LogLevel } from "telegram/extensions/Logger";
|
||||
import { AccountInterface } from "./interfaces/databaseInterface";
|
||||
import { sleep } from "telegram/Helpers";
|
||||
import findFreePorts from "find-free-ports";
|
||||
import {
|
||||
waitNewMessages,
|
||||
startNewTorDocker,
|
||||
getIP,
|
||||
getMessagesByEntity,
|
||||
isBannedByClient,
|
||||
randomAB,
|
||||
} from "./utils";
|
||||
import TorControl from "tor-control";
|
||||
import Miner from "@ulixee/miner";
|
||||
import Hero from "@ulixee/hero";
|
||||
import { portsInterface, usedIPInterface } from "./interfaces/otherInterfaces";
|
||||
import {
|
||||
doSitesTasks,
|
||||
vertification,
|
||||
doChatsTasks,
|
||||
doBotTasks,
|
||||
} from "./automatization";
|
||||
import ExecuteJsPlugin from "@ulixee/execute-js-plugin";
|
||||
import _ from "lodash";
|
||||
import Docker from "dockerode";
|
||||
import cliProgress from "cli-progress";
|
||||
import BigInteger from "big-integer";
|
||||
|
||||
const addAccounts: () => Promise<void> = async () => {
|
||||
let apiId = 0;
|
||||
let apiHash = "";
|
||||
let accounts = await db.getUsers();
|
||||
if (accounts.length != 0) {
|
||||
const usePrevData = await prompt({
|
||||
type: "confirm",
|
||||
name: "confirmed",
|
||||
message: "Use apiId and apiHash from last added account?",
|
||||
});
|
||||
if (usePrevData.confirmed == true) {
|
||||
apiId = accounts[accounts.length - 1].apiID;
|
||||
apiHash = accounts[accounts.length - 1].apiHash;
|
||||
}
|
||||
}
|
||||
if (apiId == 0 && apiHash == "") {
|
||||
const api = await prompt([
|
||||
{
|
||||
type: "number",
|
||||
name: "apiId",
|
||||
message: "ApiId?",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "apiHash",
|
||||
message: "ApiHash?",
|
||||
},
|
||||
]);
|
||||
apiId = Number(api.apiId);
|
||||
apiHash = api.apiHash;
|
||||
}
|
||||
const jsonFiles: prompt.Choice[] = [];
|
||||
fs.readdirSync("./").forEach((file) => {
|
||||
if (
|
||||
file.search(".json") != -1 &&
|
||||
file != "db.json" &&
|
||||
file != "settings.json"
|
||||
) {
|
||||
jsonFiles.push({
|
||||
title: file,
|
||||
description: "json file",
|
||||
value: file,
|
||||
});
|
||||
}
|
||||
});
|
||||
const walletsFile = (
|
||||
await prompt({
|
||||
type: "select",
|
||||
name: "file",
|
||||
message: "Choose wallets json file",
|
||||
choices: jsonFiles,
|
||||
})
|
||||
).file;
|
||||
await db.findWallet(walletsFile);
|
||||
|
||||
mainLoop: while (true) {
|
||||
accounts = await db.getUsers();
|
||||
const answers = await prompt([
|
||||
{
|
||||
type: "text",
|
||||
name: "number",
|
||||
message: "Phone number?",
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
name: "password",
|
||||
message: "2FA Password?",
|
||||
},
|
||||
]);
|
||||
for (const account of accounts) {
|
||||
if (account.phoneNumber == answers.number) {
|
||||
logger.warn("You already added this number");
|
||||
continue mainLoop;
|
||||
}
|
||||
}
|
||||
const session = new telegram.sessions.StringSession("");
|
||||
const client = new telegram.TelegramClient(session, apiId, apiHash, {
|
||||
deviceModel: "Samsung SM-G980",
|
||||
connectionRetries: 5,
|
||||
systemVersion: "10",
|
||||
});
|
||||
client.setLogLevel(LogLevel.ERROR);
|
||||
await client.start({
|
||||
phoneNumber: async () => answers.number.replace(/ /g, ""),
|
||||
password: async () => answers.password.replace(/ /g, ""),
|
||||
phoneCode: async () =>
|
||||
(
|
||||
await prompt({
|
||||
type: "number",
|
||||
name: "code",
|
||||
message: "Enter recieved code",
|
||||
})
|
||||
).code.toString(),
|
||||
onError: (err) => {
|
||||
logger.error(
|
||||
`Error due singning into telegram account\n${err}`
|
||||
);
|
||||
throw err;
|
||||
},
|
||||
});
|
||||
if ((await client.isUserAuthorized()) == true) {
|
||||
const account: telegram.Api.User | telegram.Api.InputPeerUser =
|
||||
await client.getMe(false);
|
||||
if (account instanceof telegram.Api.User) {
|
||||
await db.addUser(
|
||||
{
|
||||
password: answers.password,
|
||||
phoneNumber: answers.number,
|
||||
apiHash: apiHash,
|
||||
telegramID: Number(account.id),
|
||||
apiID: apiId,
|
||||
stringSession: String(client.session.save()),
|
||||
refferal: await db.findRefferal(settings.maxRefferals),
|
||||
},
|
||||
walletsFile
|
||||
);
|
||||
} else {
|
||||
logger.error("Wrong type of account?");
|
||||
}
|
||||
} else {
|
||||
logger.error("Client not authorized");
|
||||
}
|
||||
if (
|
||||
(
|
||||
await prompt({
|
||||
type: "confirm",
|
||||
name: "continue",
|
||||
message: "continue?",
|
||||
})
|
||||
).continue != true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const farm: () => Promise<void> = async () => {
|
||||
const usedIPs: usedIPInterface[] = [];
|
||||
const proccesGroup = async (
|
||||
workersGroups: AccountInterface[],
|
||||
ports: portsInterface
|
||||
) => {
|
||||
workersLoop: for (const worker of workersGroups) {
|
||||
logger.info(
|
||||
`Current worker:${worker.phoneNumber}\nBalance:${worker.balance}`
|
||||
);
|
||||
{
|
||||
let tor: any;
|
||||
try {
|
||||
tor = new TorControl({
|
||||
host: "127.0.0.1",
|
||||
port: ports.control,
|
||||
password: "qwerty", // Your password for tor-control
|
||||
persistent: false, // Keep connection (persistent)
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Cant connect to tor control via ${ports.control}\n${err}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
function isFree(currentIP: string) {
|
||||
for (const usedIP of usedIPs) {
|
||||
if (
|
||||
usedIP.usedIps.indexOf(currentIP) != -1 ||
|
||||
usedIP.current == currentIP
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
while (true) {
|
||||
const currentIP = await getIP(ports.http);
|
||||
if (currentIP != null) {
|
||||
if (isFree(currentIP)) {
|
||||
usedIPs.filter((value) => {
|
||||
return _.isEqual(worker, value.worker);
|
||||
})[0].current = currentIP;
|
||||
usedIPs
|
||||
.filter((value) => {
|
||||
return _.isEqual(worker, value.worker);
|
||||
})[0]
|
||||
.usedIps.push(currentIP);
|
||||
break;
|
||||
} else {
|
||||
await tor.signalNewnym();
|
||||
await sleep(3_000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const fingerprint = worker.browserFingerprint;
|
||||
let hero: Hero;
|
||||
while (true) {
|
||||
hero = new Hero({
|
||||
userProfile: {
|
||||
deviceProfile: {
|
||||
deviceMemory: fingerprint.navigator.deviceMemory,
|
||||
},
|
||||
},
|
||||
name: `${worker.telegramID}`,
|
||||
connectionToCore: {
|
||||
host: `ws://127.0.0.1:${ports.minerPort}`,
|
||||
},
|
||||
disableDevtools: true, // to bypass hk site
|
||||
showChrome: true, // to debug
|
||||
userAgent: fingerprint.navigator.userAgent,
|
||||
viewport: fingerprint.screen,
|
||||
locale: fingerprint.navigator.language,
|
||||
upstreamProxyUrl: `socks5://127.0.0.1:${ports.socks}`,
|
||||
upstreamProxyIpMask: {
|
||||
ipLookupService: "icanhazip.com",
|
||||
proxyIp: usedIPs.filter((value) => {
|
||||
return _.isEqual(worker, value.worker);
|
||||
})[0].current,
|
||||
},
|
||||
});
|
||||
hero.use(ExecuteJsPlugin);
|
||||
try {
|
||||
await hero.goto("https://www.google.com");
|
||||
} catch (err) {
|
||||
await hero.close();
|
||||
logger.warn(
|
||||
`Some error due openning Hero. Trying again...\n${err}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
const client = new telegram.TelegramClient(
|
||||
new telegram.sessions.StringSession(worker.stringSession),
|
||||
worker.apiID,
|
||||
worker.apiHash,
|
||||
{
|
||||
deviceModel: "Samsung SM-G980",
|
||||
connectionRetries: 5,
|
||||
systemVersion: "10",
|
||||
}
|
||||
);
|
||||
client.setLogLevel(LogLevel.NONE);
|
||||
await client.connect();
|
||||
if ((await client.checkAuthorization()) == false) {
|
||||
logger.error(
|
||||
`Account ${worker.phoneNumber} is not authorizated`
|
||||
);
|
||||
continue workersLoop;
|
||||
} else {
|
||||
logger.debug(
|
||||
`Successfully connected to account ${worker.phoneNumber}`
|
||||
);
|
||||
// https://gram.js.org/beta/modules/Api.channels.html
|
||||
// https://gram.js.org/beta/classes/Api.messages.DeleteChat.html
|
||||
let botEntity: telegram.Api.User;
|
||||
try {
|
||||
botEntity = (await client.getEntity(
|
||||
settings.telegramLinks.botLink
|
||||
)) as telegram.Api.User;
|
||||
} catch (err) {
|
||||
if (err instanceof telegram.errors.FloodWaitError) {
|
||||
switch (err.errorMessage) {
|
||||
case "FLOOD":
|
||||
logger.warn(
|
||||
`Account has flood(${err.seconds} secs timeout) error,skipping`
|
||||
);
|
||||
break;
|
||||
default:
|
||||
logger.error(
|
||||
`Unknown error due getEntity ${err}`
|
||||
);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
logger.error(`Unknown error due getEntity ${err}`);
|
||||
}
|
||||
usedIPs.filter((value) => {
|
||||
return _.isEqual(worker, value.worker);
|
||||
})[0].current = "";
|
||||
usedIPs
|
||||
.filter((value) => {
|
||||
return _.isEqual(worker, value.worker);
|
||||
})[0]
|
||||
.usedIps.pop();
|
||||
await hero.close();
|
||||
continue workersLoop;
|
||||
}
|
||||
|
||||
// leaving old groups
|
||||
{
|
||||
const now = new Date();
|
||||
worker.completedGroupsTasks =
|
||||
worker.completedGroupsTasks.filter(async (oldGroup) => {
|
||||
if (+now > oldGroup.timeToLeave) {
|
||||
const olderGroups =
|
||||
worker.completedGroupsTasks.filter(
|
||||
(value) => {
|
||||
if (
|
||||
value.groupID ==
|
||||
oldGroup.groupID &&
|
||||
value.timeToLeave >
|
||||
oldGroup.timeToLeave
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
if (olderGroups.length == 0) {
|
||||
let peerChannel: telegram.Api.TypeInputPeer;
|
||||
try {
|
||||
peerChannel =
|
||||
await client.getInputEntity(
|
||||
BigInteger(oldGroup.groupID)
|
||||
);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await client.invoke(
|
||||
new telegram.Api.channels.GetParticipant(
|
||||
{
|
||||
channel: peerChannel,
|
||||
participant: "me",
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.code == 400) {
|
||||
return false;
|
||||
} else {
|
||||
logger.error(
|
||||
`Unknown error due GetParticipant | ${worker.phoneNumber}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
try {
|
||||
await client.invoke(
|
||||
new telegram.Api.channels.LeaveChannel(
|
||||
{
|
||||
channel: peerChannel,
|
||||
}
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
`Cant leave channel | ${worker.phoneNumber}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
//
|
||||
|
||||
for (const chat of settings.telegramLinks.groupsToJoin) {
|
||||
try {
|
||||
await client.invoke(
|
||||
new telegram.Api.channels.GetParticipant({
|
||||
channel: chat,
|
||||
participant: "me",
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.code == 400) {
|
||||
try {
|
||||
await client.invoke(
|
||||
new telegram.Api.channels.JoinChannel({
|
||||
channel: chat,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
if (err instanceof telegram.errors.RPCError) {
|
||||
switch (err.errorMessage) {
|
||||
case "CHANNELS_TOO_MUCH":
|
||||
logger.error(
|
||||
`Too much groups | ${worker.phoneNumber}`
|
||||
);
|
||||
continue workersLoop;
|
||||
default:
|
||||
logger.error(
|
||||
`Some error due joining HK groups | ${worker.phoneNumber}\n${err.message}\n${err.stack}`
|
||||
);
|
||||
continue workersLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.error(
|
||||
`Unknown error due GetParticipant | ${worker.phoneNumber}`
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// unblock hkbot
|
||||
if (
|
||||
await isBannedByClient(
|
||||
client,
|
||||
settings.telegramLinks.botLink
|
||||
)
|
||||
) {
|
||||
const result = await client.invoke(
|
||||
new telegram.Api.contacts.Unblock({
|
||||
id: settings.telegramLinks.botLink,
|
||||
})
|
||||
);
|
||||
if (result != true) {
|
||||
logger.error(
|
||||
`Cant unblock ${settings.telegramLinks.botLink} | ${worker.phoneNumber}`
|
||||
);
|
||||
continue workersLoop;
|
||||
} else {
|
||||
logger.info(
|
||||
`HK bot unblocked | ${worker.phoneNumber}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
await sleep(Math.random() * 50_000);
|
||||
if (
|
||||
(await getMessagesByEntity(client, botEntity, botEntity))
|
||||
.length == 0
|
||||
) {
|
||||
// sending start message
|
||||
let id = -1;
|
||||
if (worker.refferal !== null) {
|
||||
id = (
|
||||
await client.sendMessage(botEntity, {
|
||||
message: `/start ${worker.refferal}`,
|
||||
})
|
||||
).id;
|
||||
logger.debug(
|
||||
`First start of ${botEntity.username} via refferal link of ${worker.refferal} | ${worker.phoneNumber}`
|
||||
);
|
||||
} else {
|
||||
id = (
|
||||
await client.sendMessage(botEntity, {
|
||||
message: `/start`,
|
||||
})
|
||||
).id;
|
||||
logger.debug(
|
||||
`First start of ${botEntity.username} | ${worker.phoneNumber}`
|
||||
);
|
||||
}
|
||||
await waitNewMessages(client, worker, botEntity, id);
|
||||
}
|
||||
logger.info(`Sending earn message... | ${worker.phoneNumber}`);
|
||||
const requestTasksMessage = await client.sendMessage(
|
||||
botEntity,
|
||||
{
|
||||
message: settings.botButtons.earn,
|
||||
}
|
||||
);
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
requestTasksMessage.id
|
||||
);
|
||||
let tasksSelector: telegram.Api.Message = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: requestTasksMessage.id,
|
||||
})
|
||||
)[0];
|
||||
if (
|
||||
tasksSelector.message.includes(
|
||||
settings.botMessages.verification
|
||||
) == true
|
||||
) {
|
||||
// vertification
|
||||
logger.warn(
|
||||
`Account ${worker.phoneNumber} is unvertificated`
|
||||
);
|
||||
const url: string = tasksSelector.buttons![0][0].url!;
|
||||
await vertification(hero, url);
|
||||
const requestTasksMessage = await client.sendMessage(
|
||||
botEntity,
|
||||
{
|
||||
message: settings.botButtons.earn,
|
||||
}
|
||||
);
|
||||
await waitNewMessages(
|
||||
client,
|
||||
worker,
|
||||
botEntity,
|
||||
requestTasksMessage.id
|
||||
);
|
||||
tasksSelector = (
|
||||
await client.getMessages(botEntity, {
|
||||
minId: requestTasksMessage.id,
|
||||
})
|
||||
)[0];
|
||||
}
|
||||
|
||||
try {
|
||||
await doSitesTasks(
|
||||
client,
|
||||
worker,
|
||||
hero,
|
||||
botEntity,
|
||||
tasksSelector
|
||||
);
|
||||
await doChatsTasks(
|
||||
client,
|
||||
worker,
|
||||
hero,
|
||||
botEntity,
|
||||
tasksSelector
|
||||
);
|
||||
try {
|
||||
await doBotTasks(
|
||||
client,
|
||||
worker,
|
||||
hero,
|
||||
botEntity,
|
||||
tasksSelector
|
||||
);
|
||||
} catch (err) {
|
||||
await client.sendMessage(botEntity, {
|
||||
message: "/cancel",
|
||||
});
|
||||
throw err;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Some error due doing tasks\n${err}\n${err.stack}`
|
||||
);
|
||||
}
|
||||
db.updateUser(worker);
|
||||
await hero.close();
|
||||
await client.disconnect();
|
||||
await sleep(
|
||||
randomAB(
|
||||
settings.sleepTime.betweenSessions[0],
|
||||
settings.sleepTime.betweenSessions[1]
|
||||
) * 1_000
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const workers = await db.getUsers();
|
||||
if (settings.shuffleAccounts) {
|
||||
workers.sort(() => Math.random() - 0.5);
|
||||
}
|
||||
const workersGroups: Array<AccountInterface[]> = [];
|
||||
|
||||
for (const worker of workers) {
|
||||
usedIPs.push({
|
||||
worker: worker,
|
||||
usedIps: [],
|
||||
current: "",
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i != settings.pararels; i++) {
|
||||
const startIndex = i * Math.ceil(workers.length / settings.pararels);
|
||||
const _workers = workers.slice(
|
||||
startIndex,
|
||||
startIndex + Math.ceil(workers.length / settings.pararels)
|
||||
);
|
||||
workersGroups.push(_workers);
|
||||
}
|
||||
const pararels: Promise<void>[] = [];
|
||||
|
||||
const miner = new Miner();
|
||||
await miner.listen({ port: (await findFreePorts(1))[0] });
|
||||
|
||||
const _ports = await findFreePorts(workers.length * 3);
|
||||
// logger.debug(`Is there port of miner:${_ports.indexOf(await miner.port)}, ${await miner.port}`)
|
||||
let containers: Docker.Container[] = [];
|
||||
|
||||
{
|
||||
const multibar = new cliProgress.MultiBar({
|
||||
hideCursor: true,
|
||||
barsize: 50,
|
||||
barCompleteChar: "❌",
|
||||
barIncompleteChar: "✔️",
|
||||
clearOnComplete: true,
|
||||
format: `{status} | {bar} | {value}/{total}sec timeout`,
|
||||
});
|
||||
const _containers: Promise<Docker.Container>[] = [];
|
||||
for (let i = 0; i != workersGroups.length; i++) {
|
||||
_containers.push(
|
||||
startNewTorDocker(
|
||||
_ports[i * 3],
|
||||
_ports[i * 3 + 1],
|
||||
_ports[i * 3 + 2],
|
||||
multibar
|
||||
)
|
||||
);
|
||||
}
|
||||
containers = (await Promise.allSettled(_containers)).map((value) => {
|
||||
return (value as PromiseFulfilledResult<Docker.Container>).value;
|
||||
});
|
||||
multibar.stop();
|
||||
}
|
||||
|
||||
for (let i = 0; i != workersGroups.length; i++) {
|
||||
pararels.push(
|
||||
proccesGroup(workersGroups[i], {
|
||||
http: _ports[i * 3],
|
||||
socks: _ports[i * 3 + 1],
|
||||
control: _ports[i * 3 + 2],
|
||||
minerPort: await miner.port,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const results = await Promise.allSettled(pararels);
|
||||
for (const result of results) {
|
||||
if (result.status == "rejected") {
|
||||
logger.warn(`Promise is canceled due ${result.reason}`);
|
||||
}
|
||||
}
|
||||
logger.debug("Closing opened docker containers ");
|
||||
for (const container of containers) {
|
||||
try {
|
||||
await container.stop();
|
||||
} catch (err) {}
|
||||
}
|
||||
await db.save();
|
||||
await miner.close(true);
|
||||
};
|
||||
|
||||
// menu
|
||||
import { db } from "./classes/Database";
|
||||
import { settings } from "./classes/Settings";
|
||||
import { addAccounts } from "./addAccounts";
|
||||
import { logger } from "./logger";
|
||||
import { executor } from "./classes/Automatization";
|
||||
(async () => {
|
||||
while (true) {
|
||||
let accounts: AccountInterface[] = [];
|
||||
try {
|
||||
accounts = await db.getUsers();
|
||||
} catch (err) {
|
||||
continue;
|
||||
}
|
||||
// databases load
|
||||
await settings.load();
|
||||
//
|
||||
|
||||
const workers = await db.getWorkers();
|
||||
|
||||
while (true) {
|
||||
const answer = await prompt({
|
||||
type: "select",
|
||||
name: "menu",
|
||||
message: "Choose action",
|
||||
choices: [
|
||||
accounts.length > 0
|
||||
workers.length > 0
|
||||
? {
|
||||
title: "Start",
|
||||
description: `Starting farm for ${accounts.length} accounts`,
|
||||
description: `Starting farm for ${workers.length} accounts`,
|
||||
value: "start",
|
||||
}
|
||||
: {
|
||||
|
@ -708,29 +46,14 @@ const farm: () => Promise<void> = async () => {
|
|||
},
|
||||
],
|
||||
});
|
||||
|
||||
switch (answer.menu) {
|
||||
case "start":
|
||||
await executor.proccessWorkers()
|
||||
break;
|
||||
case "addAccounts":
|
||||
await addAccounts();
|
||||
break;
|
||||
case "start":
|
||||
while (true) {
|
||||
try {
|
||||
await farm();
|
||||
const sleepTime = randomAB(
|
||||
settings.sleepTime.afterDoing[0],
|
||||
settings.sleepTime.afterDoing[1]
|
||||
);
|
||||
logger.info(`Sleeping for ${sleepTime} secs`);
|
||||
await sleep(sleepTime * 1_000);
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
`Unknown error\n${err.stack}\n${typeof err}`
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.info("Bye bye");
|
||||
process.exit();
|
||||
|
@ -739,9 +62,6 @@ const farm: () => Promise<void> = async () => {
|
|||
})();
|
||||
|
||||
process.on("SIGINT", function () {
|
||||
db.save().then(() => {
|
||||
logger.info("Bye bye");
|
||||
process.exit();
|
||||
});
|
||||
logger.info("Bye bye");
|
||||
process.exit();
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { IWorker } from "./IWorker";
|
||||
|
||||
export interface IUsedIPInterface {
|
||||
worker: Pick<IWorker,"phoneNumber">;
|
||||
usedIps: string[];
|
||||
current: string;
|
||||
}
|
||||
|
||||
export interface IGroupPorts {
|
||||
http: number,
|
||||
socks: number,
|
||||
control: number,
|
||||
miner: number
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
export interface IFaucetMail {
|
||||
readonly faucet: {
|
||||
readonly username: string;
|
||||
readonly password: string;
|
||||
};
|
||||
readonly mail: {
|
||||
readonly address: string;
|
||||
readonly password: string;
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
export interface settingsInterface {
|
||||
export interface ISettings {
|
||||
logLevel: "debug" | "info" | "error";
|
||||
pararels: number;
|
||||
mainCrypto: "TRX";
|
||||
|
@ -30,4 +30,4 @@ export interface settingsInterface {
|
|||
};
|
||||
shuffleAccounts: boolean;
|
||||
bypassMode: boolean;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export interface IWorkerWithdraw {
|
||||
timestamp: number,
|
||||
amount: number,
|
||||
toMail: string,
|
||||
isWithdrawed: boolean
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
import { Fingerprint } from "fingerprint-generator";
|
||||
import { IFaucetMail } from "./IFaucetMail";
|
||||
import { IWorkerWithdraw } from "./IWithdraw";
|
||||
|
||||
export interface IWorkerCompletedGroupTask {
|
||||
readonly timeToLeave: number;
|
||||
readonly groupID: string;
|
||||
}
|
||||
|
||||
interface IWorkerBase {
|
||||
readonly phoneNumber: string;
|
||||
readonly telegramID: number;
|
||||
readonly apiID: number;
|
||||
readonly apiHash: string;
|
||||
readonly password: string;
|
||||
readonly stringSession: string;
|
||||
readonly balance: number;
|
||||
readonly canBeRefferal: boolean;
|
||||
|
||||
readonly refferal: number | null;
|
||||
}
|
||||
|
||||
export interface IWorkerDatabase extends IWorkerBase {
|
||||
readonly faucetMail: string;
|
||||
readonly browserFingerprint: string;
|
||||
troubled: boolean
|
||||
}
|
||||
|
||||
export interface IWorker extends IWorkerBase{
|
||||
|
||||
readonly faucetMail: IFaucetMail;
|
||||
readonly browserFingerprint: Fingerprint;
|
||||
withdraws: IWorkerWithdraw[];
|
||||
completedGroupsTasks: IWorkerCompletedGroupTask[];
|
||||
troubled: boolean
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
import { Fingerprint } from "fingerprint-generator";
|
||||
export interface faucetMailInterface {
|
||||
faucet: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
mail: {
|
||||
address: string;
|
||||
password: string;
|
||||
};
|
||||
}
|
||||
export interface AccountCompletedGroupsTasksInterface {
|
||||
timeToLeave: number;
|
||||
groupID: string;
|
||||
}
|
||||
|
||||
export interface AccountWithdrawInterface {}
|
||||
export interface AccountInterface {
|
||||
phoneNumber: string;
|
||||
telegramID: number;
|
||||
apiID: number;
|
||||
apiHash: string;
|
||||
password: string;
|
||||
faucetMail: faucetMailInterface;
|
||||
stringSession: string;
|
||||
balance: number;
|
||||
withdraws: AccountWithdrawInterface[];
|
||||
completedGroupsTasks: AccountCompletedGroupsTasksInterface[];
|
||||
canBeRefferal: boolean;
|
||||
browserFingerprint: Fingerprint;
|
||||
refferal: number | null;
|
||||
}
|
||||
export interface DatabaseInterface {
|
||||
accounts: AccountInterface[];
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import * as telegram from "telegram";
|
||||
import { AccountInterface } from "./databaseInterface";
|
||||
|
||||
export interface prevTaskInterface {
|
||||
task: telegram.Api.Message;
|
||||
lastMessage: telegram.Api.Message;
|
||||
}
|
||||
|
||||
export interface portsInterface {
|
||||
http: number;
|
||||
socks: number;
|
||||
control: number;
|
||||
minerPort?: number;
|
||||
}
|
||||
|
||||
export interface usedIPInterface {
|
||||
worker: AccountInterface;
|
||||
usedIps: string[];
|
||||
current: string;
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import winston = require("winston");
|
||||
const logger = winston.createLogger({
|
||||
import winston from "winston";
|
||||
export const logger = winston.createLogger({
|
||||
level: "debug",
|
||||
format: winston.format.combine(
|
||||
winston.format.colorize(),
|
||||
winston.format.printf((info) => {
|
||||
return `${new Date().toLocaleTimeString()} | ${info.level} - ${
|
||||
return `${(new Date()).toLocaleTimeString()} | ${info.level} - ${
|
||||
info.message
|
||||
} `;
|
||||
})
|
||||
|
@ -15,5 +15,3 @@ const logger = winston.createLogger({
|
|||
new winston.transports.File({ filename: "info.log" }),
|
||||
],
|
||||
});
|
||||
|
||||
export default logger;
|
||||
|
|
13
package.json
13
package.json
|
@ -1,19 +1,22 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"@ulixee/execute-js-plugin": "^2.0.0-alpha.16",
|
||||
"@ulixee/hero": "^2.0.0-alpha.16",
|
||||
"@ulixee/miner": "^2.0.0-alpha.16",
|
||||
"@ulixee/execute-js-plugin": "^2.0.0-alpha.17",
|
||||
"@ulixee/hero": "^2.0.0-alpha.17",
|
||||
"@ulixee/miner": "^2.0.0-alpha.17",
|
||||
"axios": "^1.2.1",
|
||||
"better-sqlite3": "^8.0.1",
|
||||
"cli-progress": "^3.11.2",
|
||||
"dockerode": "^3.3.4",
|
||||
"find-free-ports": "^3.0.0",
|
||||
"fingerprint-generator": "^2.1.7",
|
||||
"knex": "^2.3.0",
|
||||
"lodash": "^4.17.21",
|
||||
"node-json-db": "^2.1.3",
|
||||
"prompts": "^2.4.2",
|
||||
"socks5-https-client": "^1.2.1",
|
||||
"telegram": "^2.14.7",
|
||||
"telegram": "^2.15.2",
|
||||
"tor-control": "^0.0.3",
|
||||
"type-fest": "^3.4.0",
|
||||
"typescript": "^4.9.4",
|
||||
"winston": "^3.8.2"
|
||||
},
|
||||
|
@ -25,7 +28,7 @@
|
|||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/dockerode": "^3.3.14",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.11.12",
|
||||
"@types/node": "^18.11.17",
|
||||
"@types/prompts": "^2.4.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
"module": "CommonJS",
|
||||
"moduleResolution": "Node",
|
||||
"target": "ES2022",
|
||||
"jsx": "react",
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"esModuleInterop": true,
|
||||
|
@ -13,7 +12,7 @@
|
|||
|
||||
},
|
||||
"exclude": [
|
||||
"interfaces",
|
||||
"clasess",
|
||||
"node_modules",
|
||||
"**/node_modules/*"
|
||||
]
|
||||
|
|
227
utils.ts
227
utils.ts
|
@ -1,230 +1,15 @@
|
|||
import Docker from "dockerode";
|
||||
import logger from "./logger";
|
||||
import { settings } from "./database";
|
||||
// import Hero from "@ulixee/hero";
|
||||
// import Miner from "@ulixee/miner";
|
||||
|
||||
import { sleep } from "telegram/Helpers";
|
||||
import { AccountInterface } from "./interfaces/databaseInterface";
|
||||
import * as telegram from "telegram";
|
||||
import axios from "axios";
|
||||
import cliProgress from "cli-progress";
|
||||
import { isNull, isUndefined } from "lodash";
|
||||
export class CaptchaError extends Error {}
|
||||
export class NoNewMessagesError extends Error {}
|
||||
export class DockerIsBrockenError extends Error {}
|
||||
|
||||
export function randomAB(a: number, b: number) {
|
||||
return Math.floor(Math.random() * (b - a + 1) + a);
|
||||
}
|
||||
export async function isBannedByClient(
|
||||
client: telegram.TelegramClient,
|
||||
username: string
|
||||
): Promise<boolean> {
|
||||
const blockedUsers = (
|
||||
await client.invoke(
|
||||
new telegram.Api.contacts.GetBlocked({ limit: 2147483647 })
|
||||
)
|
||||
).users as telegram.Api.User[];
|
||||
for (const blockedUser of blockedUsers) {
|
||||
if (
|
||||
blockedUser.username !== undefined &&
|
||||
blockedUser.username == username.replace("@", "")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export async function getMessagesByEntity(
|
||||
client: telegram.TelegramClient,
|
||||
chatEntity: telegram.Api.Chat | telegram.Api.User | string,
|
||||
entity: telegram.Api.User | string,
|
||||
params = {}
|
||||
) {
|
||||
const messages = new telegram.helpers.TotalList<telegram.Api.Message>();
|
||||
if (entity instanceof telegram.Api.User) {
|
||||
for (const message of await client.getMessages(chatEntity, params)) {
|
||||
if (
|
||||
(message.sender as telegram.Api.User).username ==
|
||||
entity.username
|
||||
) {
|
||||
messages.push(message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const message of await client.getMessages(chatEntity, params)) {
|
||||
if (
|
||||
isNull((message.sender as telegram.Api.User).username) !=
|
||||
true &&
|
||||
isUndefined((message.sender as telegram.Api.User).username) !=
|
||||
true
|
||||
) {
|
||||
if (
|
||||
(message.sender as telegram.Api.User).username!.includes(
|
||||
entity.replace("@", "")
|
||||
)
|
||||
) {
|
||||
messages.push(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
import { IWorker } from "./interfaces/IWorker";
|
||||
import lookupPublicIp from "@ulixee/default-browser-emulator/lib/helpers/lookupPublicIp"
|
||||
export function arrayWithoutElementAtIndex(
|
||||
arr: AccountInterface[] | [],
|
||||
arr: IWorker[] | [],
|
||||
index: number
|
||||
) {
|
||||
return arr.filter(function (value, arrIndex) {
|
||||
return index !== arrIndex;
|
||||
});
|
||||
}
|
||||
export async function getIP(proxyPort: number): Promise<string | null> {
|
||||
// https://github.com/ulixee/unblocked/blob/main/plugins/default-browser-emulator/lib/helpers/lookupPublicIp.ts
|
||||
let data: string | PromiseLike<string | null> | null;
|
||||
try {
|
||||
data = (
|
||||
await axios.get("http://icanhazip.com/", {
|
||||
proxy: {
|
||||
host: "127.0.0.1",
|
||||
port: proxyPort,
|
||||
},
|
||||
timeout: 100000,
|
||||
})
|
||||
).data;
|
||||
} catch (err) {
|
||||
logger.debug(err);
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((await data) == null || (await data)!.trim() == "") {
|
||||
return null;
|
||||
}
|
||||
return await data;
|
||||
}
|
||||
export async function waitNewMessages(
|
||||
client: telegram.TelegramClient,
|
||||
worker: AccountInterface,
|
||||
chatEntity: telegram.Api.Chat | telegram.Api.User | string,
|
||||
idOfLastMessage: number,
|
||||
timeout = 20
|
||||
): Promise<void> {
|
||||
const start_time = new Date();
|
||||
while (
|
||||
(
|
||||
await getMessagesByEntity(
|
||||
client,
|
||||
chatEntity,
|
||||
chatEntity as telegram.Api.User | string,
|
||||
{ minId: idOfLastMessage, limit: 2147483647 }
|
||||
)
|
||||
).length == 0
|
||||
) {
|
||||
if ((+new Date() - +start_time) / 1000 >= timeout) {
|
||||
logger.error(
|
||||
`${worker.phoneNumber} | Bot didnt answer for ${timeout}s`
|
||||
);
|
||||
throw new NoNewMessagesError("Is bot working?");
|
||||
}
|
||||
}
|
||||
logger.debug(`${worker.phoneNumber} | Bot answered`);
|
||||
}
|
||||
|
||||
export async function startNewTorDocker(
|
||||
proxyPort: number,
|
||||
socksPort: number,
|
||||
controlPort: number,
|
||||
mainProgressBar: cliProgress.MultiBar,
|
||||
timeout = 200
|
||||
): Promise<Docker.Container> {
|
||||
timeout *= 2;
|
||||
const docker = new Docker({ socketPath: "/var/run/docker.sock" });
|
||||
let isPulled = false;
|
||||
mainLoop: for (const image of await docker.listImages()) {
|
||||
const tags = image.RepoTags;
|
||||
if (tags !== undefined)
|
||||
for (const repoTag of tags) {
|
||||
if (repoTag.search("dperson/torproxy:latest") != -1) {
|
||||
isPulled = true;
|
||||
break mainLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPulled != true) {
|
||||
await docker.pull("dperson/torproxy:latest");
|
||||
}
|
||||
|
||||
// bugy shit
|
||||
const options: Docker.ContainerCreateOptions = {
|
||||
Image: "dperson/torproxy",
|
||||
Env: ["PASSWORD=qwerty", "LOCATION=US", "TOR_NewCircuitPeriod=50"],
|
||||
ExposedPorts: {},
|
||||
HostConfig: {
|
||||
PortBindings: {
|
||||
"8118/tcp": [
|
||||
{
|
||||
HostPort: `${proxyPort}`,
|
||||
},
|
||||
],
|
||||
"9050/tcp": [
|
||||
{
|
||||
HostPort: `${socksPort}`,
|
||||
},
|
||||
],
|
||||
"9051/tcp": [
|
||||
{
|
||||
HostPort: `${controlPort}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
Healthcheck: {
|
||||
Interval: 2 * 1000000000,
|
||||
Timeout: 50 * 1000000000,
|
||||
StartPeriod: 50 * 1000000000,
|
||||
// Test:['CMD_SHELL',`curl -sx localhost:8118 'https://check.torproject.org/' | grep -qm1 Congratulations`]
|
||||
},
|
||||
};
|
||||
const container = await docker.createContainer(options);
|
||||
await container.start();
|
||||
|
||||
const progressBar = mainProgressBar.create(timeout / 2, 0, {
|
||||
status: `Starting docker${
|
||||
settings.logLevel == "debug"
|
||||
? ` ${proxyPort} ${socksPort} ${controlPort}`
|
||||
: ""
|
||||
}`,
|
||||
});
|
||||
while ((await container.inspect())!.State.Health!.Status != "healthy") {
|
||||
const state = (await container.inspect())!.State.Health!.Status;
|
||||
if (progressBar.getProgress() >= timeout) {
|
||||
await container.kill();
|
||||
progressBar.update(timeout / 2, { status: "Failed" });
|
||||
progressBar.stop();
|
||||
throw new DockerIsBrockenError(`Docker ${container.id} is broken`);
|
||||
}
|
||||
if (state == "unhealthy") {
|
||||
await container.kill();
|
||||
progressBar.update(timeout / 2, {
|
||||
status: "Docker is unhealthy...",
|
||||
});
|
||||
progressBar.stop();
|
||||
return await startNewTorDocker(
|
||||
proxyPort,
|
||||
socksPort,
|
||||
controlPort,
|
||||
mainProgressBar,
|
||||
timeout / 2
|
||||
);
|
||||
}
|
||||
progressBar.increment();
|
||||
await sleep(2000);
|
||||
}
|
||||
progressBar.update(0, { status: "Started" });
|
||||
progressBar.stop();
|
||||
|
||||
return container;
|
||||
}
|
||||
export async function getIP(httpPort: number) {
|
||||
return await lookupPublicIp('icanhazip.com',undefined,`http://127.0.0.1:${httpPort}`)
|
||||
}
|
Loading…
Reference in New Issue