Greasy Fork is available in English.
Warns on clicking links and arriving into sites which uses PunyCode.
- // ==UserScript==
- // @name PunyCode Protection
- // @namespace PunyCode Protection
- // @version 1.0.4
- // @description Warns on clicking links and arriving into sites which uses PunyCode.
- // @author jcunews
- // @match *://*/*
- // @grant none
- // @run-at document-start
- // ==/UserScript==
- //URL to redirect when user rejected the prompt upon arriving to a possibly fake site.
- var redirectURL = "about:blank";
- //---------------------------punycode.js start
- //source: https://github.com/bestiejs/punycode.js/blob/master/punycode.js
- //modified to be compatible with ES5.1 and client-side scripting, and to remove comments.
- var punycode = (function() {
- var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
- var base = 36;
- var tMin = 1;
- var tMax = 26;
- var skew = 38;
- var damp = 700;
- var initialBias = 72;
- var initialN = 128; // 0x80
- var delimiter = '-'; // '\x2D'
- var regexPunycode = /^xn--/;
- var regexNonASCII = /[^\0-\x7E]/; // non-ASCII chars
- var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
- var errors = {
- 'overflow': 'Overflow: input needs wider integers to process',
- 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
- 'invalid-input': 'Invalid input'
- };
- var baseMinusTMin = base - tMin;
- var floor = Math.floor;
- var stringFromCharCode = String.fromCharCode;
- function error(type) {
- throw new RangeError(errors[type]);
- }
- function map(array, fn) {
- var r###lt = [];
- var length = array.length;
- while (length--) {
- r###lt[length] = fn(array[length]);
- }
- return r###lt;
- }
- function mapDomain(string, fn) {
- var parts = string.split('@');
- var r###lt = '';
- if (parts.length > 1) {
- r###lt = parts[0] + '@';
- string = parts[1];
- }
- string = string.replace(regexSeparators, '\x2E');
- var labels = string.split('.');
- var encoded = map(labels, fn).join('.');
- return r###lt + encoded;
- }
- function ucs2decode(string) {
- var output = [];
- var counter = 0;
- var length = string.length;
- while (counter < length) {
- var value = string.charCodeAt(counter++);
- if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
- var extra = string.charCodeAt(counter++);
- if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
- output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
- } else {
- output.push(value);
- counter--;
- }
- } else {
- output.push(value);
- }
- }
- return output;
- }
- //var ucs2encode = array => String.fromCodePoint(...array);
- var ucs2encode = function(array) {
- return String.fromCodePoint.apply(String, array);
- };
- var basicToDigit = function(codePoint) {
- if (codePoint - 0x30 < 0x0A) {
- return codePoint - 0x16;
- }
- if (codePoint - 0x41 < 0x1A) {
- return codePoint - 0x41;
- }
- if (codePoint - 0x61 < 0x1A) {
- return codePoint - 0x61;
- }
- return base;
- };
- var digitToBasic = function(digit, flag) {
- return digit + 22 + 75 * (digit < 26) - ((flag !== 0) << 5);
- };
- var adapt = function(delta, numPoints, firstTime) {
- var k = 0;
- delta = firstTime ? floor(delta / damp) : delta >> 1;
- delta += floor(delta / numPoints);
- for (; delta > baseMinusTMin * tMax >> 1; k += base) {
- delta = floor(delta / baseMinusTMin);
- }
- return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
- };
- var decode = function(input) {
- var output = [];
- var inputLength = input.length;
- var i = 0;
- var n = initialN;
- var bias = initialBias;
- var basic = input.lastIndexOf(delimiter);
- if (basic < 0) {
- basic = 0;
- }
- for (var j = 0; j < basic; ++j) {
- if (input.charCodeAt(j) >= 0x80) {
- error('not-basic');
- }
- output.push(input.charCodeAt(j));
- }
- for (var index = basic > 0 ? basic + 1 : 0; index < inputLength;) {
- var oldi = i;
- for (var w = 1, k = base; ; k += base) {
- if (index >= inputLength) {
- error('invalid-input');
- }
- var digit = basicToDigit(input.charCodeAt(index++));
- if (digit >= base || digit > floor((maxInt - i) / w)) {
- error('overflow');
- }
- i += digit * w;
- var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
- if (digit < t) {
- break;
- }
- var baseMinusT = base - t;
- if (w > floor(maxInt / baseMinusT)) {
- error('overflow');
- }
- w *= baseMinusT;
- }
- var out = output.length + 1;
- bias = adapt(i - oldi, out, oldi === 0);
- if (floor(i / out) > maxInt - n) {
- error('overflow');
- }
- n += floor(i / out);
- i %= out;
- output.splice(i++, 0, n);
- }
- // return String.fromCodePoint(...output);
- return String.fromCodePoint.apply(String, output);
- };
- var encode = function(input) {
- var output = [];
- input = ucs2decode(input);
- var inputLength = input.length;
- var n = initialN;
- var delta = 0;
- var bias = initialBias;
- input.forEach(function(currentValue) {
- if (currentValue < 0x80) {
- output.push(stringFromCharCode(currentValue));
- }
- });
- var basicLength = output.length;
- var handled###ount = basicLength;
- if (basicLength) {
- output.push(delimiter);
- }
- while (handled###ount < inputLength) {
- var m = maxInt;
- input.forEach(function(currentValue) {
- if (currentValue >= n && currentValue < m) {
- m = currentValue;
- }
- });
- var handled###ountPlusOne = handled###ount + 1;
- if (m - n > floor((maxInt - delta) / handled###ountPlusOne)) {
- error('overflow');
- }
- delta += (m - n) * handled###ountPlusOne;
- n = m;
- input.forEach(function(currentValue) {
- if (currentValue < n && ++delta > maxInt) {
- error('overflow');
- }
- if (currentValue == n) {
- var q = delta;
- for (var k = base; ; k += base) {
- var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
- if (q < t) {
- break;
- }
- var qMinusT = q - t;
- var baseMinusT = base - t;
- output.push(
- stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
- );
- q = floor(qMinusT / baseMinusT);
- }
- output.push(stringFromCharCode(digitToBasic(q, 0)));
- bias = adapt(delta, handled###ountPlusOne, handled###ount == basicLength);
- delta = 0;
- ++handled###ount;
- }
- });
- ++delta;
- ++n;
- }
- return output.join('');
- };
- var toUnicode = function(input) {
- return mapDomain(input, function(string) {
- return regexPunycode.test(string) ? decode(string.slice(4).toLowerCase()) : string;
- });
- };
- var toASCII = function(input) {
- return mapDomain(input, function(string) {
- return regexNonASCII.test(string) ? 'xn--' + encode(string) : string;
- });
- };
- return {
- 'version': '2.1.0',
- 'ucs2': {
- 'decode': ucs2decode,
- 'encode': ucs2encode
- },
- 'decode': decode,
- 'encode': encode,
- 'toASCII': toASCII,
- 'toUnicode': toUnicode
- };
- })();
- //---------------------------punycode.js end
- var hostname;
- window.pc=punycode;
- function latinLike(s) {
- return punycode.ucs2.decode(s).some(function(code){
- return (
- //C1 Controls and Latin-1 Supplement; up to Cyrillic Supplement
- (code >= 0x0080) && (code <= 0x052f) ||
- //Cherokee
- (code >= 0x13a0) && (code <= 0x13ff) ||
- //Cyrillic Extended-C
- (code >= 0x1c80) && (code <= 0x1c8f) ||
- //Latin-2 supplement, Greek Extended
- (code >= 0x1d00) && (code <= 0x1eff) ||
- //Superscripts and Subscripts
- (code >= 0x2070) && (code <= 0x209f) ||
- //Letterlike Symbols
- (code >= 0x2100) && (code <= 0x214f) ||
- //Latin Extended-C, Coptic, Tifinagh
- (code >= 0x2c60) && (code <= 0x2d7f) ||
- //Cyrillic Extended-A
- (code >= 0x2de0) && (code <= 0x2dff) ||
- //Lisu
- (code >= 0xa4d0) && (code <= 0xa4ff) ||
- //Cyrillic Extended-B
- (code >= 0xa640) && (code <= 0xa69f) ||
- //Latin Extended-D
- (code >= 0xa720) && (code <= 0xa7ff) ||
- //Latin Extended-E, Cherokee Supplement
- (code >= 0xab30) && (code <= 0xabbf) ||
- //Halfwidth and Fullwidth Forms (letters only)
- (code >= 0xff00) && (code <= 0xff5a)
- );
- })
- }
- function checkHostName(ahostname, hn, suspicious) {
- suspicious = latinLike(ahostname);
- if (suspicious) {
- hn = punycode.toUnicode(ahostname);
- if (hn === ahostname) {
- hn = punycode.toASCII(ahostname);
- suspicious = hn !== ahostname;
- } else {
- hn = ahostname;
- suspicious = true;
- }
- hostname = hn;
- } else if (suspicious = ((hn = punycode.toUnicode(ahostname)) !== ahostname) && latinLike(hn)) hostname = ahostname;
- return suspicious;
- }
- //warn upon arriving to a possibly fake site
- if (checkHostName(location.hostname) &&
- !confirm("Warning! This website real domain name is:\n\n" + hostname + "\n\nDo you want to proceed?")) {
- location.href = redirectURL;
- }
- //warn on clicking a link pointing to a possibly fake site
- addEventListener("click", function(ev) {
- if (!ev.button && ev.target && (ev.target.tagName === "A") &&
- ev.target.hostname && (ev.target.hostname !== location.hostname)) {
- if (checkHostName(ev.target.hostname) &&
- !confirm("Warning! About to go to a web page whose real domain name is:\n\n" + hostname + "\n\nDo you want to proceed?")) {
- ev.preventDefault();
- if (ev.stopPropagation) ev.stopPropagation();
- if (ev.stopImmediatePropagation) ev.stopImmediatePropagation();
- return false;
- }
- }
- return true;
- }, true);
- //hook window.open()
- var _open = window.open;
- window._open = window.open;
- window.open = function(url) {
- if (checkHostName(url) &&
- !confirm("Warning! A script is about to open a web page whose real domain name is:\n\n" + hostname + "\n\nDo you want to proceed?")) {
- return null;
- }
- return _open.apply(window, arguments);
- };