Skip to content

Instantly share code, notes, and snippets.

@longnull
Last active April 20, 2024 12:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save longnull/8f06d748a46646163748d56b81730039 to your computer and use it in GitHub Desktop.
Save longnull/8f06d748a46646163748d56b81730039 to your computer and use it in GitHub Desktop.
AliExpress User Paste
// ==UserScript==
// @name AliExpress User Paste
// @description Позволяет вставлять в форму входа/регистрации логин и пароль одновременно
// @author longnull
// @namespace longnull
// @version 1.6
// @homepage https://gist.github.com/longnull/8f06d748a46646163748d56b81730039
// @updateURL https://gist.github.com/longnull/8f06d748a46646163748d56b81730039/raw/AliExpressUserPaste.user.js
// @downloadURL https://gist.github.com/longnull/8f06d748a46646163748d56b81730039/raw/AliExpressUserPaste.user.js
// @match *://*.aliexpress.com/*
// @match *://*.aliexpress.ru/*
// @grant none
// ==/UserScript==
(() => {
'use strict';
////////////////////////////////////////////////////////////
// Настройки
////////////////////////////////////////////////////////////
const config = {
// Один пароль для всех аккаунтов
onePasswordForAllAccounts: '',
// Установить фокус на поле логина или пароля
// login - фокус на поле логина
// password - фокус на поле пароля
// другое - не устанавливать фокус
setFocusTo: 'login',
// true - Нажать кнопку для входа/регистрации
submit: true
};
////////////////////////////////////////////////////////////
const forms = [
{login: '#fm-login-id', pass: '#fm-login-password', submit: '[class*="login-submit"], .password-login'},
{login: '.email', pass: '.password', submit: '.submit'},
{login: '.fm-join .fm-field input[type="text"]', pass: '.fm-join .comet-input-password input', submit: '.create-submit'},
{login: '[class*="fm-join"] [class*="fm-field"] input[type="text"]', pass: '[class*="fm-join"] input[type="password"]', submit: '[class*="create-submit"]'},
{login: '#email', pass: '#password', submit: 'form[class*="email-auth_DefaultFlow__form"] button[type="submit"]'},
{login: 'div[class*="SnowAuthContextWidget__newDialog"] [name="email"]', pass: '[name="password"]', next: '[name="login-continue"]', submit: '[name="login-submit"]'},
{login: '.nfm-batman-container .nfm-multiple-container input', pass: '#fm-login-password', next: '.nfm-batman-container .cosmos-btn-primary, .nfm-batman-container .comet-btn-primary', nextWait: '.nfm-batman-container .cosmos-btn-primary:not(.cosmos-btn-loading), .nfm-batman-container .comet-btn-primary:not(.comet-btn-loading)', submit: '.nfm-batman-container .cosmos-btn-primary, .nfm-batman-container .comet-btn-primary'}
];
const waitForElement = (selectors, waitForExistence = true, visible = false, parent = document, interval = 250, seconds = 0) => {
const isVisible = (e) => {
return !!(e.offsetWidth || e.offsetHeight || e.getClientRects().length);
};
return new Promise((resolve) => {
if (!Array.isArray(selectors)) {
selectors = [selectors];
}
seconds = seconds * 1000;
const startTime = Date.now();
const check = () => {
let found = true;
let el;
for (const s of selectors) {
el = parent.querySelector(s);
if ((waitForExistence && (!el || (visible && !isVisible(el)))) || (!waitForExistence && el)) {
found = false;
break;
}
}
if (found) {
return resolve(el);
}
if (seconds > 0 && Date.now() - startTime > seconds) {
return resolve(false);
}
setTimeout(check, interval);
};
check();
});
};
const sleep = async (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
};
const setInput = (input, value) => {
if (typeof input === 'string') {
input = document.querySelector(input);
}
if (!input) {
return;
}
input.value = value;
Object.getOwnPropertyDescriptor(Object.getPrototypeOf(input), 'value').set.call(input, value);
let props = Object.keys(input).filter((i) => i.indexOf('__reactEventHandlers') >= 0);
if (!props.length) {
props = Object.keys(input).filter((i) => i.indexOf('__reactProps') >= 0);
}
if (props.length) {
if (input[props[0]].onChange) {
input[props[0]].onChange({target: {value: input.value}});
}
if (input[props[0]].onKeyDown) {
input[props[0]].onKeyDown({target: {value: input.value}});
}
}
input.dispatchEvent(new Event('input', {bubbles: true}));
input.dispatchEvent(new Event('change', {bubbles: true}));
input.dispatchEvent(new Event('keyup', {bubbles: true}));
input.dispatchEvent(new Event('keydown', {bubbles: true}));
input.dispatchEvent(new Event('keypress', {bubbles: true}));
input.dispatchEvent(new Event('input', {bubbles: true}));
input.dispatchEvent(new Event('blur', {bubbles: true}));
};
setInterval(() => {
for (const f of forms) {
if (f.listen) {
continue;
}
const elLogin = document.querySelector(f.login);
if (!elLogin) {
continue;
}
let elPass;
let elNext;
let elSubmit;
if (f.next) {
elNext = document.querySelector(f.next);
if (!elNext) {
continue;
}
} else {
elPass = document.querySelector(f.pass);
elSubmit = document.querySelector(f.submit);
if (!elPass || (config.submit && !elSubmit)) {
continue;
}
}
const listener = async (event) => {
const text = (event.clipboardData || window.clipboardData).getData('text').trim();
const match = text.match(config.onePasswordForAllAccounts ? /([^\s:;]+)/ : /([^\s:;]+)[\s:;]+([^\s:;]+)/);
if (match) {
event.preventDefault();
setInput(elLogin, match[1]);
if (f.next) {
if (f.nextWait) {
await waitForElement(f.nextWait);
} else {
await sleep(200);
}
elNext.click();
await waitForElement([f.pass, f.submit]);
elPass = document.querySelector(f.pass);
elSubmit = document.querySelector(f.submit);
}
setInput(elPass, config.onePasswordForAllAccounts ? config.onePasswordForAllAccounts : match[2]);
if (config.submit) {
await sleep(200);
elSubmit.click();
}
}
};
elLogin.addEventListener('paste', listener);
if (config.setFocusTo === 'login') {
elLogin.focus();
}
if (!f.next) {
elPass.addEventListener('paste', listener);
if (config.setFocusTo === 'password') {
elPass.focus();
}
}
f.listen = true;
}
}, 200);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment