Skip to content

Commit

Permalink
feat: simulate user input
Browse files Browse the repository at this point in the history
  • Loading branch information
dessant committed Feb 18, 2019
1 parent 3398166 commit 779f466
Show file tree
Hide file tree
Showing 22 changed files with 992 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"presets": ["@babel/env"],
"presets": [["@babel/env", {"useBuiltIns": "usage"}]],
"env": {
"production": {
"plugins": ["lodash"]
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"build:prod:chrome": "cross-env TARGET_ENV=chrome yarn _build:prod",
"build:prod:firefox": "cross-env TARGET_ENV=firefox yarn _build:prod",
"build:prod:opera": "cross-env TARGET_ENV=opera yarn _build:prod",
"build:prod:all": "run-s 'build:@(chrome|firefox|opera)'",
"build:prod:all": "run-s 'build:prod:@(chrome|firefox|opera)'",
"_build:prod:zip": "yarn _build:prod && gulp zip",
"build:prod:zip:chrome": "cross-env TARGET_ENV=chrome yarn _build:prod:zip",
"build:prod:zip:firefox": "cross-env TARGET_ENV=firefox yarn _build:prod:zip",
Expand All @@ -39,10 +39,12 @@
"@material/theme": "^0.30.0",
"@material/typography": "^0.28.0",
"audiobuffer-to-wav": "^1.0.0",
"bowser": "^2.1.0",
"ext-components": "dessant/ext-components#^0.1.6",
"ext-contribute": "dessant/ext-contribute#^0.1.6",
"storage-versions": "dessant/storage-versions#^0.2.4",
"typeface-roboto": "^0.0.54",
"uuid": "^3.3.2",
"vue": "^2.5.17",
"webextension-polyfill": "^0.3.1"
},
Expand Down
75 changes: 75 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@
"description": "Title of the option."
},

"optionTitle_simulateUserInput": {
"message": "Simulate user input",
"description": "Title of the option."
},

"optionTitle_witSpeechApiLang": {
"message": "API language",
"description": "Title of the option."
Expand Down Expand Up @@ -420,6 +425,16 @@
}
},

"inputLabel_appLocation": {
"message": "App location",
"description": "Label of the input."
},

"inputLabel_manifestLocation": {
"message": "Manifest location",
"description": "Label of the input."
},

"buttonText_addApi": {
"message": "Add API",
"description": "Text of the button."
Expand All @@ -435,6 +450,61 @@
"description": "Text of the button."
},

"buttonText_downloadApp": {
"message": "Download app",
"description": "Text of the button."
},

"buttonText_installApp": {
"message": "Install app",
"description": "Text of the button."
},

"buttonText_goBack": {
"message": "Go back",
"description": "Text of the button."
},

"pageContent_optionClientAppDownloadDesc": {
"message": "Download and install the client app for user input simulation.",
"description": "Page content."
},

"pageContent_optionClientAppOSError": {
"message": "Your operating system is not supported.",
"description": "Page content."
},

"pageContent_installTitle": {
"message": "Install Buster Client",
"description": "Page content."
},

"pageContent_installDesc": {
"message": "The client app enables Buster to simulate user input and helps lower the occurrence of difficult challenges and temporary blocks.",
"description": "Page content."
},

"pageContent_installSuccessTitle": {
"message": "Installation finished",
"description": "Page content."
},

"pageContent_installSuccessDesc": {
"message": "The client app has been installed for the current browser.",
"description": "Page content."
},

"pageContent_installErrorTitle": {
"message": "Something went wrong",
"description": "Page content."
},

"pageContent_installErrorDesc": {
"message": "The installation has failed. Check the browser console for more details, and open an issue on GitHub if this error persists.",
"description": "Page content."
},

"pageTitle": {
"message": "$PAGETITLE$ - $EXTENSIONNAME$",
"description": "Title of the page.",
Expand Down Expand Up @@ -475,6 +545,11 @@
"description": "Error message."
},

"error_missingNativeApp": {
"message": "Cannot connect to native app. Finish setting up the application or turn off user input simulation from the options page.",
"description": "Error message."
},

"error_internalError": {
"message": "Something went wrong. Open the browser console for more details.",
"description": "Error message."
Expand Down
128 changes: 101 additions & 27 deletions src/background/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,96 @@ import browser from 'webextension-polyfill';

import {initStorage} from 'storage/init';
import storage from 'storage/storage';
import {showNotification, showContributePage} from 'utils/app';
import {
showNotification,
showContributePage,
sendNativeMessage
} from 'utils/app';
import {
executeCode,
executeFile,
scriptsAllowed,
functionInContext
} from 'utils/common';
import {clientAppApiVersion} from 'utils/config';

let nativePort;

function getFrameClientPos(index) {
let currentIndex = -1;
if (window !== window.top) {
const siblingWindows = window.parent.frames;
for (let i = 0; i < siblingWindows.length; i++) {
if (siblingWindows[i] === window) {
currentIndex = i;
break;
}
}
}

const targetWindow = window.frames[index];
for (const frame of document.querySelectorAll('iframe')) {
if (frame.contentWindow === targetWindow) {
let {left: x, top: y} = frame.getBoundingClientRect();
const scale = window.devicePixelRatio;

return {x: x * scale, y: y * scale, currentIndex};
}
}
}

async function getFramePos(tabId, frameId, frameIndex) {
let x = 0;
let y = 0;

while (true) {
frameId = (await browser.webNavigation.getFrame({
tabId,
frameId
})).parentFrameId;
if (frameId === -1) {
break;
}

const [data] = await executeCode(
`(${getFrameClientPos.toString()})(${frameIndex})`,
tabId,
frameId
);

frameIndex = data.currentIndex;
x += data.x;
y += data.y;
}

return {x, y};
}

async function resetCaptcha(tabId, frameId, challengeUrl) {
frameId = (await browser.webNavigation.getFrame({
tabId,
frameId: frameId
})).parentFrameId;

if (!(await scriptsAllowed(tabId, frameId))) {
await showNotification({messageId: 'error_scriptsNotAllowed'});
return;
}

if (!(await functionInContext('addListener', tabId, frameId))) {
await executeFile('/src/content/initReset.js', tabId, frameId);
}
await executeCode('addListener()', tabId, frameId);

await browser.tabs.sendMessage(
tabId,
{
id: 'resetCaptcha',
challengeUrl
},
{frameId}
);
}

function challengeRequestCallback(details) {
const url = new URL(details.url);
Expand All @@ -19,12 +102,12 @@ function challengeRequestCallback(details) {
}

async function setChallengeLocale() {
const {loadEnglishChallenge} = await storage.get(
'loadEnglishChallenge',
const {loadEnglishChallenge, simulateUserInput} = await storage.get(
['loadEnglishChallenge', 'simulateUserInput'],
'sync'
);

if (loadEnglishChallenge) {
if (loadEnglishChallenge || simulateUserInput) {
if (
!browser.webRequest.onBeforeRequest.hasListener(challengeRequestCallback)
) {
Expand Down Expand Up @@ -63,30 +146,21 @@ async function onMessage(request, sender) {
await showContributePage('use');
}
} else if (request.id === 'resetCaptcha') {
const tabId = sender.tab.id;
const frameId = (await browser.webNavigation.getFrame({
tabId,
frameId: sender.frameId
})).parentFrameId;

if (!(await scriptsAllowed(tabId, frameId))) {
await showNotification({messageId: 'error_scriptsNotAllowed'});
return;
await resetCaptcha(sender.tab.id, sender.frameId, request.challengeUrl);
} else if (request.id === 'getFramePos') {
return getFramePos(sender.tab.id, sender.frameId, request.index);
} else if (request.id === 'startNativeApp') {
nativePort = browser.runtime.connectNative('org.buster.client');
} else if (request.id === 'stopNativeApp') {
if (nativePort) {
nativePort.disconnect();
}

if (!(await functionInContext('addListener', tabId, frameId))) {
await executeFile('/src/content/initReset.js', tabId, frameId);
}
await executeCode('addListener()', tabId, frameId);

await browser.tabs.sendMessage(
tabId,
{
id: 'resetCaptcha',
challengeUrl: request.challengeUrl
},
{frameId}
);
} else if (request.id === 'sendNativeMessage') {
const message = {
apiVersion: clientAppApiVersion,
...request.message
};
return await sendNativeMessage(nativePort, message);
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/content/install.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
function install() {
const url = new URL(chrome.extension.getURL('/src/install/index.html'));
url.searchParams.set(
'session',
new URL(window.location.href).searchParams.get('session')
);
url.searchParams.set('port', window.location.port);

const frame = document.createElement('iframe');
frame.src = url.href;
document.body.appendChild(frame);
}

install();
14 changes: 10 additions & 4 deletions src/content/reset.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
(function() {
const onMessage = function(e) {
e.stopImmediatePropagation();
window.clearTimeout(timeoutId);

const challengeUrl = e.detail;
for (const [k, v] of Object.entries(___grecaptcha_cfg.clients)) {
if (v['O'].D.src === challengeUrl) {
grecaptcha.reset(k);
break;
for (const [k, client] of Object.entries(___grecaptcha_cfg.clients)) {
for (const [_, items] of Object.entries(client)) {
for (const [_, v] of Object.entries(items)) {
if (v instanceof Element && v.src === challengeUrl) {
grecaptcha.reset(k);
break;
}
}
}
}
};
Expand Down
Loading

0 comments on commit 779f466

Please sign in to comment.