Initial release.

This commit is contained in:
2023-05-19 18:14:26 +02:00
parent 0d68262245
commit 16426f96a9
12 changed files with 2202 additions and 0 deletions

4
.env.sample Normal file
View File

@@ -0,0 +1,4 @@
MAIL_USER=
MAIL_PASSWORD=
MAIL_HOST=
MAIL_PORT=993

49
.eslintrc.json Normal file
View File

@@ -0,0 +1,49 @@
{
"extends": "eslint:recommended",
"env": {
"node": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 2021
},
"rules": {
"arrow-spacing": ["warn", { "before": true, "after": true }],
"brace-style": ["error", "stroustrup", { "allowSingleLine": true }],
"comma-dangle": ["error", "always-multiline"],
"comma-spacing": "error",
"comma-style": "error",
"curly": ["error", "multi-line", "consistent"],
"dot-location": ["error", "property"],
"handle-callback-err": "off",
"indent": ["error", "tab"],
"keyword-spacing": "error",
"max-nested-callbacks": ["error", { "max": 4 }],
"max-statements-per-line": ["error", { "max": 2 }],
"no-console": "off",
"no-empty-function": "error",
"no-floating-decimal": "error",
"no-inline-comments": "error",
"no-lonely-if": "error",
"no-multi-spaces": "error",
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
"no-shadow": ["error", { "allow": ["err", "resolve", "reject"] }],
"no-trailing-spaces": ["error"],
"no-var": "error",
"object-curly-spacing": ["error", "always"],
"prefer-const": "error",
"quotes": ["error", "single"],
"semi": ["error", "always"],
"space-before-blocks": "error",
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always"
}],
"space-in-parens": "error",
"space-infix-ops": "error",
"space-unary-ops": "error",
"spaced-comment": "error",
"yoda": "error"
}
}

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
node_modules/
.env
sorted/
accounts.json

22
main.js Normal file
View File

@@ -0,0 +1,22 @@
require('dotenv').config();
const { connect, disconnect } = require('./modules/codeHandler');
const { createDriver } = require('./modules/driverManager');
const { createAccount } = require('./modules/microsoftHandler');
async function main() {
const numAccounts = 3;
await connect();
const accountPromises = [];
for (let i = 0; i < numAccounts; i++) {
const promise = createAccount(createDriver());
accountPromises.push(promise);
console.log(`Account ${i + 1} done!`);
await new Promise((resolve) => setTimeout(resolve, 20000));
}
await Promise.all(accountPromises);
console.log('All accounts done!');
await disconnect();
}
main();

20
modules/accountManager.js Normal file
View File

@@ -0,0 +1,20 @@
const fs = require('fs');
function batchAccounts(accounts, batchSize) {
const sortedDir = '../accounts/sorted';
if (!fs.existsSync(sortedDir)) {
fs.mkdirSync(sortedDir);
}
for (let i = 0; i < accounts.length; i += batchSize) {
const batch = accounts.slice(i, i + batchSize);
const batchNumber = Math.ceil((i + 1) / batchSize);
const batchFilename = `${sortedDir}/batch${batchNumber}.json`;
fs.writeFileSync(batchFilename, JSON.stringify(batch, null, 2));
}
}
const accounts = require('../accounts/accounts.json');
batchAccounts(accounts, 6);
module.exports = { batchAccounts };

55
modules/codeHandler.js Normal file
View File

@@ -0,0 +1,55 @@
const MailListener = require('mail-listener2');
const mailListener = new MailListener({
username: process.env.MAIL_USER,
password: process.env.MAIL_PASSWORD,
host: process.env.MAIL_HOST,
port: process.env.MAIL_PORT,
tls: true,
});
mailListener.on('server:connected', function() {
console.log('imapConnected');
});
mailListener.on('server:disconnected', function() {
console.log('imapDisconnected');
});
mailListener.on('error', function(err) {
console.log(err);
});
function getCodeFromEmail() {
return new Promise((resolve) => {
mailListener.on('mail', function(mail, seqno, attributes) {
if (mail.subject.trim() !== 'Verify your email address') return;
if (!attributes) return;
const text = mail.text.trim();
const match = text.match(/code: (\d+)/i);
if (match) {
const imap = mailListener.imap;
imap.addFlags(attributes.uid, '\\Seen', (err) => {
if (err) console.log('Error marking email as seen:', err);
// else console.log('Email marked as seen');
});
resolve(match[1]);
}
});
});
}
function connect() {
mailListener.start();
}
function disconnect() {
mailListener.stop();
}
mailListener.on('attachment', function(attachment) {
console.log(attachment.path);
});
module.exports = { getCodeFromEmail, connect, disconnect };

80
modules/driverManager.js Normal file
View File

@@ -0,0 +1,80 @@
const { Builder } = require('selenium-webdriver');
const firefox = require('selenium-webdriver/firefox');
const chrome = require('selenium-webdriver/chrome');
const edge = require('selenium-webdriver/edge');
const args = process.argv.slice(2);
const userAgents = new Map([
['desktop', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.34'],
['mobile', 'Mozilla/5.0 (Linux; Android 10; Redmi Note 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Mobile Safari/537.36'],
]);
const userAgent = userAgents.get(args.find(arg => arg.startsWith('--userAgent='))?.split('=')[1] ?? 'desktop');
function createDriverChrome() {
const driver = new Builder()
.forBrowser('chrome')
.setChromeOptions(
new chrome.Options()
.windowSize({ width: 1024, height: 768 })
.addArguments(`--user-agent=${userAgent}`),
)
.build();
return driver;
}
function createDriverFirefox() {
const driver = new Builder()
.forBrowser('firefox')
.setFirefoxOptions(
new firefox.Options()
.windowSize({ width: 1024, height: 768 })
.addArguments(`--user-agent=${userAgent}`),
)
.build();
return driver;
}
function createDriverEdge() {
const driver = new Builder()
.forBrowser('MicrosoftEdge')
.setEdgeOptions(
new edge.Options()
.windowSize({ width: 1024, height: 768 })
.addArguments(`--user-agent=${userAgent}`),
)
.build();
return driver;
}
function createDriver() {
let browserType = 'chrome';
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith('--')) {
if (args[i] === '--firefox') {
browserType = 'firefox';
}
else if (args[i] === '--edge') {
browserType = 'edge';
}
}
}
let driver;
switch (browserType) {
case 'firefox':
driver = createDriverFirefox();
break;
case 'edge':
driver = createDriverEdge();
break;
default:
driver = createDriverChrome();
}
console.log(`Using ${browserType} browser with user agent: ${userAgent}`);
return driver;
}
module.exports = {
createDriver,
};

View File

@@ -0,0 +1,21 @@
const { faker } = require('@faker-js/faker');
function createIdentity() {
const firstName = faker.name.firstName();
const lastName = faker.name.lastName();
const birthDate = faker.date.between('1960-01-01', '2004-12-31');
const email = firstName + '.' + lastName + '@aostia.org';
const password = generatePassword(12);
return { first_name: firstName, last_name: lastName, birth_date: birthDate, email: email, password: password };
}
function generatePassword(length) {
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_+=~';
let password = '';
for (let i = 0; i < length; i++) {
password += charset.charAt(Math.floor(Math.random() * charset.length));
}
return password;
}
module.exports = { createIdentity };

181
modules/microsoftHandler.js Normal file
View File

@@ -0,0 +1,181 @@
const fs = require('fs');
const { By, Key, until } = require('selenium-webdriver');
const { createIdentity } = require('./identityHandler');
const { getCodeFromEmail } = require('./codeHandler');
const { clickTime, urlTime, timeoutLoading } = require('./speedHandler').getSpeed();
async function createAccount(driver) {
try {
const identity = await createIdentity();
await driver.get('https://rewards.microsoft.com/');
await driver.sleep(urlTime);
await driver.wait(until.titleContains('Sign in to'), timeoutLoading);
const emailInput = await driver.findElement(By.name('loginfmt'));
await emailInput.sendKeys(identity.email);
await driver.sleep(clickTime);
await emailInput.sendKeys(Key.RETURN);
await driver.sleep(urlTime);
const getANewOneButton = await driver.findElement(By.id('idA_PWD_SignUp'));
await getANewOneButton.click();
await driver.sleep(urlTime);
await driver.findElement(By.id('iSignupAction')).click();
await driver.sleep(clickTime);
await driver.wait(until.titleContains('password'), timeoutLoading);
const passwordInput = await await driver.findElement(By.id('PasswordInput'));
await passwordInput.sendKeys(identity.password);
await driver.findElement(By.id('iSignupAction')).click();
await driver.sleep(clickTime);
await driver.wait(until.titleContains('name'), timeoutLoading);
const firstNameInput = await await driver.findElement(By.id('FirstName'));
await firstNameInput.sendKeys(identity.first_name);
const lastNameInput = await await driver.findElement(By.id('LastName'));
await lastNameInput.sendKeys(identity.last_name);
await driver.sleep(urlTime);
await driver.findElement(By.id('iSignupAction')).click();
await driver.sleep(clickTime);
await driver.wait(until.titleContains('birthdate'), timeoutLoading);
await driver.sleep(urlTime);
driver.findElement(By.id('BirthMonth')).then(function(birthMonthSelect) {
birthMonthSelect.findElement(By.css(`option[value="${identity.birth_date.getMonth() + 1}"]`)).click();
});
driver.findElement(By.id('BirthDay')).then(function(birthDaySelect) {
birthDaySelect.findElement(By.css(`option[value="${identity.birth_date.getDate()}"]`)).click();
});
driver.findElement(By.id('BirthYear')).then(function(birthYearInput) {
birthYearInput.clear();
birthYearInput.sendKeys(identity.birth_date.getFullYear());
});
await driver.sleep(clickTime);
await driver.findElement(By.id('iSignupAction')).click();
await driver.wait(until.titleContains('code'), timeoutLoading);
// VerificationCode
const VerificationCodeInput = await await driver.findElement(By.id('VerificationCode'));
try {
const code = await getCodeFromEmail();
await VerificationCodeInput.sendKeys(`${code}`);
}
catch (err) {
return;
}
await driver.findElement(By.id('iOptinEmail')).click();
await driver.sleep(clickTime);
await driver.findElement(By.id('iSignupAction')).click();
await driver.sleep(urlTime + 4000);
const source = await driver.getPageSource();
if (source.includes('Phone number')) {
console.log('Ip usage exceeded please switch IP');
}
else {
await driver.wait(until.titleContains('Welcome'), 300000);
const account = {
'name': identity.first_name + ' ' + identity.last_name,
'birthdate': identity.birth_date,
'username': identity.email,
'password': identity.password,
};
let accounts = [];
if (fs.existsSync('../accounts/accounts.json')) {
const content = fs.readFileSync('accounts.json', 'utf8');
accounts = JSON.parse(content);
}
accounts.push(account);
fs.writeFileSync('../accounts/accounts.json', JSON.stringify(accounts));
console.log('Account saved to accounts.json, there are currently ' + accounts.length + ' accounts');
await driver.sleep(urlTime);
try {
await driver.findElement(By.xpath('//button[contains(text(),\'Reject\')]')).click();
await driver.sleep(clickTime);
}
catch (err) {
console.log(err);
}
const startEarningLink = By.id('start-earning-rewards-link');
let linkFound = false;
while (!linkFound) {
try {
await driver.findElement(startEarningLink).click();
linkFound = true;
}
catch (error) {
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
await driver.sleep(clickTime);
await driver.wait(until.titleContains('Rewards'), timeoutLoading);
await driver.sleep(5000);
try {
await driver.findElement(By.css('a.welcome-tour-next-button.c-call-to-action.c-glyph')).click();
await driver.sleep(clickTime);
let buttons = await driver.findElements(By.css('a.quiz-link.gray-button.c-call-to-action.c-glyph.f-lightweight'));
buttons[1].click();
await driver.sleep(clickTime);
await driver.get('https://rewards.microsoft.com/');
await driver.sleep(urlTime);
await driver.get('https://rewards.bing.com/welcometour');
await driver.sleep(urlTime);
buttons = await driver.findElements(By.css('a.quiz-link.gray-button.c-call-to-action.c-glyph.f-lightweight'));
buttons[0].click();
await driver.sleep(clickTime);
await driver.get('https://rewards.microsoft.com/');
await driver.sleep(urlTime);
await driver.get('https://rewards.bing.com/welcometour');
await driver.sleep(clickTime);
buttons = await driver.findElements(By.css('a.quiz-link.gray-button.c-call-to-action.c-glyph.f-lightweight'));
buttons[0].click();
}
catch (err) {
console.log(err);
}
await driver.sleep(clickTime);
await driver.get('https://rewards.bing.com/redeem/000803000032');
await driver.sleep(urlTime);
await driver.findElement(By.xpath('//span[contains(text(), "SET AS GOAL")]')).click();
await driver.sleep(2000);
}
}
finally {
await driver.quit();
}
return;
}
module.exports = { createAccount };

29
modules/speedHandler.js Normal file
View File

@@ -0,0 +1,29 @@
const speeds = {
slow: { click: 2000, url: 4000, timeout: 50000 },
normal: { click: 1000, url: 2000, timeout: 30000 },
fast: { click: 750, url: 1500, timeout: 20000 },
superfast: { click: 500, url: 1000, timeout: 10000 },
};
function getSpeed() {
let speed = 'normal';
const args = process.argv.slice(2);
for (let i = 0; i < args.length; i++) {
if (args[i].startsWith('--')) {
if (args[i] === '--fast') {
speed = 'fast';
}
else if (args[i] === '--superfast') {
speed = 'superfast';
}
else if (args[i] === '--slow') {
speed = 'slow';
}
}
}
console.log(`Using ${speed} speed`);
const { click: timeTypeClick, url: timeTypeUrl, timeout: timeTypeTimeoutLoading } = speeds[speed];
return { clickTime: timeTypeClick, urlTime: timeTypeUrl, timeoutLoading: timeTypeTimeoutLoading };
}
module.exports = { getSpeed };

1721
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

16
package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"dependencies": {
"bluebird": "^3.7.2",
"cron": "^2.3.0",
"faker": "^6.6.6",
"imap": "^0.8.19",
"mail-listener2": "^0.3.1",
"mailparser": "^3.6.4",
"node-imap": "^0.9.6",
"selenium-webdriver": "^4.8.2"
},
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"eslint": "^8.38.0"
}
}