Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Vexcited/fb392f782cae8b78a91b3dcd300c22fb to your computer and use it in GitHub Desktop.
Save Vexcited/fb392f782cae8b78a91b3dcd300c22fb to your computer and use it in GitHub Desktop.
A helper for captcha completion in Genshin Impact on mobile devices using Boosteroid Cloud Gaming platform in any Chromium-based browser.

Helper for Genshin Impact on mobile devices for Boosteroid

Everytime you start Genshin Impact on Boosteroid, you need to specify your identifier and password and then complete some captcha challenges. The thing is that with a touch screen device, you can't complete these captcha using Boosteroid.

My solution

I've found a way - through looking at their code and how WS worked - to send mouse events and then complete the captcha challenge only using your mobile device (basically, without a computer).

How does it work ?

  • Start a session and launch Genshin Impact.
  • When you're on the login screen (email/password), go to the search bar and type this.
javascript:(async()=%3E{function%20a(a){return%20new%20Promise(b=%3E{setTimeout(b,a)})}const%20b=({isPressed:a,code:b})=%3ESessionHandler.sendEvents({type:%22keyboard%22,action:%22button%22,isPressed:a,code:b}),c=async%20c=%3E{console.info(%22Sending%20text%20to%20paste...%22),SessionHandler.sendEvents({type:%22keyboard%22,action:%22clipboard%22,text:c}),await%20a(50),b({isPressed:!0,code:162}),await%20a(50),b({isPressed:!0,code:86}),await%20a(50),b({isPressed:!1,code:162}),await%20a(50),b({isPressed:!1,code:86}),console.info(%22Finished%20sending%20text%20to%20paste.%22)};console.info(%22Asking%20credentials...%22);const%20d=prompt(%22Email%20or%20Username%22),e=prompt(%22Password%22);console.info(%22Got%20credentials,%20now%20logging%20in...%22);const%20f=({isPressed:a})=%3ESessionHandler.sendEvents({type:%22mouse%22,action:%22button%22,btn:0,isPressed:a}),g=({x:a,y:b})=%3ESessionHandler.sendEvents({type:%22mouse%22,action:%22move%22,X:a,Y:b,offsetX:0,offsetY:0,isVisible:!0}),h=.6124497991967871;g({x:h,y:.3742138364779874}),await%20a(50),f({isPressed:!0}),await%20a(50),f({isPressed:!1});const%20i=async()=%3E{await%20a(50),b({isPressed:!0,code:162}),await%20a(50),b({isPressed:!0,code:65}),await%20a(50),b({isPressed:!1,code:65}),await%20a(50),b({isPressed:!1,code:162})};await%20i(),await%20c(d),console.info(%22Pasted%20identifier%20!%22),g({x:h,y:.4698275862068966}),await%20a(50),f({isPressed:!0}),await%20a(50),f({isPressed:!1}),await%20i(),await%20c(e),console.info(%22Pasted%20password%20!%22),g({x:h,y:.6508620689655172}),await%20a(50),f({isPressed:!0}),await%20a(50),f({isPressed:!1}),console.info(%22Pressed%20login%20button%20!%22);const%20j=.5818965517241379,k=.4441747572815534,l=document.createElement(%22div%22),m=document.createElement(%22div%22),n=document.createElement(%22input%22);n.setAttribute(%22type%22,%22range%22),n.setAttribute(%22min%22,k+%22%22),n.setAttribute(%22max%22,%220.5655339805825242%22),n.setAttribute(%22step%22,%22any%22),n.addEventListener(%22input%22,a=%3E{g({x:+a.target.value,y:j}),console.info(%22Moved%20cursor%20to%22,a.target.value)});const%20o=document.createElement(%22button%22);o.innerText=%22Start%22,o.onclick=()=%3E{g({x:k,y:j}),f({isPressed:!0}),console.info(%22Start%20pressing%20slider.%22)};const%20p=document.createElement(%22button%22);p.innerText=%22Confirm%20!%22,p.onclick=()=%3E{f({isPressed:!1}),console.info(%22Confirmed%20slider%20(release%20click).%22)};const%20q=document.createElement(%22button%22);q.innerText=%22Close%20captcha%20helper%22,q.onclick=()=%3El.remove(),l.style.zIndex=%22999%22,l.style.position=%22fixed%22,l.style.display=%22flex%22,l.style.flexDirection=%22column%22,l.style.gap=%2224px%22,m.style.display=%22flex%22,m.style.gap=%2224px%22,l.style.bottom=%2225px%22,l.style.width=%22100vw%22,l.style.left=%220%22,m.style.padding=%220.75em%200%22,m.style.background=%22rgba(0,%200,%200,%20.5)%22,m.style.alignItems=%22center%22,m.style.justifyContent=%22center%22,q.style.background=%22%23fff%22,q.style.width=%22fit-content%22,q.style.padding=%220.75em%201em%22,q.style.border=%22none%22,q.style.outline=%22none%22,q.style.borderRadius=%2242px%22,q.style.margin=%220%20auto%22,m.append(o),m.append(n),m.append(p),l.append(m),l.append(q),document.body.append(l)})();

Warning ! Don't forget the javascript: at the start, else the script will just not work. If you don't trust the minified version of the source code (available below, un-minified), minify it yourself.

  • It will prompt you your identifier (email or username)
  • It will prompt you your password.
  • It will paste these values into the login form of Genshin (easier login)
  • Now, a bar will show up, this bar is the helper for resolving the captcha.
    1. Start button will move the cursor to the start of the captcha slider and hold down left click
    2. The slider is used to calibrate the captcha.
    3. Confirm button will release the left click to confirm the captcha.
    • There's also a Close captcha helper button to remove the helper definitely from the DOM.
(async () => {
// 162 => CTRL ; 86 => V ; A => 65 ; Backspace => 8
const sendKeyboardEvent = ({ isPressed, code }) => SessionHandler.sendEvents({
type: "keyboard",
action: "button",
isPressed,
code
});
function delay (ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
const sendTextToPaste = async (text) => {
console.info("Sending text to paste...");
// Sending event to WS.
SessionHandler.sendEvents({
type: "keyboard",
action: "clipboard",
text
});
// Press CTRL.
await delay(50);
sendKeyboardEvent({ isPressed: true, code: 162 });
// Press V.
await delay(50);
sendKeyboardEvent({ isPressed: true, code: 86 });
// Release CTRL.
await delay(50);
sendKeyboardEvent({ isPressed: false, code: 162 });
// Release V.
await delay(50);
sendKeyboardEvent({ isPressed: false, code: 86 });
// Debug.
console.info("Finished sending text to paste.");
};
// Getting credentials to login.
console.info("Asking credentials...");
const uid = prompt("Email or Username");
const password = prompt("Password");
console.info("Got credentials, now logging in...");
// Send to WebSocket mouse event with `isPressed`: true or false.
const sendMousePressEvent = ({ isPressed }) => SessionHandler.sendEvents({
type: "mouse",
action: "button",
btn: 0, // Left Click
isPressed
});
const sendMouseMoveEvent = ({ x, y }) => SessionHandler.sendEvents({
type: "mouse",
action: "move",
X: x,
Y: y,
offsetX: 0,
offsetY: 0,
isVisible: true // Show mouse.
});
const inputsX = 0.6124497991967871;
// Emplacement of email/username input.
sendMouseMoveEvent({ x: inputsX, y: 0.3742138364779874 });
// Click on the input.
await delay(50);
sendMousePressEvent({ isPressed: true });
// Release click on the input.
await delay(50);
sendMousePressEvent({ isPressed: false });
const selectAllAndClear = async () => {
// Press CTRL.
await delay(50);
sendKeyboardEvent({ isPressed: true, code: 162 });
// Press A.
await delay(50);
sendKeyboardEvent({ isPressed: true, code: 65 });
// Release A.
await delay(50);
sendKeyboardEvent({ isPressed: false, code: 65 });
// Release CTRL.
await delay(50);
sendKeyboardEvent({ isPressed: false, code: 162 });
};
// Clear input and paste identifier.
await selectAllAndClear();
await sendTextToPaste(uid);
console.info("Pasted identifier !");
// Emplacement of password input.
sendMouseMoveEvent({ x: inputsX, y: 0.4698275862068966 });
// Click on the input.
await delay(50);
sendMousePressEvent({ isPressed: true });
// Release click on the input.
await delay(50);
sendMousePressEvent({ isPressed: false });
// Clear input and paste password.
await selectAllAndClear();
await sendTextToPaste(password);
console.info("Pasted password !");
// Emplacement of login button.
sendMouseMoveEvent({ x: inputsX, y: 0.6508620689655172 });
// Click on the login button.
await delay(50);
sendMousePressEvent({ isPressed: true });
// Release click on the login button.
await delay(50);
sendMousePressEvent({ isPressed: false });
// Debug.
console.info("Pressed login button !");
const captchaSliderY = 0.5818965517241379;
const captchaSliderInitialX = 0.4441747572815534;
const captchaSliderMenu = document.createElement("div");
const captchaSliderContainer = document.createElement("div");
const captchaSliderElement = document.createElement("input");
captchaSliderElement.setAttribute("type", "range");
// Slider limitations.
captchaSliderElement.setAttribute("min", String(captchaSliderInitialX));
captchaSliderElement.setAttribute("max", "0.5655339805825242");
captchaSliderElement.setAttribute("step", "any");
// Move the cursor when we scroll the slider.
captchaSliderElement.addEventListener("input", (e) => {
sendMouseMoveEvent({ x: +e.target.value, y: captchaSliderY });
console.info("Moved cursor to", e.target.value);
});
const captchaSliderStartElement = document.createElement("button");
captchaSliderStartElement.innerText = "Start";
captchaSliderStartElement.onclick = () => {
// Move cursor to initial captcha position.
sendMouseMoveEvent({ x: captchaSliderInitialX, y: captchaSliderY });
sendMousePressEvent({ isPressed: true });
console.info("Start pressing slider.");
};
const captchaSliderConfirmElement = document.createElement("button");
captchaSliderConfirmElement.innerText = "Confirm !";
captchaSliderConfirmElement.onclick = () => {
sendMousePressEvent({ isPressed: false });
console.info("Confirmed slider (release click).");
}
const captchaSliderClose = document.createElement("button");
captchaSliderClose.innerText = "Close captcha helper";
captchaSliderClose.onclick = () => captchaSliderMenu.remove();
captchaSliderMenu.style.zIndex = "999";
captchaSliderMenu.style.position = "fixed";
captchaSliderMenu.style.display = "flex";
captchaSliderMenu.style.flexDirection = "column";
captchaSliderMenu.style.gap = "24px";
captchaSliderContainer.style.display = "flex";
captchaSliderContainer.style.gap = "24px";
captchaSliderMenu.style.bottom = "25px";
captchaSliderMenu.style.width = "100vw";
captchaSliderMenu.style.left = "0";
captchaSliderContainer.style.padding = "0.75em 0";
captchaSliderContainer.style.background = "rgba(0, 0, 0, .5)"
captchaSliderContainer.style.alignItems = "center";
captchaSliderContainer.style.justifyContent = "center";
captchaSliderClose.style.background = "#fff";
captchaSliderClose.style.width = "fit-content";
captchaSliderClose.style.padding = "0.75em 1em";
captchaSliderClose.style.border = "none";
captchaSliderClose.style.outline = "none";
captchaSliderClose.style.borderRadius = "42px";
captchaSliderClose.style.margin = "0 auto";
captchaSliderContainer.append(captchaSliderStartElement);
captchaSliderContainer.append(captchaSliderElement);
captchaSliderContainer.append(captchaSliderConfirmElement);
captchaSliderMenu.append(captchaSliderContainer);
captchaSliderMenu.append(captchaSliderClose);
document.body.append(captchaSliderMenu);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment