Initial release.
This commit is contained in:
4
.env.sample
Normal file
4
.env.sample
Normal file
@@ -0,0 +1,4 @@
|
||||
MAIL_USER=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=993
|
||||
49
.eslintrc.json
Normal file
49
.eslintrc.json
Normal 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
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
.env
|
||||
sorted/
|
||||
accounts.json
|
||||
22
main.js
Normal file
22
main.js
Normal 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
20
modules/accountManager.js
Normal 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
55
modules/codeHandler.js
Normal 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
80
modules/driverManager.js
Normal 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,
|
||||
};
|
||||
21
modules/identityHandler.js
Normal file
21
modules/identityHandler.js
Normal 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
181
modules/microsoftHandler.js
Normal 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
29
modules/speedHandler.js
Normal 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
1721
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
16
package.json
Normal file
16
package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user