AnthonyZJiang / Microsoft-Reward-Chrome-Ext

A Chrome extension for Microsoft Rewards search, for accounts with two-factor authentication.
Apache License 2.0
319 stars 71 forks source link

keeps showing error, doesnt do my searches #114

Closed ivvyleague closed 1 year ago

ivvyleague commented 1 year ago

keeps showing error, doesnt do my searches even tho im logged in on microsoft & bing

AnthonyZJiang commented 1 year ago

Can you please visit chrome://extensions page and click the Errors next to this extension? Take screenshots of the errors and add them here.

mreuther commented 1 year ago

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 class DailyRewardStatus { constructor() { this.reset(); }

reset() {
    this._pcSearch_ = new DailySearchQuest(0, 0);
    this._mbSearch_ = new DailySearchQuest(0, 0);
    this._quizAndDaily_ = new DailyQuest(0, 0);
    this._jobStatus_ = STATUS_NONE;
}

get jobStatus() {
    return this._jobStatus_;
}

get pcSearchStatus() {
    return this._pcSearch_;
}

get mbSearchStatus() {
    return this._mbSearch_;
}

get quizAndDailyStatus() {
    return this._quizAndDaily_;
}

get summary() {
    return new DailyQuest(this._progressSummary_, this._maxSummary_);
}

get isSearchCompleted() {
    return this._mbSearch_.isCompleted && this._pcSearch_.isCompleted;
}

get _progressSummary_() {
    return this._pcSearch_.progress + this._mbSearch_.progress + this._quizAndDaily_.progress;
}

get _maxSummary_() {
    return this._pcSearch_.max + this._mbSearch_.max + this._quizAndDaily_.max;
}

async update() {
    // Exceptions:
    // ParseJSONFailedException         @ _parsePointBreakdownDocument(), caused by changes in point breakdown page.
    //                                  @ parse methods, caused by changes in user status JSON.
    // FetchFailedException             @ _getPointBreakdownDocument(), when point breakdown page is unreachable - because server is down, network is interrupted, etc.

    this.reset();
    this._jobStatus_ = STATUS_BUSY;
    try {
        const statusJson = await this.getUserStatusJson();
        this._parseUserStatus(statusJson);
        const detailedStatusJson = await this.getDetailedUserStatusJson();
        if (detailedStatusJson) {
            this._parseDetailedUserStatus(detailedStatusJson);
        }
    } catch (ex) {
        this._jobStatus_ = STATUS_ERROR;
        throw ex;
    }
    this._jobStatus_ = STATUS_DONE;

    return this._jobStatus_;
}

async getUserStatusJson() {
    const controller = new AbortController();
    const signal = controller.signal;
    const fetchPromise = fetch(USER_STATUS_BING_URL, this._getFetchOptions(signal));
    setTimeout(() => controller.abort(), 3000);
    const text = await this._awaitFetchPromise(fetchPromise).catch(async (ex) => {
        throw new ResponseUnexpectedStatusException('DailyRewardStatus::getUserStatusJsonFromBing', ex);
    });
    return DailyRewardStatus.getUserStatusJSON(text);
}

async getDetailedUserStatusJson() {
    const controller = new AbortController();
    const signal = controller.signal;
    const fetchPromise = fetch(USER_STATUS_DETAILED_URL, this._getFetchOptions(signal));
    setTimeout(() => controller.abort(), 3000);
    const text = await this._awaitFetchPromise(fetchPromise).catch(async (ex) => {
        if (ex.name == 'FetchFailed::TypeError') {
            console.log('An error occurred in the first status update attempt:');
            logException(ex);
            return null;
        }
        throw new ResponseUnexpectedStatusException('DailyRewardStatus::getUserStatusJson', ex);
    });
    const doc = getDomFromText(text);
    return DailyRewardStatus.getDetailedUserStatusJSON(doc);
}

async _awaitFetchPromise(fetchPromise) {
    let response;
    try {
        response = await fetchPromise;
    } catch (ex) {
        if (ex.name == 'TypeError') {
            throw new FetchFailedException('DailyRewardStatus::_awaitFetchPromise', ex, 'Are we redirected? You probably haven\'t logged in yet.');
        }
        if (ex.name == 'AbortError') {
            throw new FetchFailedException('DailyRewardStatus::_awaitFetchPromise', ex, 'Fetch timed out. Do you have internet connection? Otherwise, perhaps MSR server is down.');
        }
        throw ex;
    }

    if (response.ok) {
        return response.text();
    }

    throw await response.text();
}

_getFetchOptions(signal) {
    return {
        method: 'GET',
        signal: signal,
    };
}

//* *************
// PARSE METHODS
//* *************
_parseUserStatus(statusJson) {
    if (statusJson == null) {
        throw new ParseJSONFailedException('DailyRewardStatus::_parseDetailedUserStatus', null, 'Empty json received.');
    }
    try {
        this._parseRewardUser(statusJson);
        if (this._userIsError || !this._isRewardsUser) {
            throw new NotRewardUserException(`Have you logged into Microsoft Rewards? Query returns {IsError:${this._userIsError},IsRewardsUser:${this._isRewardsUser}}`);
        }
        this._parsePcSearch(statusJson.FlyoutResult);
        this._parseMbSearch(statusJson.FlyoutResult);
        this._parseActivityAndQuiz(statusJson.FlyoutResult);
        this._parseDaily(statusJson.FlyoutResult);
    } catch (ex) {
        if (ex.name == 'TypeError' || ex.name == 'ReferenceError') {
            throw new ParseJSONFailedException('DailyRewardStatus::_parseDetailedUserStatus', ex, 'Fail to parse the received json document. Has MSR updated its json structure?');
        }
        throw ex;
    }
}

_parseRewardUser(statusJson) {
    this._userIsError = statusJson.hasOwnProperty('IsError') && statusJson.IsError;
    this._isRewardsUser = statusJson.hasOwnProperty('IsRewardsUser') && statusJson.IsRewardsUser;
}

_parsePcSearch(statusJson) {
    statusJson.UserStatus.Counters.PCSearch.forEach((obj) => {
        this._pcSearch_.progress += obj.PointProgress;
        this._pcSearch_.max += obj.PointProgressMax;
    });
}

_parseMbSearch(statusJson) {
    if (!statusJson.UserStatus.Counters.hasOwnProperty('MobileSearch')) {
        this._mbSearch_.progress = 1;
        this._mbSearch_.max = 1;
        return;
    }
    this._mbSearch_.progress = statusJson.UserStatus.Counters.MobileSearch[0].PointProgress;
    this._mbSearch_.max = statusJson.UserStatus.Counters.MobileSearch[0].PointProgressMax;
}

_parseActivityAndQuiz(statusJson) {
    this._quizAndDaily_.progress += statusJson.UserStatus.Counters.ActivityAndQuiz[0].PointProgress;
    this._quizAndDaily_.max += statusJson.UserStatus.Counters.ActivityAndQuiz[0].PointProgressMax;
}

_parseDaily(statusJson) {
    const dailySet = statusJson.DailySetPromotions[getTodayDate()];
    if (!dailySet) return;
    dailySet.forEach((obj) => {
        if (obj.Complete) {
            this._quizAndDaily_.progress += obj.PointProgressMax;
        } else {
            this._quizAndDaily_.progress += obj.PointProgress;
        }
        this._quizAndDaily_.max += obj.PointProgressMax;
    });
}

_parseDetailedUserStatus(statusJson) {
    if (statusJson == null) {
        throw new ParseJSONFailedException('DailyRewardStatus::_parseDetailedUserStatus', null, 'Empty json received.');
    }
    try {
        this._parsePunchCards(statusJson, _compatibilityMode);
    } catch (ex) {
        if (ex.name == 'TypeError' || ex.name == 'ReferenceError') {
            throw new ParseJSONFailedException('DailyRewardStatus::_parseDetailedUserStatus', ex, 'Fail to parse the received json document. Has MSR updated its json structure?');
        }
    }
}

_parsePunchCards(statusJson, flagDeduct) {
    // flagDeduct: set true to deduct the point progress from the total point progress, only accurate in rare cases, reserved for compatibility mode
    for (let i = 0; i < statusJson.punchCards.length; i++) {
        const card = statusJson.punchCards[i];
        if (!card) continue;
        const parentPromo = card.parentPromo;
        if (!parentPromo) continue;

        const promoTypes = parentPromo.promotionType.split(',');
        const isPurchaseCard = !promoTypes.every((val) => (val == 'urlreward' || val == 'quiz'));
        if (flagDeduct && isPurchaseCard) {
            this._quizAndDaily_.max -= parentPromo.pointProgressMax;
        } else if (!flagDeduct && !isPurchaseCard) {
            let pointProgress = parentPromo.pointProgress;
            let pointProgressMax = parentPromo.pointProgressMax;
            for (const j in card.childPromotions) {
                if (!j) continue;
                if (card.childPromotions[j].pointProgressMax == 1) continue;
                pointProgressMax += card.childPromotions[j].pointProgressMax;
                pointProgress += card.childPromotions[j].pointProgress;
            }
            this._quizAndDaily_.max += pointProgressMax;
            if (pointProgress == pointProgressMax) {
                this._quizAndDaily_.progress += pointProgress;
            }
        }
    }
}

//* **************
// STATIC METHODS
//* **************
static getUserStatusJSON(text) {
    const m = /(=?\{"FlyoutConfig":).*(=?\}\);;)/.exec(text);
    if (m) {
        return JSON.parse(m[0].slice(0, m[0].length - 3));
    }
}

static getDetailedUserStatusJSON(doc) {
    const jsList = doc.querySelectorAll('body script[type=\'text/javascript\']:not([id])');
    for (let i = 0; i < jsList.length; i++) {
        const m = /(?=\{"userStatus":).*(=?\}\};)/.exec(jsList[i].text);
        if (m) {
            return JSON.parse(m[0].slice(0, m[0].length - 1));
        }
    }
    return null;
}

}

const USER_STATUS_BING_URL = 'https://www.bing.com/rewardsapp/flyout?channel=0&partnerId=EdgeNTP&pageType=ntp&isDarkMode=0'; const USER_STATUS_DETAILED_URL = 'https://rewards.bing.com/';

mreuther commented 1 year ago

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 class SearchQuest { constructor(googleTrend) { this.googleTrend = googleTrend; this._searchIntervalMS = 2000; this.reset(); }

reset() {
    this._status_ = null;
    this._pcSearchWordIdx_ = 0;
    this._mbSearchWordIdx_ = 0;
    this._currentSearchCount_ = 0;
    this._currentSearchType_ = null;
    this._jobStatus_ = STATUS_NONE;
}

get jobStatus() {
    return this._jobStatus_;
}

async doWork(status) {
    console.assert(status != null);

    this._status_ = status;
    this._jobStatus_ = STATUS_BUSY;
    try {
        await getUA();
        await this._googleTrend_.getGoogleTrendWords();
        await this._doWorkLoop();
    } catch (ex) {
        this._jobStatus_ = STATUS_ERROR;
        if (ex instanceof UserAgentInvalidException) {
            notifyUpdatedUAOutdated();
        }
        throw ex;
    }
}

async _doWorkLoop() {
    while (true) {
        if (this._status_.isSearchCompleted) {
            return;
        }

        if (this._status_.jobStatus == STATUS_ERROR || !this._status_.summary.isValid) {
            this._jobStatus_ = STATUS_ERROR;
            return;
        }

        await this._startSearchQuests();

        const flag = await this.isSearchSuccessful();
        if (flag > 0) {
            await this._getAlternativeUA(flag);
        }
    }
}

async _startSearchQuests() {
    await this._doPcSearch();
    await this._doMbSearch();
    this._quitSearchCleanUp();
}

async isSearchSuccessful() {
    // Return:
    // 0 - successful; 1 - pc search failed; 2 - mb search failed; 3 - both failed
    const pcSearchProgBefore = this._status_.pcSearchStatus.progress;
    const mbSearchProgBefore = this._status_.mbSearchStatus.progress;
    await this._status_.update();
    const flag = (!this._status_.pcSearchStatus.isValidAndCompleted && (pcSearchProgBefore == this._status_.pcSearchStatus.progress));
    return flag + 2 * (!this._status_.mbSearchStatus.isValidAndCompleted && (mbSearchProgBefore == this._status_.mbSearchStatus.progress));
}

async _getAlternativeUA(flag) {
    if (flag == 3) {
        if (userAgents.pcSource == 'updated' && userAgents.mbSource == 'updated') {
            throw new UserAgentInvalidException('Cannot find working UAs for pc and mobile.');
        }
        await getUpdatedUA('both');
    } else if (flag == 1) {
        if (userAgents.pcSource == 'updated') {
            throw new UserAgentInvalidException('Cannot find a working UA for pc.');
        }
        await getUpdatedUA('pc');
    } else if (flag == 2) {
        if (userAgents.mbSource == 'updated') {
            throw new UserAgentInvalidException('Cannot find a working UA for mobile.');
        }
        await getUpdatedUA('mb');
    }
    notifyStableUAOutdated(flag);
}

async _doPcSearch() {
    this._initiateSearch();
    if (this._currentSearchType_ != SEARCH_TYPE_PC_SEARCH) {
        this._preparePCSearch();
    }

    await this._requestBingSearch();
}

async _doMbSearch() {
    this._initiateSearch();
    if (this._currentSearchType_ != SEARCH_TYPE_MB_SEARCH) {
        this._prepareMbSearch();
    }

    await this._requestBingSearch();
}

_initiateSearch() {
    this._currentSearchCount_ = 0;
}

_preparePCSearch() {
    this._currentSearchType_ = SEARCH_TYPE_PC_SEARCH;
    removeUA();
    setMsEdgeUA();
}

_prepareMbSearch() {
    this._currentSearchType_ = SEARCH_TYPE_MB_SEARCH;
    removeUA();
    setMobileUA();
}

_quitSearchCleanUp() {
    if (this._jobStatus_ == STATUS_BUSY) {
        this._jobStatus_ = STATUS_DONE;
    }
    this._currentSearchType_ = null;
    removeUA();
}

async _requestBingSearch() {
    if (this._isCurrentSearchCompleted()) {
        return;
    }
    let response;
    try {
        response = await fetch(this._getBingSearchUrl());
    } catch (ex) {
        throw new FetchFailedException('Search', ex);
    }

    if (response.status != 200) {
        throw new FetchResponseAnomalyException('Search');
    }

    this._currentSearchCount_++;
    await sleep(this._searchIntervalMS);

    await this._requestBingSearch();
}

_getBingSearchUrl() {
    const word = this._currentSearchType_ == SEARCH_TYPE_PC_SEARCH ?
        this._googleTrend_.nextPCWord :
        this._googleTrend_.nextMBWord;

    return `https://www.bing.com/search?q=${word}`;
}

_isCurrentSearchCompleted() {
    return this._currentSearchType_ == SEARCH_TYPE_PC_SEARCH ?
        this._currentSearchCount_ >= this._status_.pcSearchStatus.searchNeededCount :
        this._currentSearchCount_ >= this._status_.mbSearchStatus.searchNeededCount;
}

}

function removeUA() { try { chrome.webRequest.onBeforeSendHeaders.removeListener(toMobileUA); } catch (ex) { } try { chrome.webRequest.onBeforeSendHeaders.removeListener(toMsEdgeUA); } catch (ex) { } }

function setMsEdgeUA() { chrome.webRequest.onBeforeSendHeaders.addListener(toMsEdgeUA, { urls: ['https://www.bing.com/search?q=*'], }, ['blocking', 'requestHeaders']); }

function toMsEdgeUA(details) { for (const i in details.requestHeaders) { if (details.requestHeaders[i].name === 'User-Agent') { details.requestHeaders[i].value = userAgents.pc; break; } } return { requestHeaders: details.requestHeaders, }; }

function setMobileUA() { chrome.webRequest.onBeforeSendHeaders.addListener(toMobileUA, { urls: ['https://www.bing.com/search?q=*'], }, ['blocking', 'requestHeaders']); }

function toMobileUA(details) { for (const i in details.requestHeaders) { if (details.requestHeaders[i].name === 'User-Agent') { details.requestHeaders[i].value = userAgents.mb; break; } } return { requestHeaders: details.requestHeaders, }; }

function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); }

function notifyStableUAOutdated(flag) { if (developer && developer.notification_ua_stable_outdated) { const message = 'Stable UA is outdated! Flag: ' + (flag == 3 ? 'pc and mobile' : flag == 1 ? 'pc' : 'mobile'); console.log(message); chrome.notifications.clear('stable_ua_outdated'); chrome.notifications.create('stable_ua_outdated', { type: 'basic', iconUrl: 'img/warn@8x.png', title: 'Developer notification', message: message, priority: 2, }); } }

function notifyUpdatedUAOutdated() { if (developer && developer.notification_ua_updated_outdated) { const message = 'Critical!! Updated UA is outdated!'; console.log(message); chrome.notifications.clear('updated_ua_outdated'); chrome.notifications.create('updated_ua_outdated', { type: 'basic', iconUrl: 'img/err@8x.png', title: 'Developer notification', message: message, priority: 2, }); } }

const SEARCH_TYPE_PC_SEARCH = 0; const SEARCH_TYPE_MB_SEARCH = 1; const STATUS_NONE = 0; const STATUS_BUSY = 1; const STATUS_DONE = 20; const STATUS_WARNING = 30; const STATUS_ERROR = 3;

mreuther commented 1 year ago

Similar behavior to original poster, specifically affecting mobile searches. System is throwing both an error that says the user is not logged in (they are on both) as well as an error declaring the unavailability of a proper mobile UA.

At this time the extension has completed searches, but not mobile searches. This behavior is happening on the latest stable chrome. (The default version.)

Screenshot 2023-04-16 211820

Screenshot 2023-04-16 212004

Screenshot 2023-04-16 212040

PlsFixTheErrorMan commented 1 year ago

heres my errors image image

mreuther commented 1 year ago

Today the error has morphed into the same PC and mobile UA error posted by PlsFixTheErrorMan.

Now no searches are being executed.

PlsFixTheErrorMan commented 1 year ago

cmon mane pls fix the error

AnthonyZJiang commented 1 year ago

Today the error has morphed into the same PC and mobile UA error posted by PlsFixTheErrorMan.

Now no searches are being executed.

Hey, thank you for your feedback. Sorry, I had to hide your other comments as they are too long making the issue page difficult to read.

This is a typical user agent issue, which is probably only happening to a small group of people. I would suggest you to go to the extension options, enable the relevant user agent override, and copy and paste one user agents from the list below. You probably need to try a few times before getting a working one.

I suggest Edge browser for PC and safari ios for mobile.