Removed nscl cache directory from src.
This commit is contained in:
parent
9fad0842f7
commit
0d6c029484
|
@ -1,88 +0,0 @@
|
|||
var Permissions = (() => {
|
||||
'use strict';
|
||||
/**
|
||||
* This class models an extensible set of browser capabilities, to be assigned to a certain site,
|
||||
* possibly tied to a set of parent sites (contextual permissions).
|
||||
* Depends on Sites.js.
|
||||
*/
|
||||
class Permissions {
|
||||
/**
|
||||
* Creates a Permissions object
|
||||
* @param {Set/array} capabilities the capability enabled by this Permissions
|
||||
* @param {boolean} temp are these permissions marked as temporary (volatile?)
|
||||
* @param {Sites/array} contextual (optional) the parent sites which these permissions are tied to
|
||||
*/
|
||||
constructor(capabilities, temp = false, contextual = null) {
|
||||
this.capabilities = new Set(capabilities);
|
||||
this.temp = temp;
|
||||
this.contextual = contextual instanceof Sites ? contextual : new Sites(contextual);
|
||||
}
|
||||
|
||||
dry() {
|
||||
return {capabilities: [...this.capabilities], contextual: this.contextual.dry(), temp: this.temp};
|
||||
}
|
||||
|
||||
static hydrate(dry = {}, obj = null) {
|
||||
let capabilities = new Set(dry.capabilities);
|
||||
let contextual = Sites.hydrate(dry.contextual);
|
||||
let temp = dry.temp;
|
||||
return obj ? Object.assign(obj, {capabilities, temp, contextual, _tempTwin: undefined})
|
||||
: new Permissions(capabilities, temp, contextual);
|
||||
}
|
||||
|
||||
static typed(capability, type) {
|
||||
let [capName] = capability.split(":");
|
||||
return `${capName}:${type}`;
|
||||
}
|
||||
|
||||
allowing(capability) {
|
||||
return this.capabilities.has(capability);
|
||||
}
|
||||
|
||||
set(capability, enabled = true) {
|
||||
if (enabled) {
|
||||
this.capabilities.add(capability);
|
||||
} else {
|
||||
this.capabilities.delete(capability);
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
sameAs(otherPerms) {
|
||||
let otherCaps = new Set(otherPerms.capabilities);
|
||||
let theseCaps = this.capabilities;
|
||||
for (let c of theseCaps) {
|
||||
if (!otherCaps.delete(c)) return false;
|
||||
}
|
||||
for (let c of otherCaps) {
|
||||
if (!theseCaps.has(c)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
clone() {
|
||||
return new Permissions(this.capabilities, this.temp, this.contextual);
|
||||
}
|
||||
get tempTwin() {
|
||||
return this._tempTwin || (this._tempTwin = new Permissions(this.capabilities, true, this.contextual));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Permissions.ALL = ["script", "object", "media", "frame", "font", "webgl", "fetch", "ping", "other"];
|
||||
Permissions.IMMUTABLE = {
|
||||
UNTRUSTED: {
|
||||
"script": false,
|
||||
"object": false,
|
||||
"webgl": false,
|
||||
"fetch": false,
|
||||
"other": false,
|
||||
"ping": false,
|
||||
},
|
||||
TRUSTED: {
|
||||
"script": true,
|
||||
}
|
||||
};
|
||||
|
||||
Object.freeze(Permissions.ALL);
|
||||
|
||||
return Permissions;
|
||||
})();
|
|
@ -1,198 +0,0 @@
|
|||
var Policy = (() => {
|
||||
'use strict';
|
||||
|
||||
function defaultOptions() {
|
||||
return {
|
||||
sites:{
|
||||
trusted: [],
|
||||
untrusted: [],
|
||||
custom: {},
|
||||
},
|
||||
DEFAULT: new Permissions(["frame", "fetch", "other"]),
|
||||
TRUSTED: new Permissions(Permissions.ALL),
|
||||
UNTRUSTED: new Permissions(),
|
||||
enforced: true,
|
||||
autoAllowTop: false,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizePolicyOptions(dry) {
|
||||
let options = Object.assign({}, dry);
|
||||
for (let p of ["DEFAULT", "TRUSTED", "UNTRUSTED"]) {
|
||||
options[p] = dry[p] instanceof Permissions ? dry[p] : Permissions.hydrate(dry[p]);
|
||||
options[p].temp = false; // preserve immutability of presets persistence
|
||||
}
|
||||
if (typeof dry.sites === "object" && !(dry.sites instanceof Sites)) {
|
||||
let {trusted, untrusted, temp, custom} = dry.sites;
|
||||
let sites = Sites.hydrate(custom);
|
||||
for (let key of trusted) {
|
||||
sites.set(key, options.TRUSTED);
|
||||
}
|
||||
for (let key of untrusted) {
|
||||
sites.set(Sites.toggleSecureDomainKey(key, false), options.UNTRUSTED);
|
||||
}
|
||||
if (temp) {
|
||||
let tempPreset = options.TRUSTED.tempTwin;
|
||||
for (let key of temp) sites.set(key, tempPreset);
|
||||
}
|
||||
options.sites = sites;
|
||||
}
|
||||
enforceImmutable(options);
|
||||
return options;
|
||||
}
|
||||
|
||||
function enforceImmutable(policy) {
|
||||
for (let [preset, filter] of Object.entries(Permissions.IMMUTABLE)) {
|
||||
let presetCaps = policy[preset].capabilities;
|
||||
for (let [cap, value] of Object.entries(filter)) {
|
||||
if (value) presetCaps.add(cap);
|
||||
else presetCaps.delete(cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A browser-independent class representing all the restrictions to content
|
||||
* loading and script execution we want to apply globally and per-site,
|
||||
* providing methods to set, query and serialize these settings.
|
||||
* Depends on Permissions.js and Sites.js.
|
||||
*/
|
||||
class Policy {
|
||||
|
||||
constructor(options = defaultOptions()) {
|
||||
Object.assign(this, normalizePolicyOptions(options));
|
||||
}
|
||||
|
||||
static hydrate(dry, policyObj) {
|
||||
return policyObj ? Object.assign(policyObj, normalizePolicyOptions(dry))
|
||||
: new Policy(dry);
|
||||
}
|
||||
|
||||
dry(includeTemp = false) {
|
||||
let trusted = [],
|
||||
temp = [],
|
||||
untrusted = [],
|
||||
custom = Object.create(null);
|
||||
|
||||
const {DEFAULT, TRUSTED, UNTRUSTED} = this;
|
||||
for(let [key, perms] of this.sites) {
|
||||
if (!includeTemp && perms.temp) {
|
||||
continue;
|
||||
}
|
||||
switch(perms) {
|
||||
case TRUSTED:
|
||||
trusted.push(key);
|
||||
break;
|
||||
case TRUSTED.tempTwin:
|
||||
temp.push(key);
|
||||
break;
|
||||
case UNTRUSTED:
|
||||
untrusted.push(key);
|
||||
break;
|
||||
case DEFAULT:
|
||||
break;
|
||||
default:
|
||||
custom[key] = perms.dry();
|
||||
}
|
||||
}
|
||||
|
||||
let sites = {
|
||||
trusted,
|
||||
untrusted,
|
||||
custom
|
||||
};
|
||||
if (includeTemp) {
|
||||
sites.temp = temp;
|
||||
}
|
||||
enforceImmutable(this);
|
||||
return {
|
||||
DEFAULT: DEFAULT.dry(),
|
||||
TRUSTED: TRUSTED.dry(),
|
||||
UNTRUSTED: UNTRUSTED.dry(),
|
||||
sites,
|
||||
enforced: this.enforced,
|
||||
autoAllowTop: this.autoAllowTop,
|
||||
};
|
||||
}
|
||||
|
||||
static requestKey(url, type, documentUrl, includePath = false) {
|
||||
url = includePath ? Sites.parse(url).siteKey : Sites.origin(url);
|
||||
return `${type}@${url}<${Sites.origin(documentUrl)}`;
|
||||
}
|
||||
|
||||
static explodeKey(requestKey) {
|
||||
let [, type, url, documentUrl] = /(\w+)@([^<]+)<(.*)/.exec(requestKey);
|
||||
return {url, type, documentUrl};
|
||||
}
|
||||
|
||||
set(site, perms, cascade = false) {
|
||||
let sites = this.sites;
|
||||
let {url, siteKey} = Sites.parse(site);
|
||||
|
||||
sites.delete(siteKey);
|
||||
let wideSiteKey = Sites.toggleSecureDomainKey(siteKey, false);
|
||||
|
||||
if (perms === this.UNTRUSTED) {
|
||||
cascade = true;
|
||||
siteKey = wideSiteKey;
|
||||
} else {
|
||||
if (wideSiteKey !== siteKey) {
|
||||
sites.delete(wideSiteKey);
|
||||
}
|
||||
}
|
||||
if (cascade && !url) {
|
||||
for (let subMatch; (subMatch = sites.match(siteKey));) {
|
||||
sites.delete(subMatch);
|
||||
}
|
||||
}
|
||||
|
||||
if (!perms || perms === this.DEFAULT) {
|
||||
perms = this.DEFAULT;
|
||||
} else {
|
||||
sites.set(siteKey, perms);
|
||||
}
|
||||
return {siteKey, perms};
|
||||
}
|
||||
|
||||
get(site, ctx = null) {
|
||||
let perms, contextMatch;
|
||||
let siteMatch = !(this.onlySecure && /^\w+tp:/i.test(site)) && this.sites.match(site);
|
||||
if (siteMatch) {
|
||||
perms = this.sites.get(siteMatch);
|
||||
if (ctx) {
|
||||
contextMatch = perms.contextual.match(ctx);
|
||||
if (contextMatch) perms = perms.contextual.get(ctx);
|
||||
}
|
||||
} else {
|
||||
perms = this.DEFAULT;
|
||||
}
|
||||
|
||||
return {perms, siteMatch, contextMatch};
|
||||
}
|
||||
|
||||
can(url, capability = "script", ctx = null) {
|
||||
return !this.enforced ||
|
||||
this.get(url, ctx).perms.allowing(capability);
|
||||
}
|
||||
|
||||
get snapshot() {
|
||||
return JSON.stringify(this.dry(true));
|
||||
}
|
||||
|
||||
cascadeRestrictions(perms, topUrl) {
|
||||
let topPerms = this.get(topUrl, topUrl).perms;
|
||||
if (topPerms !== perms) {
|
||||
let topCaps = topPerms.capabilities;
|
||||
perms = new Permissions([...perms.capabilities].filter(c => topCaps.has(c)),
|
||||
perms.temp, perms.contextual);
|
||||
}
|
||||
return perms;
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
this.snapshot === other.snapshot;
|
||||
}
|
||||
}
|
||||
|
||||
return Policy;
|
||||
})();
|
|
@ -1,12 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var RequestKey = {
|
||||
create(url, type, documentOrigin) {
|
||||
return `${type}@${url}<${documentOrigin}`;
|
||||
},
|
||||
|
||||
explode(requestKey) {
|
||||
let [, type, url, documentOrigin] = /(\w+)@([^<]+)<(.*)/.exec(requestKey);
|
||||
return {url, type, documentOrigin};
|
||||
}
|
||||
};
|
|
@ -1,224 +0,0 @@
|
|||
var Sites = (() => {
|
||||
'use strict';
|
||||
const SECURE_DOMAIN_PREFIX = "§:";
|
||||
const SECURE_DOMAIN_RX = new RegExp(`^${SECURE_DOMAIN_PREFIX}`);
|
||||
const DOMAIN_RX = new RegExp(`(?:^\\w+://|${SECURE_DOMAIN_PREFIX})?([^/]*)`, "i");
|
||||
const IPV4_RX = /^(?:\d+\.){1,3}\d+/;
|
||||
const INTERNAL_SITE_RX = /^(?:(?:about|chrome|resource|(?:moz|chrome)-.*):|\[System)/;
|
||||
const VALID_SITE_RX = /^(?:(?:(?:(?:http|ftp|ws)s?|file):)(?:(?:\/\/)[\w\u0100-\uf000][\w\u0100-\uf000.-]*[\w\u0100-\uf000.](?:$|\/))?|[\w\u0100-\uf000][\w\u0100-\uf000.-]*[\w\u0100-\uf000]$)/;
|
||||
|
||||
let rxQuote = s => s.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&");
|
||||
|
||||
/**
|
||||
* a Map whose keys are (partial) URLs, used by Policy to store per-site Permissions
|
||||
* and providing several utility functions for URL/origin manipulation and mapping.
|
||||
*/
|
||||
class Sites extends Map {
|
||||
static secureDomainKey(domain) {
|
||||
return /^[§\w]+:/.test(domain) ? domain : `${SECURE_DOMAIN_PREFIX}${domain}`;
|
||||
}
|
||||
static isSecureDomainKey(domain) {
|
||||
return domain.startsWith(SECURE_DOMAIN_PREFIX);
|
||||
}
|
||||
static toggleSecureDomainKey(domain, b = !Sites.isSecureDomainKey(domain)) {
|
||||
return b ? Sites.secureDomainKey(domain) : domain.replace(SECURE_DOMAIN_RX, '');
|
||||
}
|
||||
|
||||
static isValid(site) {
|
||||
return VALID_SITE_RX.test(site);
|
||||
}
|
||||
|
||||
static isInternal(site) {
|
||||
return INTERNAL_SITE_RX.test(site);
|
||||
}
|
||||
|
||||
static originImplies(originKey, site) {
|
||||
return originKey === site || site.startsWith(`${originKey}/`);
|
||||
}
|
||||
|
||||
static domainImplies(domainKey, site, protocol ="https?") {
|
||||
if (Sites.isSecureDomainKey(domainKey)) {
|
||||
protocol = "https";
|
||||
domainKey = Sites.toggleSecureDomainKey(domainKey, false);
|
||||
}
|
||||
if (!site.includes(domainKey)) return false;
|
||||
try {
|
||||
return new RegExp(`^${protocol}://([^/?#:]+\\.)?${rxQuote(domainKey)}(?:[:/]|$)`)
|
||||
.test(site);
|
||||
} catch (e) {
|
||||
error(e, `Cannot check if ${domainKey} implies ${site}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static isImplied(site, byKey) {
|
||||
return byKey.includes("://")
|
||||
? Sites.originImplies(byKey, site)
|
||||
: Sites.domainImplies(byKey, site);
|
||||
}
|
||||
|
||||
static parse(site) {
|
||||
let url, siteKey = "";
|
||||
if (site instanceof URL) {
|
||||
url = site;
|
||||
} else {
|
||||
try {
|
||||
url = new URL(site);
|
||||
} catch (e) {
|
||||
siteKey = site ? (typeof site === "string" ? site : site.toString()) : "";
|
||||
}
|
||||
}
|
||||
if (url) {
|
||||
if (Sites.onionSecure && url.protocol === "http:" && url.hostname.endsWith(".onion")) {
|
||||
url.protocol = "https:";
|
||||
}
|
||||
let path = url.pathname;
|
||||
siteKey = url.origin;
|
||||
if (siteKey === "null") {
|
||||
([siteKey] = site.split(/[?#]/)); // drop any search / hash segment
|
||||
} else if (path !== '/') {
|
||||
siteKey += path;
|
||||
}
|
||||
}
|
||||
return {url, siteKey};
|
||||
}
|
||||
|
||||
static optimalKey(site) {
|
||||
let {url, siteKey} = Sites.parse(site);
|
||||
if (url && url.protocol === "https:") return Sites.secureDomainKey(tld.getDomain(url.hostname));
|
||||
return Sites.origin(url) || siteKey;
|
||||
}
|
||||
|
||||
static origin(site) {
|
||||
if (!site) return "";
|
||||
try {
|
||||
let objUrl = (typeof site === "object" && "origin" in site) ? site : site.startsWith("chrome:") ? {origin: "chrome:" } : new URL(site);
|
||||
let {origin} = objUrl;
|
||||
return origin === "null" ? Sites.cleanUrl(objUrl) || site : origin;
|
||||
} catch (e) {
|
||||
error(e);
|
||||
};
|
||||
return site.origin || site;
|
||||
}
|
||||
|
||||
static cleanUrl(url) {
|
||||
try {
|
||||
url = new URL(url);
|
||||
if (!tld.preserveFQDNs && url.hostname) {
|
||||
url.hostname = tld.normalize(url.hostname);
|
||||
}
|
||||
url.port = "";
|
||||
url.search = "";
|
||||
url.hash = "";
|
||||
return url.href;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static toExternal(url) { // domains are stored in punycode internally
|
||||
let s = typeof url === "string" ? url : url && url.toString() || "";
|
||||
if (s.startsWith(SECURE_DOMAIN_PREFIX)) s = s.substring(SECURE_DOMAIN_PREFIX.length);
|
||||
let [,domain] = DOMAIN_RX.exec(s);
|
||||
return domain.startsWith("xn--") ?
|
||||
s.replace(domain, punycode.toUnicode(domain))
|
||||
: s;
|
||||
}
|
||||
|
||||
set(k, v) {
|
||||
if (!k || Sites.isInternal(k) || k === "§:") return this;
|
||||
let [,domain] = DOMAIN_RX.exec(k);
|
||||
if (/[^\u0000-\u007f]/.test(domain)) {
|
||||
k = k.replace(domain, punycode.toASCII(domain));
|
||||
}
|
||||
return super.set(k, v);
|
||||
}
|
||||
|
||||
match(site) {
|
||||
if (site && this.size) {
|
||||
if (site instanceof URL) site = site.href;
|
||||
if (this.has(site)) return site;
|
||||
|
||||
let {url, siteKey} = Sites.parse(site);
|
||||
|
||||
if (site !== siteKey && this.has(siteKey)) {
|
||||
return siteKey;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
let {origin} = url;
|
||||
if (origin && origin !== "null" && origin < siteKey && this.has(origin)) {
|
||||
return origin;
|
||||
}
|
||||
let domain = this.domainMatch(url);
|
||||
if (domain) return domain;
|
||||
let protocol = url.protocol;
|
||||
if (this.has(protocol)) {
|
||||
return protocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
domainMatch(url) {
|
||||
let {protocol, hostname} = url;
|
||||
if (!hostname) return null;
|
||||
if (!tld.preserveFQDNs) hostname = tld.normalize(hostname);
|
||||
let secure = protocol === "https:";
|
||||
let isIPv4 = IPV4_RX.test(hostname);
|
||||
for (let domain = hostname;;) {
|
||||
if (this.has(domain)) {
|
||||
return domain;
|
||||
}
|
||||
if (secure) {
|
||||
let ssDomain = Sites.secureDomainKey(domain);
|
||||
if (this.has(ssDomain)) {
|
||||
return ssDomain;
|
||||
}
|
||||
}
|
||||
|
||||
if (isIPv4) {
|
||||
// subnet shortcuts
|
||||
let dotPos = domain.lastIndexOf(".");
|
||||
if (!(dotPos > 3 || domain.indexOf(".") < dotPos)) {
|
||||
break; // we want at least the 2 most significant bytes
|
||||
}
|
||||
domain = domain.substring(0, dotPos);
|
||||
} else {
|
||||
// (sub)domain matching
|
||||
let dotPos = domain.indexOf(".");
|
||||
if (dotPos === -1) {
|
||||
break;
|
||||
}
|
||||
domain = domain.substring(dotPos + 1); // upper level
|
||||
if (!domain) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
dry() {
|
||||
let dry;
|
||||
if (this.size) {
|
||||
dry = Object.create(null);
|
||||
for (let [key, perms] of this) {
|
||||
dry[key] = perms.dry();
|
||||
}
|
||||
}
|
||||
return dry;
|
||||
}
|
||||
|
||||
static hydrate(dry, obj = new Sites()) {
|
||||
if (dry) {
|
||||
for (let [key, dryPerms] of Object.entries(dry)) {
|
||||
obj.set(key, Permissions.hydrate(dryPerms));
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return Sites;
|
||||
})();
|
File diff suppressed because one or more lines are too long
|
@ -1,94 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
function patchWindow(patchingCallback, env = {}) {
|
||||
let nativeExport = this && this.exportFunction || typeof exportFunction == "function";
|
||||
if (!nativeExport) {
|
||||
// Chromium
|
||||
let exportFunction = (func, targetObject, {defineAs}) => {
|
||||
let original = targetObject[defineAs];
|
||||
console.log(`Setting ${targetObject}.${defineAs}`, func);
|
||||
targetObject[defineAs] = new Proxy(original, {
|
||||
apply(target, thisArg, args) {
|
||||
return func.apply(thisArg, args);
|
||||
}
|
||||
});
|
||||
};
|
||||
let cloneInto = (obj, targetObject) => {
|
||||
return obj; // dummy for assignment
|
||||
};
|
||||
let script = document.createElement("script");
|
||||
script.text = `
|
||||
(() => {
|
||||
console.log("Chromium patchWindow");
|
||||
let patchWindow = ${patchWindow};
|
||||
let cloneInto = ${cloneInto};
|
||||
let exportFunction = ${exportFunction};
|
||||
({
|
||||
patchWindow,
|
||||
exportFunction,
|
||||
cloneInto,
|
||||
}).patchWindow(${patchingCallback}, ${JSON.stringify(env)});
|
||||
})();
|
||||
`;
|
||||
document.documentElement.insertBefore(script, document.documentElement.firstChild);
|
||||
script.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// win: window object to modify.
|
||||
// modifyTarget: callback to function that modifies the desired properties
|
||||
// or methods. Callback must take target window as argument.
|
||||
function modifyWindow(win, modifyTarget) {
|
||||
try {
|
||||
modifyTarget(win.wrappedJSObject || win, env);
|
||||
modifyWindowOpenMethod(win, modifyTarget);
|
||||
modifyFramingElements(win, modifyTarget);
|
||||
} catch (e) {
|
||||
if (e instanceof DOMException && e.name === "SecurityError") {
|
||||
// In case someone tries to access SOP restricted window.
|
||||
// We can just ignore this.
|
||||
} else throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function modifyWindowOpenMethod(win, modifyTarget) {
|
||||
let windowOpen = win.wrappedJSObject ? win.wrappedJSObject.open : win.open;
|
||||
exportFunction(function(...args) {
|
||||
let newWin = windowOpen.call(this, ...args);
|
||||
if (newWin) modifyWindow(newWin, modifyTarget);
|
||||
return newWin;
|
||||
}, win, {defineAs: "open"});
|
||||
}
|
||||
|
||||
function modifyFramingElements(win, modifyTarget) {
|
||||
for (let property of ["contentWindow", "contentDocument"]) {
|
||||
for (let iface of ["Frame", "IFrame", "Object"]) {
|
||||
let proto = win[`HTML${iface}Element`].prototype;
|
||||
modifyContentProperties(proto, property, modifyTarget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function modifyContentProperties(proto, property, modifyTarget) {
|
||||
let descriptor = Object.getOwnPropertyDescriptor(proto, property);
|
||||
let origGetter = descriptor.get;
|
||||
let replacementFn;
|
||||
|
||||
if (property === "contentWindow") { replacementFn = function() {
|
||||
let win = origGetter.call(this);
|
||||
if (win) modifyWindow(win, modifyTarget);
|
||||
return win;
|
||||
}}
|
||||
if (property === "contentDocument") { replacementFn = function() {
|
||||
let document = origGetter.call(this);
|
||||
if (document && document.defaultView) modifyWindow(document.defaultView, modifyTarget);
|
||||
return document;
|
||||
}}
|
||||
|
||||
descriptor.get = exportFunction(replacementFn, proto, {defineAs: `get $property`});
|
||||
let wrappedProto = proto.wrappedJSObject || proto;
|
||||
Object.defineProperty(wrappedProto, property, descriptor);
|
||||
}
|
||||
|
||||
return modifyWindow(window, patchingCallback);
|
||||
}
|
|
@ -1,533 +0,0 @@
|
|||
/*! https://mths.be/punycode v1.4.1 by @mathias */
|
||||
;(function(root) {
|
||||
|
||||
/** Detect free variables */
|
||||
var freeExports = typeof exports == 'object' && exports &&
|
||||
!exports.nodeType && exports;
|
||||
var freeModule = typeof module == 'object' && module &&
|
||||
!module.nodeType && module;
|
||||
var freeGlobal = typeof global == 'object' && global;
|
||||
if (
|
||||
freeGlobal.global === freeGlobal ||
|
||||
freeGlobal.window === freeGlobal ||
|
||||
freeGlobal.self === freeGlobal
|
||||
) {
|
||||
root = freeGlobal;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `punycode` object.
|
||||
* @name punycode
|
||||
* @type Object
|
||||
*/
|
||||
var punycode,
|
||||
|
||||
/** Highest positive signed 32-bit float value */
|
||||
maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
|
||||
|
||||
/** Bootstring parameters */
|
||||
base = 36,
|
||||
tMin = 1,
|
||||
tMax = 26,
|
||||
skew = 38,
|
||||
damp = 700,
|
||||
initialBias = 72,
|
||||
initialN = 128, // 0x80
|
||||
delimiter = '-', // '\x2D'
|
||||
|
||||
/** Regular expressions */
|
||||
regexPunycode = /^xn--/,
|
||||
regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
|
||||
regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
|
||||
|
||||
/** Error messages */
|
||||
errors = {
|
||||
'overflow': 'Overflow: input needs wider integers to process',
|
||||
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
|
||||
'invalid-input': 'Invalid input'
|
||||
},
|
||||
|
||||
/** Convenience shortcuts */
|
||||
baseMinusTMin = base - tMin,
|
||||
floor = Math.floor,
|
||||
stringFromCharCode = String.fromCharCode,
|
||||
|
||||
/** Temporary variable */
|
||||
key;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* A generic error utility function.
|
||||
* @private
|
||||
* @param {String} type The error type.
|
||||
* @returns {Error} Throws a `RangeError` with the applicable error message.
|
||||
*/
|
||||
function error(type) {
|
||||
throw new RangeError(errors[type]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic `Array#map` utility function.
|
||||
* @private
|
||||
* @param {Array} array The array to iterate over.
|
||||
* @param {Function} callback The function that gets called for every array
|
||||
* item.
|
||||
* @returns {Array} A new array of values returned by the callback function.
|
||||
*/
|
||||
function map(array, fn) {
|
||||
var length = array.length;
|
||||
var result = [];
|
||||
while (length--) {
|
||||
result[length] = fn(array[length]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple `Array#map`-like wrapper to work with domain name strings or email
|
||||
* addresses.
|
||||
* @private
|
||||
* @param {String} domain The domain name or email address.
|
||||
* @param {Function} callback The function that gets called for every
|
||||
* character.
|
||||
* @returns {Array} A new string of characters returned by the callback
|
||||
* function.
|
||||
*/
|
||||
function mapDomain(string, fn) {
|
||||
var parts = string.split('@');
|
||||
var result = '';
|
||||
if (parts.length > 1) {
|
||||
// In email addresses, only the domain name should be punycoded. Leave
|
||||
// the local part (i.e. everything up to `@`) intact.
|
||||
result = parts[0] + '@';
|
||||
string = parts[1];
|
||||
}
|
||||
// Avoid `split(regex)` for IE8 compatibility. See #17.
|
||||
string = string.replace(regexSeparators, '\x2E');
|
||||
var labels = string.split('.');
|
||||
var encoded = map(labels, fn).join('.');
|
||||
return result + encoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array containing the numeric code points of each Unicode
|
||||
* character in the string. While JavaScript uses UCS-2 internally,
|
||||
* this function will convert a pair of surrogate halves (each of which
|
||||
* UCS-2 exposes as separate characters) into a single code point,
|
||||
* matching UTF-16.
|
||||
* @see `punycode.ucs2.encode`
|
||||
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
||||
* @memberOf punycode.ucs2
|
||||
* @name decode
|
||||
* @param {String} string The Unicode input string (UCS-2).
|
||||
* @returns {Array} The new array of code points.
|
||||
*/
|
||||
function ucs2decode(string) {
|
||||
var output = [],
|
||||
counter = 0,
|
||||
length = string.length,
|
||||
value,
|
||||
extra;
|
||||
while (counter < length) {
|
||||
value = string.charCodeAt(counter++);
|
||||
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
||||
// high surrogate, and there is a next character
|
||||
extra = string.charCodeAt(counter++);
|
||||
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
|
||||
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
||||
} else {
|
||||
// unmatched surrogate; only append this code unit, in case the next
|
||||
// code unit is the high surrogate of a surrogate pair
|
||||
output.push(value);
|
||||
counter--;
|
||||
}
|
||||
} else {
|
||||
output.push(value);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string based on an array of numeric code points.
|
||||
* @see `punycode.ucs2.decode`
|
||||
* @memberOf punycode.ucs2
|
||||
* @name encode
|
||||
* @param {Array} codePoints The array of numeric code points.
|
||||
* @returns {String} The new Unicode string (UCS-2).
|
||||
*/
|
||||
function ucs2encode(array) {
|
||||
return map(array, function(value) {
|
||||
var output = '';
|
||||
if (value > 0xFFFF) {
|
||||
value -= 0x10000;
|
||||
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
|
||||
value = 0xDC00 | value & 0x3FF;
|
||||
}
|
||||
output += stringFromCharCode(value);
|
||||
return output;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a basic code point into a digit/integer.
|
||||
* @see `digitToBasic()`
|
||||
* @private
|
||||
* @param {Number} codePoint The basic numeric code point value.
|
||||
* @returns {Number} The numeric value of a basic code point (for use in
|
||||
* representing integers) in the range `0` to `base - 1`, or `base` if
|
||||
* the code point does not represent a value.
|
||||
*/
|
||||
function basicToDigit(codePoint) {
|
||||
if (codePoint - 48 < 10) {
|
||||
return codePoint - 22;
|
||||
}
|
||||
if (codePoint - 65 < 26) {
|
||||
return codePoint - 65;
|
||||
}
|
||||
if (codePoint - 97 < 26) {
|
||||
return codePoint - 97;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a digit/integer into a basic code point.
|
||||
* @see `basicToDigit()`
|
||||
* @private
|
||||
* @param {Number} digit The numeric value of a basic code point.
|
||||
* @returns {Number} The basic code point whose value (when used for
|
||||
* representing integers) is `digit`, which needs to be in the range
|
||||
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
|
||||
* used; else, the lowercase form is used. The behavior is undefined
|
||||
* if `flag` is non-zero and `digit` has no uppercase form.
|
||||
*/
|
||||
function digitToBasic(digit, flag) {
|
||||
// 0..25 map to ASCII a..z or A..Z
|
||||
// 26..35 map to ASCII 0..9
|
||||
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bias adaptation function as per section 3.4 of RFC 3492.
|
||||
* https://tools.ietf.org/html/rfc3492#section-3.4
|
||||
* @private
|
||||
*/
|
||||
function adapt(delta, numPoints, firstTime) {
|
||||
var k = 0;
|
||||
delta = firstTime ? floor(delta / damp) : delta >> 1;
|
||||
delta += floor(delta / numPoints);
|
||||
for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
|
||||
delta = floor(delta / baseMinusTMin);
|
||||
}
|
||||
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
|
||||
* symbols.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The Punycode string of ASCII-only symbols.
|
||||
* @returns {String} The resulting string of Unicode symbols.
|
||||
*/
|
||||
function decode(input) {
|
||||
// Don't use UCS-2
|
||||
var output = [],
|
||||
inputLength = input.length,
|
||||
out,
|
||||
i = 0,
|
||||
n = initialN,
|
||||
bias = initialBias,
|
||||
basic,
|
||||
j,
|
||||
index,
|
||||
oldi,
|
||||
w,
|
||||
k,
|
||||
digit,
|
||||
t,
|
||||
/** Cached calculation results */
|
||||
baseMinusT;
|
||||
|
||||
// Handle the basic code points: let `basic` be the number of input code
|
||||
// points before the last delimiter, or `0` if there is none, then copy
|
||||
// the first basic code points to the output.
|
||||
|
||||
basic = input.lastIndexOf(delimiter);
|
||||
if (basic < 0) {
|
||||
basic = 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < basic; ++j) {
|
||||
// if it's not a basic code point
|
||||
if (input.charCodeAt(j) >= 0x80) {
|
||||
error('not-basic');
|
||||
}
|
||||
output.push(input.charCodeAt(j));
|
||||
}
|
||||
|
||||
// Main decoding loop: start just after the last delimiter if any basic code
|
||||
// points were copied; start at the beginning otherwise.
|
||||
|
||||
for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
|
||||
|
||||
// `index` is the index of the next character to be consumed.
|
||||
// Decode a generalized variable-length integer into `delta`,
|
||||
// which gets added to `i`. The overflow checking is easier
|
||||
// if we increase `i` as we go, then subtract off its starting
|
||||
// value at the end to obtain `delta`.
|
||||
for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
|
||||
|
||||
if (index >= inputLength) {
|
||||
error('invalid-input');
|
||||
}
|
||||
|
||||
digit = basicToDigit(input.charCodeAt(index++));
|
||||
|
||||
if (digit >= base || digit > floor((maxInt - i) / w)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
i += digit * w;
|
||||
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
||||
|
||||
if (digit < t) {
|
||||
break;
|
||||
}
|
||||
|
||||
baseMinusT = base - t;
|
||||
if (w > floor(maxInt / baseMinusT)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
w *= baseMinusT;
|
||||
|
||||
}
|
||||
|
||||
out = output.length + 1;
|
||||
bias = adapt(i - oldi, out, oldi == 0);
|
||||
|
||||
// `i` was supposed to wrap around from `out` to `0`,
|
||||
// incrementing `n` each time, so we'll fix that now:
|
||||
if (floor(i / out) > maxInt - n) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
n += floor(i / out);
|
||||
i %= out;
|
||||
|
||||
// Insert `n` at position `i` of the output
|
||||
output.splice(i++, 0, n);
|
||||
|
||||
}
|
||||
|
||||
return ucs2encode(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string of Unicode symbols (e.g. a domain name label) to a
|
||||
* Punycode string of ASCII-only symbols.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The string of Unicode symbols.
|
||||
* @returns {String} The resulting Punycode string of ASCII-only symbols.
|
||||
*/
|
||||
function encode(input) {
|
||||
var n,
|
||||
delta,
|
||||
handledCPCount,
|
||||
basicLength,
|
||||
bias,
|
||||
j,
|
||||
m,
|
||||
q,
|
||||
k,
|
||||
t,
|
||||
currentValue,
|
||||
output = [],
|
||||
/** `inputLength` will hold the number of code points in `input`. */
|
||||
inputLength,
|
||||
/** Cached calculation results */
|
||||
handledCPCountPlusOne,
|
||||
baseMinusT,
|
||||
qMinusT;
|
||||
|
||||
// Convert the input in UCS-2 to Unicode
|
||||
input = ucs2decode(input);
|
||||
|
||||
// Cache the length
|
||||
inputLength = input.length;
|
||||
|
||||
// Initialize the state
|
||||
n = initialN;
|
||||
delta = 0;
|
||||
bias = initialBias;
|
||||
|
||||
// Handle the basic code points
|
||||
for (j = 0; j < inputLength; ++j) {
|
||||
currentValue = input[j];
|
||||
if (currentValue < 0x80) {
|
||||
output.push(stringFromCharCode(currentValue));
|
||||
}
|
||||
}
|
||||
|
||||
handledCPCount = basicLength = output.length;
|
||||
|
||||
// `handledCPCount` is the number of code points that have been handled;
|
||||
// `basicLength` is the number of basic code points.
|
||||
|
||||
// Finish the basic string - if it is not empty - with a delimiter
|
||||
if (basicLength) {
|
||||
output.push(delimiter);
|
||||
}
|
||||
|
||||
// Main encoding loop:
|
||||
while (handledCPCount < inputLength) {
|
||||
|
||||
// All non-basic code points < n have been handled already. Find the next
|
||||
// larger one:
|
||||
for (m = maxInt, j = 0; j < inputLength; ++j) {
|
||||
currentValue = input[j];
|
||||
if (currentValue >= n && currentValue < m) {
|
||||
m = currentValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
|
||||
// but guard against overflow
|
||||
handledCPCountPlusOne = handledCPCount + 1;
|
||||
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
delta += (m - n) * handledCPCountPlusOne;
|
||||
n = m;
|
||||
|
||||
for (j = 0; j < inputLength; ++j) {
|
||||
currentValue = input[j];
|
||||
|
||||
if (currentValue < n && ++delta > maxInt) {
|
||||
error('overflow');
|
||||
}
|
||||
|
||||
if (currentValue == n) {
|
||||
// Represent delta as a generalized variable-length integer
|
||||
for (q = delta, k = base; /* no condition */; k += base) {
|
||||
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
||||
if (q < t) {
|
||||
break;
|
||||
}
|
||||
qMinusT = q - t;
|
||||
baseMinusT = base - t;
|
||||
output.push(
|
||||
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
|
||||
);
|
||||
q = floor(qMinusT / baseMinusT);
|
||||
}
|
||||
|
||||
output.push(stringFromCharCode(digitToBasic(q, 0)));
|
||||
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
|
||||
delta = 0;
|
||||
++handledCPCount;
|
||||
}
|
||||
}
|
||||
|
||||
++delta;
|
||||
++n;
|
||||
|
||||
}
|
||||
return output.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Punycode string representing a domain name or an email address
|
||||
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
|
||||
* it doesn't matter if you call it on a string that has already been
|
||||
* converted to Unicode.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The Punycoded domain name or email address to
|
||||
* convert to Unicode.
|
||||
* @returns {String} The Unicode representation of the given Punycode
|
||||
* string.
|
||||
*/
|
||||
function toUnicode(input) {
|
||||
return mapDomain(input, function(string) {
|
||||
return regexPunycode.test(string)
|
||||
? decode(string.slice(4).toLowerCase())
|
||||
: string;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Unicode string representing a domain name or an email address to
|
||||
* Punycode. Only the non-ASCII parts of the domain name will be converted,
|
||||
* i.e. it doesn't matter if you call it with a domain that's already in
|
||||
* ASCII.
|
||||
* @memberOf punycode
|
||||
* @param {String} input The domain name or email address to convert, as a
|
||||
* Unicode string.
|
||||
* @returns {String} The Punycode representation of the given domain name or
|
||||
* email address.
|
||||
*/
|
||||
function toASCII(input) {
|
||||
return mapDomain(input, function(string) {
|
||||
return regexNonASCII.test(string)
|
||||
? 'xn--' + encode(string)
|
||||
: string;
|
||||
});
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/** Define the public API */
|
||||
punycode = {
|
||||
/**
|
||||
* A string representing the current Punycode.js version number.
|
||||
* @memberOf punycode
|
||||
* @type String
|
||||
*/
|
||||
'version': '1.4.1',
|
||||
/**
|
||||
* An object of methods to convert from JavaScript's internal character
|
||||
* representation (UCS-2) to Unicode code points, and back.
|
||||
* @see <https://mathiasbynens.be/notes/javascript-encoding>
|
||||
* @memberOf punycode
|
||||
* @type Object
|
||||
*/
|
||||
'ucs2': {
|
||||
'decode': ucs2decode,
|
||||
'encode': ucs2encode
|
||||
},
|
||||
'decode': decode,
|
||||
'encode': encode,
|
||||
'toASCII': toASCII,
|
||||
'toUnicode': toUnicode
|
||||
};
|
||||
|
||||
/** Expose `punycode` */
|
||||
// Some AMD build optimizers, like r.js, check for specific condition patterns
|
||||
// like the following:
|
||||
if (
|
||||
typeof define == 'function' &&
|
||||
typeof define.amd == 'object' &&
|
||||
define.amd
|
||||
) {
|
||||
define('punycode', function() {
|
||||
return punycode;
|
||||
});
|
||||
} else if (freeExports && freeModule) {
|
||||
if (module.exports == freeExports) {
|
||||
// in Node.js, io.js, or RingoJS v0.8.0+
|
||||
freeModule.exports = punycode;
|
||||
} else {
|
||||
// in Narwhal or RingoJS v0.7.0-
|
||||
for (key in punycode) {
|
||||
punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// in Rhino or a web browser
|
||||
root.punycode = punycode;
|
||||
}
|
||||
|
||||
}(this));
|
|
@ -1,20 +0,0 @@
|
|||
Copyright Mathias Bynens <https://mathiasbynens.be/>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
Loading…
Reference in New Issue