mirror of
https://github.com/TheNetsky/Microsoft-Rewards-Script.git
synced 2026-01-18 14:03:58 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f015649d16 | ||
|
|
034359019c | ||
|
|
09ddbee45a | ||
|
|
7939196e88 | ||
|
|
5bc66c5fc9 |
12
Dockerfile
12
Dockerfile
@@ -24,17 +24,23 @@ RUN apt-get install -y \
|
|||||||
# Install application dependencies
|
# Install application dependencies
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
|
# Ensure correct permissions for node_modules
|
||||||
|
RUN chmod -R 755 /usr/src/microsoft-rewards-script/node_modules
|
||||||
|
|
||||||
|
# Install Playwright Chromium directly from local node_modules
|
||||||
|
RUN ./node_modules/.bin/playwright install chromium
|
||||||
|
|
||||||
# Build the script
|
# Build the script
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Install playwright chromium
|
|
||||||
RUN npx playwright install chromium
|
|
||||||
|
|
||||||
# Copy cron file to cron directory
|
# Copy cron file to cron directory
|
||||||
COPY src/crontab.template /etc/cron.d/microsoft-rewards-cron.template
|
COPY src/crontab.template /etc/cron.d/microsoft-rewards-cron.template
|
||||||
|
|
||||||
# Create the log file to be able to run tail
|
# Create the log file to be able to run tail
|
||||||
RUN touch /var/log/cron.log
|
RUN touch /var/log/cron.log
|
||||||
|
|
||||||
|
# Ensure correct permissions for the working directory
|
||||||
|
RUN chmod -R 755 /usr/src/microsoft-rewards-script
|
||||||
|
|
||||||
# Define the command to run your application with cron optionally
|
# Define the command to run your application with cron optionally
|
||||||
CMD sh -c 'node src/updateConfig.js && echo "$TZ" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && if [ "$RUN_ON_START" = "true" ]; then npm start; fi && envsubst < /etc/cron.d/microsoft-rewards-cron.template > /etc/cron.d/microsoft-rewards-cron && crontab /etc/cron.d/microsoft-rewards-cron && cron && tail -f /var/log/cron.log'
|
CMD sh -c 'node src/updateConfig.js && echo "$TZ" > /etc/timezone && dpkg-reconfigure -f noninteractive tzdata && if [ "$RUN_ON_START" = "true" ]; then npm start; fi && envsubst < /etc/cron.d/microsoft-rewards-cron.template > /etc/cron.d/microsoft-rewards-cron && crontab /etc/cron.d/microsoft-rewards-cron && cron && tail -f /var/log/cron.log'
|
||||||
|
|||||||
@@ -68,8 +68,10 @@ Under development, however mainly for personal use!
|
|||||||
| workers.doPunchCards | Complete punchcards | `true` | DO_PUNCH_CARDS |
|
| workers.doPunchCards | Complete punchcards | `true` | DO_PUNCH_CARDS |
|
||||||
| workers.doDesktopSearch | Complete daily desktop searches | `true` | DO_DESKTOP_SEARCH |
|
| workers.doDesktopSearch | Complete daily desktop searches | `true` | DO_DESKTOP_SEARCH |
|
||||||
| workers.doMobileSearch | Complete daily mobile searches | `true` | DO_MOBILE_SEARCH |
|
| workers.doMobileSearch | Complete daily mobile searches | `true` | DO_MOBILE_SEARCH |
|
||||||
|
| workers.doDailyCheckIn | Complete daily check-in activity | `true` | DO_DAILY_CHECK_IN |
|
||||||
|
| workers.doReadToEarn | Complete read to earn activity | `true` | DO_READ_TO_EARN |
|
||||||
| globalTimeout | The length before the action gets timeout | `30000` (30 seconds) | GLOBAL_TIMEOUT |
|
| globalTimeout | The length before the action gets timeout | `30000` (30 seconds) | GLOBAL_TIMEOUT |
|
||||||
| searchSettings.useGeoLocaleQueries | Generate search queries based on your geo-location | `false` (Uses EN-US generated queries) | USE_GEO_LOCALE_QUERIES |
|
| searchSettings.useGeoLocaleQueries | Generate search queries based on your geo-location | `true` (Uses EN-US generated queries) | USE_GEO_LOCALE_QUERIES |
|
||||||
| scrollRandomResults | Scroll randomly in search results | `true` | SCROLL_RANDOM_RESULTS |
|
| scrollRandomResults | Scroll randomly in search results | `true` | SCROLL_RANDOM_RESULTS |
|
||||||
| searchSettings.clickRandomResults | Visit random website from search result| `true` | CLICK_RANDOM_RESULTS |
|
| searchSettings.clickRandomResults | Visit random website from search result| `true` | CLICK_RANDOM_RESULTS |
|
||||||
| searchSettings.searchDelay | Minimum and maximum time in miliseconds between search queries | `min: 10000` (10 seconds) `max: 20000` (20 seconds) | SEARCH_DELAY_MIN SEARCH_DELAY_MAX |
|
| searchSettings.searchDelay | Minimum and maximum time in miliseconds between search queries | `min: 10000` (10 seconds) `max: 20000` (20 seconds) | SEARCH_DELAY_MIN SEARCH_DELAY_MAX |
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "microsoft-rewards-script",
|
"name": "microsoft-rewards-script",
|
||||||
"version": "1.4.9",
|
"version": "1.4.10",
|
||||||
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
"description": "Automatically do tasks for Microsoft Rewards but in TS!",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -34,9 +34,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.5",
|
"axios": "^1.7.5",
|
||||||
"cheerio": "^1.0.0",
|
"cheerio": "^1.0.0",
|
||||||
"fingerprint-generator": "^2.1.54",
|
"fingerprint-generator": "^2.1.56",
|
||||||
"fingerprint-injector": "^2.1.54",
|
"fingerprint-injector": "^2.1.56",
|
||||||
"playwright": "^1.46.1",
|
"playwright": "^1.47.2",
|
||||||
"ts-node": "^10.9.2"
|
"ts-node": "^10.9.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { AccountProxy } from '../interface/Account'
|
|||||||
https://abrahamjuliot.github.io/creepjs/
|
https://abrahamjuliot.github.io/creepjs/
|
||||||
https://botcheck.luminati.io/
|
https://botcheck.luminati.io/
|
||||||
http://f.vision/
|
http://f.vision/
|
||||||
|
https://pixelscan.net/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Browser {
|
class Browser {
|
||||||
@@ -61,7 +62,7 @@ class Browser {
|
|||||||
const fingerPrintData = new FingerprintGenerator().getFingerprint({
|
const fingerPrintData = new FingerprintGenerator().getFingerprint({
|
||||||
devices: this.bot.isMobile ? ['mobile'] : ['desktop'],
|
devices: this.bot.isMobile ? ['mobile'] : ['desktop'],
|
||||||
operatingSystems: this.bot.isMobile ? ['android'] : ['windows'],
|
operatingSystems: this.bot.isMobile ? ['android'] : ['windows'],
|
||||||
browsers: ['edge']
|
browserListQuery: 'last 2 edge version'
|
||||||
})
|
})
|
||||||
|
|
||||||
return fingerPrintData
|
return fingerPrintData
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ export default class BrowserFunc {
|
|||||||
if (data.morePromotions?.length) {
|
if (data.morePromotions?.length) {
|
||||||
data.morePromotions.forEach(x => {
|
data.morePromotions.forEach(x => {
|
||||||
// Only count points from supported activities
|
// Only count points from supported activities
|
||||||
if (['quiz', 'urlreward'].includes(x.promotionType) && !x.attributes.is_unlocked) {
|
if (['quiz', 'urlreward'].includes(x.promotionType) && x.exclusiveLockedFeatureStatus !== 'locked') {
|
||||||
totalEarnablePoints += (x.pointProgressMax - x.pointProgress)
|
totalEarnablePoints += (x.pointProgressMax - x.pointProgress)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"globalTimeout": 30000,
|
"globalTimeout": 30000,
|
||||||
"searchSettings": {
|
"searchSettings": {
|
||||||
"useGeoLocaleQueries": false,
|
"useGeoLocaleQueries": true,
|
||||||
"scrollRandomResults": true,
|
"scrollRandomResults": true,
|
||||||
"clickRandomResults": true,
|
"clickRandomResults": true,
|
||||||
"searchDelay": {
|
"searchDelay": {
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export class Workers {
|
|||||||
morePromotions.push(data.promotionalItem as unknown as MorePromotion)
|
morePromotions.push(data.promotionalItem as unknown as MorePromotion)
|
||||||
}
|
}
|
||||||
|
|
||||||
const activitiesUncompleted = morePromotions?.filter(x => !x.complete && x.pointProgressMax > 0 && !x.attributes.is_unlocked) ?? []
|
const activitiesUncompleted = morePromotions?.filter(x => !x.complete && x.pointProgressMax > 0 && x.exclusiveLockedFeatureStatus !== 'locked') ?? []
|
||||||
|
|
||||||
if (!activitiesUncompleted.length) {
|
if (!activitiesUncompleted.length) {
|
||||||
this.bot.log('MORE-PROMOTIONS', 'All "More Promotion" items have already been completed')
|
this.bot.log('MORE-PROMOTIONS', 'All "More Promotion" items have already been completed')
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ export class ReadToEarn extends Workers {
|
|||||||
this.bot.log('READ-TO-EARN', 'Starting Read to Earn')
|
this.bot.log('READ-TO-EARN', 'Starting Read to Earn')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
let geoLocale = data.userProfile.attributes.country
|
let geoLocale = data.userProfile.attributes.country
|
||||||
geoLocale = (this.bot.config.searchSettings.useGeoLocaleQueries && geoLocale.length === 2) ? geoLocale.toLowerCase() : 'us'
|
geoLocale = (this.bot.config.searchSettings.useGeoLocaleQueries && geoLocale.length === 2) ? geoLocale.toLowerCase() : 'us'
|
||||||
|
|
||||||
@@ -26,7 +25,7 @@ export class ReadToEarn extends Workers {
|
|||||||
}
|
}
|
||||||
const userDataResponse = await axios(userDataRequest)
|
const userDataResponse = await axios(userDataRequest)
|
||||||
const userData = (await userDataResponse.data).response
|
const userData = (await userDataResponse.data).response
|
||||||
let balance: number = userData.balance
|
let userBalance = userData.balance
|
||||||
|
|
||||||
const jsonData = {
|
const jsonData = {
|
||||||
amount: 1,
|
amount: 1,
|
||||||
@@ -38,7 +37,8 @@ export class ReadToEarn extends Workers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < 10; ++i) {
|
const articleCount = 10
|
||||||
|
for (let i = 0; i < articleCount; ++i) {
|
||||||
jsonData.id = randomBytes(64).toString('hex')
|
jsonData.id = randomBytes(64).toString('hex')
|
||||||
const claimRequest = {
|
const claimRequest = {
|
||||||
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me/activities',
|
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me/activities',
|
||||||
@@ -55,12 +55,12 @@ export class ReadToEarn extends Workers {
|
|||||||
const claimResponse = await axios(claimRequest)
|
const claimResponse = await axios(claimRequest)
|
||||||
const newBalance = (await claimResponse.data).response.balance
|
const newBalance = (await claimResponse.data).response.balance
|
||||||
|
|
||||||
if (newBalance == balance) {
|
if (newBalance == userBalance) {
|
||||||
this.bot.log('READ-TO-EARN', 'Read all available articles')
|
this.bot.log('READ-TO-EARN', 'Read all available articles')
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
balance = newBalance
|
this.bot.log('READ-TO-EARN', `Read article ${i + 1} of ${articleCount} max | Gained ${newBalance - userBalance} Points`)
|
||||||
this.bot.log('READ-TO-EARN', `Read article ${i + 1}`)
|
userBalance = newBalance
|
||||||
await this.bot.utils.wait(Math.floor(this.bot.utils.randomNumber(this.bot.config.searchSettings.searchDelay.min, this.bot.config.searchSettings.searchDelay.max)))
|
await this.bot.utils.wait(Math.floor(this.bot.utils.randomNumber(this.bot.config.searchSettings.searchDelay.min, this.bot.config.searchSettings.searchDelay.max)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import { GoogleSearch } from '../../interface/Search'
|
|||||||
|
|
||||||
|
|
||||||
export class Search extends Workers {
|
export class Search extends Workers {
|
||||||
|
private bingHome = 'https://bing.com'
|
||||||
private searchPageURL = 'https://bing.com'
|
private searchPageURL = ''
|
||||||
|
|
||||||
public async doSearch(page: Page, data: DashboardData) {
|
public async doSearch(page: Page, data: DashboardData) {
|
||||||
this.bot.log('SEARCH-BING', 'Starting bing searches')
|
this.bot.log('SEARCH-BING', 'Starting Bing searches')
|
||||||
|
|
||||||
page = await this.bot.browser.utils.getLatestTab(page)
|
page = await this.bot.browser.utils.getLatestTab(page)
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ export class Search extends Workers {
|
|||||||
googleSearchQueries = [...new Set(googleSearchQueries)]
|
googleSearchQueries = [...new Set(googleSearchQueries)]
|
||||||
|
|
||||||
// Go to bing
|
// Go to bing
|
||||||
await page.goto(this.searchPageURL)
|
await page.goto(this.searchPageURL ? this.searchPageURL : this.bingHome)
|
||||||
|
|
||||||
let maxLoop = 0 // If the loop hits 10 this when not gaining any points, we're assuming it's stuck. If it ddoesn't continue after 5 more searches with alternative queries, abort search
|
let maxLoop = 0 // If the loop hits 10 this when not gaining any points, we're assuming it's stuck. If it ddoesn't continue after 5 more searches with alternative queries, abort search
|
||||||
|
|
||||||
@@ -133,19 +133,17 @@ export class Search extends Workers {
|
|||||||
private async bingSearch(searchPage: Page, query: string) {
|
private async bingSearch(searchPage: Page, query: string) {
|
||||||
const platformControlKey = platform() === 'darwin' ? 'Meta' : 'Control'
|
const platformControlKey = platform() === 'darwin' ? 'Meta' : 'Control'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Try a max of 5 times
|
// Try a max of 5 times
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
try {
|
try {
|
||||||
|
// This page had already been set to the Bing.com page or the previous search listing, we just need to select it
|
||||||
|
searchPage = await this.bot.browser.utils.getLatestTab(searchPage)
|
||||||
|
|
||||||
// Go to top of the page
|
// Go to top of the page
|
||||||
await searchPage.evaluate(() => {
|
await searchPage.evaluate(() => {
|
||||||
window.scrollTo(0, 0)
|
window.scrollTo(0, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set it since params get added after visiting
|
|
||||||
this.searchPageURL = searchPage.url()
|
|
||||||
|
|
||||||
await this.bot.utils.wait(500)
|
await this.bot.utils.wait(500)
|
||||||
|
|
||||||
const searchBar = '#sb_form_q'
|
const searchBar = '#sb_form_q'
|
||||||
@@ -163,6 +161,7 @@ export class Search extends Workers {
|
|||||||
|
|
||||||
// Bing.com in Chrome opens a new tab when searching
|
// Bing.com in Chrome opens a new tab when searching
|
||||||
const resultPage = await this.bot.browser.utils.getLatestTab(searchPage)
|
const resultPage = await this.bot.browser.utils.getLatestTab(searchPage)
|
||||||
|
this.searchPageURL = new URL(resultPage.url()).href // Set the results page
|
||||||
|
|
||||||
if (this.bot.config.searchSettings.scrollRandomResults) {
|
if (this.bot.config.searchSettings.scrollRandomResults) {
|
||||||
await this.bot.utils.wait(2000)
|
await this.bot.utils.wait(2000)
|
||||||
@@ -185,6 +184,7 @@ export class Search extends Workers {
|
|||||||
break
|
break
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bot.log('SEARCH-BING', 'Search failed, An error occurred:' + error, 'error')
|
this.bot.log('SEARCH-BING', 'Search failed, An error occurred:' + error, 'error')
|
||||||
this.bot.log('SEARCH-BING', `Retrying search, attempt ${i}/5`, 'warn')
|
this.bot.log('SEARCH-BING', `Retrying search, attempt ${i}/5`, 'warn')
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ export class Search extends Workers {
|
|||||||
|
|
||||||
return response.data[1] as string[]
|
return response.data[1] as string[]
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.bot.log('SEARCH-BING-RELTATED', 'An error occurred:' + error, 'error')
|
this.bot.log('SEARCH-BING-RELATED', 'An error occurred:' + error, 'error')
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@@ -286,16 +286,15 @@ export class Search extends Workers {
|
|||||||
|
|
||||||
private async clickRandomLink(page: Page) {
|
private async clickRandomLink(page: Page) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await page.click('#b_results .b_algo h2', { timeout: 2000 }).catch(() => { }) // Since we don't really care if it did it or not
|
await page.click('#b_results .b_algo h2', { timeout: 2000 }).catch(() => { }) // Since we don't really care if it did it or not
|
||||||
|
|
||||||
// Will get current tab if no new one is created
|
// Stay for 10 seconds for page to load and "visit"
|
||||||
let lastTab = await this.bot.browser.utils.getLatestTab(page)
|
|
||||||
|
|
||||||
// Stay for 10 seconds
|
|
||||||
await this.bot.utils.wait(10_000)
|
await this.bot.utils.wait(10_000)
|
||||||
|
|
||||||
let lastTabURL = new URL(lastTab.url()) // Get new tab info
|
// Will get current tab if no new one is created, this will always be the visited site or the result page if it failed to click
|
||||||
|
let lastTab = await this.bot.browser.utils.getLatestTab(page)
|
||||||
|
|
||||||
|
let lastTabURL = new URL(lastTab.url()) // Get new tab info, this is the website we're visiting
|
||||||
|
|
||||||
// Check if the URL is different from the original one, don't loop more than 5 times.
|
// Check if the URL is different from the original one, don't loop more than 5 times.
|
||||||
let i = 0
|
let i = 0
|
||||||
@@ -325,11 +324,15 @@ export class Search extends Workers {
|
|||||||
// If only 1 tab is open, open a new one to search in
|
// If only 1 tab is open, open a new one to search in
|
||||||
} else if (tabs.length === 1) {
|
} else if (tabs.length === 1) {
|
||||||
const newPage = await browser.newPage()
|
const newPage = await browser.newPage()
|
||||||
await newPage.goto(this.searchPageURL)
|
await this.bot.utils.wait(1000)
|
||||||
|
await newPage.goto(this.bingHome)
|
||||||
|
await this.bot.utils.wait(3000)
|
||||||
|
this.searchPageURL = newPage.url()
|
||||||
|
|
||||||
// Else go back one page, this means the correct amount is open
|
// Else reset the last tab back to the search listing or Bing.com
|
||||||
} else {
|
} else {
|
||||||
await lastTab.goBack().catch(() => { })
|
lastTab = await this.bot.browser.utils.getLatestTab(lastTab)
|
||||||
|
await lastTab.goto(this.searchPageURL ? this.searchPageURL : this.bingHome)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -351,6 +351,8 @@ export interface MorePromotion {
|
|||||||
legalText: string;
|
legalText: string;
|
||||||
legalLinkText: string;
|
legalLinkText: string;
|
||||||
deviceType: string;
|
deviceType: string;
|
||||||
|
exclusiveLockedFeatureType: string;
|
||||||
|
exclusiveLockedFeatureStatus: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PunchCard {
|
export interface PunchCard {
|
||||||
|
|||||||
Reference in New Issue
Block a user