I'm using this handy Javascript function to decode a base64 string and get an array in return.
This is the string:
base64_decode_array('6gAAAOsAAADsAAAACAEAAAkBAAAKAQAAJgEAACcBAAAoAQAA')
This is what's returned:
234,0,0,0,235,0,0,0,236,0,0,0,8,1,0,0,9,1,0,0,10,1,0,0,38,1,0,0,39,1,0,0,40,1,0,0
The problem is I don't really understand the javascript function:
var base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split("");
var base64inv = {};
for (var i = 0; i < base64chars.length; i++) {
base64inv[base64chars[i]] = i;
}
function base64_decode_array (s)
{
// remove/ignore any characters not in the base64 characters list
// or the pad character -- particularly newlines
s = s.replace(new RegExp('[^'+base64chars.join("")+'=]', 'g'), "");
// replace any incoming padding with a zero pad (the 'A' character is zero)
var p = (s.charAt(s.length-1) == '=' ?
(s.charAt(s.length-2) == '=' ? 'AA' : 'A') : "");
var r = [];
s = s.substr(0, s.length - p.length) + p;
// increment over the length of this encrypted string, four characters at a time
for (var c = 0; c < s.length; c += 4) {
// each of these four characters represents a 6-bit index in the base64 characters list
// which, when concatenated, will give the 24-bit number for the original 3 characters
var n = (base64inv[s.charAt(c)] << 18) + (base64inv[s.charAt(c+1)] << 12) +
(base64inv[s.charAt(c+2)] << 6) + base64inv[s.charAt(c+3)];
// split the 24-bit number into the original three 8-bit (ASCII) characters
r.push((n >>> 16) & 255);
r.push((n >>> 8) & 255);
r.push(n & 255);
}
// remove any zero pad that was added to make this a multiple of 24 bits
return r;
}
What's the function of those "<<<" and ">>>" characters.
Or is there a function like this for Python?
Who cares. Python has easier ways of doing the same.
[ord(c) for c in '6gAAAOsAAADsAAAACAEAAAkBAAAKAQAAJgEAACcBAAAoAQAA'.decode('base64')]
In Python I expected you'd just use the base64 module...
... but in response to your question about << and >>>:
<< is the left-shift operator; the result is the first operand shifted left by the second operand number of bits; for example 5 << 2 is 20, as 5 is 101 in binary, and 20 is 10100.
>>> is the non-sign-extended right-shift operator; the result is the first operand shifted
right by the second operand number of bits... with the leftmost bit always being filled with a 0.
Why not just:
from binascii import a2b_base64, b2a_base64
encoded_data = b2a_base64(some_string)
decoded_string = a2b_base64(encoded_data)
def base64_decode_array(string):
return [ord(c) for c in a2b_base64(string)]
Just for fun/completeness, I'll translate the javascript more literally: :)
# No particular reason to make a list of chars here instead of a string.
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
lookup = dict((c, i) for (i, c) in enumerate(base64chars))
def base64_decode_array(s):
# Filter out meaningless chars, especially newlines. No need for a regex.
s = ''.join(c for c in s if c in base64chars + '=')
# replace any incoming padding with a zero pad (the 'A' character is zero)
# Their way:
# p = ('AA' if s[-2] == '=' else 'A') if s[-1] == '=' else ''
# s = s[:len(s) - len(p)] + p
# My way (allows for more padding than that;
# '=' will only appear at the end anyway
s = s.replace('=', 'A')
r = []
# Iterate over the string in blocks of 4 chars - an ugly hack
# though we are preserving the original code's assumption that the text length
# is a multiple of 4 (that's what the '=' padding is for) ;)
for a, b, c, d in zip(*([iter(s)] * 4)):
# Translate each letter in the quad into a 6-bit value and bit-shift them
# together into a 24-bit value
n = (lookup[a] << 18) + (lookup[b] << 12) + (lookup[c] << 6) + lookup[d]
# split the 24-bit number into the original three 8-bit (ASCII) characters
r += [(n >> 16) & 0xFF), (n >> 8) & 0xFF), (n & 0xFF)]
return r
Related
Random one guys but I have has the misfortune of picking up and old legacy project for our systems queuing process and right now I am trying to piece together all the parts of it with no documentation - yes I said it NO DOCUMENTATION!
The one part I am really struggling with is this very ugly piece of javascript - I can see it's in an interval that keeps submitting a form in an interval every 400ms but it's all the insanity in the middle i am trying to work out.
(function(){
var a = function() {try{return !!window.addEventListener} catch(e) {return !1} },
b = function(b, c) {a() ? document.addEventListener("DOMContentLoaded", b, c) : document.attachEvent("onreadystatechange", b)};
b(function(){
var a = document.getElementById('cf-content');a.style.display = 'block';
setTimeout(function(){
var s,t,o,p,b,r,e,a,k,i,n,g,f, OBQXEnQ={"GMuEaNBC":+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))/+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+[])+(!+[]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]))};
g = String.fromCharCode;
o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
e = function(s) {
s += "==".slice(2 - (s.length & 3));
var bm, r = "", r1, r2, i = 0;
for (; i < s.length;) {
bm = o.indexOf(s.charAt(i++)) << 18 | o.indexOf(s.charAt(i++)) << 12
| (r1 = o.indexOf(s.charAt(i++))) << 6 | (r2 = o.indexOf(s.charAt(i++)));
r += r1 === 64 ? g(bm >> 16 & 255)
: r2 === 64 ? g(bm >> 16 & 255, bm >> 8 & 255)
: g(bm >> 16 & 255, bm >> 8 & 255, bm & 255);
}
return r;
};
t = document.createElement('div');
t.innerHTML="<a href='/'>x</a>";
t = t.firstChild.href;r = t.match(/https?:\/\//)[0];
t = t.substr(r.length); t = t.substr(0,t.length-1);
a = document.getElementById('jschl-answer');
f = document.getElementById('challenge-form');
;OBQXEnQ.GMuEaNBC+=+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(+!![]))/+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![])+(!+[]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![])+(!+[]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]));OBQXEnQ.GMuEaNBC-=+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))/+((+!![]+[])+(!+[]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]));OBQXEnQ.GMuEaNBC+=+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))/+((!+[]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]));OBQXEnQ.GMuEaNBC+=+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))/+((!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(+[])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]));a.value = (+OBQXEnQ.GMuEaNBC + t.length).toFixed(10); '; 121'
f.action += location.hash;
f.submit();
}, 4000);
}, false);
})();
Here is the markup
<form id="challenge-form" action="/Queue.aspx?__cf_chl_jschl_tk__=5f04d92efb1edb011edabc24cda3a235e06eb8ba-1581158560-0-AW-KwafTO7e0NxbCGPpzLlWrAU7w5hIso3jE7mgZFhCOvFb1g3xqglnwGhj6WL-2y_ECUZbobHbvPBykf59dve4xLS5aozksjkZkH12e8LOF1svbylQRNURkKmiILeAOhzeKXmzSH4ipu1OhgrKsjNfLgvcXIWz4a24GCSxxjNZKnLmsKLI3pPcN6SxeZASqynHvvZVf1n6Xa297FqIEu2a44P0_ztTkpIJodgatQyaXHrI4zYudSNdD_OGEmgCpyhuyHLjx8un4ILE2lcKwecKmWx2UZlzttaeQgsqJP3vd" method="POST" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="r" value="10a1cf729542cb5335935dbd86df47dfd6e6c413-1581158560-0-AbUplhHDvPuYV2B2BYVsWPZBU73o1fTlVXNJ/9uyPNG3D37ODbaeVdeHe5X51WlC6rAwkqXWDPrLJUyVCBDMU+rvLP38yZycbr3c95pZiUAa1NGWDB8ebbDB2Rcyanw5UKxYCgSCMGtxNlypoWJprK4p2RNjI5fG/9r+7nY7es28+MQC2morY38wCjTpKbY0SREp2iCToPB0uq8nlQwkHTK8jjuNYK4ZK+zYKVffgT+U6s62z8sglX1YA83iSzCWgM3piWdTvtz6TKddEuHMmY6RsOcaog8DuuO5+RqT0Re9qaGUO9x/pCf6N4ho5Ms1byBnPYtzD1gnnlfKjtD29FEGcsz1U1x4aRe8D6SqvzTb/IEudytoLLWpL4Q9oSKv4t8DdwZs6I5w5LMBcltUOjm69ptN+qFg/m+0hzFzHXAOaLcu1UZU725QQofIPQw21ofFsDihHXYHiuSEZq1jZMAcOKtaq8pY4fyzxyccV6qvfz4p1U3RuWnplKt6OP33dquly4DlJOamOuAnrPz3oWOQLJ5tDz95mg8GdbzvX088pe1nh9dp1YTDup82zIv3Gebme2/pzPCKjcCxBOOJHEK1H0i5qZoNi6WROohbvPc0kGwxyJWsGD1sXY2QpAfw0Mt2IXujShOOtD94JY4Yc7cLx4H4YPbqKh+ouwf9FRWH6dWTz6hnIMmNtbduNrgDxfl0rlWSyyeIOzty9HXg4+K9mvw4E5irwxdXJ2mDfHsqbbiGvGlwkcq1bAioSGYh3sL3fqenRkVEdJIGKE29wg93v7ZgeD+lIaFmF6Zy0nv1MSY8KVkZrERoFSGlJJgbTG3rkHagIKa72rs4h0d07wkJNIqkKwrJtS8txO+KVpyalCbVrqhb1yocmaFysoV5P1IFPTNrzocZelCkqMMq4Mquxq0TpIwEWvxfMN6JwXuM+7hrp7rD7hJzCDqJUiitA3TIUybw6FSie/Bwdq3fPHhnwg8dpVn372hcK/l9UPcyR+b+TReMy6HxO+/qPiNiYpQ/vuYjTs5efIeJ4hULJl2JRNV6LkPAf2Ees4KvBBVp2FjBubxjYmfORygZIjCQUCP2WcgXD34zy4w8kwngxsKiQ8UhHsiehvAl//5J1tA5H6Me9RuReJ8kWmelnFP+mrV4RnMpjmFifmRY9pwYQb1AIkl7VGsi5eR6Vmeq2Bb/iRhyFxIIpxzHJV9GF/rrO37/vjlTFxNUQ72CTS38jtUBaQivCFx2+qb/kfI5nW4DP3LOTUz9D/zJGmWYHKkz3G2jX/UWDWm2CzbtfsLLfzercuWl3hPqkdwqg/QZz9G05Qayf+jKCC+mWYuSNL8MHXxZereb6jPMyAu8n9jtVjXAxgtGGZMuIqXK+HOCMMMfQL4zxuUBe4Z6lJ45XiL0Hn0fX9JPY5ahi0zzX7ZSLSL3E2iiDcHbFxvByBYNNh1uTaxKoJyxVCrYZFBbpUkriI01N5u//u3nc5RYcgTsbsuC/31cDqmTO0KNkbN0/BYN9gG0qP4q2Hf0CaIGgw/Ip7QwzmF491opP8iIysH8kEp4rMSjeL6XIVLjhGN9dXfWcklq9G9A0iaIj2b2O1ra0y6nCauN+8DTWPRbz4pmDUryfDkG35/kk8wzqG5Yp5+TTeX9+4MJGMm5wz5fa3K8vi7sn4wdneroVB2TIb6evQZ//eSWFgEw67MFOW86+ROj"></input>
<input type="hidden" name="jschl_vc" value="d308f58453fdc399f02de1819459f64d"/>
<input type="hidden" name="pass" value="1581158564.634-jWe4nK3hOC"/>
<input type="hidden" id="jschl-answer" name="jschl_answer"/>
Let's see how we can make sense of this code, topic by topic.
The bracket-obfuscated expressions.
These could potentially call functions, so let's see exactly what they do. They always appear as numerator or denominator in a single division. So I list here all the used numerator/denominators:
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+[])+(!+[]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![])+(!+[]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![])+(!+[]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))
+((+!![]+[])+(!+[]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![])+(+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(+[])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]))
+((!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![])+(+[])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]))
These expressions work with only a few different components:
!![]
!+[]
(+[])
[]
!![] and !+[] evaluate to true, and as they all appear as operand of an addition or unary plus, they are coerced to 1. Replacing that, gives:
+((1+1+1+1+1+1+1+[])+(1+1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(+[])+(+[])+(1+1+1)+(1+1+1+1)+(1+1+1)+(1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+1+[])+(+[])+(1+1+1+1)+(+[])+(1+1+1+1)+(+[])+(1+1+1+1+1+1)+(+[])+(1+1+1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+[])+(1+1+1)+(1+1+1+1+1+1+1+1)+(+[])+(1+1+1+1)+(+1)+(1+1+1+1+1+1)+(1+1+1+1)+(+1))
+((1+1+1+1+1+1+1+1+1+[])+(1+1+1+1)+(1+1)+(1+1+1)+(1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(1+1+1+1+1)+(1+1)+(1+1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+[])+(1+1+1)+(1+1+1+1+1+1+1+1)+(+[])+(1+1+1+1)+(+1)+(1+1+1+1+1+1)+(1+1+1+1)+(1+1+1+1+1+1+1))
+((+1+[])+(1+1)+(1+1+1+1+1+1+1)+(+1)+(1+1+1+1+1+1+1+1+1)+(+1)+(+[])+(1+1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+[])+(1+1+1)+(1+1+1+1+1+1+1+1)+(+[])+(1+1+1+1)+(+1)+(1+1+1+1+1+1)+(1+1+1+1)+(1+1+1+1+1+1+1))
+((1+1+1+1+1+1+[])+(1+1)+(1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(1+1+1+1+1+1+1+1)+(1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(1+1+1+1+1+1+1+1)+(1+1+1+1+1))
+((1+1+1+1+1+1+1+[])+(1+1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(+[])+(+[])+(1+1+1)+(1+1+1+1)+(1+1+1)+(1+1+1+1+1+1+1))
+((1+1+1+1+[])+(1+1+1+1)+(1+1+1+1)+(1+1+1+1+1+1)+(1+1+1+1+1+1)+(+[])+(+[])+(1+1+1+1+1+1+1)+(1+1+1+1))
The (+[]) components evaluate to 0, and the remaining +[] trigger a string concatenation, so that corresponds to +"". The result:
+((1+1+1+1+1+1+1+"")+(1+1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1)+0+0+(1+1+1)+(1+1+1+1)+(1+1+1)+(1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+1+"")+0+(1+1+1+1)+0+(1+1+1+1)+0+(1+1+1+1+1+1)+0+(1+1+1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+"")+(1+1+1)+(1+1+1+1+1+1+1+1)+0+(1+1+1+1)+(+1)+(1+1+1+1+1+1)+(1+1+1+1)+(+1))
+((1+1+1+1+1+1+1+1+1+"")+(1+1+1+1)+(1+1)+(1+1+1)+(1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(1+1+1+1+1)+(1+1)+(1+1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+"")+(1+1+1)+(1+1+1+1+1+1+1+1)+0+(1+1+1+1)+(+1)+(1+1+1+1+1+1)+(1+1+1+1)+(1+1+1+1+1+1+1))
+((+1+"")+(1+1)+(1+1+1+1+1+1+1)+(+1)+(1+1+1+1+1+1+1+1+1)+(+1)+0+(1+1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1+1+1))
+((1+1+1+1+1+1+1+1+"")+(1+1+1)+(1+1+1+1+1+1+1+1)+0+(1+1+1+1)+(+1)+(1+1+1+1+1+1)+(1+1+1+1)+(1+1+1+1+1+1+1))
+((1+1+1+1+1+1+"")+(1+1)+(1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(1+1+1+1+1+1+1+1)+(1+1+1+1+1+1)+(1+1+1+1+1+1+1)+(1+1+1+1+1+1+1+1)+(1+1+1+1+1))
+((1+1+1+1+1+1+1+"")+(1+1+1+1+1+1+1+1+1)+(1+1+1+1+1+1+1)+0+0+(1+1+1)+(1+1+1+1)+(1+1+1)+(1+1+1+1+1+1+1))
+((1+1+1+1+"")+(1+1+1+1)+(1+1+1+1)+(1+1+1+1+1+1)+(1+1+1+1+1+1)+0+0+(1+1+1+1+1+1+1)+(1+1+1+1))
We can now calculate replace those 1+1+...+1 by what they evaluate to (don't deal with parentheses yet):
+((7+"")+(9)+(7)+0+0+(3)+(4)+(3)+(7))
+((9+"")+0+(4)+0+(4)+0+(6)+0+(9))
+((8+"")+(3)+(8)+0+(4)+(+1)+(6)+(4)+(+1))
+((9+"")+(4)+(2)+(3)+(8)+(7)+(5)+(2)+(8))
+((8+"")+(3)+(8)+0+(4)+(+1)+(6)+(4)+(7))
+((+1+"")+(2)+(7)+(+1)+(9)+(+1)+0+(9)+(9))
+((8+"")+(3)+(8)+0+(4)+(+1)+(6)+(4)+(7))
+((6+"")+(2)+(6)+(7)+(8)+(6)+(7)+(8)+(5))
+((7+"")+(9)+(7)+0+0+(3)+(4)+(3)+(7))
+((4+"")+(4)+(4)+(6)+(6)+0+0+(7)+(4))
The remaining, inner unary plus operators, in (+1, can be removed and all except the outer parentheses can be removed as well:
+(7+""+9+7+0+0+3+4+3+7)
+(9+""+0+4+0+4+0+6+0+9)
+(8+""+3+8+0+4+1+6+4+1)
+(9+""+4+2+3+8+7+5+2+8)
+(8+""+3+8+0+4+1+6+4+7)
+(1+""+2+7+1+9+1+0+9+9)
+(8+""+3+8+0+4+1+6+4+7)
+(6+""+2+6+7+8+6+7+8+5)
+(7+""+9+7+0+0+3+4+3+7)
+(4+""+4+4+6+6+0+0+7+4)
All the inner plus operators are now string concatenations, so this evaluates to:
+("797003437")
+("904040609")
+("838041641")
+("942387528")
+("838041647")
+("127191099")
+("838041647")
+("626786785")
+("797003437")
+("444660074")
The remaining unary operator performs the final evaluation:
797003437
904040609
838041641
942387528
838041647
127191099
838041647
626786785
797003437
444660074
You could have evaluated the expressions as they were in the dev console, but this way you are absolutely sure there are no hidden side effects or dependencies that could go unnoticed.
The value of OBQXEnQ.GMuEaNBC
With the above expressions reduced to their numerical values, we get this:
var OBQXEnQ = {
"GMuEaNBC": 797003437 / 904040609;
};
OBQXEnQ.GMuEaNBC += 838041641 / 942387528;
OBQXEnQ.GMuEaNBC -= 838041647 / 127191099;
OBQXEnQ.GMuEaNBC += 838041647 / 626786785;
OBQXEnQ.GMuEaNBC += 797003437 / 444660074;
... so that can be simplified to:
var OBQXEnQ.GMuEaNBC = 797003437 / 904040609 + 838041641 / 942387528 - 838041647 / 127191099 + 838041647 / 626786785 + 797003437 / 444660074;
... which is:
var OBQXEnQ.GMuEaNBC = -1.6885301087751048;
The variables s,t,o,p,b,r,e,a,k,i,n,g
We ignore the hint :-)
Now that we have decoded the obfuscated expressions, it becomes clear that e is never called. So we can remove that function from the code.
The variables o and g were only used in e, so they can also be removed from the code.
Of the variables s,t,o,p,b,r,e,a,k,i,n,g, we only need to keep (for the moment) t, r, and a. The others are not used.
The loose expression '; 121' plays no role either.
The value of t.length
There is this part in the code:
t = document.createElement('div');
t.innerHTML="<a href='/'>x</a>";
t = t.firstChild.href;
r = t.match(/https?:\/\//)[0];
t = t.substr(r.length);
t = t.substr(0,t.length-1);
It is a complicated way to do t = location.host. The only use of t is its length in a later expression.
So t.length becomes location.host.length. But it is clear that it depends on where this javascript is running. In comments below you mention the web address of this page, and so t evaluates to "queue-tickets.liverpoolfc.com", and thus t.length is 29.
With this simplication we no longer need variables t and r.
The value assigned to a.value
We have reduced the assignment to a.value to:
a.value = (-1.6885301087751048 + location.host.length).toFixed(10);
As stated before location.host.length is 29 in your case. Therefore the above is equivalent to:
a.value = "27.3114698912";
functions for listening to the DOMContentLoaded event
The two functions a and b are intended to execute code when the document is loaded, with backwards compatibility for pre-IE9.
The parameter variable c is getting value false in the actual call of b, but that is the default for addEventListener; we can omit that.
So ignoring the IE8 compatibility concern, the call of b is equivalent to:
document.addEventListener("DOMContentLoaded", callback);
So we can skip the definition of those two functions as well. And since those were the only variables defined directly in the outer IIFE scope, we can leave that IIFE out as well.
The result:
The above reductions lead to this code:
document.addEventListener("DOMContentLoaded", function () {
document.getElementById('cf-content').style.display = 'block';
setTimeout(function () {
document.getElementById('jschl-answer').value = "27.3114698912";
var f = document.getElementById('challenge-form');
f.action += location.hash;
f.submit();
}, 4000);
});
Client / Server
This client code submits the form to the server page Queue.aspx. It passes information via the URL and via a POST payload.
The URL has two bits of information:
__cf_chl_jschl_tk__=: a hardcoded value
#: a so-called "hash", which is just a repetition of whatever was in the current URL's hash (following the # symbol).
The POST payload has this:
r=: a hardcoded value
jschl_vc=: a hardcoded value
pass=: a hardcoded value
jschl-answer=: the value which the JavaScript code provides, i.e. "27.3114698912" when run on your live site.
This HTTP-request is submitted to Queue.aspx, 4 seconds after the current page had loaded.
As your question provides no information on what Queue.aspx does with that information, my analysis ends here.
If you have control over Queue.aspx, then all this analysis is really irrelevant, as you could simply put some logging in the ASP (.NET) code of Queue.aspx and see:
what exactly is in the POST variable jschl-answer which the client submits, and
what is sent back to the client: which URL redirection (if any) and which content.
Addendum
When trying the live URL myself, I note that it writes a cookie, so that the next time you visit that same URL, the redirection is immediate.
The first delay of 4 seconds (with setTimeout) seems to only serve as a protection against bulk attacks on the web site (DOS attacks). This is however a very simple measure and can be easily bypassed.
const g = String.fromCharCode;
const o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
const e = function(s) {
s += "==".slice(2 - (s.length & 3));
var bm, r = "", r1, r2, i = 0;
for (; i < s.length;) {
bm = o.indexOf(s.charAt(i++)) << 18 | o.indexOf(s.charAt(i++)) << 12
| (r1 = o.indexOf(s.charAt(i++))) << 6 | (r2 = o.indexOf(s.charAt(i++)));
r += r1 === 64 ? g(bm >> 16 & 255)
: r2 === 64 ? g(bm >> 16 & 255, bm >> 8 & 255)
: g(bm >> 16 & 255, bm >> 8 & 255, bm & 255);
}
return r;
};
you can kind of tell that it has something to do with base64, especially when given all valid characters in base64 encoded strings and forcing padding (==) based on the length of the input.
effectively, its just base64 decoding:
const g = String.fromCharCode;
const o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
const e = function(s) {
s += "==".slice(2 - (s.length & 3));
var bm, r = "", r1, r2, i = 0;
for (; i < s.length;) {
bm = o.indexOf(s.charAt(i++)) << 18 | o.indexOf(s.charAt(i++)) << 12
| (r1 = o.indexOf(s.charAt(i++))) << 6 | (r2 = o.indexOf(s.charAt(i++)));
r += r1 === 64 ? g(bm >> 16 & 255)
: r2 === 64 ? g(bm >> 16 & 255, bm >> 8 & 255)
: g(bm >> 16 & 255, bm >> 8 & 255, bm & 255);
}
return r;
};
const input = 'some input';
const base64 = window.btoa(input); // Buffer.from(input).toString('base64');
console.log(e(input))
console.log(base64)
console.log(e(base64))
It doesnt create an interval, but a single timeout of 400ms. Probably to "ensure" all of the dom is loaded. I suggest you'd skip this implementation and write your own based on the requirements of your application.
So, basically I am doing some JS exercises and I understand this code, just cant figure out whats the math behind obtaining characters Ascii code in String.fromCharCode function?
why do we decrement by 18?
Have the function LetterChanges(str) take the str parameter being passed and modify it using the following algorithm. Replace every letter in the string with the letter following it in the alphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
function LetterChanges(str) {
str = str.trim().toLowerCase();
var len = str.length;
var newStr = '';
for (var i = 0; i < len; i++) {
if (/[a-ce-gi-mo-su-y]/.test(str[i])) {
newStr += String.fromCharCode(((str[i].charCodeAt(0) - 18) % 26) +
97)
}
else if (/[zdhnt]/.test(str[i])) {
newStr += String.fromCharCode(((str[i].charCodeAt(0) - 18) % 26) +
65);
}
else {
newStr += str[i];
}
}
return newStr;
}
LetterChanges(readline());
Fact: charCode for 'a' is 97, and (97 - 18) % 26 == 1
Take 'b' for example, (98 - 18) % 26 == 2, so after change, its charCode equals 97 + 2 == 99, becomes 'c'. This rule applies to all 'a-z'.
Now you should see the pattern.
Quiz: what if you want to change uppercase letters, what would you pick as the "magic number" for this case?
About ASCII
Well, as you know, computers don't store characters as 'a', 'b', 'z' or '.', they only accept binary bits (0 or 1). These binary bits can be used to form integers and numbers, but not strings and characters.
So how does the computer store characters? That's where ASCII (American Standard Code for Information Interchange) comes in.
So the idea is that each character needs to be stored as a number, and ASCII code is then the standardization for what number corresponds to what character and vice versa.
So to answer your first question: String.fromCharCode(x) is just returning you the character in the standardized ASCII table corresponding to the number x. For eg, String.fromCharCode(65) will return you 'A' because the ASCII code for 'A' is standardized by the standard as 65.
Why -18
It's a clever (but confusing) hack to force all the lowercase letters to the character following it.
Because str has been made to be lowercase by the line str = str.trim().toLowerCase();, str[i] will now only contain values from 97 ('a') to 97+25 = 122 ('z').
Now 18 = 122 (mod 26) or 122%26.
This is necessary to accommodate for the fact that 'z' needs to go to 'a', and since we only have 26 characters from 'a' to 'z' that we need to "wrap around" (modulus/%)
Note that:
(97('a')-18)%26 = 1
(98('b')-18)%26 = 2
...
(122('z')-18)%26 = 0
So when you add 97 ('a') to each of the numbers you get a function mapping of 'a'->'b', 'b'->'c', ... , 'z'->'a'
I have an array of combinations from 5 characters (order within a combination plays no role):
AB, ABDE, CDE, C, BE ...
On its basis I need to validate the input from user. The entered combination of characters should be contained in one of the combinations of the array.
If user enters "ADE" or "CE" the result should be yes, if e.g. "BCE" - no.
In a trivial case, when entered combination simply matches the one in array, I can use .inArray. If entered combination consists of neighbors, I can do .indexOf. How to be in the case above?
One of the solutions would be to extend the initial array by including all possible "child" combinations. Is there an alternative?
The first thing I could think of is grep'ping the array with a regex match.
var haystack = ["BCED","DBCE","CEB","ECBA","CB","BDCA"];
var needle = "CBE";
var re = new RegExp("(?=.*" + needle.split('').join(")(?=.*") + ").{" + needle.length+"}");
console.log(re);
console.log($.grep(haystack, function(str){
return str.match(re,"g");
}));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'll expand on the comment I've made to the quesion above: If you have a small number of fixed set elements, you can represent the sets as binary masks. So say you have the original sets as strings:
var sset = ["AB", "ABDE", "CDE", "C", "BE"];
Create a dictionary of possible elements and bits. The bits are powers of two, which can be created by bit-shifting: 1 << n is bit n:
dict = {
A: (1 << 0),
B: (1 << 1),
C: (1 << 2),
D: (1 << 3),
E: (1 << 4),
};
That dictionary can then be used to create the bitmask:
function bitmask(s, d) {
let res = 0;
for (let i = 0; i < s.length; i++) {
res |= d[s[i]]
}
return res;
}
Create a companion array to the sets that contains the masks:
var mset = sset.map(function(x) { return bitmask(x, dict); });
If you want to check an input, cnvert it to a mask first and then run the checks. A set s contains all bits of an input x if (s & x) == x:
var s = "ADE";
var m = bitmask(s, dict);
for (let i = 0; i < mset.length; i++) {
console.log(sset[i], s, (mset[i] & m) == m);
}
You can use this strategy for several conditions:
• (a & b) == b — all elements of b are contained in a;
• (a & b) == 0 — a and b have no common elements;
• (a & b) != 0 — at least one elements of b is in a;
• a == b — the sets a and b are identical.
In set parlance a & b is the intersection, a | b is the union and a ^ b is the symmetric difference of a and b.
As far as I know, jQuery is a library written in Javascript, so all bit-wise operators should be available.
How do you convert following
var data = new Uint16Array([131, 220]);
to integer? Expected value is somewhere around 970
Basically you need to reduce the values by multiplying with 28 and cut off the first bit.
(This is not a general converting, but rather for this special purpose.)
var data = new Uint16Array([131, 220]),
value = [].reduce.call(data, function (r, a) {
return (r << 8) + a;
}, 0) & ((1 << 15) - 1);
console.log(value);
I have JavaScript code that retrieves numerical vectors from a web-service. The original data is an array of doubles that is converted to a byte array and then base64 encoded. I decode from base64 in JavaScript, but then I don't know how to transform the resulting bytes into an array of numbers.
This was the only way I could think of off the top of my head to do it.
function bytesToDouble(str,start) {
start *= 8;
var data = [str.charCodeAt(start+7),
str.charCodeAt(start+6),
str.charCodeAt(start+5),
str.charCodeAt(start+4),
str.charCodeAt(start+3),
str.charCodeAt(start+2),
str.charCodeAt(start+1),
str.charCodeAt(start+0)];
var sign = (data[0] & 1<<7)>>7;
var exponent = (((data[0] & 127) << 4) | (data[1]&(15<<4))>>4);
if(exponent == 0) return 0;
if(exponent == 0x7ff) return (sign) ? Number.POSITIVE_INFINITY : Number.NEGATIVE_INFINITY;
var mul = Math.pow(2,exponent - 1023 - 52);
var mantissa = data[7]+
data[6]*Math.pow(2,8*1)+
data[5]*Math.pow(2,8*2)+
data[4]*Math.pow(2,8*3)+
data[3]*Math.pow(2,8*4)+
data[2]*Math.pow(2,8*5)+
(data[1]&15)*Math.pow(2,8*6)+
Math.pow(2,52);
return Math.pow(-1,sign)*mantissa*mul;
}
var data = atob("AAAAAABsskAAAAAAAPmxQAAAAAAAKrF");
alert(bytesToDouble(data,0)); // 4716.0
alert(bytesToDouble(data,1)); // 4601.0
This should give you a push in the right direction, though it took me a while to remember how to deal with doubles.
One big caveats to note though:
This relies on the atob to do the base64 decoding, which is not supported everywhere, and aside from that probably isn't a great idea anyway. What you really want to do is unroll the base64 encoded string to an array of numbers (bytes would be the easiest to work with although not the most efficient thing on the planet). The reason is that when atob does its magic, it returns a string, which is far from ideal. Depending on the encoding the code points it maps to (especially for code points between 128 and 255) the resulting .charCodeAt() may not return what you expect.
And there may be some accuracy issues, because after all I am using a double to calculate a double, but I think it might be okay.
Base64 is fairly trivial to work with, so you should be able to figure that part out.
If you did switch to an array (rather than the str string now), then you would obviously drop the .charCodeAt() reference and just get the indices you want directly.
There is a functioning fiddle here
I assume we have used this function in web service (c#) to encode the double array data as string:
//Input: [552.4, 539.8]
//Output: IOz0gCAsscA=
private string ConvertToSerializableString(double[] input)
{
byte[] data = new byte[input.Length * 4];
for (int i = 0; i < input.Length; i++)
{
int source = (int)(input[i] * 1E6);
int dataIndex = i * 4;
data[dataIndex] = (byte)((source >> 24) & 0xFF);
data[dataIndex + 1] = (byte)((source >> 16) & 0xFF);
data[dataIndex + 2] = (byte)((source >> 8) & 0xFF);
data[dataIndex + 3] = (byte)(source & 0xFF);
}
return Convert.ToBase64String(data);
}
Then we can use the following client script (javascript) to decode it:
var base64EncodedDoubleArrayData = "IOz0gCAsscA=";
var byteData = window.atob(base64EncodedDoubleArrayData);
var doubleArray = [];
for (var iColumn = 0; iColumn < byteData.length; iColumn = iColumn + 4)
{
var item = (byteData.charCodeAt(iColumn) << 24) + (byteData.charCodeAt(iColumn + 1) << 16) + (byteData.charCodeAt(iColumn + 2) << 8) + byteData.charCodeAt(iColumn + 3);
var doubleResult = parseFloat(item/1e6);
doubleArray.push(doubleResult);
}
//it should return something like doubleArray = [552.4, 539.8]