Files
YouTube.js/lib/NToken.js
2021-11-23 06:09:12 -03:00

111 lines
4.4 KiB
JavaScript

'use strict';
const Utils = require('./Utils');
const Constants = require('./Constants');
class NToken {
constructor(raw_code) {
this.raw_code = raw_code;
this.null_placeholder_regex = /c\[(.*?)\]=c/g;
this.transformation_calls_regex = /c\[(.*?)\]\((.+?)\)/g;
}
transform(n) {
let n_token = n.split('');
try {
let transformations = this.getTransformationData();
transformations = transformations.map((el) => {
if (el != null && typeof el != 'number') {
const is_reverse_base64 = el.includes('case 65:');
(({ // Identifies the transformation functions and emulates them accordingly.
[Constants.FUNCS.PUSH]: () => el = (arr, i) => this.push(arr, i),
[Constants.FUNCS.SPLICE]: () => el = (arr, i) => this.splice(arr, i),
[Constants.FUNCS.SWAP0_1]: () => el = (arr, i) => this.swap0(arr, i),
[Constants.FUNCS.SWAP0_2]: () => el = (arr, i) => this.swap0(arr, i),
[Constants.FUNCS.ROTATE_1]: () => el = (arr, i) => this.rotate(arr, i),
[Constants.FUNCS.ROTATE_2]: () => el = (arr, i) => this.rotate(arr, i),
[Constants.FUNCS.REVERSE_1]: () => el = (arr) => this.reverse(arr),
[Constants.FUNCS.REVERSE_2]: () => el = (arr) => this.reverse(arr),
[Constants.FUNCS.BASE64_DIA]: () => el = () => this.getBase64Dia(is_reverse_base64),
[Constants.FUNCS.TRANSLATE_1]: () => el = (arr, token) => this.translate1(arr, token, is_reverse_base64),
[Constants.FUNCS.TRANSLATE_2]: () => el = (arr, token, base64_dic) => this.translate2(arr, token, base64_dic)
})[this.getFunc(el)] || (() => el === 'b' && (el = n_token)))();
}
return el;
});
// Fills the null placeholders with a copy of the transformations array.
let null_placeholder_positions = [...this.raw_code.matchAll(this.null_placeholder_regex)].map((item) => parseInt(item[1]));
null_placeholder_positions.forEach((pos) => transformations[pos] = transformations);
// Parses and emulates calls to functions of the transformations array.
let transformation_calls = [...Utils.getStringBetweenStrings(this.raw_code.replace(/\n/g, ''), 'try{', '}catch').matchAll(this.transformation_calls_regex)].map((params) => ({ index: params[1], params: params[2] }));
transformation_calls.forEach((data) => {
const param_index = data.params.split(',').map((param) => param.match(/c\[(.*?)\]/)[1]);
const base64_dia = (param_index[2] && transformations[param_index[2]]());
transformations[data.index](transformations[param_index[0]], transformations[param_index[1]], base64_dia);
});
} catch (err) {
console.error('Could not transform n-token, download may be throttled:', err);
return n;
}
return n_token.join('');
}
getFunc(el) {
return el.match(Constants.FUNCS_REGEX);
}
getTransformationData() {
const data = `[${Utils.getStringBetweenStrings(this.raw_code.replace(/\n/g, ''), 'c=[', '];c')}]`;
return JSON.parse(Constants.formatNTransformData(data));
}
translate1(arr, token, is_reverse_base64) {
const characters = is_reverse_base64 && Constants.BASE64_DIALECT.REVERSE || Constants.BASE64_DIALECT.NORMAL;
arr.forEach(function(char, index, loc) {
this.push(loc[index] = characters[(characters.indexOf(char) - characters.indexOf(this[index]) + 64) % characters.length]);
}, token.split(''));
}
translate2(arr, token, characters) {
let chars_length = characters.length;
arr.forEach(function(char, index, loc) {
this.push(loc[index] = characters[(characters.indexOf(char) - characters.indexOf(this[index]) + index + chars_length--) % characters.length]);
}, token.split(''));
}
getBase64Dia(is_reverse_base64) {
const characters = is_reverse_base64 && Constants.BASE64_DIALECT.REVERSE || Constants.BASE64_DIALECT.NORMAL;
return characters;
}
swap0(arr, index) {
const old_value = arr[0];
index = (index % arr.length + arr.length) % arr.length;
arr[0] = arr[index];
arr[index] = old_value;
}
rotate(arr, index) {
index = (index % arr.length + arr.length) % arr.length;
arr.splice(-index).reverse().forEach((el) => arr.unshift(el));
}
splice(arr, index) {
index = (index % arr.length + arr.length) % arr.length;
arr.splice(index, 1);
}
reverse(arr) {
arr.reverse();
}
push(arr, item) {
arr.push(item);
}
}
module.exports = NToken;