- // ==UserScript==
- // @name MegaCloud Auto Password Decrypter
- // @namespace MGDEC_V1
- // @version 1.0
- // @description try to resolve password in mega cloud
- // @author Laria
- // @match https://mega.nz/#P*
- // @match https://mega.io/#P*
- // @icon https://mega.nz/favicon.ico?v=3
- // @license MIT
- // @grant none
- // ==/UserScript==
- /*
- * == Change log ==
- * 1.0 - Release
- */
-
- //utility
- const currentDate = new Date();
- function zeroPad(num, numZeros) {
- var n = Math.abs(num);
- var zeros = Math.max(0, numZeros - Math.floor(n).toString().length );
- var zeroString = Math.pow(10,zeros).toString().substr(1);
- if( num < 0 ) {
- zeroString = '-' + zeroString;
- }
- return zeroString+n;
- }
-
- //script const db
- const mapdConstDB = {
- //password dictionary, input common password or your own password
- //you must change here.
- passwordDict: [
- 'password01',
- 'password02',
- 'password03',
- 'password04',
- 'password05',
- 'password06',
- ],
- //try to resolve decrypt time interval, def:50
- timeInterval: 50, //logging prefix
- logPrompt: {
- default: '['+GM.info.script.namespace+']',
- },
- };
-
- //script internal db
- let mapdInternalDB = {
- elements: { //define after load
- container: null,
- passwordVisible: null,
- inputArea: null,
- decryptButton: null,
- megaBanner: null,
- decryptionProgress: null,
- },
- isValidation: false,
- };
-
- //utility 2
-
- const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
-
- //https://stackoverflow.com/questions/5525071
- function waitForElm(selector) {
- return new Promise(resolve => {
- if (document.querySelector(selector)) {
- return resolve(document.querySelector(selector));
- }
-
- const observer = new MutationObserver(mutations => {
- if (document.querySelector(selector)) {
- observer.disconnect();
- resolve(document.querySelector(selector));
- }
- });
-
- // If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
- });
- }
-
- //input given password and resolve it
- async function tryToDecrypt(pwd) {
- //remove modal valid msg
- await mapdInternalDB.elements.inputArea.dispatchEvent(new Event('input'));
- //fill password field
- mapdInternalDB.elements.inputArea.value = pwd;
- //click confirm
- await mapdInternalDB.elements.decryptButton.click();
- }
-
- //await validation
- async function waitForValidation() {
- let timeCnt = 0;
- while(mapdInternalDB.isValidation) {
- if (timeCnt > 100) break;
- timeCnt ++;
- await delay(mapdConstDB.timeInterval);
- }
- }
-
- //decrypt procedure
- async function decrypt() {
- //mutation observer - decrypt process
- const observer = new MutationObserver(function(mutations) {
- mutations.forEach(function(mutation) {
- mapdInternalDB.isValidation = !mutation.target.classList.contains('hidden');
- });
- });
-
- observer.observe(mapdInternalDB.elements.decryptionProgress, {
- attributes: true,
- });
-
- //pre-process
- await delay(50);
- //remove view
- await mapdInternalDB.elements.passwordVisible.click();
- //remove default input message
- mapdInternalDB.elements.inputArea.dispatchEvent(new Event('focus'));
-
- //main process
- let tryCount = 0;
- const startTime = performance.now();
- for (let i = 0; i < mapdConstDB.passwordDict.length; i++) {
- window.console.log(mapdConstDB.logPrompt.default, 'no.', i, ', try:', mapdConstDB.passwordDict[i]);
- await tryToDecrypt(mapdConstDB.passwordDict[i]);
- if (i > 0) await waitForValidation();
- //correct password
- if (mapdInternalDB.elements.container.classList.contains('hidden')) {
- const endTime = performance.now();
- const durationSec = parseFloat((Math.ceil((endTime-startTime) * 100) / 100000).toFixed(2));
- window.console.log(mapdConstDB.logPrompt.default, 'decrypt finished.');
- window.console.log(mapdConstDB.logPrompt.default, 'expected password :', mapdConstDB.passwordDict[i]);
- window.console.log(mapdConstDB.logPrompt.default, 'tries:', tryCount, ', duration:', durationSec, 'sec');
- return;
- }
- tryCount ++;
- }
- const endTime = performance.now();
- const durationSec = parseFloat((Math.ceil((endTime-startTime) * 100) / 100000).toFixed(2));
- //if resolve failed,
- window.console.log(mapdConstDB.logPrompt.default, 'cannot find password in dict..');
- window.console.log(mapdConstDB.logPrompt.default, 'tries:', tryCount, ', duration:', durationSec, 'sec');
- //replace first dict password, show summary, focus input area
- await delay(50);
- mapdInternalDB.elements.inputArea.value = mapdConstDB.passwordDict[0];
- await delay(20);
- mapdInternalDB.elements.megaBanner.innerHTML = `<div><b>Auto Decryption Failed</b><br><i style="font-size: 82.5%;">Please input manually..</i><br><span style="font-size: 78.5%;">( tries: ${tryCount}, dur: ${durationSec} sec )</span></div>`;
- await mapdInternalDB.elements.inputArea.focus();
-
- }
-
- //register elements
- function registerElements() {
- mapdInternalDB.elements.container = document.querySelector('.password-dialog');
- mapdInternalDB.elements.passwordVisible = mapdInternalDB.elements.container.querySelector('.pass-visible');
- mapdInternalDB.elements.inputArea = mapdInternalDB.elements.container.querySelector('#password-decrypt-input');
- mapdInternalDB.elements.decryptButton = mapdInternalDB.elements.container.querySelector('.decrypt-link-button');
- mapdInternalDB.elements.megaBanner = mapdInternalDB.elements.container.querySelector('.mega-banner');
- mapdInternalDB.elements.decryptionProgress = mapdInternalDB.elements.container.querySelector('.decryption-in-progress');
- }
-
- async function rootProcedure() {
- window.console.log(mapdConstDB.logPrompt.default,'V',GM.info.script.version, '-', GM.info.script.name);
- window.console.log(mapdConstDB.logPrompt.default, '- wait modal..');
- //await password modal
- await waitForElm('.password-dialog');
- window.console.log(mapdConstDB.logPrompt.default,'modal loaded, decrypt ready');
- //register modal elements
- registerElements();
- //decrypt start
- await decrypt();
- window.console.log(mapdConstDB.logPrompt.default,'task finished.');
- }
-
- window.addEventListener('load', () => setTimeout(rootProcedure, 100));