Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/browser/BrowserFunc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { AppUserData } from '../interface/AppUserData'
import type { XboxDashboardData } from '../interface/XboxDashboardData'
import type { AppEarnablePoints, BrowserEarnablePoints, MissingSearchPoints } from '../interface/Points'
import type { AppDashboardData } from '../interface/AppDashBoardData'
import { PanelFlyoutData } from '../interface/PanelFlyoutData'

export default class BrowserFunc {
private bot: MicrosoftRewardsBot
Expand Down Expand Up @@ -76,6 +77,38 @@ export default class BrowserFunc {
}
}

/**
* Fetch user panel flyout data
* @returns {PanelFlyoutData} Object of user bing rewards dashboard data
*/
async getPanelFlyoutData(): Promise<PanelFlyoutData> {
try {
const request: AxiosRequestConfig = {
url: 'https://www.bing.com/rewards/panelflyout/getuserinfo?channel=BingFlyout&partnerId=BingRewards',
method: 'GET',
headers: {
...(this.bot.fingerprint?.headers ?? {}),
Cookie: this.buildCookieHeader(this.bot.cookies.mobile, [
'bing.com',
'live.com',
'microsoftonline.com'
]),
Origin: 'https://www.bing.com'
}
}

const response = await this.bot.axios.request(request)
return response.data as PanelFlyoutData
} catch (error) {
this.bot.logger.error(
this.bot.isMobile,
'GET-PANEL-FLYOUT-DATA',
`Error fetching dashboard data: ${error instanceof Error ? error.message : String(error)}`
)
throw error
}
}

/**
* Fetch user app dashboard data
* @returns {AppDashboardData} Object of user bing rewards dashboard data
Expand Down
59 changes: 31 additions & 28 deletions src/functions/activities/api/DoubleSearchPoints.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AxiosRequestConfig } from 'axios'
import { Workers } from '../../Workers'
import { PromotionalItem } from '../../../interface/DashboardData'
import { randomUUID } from 'crypto'

export class DoubleSearchPoints extends Workers {
private cookieHeader: string = ''
Expand All @@ -12,14 +13,14 @@ export class DoubleSearchPoints extends Workers {
const activityType = promotion.activityType

try {
if (!this.bot.requestToken && this.bot.rewardsVersion === 'legacy') {
this.bot.logger.warn(
this.bot.isMobile,
'DOUBLE-SEARCH-POINTS',
'Skipping: Request token not available, this activity requires it!'
)
return
}
// if (!this.bot.requestToken && this.bot.rewardsVersion === 'legacy') {
// this.bot.logger.warn(
// this.bot.isMobile,
// 'DOUBLE-SEARCH-POINTS',
// 'Skipping: Request token not available, this activity requires it!'
// )
// return
// }

this.cookieHeader = this.bot.browser.func.buildCookieHeader(
this.bot.isMobile ? this.bot.cookies.mobile : this.bot.cookies.desktop,
Expand All @@ -43,16 +44,15 @@ export class DoubleSearchPoints extends Workers {
`Prepared headers | cookieLength=${this.cookieHeader.length} | fingerprintHeaderKeys=${Object.keys(this.fingerprintHeader).length}`
)

const formData = new URLSearchParams({
id: offerId,
hash: promotion.hash,
timeZone: '60',
activityAmount: '1',
dbs: '0',
form: '',
type: activityType,
__RequestVerificationToken: this.bot.requestToken
})
const jsonData = {
amount: 1,
id: randomUUID(),
type: 101,
attributes: {
offerid: offerId,
},
country: this.bot.userData.geoLocale
}

this.bot.logger.debug(
this.bot.isMobile,
Expand All @@ -61,16 +61,19 @@ export class DoubleSearchPoints extends Workers {
)

const request: AxiosRequestConfig = {
url: 'https://rewards.bing.com/api/reportactivity?X-Requested-With=XMLHttpRequest',
method: 'POST',
headers: {
...(this.bot.fingerprint?.headers ?? {}),
Cookie: this.cookieHeader,
Referer: 'https://rewards.bing.com/',
Origin: 'https://rewards.bing.com'
},
data: formData
}
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me/activities',
method: 'POST',
headers: {
Authorization: `Bearer ${this.bot.accessToken}`,
'User-Agent':
'Bing/32.5.431027001 (com.microsoft.bing; build:431027001; iOS 17.6.1) Alamofire/5.10.2',
'Content-Type': 'application/json',
'X-Rewards-Country': this.bot.userData.geoLocale,
'X-Rewards-Language': 'en',
'X-Rewards-ismobile': 'true'
},
data: JSON.stringify(jsonData)
}

this.bot.logger.debug(
this.bot.isMobile,
Expand Down
60 changes: 32 additions & 28 deletions src/functions/activities/api/FindClippy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { AxiosRequestConfig } from 'axios'
import type { FindClippyPromotion } from '../../../interface/DashboardData'
import { Workers } from '../../Workers'
import { randomUUID } from 'crypto'

export class FindClippy extends Workers {
private cookieHeader: string = ''
Expand All @@ -16,14 +17,14 @@ export class FindClippy extends Workers {
const activityType = promotion.activityType

try {
if (!this.bot.requestToken && this.bot.rewardsVersion === 'legacy') {
this.bot.logger.warn(
this.bot.isMobile,
'FIND-CLIPPY',
'Skipping: Request token not available, this activity requires it!'
)
return
}
// if (!this.bot.requestToken && this.bot.rewardsVersion === 'legacy') {
// this.bot.logger.warn(
// this.bot.isMobile,
// 'FIND-CLIPPY',
// 'Skipping: Request token not available, this activity requires it!'
// )
// return
// }

this.cookieHeader = this.bot.browser.func.buildCookieHeader(
this.bot.isMobile ? this.bot.cookies.mobile : this.bot.cookies.desktop,
Expand All @@ -47,16 +48,15 @@ export class FindClippy extends Workers {
`Prepared headers | cookieLength=${this.cookieHeader.length} | fingerprintHeaderKeys=${Object.keys(this.fingerprintHeader).length}`
)

const formData = new URLSearchParams({
id: offerId,
hash: promotion.hash,
timeZone: '60',
activityAmount: '1',
dbs: '0',
form: '',
type: activityType,
__RequestVerificationToken: this.bot.requestToken
})
const jsonData = {
amount: 1,
id: randomUUID(),
type: 101,
attributes: {
offerid: offerId,
},
country: this.bot.userData.geoLocale
}

this.bot.logger.debug(
this.bot.isMobile,
Expand All @@ -65,16 +65,20 @@ export class FindClippy extends Workers {
)

const request: AxiosRequestConfig = {
url: 'https://rewards.bing.com/api/reportactivity?X-Requested-With=XMLHttpRequest',
method: 'POST',
headers: {
...(this.bot.fingerprint?.headers ?? {}),
Cookie: this.cookieHeader,
Referer: 'https://rewards.bing.com/',
Origin: 'https://rewards.bing.com'
},
data: formData
}
url: 'https://prod.rewardsplatform.microsoft.com/dapi/me/activities',
method: 'POST',
headers: {
Authorization: `Bearer ${this.bot.accessToken}`,
'User-Agent':
'Bing/32.5.431027001 (com.microsoft.bing; build:431027001; iOS 17.6.1) Alamofire/5.10.2',
'Content-Type': 'application/json',
'X-Rewards-Country': this.bot.userData.geoLocale,
'X-Rewards-Language': 'en',
'X-Rewards-ismobile': 'true'
},
data: JSON.stringify(jsonData)
}


this.bot.logger.debug(
this.bot.isMobile,
Expand Down
59 changes: 35 additions & 24 deletions src/functions/activities/api/UrlReward.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { AxiosRequestConfig } from 'axios'
import type { BasePromotion } from '../../../interface/DashboardData'
import type { PanelFlyoutData } from '../../../interface/PanelFlyoutData'
import { Workers } from '../../Workers'

export class UrlReward extends Workers {
Expand All @@ -11,18 +12,28 @@ export class UrlReward extends Workers {

private oldBalance: number = this.bot.userData.currentPoints

private panelData: PanelFlyoutData = this.bot.panelData

public async doUrlReward(promotion: BasePromotion) {
if (!this.bot.requestToken && this.bot.rewardsVersion === 'legacy') {

const offerId = promotion.offerId

const todayKey = this.bot.utils.getFormattedDate()

// find promotion in panelData promotions or flyoutResult.morePromotions
const panelPromotion =
this.panelData.flyoutResult.morePromotions.find(p => p.offerId === offerId) ||
this.panelData.flyoutResult.dailySetPromotions[todayKey]?.find(p => p.offerId === offerId)

if (!panelPromotion) {
this.bot.logger.warn(
this.bot.isMobile,
this.bot.isMobile,
'URL-REWARD',
'Skipping: Request token not available, this activity requires it!'
`Promotion not found in panel data | offerId=${offerId}`
)
return
}

const offerId = promotion.offerId

this.bot.logger.info(
this.bot.isMobile,
'URL-REWARD',
Expand All @@ -46,33 +57,33 @@ export class UrlReward extends Workers {
`Prepared UrlReward headers | offerId=${offerId} | cookieLength=${this.cookieHeader.length} | fingerprintHeaderKeys=${Object.keys(this.fingerprintHeader).length}`
)

const formData = new URLSearchParams({
id: offerId,
hash: promotion.hash,
timeZone: '60',
activityAmount: '1',
dbs: '0',
form: '',
type: '',
__RequestVerificationToken: this.bot.requestToken
})
const jsonData = {
ActivityCount: 1,
ActivityType: panelPromotion.activityType,
ActivitySubType: "",
OfferId: offerId,
AuthKey: panelPromotion.hash,
Channel: this.panelData.channel,
PartnerId: this.panelData.partnerId,
UserId: this.panelData.userId,
}

this.bot.logger.debug(
this.bot.isMobile,
'URL-REWARD',
`Prepared UrlReward form data | offerId=${offerId} | hash=${promotion.hash} | timeZone=60 | activityAmount=1`
`Prepared UrlReward form data | offerId=${offerId} | hash=${panelPromotion.hash} | timeZone=60 | activityAmount=1`
)

const request: AxiosRequestConfig = {
url: 'https://rewards.bing.com/api/reportactivity?X-Requested-With=XMLHttpRequest',
url: 'https://www.bing.com/msrewards/api/v1/reportactivity',
method: 'POST',
headers: {
...(this.bot.fingerprint?.headers ?? {}),
Cookie: this.cookieHeader,
Referer: 'https://rewards.bing.com/',
Origin: 'https://rewards.bing.com'
},
data: formData
// headers: {
// ...(this.bot.fingerprint?.headers ?? {}),
// Accept: '*/*',
// "Content-Type": 'text/plain;charset=UTF-8',
// Origin: 'https://www.bing.com',
// },
data: jsonData
}

this.bot.logger.debug(
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { sendDiscord, flushDiscordQueue } from './logging/Discord'
import { sendNtfy, flushNtfyQueue } from './logging/Ntfy'
import type { DashboardData } from './interface/DashboardData'
import type { AppDashboardData } from './interface/AppDashBoardData'
import { PanelFlyoutData } from './interface/PanelFlyoutData'

interface ExecutionContext {
isMobile: boolean
Expand Down Expand Up @@ -80,6 +81,7 @@ export class MicrosoftRewardsBot {
public mainDesktopPage!: Page

public userData: UserData
public panelData!: PanelFlyoutData

public rewardsVersion: 'legacy' | 'modern' = 'legacy'

Expand Down Expand Up @@ -410,6 +412,7 @@ export class MicrosoftRewardsBot {

const data: DashboardData = await this.browser.func.getDashboardData()
const appData: AppDashboardData = await this.browser.func.getAppDashboardData()
this.panelData = await this.browser.func.getPanelFlyoutData()

// Set geo
this.userData.geoLocale =
Expand Down
Loading