mirror of
https://codeberg.org/keyoxide/doipjs.git
synced 2024-12-23 06:59:29 -07:00
8958 lines
342 KiB
JavaScript
8958 lines
342 KiB
JavaScript
|
var doip = (function (exports, fetcher, openpgp) {
|
|||
|
'use strict';
|
|||
|
|
|||
|
function _interopNamespaceDefault(e) {
|
|||
|
var n = Object.create(null);
|
|||
|
if (e) {
|
|||
|
Object.keys(e).forEach(function (k) {
|
|||
|
if (k !== 'default') {
|
|||
|
var d = Object.getOwnPropertyDescriptor(e, k);
|
|||
|
Object.defineProperty(n, k, d.get ? d : {
|
|||
|
enumerable: true,
|
|||
|
get: function () { return e[k]; }
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
n.default = e;
|
|||
|
return Object.freeze(n);
|
|||
|
}
|
|||
|
|
|||
|
var fetcher__namespace = /*#__PURE__*/_interopNamespaceDefault(fetcher);
|
|||
|
|
|||
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|||
|
|
|||
|
function getDefaultExportFromCjs (x) {
|
|||
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|||
|
}
|
|||
|
|
|||
|
function getAugmentedNamespace(n) {
|
|||
|
if (n.__esModule) return n;
|
|||
|
var f = n.default;
|
|||
|
if (typeof f == "function") {
|
|||
|
var a = function a () {
|
|||
|
if (this instanceof a) {
|
|||
|
var args = [null];
|
|||
|
args.push.apply(args, arguments);
|
|||
|
var Ctor = Function.bind.apply(f, args);
|
|||
|
return new Ctor();
|
|||
|
}
|
|||
|
return f.apply(this, arguments);
|
|||
|
};
|
|||
|
a.prototype = f.prototype;
|
|||
|
} else a = {};
|
|||
|
Object.defineProperty(a, '__esModule', {value: true});
|
|||
|
Object.keys(n).forEach(function (k) {
|
|||
|
var d = Object.getOwnPropertyDescriptor(n, k);
|
|||
|
Object.defineProperty(a, k, d.get ? d : {
|
|||
|
enumerable: true,
|
|||
|
get: function () {
|
|||
|
return n[k];
|
|||
|
}
|
|||
|
});
|
|||
|
});
|
|||
|
return a;
|
|||
|
}
|
|||
|
|
|||
|
var isAlphanumeric$1 = {};
|
|||
|
|
|||
|
var assertString = {exports: {}};
|
|||
|
|
|||
|
(function (module, exports) {
|
|||
|
|
|||
|
Object.defineProperty(exports, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
exports.default = assertString;
|
|||
|
|
|||
|
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|||
|
|
|||
|
function assertString(input) {
|
|||
|
var isString = typeof input === 'string' || input instanceof String;
|
|||
|
|
|||
|
if (!isString) {
|
|||
|
var invalidType = _typeof(input);
|
|||
|
|
|||
|
if (input === null) invalidType = 'null';else if (invalidType === 'object') invalidType = input.constructor.name;
|
|||
|
throw new TypeError("Expected a string but received a ".concat(invalidType));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
module.exports = exports.default;
|
|||
|
module.exports.default = exports.default;
|
|||
|
} (assertString, assertString.exports));
|
|||
|
|
|||
|
var assertStringExports = assertString.exports;
|
|||
|
|
|||
|
var alpha$2 = {};
|
|||
|
|
|||
|
Object.defineProperty(alpha$2, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
alpha$2.commaDecimal = alpha$2.dotDecimal = alpha$2.bengaliLocales = alpha$2.farsiLocales = alpha$2.arabicLocales = alpha$2.englishLocales = alpha$2.decimal = alpha$2.alphanumeric = alpha$2.alpha = void 0;
|
|||
|
var alpha$1 = {
|
|||
|
'en-US': /^[A-Z]+$/i,
|
|||
|
'az-AZ': /^[A-VXYZÇƏĞİıÖŞÜ]+$/i,
|
|||
|
'bg-BG': /^[А-Я]+$/i,
|
|||
|
'cs-CZ': /^[A-ZÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ]+$/i,
|
|||
|
'da-DK': /^[A-ZÆØÅ]+$/i,
|
|||
|
'de-DE': /^[A-ZÄÖÜß]+$/i,
|
|||
|
'el-GR': /^[Α-ώ]+$/i,
|
|||
|
'es-ES': /^[A-ZÁÉÍÑÓÚÜ]+$/i,
|
|||
|
'fa-IR': /^[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهی]+$/i,
|
|||
|
'fi-FI': /^[A-ZÅÄÖ]+$/i,
|
|||
|
'fr-FR': /^[A-ZÀÂÆÇÉÈÊËÏÎÔŒÙÛÜŸ]+$/i,
|
|||
|
'it-IT': /^[A-ZÀÉÈÌÎÓÒÙ]+$/i,
|
|||
|
'ja-JP': /^[ぁ-んァ-ヶヲ-゚一-龠ー・。、]+$/i,
|
|||
|
'nb-NO': /^[A-ZÆØÅ]+$/i,
|
|||
|
'nl-NL': /^[A-ZÁÉËÏÓÖÜÚ]+$/i,
|
|||
|
'nn-NO': /^[A-ZÆØÅ]+$/i,
|
|||
|
'hu-HU': /^[A-ZÁÉÍÓÖŐÚÜŰ]+$/i,
|
|||
|
'pl-PL': /^[A-ZĄĆĘŚŁŃÓŻŹ]+$/i,
|
|||
|
'pt-PT': /^[A-ZÃÁÀÂÄÇÉÊËÍÏÕÓÔÖÚÜ]+$/i,
|
|||
|
'ru-RU': /^[А-ЯЁ]+$/i,
|
|||
|
'sl-SI': /^[A-ZČĆĐŠŽ]+$/i,
|
|||
|
'sk-SK': /^[A-ZÁČĎÉÍŇÓŠŤÚÝŽĹŔĽÄÔ]+$/i,
|
|||
|
'sr-RS@latin': /^[A-ZČĆŽŠĐ]+$/i,
|
|||
|
'sr-RS': /^[А-ЯЂЈЉЊЋЏ]+$/i,
|
|||
|
'sv-SE': /^[A-ZÅÄÖ]+$/i,
|
|||
|
'th-TH': /^[ก-๐\s]+$/i,
|
|||
|
'tr-TR': /^[A-ZÇĞİıÖŞÜ]+$/i,
|
|||
|
'uk-UA': /^[А-ЩЬЮЯЄIЇҐі]+$/i,
|
|||
|
'vi-VN': /^[A-ZÀÁẠẢÃÂẦẤẬẨẪĂẰẮẶẲẴĐÈÉẸẺẼÊỀẾỆỂỄÌÍỊỈĨÒÓỌỎÕÔỒỐỘỔỖƠỜỚỢỞỠÙÚỤỦŨƯỪỨỰỬỮỲÝỴỶỸ]+$/i,
|
|||
|
'ko-KR': /^[ㄱ-ㅎㅏ-ㅣ가-힣]*$/,
|
|||
|
'ku-IQ': /^[ئابپتجچحخدرڕزژسشعغفڤقکگلڵمنوۆھەیێيطؤثآإأكضصةظذ]+$/i,
|
|||
|
ar: /^[ءآأؤإئابةتثجحخدذرزسشصضطظعغفقكلمنهوىيًٌٍَُِّْٰ]+$/,
|
|||
|
he: /^[א-ת]+$/,
|
|||
|
fa: /^['آاءأؤئبپتثجچحخدذرزژسشصضطظعغفقکگلمنوهةی']+$/i,
|
|||
|
bn: /^['ঀঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣৰৱ৲৳৴৵৶৷৸৹৺৻']+$/,
|
|||
|
'hi-IN': /^[\u0900-\u0961]+[\u0972-\u097F]*$/i,
|
|||
|
'si-LK': /^[\u0D80-\u0DFF]+$/
|
|||
|
};
|
|||
|
alpha$2.alpha = alpha$1;
|
|||
|
var alphanumeric = {
|
|||
|
'en-US': /^[0-9A-Z]+$/i,
|
|||
|
'az-AZ': /^[0-9A-VXYZÇƏĞİıÖŞÜ]+$/i,
|
|||
|
'bg-BG': /^[0-9А-Я]+$/i,
|
|||
|
'cs-CZ': /^[0-9A-ZÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ]+$/i,
|
|||
|
'da-DK': /^[0-9A-ZÆØÅ]+$/i,
|
|||
|
'de-DE': /^[0-9A-ZÄÖÜß]+$/i,
|
|||
|
'el-GR': /^[0-9Α-ω]+$/i,
|
|||
|
'es-ES': /^[0-9A-ZÁÉÍÑÓÚÜ]+$/i,
|
|||
|
'fi-FI': /^[0-9A-ZÅÄÖ]+$/i,
|
|||
|
'fr-FR': /^[0-9A-ZÀÂÆÇÉÈÊËÏÎÔŒÙÛÜŸ]+$/i,
|
|||
|
'it-IT': /^[0-9A-ZÀÉÈÌÎÓÒÙ]+$/i,
|
|||
|
'ja-JP': /^[0-90-9ぁ-んァ-ヶヲ-゚一-龠ー・。、]+$/i,
|
|||
|
'hu-HU': /^[0-9A-ZÁÉÍÓÖŐÚÜŰ]+$/i,
|
|||
|
'nb-NO': /^[0-9A-ZÆØÅ]+$/i,
|
|||
|
'nl-NL': /^[0-9A-ZÁÉËÏÓÖÜÚ]+$/i,
|
|||
|
'nn-NO': /^[0-9A-ZÆØÅ]+$/i,
|
|||
|
'pl-PL': /^[0-9A-ZĄĆĘŚŁŃÓŻŹ]+$/i,
|
|||
|
'pt-PT': /^[0-9A-ZÃÁÀÂÄÇÉÊËÍÏÕÓÔÖÚÜ]+$/i,
|
|||
|
'ru-RU': /^[0-9А-ЯЁ]+$/i,
|
|||
|
'sl-SI': /^[0-9A-ZČĆĐŠŽ]+$/i,
|
|||
|
'sk-SK': /^[0-9A-ZÁČĎÉÍŇÓŠŤÚÝŽĹŔĽÄÔ]+$/i,
|
|||
|
'sr-RS@latin': /^[0-9A-ZČĆŽŠĐ]+$/i,
|
|||
|
'sr-RS': /^[0-9А-ЯЂЈЉЊЋЏ]+$/i,
|
|||
|
'sv-SE': /^[0-9A-ZÅÄÖ]+$/i,
|
|||
|
'th-TH': /^[ก-๙\s]+$/i,
|
|||
|
'tr-TR': /^[0-9A-ZÇĞİıÖŞÜ]+$/i,
|
|||
|
'uk-UA': /^[0-9А-ЩЬЮЯЄIЇҐі]+$/i,
|
|||
|
'ko-KR': /^[0-9ㄱ-ㅎㅏ-ㅣ가-힣]*$/,
|
|||
|
'ku-IQ': /^[٠١٢٣٤٥٦٧٨٩0-9ئابپتجچحخدرڕزژسشعغفڤقکگلڵمنوۆھەیێيطؤثآإأكضصةظذ]+$/i,
|
|||
|
'vi-VN': /^[0-9A-ZÀÁẠẢÃÂẦẤẬẨẪĂẰẮẶẲẴĐÈÉẸẺẼÊỀẾỆỂỄÌÍỊỈĨÒÓỌỎÕÔỒỐỘỔỖƠỜỚỢỞỠÙÚỤỦŨƯỪỨỰỬỮỲÝỴỶỸ]+$/i,
|
|||
|
ar: /^[٠١٢٣٤٥٦٧٨٩0-9ءآأؤإئابةتثجحخدذرزسشصضطظعغفقكلمنهوىيًٌٍَُِّْٰ]+$/,
|
|||
|
he: /^[0-9א-ת]+$/,
|
|||
|
fa: /^['0-9آاءأؤئبپتثجچحخدذرزژسشصضطظعغفقکگلمنوهةی۱۲۳۴۵۶۷۸۹۰']+$/i,
|
|||
|
bn: /^['ঀঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻']+$/,
|
|||
|
'hi-IN': /^[\u0900-\u0963]+[\u0966-\u097F]*$/i,
|
|||
|
'si-LK': /^[0-9\u0D80-\u0DFF]+$/
|
|||
|
};
|
|||
|
alpha$2.alphanumeric = alphanumeric;
|
|||
|
var decimal = {
|
|||
|
'en-US': '.',
|
|||
|
ar: '٫'
|
|||
|
};
|
|||
|
alpha$2.decimal = decimal;
|
|||
|
var englishLocales = ['AU', 'GB', 'HK', 'IN', 'NZ', 'ZA', 'ZM'];
|
|||
|
alpha$2.englishLocales = englishLocales;
|
|||
|
|
|||
|
for (var locale, i = 0; i < englishLocales.length; i++) {
|
|||
|
locale = "en-".concat(englishLocales[i]);
|
|||
|
alpha$1[locale] = alpha$1['en-US'];
|
|||
|
alphanumeric[locale] = alphanumeric['en-US'];
|
|||
|
decimal[locale] = decimal['en-US'];
|
|||
|
} // Source: http://www.localeplanet.com/java/
|
|||
|
|
|||
|
|
|||
|
var arabicLocales = ['AE', 'BH', 'DZ', 'EG', 'IQ', 'JO', 'KW', 'LB', 'LY', 'MA', 'QM', 'QA', 'SA', 'SD', 'SY', 'TN', 'YE'];
|
|||
|
alpha$2.arabicLocales = arabicLocales;
|
|||
|
|
|||
|
for (var _locale, _i = 0; _i < arabicLocales.length; _i++) {
|
|||
|
_locale = "ar-".concat(arabicLocales[_i]);
|
|||
|
alpha$1[_locale] = alpha$1.ar;
|
|||
|
alphanumeric[_locale] = alphanumeric.ar;
|
|||
|
decimal[_locale] = decimal.ar;
|
|||
|
}
|
|||
|
|
|||
|
var farsiLocales = ['IR', 'AF'];
|
|||
|
alpha$2.farsiLocales = farsiLocales;
|
|||
|
|
|||
|
for (var _locale2, _i2 = 0; _i2 < farsiLocales.length; _i2++) {
|
|||
|
_locale2 = "fa-".concat(farsiLocales[_i2]);
|
|||
|
alphanumeric[_locale2] = alphanumeric.fa;
|
|||
|
decimal[_locale2] = decimal.ar;
|
|||
|
}
|
|||
|
|
|||
|
var bengaliLocales = ['BD', 'IN'];
|
|||
|
alpha$2.bengaliLocales = bengaliLocales;
|
|||
|
|
|||
|
for (var _locale3, _i3 = 0; _i3 < bengaliLocales.length; _i3++) {
|
|||
|
_locale3 = "bn-".concat(bengaliLocales[_i3]);
|
|||
|
alpha$1[_locale3] = alpha$1.bn;
|
|||
|
alphanumeric[_locale3] = alphanumeric.bn;
|
|||
|
decimal[_locale3] = decimal['en-US'];
|
|||
|
} // Source: https://en.wikipedia.org/wiki/Decimal_mark
|
|||
|
|
|||
|
|
|||
|
var dotDecimal = ['ar-EG', 'ar-LB', 'ar-LY'];
|
|||
|
alpha$2.dotDecimal = dotDecimal;
|
|||
|
var commaDecimal = ['bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-ZM', 'es-ES', 'fr-CA', 'fr-FR', 'id-ID', 'it-IT', 'ku-IQ', 'hi-IN', 'hu-HU', 'nb-NO', 'nn-NO', 'nl-NL', 'pl-PL', 'pt-PT', 'ru-RU', 'si-LK', 'sl-SI', 'sr-RS@latin', 'sr-RS', 'sv-SE', 'tr-TR', 'uk-UA', 'vi-VN'];
|
|||
|
alpha$2.commaDecimal = commaDecimal;
|
|||
|
|
|||
|
for (var _i4 = 0; _i4 < dotDecimal.length; _i4++) {
|
|||
|
decimal[dotDecimal[_i4]] = decimal['en-US'];
|
|||
|
}
|
|||
|
|
|||
|
for (var _i5 = 0; _i5 < commaDecimal.length; _i5++) {
|
|||
|
decimal[commaDecimal[_i5]] = ',';
|
|||
|
}
|
|||
|
|
|||
|
alpha$1['fr-CA'] = alpha$1['fr-FR'];
|
|||
|
alphanumeric['fr-CA'] = alphanumeric['fr-FR'];
|
|||
|
alpha$1['pt-BR'] = alpha$1['pt-PT'];
|
|||
|
alphanumeric['pt-BR'] = alphanumeric['pt-PT'];
|
|||
|
decimal['pt-BR'] = decimal['pt-PT']; // see #862
|
|||
|
|
|||
|
alpha$1['pl-Pl'] = alpha$1['pl-PL'];
|
|||
|
alphanumeric['pl-Pl'] = alphanumeric['pl-PL'];
|
|||
|
decimal['pl-Pl'] = decimal['pl-PL']; // see #1455
|
|||
|
|
|||
|
alpha$1['fa-AF'] = alpha$1.fa;
|
|||
|
|
|||
|
Object.defineProperty(isAlphanumeric$1, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
var _default = isAlphanumeric$1.default = isAlphanumeric;
|
|||
|
isAlphanumeric$1.locales = void 0;
|
|||
|
|
|||
|
var _assertString = _interopRequireDefault(assertStringExports);
|
|||
|
|
|||
|
var _alpha = alpha$2;
|
|||
|
|
|||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|||
|
|
|||
|
function isAlphanumeric(_str) {
|
|||
|
var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'en-US';
|
|||
|
var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|||
|
(0, _assertString.default)(_str);
|
|||
|
var str = _str;
|
|||
|
var ignore = options.ignore;
|
|||
|
|
|||
|
if (ignore) {
|
|||
|
if (ignore instanceof RegExp) {
|
|||
|
str = str.replace(ignore, '');
|
|||
|
} else if (typeof ignore === 'string') {
|
|||
|
str = str.replace(new RegExp("[".concat(ignore.replace(/[-[\]{}()*+?.,\\^$|#\\s]/g, '\\$&'), "]"), 'g'), ''); // escape regex for ignore
|
|||
|
} else {
|
|||
|
throw new Error('ignore should be instance of a String or RegExp');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (locale in _alpha.alphanumeric) {
|
|||
|
return _alpha.alphanumeric[locale].test(str);
|
|||
|
}
|
|||
|
|
|||
|
throw new Error("Invalid locale '".concat(locale, "'"));
|
|||
|
}
|
|||
|
|
|||
|
var locales = Object.keys(_alpha.alphanumeric);
|
|||
|
isAlphanumeric$1.locales = locales;
|
|||
|
|
|||
|
var validUrl = {exports: {}};
|
|||
|
|
|||
|
(function (module) {
|
|||
|
(function(module) {
|
|||
|
|
|||
|
module.exports.is_uri = is_iri;
|
|||
|
module.exports.is_http_uri = is_http_iri;
|
|||
|
module.exports.is_https_uri = is_https_iri;
|
|||
|
module.exports.is_web_uri = is_web_iri;
|
|||
|
// Create aliases
|
|||
|
module.exports.isUri = is_iri;
|
|||
|
module.exports.isHttpUri = is_http_iri;
|
|||
|
module.exports.isHttpsUri = is_https_iri;
|
|||
|
module.exports.isWebUri = is_web_iri;
|
|||
|
|
|||
|
|
|||
|
// private function
|
|||
|
// internal URI spitter method - direct from RFC 3986
|
|||
|
var splitUri = function(uri) {
|
|||
|
var splitted = uri.match(/(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?/);
|
|||
|
return splitted;
|
|||
|
};
|
|||
|
|
|||
|
function is_iri(value) {
|
|||
|
if (!value) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// check for illegal characters
|
|||
|
if (/[^a-z0-9\:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\.\-\_\~\%]/i.test(value)) return;
|
|||
|
|
|||
|
// check for hex escapes that aren't complete
|
|||
|
if (/%[^0-9a-f]/i.test(value)) return;
|
|||
|
if (/%[0-9a-f](:?[^0-9a-f]|$)/i.test(value)) return;
|
|||
|
|
|||
|
var splitted = [];
|
|||
|
var scheme = '';
|
|||
|
var authority = '';
|
|||
|
var path = '';
|
|||
|
var query = '';
|
|||
|
var fragment = '';
|
|||
|
var out = '';
|
|||
|
|
|||
|
// from RFC 3986
|
|||
|
splitted = splitUri(value);
|
|||
|
scheme = splitted[1];
|
|||
|
authority = splitted[2];
|
|||
|
path = splitted[3];
|
|||
|
query = splitted[4];
|
|||
|
fragment = splitted[5];
|
|||
|
|
|||
|
// scheme and path are required, though the path can be empty
|
|||
|
if (!(scheme && scheme.length && path.length >= 0)) return;
|
|||
|
|
|||
|
// if authority is present, the path must be empty or begin with a /
|
|||
|
if (authority && authority.length) {
|
|||
|
if (!(path.length === 0 || /^\//.test(path))) return;
|
|||
|
} else {
|
|||
|
// if authority is not present, the path must not start with //
|
|||
|
if (/^\/\//.test(path)) return;
|
|||
|
}
|
|||
|
|
|||
|
// scheme must begin with a letter, then consist of letters, digits, +, ., or -
|
|||
|
if (!/^[a-z][a-z0-9\+\-\.]*$/.test(scheme.toLowerCase())) return;
|
|||
|
|
|||
|
// re-assemble the URL per section 5.3 in RFC 3986
|
|||
|
out += scheme + ':';
|
|||
|
if (authority && authority.length) {
|
|||
|
out += '//' + authority;
|
|||
|
}
|
|||
|
|
|||
|
out += path;
|
|||
|
|
|||
|
if (query && query.length) {
|
|||
|
out += '?' + query;
|
|||
|
}
|
|||
|
|
|||
|
if (fragment && fragment.length) {
|
|||
|
out += '#' + fragment;
|
|||
|
}
|
|||
|
|
|||
|
return out;
|
|||
|
}
|
|||
|
|
|||
|
function is_http_iri(value, allowHttps) {
|
|||
|
if (!is_iri(value)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
var splitted = [];
|
|||
|
var scheme = '';
|
|||
|
var authority = '';
|
|||
|
var path = '';
|
|||
|
var port = '';
|
|||
|
var query = '';
|
|||
|
var fragment = '';
|
|||
|
var out = '';
|
|||
|
|
|||
|
// from RFC 3986
|
|||
|
splitted = splitUri(value);
|
|||
|
scheme = splitted[1];
|
|||
|
authority = splitted[2];
|
|||
|
path = splitted[3];
|
|||
|
query = splitted[4];
|
|||
|
fragment = splitted[5];
|
|||
|
|
|||
|
if (!scheme) return;
|
|||
|
|
|||
|
if(allowHttps) {
|
|||
|
if (scheme.toLowerCase() != 'https') return;
|
|||
|
} else {
|
|||
|
if (scheme.toLowerCase() != 'http') return;
|
|||
|
}
|
|||
|
|
|||
|
// fully-qualified URIs must have an authority section that is
|
|||
|
// a valid host
|
|||
|
if (!authority) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// enable port component
|
|||
|
if (/:(\d+)$/.test(authority)) {
|
|||
|
port = authority.match(/:(\d+)$/)[0];
|
|||
|
authority = authority.replace(/:\d+$/, '');
|
|||
|
}
|
|||
|
|
|||
|
out += scheme + ':';
|
|||
|
out += '//' + authority;
|
|||
|
|
|||
|
if (port) {
|
|||
|
out += port;
|
|||
|
}
|
|||
|
|
|||
|
out += path;
|
|||
|
|
|||
|
if(query && query.length){
|
|||
|
out += '?' + query;
|
|||
|
}
|
|||
|
|
|||
|
if(fragment && fragment.length){
|
|||
|
out += '#' + fragment;
|
|||
|
}
|
|||
|
|
|||
|
return out;
|
|||
|
}
|
|||
|
|
|||
|
function is_https_iri(value) {
|
|||
|
return is_http_iri(value, true);
|
|||
|
}
|
|||
|
|
|||
|
function is_web_iri(value) {
|
|||
|
return (is_http_iri(value) || is_https_iri(value));
|
|||
|
}
|
|||
|
|
|||
|
})(module);
|
|||
|
} (validUrl));
|
|||
|
|
|||
|
var validUrlExports = validUrl.exports;
|
|||
|
|
|||
|
var isPlainObj = value => {
|
|||
|
if (Object.prototype.toString.call(value) !== '[object Object]') {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
const prototype = Object.getPrototypeOf(value);
|
|||
|
return prototype === null || prototype === Object.prototype;
|
|||
|
};
|
|||
|
|
|||
|
const isOptionObject = isPlainObj;
|
|||
|
|
|||
|
const {hasOwnProperty} = Object.prototype;
|
|||
|
const {propertyIsEnumerable} = Object;
|
|||
|
const defineProperty = (object, name, value) => Object.defineProperty(object, name, {
|
|||
|
value,
|
|||
|
writable: true,
|
|||
|
enumerable: true,
|
|||
|
configurable: true
|
|||
|
});
|
|||
|
|
|||
|
const globalThis$1 = commonjsGlobal;
|
|||
|
const defaultMergeOptions = {
|
|||
|
concatArrays: false,
|
|||
|
ignoreUndefined: false
|
|||
|
};
|
|||
|
|
|||
|
const getEnumerableOwnPropertyKeys = value => {
|
|||
|
const keys = [];
|
|||
|
|
|||
|
for (const key in value) {
|
|||
|
if (hasOwnProperty.call(value, key)) {
|
|||
|
keys.push(key);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* istanbul ignore else */
|
|||
|
if (Object.getOwnPropertySymbols) {
|
|||
|
const symbols = Object.getOwnPropertySymbols(value);
|
|||
|
|
|||
|
for (const symbol of symbols) {
|
|||
|
if (propertyIsEnumerable.call(value, symbol)) {
|
|||
|
keys.push(symbol);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return keys;
|
|||
|
};
|
|||
|
|
|||
|
function clone(value) {
|
|||
|
if (Array.isArray(value)) {
|
|||
|
return cloneArray(value);
|
|||
|
}
|
|||
|
|
|||
|
if (isOptionObject(value)) {
|
|||
|
return cloneOptionObject(value);
|
|||
|
}
|
|||
|
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
function cloneArray(array) {
|
|||
|
const result = array.slice(0, 0);
|
|||
|
|
|||
|
getEnumerableOwnPropertyKeys(array).forEach(key => {
|
|||
|
defineProperty(result, key, clone(array[key]));
|
|||
|
});
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
function cloneOptionObject(object) {
|
|||
|
const result = Object.getPrototypeOf(object) === null ? Object.create(null) : {};
|
|||
|
|
|||
|
getEnumerableOwnPropertyKeys(object).forEach(key => {
|
|||
|
defineProperty(result, key, clone(object[key]));
|
|||
|
});
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* @param {*} merged already cloned
|
|||
|
* @param {*} source something to merge
|
|||
|
* @param {string[]} keys keys to merge
|
|||
|
* @param {Object} config Config Object
|
|||
|
* @returns {*} cloned Object
|
|||
|
*/
|
|||
|
const mergeKeys = (merged, source, keys, config) => {
|
|||
|
keys.forEach(key => {
|
|||
|
if (typeof source[key] === 'undefined' && config.ignoreUndefined) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Do not recurse into prototype chain of merged
|
|||
|
if (key in merged && merged[key] !== Object.getPrototypeOf(merged)) {
|
|||
|
defineProperty(merged, key, merge$2(merged[key], source[key], config));
|
|||
|
} else {
|
|||
|
defineProperty(merged, key, clone(source[key]));
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return merged;
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* @param {*} merged already cloned
|
|||
|
* @param {*} source something to merge
|
|||
|
* @param {Object} config Config Object
|
|||
|
* @returns {*} cloned Object
|
|||
|
*
|
|||
|
* see [Array.prototype.concat ( ...arguments )](http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat)
|
|||
|
*/
|
|||
|
const concatArrays = (merged, source, config) => {
|
|||
|
let result = merged.slice(0, 0);
|
|||
|
let resultIndex = 0;
|
|||
|
|
|||
|
[merged, source].forEach(array => {
|
|||
|
const indices = [];
|
|||
|
|
|||
|
// `result.concat(array)` with cloning
|
|||
|
for (let k = 0; k < array.length; k++) {
|
|||
|
if (!hasOwnProperty.call(array, k)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
indices.push(String(k));
|
|||
|
|
|||
|
if (array === merged) {
|
|||
|
// Already cloned
|
|||
|
defineProperty(result, resultIndex++, array[k]);
|
|||
|
} else {
|
|||
|
defineProperty(result, resultIndex++, clone(array[k]));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Merge non-index keys
|
|||
|
result = mergeKeys(result, array, getEnumerableOwnPropertyKeys(array).filter(key => !indices.includes(key)), config);
|
|||
|
});
|
|||
|
|
|||
|
return result;
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* @param {*} merged already cloned
|
|||
|
* @param {*} source something to merge
|
|||
|
* @param {Object} config Config Object
|
|||
|
* @returns {*} cloned Object
|
|||
|
*/
|
|||
|
function merge$2(merged, source, config) {
|
|||
|
if (config.concatArrays && Array.isArray(merged) && Array.isArray(source)) {
|
|||
|
return concatArrays(merged, source, config);
|
|||
|
}
|
|||
|
|
|||
|
if (!isOptionObject(source) || !isOptionObject(merged)) {
|
|||
|
return clone(source);
|
|||
|
}
|
|||
|
|
|||
|
return mergeKeys(merged, source, getEnumerableOwnPropertyKeys(source), config);
|
|||
|
}
|
|||
|
|
|||
|
var mergeOptions = function (...options) {
|
|||
|
const config = merge$2(clone(defaultMergeOptions), (this !== globalThis$1 && this) || {}, defaultMergeOptions);
|
|||
|
let merged = {_: {}};
|
|||
|
|
|||
|
for (const option of options) {
|
|||
|
if (option === undefined) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (!isOptionObject(option)) {
|
|||
|
throw new TypeError('`' + option + '` is not an Option Object');
|
|||
|
}
|
|||
|
|
|||
|
merged = merge$2(merged, {_: option}, config);
|
|||
|
}
|
|||
|
|
|||
|
return merged._;
|
|||
|
};
|
|||
|
|
|||
|
var mergeOptions$1 = /*@__PURE__*/getDefaultExportFromCjs(mergeOptions);
|
|||
|
|
|||
|
var global$1 = (typeof global !== "undefined" ? global :
|
|||
|
typeof self !== "undefined" ? self :
|
|||
|
typeof window !== "undefined" ? window : {});
|
|||
|
|
|||
|
// shim for using process in browser
|
|||
|
// based off https://github.com/defunctzombie/node-process/blob/master/browser.js
|
|||
|
|
|||
|
function defaultSetTimout() {
|
|||
|
throw new Error('setTimeout has not been defined');
|
|||
|
}
|
|||
|
function defaultClearTimeout () {
|
|||
|
throw new Error('clearTimeout has not been defined');
|
|||
|
}
|
|||
|
var cachedSetTimeout = defaultSetTimout;
|
|||
|
var cachedClearTimeout = defaultClearTimeout;
|
|||
|
if (typeof global$1.setTimeout === 'function') {
|
|||
|
cachedSetTimeout = setTimeout;
|
|||
|
}
|
|||
|
if (typeof global$1.clearTimeout === 'function') {
|
|||
|
cachedClearTimeout = clearTimeout;
|
|||
|
}
|
|||
|
|
|||
|
function runTimeout(fun) {
|
|||
|
if (cachedSetTimeout === setTimeout) {
|
|||
|
//normal enviroments in sane situations
|
|||
|
return setTimeout(fun, 0);
|
|||
|
}
|
|||
|
// if setTimeout wasn't available but was latter defined
|
|||
|
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
|
|||
|
cachedSetTimeout = setTimeout;
|
|||
|
return setTimeout(fun, 0);
|
|||
|
}
|
|||
|
try {
|
|||
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
|||
|
return cachedSetTimeout(fun, 0);
|
|||
|
} catch(e){
|
|||
|
try {
|
|||
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
|||
|
return cachedSetTimeout.call(null, fun, 0);
|
|||
|
} catch(e){
|
|||
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
|
|||
|
return cachedSetTimeout.call(this, fun, 0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
function runClearTimeout(marker) {
|
|||
|
if (cachedClearTimeout === clearTimeout) {
|
|||
|
//normal enviroments in sane situations
|
|||
|
return clearTimeout(marker);
|
|||
|
}
|
|||
|
// if clearTimeout wasn't available but was latter defined
|
|||
|
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
|
|||
|
cachedClearTimeout = clearTimeout;
|
|||
|
return clearTimeout(marker);
|
|||
|
}
|
|||
|
try {
|
|||
|
// when when somebody has screwed with setTimeout but no I.E. maddness
|
|||
|
return cachedClearTimeout(marker);
|
|||
|
} catch (e){
|
|||
|
try {
|
|||
|
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
|
|||
|
return cachedClearTimeout.call(null, marker);
|
|||
|
} catch (e){
|
|||
|
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
|
|||
|
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
|
|||
|
return cachedClearTimeout.call(this, marker);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
var queue = [];
|
|||
|
var draining = false;
|
|||
|
var currentQueue;
|
|||
|
var queueIndex = -1;
|
|||
|
|
|||
|
function cleanUpNextTick() {
|
|||
|
if (!draining || !currentQueue) {
|
|||
|
return;
|
|||
|
}
|
|||
|
draining = false;
|
|||
|
if (currentQueue.length) {
|
|||
|
queue = currentQueue.concat(queue);
|
|||
|
} else {
|
|||
|
queueIndex = -1;
|
|||
|
}
|
|||
|
if (queue.length) {
|
|||
|
drainQueue();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function drainQueue() {
|
|||
|
if (draining) {
|
|||
|
return;
|
|||
|
}
|
|||
|
var timeout = runTimeout(cleanUpNextTick);
|
|||
|
draining = true;
|
|||
|
|
|||
|
var len = queue.length;
|
|||
|
while(len) {
|
|||
|
currentQueue = queue;
|
|||
|
queue = [];
|
|||
|
while (++queueIndex < len) {
|
|||
|
if (currentQueue) {
|
|||
|
currentQueue[queueIndex].run();
|
|||
|
}
|
|||
|
}
|
|||
|
queueIndex = -1;
|
|||
|
len = queue.length;
|
|||
|
}
|
|||
|
currentQueue = null;
|
|||
|
draining = false;
|
|||
|
runClearTimeout(timeout);
|
|||
|
}
|
|||
|
function nextTick(fun) {
|
|||
|
var args = new Array(arguments.length - 1);
|
|||
|
if (arguments.length > 1) {
|
|||
|
for (var i = 1; i < arguments.length; i++) {
|
|||
|
args[i - 1] = arguments[i];
|
|||
|
}
|
|||
|
}
|
|||
|
queue.push(new Item(fun, args));
|
|||
|
if (queue.length === 1 && !draining) {
|
|||
|
runTimeout(drainQueue);
|
|||
|
}
|
|||
|
}
|
|||
|
// v8 likes predictible objects
|
|||
|
function Item(fun, array) {
|
|||
|
this.fun = fun;
|
|||
|
this.array = array;
|
|||
|
}
|
|||
|
Item.prototype.run = function () {
|
|||
|
this.fun.apply(null, this.array);
|
|||
|
};
|
|||
|
var title = 'browser';
|
|||
|
var platform = 'browser';
|
|||
|
var browser = true;
|
|||
|
var env = {};
|
|||
|
var argv = [];
|
|||
|
var version = ''; // empty string to avoid regexp issues
|
|||
|
var versions = {};
|
|||
|
var release = {};
|
|||
|
var config = {};
|
|||
|
|
|||
|
function noop() {}
|
|||
|
|
|||
|
var on = noop;
|
|||
|
var addListener = noop;
|
|||
|
var once = noop;
|
|||
|
var off = noop;
|
|||
|
var removeListener = noop;
|
|||
|
var removeAllListeners = noop;
|
|||
|
var emit = noop;
|
|||
|
|
|||
|
function binding(name) {
|
|||
|
throw new Error('process.binding is not supported');
|
|||
|
}
|
|||
|
|
|||
|
function cwd () { return '/' }
|
|||
|
function chdir (dir) {
|
|||
|
throw new Error('process.chdir is not supported');
|
|||
|
}function umask() { return 0; }
|
|||
|
|
|||
|
// from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js
|
|||
|
var performance = global$1.performance || {};
|
|||
|
var performanceNow =
|
|||
|
performance.now ||
|
|||
|
performance.mozNow ||
|
|||
|
performance.msNow ||
|
|||
|
performance.oNow ||
|
|||
|
performance.webkitNow ||
|
|||
|
function(){ return (new Date()).getTime() };
|
|||
|
|
|||
|
// generate timestamp or delta
|
|||
|
// see http://nodejs.org/api/process.html#process_process_hrtime
|
|||
|
function hrtime(previousTimestamp){
|
|||
|
var clocktime = performanceNow.call(performance)*1e-3;
|
|||
|
var seconds = Math.floor(clocktime);
|
|||
|
var nanoseconds = Math.floor((clocktime%1)*1e9);
|
|||
|
if (previousTimestamp) {
|
|||
|
seconds = seconds - previousTimestamp[0];
|
|||
|
nanoseconds = nanoseconds - previousTimestamp[1];
|
|||
|
if (nanoseconds<0) {
|
|||
|
seconds--;
|
|||
|
nanoseconds += 1e9;
|
|||
|
}
|
|||
|
}
|
|||
|
return [seconds,nanoseconds]
|
|||
|
}
|
|||
|
|
|||
|
var startTime = new Date();
|
|||
|
function uptime() {
|
|||
|
var currentTime = new Date();
|
|||
|
var dif = currentTime - startTime;
|
|||
|
return dif / 1000;
|
|||
|
}
|
|||
|
|
|||
|
var browser$1 = {
|
|||
|
nextTick: nextTick,
|
|||
|
title: title,
|
|||
|
browser: browser,
|
|||
|
env: env,
|
|||
|
argv: argv,
|
|||
|
version: version,
|
|||
|
versions: versions,
|
|||
|
on: on,
|
|||
|
addListener: addListener,
|
|||
|
once: once,
|
|||
|
off: off,
|
|||
|
removeListener: removeListener,
|
|||
|
removeAllListeners: removeAllListeners,
|
|||
|
emit: emit,
|
|||
|
binding: binding,
|
|||
|
cwd: cwd,
|
|||
|
chdir: chdir,
|
|||
|
umask: umask,
|
|||
|
hrtime: hrtime,
|
|||
|
platform: platform,
|
|||
|
release: release,
|
|||
|
config: config,
|
|||
|
uptime: uptime
|
|||
|
};
|
|||
|
|
|||
|
var lib$1 = {};
|
|||
|
|
|||
|
Object.defineProperty(lib$1, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
|
|||
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
|
|||
|
|
|||
|
/* global window self */
|
|||
|
|
|||
|
var isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
|||
|
|
|||
|
/* eslint-disable no-restricted-globals */
|
|||
|
var isWebWorker = (typeof self === 'undefined' ? 'undefined' : _typeof(self)) === 'object' && self.constructor && self.constructor.name === 'DedicatedWorkerGlobalScope';
|
|||
|
/* eslint-enable no-restricted-globals */
|
|||
|
|
|||
|
var isNode = typeof browser$1 !== 'undefined' && browser$1.versions != null && browser$1.versions.node != null;
|
|||
|
|
|||
|
/**
|
|||
|
* @see https://github.com/jsdom/jsdom/releases/tag/12.0.0
|
|||
|
* @see https://github.com/jsdom/jsdom/issues/1537
|
|||
|
*/
|
|||
|
/* eslint-disable no-undef */
|
|||
|
var isJsDom = function isJsDom() {
|
|||
|
return typeof window !== 'undefined' && window.name === 'nodejs' || navigator.userAgent.includes('Node.js') || navigator.userAgent.includes('jsdom');
|
|||
|
};
|
|||
|
|
|||
|
lib$1.isBrowser = isBrowser;
|
|||
|
lib$1.isWebWorker = isWebWorker;
|
|||
|
var isNode_1 = lib$1.isNode = isNode;
|
|||
|
lib$1.isJsDom = isJsDom;
|
|||
|
|
|||
|
var isFQDN$1 = {exports: {}};
|
|||
|
|
|||
|
var merge$1 = {exports: {}};
|
|||
|
|
|||
|
(function (module, exports) {
|
|||
|
|
|||
|
Object.defineProperty(exports, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
exports.default = merge;
|
|||
|
|
|||
|
function merge() {
|
|||
|
var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|||
|
var defaults = arguments.length > 1 ? arguments[1] : undefined;
|
|||
|
|
|||
|
for (var key in defaults) {
|
|||
|
if (typeof obj[key] === 'undefined') {
|
|||
|
obj[key] = defaults[key];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return obj;
|
|||
|
}
|
|||
|
|
|||
|
module.exports = exports.default;
|
|||
|
module.exports.default = exports.default;
|
|||
|
} (merge$1, merge$1.exports));
|
|||
|
|
|||
|
var mergeExports = merge$1.exports;
|
|||
|
|
|||
|
(function (module, exports) {
|
|||
|
|
|||
|
Object.defineProperty(exports, "__esModule", {
|
|||
|
value: true
|
|||
|
});
|
|||
|
exports.default = isFQDN;
|
|||
|
|
|||
|
var _assertString = _interopRequireDefault(assertStringExports);
|
|||
|
|
|||
|
var _merge = _interopRequireDefault(mergeExports);
|
|||
|
|
|||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|||
|
|
|||
|
var default_fqdn_options = {
|
|||
|
require_tld: true,
|
|||
|
allow_underscores: false,
|
|||
|
allow_trailing_dot: false,
|
|||
|
allow_numeric_tld: false,
|
|||
|
allow_wildcard: false,
|
|||
|
ignore_max_length: false
|
|||
|
};
|
|||
|
|
|||
|
function isFQDN(str, options) {
|
|||
|
(0, _assertString.default)(str);
|
|||
|
options = (0, _merge.default)(options, default_fqdn_options);
|
|||
|
/* Remove the optional trailing dot before checking validity */
|
|||
|
|
|||
|
if (options.allow_trailing_dot && str[str.length - 1] === '.') {
|
|||
|
str = str.substring(0, str.length - 1);
|
|||
|
}
|
|||
|
/* Remove the optional wildcard before checking validity */
|
|||
|
|
|||
|
|
|||
|
if (options.allow_wildcard === true && str.indexOf('*.') === 0) {
|
|||
|
str = str.substring(2);
|
|||
|
}
|
|||
|
|
|||
|
var parts = str.split('.');
|
|||
|
var tld = parts[parts.length - 1];
|
|||
|
|
|||
|
if (options.require_tld) {
|
|||
|
// disallow fqdns without tld
|
|||
|
if (parts.length < 2) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (!options.allow_numeric_tld && !/^([a-z\u00A1-\u00A8\u00AA-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}|xn[a-z0-9-]{2,})$/i.test(tld)) {
|
|||
|
return false;
|
|||
|
} // disallow spaces
|
|||
|
|
|||
|
|
|||
|
if (/\s/.test(tld)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
} // reject numeric TLDs
|
|||
|
|
|||
|
|
|||
|
if (!options.allow_numeric_tld && /^\d+$/.test(tld)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return parts.every(function (part) {
|
|||
|
if (part.length > 63 && !options.ignore_max_length) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (!/^[a-z_\u00a1-\uffff0-9-]+$/i.test(part)) {
|
|||
|
return false;
|
|||
|
} // disallow full-width chars
|
|||
|
|
|||
|
|
|||
|
if (/[\uff01-\uff5e]/.test(part)) {
|
|||
|
return false;
|
|||
|
} // disallow parts starting or ending with hyphen
|
|||
|
|
|||
|
|
|||
|
if (/^-|-$/.test(part)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (!options.allow_underscores && /_/.test(part)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
module.exports = exports.default;
|
|||
|
module.exports.default = exports.default;
|
|||
|
} (isFQDN$1, isFQDN$1.exports));
|
|||
|
|
|||
|
var isFQDNExports = isFQDN$1.exports;
|
|||
|
var isFQDN = /*@__PURE__*/getDefaultExportFromCjs(isFQDNExports);
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
/**
|
|||
|
* Contains enums
|
|||
|
* @module enums
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* The proxy policy that decides how to fetch a proof
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const ProxyPolicy = {
|
|||
|
/** Proxy usage decision depends on environment and service provider */
|
|||
|
ADAPTIVE: 'adaptive',
|
|||
|
/** Always use a proxy */
|
|||
|
ALWAYS: 'always',
|
|||
|
/** Never use a proxy, skip a verification if a proxy is inevitable */
|
|||
|
NEVER: 'never'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Methods for fetching proofs
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const Fetcher = {
|
|||
|
/** HTTP requests to ActivityPub */
|
|||
|
ACTIVITYPUB: 'activitypub',
|
|||
|
/** DNS module from Node.js */
|
|||
|
DNS: 'dns',
|
|||
|
/** GraphQL over HTTP requests */
|
|||
|
GRAPHQL: 'graphql',
|
|||
|
/** Basic HTTP requests */
|
|||
|
HTTP: 'http',
|
|||
|
/** IRC module from Node.js */
|
|||
|
IRC: 'irc',
|
|||
|
/** HTTP request to Matrix API */
|
|||
|
MATRIX: 'matrix',
|
|||
|
/** HTTP request to Telegram API */
|
|||
|
TELEGRAM: 'telegram',
|
|||
|
/** XMPP module from Node.js */
|
|||
|
XMPP: 'xmpp'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Entity encoding format
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const EntityEncodingFormat = {
|
|||
|
/** No special formatting */
|
|||
|
PLAIN: 'plain',
|
|||
|
/** HTML encoded entities */
|
|||
|
HTML: 'html',
|
|||
|
/** XML encoded entities */
|
|||
|
XML: 'xml'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Levels of access restriction for proof fetching
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const ProofAccess = {
|
|||
|
/** Any HTTP request will work */
|
|||
|
GENERIC: 'generic',
|
|||
|
/** CORS requests are denied */
|
|||
|
NOCORS: 'nocors',
|
|||
|
/** HTTP requests must contain API or access tokens */
|
|||
|
GRANTED: 'granted',
|
|||
|
/** Not accessible by HTTP request, needs server software */
|
|||
|
SERVER: 'server'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Format of proof
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const ProofFormat = {
|
|||
|
/** JSON format */
|
|||
|
JSON: 'json',
|
|||
|
/** Plaintext format */
|
|||
|
TEXT: 'text'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Format of claim
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const ClaimFormat = {
|
|||
|
/** `openpgp4fpr:123123123` */
|
|||
|
URI: 'uri',
|
|||
|
/** `123123123` */
|
|||
|
FINGERPRINT: 'fingerprint'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* How to find the claim inside the proof's JSON data
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const ClaimRelation = {
|
|||
|
/** Claim is somewhere in the JSON field's textual content */
|
|||
|
CONTAINS: 'contains',
|
|||
|
/** Claim is equal to the JSON field's textual content */
|
|||
|
EQUALS: 'equals',
|
|||
|
/** Claim is equal to an element of the JSON field's array of strings */
|
|||
|
ONEOF: 'oneof'
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Status of the Claim instance
|
|||
|
* @readonly
|
|||
|
* @enum {string}
|
|||
|
*/
|
|||
|
const ClaimStatus = {
|
|||
|
/** Claim has been initialized */
|
|||
|
INIT: 'init',
|
|||
|
/** Claim has matched its URI to candidate claim definitions */
|
|||
|
MATCHED: 'matched',
|
|||
|
/** Claim has verified one or multiple candidate claim definitions */
|
|||
|
VERIFIED: 'verified'
|
|||
|
};
|
|||
|
|
|||
|
var enums = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
ClaimFormat: ClaimFormat,
|
|||
|
ClaimRelation: ClaimRelation,
|
|||
|
ClaimStatus: ClaimStatus,
|
|||
|
EntityEncodingFormat: EntityEncodingFormat,
|
|||
|
Fetcher: Fetcher,
|
|||
|
ProofAccess: ProofAccess,
|
|||
|
ProofFormat: ProofFormat,
|
|||
|
ProxyPolicy: ProxyPolicy
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @module utils
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Generate an URL to request data from a proxy server
|
|||
|
* @param {string} type - The name of the fetcher the proxy must use
|
|||
|
* @param {object} data - The data the proxy must provide to the fetcher
|
|||
|
* @param {object} opts - Options to enable the request
|
|||
|
* @param {object} opts.proxy - Proxy related options
|
|||
|
* @param {object} opts.proxy.scheme - The scheme used by the proxy server
|
|||
|
* @param {object} opts.proxy.hostname - The hostname of the proxy server
|
|||
|
* @returns {string}
|
|||
|
*/
|
|||
|
function generateProxyURL (type, data, opts) {
|
|||
|
try {
|
|||
|
isFQDN(opts.proxy.hostname);
|
|||
|
} catch (err) {
|
|||
|
throw new Error('Invalid proxy hostname')
|
|||
|
}
|
|||
|
|
|||
|
const queryStrings = [];
|
|||
|
|
|||
|
Object.keys(data).forEach((key) => {
|
|||
|
queryStrings.push(`${key}=${encodeURIComponent(data[key])}`);
|
|||
|
});
|
|||
|
|
|||
|
const scheme = opts.proxy.scheme ? opts.proxy.scheme : 'https';
|
|||
|
|
|||
|
return `${scheme}://${opts.proxy.hostname}/api/2/get/${type}?${queryStrings.join(
|
|||
|
'&'
|
|||
|
)}`
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Generate the string that must be found in the proof to verify a claim
|
|||
|
* @param {string} fingerprint - The fingerprint of the claim
|
|||
|
* @param {string} format - The claim's format (see {@link module:enums~ClaimFormat|enums.ClaimFormat})
|
|||
|
* @returns {string}
|
|||
|
*/
|
|||
|
function generateClaim (fingerprint, format) {
|
|||
|
switch (format) {
|
|||
|
case ClaimFormat.URI:
|
|||
|
if (fingerprint.match(/^(openpgp4fpr|aspe):/)) {
|
|||
|
return fingerprint
|
|||
|
}
|
|||
|
return `openpgp4fpr:${fingerprint}`
|
|||
|
case ClaimFormat.FINGERPRINT:
|
|||
|
return fingerprint
|
|||
|
default:
|
|||
|
throw new Error('No valid claim format')
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get the URIs from a string and return them as an array
|
|||
|
* @param {string} text - The text that may contain URIs
|
|||
|
* @returns {Array<string>}
|
|||
|
*/
|
|||
|
function getUriFromString (text) {
|
|||
|
const re = /((([A-Za-z0-9]+:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www\.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w\-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[.!/\\\w]*))?)/gi;
|
|||
|
const res = text.match(re);
|
|||
|
|
|||
|
const urls = [];
|
|||
|
|
|||
|
if (!res) {
|
|||
|
return []
|
|||
|
}
|
|||
|
|
|||
|
res.forEach(url => {
|
|||
|
// Remove bad trailing characters
|
|||
|
let hasBadTrailingChars = true;
|
|||
|
|
|||
|
while (hasBadTrailingChars) {
|
|||
|
const lastChar = url.charAt(url.length - 1);
|
|||
|
if ('?!.'.indexOf(lastChar) === -1) {
|
|||
|
hasBadTrailingChars = false;
|
|||
|
continue
|
|||
|
}
|
|||
|
url = url.substring(0, url.length - 1);
|
|||
|
}
|
|||
|
|
|||
|
urls.push(url);
|
|||
|
});
|
|||
|
|
|||
|
return urls
|
|||
|
}
|
|||
|
|
|||
|
var utils$9 = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
generateClaim: generateClaim,
|
|||
|
generateProxyURL: generateProxyURL,
|
|||
|
getUriFromString: getUriFromString
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @module proofs
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Delegate the proof request to the correct fetcher.
|
|||
|
* This method uses the current environment (browser/node), certain values from
|
|||
|
* the `data` parameter and the proxy policy set in the `opts` parameter to
|
|||
|
* choose the right approach to fetch the proof. An error will be thrown if no
|
|||
|
* approach is possible.
|
|||
|
* @async
|
|||
|
* @param {object} data - Data from a claim definition
|
|||
|
* @param {object} opts - Options to enable the request
|
|||
|
* @returns {Promise<object|string>}
|
|||
|
*/
|
|||
|
async function fetch$2 (data, opts) {
|
|||
|
switch (data.proof.request.fetcher) {
|
|||
|
case Fetcher.HTTP:
|
|||
|
data.proof.request.data.format = data.proof.request.format;
|
|||
|
break
|
|||
|
}
|
|||
|
|
|||
|
if (isNode_1) {
|
|||
|
return handleNodeRequests(data, opts)
|
|||
|
}
|
|||
|
|
|||
|
return handleBrowserRequests(data, opts)
|
|||
|
}
|
|||
|
|
|||
|
const handleBrowserRequests = (data, opts) => {
|
|||
|
switch (opts.proxy.policy) {
|
|||
|
case ProxyPolicy.ALWAYS:
|
|||
|
return createProxyRequestPromise(data, opts)
|
|||
|
|
|||
|
case ProxyPolicy.NEVER:
|
|||
|
switch (data.proof.request.access) {
|
|||
|
case ProofAccess.GENERIC:
|
|||
|
case ProofAccess.GRANTED:
|
|||
|
return createDefaultRequestPromise(data, opts)
|
|||
|
case ProofAccess.NOCORS:
|
|||
|
case ProofAccess.SERVER:
|
|||
|
throw new Error(
|
|||
|
'Impossible to fetch proof (bad combination of service access and proxy policy)'
|
|||
|
)
|
|||
|
default:
|
|||
|
throw new Error('Invalid proof access value')
|
|||
|
}
|
|||
|
|
|||
|
case ProxyPolicy.ADAPTIVE:
|
|||
|
switch (data.proof.request.access) {
|
|||
|
case ProofAccess.GENERIC:
|
|||
|
return createFallbackRequestPromise(data, opts)
|
|||
|
case ProofAccess.NOCORS:
|
|||
|
return createProxyRequestPromise(data, opts)
|
|||
|
case ProofAccess.GRANTED:
|
|||
|
return createFallbackRequestPromise(data, opts)
|
|||
|
case ProofAccess.SERVER:
|
|||
|
return createProxyRequestPromise(data, opts)
|
|||
|
default:
|
|||
|
throw new Error('Invalid proof access value')
|
|||
|
}
|
|||
|
|
|||
|
default:
|
|||
|
throw new Error('Invalid proxy policy')
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
const handleNodeRequests = (data, opts) => {
|
|||
|
switch (opts.proxy.policy) {
|
|||
|
case ProxyPolicy.ALWAYS:
|
|||
|
return createProxyRequestPromise(data, opts)
|
|||
|
|
|||
|
case ProxyPolicy.NEVER:
|
|||
|
return createDefaultRequestPromise(data, opts)
|
|||
|
|
|||
|
case ProxyPolicy.ADAPTIVE:
|
|||
|
return createFallbackRequestPromise(data, opts)
|
|||
|
|
|||
|
default:
|
|||
|
throw new Error('Invalid proxy policy')
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
const createDefaultRequestPromise = (data, opts) => {
|
|||
|
return new Promise((resolve, reject) => {
|
|||
|
fetcher__namespace[data.proof.request.fetcher]
|
|||
|
.fn(data.proof.request.data, opts)
|
|||
|
.then((res) => {
|
|||
|
return resolve({
|
|||
|
fetcher: data.proof.request.fetcher,
|
|||
|
data,
|
|||
|
viaProxy: false,
|
|||
|
result: res
|
|||
|
})
|
|||
|
})
|
|||
|
.catch((err) => {
|
|||
|
return reject(err)
|
|||
|
});
|
|||
|
})
|
|||
|
};
|
|||
|
|
|||
|
const createProxyRequestPromise = (data, opts) => {
|
|||
|
return new Promise((resolve, reject) => {
|
|||
|
let proxyUrl;
|
|||
|
try {
|
|||
|
proxyUrl = generateProxyURL(
|
|||
|
data.proof.request.fetcher,
|
|||
|
data.proof.request.data,
|
|||
|
opts
|
|||
|
);
|
|||
|
} catch (err) {
|
|||
|
reject(err);
|
|||
|
}
|
|||
|
|
|||
|
const requestData = {
|
|||
|
url: proxyUrl,
|
|||
|
format: data.proof.request.format,
|
|||
|
fetcherTimeout: fetcher__namespace[data.proof.request.fetcher].timeout
|
|||
|
};
|
|||
|
fetcher__namespace.http
|
|||
|
.fn(requestData, opts)
|
|||
|
.then((res) => {
|
|||
|
return resolve({
|
|||
|
fetcher: 'http',
|
|||
|
data,
|
|||
|
viaProxy: true,
|
|||
|
result: res
|
|||
|
})
|
|||
|
})
|
|||
|
.catch((err) => {
|
|||
|
return reject(err)
|
|||
|
});
|
|||
|
})
|
|||
|
};
|
|||
|
|
|||
|
const createFallbackRequestPromise = (data, opts) => {
|
|||
|
return new Promise((resolve, reject) => {
|
|||
|
createDefaultRequestPromise(data, opts)
|
|||
|
.then((res) => {
|
|||
|
return resolve(res)
|
|||
|
})
|
|||
|
.catch((err1) => {
|
|||
|
createProxyRequestPromise(data, opts)
|
|||
|
.then((res) => {
|
|||
|
return resolve(res)
|
|||
|
})
|
|||
|
.catch((err2) => {
|
|||
|
return reject(err2)
|
|||
|
});
|
|||
|
});
|
|||
|
})
|
|||
|
};
|
|||
|
|
|||
|
var proofs = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
fetch: fetch$2
|
|||
|
});
|
|||
|
|
|||
|
/*!
|
|||
|
* hash-wasm (https://www.npmjs.com/package/hash-wasm)
|
|||
|
* (c) Dani Biro
|
|||
|
* @license MIT
|
|||
|
*/
|
|||
|
|
|||
|
/*! *****************************************************************************
|
|||
|
Copyright (c) Microsoft Corporation.
|
|||
|
|
|||
|
Permission to use, copy, modify, and/or distribute this software for any
|
|||
|
purpose with or without fee is hereby granted.
|
|||
|
|
|||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|||
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|||
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|||
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|||
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|||
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|||
|
PERFORMANCE OF THIS SOFTWARE.
|
|||
|
***************************************************************************** */
|
|||
|
|
|||
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|||
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|||
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
class Mutex {
|
|||
|
constructor() {
|
|||
|
this.mutex = Promise.resolve();
|
|||
|
}
|
|||
|
lock() {
|
|||
|
let begin = () => { };
|
|||
|
this.mutex = this.mutex.then(() => new Promise(begin));
|
|||
|
return new Promise((res) => {
|
|||
|
begin = res;
|
|||
|
});
|
|||
|
}
|
|||
|
dispatch(fn) {
|
|||
|
return __awaiter(this, void 0, void 0, function* () {
|
|||
|
const unlock = yield this.lock();
|
|||
|
try {
|
|||
|
return yield Promise.resolve(fn());
|
|||
|
}
|
|||
|
finally {
|
|||
|
unlock();
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* eslint-disable import/prefer-default-export */
|
|||
|
/* eslint-disable no-bitwise */
|
|||
|
var _a$1;
|
|||
|
function getGlobal() {
|
|||
|
if (typeof globalThis !== 'undefined')
|
|||
|
return globalThis;
|
|||
|
// eslint-disable-next-line no-restricted-globals
|
|||
|
if (typeof self !== 'undefined')
|
|||
|
return self;
|
|||
|
if (typeof window !== 'undefined')
|
|||
|
return window;
|
|||
|
return global$1;
|
|||
|
}
|
|||
|
const globalObject = getGlobal();
|
|||
|
const nodeBuffer = (_a$1 = globalObject.Buffer) !== null && _a$1 !== void 0 ? _a$1 : null;
|
|||
|
const textEncoder = globalObject.TextEncoder ? new globalObject.TextEncoder() : null;
|
|||
|
function hexCharCodesToInt(a, b) {
|
|||
|
return (((a & 0xF) + ((a >> 6) | ((a >> 3) & 0x8))) << 4) | ((b & 0xF) + ((b >> 6) | ((b >> 3) & 0x8)));
|
|||
|
}
|
|||
|
function writeHexToUInt8(buf, str) {
|
|||
|
const size = str.length >> 1;
|
|||
|
for (let i = 0; i < size; i++) {
|
|||
|
const index = i << 1;
|
|||
|
buf[i] = hexCharCodesToInt(str.charCodeAt(index), str.charCodeAt(index + 1));
|
|||
|
}
|
|||
|
}
|
|||
|
function hexStringEqualsUInt8(str, buf) {
|
|||
|
if (str.length !== buf.length * 2) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
for (let i = 0; i < buf.length; i++) {
|
|||
|
const strIndex = i << 1;
|
|||
|
if (buf[i] !== hexCharCodesToInt(str.charCodeAt(strIndex), str.charCodeAt(strIndex + 1))) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
const alpha = 'a'.charCodeAt(0) - 10;
|
|||
|
const digit = '0'.charCodeAt(0);
|
|||
|
function getDigestHex(tmpBuffer, input, hashLength) {
|
|||
|
let p = 0;
|
|||
|
/* eslint-disable no-plusplus */
|
|||
|
for (let i = 0; i < hashLength; i++) {
|
|||
|
let nibble = input[i] >>> 4;
|
|||
|
tmpBuffer[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
|
|||
|
nibble = input[i] & 0xF;
|
|||
|
tmpBuffer[p++] = nibble > 9 ? nibble + alpha : nibble + digit;
|
|||
|
}
|
|||
|
/* eslint-enable no-plusplus */
|
|||
|
return String.fromCharCode.apply(null, tmpBuffer);
|
|||
|
}
|
|||
|
const getUInt8Buffer = nodeBuffer !== null
|
|||
|
? (data) => {
|
|||
|
if (typeof data === 'string') {
|
|||
|
const buf = nodeBuffer.from(data, 'utf8');
|
|||
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.length);
|
|||
|
}
|
|||
|
if (nodeBuffer.isBuffer(data)) {
|
|||
|
return new Uint8Array(data.buffer, data.byteOffset, data.length);
|
|||
|
}
|
|||
|
if (ArrayBuffer.isView(data)) {
|
|||
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|||
|
}
|
|||
|
throw new Error('Invalid data type!');
|
|||
|
}
|
|||
|
: (data) => {
|
|||
|
if (typeof data === 'string') {
|
|||
|
return textEncoder.encode(data);
|
|||
|
}
|
|||
|
if (ArrayBuffer.isView(data)) {
|
|||
|
return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|||
|
}
|
|||
|
throw new Error('Invalid data type!');
|
|||
|
};
|
|||
|
const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|||
|
const base64Lookup = new Uint8Array(256);
|
|||
|
for (let i = 0; i < base64Chars.length; i++) {
|
|||
|
base64Lookup[base64Chars.charCodeAt(i)] = i;
|
|||
|
}
|
|||
|
function encodeBase64$1(data, pad = true) {
|
|||
|
const len = data.length;
|
|||
|
const extraBytes = len % 3;
|
|||
|
const parts = [];
|
|||
|
const len2 = len - extraBytes;
|
|||
|
for (let i = 0; i < len2; i += 3) {
|
|||
|
const tmp = ((data[i] << 16) & 0xFF0000)
|
|||
|
+ ((data[i + 1] << 8) & 0xFF00)
|
|||
|
+ (data[i + 2] & 0xFF);
|
|||
|
const triplet = base64Chars.charAt((tmp >> 18) & 0x3F)
|
|||
|
+ base64Chars.charAt((tmp >> 12) & 0x3F)
|
|||
|
+ base64Chars.charAt((tmp >> 6) & 0x3F)
|
|||
|
+ base64Chars.charAt(tmp & 0x3F);
|
|||
|
parts.push(triplet);
|
|||
|
}
|
|||
|
if (extraBytes === 1) {
|
|||
|
const tmp = data[len - 1];
|
|||
|
const a = base64Chars.charAt(tmp >> 2);
|
|||
|
const b = base64Chars.charAt((tmp << 4) & 0x3F);
|
|||
|
parts.push(`${a}${b}`);
|
|||
|
if (pad) {
|
|||
|
parts.push('==');
|
|||
|
}
|
|||
|
}
|
|||
|
else if (extraBytes === 2) {
|
|||
|
const tmp = (data[len - 2] << 8) + data[len - 1];
|
|||
|
const a = base64Chars.charAt(tmp >> 10);
|
|||
|
const b = base64Chars.charAt((tmp >> 4) & 0x3F);
|
|||
|
const c = base64Chars.charAt((tmp << 2) & 0x3F);
|
|||
|
parts.push(`${a}${b}${c}`);
|
|||
|
if (pad) {
|
|||
|
parts.push('=');
|
|||
|
}
|
|||
|
}
|
|||
|
return parts.join('');
|
|||
|
}
|
|||
|
function getDecodeBase64Length(data) {
|
|||
|
let bufferLength = Math.floor(data.length * 0.75);
|
|||
|
const len = data.length;
|
|||
|
if (data[len - 1] === '=') {
|
|||
|
bufferLength -= 1;
|
|||
|
if (data[len - 2] === '=') {
|
|||
|
bufferLength -= 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return bufferLength;
|
|||
|
}
|
|||
|
function decodeBase64$1(data) {
|
|||
|
const bufferLength = getDecodeBase64Length(data);
|
|||
|
const len = data.length;
|
|||
|
const bytes = new Uint8Array(bufferLength);
|
|||
|
let p = 0;
|
|||
|
for (let i = 0; i < len; i += 4) {
|
|||
|
const encoded1 = base64Lookup[data.charCodeAt(i)];
|
|||
|
const encoded2 = base64Lookup[data.charCodeAt(i + 1)];
|
|||
|
const encoded3 = base64Lookup[data.charCodeAt(i + 2)];
|
|||
|
const encoded4 = base64Lookup[data.charCodeAt(i + 3)];
|
|||
|
bytes[p] = (encoded1 << 2) | (encoded2 >> 4);
|
|||
|
p += 1;
|
|||
|
bytes[p] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
|
|||
|
p += 1;
|
|||
|
bytes[p] = ((encoded3 & 3) << 6) | (encoded4 & 63);
|
|||
|
p += 1;
|
|||
|
}
|
|||
|
return bytes;
|
|||
|
}
|
|||
|
|
|||
|
const MAX_HEAP = 16 * 1024;
|
|||
|
const WASM_FUNC_HASH_LENGTH = 4;
|
|||
|
const wasmMutex = new Mutex();
|
|||
|
const wasmModuleCache = new Map();
|
|||
|
function WASMInterface(binary, hashLength) {
|
|||
|
return __awaiter(this, void 0, void 0, function* () {
|
|||
|
let wasmInstance = null;
|
|||
|
let memoryView = null;
|
|||
|
let initialized = false;
|
|||
|
if (typeof WebAssembly === 'undefined') {
|
|||
|
throw new Error('WebAssembly is not supported in this environment!');
|
|||
|
}
|
|||
|
const writeMemory = (data, offset = 0) => {
|
|||
|
memoryView.set(data, offset);
|
|||
|
};
|
|||
|
const getMemory = () => memoryView;
|
|||
|
const getExports = () => wasmInstance.exports;
|
|||
|
const setMemorySize = (totalSize) => {
|
|||
|
wasmInstance.exports.Hash_SetMemorySize(totalSize);
|
|||
|
const arrayOffset = wasmInstance.exports.Hash_GetBuffer();
|
|||
|
const memoryBuffer = wasmInstance.exports.memory.buffer;
|
|||
|
memoryView = new Uint8Array(memoryBuffer, arrayOffset, totalSize);
|
|||
|
};
|
|||
|
const getStateSize = () => {
|
|||
|
const view = new DataView(wasmInstance.exports.memory.buffer);
|
|||
|
const stateSize = view.getUint32(wasmInstance.exports.STATE_SIZE, true);
|
|||
|
return stateSize;
|
|||
|
};
|
|||
|
const loadWASMPromise = wasmMutex.dispatch(() => __awaiter(this, void 0, void 0, function* () {
|
|||
|
if (!wasmModuleCache.has(binary.name)) {
|
|||
|
const asm = decodeBase64$1(binary.data);
|
|||
|
const promise = WebAssembly.compile(asm);
|
|||
|
wasmModuleCache.set(binary.name, promise);
|
|||
|
}
|
|||
|
const module = yield wasmModuleCache.get(binary.name);
|
|||
|
wasmInstance = yield WebAssembly.instantiate(module, {
|
|||
|
// env: {
|
|||
|
// emscripten_memcpy_big: (dest, src, num) => {
|
|||
|
// const memoryBuffer = wasmInstance.exports.memory.buffer;
|
|||
|
// const memView = new Uint8Array(memoryBuffer, 0);
|
|||
|
// memView.set(memView.subarray(src, src + num), dest);
|
|||
|
// },
|
|||
|
// print_memory: (offset, len) => {
|
|||
|
// const memoryBuffer = wasmInstance.exports.memory.buffer;
|
|||
|
// const memView = new Uint8Array(memoryBuffer, 0);
|
|||
|
// console.log('print_int32', memView.subarray(offset, offset + len));
|
|||
|
// },
|
|||
|
// },
|
|||
|
});
|
|||
|
// wasmInstance.exports._start();
|
|||
|
}));
|
|||
|
const setupInterface = () => __awaiter(this, void 0, void 0, function* () {
|
|||
|
if (!wasmInstance) {
|
|||
|
yield loadWASMPromise;
|
|||
|
}
|
|||
|
const arrayOffset = wasmInstance.exports.Hash_GetBuffer();
|
|||
|
const memoryBuffer = wasmInstance.exports.memory.buffer;
|
|||
|
memoryView = new Uint8Array(memoryBuffer, arrayOffset, MAX_HEAP);
|
|||
|
});
|
|||
|
const init = (bits = null) => {
|
|||
|
initialized = true;
|
|||
|
wasmInstance.exports.Hash_Init(bits);
|
|||
|
};
|
|||
|
const updateUInt8Array = (data) => {
|
|||
|
let read = 0;
|
|||
|
while (read < data.length) {
|
|||
|
const chunk = data.subarray(read, read + MAX_HEAP);
|
|||
|
read += chunk.length;
|
|||
|
memoryView.set(chunk);
|
|||
|
wasmInstance.exports.Hash_Update(chunk.length);
|
|||
|
}
|
|||
|
};
|
|||
|
const update = (data) => {
|
|||
|
if (!initialized) {
|
|||
|
throw new Error('update() called before init()');
|
|||
|
}
|
|||
|
const Uint8Buffer = getUInt8Buffer(data);
|
|||
|
updateUInt8Array(Uint8Buffer);
|
|||
|
};
|
|||
|
const digestChars = new Uint8Array(hashLength * 2);
|
|||
|
const digest = (outputType, padding = null) => {
|
|||
|
if (!initialized) {
|
|||
|
throw new Error('digest() called before init()');
|
|||
|
}
|
|||
|
initialized = false;
|
|||
|
wasmInstance.exports.Hash_Final(padding);
|
|||
|
if (outputType === 'binary') {
|
|||
|
// the data is copied to allow GC of the original memory object
|
|||
|
return memoryView.slice(0, hashLength);
|
|||
|
}
|
|||
|
return getDigestHex(digestChars, memoryView, hashLength);
|
|||
|
};
|
|||
|
const save = () => {
|
|||
|
if (!initialized) {
|
|||
|
throw new Error('save() can only be called after init() and before digest()');
|
|||
|
}
|
|||
|
const stateOffset = wasmInstance.exports.Hash_GetState();
|
|||
|
const stateLength = getStateSize();
|
|||
|
const memoryBuffer = wasmInstance.exports.memory.buffer;
|
|||
|
const internalState = new Uint8Array(memoryBuffer, stateOffset, stateLength);
|
|||
|
// prefix is 4 bytes from SHA1 hash of the WASM binary
|
|||
|
// it is used to detect incompatible internal states between different versions of hash-wasm
|
|||
|
const prefixedState = new Uint8Array(WASM_FUNC_HASH_LENGTH + stateLength);
|
|||
|
writeHexToUInt8(prefixedState, binary.hash);
|
|||
|
prefixedState.set(internalState, WASM_FUNC_HASH_LENGTH);
|
|||
|
return prefixedState;
|
|||
|
};
|
|||
|
const load = (state) => {
|
|||
|
if (!(state instanceof Uint8Array)) {
|
|||
|
throw new Error('load() expects an Uint8Array generated by save()');
|
|||
|
}
|
|||
|
const stateOffset = wasmInstance.exports.Hash_GetState();
|
|||
|
const stateLength = getStateSize();
|
|||
|
const overallLength = WASM_FUNC_HASH_LENGTH + stateLength;
|
|||
|
const memoryBuffer = wasmInstance.exports.memory.buffer;
|
|||
|
if (state.length !== overallLength) {
|
|||
|
throw new Error(`Bad state length (expected ${overallLength} bytes, got ${state.length})`);
|
|||
|
}
|
|||
|
if (!hexStringEqualsUInt8(binary.hash, state.subarray(0, WASM_FUNC_HASH_LENGTH))) {
|
|||
|
throw new Error('This state was written by an incompatible hash implementation');
|
|||
|
}
|
|||
|
const internalState = state.subarray(WASM_FUNC_HASH_LENGTH);
|
|||
|
new Uint8Array(memoryBuffer, stateOffset, stateLength).set(internalState);
|
|||
|
initialized = true;
|
|||
|
};
|
|||
|
const isDataShort = (data) => {
|
|||
|
if (typeof data === 'string') {
|
|||
|
// worst case is 4 bytes / char
|
|||
|
return data.length < MAX_HEAP / 4;
|
|||
|
}
|
|||
|
return data.byteLength < MAX_HEAP;
|
|||
|
};
|
|||
|
let canSimplify = isDataShort;
|
|||
|
switch (binary.name) {
|
|||
|
case 'argon2':
|
|||
|
case 'scrypt':
|
|||
|
canSimplify = () => true;
|
|||
|
break;
|
|||
|
case 'blake2b':
|
|||
|
case 'blake2s':
|
|||
|
// if there is a key at blake2 then cannot simplify
|
|||
|
canSimplify = (data, initParam) => initParam <= 512 && isDataShort(data);
|
|||
|
break;
|
|||
|
case 'blake3':
|
|||
|
// if there is a key at blake3 then cannot simplify
|
|||
|
canSimplify = (data, initParam) => initParam === 0 && isDataShort(data);
|
|||
|
break;
|
|||
|
case 'xxhash64': // cannot simplify
|
|||
|
case 'xxhash3':
|
|||
|
case 'xxhash128':
|
|||
|
canSimplify = () => false;
|
|||
|
break;
|
|||
|
}
|
|||
|
// shorthand for (init + update + digest) for better performance
|
|||
|
const calculate = (data, initParam = null, digestParam = null) => {
|
|||
|
if (!canSimplify(data, initParam)) {
|
|||
|
init(initParam);
|
|||
|
update(data);
|
|||
|
return digest('hex', digestParam);
|
|||
|
}
|
|||
|
const buffer = getUInt8Buffer(data);
|
|||
|
memoryView.set(buffer);
|
|||
|
wasmInstance.exports.Hash_Calculate(buffer.length, initParam, digestParam);
|
|||
|
return getDigestHex(digestChars, memoryView, hashLength);
|
|||
|
};
|
|||
|
yield setupInterface();
|
|||
|
return {
|
|||
|
getMemory,
|
|||
|
writeMemory,
|
|||
|
getExports,
|
|||
|
setMemorySize,
|
|||
|
init,
|
|||
|
update,
|
|||
|
digest,
|
|||
|
save,
|
|||
|
load,
|
|||
|
calculate,
|
|||
|
hashLength,
|
|||
|
};
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
var name$j = "blake2b";
|
|||
|
var data$j = "AGFzbQEAAAABEQRgAAF/YAJ/fwBgAX8AYAAAAwoJAAECAwECAgABBAUBcAEBAQUEAQECAgYOAn8BQbCLBQt/AEGACAsHcAgGbWVtb3J5AgAOSGFzaF9HZXRCdWZmZXIAAApIYXNoX0ZpbmFsAAMJSGFzaF9Jbml0AAULSGFzaF9VcGRhdGUABg1IYXNoX0dldFN0YXRlAAcOSGFzaF9DYWxjdWxhdGUACApTVEFURV9TSVpFAwEKjzkJBQBBgAkL5QICBH8BfgJAIAFBAUgNAAJAAkACQEGAAUEAKALgigEiAmsiAyABSA0AIAEhAwwBC0EAQQA2AuCKAQJAIAJB/wBKDQBBACEEQQAhBQNAIAQgAmpB4IkBaiAAIARqLQAAOgAAIAMgBUEBaiIFQf8BcSIESg0ACwtBAEEAKQPAiQEiBkKAAXw3A8CJAUEAQQApA8iJASAGQv9+Vq18NwPIiQFB4IkBEAIgACADaiEAAkAgASADayIDQYEBSA0AIAIgAWohBANAQQBBACkDwIkBIgZCgAF8NwPAiQFBAEEAKQPIiQEgBkL/flatfDcDyIkBIAAQAiAAQYABaiEAIARBgH9qIgRBgAJKDQALIARBgH9qIQMLIANBAUgNAQtBACEEQQAhBQNAQQAoAuCKASAEakHgiQFqIAAgBGotAAA6AAAgAyAFQQFqIgVB/wFxIgRKDQALC0EAQQAoAuCKASADajYC4IoBCwu/LgEkfkEAIAApA2AiASAAKQNAIgIgACkDSCIDIAIgACkDGCIEIAApA1giBSAAKQMgIgYgAiAAKQMQIgcgASADIAApAwAiCCAAKQNwIgkgACkDOCIKIAggACkDeCILIAApA2giDCAGIAApA1AiDSAAKQMIIg4gCSAKIAApAzAiDyAHIA4gBCAJIA0gCCABIAEgDiACIAYgAyACIAQgB0EAKQOoiQEiEEEAKQOIiQF8fCIRfEEAKQPIiQEgEYVCn9j52cKR2oKbf4VCIIkiEUK7zqqm2NDrs7t/fCISIBCFQiiJIhB8IhMgEYVCMIkiESASfCISIBCFQgGJIhQgDiAIQQApA6CJASIQQQApA4CJASIVfHwiFnxBACkDwIkBIBaFQtGFmu/6z5SH0QCFQiCJIhZCiJLznf/M+YTqAHwiFyAQhUIoiSIYfCIZfHwiEHwgECAKIA9BACkDuIkBIhpBACkDmIkBfHwiG3xBACkD2IkBIBuFQvnC+JuRo7Pw2wCFQiCJIhtC8e30+KWn/aelf3wiHCAahUIoiSIafCIdIBuFQjCJIhuFQiCJIh4gACkDKCIQIAZBACkDsIkBIh9BACkDkIkBfHwiIHxBACkD0IkBICCFQuv6htq/tfbBH4VCIIkiIEKr8NP0r+68tzx8IiEgH4VCKIkiH3wiIiAghUIwiSIgICF8IiF8IiMgFIVCKIkiFHwiJCAehUIwiSIeICN8IiMgFIVCAYkiFCAFIA0gISAfhUIBiSIfIBN8fCITfCATIBkgFoVCMIkiFoVCIIkiEyAbIBx8Ihl8IhsgH4VCKIkiHHwiH3x8IiF8IAwgASAZIBqFQgGJIhkgInx8Ihp8IBogEYVCIIkiESAWIBd8IhZ8IhcgGYVCKIkiGXwiGiARhUIwiSIRICGFQiCJIiEgCyAJIB0gFiAYhUIBiSIWfHwiGHwgGCAghUIgiSIYIBJ8IhIgFoVCKIkiFnwiHSAYhUIwiSIYIBJ8IhJ8IiAgFIVCKIkiFHwiIiAhhUIwiSIhICB8IiAgFIVCAYkiFCANIAkgEiAWhUIBiSISICR8fCIWfCAfIBOFQjCJIhMgFoVCIIkiFiARIBd8IhF8IhcgEoVCKIkiEnwiH3x8IiR8ICQgDyAMIBEgGYVCAYkiESAdfHwiGXwgHiAZhUIgiSIZIBMgG3wiE3wiGyARhUIoiSIRfCIdIBmFQjCJIhmFQiCJIh4gCyADIBMgHIVCAYkiEyAafHwiGnwgGCAahUIgiSIYICN8IhogE4VCKIkiE3wiHCAYhUIwiSIYIBp8Ihp8IiMgFIVCKIkiFHwiJCAehUIwiSIeICN8IiMgFIVCAYkiFCAHIAggGiAThUIBiSITICJ8fCIafCAaIB8gFoVCMIkiFoVCIIkiGiAZIBt8Ihl8IhsgE4VCKIkiE3wiH3x8IiJ8IAogBSAZIBGFQgGJIhEgHHx8Ihl8IBkgIYVCIIkiGSAWIBd8IhZ8IhcgEYVCKIkiEXwiHCAZhUIwiSIZICKFQiCJIiEgBCAdIBYgEoVCAYkiEnwgEHwiFnwgFiAYhUIgiSIWICB8IhggEoVCKIkiEnwiHSAWhUIwiSIWIBh8Ihh8IiAgFIVCKIkiFHwiIiAhhUIwiSIhICB8IiAgFIVCAYkiFCACIAUgGCAShUIBiSISICR8fCIYfCAfIBqFQjCJIhogGIVCIIkiGCAZIBd8Ihd8IhkgEoVCKIkiEnwiH3x8IiR8ICQgDCALIBcgEYVCAYkiESAdfHwiF3wgHiAXhUIgiSIXIBogG3wiGnwiGyARhUIoiSIRfCIdIBeFQjCJIheFQiCJIh4gByAaIBOFQgGJIhMgHHwgEHwiGnwgFiAahUIgiSIWICN8IhogE4VCKIkiE3wiHCAWhUIwiSIWIBp8Ihp8IiMgFIVCKIkiFHwiJCAehUIwiSIeICN8IiMgFIVCAYkiFCAPIAQgGiAThUIBiSITICJ8fCIafCAaIB8gGIVCMIkiGIVCIIkiGiAXIBt8Ihd8IhsgE4VCKIkiE3wiH3x8IiJ8IA4gCiAXIBGFQgGJIhEgHHx8Ihd8IBcgIYVCIIkiFyAYIBl8Ihh8IhkgEYVCKIkiEXwiHCAXhUIwiSIXICKFQiCJIiEgBiADIB0gGCAShUIBiSISfHwiGHwgGCAWhUIgiSIWICB8IhggEoVCKIkiEnwiHSAWhUIwiSIWIBh8Ihh8IiAgFIVCKIkiFHwiIiAhhUIwiSIhICB8IiAgFIVCAYkiFCADIAogGCAShUIBiSISICR8fCIYfCAfIBqFQjCJIhogGIVCIIkiGCAXIBl8Ihd8IhkgEoVCKIkiEnwiH3x8IiR8ICQgCSAFIBcgEYVCAYkiESAdfHwiF3wgHiAXhUIgiSIXIBogG3wiGnwiGyARhUIoiSIRfCIdIBeFQjCJIheFQiCJIh4gASAMIBogE4VCAYkiEyAcfHwiGnwgFiAahUIgiSIWICN8IhogE4VCKIkiE3wiHCAWhUIwiSIWIBp8Ihp8IiMgFIVCKIkiFHwiJCAehUIwiSIeICN8IiMgFIVCAYkiFCANIBogE4VCAYkiEyAifCAQfCIafCAaIB8gGIVCMIkiGIVCIIkiGiAXIBt8Ihd8IhsgE4VCKIkiE3wiH3wgEHwiInwgCCAGIBcgEYVCAYkiESAcfHwiF3wgFyAhhUIgiSIXIBggGXwiGHwiGSARhUIoiSIRfCIcIBeFQjCJIhcgIoVCIIkiISACIAsgHSAYIBKFQgGJIhJ8fCIYfCAYIBaFQiCJIhYgIHwiGCAShUIoiSISfCIdIBaFQjCJIhYgGHwiGHwiICAUhUIoiSIUfCIiICGFQjCJIiEgIHwiICAUhUIBiSIUIAggAyAYIBKFQgGJIhIgJHx8Ihh8IB8gGoVCMIkiGiAYhUIgiSIYIBcgGXwiF3wiGSAShUIoiSISfCIffHwiJHwgJCALIA0gFyARhUIBiSIRIB18fCIXfCAeIBeFQiCJIhcgGiAbfCIafCIbIBGFQiiJIhF8Ih0gF4VCMIkiF4VCIIkiHiAGIAcgGiAThUIBiSITIBx8fCIafCAWIBqFQiCJIhYgI3wiGiAThUIoiSITfCIcIBaFQjCJIhYgGnwiGnwiIyAUhUIoiSIUfCIkIB6FQjCJIh4gI3wiIyAUhUIBiSIUIAEgBSAaIBOFQgGJIhMgInx8Ihp8IBogHyAYhUIwiSIYhUIgiSIaIBcgG3wiF3wiGyAThUIoiSITfCIffCAPfCIifCACIBcgEYVCAYkiESAcfCAPfCIXfCAXICGFQiCJIhcgGCAZfCIYfCIZIBGFQiiJIhF8IhwgF4VCMIki
|
|||
|
var hash$j = "68afc9cf";
|
|||
|
var wasmJson$j = {
|
|||
|
name: name$j,
|
|||
|
data: data$j,
|
|||
|
hash: hash$j
|
|||
|
};
|
|||
|
|
|||
|
new Mutex();
|
|||
|
function validateBits$4(bits) {
|
|||
|
if (!Number.isInteger(bits) || bits < 8 || bits > 512 || bits % 8 !== 0) {
|
|||
|
return new Error('Invalid variant! Valid values: 8, 16, ..., 512');
|
|||
|
}
|
|||
|
return null;
|
|||
|
}
|
|||
|
function getInitParam$1(outputBits, keyBits) {
|
|||
|
// eslint-disable-next-line no-bitwise
|
|||
|
return outputBits | (keyBits << 16);
|
|||
|
}
|
|||
|
/**
|
|||
|
* Creates a new BLAKE2b hash instance
|
|||
|
* @param bits Number of output bits, which has to be a number
|
|||
|
* divisible by 8, between 8 and 512. Defaults to 512.
|
|||
|
* @param key Optional key (string, Buffer or TypedArray). Maximum length is 64 bytes.
|
|||
|
*/
|
|||
|
function createBLAKE2b(bits = 512, key = null) {
|
|||
|
if (validateBits$4(bits)) {
|
|||
|
return Promise.reject(validateBits$4(bits));
|
|||
|
}
|
|||
|
let keyBuffer = null;
|
|||
|
let initParam = bits;
|
|||
|
if (key !== null) {
|
|||
|
keyBuffer = getUInt8Buffer(key);
|
|||
|
if (keyBuffer.length > 64) {
|
|||
|
return Promise.reject(new Error('Max key length is 64 bytes'));
|
|||
|
}
|
|||
|
initParam = getInitParam$1(bits, keyBuffer.length);
|
|||
|
}
|
|||
|
const outputSize = bits / 8;
|
|||
|
return WASMInterface(wasmJson$j, outputSize).then((wasm) => {
|
|||
|
if (initParam > 512) {
|
|||
|
wasm.writeMemory(keyBuffer);
|
|||
|
}
|
|||
|
wasm.init(initParam);
|
|||
|
const obj = {
|
|||
|
init: initParam > 512
|
|||
|
? () => {
|
|||
|
wasm.writeMemory(keyBuffer);
|
|||
|
wasm.init(initParam);
|
|||
|
return obj;
|
|||
|
}
|
|||
|
: () => {
|
|||
|
wasm.init(initParam);
|
|||
|
return obj;
|
|||
|
},
|
|||
|
update: (data) => { wasm.update(data); return obj; },
|
|||
|
digest: (outputType) => wasm.digest(outputType),
|
|||
|
save: () => wasm.save(),
|
|||
|
load: (data) => { wasm.load(data); return obj; },
|
|||
|
blockSize: 128,
|
|||
|
digestSize: outputSize,
|
|||
|
};
|
|||
|
return obj;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
var name$i = "argon2";
|
|||
|
var data$i = "AGFzbQEAAAABKQVgAX8Bf2AAAX9gEH9/f39/f39/f39/f39/f38AYAR/f39/AGACf38AAwYFAAECAwQEBQFwAQEBBQYBAQKAgAIGCAF/AUGQqAQLB0EEBm1lbW9yeQIAEkhhc2hfU2V0TWVtb3J5U2l6ZQAADkhhc2hfR2V0QnVmZmVyAAEOSGFzaF9DYWxjdWxhdGUABArXMwVbAQF/QQAhAQJAIABBACgCgAhrIgBFDQACQCAAQRB2IABBgIB8cSAASWoiAEAAQX9HDQBB/wEhAQwBC0EAIQFBAEEAKQOACCAAQRB0rXw3A4AICyABQRh0QRh1C2oBAn8CQEEAKAKICCIADQBBAD8AQRB0IgA2AogIQYCAIEEAKAKACGsiAUUNAAJAIAFBEHYgAUGAgHxxIAFJaiIAQABBf0cNAEEADwtBAEEAKQOACCAAQRB0rXw3A4AIQQAoAogIIQALIAALnA8BA34gACAEKQMAIhAgACkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDCAQIAwpAwCFIhBCIIkiETcDACAIIBEgCCkDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAEIBAgBCkDAIUiEEIoiSIRNwMAIAAgESAAKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAMIBAgDCkDAIUiEEIwiSIRNwMAIAggESAIKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAEIBAgBCkDAIVCAYk3AwAgASAFKQMAIhAgASkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDSAQIA0pAwCFIhBCIIkiETcDACAJIBEgCSkDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAFIBAgBSkDAIUiEEIoiSIRNwMAIAEgESABKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACANIBAgDSkDAIUiEEIwiSIRNwMAIAkgESAJKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAFIBAgBSkDAIVCAYk3AwAgAiAGKQMAIhAgAikDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDiAQIA4pAwCFIhBCIIkiETcDACAKIBEgCikDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAGIBAgBikDAIUiEEIoiSIRNwMAIAIgESACKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAOIBAgDikDAIUiEEIwiSIRNwMAIAogESAKKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAGIBAgBikDAIVCAYk3AwAgAyAHKQMAIhAgAykDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDyAQIA8pAwCFIhBCIIkiETcDACALIBEgCykDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAHIBAgBykDAIUiEEIoiSIRNwMAIAMgESADKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAPIBAgDykDAIUiEEIwiSIRNwMAIAsgESALKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAHIBAgBykDAIVCAYk3AwAgACAFKQMAIhAgACkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDyAQIA8pAwCFIhBCIIkiETcDACAKIBEgCikDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAFIBAgBSkDAIUiEEIoiSIRNwMAIAAgESAAKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAPIBAgDykDAIUiEEIwiSIRNwMAIAogESAKKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAFIBAgBSkDAIVCAYk3AwAgASAGKQMAIhAgASkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDCAQIAwpAwCFIhBCIIkiETcDACALIBEgCykDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAGIBAgBikDAIUiEEIoiSIRNwMAIAEgESABKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAMIBAgDCkDAIUiEEIwiSIRNwMAIAsgESALKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAGIBAgBikDAIVCAYk3AwAgAiAHKQMAIhAgAikDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDSAQIA0pAwCFIhBCIIkiETcDACAIIBEgCCkDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAHIBAgBykDAIUiEEIoiSIRNwMAIAIgESACKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACANIBAgDSkDAIUiEEIwiSIRNwMAIAggESAIKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAHIBAgBykDAIVCAYk3AwAgAyAEKQMAIhAgAykDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDiAQIA4pAwCFIhBCIIkiETcDACAJIBEgCSkDACISfCASQgGGQv7///8fgyAQQiCIfnwiEDcDACAEIBAgBCkDAIUiEEIoiSIRNwMAIAMgESADKQMAIhJ8IBBCGIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAOIBAgDikDAIUiEEIwiSIRNwMAIAkgESAJKQMAIhJ8IBBCEIhC/////w+DIBJCAYZC/v///x+DfnwiEDcDACAEIBAgBCkDAIVCAYk3AwALhxoBAX9BACEEQQAgAikDACABKQMAhTcDkAhBACACKQMIIAEpAwiFNwOYCEEAIAIpAxAgASkDEIU3A6AIQQAgAikDGCABKQMYhTcDqAhBACACKQMgIAEpAyCFNwOwCEEAIAIpAyggASkDKIU3A7gIQQAgAikDMCABKQMwhTcDwAhBACACKQM4IAEpAziFNwPICEEAIAIpA0AgASkDQIU3A9AIQQAgAikDSCABKQNIhTcD2AhBACACKQNQIAEpA1CFNwPgCEEAIAIpA1ggASkDWIU3A+gIQQAgAikDYCABKQNghTcD8AhBACACKQNoIAEpA2iFNwP4CEEAIAIpA3AgASkDcIU3A4AJQQAgAikDeCABKQN4hTcDiAlBACACKQOAASABKQOAAYU3A5AJQQAgAikDiAEgASkDiAGFNwOYCUEAIAIpA5ABIAEpA5ABhTcDoAlBACACKQOYASABKQOYAYU3A6gJQQAgAikDoAEgASkDoAGFNwOwCUEAIAIpA6gBIAEpA6gBhTcDuAlBACACKQOwASABKQOwAYU3A8AJQQAgAikDuAEgASkDuAGFNwPICUEAIAIpA8ABIAEpA8ABhTcD0AlBACACKQPIASABKQPIAYU3A9gJQQAgAikD0AEgASkD0AGFNwPgCUEAIAIpA9gBIAEpA9gBhTcD6AlBACACKQPgASABKQPgAYU3A/AJQQAgAikD6AEgASkD6AGFNwP4CUEAIAIpA/ABIAEpA/ABhTcDgApBACACKQP4ASABKQP4AYU3A4gKQQAgAikDgAIgASkDgAKFNwOQCkEAIAIpA4gCIAEpA4gChTcDmApBACACKQOQAiABKQOQAoU3A6AKQQAgAikDmAIgASkDmAKFNwOoCkEAIAIpA6ACIAEpA6AChTcDsApBACACKQOoAiABKQOoAoU3A7gKQQAgAikDsAIgASkDsAKFNwPACkEAIAIpA7gCIAEpA7gChTcDyApBACACKQPAAiABKQPAAoU3A9AK
|
|||
|
var hash$i = "59aa4fb4";
|
|||
|
var wasmJson$i = {
|
|||
|
name: name$i,
|
|||
|
data: data$i,
|
|||
|
hash: hash$i
|
|||
|
};
|
|||
|
|
|||
|
function encodeResult(salt, options, res) {
|
|||
|
const parameters = [
|
|||
|
`m=${options.memorySize}`,
|
|||
|
`t=${options.iterations}`,
|
|||
|
`p=${options.parallelism}`,
|
|||
|
].join(',');
|
|||
|
return `$argon2${options.hashType}$v=19$${parameters}$${encodeBase64$1(salt, false)}$${encodeBase64$1(res, false)}`;
|
|||
|
}
|
|||
|
const uint32View = new DataView(new ArrayBuffer(4));
|
|||
|
function int32LE(x) {
|
|||
|
uint32View.setInt32(0, x, true);
|
|||
|
return new Uint8Array(uint32View.buffer);
|
|||
|
}
|
|||
|
function hashFunc(blake512, buf, len) {
|
|||
|
return __awaiter(this, void 0, void 0, function* () {
|
|||
|
if (len <= 64) {
|
|||
|
const blake = yield createBLAKE2b(len * 8);
|
|||
|
blake.update(int32LE(len));
|
|||
|
blake.update(buf);
|
|||
|
return blake.digest('binary');
|
|||
|
}
|
|||
|
const r = Math.ceil(len / 32) - 2;
|
|||
|
const ret = new Uint8Array(len);
|
|||
|
blake512.init();
|
|||
|
blake512.update(int32LE(len));
|
|||
|
blake512.update(buf);
|
|||
|
let vp = blake512.digest('binary');
|
|||
|
ret.set(vp.subarray(0, 32), 0);
|
|||
|
for (let i = 1; i < r; i++) {
|
|||
|
blake512.init();
|
|||
|
blake512.update(vp);
|
|||
|
vp = blake512.digest('binary');
|
|||
|
ret.set(vp.subarray(0, 32), i * 32);
|
|||
|
}
|
|||
|
const partialBytesNeeded = len - 32 * r;
|
|||
|
let blakeSmall;
|
|||
|
if (partialBytesNeeded === 64) {
|
|||
|
blakeSmall = blake512;
|
|||
|
blakeSmall.init();
|
|||
|
}
|
|||
|
else {
|
|||
|
blakeSmall = yield createBLAKE2b(partialBytesNeeded * 8);
|
|||
|
}
|
|||
|
blakeSmall.update(vp);
|
|||
|
vp = blakeSmall.digest('binary');
|
|||
|
ret.set(vp.subarray(0, partialBytesNeeded), r * 32);
|
|||
|
return ret;
|
|||
|
});
|
|||
|
}
|
|||
|
function getHashType(type) {
|
|||
|
switch (type) {
|
|||
|
case 'd':
|
|||
|
return 0;
|
|||
|
case 'i':
|
|||
|
return 1;
|
|||
|
default:
|
|||
|
return 2;
|
|||
|
}
|
|||
|
}
|
|||
|
function argon2Internal(options) {
|
|||
|
return __awaiter(this, void 0, void 0, function* () {
|
|||
|
const { parallelism, iterations, hashLength } = options;
|
|||
|
const password = getUInt8Buffer(options.password);
|
|||
|
const salt = getUInt8Buffer(options.salt);
|
|||
|
const version = 0x13;
|
|||
|
const hashType = getHashType(options.hashType);
|
|||
|
const { memorySize } = options; // in KB
|
|||
|
const [argon2Interface, blake512] = yield Promise.all([
|
|||
|
WASMInterface(wasmJson$i, 1024),
|
|||
|
createBLAKE2b(512),
|
|||
|
]);
|
|||
|
// last block is for storing the init vector
|
|||
|
argon2Interface.setMemorySize(memorySize * 1024 + 1024);
|
|||
|
const initVector = new Uint8Array(24);
|
|||
|
const initVectorView = new DataView(initVector.buffer);
|
|||
|
initVectorView.setInt32(0, parallelism, true);
|
|||
|
initVectorView.setInt32(4, hashLength, true);
|
|||
|
initVectorView.setInt32(8, memorySize, true);
|
|||
|
initVectorView.setInt32(12, iterations, true);
|
|||
|
initVectorView.setInt32(16, version, true);
|
|||
|
initVectorView.setInt32(20, hashType, true);
|
|||
|
argon2Interface.writeMemory(initVector, memorySize * 1024);
|
|||
|
blake512.init();
|
|||
|
blake512.update(initVector);
|
|||
|
blake512.update(int32LE(password.length));
|
|||
|
blake512.update(password);
|
|||
|
blake512.update(int32LE(salt.length));
|
|||
|
blake512.update(salt);
|
|||
|
blake512.update(int32LE(0)); // key length + key
|
|||
|
blake512.update(int32LE(0)); // associatedData length + associatedData
|
|||
|
const segments = Math.floor(memorySize / (parallelism * 4)); // length of each lane
|
|||
|
const lanes = segments * 4;
|
|||
|
const param = new Uint8Array(72);
|
|||
|
const H0 = blake512.digest('binary');
|
|||
|
param.set(H0);
|
|||
|
for (let lane = 0; lane < parallelism; lane++) {
|
|||
|
param.set(int32LE(0), 64);
|
|||
|
param.set(int32LE(lane), 68);
|
|||
|
let position = lane * lanes;
|
|||
|
let chunk = yield hashFunc(blake512, param, 1024);
|
|||
|
argon2Interface.writeMemory(chunk, position * 1024);
|
|||
|
position += 1;
|
|||
|
param.set(int32LE(1), 64);
|
|||
|
chunk = yield hashFunc(blake512, param, 1024);
|
|||
|
argon2Interface.writeMemory(chunk, position * 1024);
|
|||
|
}
|
|||
|
const C = new Uint8Array(1024);
|
|||
|
writeHexToUInt8(C, argon2Interface.calculate(new Uint8Array([]), memorySize));
|
|||
|
const res = yield hashFunc(blake512, C, hashLength);
|
|||
|
if (options.outputType === 'hex') {
|
|||
|
const digestChars = new Uint8Array(hashLength * 2);
|
|||
|
return getDigestHex(digestChars, res, hashLength);
|
|||
|
}
|
|||
|
if (options.outputType === 'encoded') {
|
|||
|
return encodeResult(salt, options, res);
|
|||
|
}
|
|||
|
// return binary format
|
|||
|
return res;
|
|||
|
});
|
|||
|
}
|
|||
|
const validateOptions$3 = (options) => {
|
|||
|
if (!options || typeof options !== 'object') {
|
|||
|
throw new Error('Invalid options parameter. It requires an object.');
|
|||
|
}
|
|||
|
if (!options.password) {
|
|||
|
throw new Error('Password must be specified');
|
|||
|
}
|
|||
|
options.password = getUInt8Buffer(options.password);
|
|||
|
if (options.password.length < 1) {
|
|||
|
throw new Error('Password must be specified');
|
|||
|
}
|
|||
|
if (!options.salt) {
|
|||
|
throw new Error('Salt must be specified');
|
|||
|
}
|
|||
|
options.salt = getUInt8Buffer(options.salt);
|
|||
|
if (options.salt.length < 8) {
|
|||
|
throw new Error('Salt should be at least 8 bytes long');
|
|||
|
}
|
|||
|
if (!Number.isInteger(options.iterations) || options.iterations < 1) {
|
|||
|
throw new Error('Iterations should be a positive number');
|
|||
|
}
|
|||
|
if (!Number.isInteger(options.parallelism) || options.parallelism < 1) {
|
|||
|
throw new Error('Parallelism should be a positive number');
|
|||
|
}
|
|||
|
if (!Number.isInteger(options.hashLength) || options.hashLength < 4) {
|
|||
|
throw new Error('Hash length should be at least 4 bytes.');
|
|||
|
}
|
|||
|
if (!Number.isInteger(options.memorySize)) {
|
|||
|
throw new Error('Memory size should be specified.');
|
|||
|
}
|
|||
|
if (options.memorySize < 8 * options.parallelism) {
|
|||
|
throw new Error('Memory size should be at least 8 * parallelism.');
|
|||
|
}
|
|||
|
if (options.outputType === undefined) {
|
|||
|
options.outputType = 'hex';
|
|||
|
}
|
|||
|
if (!['hex', 'binary', 'encoded'].includes(options.outputType)) {
|
|||
|
throw new Error(`Insupported output type ${options.outputType}. Valid values: ['hex', 'binary', 'encoded']`);
|
|||
|
}
|
|||
|
};
|
|||
|
const getHashParameters = (password, encoded) => {
|
|||
|
const regex = /^\$argon2(id|i|d)\$v=([0-9]+)\$((?:[mtp]=[0-9]+,){2}[mtp]=[0-9]+)\$([A-Za-z0-9+/]+)\$([A-Za-z0-9+/]+)$/;
|
|||
|
const match = encoded.match(regex);
|
|||
|
if (!match) {
|
|||
|
throw new Error('Invalid hash');
|
|||
|
}
|
|||
|
const [, hashType, version, parameters, salt, hash] = match;
|
|||
|
if (version !== '19') {
|
|||
|
throw new Error(`Unsupported version: ${version}`);
|
|||
|
}
|
|||
|
const parsedParameters = {};
|
|||
|
const paramMap = { m: 'memorySize', p: 'parallelism', t: 'iterations' };
|
|||
|
parameters.split(',').forEach((x) => {
|
|||
|
const [n, v] = x.split('=');
|
|||
|
parsedParameters[paramMap[n]] = parseInt(v, 10);
|
|||
|
});
|
|||
|
return Object.assign(Object.assign({}, parsedParameters), { password, hashType: hashType, salt: decodeBase64$1(salt), hashLength: getDecodeBase64Length(hash), outputType: 'encoded' });
|
|||
|
};
|
|||
|
const validateVerifyOptions$1 = (options) => {
|
|||
|
if (!options || typeof options !== 'object') {
|
|||
|
throw new Error('Invalid options parameter. It requires an object.');
|
|||
|
}
|
|||
|
if (options.hash === undefined || typeof options.hash !== 'string') {
|
|||
|
throw new Error('Hash should be specified');
|
|||
|
}
|
|||
|
};
|
|||
|
/**
|
|||
|
* Verifies password using the argon2 password-hashing function
|
|||
|
* @returns True if the encoded hash matches the password
|
|||
|
*/
|
|||
|
function argon2Verify(options) {
|
|||
|
return __awaiter(this, void 0, void 0, function* () {
|
|||
|
validateVerifyOptions$1(options);
|
|||
|
const params = getHashParameters(options.password, options.hash);
|
|||
|
validateOptions$3(params);
|
|||
|
const hashStart = options.hash.lastIndexOf('$') + 1;
|
|||
|
const result = yield argon2Internal(params);
|
|||
|
return result.substring(hashStart) === options.hash.substring(hashStart);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
var name$2 = "bcrypt";
|
|||
|
var data$2 = "AGFzbQEAAAABFwRgAAF/YAR/f39/AGADf39/AGABfwF/AwUEAAECAwQFAXABAQEFBAEBAgIGCAF/AUGQqwULBzQEBm1lbW9yeQIADkhhc2hfR2V0QnVmZmVyAAAGYmNyeXB0AAINYmNyeXB0X3ZlcmlmeQADCuRbBAUAQYArC5FVAxJ/BX4HfyMAQfAAayEEIAJBADoAAiACQargADsAAAJAIAEtAABBKkcNACABLQABQTBHDQAgAkExOgABCwJAIAEsAAUgASwABEEKbGpB8HtqIgVBBEkNAEEBIAV0IQYgAUEHaiEFIARBGGohByAEQQhqIQgDQCAFLQAAQWBqIglB3wBLDQEgCUGACGotAAAiCkE/Sw0BIAVBAWotAABBYGoiCUHfAEsNASAJQYAIai0AACIJQT9LDQEgCCAJQQR2IApBAnRyOgAAAkAgCEEBaiIIIAdPDQAgBUECai0AAEFgaiIKQd8ASw0CIApBgAhqLQAAIgpBP0sNAiAIIApBAnYgCUEEdHI6AAAgCEEBaiIIIAdPDQAgBUEDai0AAEFgaiIJQd8ASw0CIAlBgAhqLQAAIglBP0sNAiAIIAkgCkEGdHI6AAAgBUEEaiEFIAhBAWoiCCAHSQ0BCwsgBCAEKAIIIgVBGHQgBUEIdEGAgPwHcXIgBUEIdkGA/gNxIAVBGHZyciILNgIIIAQgBCgCDCIFQRh0IAVBCHRBgID8B3FyIAVBCHZBgP4DcSAFQRh2cnIiDDYCDCAEIAQoAhAiBUEYdCAFQQh0QYCA/AdxciAFQQh2QYD+A3EgBUEYdnJyNgIQIAQgBCgCFCIFQRh0IAVBCHRBgID8B3FyIAVBCHZBgP4DcSAFQRh2cnI2AhQgBEHoAGogAS0AAkH/B2otAAAiDUEBcUECdGohDkEAIQhBACEJQQAhCiAAIQUDQCAEQgA3AmggBS0AACEHIARBADYCbCAEIAc2AmggBCAFLAAAIg82AmwgBS0AACEQIAQgB0EIdCIHNgJoIAQgByAFQQFqIAAgEBsiBS0AAHIiBzYCaCAEIA9BCHQiDzYCbCAEIA8gBSwAACIQciIPNgJsIAUtAAAhESAEIAdBCHQiBzYCaCAEIAcgBUEBaiAAIBEbIgUtAAByIgc2AmggBCAPQQh0Ig82AmwgBCAPIAUsAAAiEXIiDzYCbCAFLQAAIRIgBCAHQQh0Igc2AmggBCAHIAVBAWogACASGyIFLQAAciIHNgJoIAQgD0EIdCIPNgJsIAQgDyAFLAAAIhJyIg82AmwgBS0AACETIARBIGogCGogDigCACIUNgIAIAhB6ClqIhUgFCAVKAIAczYCACAPIAdzIAlyIQkgBUEBaiAAIBMbIQUgEEGAAXEgCnIgEUGAAXFyIBJBgAFxciEKIAhBBGoiCEHIAEcNAAtBAEEAKALoKSANQQ90IApBCXRxQYCABCAJQf//A3EgCUEQdnJrcUGAgARxcyIFNgLoKUIAIRZBAEIANwOAqwFB6CkhB0EAIQgCQANAQQAoAqQqQQAoApwqQQAoApQqQQAoAowqQQAoAoQqQQAoAvwpQQAoAvQpQQAoAuwpIARBCGogCEECcUECdGopAwAgFoUiFkIgiKdzIAUgFqdzIgVBFnZB/AdxQegJaigCACAFQQ52QfwHcUHoEWooAgBqIAVBBnZB/AdxQegZaigCAHMgBUH/AXFBAnRB6CFqKAIAanMiAHNBACgC8CkgBXMgAEEWdkH8B3FB6AlqKAIAIABBDnZB/AdxQegRaigCAGogAEEGdkH8B3FB6BlqKAIAcyAAQf8BcUECdEHoIWooAgBqcyIFQRZ2QfwHcUHoCWooAgAgBUEOdkH8B3FB6BFqKAIAaiAFQQZ2QfwHcUHoGWooAgBzIAVB/wFxQQJ0QeghaigCAGpzIgBzQQAoAvgpIAVzIABBFnZB/AdxQegJaigCACAAQQ52QfwHcUHoEWooAgBqIABBBnZB/AdxQegZaigCAHMgAEH/AXFBAnRB6CFqKAIAanMiBUEWdkH8B3FB6AlqKAIAIAVBDnZB/AdxQegRaigCAGogBUEGdkH8B3FB6BlqKAIAcyAFQf8BcUECdEHoIWooAgBqcyIAc0EAKAKAKiAFcyAAQRZ2QfwHcUHoCWooAgAgAEEOdkH8B3FB6BFqKAIAaiAAQQZ2QfwHcUHoGWooAgBzIABB/wFxQQJ0QeghaigCAGpzIgVBFnZB/AdxQegJaigCACAFQQ52QfwHcUHoEWooAgBqIAVBBnZB/AdxQegZaigCAHMgBUH/AXFBAnRB6CFqKAIAanMiAHNBACgCiCogBXMgAEEWdkH8B3FB6AlqKAIAIABBDnZB/AdxQegRaigCAGogAEEGdkH8B3FB6BlqKAIAcyAAQf8BcUECdEHoIWooAgBqcyIFQRZ2QfwHcUHoCWooAgAgBUEOdkH8B3FB6BFqKAIAaiAFQQZ2QfwHcUHoGWooAgBzIAVB/wFxQQJ0QeghaigCAGpzIgBzQQAoApAqIAVzIABBFnZB/AdxQegJaigCACAAQQ52QfwHcUHoEWooAgBqIABBBnZB/AdxQegZaigCAHMgAEH/AXFBAnRB6CFqKAIAanMiBUEWdkH8B3FB6AlqKAIAIAVBDnZB/AdxQegRaigCAGogBUEGdkH8B3FB6BlqKAIAcyAFQf8BcUECdEHoIWooAgBqcyIAc0EAKAKYKiAFcyAAQRZ2QfwHcUHoCWooAgAgAEEOdkH8B3FB6BFqKAIAaiAAQQZ2QfwHcUHoGWooAgBzIABB/wFxQQJ0QeghaigCAGpzIgVBFnZB/AdxQegJaigCACAFQQ52QfwHcUHoEWooAgBqIAVBBnZB/AdxQegZaigCAHMgBUH/AXFBAnRB6CFqKAIAanMiAHNBACgCoCogBXMgAEEWdkH8B3FB6AlqKAIAIABBDnZB/AdxQegRaigCAGogAEEGdkH8B3FB6BlqKAIAcyAAQf8BcUECdEHoIWooAgBqcyIFQRZ2QfwHcUHoCWooAgAgBUEOdkH8B3FB6BFqKAIAaiAFQQZ2QfwHcUHoGWooAgBzIAVB/wFxQQJ0QeghaigCAGpzIgBB/wFxQQJ0QeghaigCACEJIABBBnZB/AdxQegZaigCACEKIABBFnZB/AdxQegJaigCACEPIABBDnZB/AdxQegRaigCACEQQQAoAqgqIRFBAEEAKAKsKiAAczYCgKsBQQAgESAFcyAJIAogDyAQanNqcyIANgKEqwEgB0EAKQOAqwEiFjcCACAIQQ9LDQEgB0EIaiEHIAhBAmohCEEAKALoKSEFDAALCyAWpyEIQegJIQUDQEEAKAKkKkEAKAKcKkEAKAKUKkEAKAKMKkEAKAKEKkEAKAL8KUEAKAL0KSAEKAIUIABzQQAoAuwpcyAEKAIQIAhzQQAoAugpcyIAQRZ2QfwHcUHoCWooAgAgAEEOdkH8B3FB6BFqKAIAaiAAQQZ2QfwHcUHoGWooAgBzIABB/wFxQQJ0QeghaigCAGpzIghzQQAoAvApIABzIAhBFnZB/AdxQegJaigCACAIQQ52QfwHcUHoEWooAgBqIAhBBnZB/AdxQegZaigCAHMgCEH/AXFBAnRB6CFqKAIAanMiAEEWdkH8B3FB6AlqKAIAIABBDnZB/AdxQegRaigCAGogAEEGdkH8B3FB6BlqKAIAcyAAQf8BcUECdEHoIWooAgBqcyIIc0EAKAL4KSAAcyAIQRZ2QfwHcUHoCWooAgAgCEEOdkH8B3FB6BFqKAIAaiAIQQZ2QfwHcUHoGWooAgBzIAhB/wFxQQJ0QeghaigCAGpzIgBBFnZB/AdxQegJaigCACAAQQ52QfwHcUHoEWooAgBqIABBBnZB/AdxQegZaigCAHMgAEH/AXFBAnRB6CFqKAIAanMiCHNBACgCgCogAHMgCEEWdkH8B3FB6AlqKAIAIAhBDnZB/AdxQegRaigCAGogCEEGdkH8B3FB6BlqKAIAcyAIQf8BcUECdEHoIWooAgBqcyIAQRZ2QfwHcUHoCWooAgAgAEEOdkH8B3FB6BFqKAIAaiAA
|
|||
|
var hash$2 = "9f4c7b9e";
|
|||
|
var wasmJson$2 = {
|
|||
|
name: name$2,
|
|||
|
data: data$2,
|
|||
|
hash: hash$2
|
|||
|
};
|
|||
|
const validateHashCharacters = (hash) => {
|
|||
|
if (!/^\$2[axyb]\$[0-3][0-9]\$[./A-Za-z0-9]{53}$/.test(hash)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (hash[4] === '0' && parseInt(hash[5], 10) < 4) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (hash[4] === '3' && parseInt(hash[5], 10) > 1) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
};
|
|||
|
const validateVerifyOptions = (options) => {
|
|||
|
if (!options || typeof options !== 'object') {
|
|||
|
throw new Error('Invalid options parameter. It requires an object.');
|
|||
|
}
|
|||
|
if (options.hash === undefined || typeof options.hash !== 'string') {
|
|||
|
throw new Error('Hash should be specified');
|
|||
|
}
|
|||
|
if (options.hash.length !== 60) {
|
|||
|
throw new Error('Hash should be 60 bytes long');
|
|||
|
}
|
|||
|
if (!validateHashCharacters(options.hash)) {
|
|||
|
throw new Error('Invalid hash');
|
|||
|
}
|
|||
|
options.password = getUInt8Buffer(options.password);
|
|||
|
if (options.password.length < 1) {
|
|||
|
throw new Error('Password should be at least 1 byte long');
|
|||
|
}
|
|||
|
if (options.password.length > 72) {
|
|||
|
throw new Error('Password should be at most 72 bytes long');
|
|||
|
}
|
|||
|
};
|
|||
|
/**
|
|||
|
* Verifies password using bcrypt password-hashing function
|
|||
|
* @returns True if the encoded hash matches the password
|
|||
|
*/
|
|||
|
function bcryptVerify(options) {
|
|||
|
return __awaiter(this, void 0, void 0, function* () {
|
|||
|
validateVerifyOptions(options);
|
|||
|
const { hash, password } = options;
|
|||
|
const bcryptInterface = yield WASMInterface(wasmJson$2, 0);
|
|||
|
bcryptInterface.writeMemory(getUInt8Buffer(hash), 0);
|
|||
|
const passwordBuffer = getUInt8Buffer(password);
|
|||
|
bcryptInterface.writeMemory(passwordBuffer, 60);
|
|||
|
return !!bcryptInterface.getExports().bcrypt_verify(passwordBuffer.length);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
new Mutex();
|
|||
|
|
|||
|
// Generated using scripts/write-decode-map.ts
|
|||
|
var htmlDecodeTree = new Uint16Array(
|
|||
|
// prettier-ignore
|
|||
|
"\u1d41<\xd5\u0131\u028a\u049d\u057b\u05d0\u0675\u06de\u07a2\u07d6\u080f\u0a4a\u0a91\u0da1\u0e6d\u0f09\u0f26\u10ca\u1228\u12e1\u1415\u149d\u14c3\u14df\u1525\0\0\0\0\0\0\u156b\u16cd\u198d\u1c12\u1ddd\u1f7e\u2060\u21b0\u228d\u23c0\u23fb\u2442\u2824\u2912\u2d08\u2e48\u2fce\u3016\u32ba\u3639\u37ac\u38fe\u3a28\u3a71\u3ae0\u3b2e\u0800EMabcfglmnoprstu\\bfms\x7f\x84\x8b\x90\x95\x98\xa6\xb3\xb9\xc8\xcflig\u803b\xc6\u40c6P\u803b&\u4026cute\u803b\xc1\u40c1reve;\u4102\u0100iyx}rc\u803b\xc2\u40c2;\u4410r;\uc000\ud835\udd04rave\u803b\xc0\u40c0pha;\u4391acr;\u4100d;\u6a53\u0100gp\x9d\xa1on;\u4104f;\uc000\ud835\udd38plyFunction;\u6061ing\u803b\xc5\u40c5\u0100cs\xbe\xc3r;\uc000\ud835\udc9cign;\u6254ilde\u803b\xc3\u40c3ml\u803b\xc4\u40c4\u0400aceforsu\xe5\xfb\xfe\u0117\u011c\u0122\u0127\u012a\u0100cr\xea\xf2kslash;\u6216\u0176\xf6\xf8;\u6ae7ed;\u6306y;\u4411\u0180crt\u0105\u010b\u0114ause;\u6235noullis;\u612ca;\u4392r;\uc000\ud835\udd05pf;\uc000\ud835\udd39eve;\u42d8c\xf2\u0113mpeq;\u624e\u0700HOacdefhilorsu\u014d\u0151\u0156\u0180\u019e\u01a2\u01b5\u01b7\u01ba\u01dc\u0215\u0273\u0278\u027ecy;\u4427PY\u803b\xa9\u40a9\u0180cpy\u015d\u0162\u017aute;\u4106\u0100;i\u0167\u0168\u62d2talDifferentialD;\u6145leys;\u612d\u0200aeio\u0189\u018e\u0194\u0198ron;\u410cdil\u803b\xc7\u40c7rc;\u4108nint;\u6230ot;\u410a\u0100dn\u01a7\u01adilla;\u40b8terDot;\u40b7\xf2\u017fi;\u43a7rcle\u0200DMPT\u01c7\u01cb\u01d1\u01d6ot;\u6299inus;\u6296lus;\u6295imes;\u6297o\u0100cs\u01e2\u01f8kwiseContourIntegral;\u6232eCurly\u0100DQ\u0203\u020foubleQuote;\u601duote;\u6019\u0200lnpu\u021e\u0228\u0247\u0255on\u0100;e\u0225\u0226\u6237;\u6a74\u0180git\u022f\u0236\u023aruent;\u6261nt;\u622fourIntegral;\u622e\u0100fr\u024c\u024e;\u6102oduct;\u6210nterClockwiseContourIntegral;\u6233oss;\u6a2fcr;\uc000\ud835\udc9ep\u0100;C\u0284\u0285\u62d3ap;\u624d\u0580DJSZacefios\u02a0\u02ac\u02b0\u02b4\u02b8\u02cb\u02d7\u02e1\u02e6\u0333\u048d\u0100;o\u0179\u02a5trahd;\u6911cy;\u4402cy;\u4405cy;\u440f\u0180grs\u02bf\u02c4\u02c7ger;\u6021r;\u61a1hv;\u6ae4\u0100ay\u02d0\u02d5ron;\u410e;\u4414l\u0100;t\u02dd\u02de\u6207a;\u4394r;\uc000\ud835\udd07\u0100af\u02eb\u0327\u0100cm\u02f0\u0322ritical\u0200ADGT\u0300\u0306\u0316\u031ccute;\u40b4o\u0174\u030b\u030d;\u42d9bleAcute;\u42ddrave;\u4060ilde;\u42dcond;\u62c4ferentialD;\u6146\u0470\u033d\0\0\0\u0342\u0354\0\u0405f;\uc000\ud835\udd3b\u0180;DE\u0348\u0349\u034d\u40a8ot;\u60dcqual;\u6250ble\u0300CDLRUV\u0363\u0372\u0382\u03cf\u03e2\u03f8ontourIntegra\xec\u0239o\u0274\u0379\0\0\u037b\xbb\u0349nArrow;\u61d3\u0100eo\u0387\u03a4ft\u0180ART\u0390\u0396\u03a1rrow;\u61d0ightArrow;\u61d4e\xe5\u02cang\u0100LR\u03ab\u03c4eft\u0100AR\u03b3\u03b9rrow;\u67f8ightArrow;\u67faightArrow;\u67f9ight\u0100AT\u03d8\u03derrow;\u61d2ee;\u62a8p\u0241\u03e9\0\0\u03efrrow;\u61d1ownArrow;\u61d5erticalBar;\u6225n\u0300ABLRTa\u0412\u042a\u0430\u045e\u047f\u037crrow\u0180;BU\u041d\u041e\u0422\u6193ar;\u6913pArrow;\u61f5reve;\u4311eft\u02d2\u043a\0\u0446\0\u0450ightVector;\u6950eeVector;\u695eector\u0100;B\u0459\u045a\u61bdar;\u6956ight\u01d4\u0467\0\u0471eeVector;\u695fector\u0100;B\u047a\u047b\u61c1ar;\u6957ee\u0100;A\u0486\u0487\u62a4rrow;\u61a7\u0100ct\u0492\u0497r;\uc000\ud835\udc9frok;\u4110\u0800NTacdfglmopqstux\u04bd\u04c0\u04c4\u04cb\u04de\u04e2\u04e7\u04ee\u04f5\u0521\u052f\u0536\u0552\u055d\u0560\u0565G;\u414aH\u803b\xd0\u40d0cute\u803b\xc9\u40c9\u0180aiy\u04d2\u04d7\u04dcron;\u411arc\u803b\xca\u40ca;\u442dot;\u4116r;\uc000\ud835\udd08rave\u803b\xc8\u40c8ement;\u6208\u0100ap\u04fa\u04fecr;\u4112ty\u0253\u0506\0\0\u0512mallSquare;\u65fberySmallSquare;\u65ab\u0100gp\u0526\u052aon;\u4118f;\uc000\ud835\udd3csilon;\u4395u\u0100ai\u053c\u0549l\u0100;T\u0542\u0543\u6a75ilde;\u6242librium;\u61cc\u0100ci\u0557\u055ar;\u6130m;\u6a73a;\u4397ml\u803b\xcb\u40cb\u0100ip\u056a\u056fsts;\u6203onentialE;\u6147\u0280cfios\u0585\u0588\u058d\u05b2\u05ccy;\u4424r;\uc000\ud835\udd09lled\u0253\u0597\0\0\u05a3mallSquare;\u65fcerySmallSquare;\u65aa\u0370\u05ba\0\u05bf\0\0\u05c4f;\uc000\ud835\udd3dAll;\u6200riertrf;\u6131c\xf2\u05cb\u0600JTabcdfgorst\u05e8\u05ec\u05ef\u05fa\u0600\u0612\u0
|
|||
|
.split("")
|
|||
|
.map((c) => c.charCodeAt(0)));
|
|||
|
|
|||
|
// Generated using scripts/write-decode-map.ts
|
|||
|
var xmlDecodeTree = new Uint16Array(
|
|||
|
// prettier-ignore
|
|||
|
"\u0200aglq\t\x15\x18\x1b\u026d\x0f\0\0\x12p;\u4026os;\u4027t;\u403et;\u403cuot;\u4022"
|
|||
|
.split("")
|
|||
|
.map((c) => c.charCodeAt(0)));
|
|||
|
|
|||
|
// Adapted from https://github.com/mathiasbynens/he/blob/36afe179392226cf1b6ccdb16ebbb7a5a844d93a/src/he.js#L106-L134
|
|||
|
var _a;
|
|||
|
const decodeMap = new Map([
|
|||
|
[0, 65533],
|
|||
|
[128, 8364],
|
|||
|
[130, 8218],
|
|||
|
[131, 402],
|
|||
|
[132, 8222],
|
|||
|
[133, 8230],
|
|||
|
[134, 8224],
|
|||
|
[135, 8225],
|
|||
|
[136, 710],
|
|||
|
[137, 8240],
|
|||
|
[138, 352],
|
|||
|
[139, 8249],
|
|||
|
[140, 338],
|
|||
|
[142, 381],
|
|||
|
[145, 8216],
|
|||
|
[146, 8217],
|
|||
|
[147, 8220],
|
|||
|
[148, 8221],
|
|||
|
[149, 8226],
|
|||
|
[150, 8211],
|
|||
|
[151, 8212],
|
|||
|
[152, 732],
|
|||
|
[153, 8482],
|
|||
|
[154, 353],
|
|||
|
[155, 8250],
|
|||
|
[156, 339],
|
|||
|
[158, 382],
|
|||
|
[159, 376],
|
|||
|
]);
|
|||
|
const fromCodePoint =
|
|||
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins
|
|||
|
(_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function (codePoint) {
|
|||
|
let output = "";
|
|||
|
if (codePoint > 0xffff) {
|
|||
|
codePoint -= 0x10000;
|
|||
|
output += String.fromCharCode(((codePoint >>> 10) & 0x3ff) | 0xd800);
|
|||
|
codePoint = 0xdc00 | (codePoint & 0x3ff);
|
|||
|
}
|
|||
|
output += String.fromCharCode(codePoint);
|
|||
|
return output;
|
|||
|
};
|
|||
|
function replaceCodePoint(codePoint) {
|
|||
|
var _a;
|
|||
|
if ((codePoint >= 0xd800 && codePoint <= 0xdfff) || codePoint > 0x10ffff) {
|
|||
|
return 0xfffd;
|
|||
|
}
|
|||
|
return (_a = decodeMap.get(codePoint)) !== null && _a !== void 0 ? _a : codePoint;
|
|||
|
}
|
|||
|
function decodeCodePoint(codePoint) {
|
|||
|
return fromCodePoint(replaceCodePoint(codePoint));
|
|||
|
}
|
|||
|
|
|||
|
var CharCodes;
|
|||
|
(function (CharCodes) {
|
|||
|
CharCodes[CharCodes["NUM"] = 35] = "NUM";
|
|||
|
CharCodes[CharCodes["SEMI"] = 59] = "SEMI";
|
|||
|
CharCodes[CharCodes["ZERO"] = 48] = "ZERO";
|
|||
|
CharCodes[CharCodes["NINE"] = 57] = "NINE";
|
|||
|
CharCodes[CharCodes["LOWER_A"] = 97] = "LOWER_A";
|
|||
|
CharCodes[CharCodes["LOWER_F"] = 102] = "LOWER_F";
|
|||
|
CharCodes[CharCodes["LOWER_X"] = 120] = "LOWER_X";
|
|||
|
/** Bit that needs to be set to convert an upper case ASCII character to lower case */
|
|||
|
CharCodes[CharCodes["To_LOWER_BIT"] = 32] = "To_LOWER_BIT";
|
|||
|
})(CharCodes || (CharCodes = {}));
|
|||
|
var BinTrieFlags;
|
|||
|
(function (BinTrieFlags) {
|
|||
|
BinTrieFlags[BinTrieFlags["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
|
|||
|
BinTrieFlags[BinTrieFlags["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH";
|
|||
|
BinTrieFlags[BinTrieFlags["JUMP_TABLE"] = 127] = "JUMP_TABLE";
|
|||
|
})(BinTrieFlags || (BinTrieFlags = {}));
|
|||
|
function getDecoder(decodeTree) {
|
|||
|
return function decodeHTMLBinary(str, strict) {
|
|||
|
let ret = "";
|
|||
|
let lastIdx = 0;
|
|||
|
let strIdx = 0;
|
|||
|
while ((strIdx = str.indexOf("&", strIdx)) >= 0) {
|
|||
|
ret += str.slice(lastIdx, strIdx);
|
|||
|
lastIdx = strIdx;
|
|||
|
// Skip the "&"
|
|||
|
strIdx += 1;
|
|||
|
// If we have a numeric entity, handle this separately.
|
|||
|
if (str.charCodeAt(strIdx) === CharCodes.NUM) {
|
|||
|
// Skip the leading "&#". For hex entities, also skip the leading "x".
|
|||
|
let start = strIdx + 1;
|
|||
|
let base = 10;
|
|||
|
let cp = str.charCodeAt(start);
|
|||
|
if ((cp | CharCodes.To_LOWER_BIT) === CharCodes.LOWER_X) {
|
|||
|
base = 16;
|
|||
|
strIdx += 1;
|
|||
|
start += 1;
|
|||
|
}
|
|||
|
do
|
|||
|
cp = str.charCodeAt(++strIdx);
|
|||
|
while ((cp >= CharCodes.ZERO && cp <= CharCodes.NINE) ||
|
|||
|
(base === 16 &&
|
|||
|
(cp | CharCodes.To_LOWER_BIT) >= CharCodes.LOWER_A &&
|
|||
|
(cp | CharCodes.To_LOWER_BIT) <= CharCodes.LOWER_F));
|
|||
|
if (start !== strIdx) {
|
|||
|
const entity = str.substring(start, strIdx);
|
|||
|
const parsed = parseInt(entity, base);
|
|||
|
if (str.charCodeAt(strIdx) === CharCodes.SEMI) {
|
|||
|
strIdx += 1;
|
|||
|
}
|
|||
|
else if (strict) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
ret += decodeCodePoint(parsed);
|
|||
|
lastIdx = strIdx;
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
let resultIdx = 0;
|
|||
|
let excess = 1;
|
|||
|
let treeIdx = 0;
|
|||
|
let current = decodeTree[treeIdx];
|
|||
|
for (; strIdx < str.length; strIdx++, excess++) {
|
|||
|
treeIdx = determineBranch(decodeTree, current, treeIdx + 1, str.charCodeAt(strIdx));
|
|||
|
if (treeIdx < 0)
|
|||
|
break;
|
|||
|
current = decodeTree[treeIdx];
|
|||
|
const masked = current & BinTrieFlags.VALUE_LENGTH;
|
|||
|
// If the branch is a value, store it and continue
|
|||
|
if (masked) {
|
|||
|
// If we have a legacy entity while parsing strictly, just skip the number of bytes
|
|||
|
if (!strict || str.charCodeAt(strIdx) === CharCodes.SEMI) {
|
|||
|
resultIdx = treeIdx;
|
|||
|
excess = 0;
|
|||
|
}
|
|||
|
// The mask is the number of bytes of the value, including the current byte.
|
|||
|
const valueLength = (masked >> 14) - 1;
|
|||
|
if (valueLength === 0)
|
|||
|
break;
|
|||
|
treeIdx += valueLength;
|
|||
|
}
|
|||
|
}
|
|||
|
if (resultIdx !== 0) {
|
|||
|
const valueLength = (decodeTree[resultIdx] & BinTrieFlags.VALUE_LENGTH) >> 14;
|
|||
|
ret +=
|
|||
|
valueLength === 1
|
|||
|
? String.fromCharCode(decodeTree[resultIdx] & ~BinTrieFlags.VALUE_LENGTH)
|
|||
|
: valueLength === 2
|
|||
|
? String.fromCharCode(decodeTree[resultIdx + 1])
|
|||
|
: String.fromCharCode(decodeTree[resultIdx + 1], decodeTree[resultIdx + 2]);
|
|||
|
lastIdx = strIdx - excess + 1;
|
|||
|
}
|
|||
|
}
|
|||
|
return ret + str.slice(lastIdx);
|
|||
|
};
|
|||
|
}
|
|||
|
function determineBranch(decodeTree, current, nodeIdx, char) {
|
|||
|
const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
|
|||
|
const jumpOffset = current & BinTrieFlags.JUMP_TABLE;
|
|||
|
// Case 1: Single branch encoded in jump offset
|
|||
|
if (branchCount === 0) {
|
|||
|
return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;
|
|||
|
}
|
|||
|
// Case 2: Multiple branches encoded in jump table
|
|||
|
if (jumpOffset) {
|
|||
|
const value = char - jumpOffset;
|
|||
|
return value < 0 || value >= branchCount
|
|||
|
? -1
|
|||
|
: decodeTree[nodeIdx + value] - 1;
|
|||
|
}
|
|||
|
// Case 3: Multiple branches encoded in dictionary
|
|||
|
// Binary search for the character.
|
|||
|
let lo = nodeIdx;
|
|||
|
let hi = lo + branchCount - 1;
|
|||
|
while (lo <= hi) {
|
|||
|
const mid = (lo + hi) >>> 1;
|
|||
|
const midVal = decodeTree[mid];
|
|||
|
if (midVal < char) {
|
|||
|
lo = mid + 1;
|
|||
|
}
|
|||
|
else if (midVal > char) {
|
|||
|
hi = mid - 1;
|
|||
|
}
|
|||
|
else {
|
|||
|
return decodeTree[mid + branchCount];
|
|||
|
}
|
|||
|
}
|
|||
|
return -1;
|
|||
|
}
|
|||
|
const htmlDecoder = getDecoder(htmlDecodeTree);
|
|||
|
const xmlDecoder = getDecoder(xmlDecodeTree);
|
|||
|
/**
|
|||
|
* Decodes an HTML string, allowing for entities not terminated by a semi-colon.
|
|||
|
*
|
|||
|
* @param str The string to decode.
|
|||
|
* @returns The decoded string.
|
|||
|
*/
|
|||
|
function decodeHTML(str) {
|
|||
|
return htmlDecoder(str, false);
|
|||
|
}
|
|||
|
/**
|
|||
|
* Decodes an XML string, requiring all entities to be terminated by a semi-colon.
|
|||
|
*
|
|||
|
* @param str The string to decode.
|
|||
|
* @returns The decoded string.
|
|||
|
*/
|
|||
|
function decodeXML(str) {
|
|||
|
return xmlDecoder(str, true);
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @module verifications
|
|||
|
* @ignore
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} data
|
|||
|
* @param {object} params
|
|||
|
* @param {string} params.target
|
|||
|
* @param {string} params.claimFormat
|
|||
|
* @param {string} params.proofEncodingFormat
|
|||
|
* @param {string} [params.claimRelation]
|
|||
|
* @returns {Promise<boolean>}
|
|||
|
*/
|
|||
|
const containsProof = async (data, params) => {
|
|||
|
const fingerprintFormatted = generateClaim(params.target, params.claimFormat);
|
|||
|
const fingerprintURI = generateClaim(params.target, ClaimFormat.URI);
|
|||
|
let result = false;
|
|||
|
|
|||
|
// Decode eventual special entities
|
|||
|
switch (params.proofEncodingFormat) {
|
|||
|
case EntityEncodingFormat.HTML:
|
|||
|
data = decodeHTML(data);
|
|||
|
break
|
|||
|
|
|||
|
case EntityEncodingFormat.XML:
|
|||
|
data = decodeXML(data);
|
|||
|
break
|
|||
|
|
|||
|
case EntityEncodingFormat.PLAIN:
|
|||
|
}
|
|||
|
data = decodeHTML(data);
|
|||
|
|
|||
|
// Check for plaintext proof
|
|||
|
result = data
|
|||
|
// remove newlines and carriage returns
|
|||
|
.replace(/\r?\n|\r/g, '')
|
|||
|
// remove spaces
|
|||
|
.replace(/\s/g, '')
|
|||
|
// normalize
|
|||
|
.toLowerCase()
|
|||
|
// search for fingerprint
|
|||
|
.indexOf(fingerprintFormatted.toLowerCase()) !== -1;
|
|||
|
|
|||
|
// Check for hashed proof
|
|||
|
if (!result) {
|
|||
|
const hashRe = /\$(argon2(?:id|d|i)|2a|2b|2y)(?:\$[a-zA-Z0-9=+\-,./]+)+/g;
|
|||
|
let match;
|
|||
|
|
|||
|
while (!result && (match = hashRe.exec(data)) != null) {
|
|||
|
let timeoutHandle;
|
|||
|
const timeoutPromise = new Promise((resolve, reject) => {
|
|||
|
timeoutHandle = setTimeout(
|
|||
|
() => {
|
|||
|
resolve(false);
|
|||
|
}, 1000
|
|||
|
);
|
|||
|
});
|
|||
|
|
|||
|
switch (match[1]) {
|
|||
|
case '2a':
|
|||
|
case '2b':
|
|||
|
case '2y':
|
|||
|
try {
|
|||
|
// Patch until promise.race properly works on WASM
|
|||
|
if (parseInt(match[0].split('$')[2]) > 12) continue
|
|||
|
|
|||
|
const hashPromise = bcryptVerify({
|
|||
|
password: fingerprintURI,
|
|||
|
hash: match[0]
|
|||
|
})
|
|||
|
.then(result => result)
|
|||
|
.catch(_ => false);
|
|||
|
|
|||
|
result = await Promise.race([hashPromise, timeoutPromise]).then((result) => {
|
|||
|
clearTimeout(timeoutHandle);
|
|||
|
return result
|
|||
|
});
|
|||
|
} catch (err) {
|
|||
|
result = false;
|
|||
|
}
|
|||
|
break
|
|||
|
|
|||
|
case 'argon2':
|
|||
|
case 'argon2i':
|
|||
|
case 'argon2d':
|
|||
|
case 'argon2id':
|
|||
|
try {
|
|||
|
const hashPromise = argon2Verify({
|
|||
|
password: fingerprintURI,
|
|||
|
hash: match[0]
|
|||
|
})
|
|||
|
.then(result => result)
|
|||
|
.catch(_ => false);
|
|||
|
|
|||
|
result = await Promise.race([hashPromise, timeoutPromise]).then((result) => {
|
|||
|
clearTimeout(timeoutHandle);
|
|||
|
return result
|
|||
|
});
|
|||
|
} catch (err) {
|
|||
|
result = false;
|
|||
|
}
|
|||
|
break
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Check for HTTP proof
|
|||
|
if (!result) {
|
|||
|
const uris = getUriFromString(data);
|
|||
|
|
|||
|
for (let index = 0; index < uris.length; index++) {
|
|||
|
if (result) continue
|
|||
|
|
|||
|
const candidate = uris[index];
|
|||
|
/** @type {URL} */
|
|||
|
let candidateURL;
|
|||
|
|
|||
|
try {
|
|||
|
candidateURL = new URL(candidate);
|
|||
|
} catch (_) {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
if (candidateURL.protocol !== 'https:') {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
// Using fetch -> axios doesn't find the ariadne-identity-proof header
|
|||
|
/** @type {Response} */
|
|||
|
const response = await fetch(candidate, {
|
|||
|
method: 'HEAD'
|
|||
|
})
|
|||
|
.catch(e => {
|
|||
|
return undefined
|
|||
|
});
|
|||
|
|
|||
|
if (!response) continue
|
|||
|
if (response.status !== 200) continue
|
|||
|
if (!response.headers.get('ariadne-identity-proof')) continue
|
|||
|
|
|||
|
result = response.headers.get('ariadne-identity-proof')
|
|||
|
.toLowerCase()
|
|||
|
.indexOf(fingerprintURI.toLowerCase()) !== -1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return result
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {any} proofData
|
|||
|
* @param {string} checkPath
|
|||
|
* @param {object} params
|
|||
|
* @param {string} params.target
|
|||
|
* @param {string} params.claimFormat
|
|||
|
* @param {string} params.proofEncodingFormat
|
|||
|
* @param {string} [params.claimRelation]
|
|||
|
* @returns {Promise<boolean>}
|
|||
|
*/
|
|||
|
const runJSON = async (proofData, checkPath, params) => {
|
|||
|
if (!proofData) {
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
if (Array.isArray(proofData)) {
|
|||
|
let result = false;
|
|||
|
|
|||
|
for (let index = 0; index < proofData.length; index++) {
|
|||
|
const item = proofData[index];
|
|||
|
|
|||
|
if (result) {
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
result = await runJSON(item, checkPath, params);
|
|||
|
}
|
|||
|
|
|||
|
return result
|
|||
|
}
|
|||
|
|
|||
|
if (checkPath.length === 0) {
|
|||
|
switch (params.claimRelation) {
|
|||
|
case ClaimRelation.ONEOF:
|
|||
|
return await containsProof(proofData.join('|'), params)
|
|||
|
|
|||
|
case ClaimRelation.CONTAINS:
|
|||
|
case ClaimRelation.EQUALS:
|
|||
|
default:
|
|||
|
return await containsProof(proofData, params)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (typeof proofData === 'object' && !(checkPath[0] in proofData)) {
|
|||
|
throw new Error('err_json_structure_incorrect')
|
|||
|
}
|
|||
|
|
|||
|
return await runJSON(
|
|||
|
proofData[checkPath[0]],
|
|||
|
checkPath.slice(1),
|
|||
|
params
|
|||
|
)
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Run the verification by finding the formatted fingerprint in the proof
|
|||
|
* @async
|
|||
|
* @param {object} proofData - The proof data
|
|||
|
* @param {object} claimData - The claim data
|
|||
|
* @param {string} fingerprint - The fingerprint
|
|||
|
* @returns {Promise<object>}
|
|||
|
*/
|
|||
|
async function run (proofData, claimData, fingerprint) {
|
|||
|
const res = {
|
|||
|
result: false,
|
|||
|
completed: false,
|
|||
|
errors: []
|
|||
|
};
|
|||
|
|
|||
|
switch (claimData.proof.request.format) {
|
|||
|
case ProofFormat.JSON:
|
|||
|
for (let index = 0; index < claimData.claim.length; index++) {
|
|||
|
const claimMethod = claimData.claim[index];
|
|||
|
try {
|
|||
|
res.result = res.result || await runJSON(
|
|||
|
proofData,
|
|||
|
claimMethod.path,
|
|||
|
{
|
|||
|
target: fingerprint,
|
|||
|
claimFormat: claimMethod.format,
|
|||
|
proofEncodingFormat: claimMethod.encoding,
|
|||
|
claimRelation: claimMethod.relation
|
|||
|
}
|
|||
|
);
|
|||
|
} catch (error) {
|
|||
|
res.errors.push(error.message ? error.message : error);
|
|||
|
}
|
|||
|
}
|
|||
|
res.completed = true;
|
|||
|
break
|
|||
|
case ProofFormat.TEXT:
|
|||
|
for (let index = 0; index < claimData.claim.length; index++) {
|
|||
|
const claimMethod = claimData.claim[index];
|
|||
|
try {
|
|||
|
res.result = res.result || await containsProof(
|
|||
|
proofData,
|
|||
|
{
|
|||
|
target: fingerprint,
|
|||
|
claimFormat: claimMethod.format,
|
|||
|
proofEncodingFormat: claimMethod.encoding,
|
|||
|
claimRelation: claimMethod.relation
|
|||
|
}
|
|||
|
);
|
|||
|
} catch (error) {
|
|||
|
res.errors.push('err_unknown_text_verification');
|
|||
|
}
|
|||
|
}
|
|||
|
res.completed = true;
|
|||
|
break
|
|||
|
}
|
|||
|
|
|||
|
// Reset the errors if one of the claim methods was successful
|
|||
|
if (res.result) {
|
|||
|
res.errors = [];
|
|||
|
}
|
|||
|
|
|||
|
return res
|
|||
|
}
|
|||
|
|
|||
|
var verifications = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
run: run
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$k = /^dns:([a-zA-Z0-9.\-_]*)(?:\?(.*))?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$k (uri) {
|
|||
|
const match = uri.match(reURI$k);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'dns'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$k,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri: `https://${match[1]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: null,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.DNS,
|
|||
|
access: ProofAccess.SERVER,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
domain: match[1]
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['records', 'txt']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$k = [
|
|||
|
{
|
|||
|
uri: 'dns:domain.org',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'dns:domain.org?type=TXT',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var dns = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$k,
|
|||
|
reURI: reURI$k,
|
|||
|
tests: tests$k
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$j = /^irc:\/\/(.*)\/([a-zA-Z0-9\-[\]\\`_^{|}]*)/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$j (uri) {
|
|||
|
const match = uri.match(reURI$j);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'communication',
|
|||
|
name: 'irc'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$j,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `irc://${match[1]}/${match[2]}`,
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: null,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.IRC,
|
|||
|
access: ProofAccess.SERVER,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
domain: match[1],
|
|||
|
nick: match[2]
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: []
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$j = [
|
|||
|
{
|
|||
|
uri: 'irc://chat.ircserver.org/Alice1',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'irc://chat.ircserver.org/alice?param=123',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'irc://chat.ircserver.org/alice_bob',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://chat.ircserver.org/alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var irc = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$j,
|
|||
|
reURI: reURI$j,
|
|||
|
tests: tests$j
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$i = /^xmpp:([a-zA-Z0-9.\-_]*)@([a-zA-Z0-9.\-_]*)(?:\?(.*))?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$i (uri) {
|
|||
|
const match = uri.match(reURI$i);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'communication',
|
|||
|
name: 'xmpp'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$i,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `${match[1]}@${match[2]}`,
|
|||
|
uri,
|
|||
|
qr: uri
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: null,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.XMPP,
|
|||
|
access: ProofAccess.SERVER,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
id: `${match[1]}@${match[2]}`
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: []
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$i = [
|
|||
|
{
|
|||
|
uri: 'xmpp:alice@domain.org',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'xmpp:alice@domain.org?omemo-sid-123456789=A1B2C3D4E5F6G7H8I9',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var xmpp = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$i,
|
|||
|
reURI: reURI$i,
|
|||
|
tests: tests$i
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$h = /^matrix:u\/(?:@)?([^@:]*:[^?]*)(\?.*)?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$h (uri) {
|
|||
|
const match = uri.match(reURI$h);
|
|||
|
|
|||
|
if (!match[2]) {
|
|||
|
return null
|
|||
|
}
|
|||
|
|
|||
|
const params = new URLSearchParams(match[2]);
|
|||
|
|
|||
|
if (!(params.has('org.keyoxide.e') && params.has('org.keyoxide.r'))) {
|
|||
|
return null
|
|||
|
}
|
|||
|
|
|||
|
const paramRoomId = `${params.get('org.keyoxide.r')[0] !== '!' ? '!' : ''}${params.get('org.keyoxide.r')}`;
|
|||
|
const paramEventId = `${params.get('org.keyoxide.e')[0] !== '$' ? '$' : ''}${params.get('org.keyoxide.e')}`;
|
|||
|
|
|||
|
const profileUrl = `https://matrix.to/#/@${match[1]}`;
|
|||
|
const eventUrl = `https://matrix.to/#/${paramRoomId}/${paramEventId}`;
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'communication',
|
|||
|
name: 'matrix'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$h,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `@${match[1]}`,
|
|||
|
uri: profileUrl,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: eventUrl,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.MATRIX,
|
|||
|
access: ProofAccess.GRANTED,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
eventId: paramEventId,
|
|||
|
roomId: paramRoomId
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['content', 'body']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$h = [
|
|||
|
{
|
|||
|
uri:
|
|||
|
'matrix:u/alice:matrix.domain.org?org.keyoxide.r=123:domain.org&org.keyoxide.e=123',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'matrix:u/alice:matrix.domain.org',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri:
|
|||
|
'matrix:u/@alice:matrix.domain.org?org.keyoxide.r=!123:domain.org&org.keyoxide.e=$123',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'xmpp:alice@domain.org',
|
|||
|
shouldMatch: false
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/@alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var matrix = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$h,
|
|||
|
reURI: reURI$h,
|
|||
|
tests: tests$h
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2022 Maximilian Siling
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$g = /https:\/\/t.me\/([A-Za-z0-9_]{5,32})\?proof=([A-Za-z0-9_]{5,32})/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$g (uri) {
|
|||
|
const match = uri.match(reURI$g);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'communication',
|
|||
|
name: 'telegram'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$g,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `@${match[1]}`,
|
|||
|
uri: `https://t.me/${match[1]}`,
|
|||
|
qr: `https://t.me/${match[1]}`
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `https://t.me/${match[2]}`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.TELEGRAM,
|
|||
|
access: ProofAccess.GRANTED,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
user: match[1],
|
|||
|
chat: match[2]
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.EQUALS,
|
|||
|
path: ['text']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$g = [
|
|||
|
{
|
|||
|
uri: 'https://t.me/alice?proof=foobar',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://t.me/complex_user_1234?proof=complex_chat_1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://t.me/foobar',
|
|||
|
shouldMatch: false
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://t.me/foobar?proof=',
|
|||
|
shouldMatch: false
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://t.me/?proof=foobar',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var telegram = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$g,
|
|||
|
reURI: reURI$g,
|
|||
|
tests: tests$g
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$f = /^https:\/\/twitter\.com\/(.*)\/status\/([0-9]*)(?:\?.*)?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$f (uri) {
|
|||
|
const match = uri.match(reURI$f);
|
|||
|
|
|||
|
const urlsp = new URLSearchParams();
|
|||
|
urlsp.set('url', match[0]);
|
|||
|
urlsp.set('omit_script', '1');
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'twitter'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$f,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `@${match[1]}`,
|
|||
|
uri: `https://twitter.com/${match[1]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
// Returns an oembed json object with the tweet content in html form
|
|||
|
url: `https://publish.twitter.com/oembed?${urlsp}`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['html']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$f = [
|
|||
|
{
|
|||
|
uri: 'https://twitter.com/alice/status/1234567890123456789',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://twitter.com/alice/status/1234567890123456789/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/status/1234567890123456789',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var twitter = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$f,
|
|||
|
reURI: reURI$f,
|
|||
|
tests: tests$f
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$e = /^https:\/\/(?:www\.)?reddit\.com\/user\/(.*)\/comments\/(.*)\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$e (uri) {
|
|||
|
const match = uri.match(reURI$e);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'reddit'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$e,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri: `https://www.reddit.com/user/${match[1]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://www.reddit.com/user/${match[1]}/comments/${match[2]}.json`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['data', 'children', 'data', 'selftext']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$e = [
|
|||
|
{
|
|||
|
uri: 'https://www.reddit.com/user/Alice/comments/123456/post',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://www.reddit.com/user/Alice/comments/123456/post/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://reddit.com/user/Alice/comments/123456/post',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://reddit.com/user/Alice/comments/123456/post/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/user/Alice/comments/123456/post',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var reddit = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$e,
|
|||
|
reURI: reURI$e,
|
|||
|
tests: tests$e
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$d = /^https:\/\/liberapay\.com\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$d (uri) {
|
|||
|
const match = uri.match(reURI$d);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'liberapay'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$d,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://liberapay.com/${match[1]}/public.json`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['statements', 'content']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$d = [
|
|||
|
{
|
|||
|
uri: 'https://liberapay.com/alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://liberapay.com/alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var liberapay = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$d,
|
|||
|
reURI: reURI$d,
|
|||
|
tests: tests$d
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$c = /^https:\/\/lichess\.org\/@\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$c (uri) {
|
|||
|
const match = uri.match(reURI$c);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'lichess'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$c,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `https://lichess.org/api/user/${match[1]}`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://lichess.org/api/user/${match[1]}`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.FINGERPRINT,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['profile', 'links']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$c = [
|
|||
|
{
|
|||
|
uri: 'https://lichess.org/@/Alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://lichess.org/@/Alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/@/Alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var lichess = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$c,
|
|||
|
reURI: reURI$c,
|
|||
|
tests: tests$c
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$b = /^https:\/\/news\.ycombinator\.com\/user\?id=(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$b (uri) {
|
|||
|
const match = uri.match(reURI$b);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'hackernews'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$b,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `https://hacker-news.firebaseio.com/v0/user/${match[1]}.json`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://hacker-news.firebaseio.com/v0/user/${match[1]}.json`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.HTML,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['about']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$b = [
|
|||
|
{
|
|||
|
uri: 'https://news.ycombinator.com/user?id=Alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://news.ycombinator.com/user?id=Alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/user?id=Alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var hackernews = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$b,
|
|||
|
reURI: reURI$b,
|
|||
|
tests: tests$b
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$a = /^https:\/\/lobste\.rs\/u\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$a (uri) {
|
|||
|
const match = uri.match(reURI$a);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'lobsters'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$a,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `https://lobste.rs/u/${match[1]}.json`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://lobste.rs/u/${match[1]}.json`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['about']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$a = [
|
|||
|
{
|
|||
|
uri: 'https://lobste.rs/u/Alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://lobste.rs/u/Alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/u/Alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var lobsters = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$a,
|
|||
|
reURI: reURI$a,
|
|||
|
tests: tests$a
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$9 = /^https:\/\/(.*)\/(.*)\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$9 (uri) {
|
|||
|
const match = uri.match(reURI$9);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'forem'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$9,
|
|||
|
isAmbiguous: true
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `${match[2]}@${match[1]}`,
|
|||
|
uri: `https://${match[1]}/${match[2]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://${match[1]}/api/articles/${match[2]}/${match[3]}`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['body_markdown']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$9 = [
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/post',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/post/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var forem = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$9,
|
|||
|
reURI: reURI$9,
|
|||
|
tests: tests$9
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$8 = /^https:\/\/(.*)\/(.*)\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$8 (uri) {
|
|||
|
const match = uri.match(reURI$8);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'gitea'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$8,
|
|||
|
isAmbiguous: true
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `${match[2]}@${match[1]}`,
|
|||
|
uri: `https://${match[1]}/${match[2]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://${match[1]}/api/v1/repos/${match[2]}/${match[3]}`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.EQUALS,
|
|||
|
path: ['description']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$8 = [
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/gitea_proof',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/gitea_proof/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/other_proof',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var gitea = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$8,
|
|||
|
reURI: reURI$8,
|
|||
|
tests: tests$8
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$7 = /^https:\/\/(.*)\/(.*)\/gitlab_proof\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$7 (uri) {
|
|||
|
const match = uri.match(reURI$7);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'gitlab'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$7,
|
|||
|
isAmbiguous: true
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `${match[2]}@${match[1]}`,
|
|||
|
uri: `https://${match[1]}/${match[2]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://${match[1]}/api/v4/projects/${match[2]}%2Fgitlab_proof`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.EQUALS,
|
|||
|
path: ['description']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$7 = [
|
|||
|
{
|
|||
|
uri: 'https://gitlab.domain.org/alice/gitlab_proof',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://gitlab.domain.org/alice/gitlab_proof/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice/other_proof',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var gitlab = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$7,
|
|||
|
reURI: reURI$7,
|
|||
|
tests: tests$7
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$6 = /^https:\/\/gist\.github\.com\/(.*)\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$6 (uri) {
|
|||
|
const match = uri.match(reURI$6);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'github'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$6,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri: `https://github.com/${match[1]}`,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://api.github.com/gists/${match[2]}`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['files', 'openpgp.md', 'content']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$6 = [
|
|||
|
{
|
|||
|
uri: 'https://gist.github.com/Alice/123456789',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://gist.github.com/Alice/123456789/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/Alice/123456789',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var github = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$6,
|
|||
|
reURI: reURI$6,
|
|||
|
tests: tests$6
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2022 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$5 = /^https:\/\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$5 (uri) {
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'activitypub'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$5,
|
|||
|
isAmbiguous: true
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: uri,
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.ACTIVITYPUB,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: uri
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [
|
|||
|
{
|
|||
|
format: ClaimFormat.FINGERPRINT,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['summary']
|
|||
|
},
|
|||
|
{
|
|||
|
format: ClaimFormat.FINGERPRINT,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['attachment', 'value']
|
|||
|
},
|
|||
|
{
|
|||
|
format: ClaimFormat.FINGERPRINT,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['content']
|
|||
|
}
|
|||
|
]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const functions = {
|
|||
|
postprocess: (claimData, proofData) => {
|
|||
|
claimData.profile.display = `@${proofData.result.preferredUsername}@${new URL(proofData.result.url).hostname}`;
|
|||
|
return { claimData, proofData }
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
const tests$5 = [
|
|||
|
{
|
|||
|
uri: 'https://domain.org',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/@/alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/@alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/@alice/123456',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/u/alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/users/alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/users/alice/123456',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'http://domain.org/alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var activitypub = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
functions: functions,
|
|||
|
processURI: processURI$5,
|
|||
|
reURI: reURI$5,
|
|||
|
tests: tests$5
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$4 = /^https:\/\/(.*)\/u\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$4 (uri) {
|
|||
|
const match = uri.match(reURI$4);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'discourse'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$4,
|
|||
|
isAmbiguous: true
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `${match[2]}@${match[1]}`,
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://${match[1]}/u/${match[2]}.json`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['user', 'bio_raw']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$4 = [
|
|||
|
{
|
|||
|
uri: 'https://domain.org/u/alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/u/alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var discourse = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$4,
|
|||
|
reURI: reURI$4,
|
|||
|
tests: tests$4
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$3 = /^https:\/\/(.*)/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$3 (uri) {
|
|||
|
const match = uri.match(reURI$3);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'owncast'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$3,
|
|||
|
isAmbiguous: true
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `${uri}/api/config`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `${uri}/api/config`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.FINGERPRINT,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['socialHandles', 'url']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$3 = [
|
|||
|
{
|
|||
|
uri: 'https://live.domain.org',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://live.domain.org/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/live',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/live/',
|
|||
|
shouldMatch: true
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var owncast = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$3,
|
|||
|
reURI: reURI$3,
|
|||
|
tests: tests$3
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2022 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$2 = /^https:\/\/(.*(?:askubuntu|mathoverflow|serverfault|stackapps|stackoverflow|superuser)|.+\.stackexchange)\.com\/users\/(\d+)/;
|
|||
|
const reStackExchange = /\.stackexchange$/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$2 (uri) {
|
|||
|
const [, domain, id] = uri.match(reURI$2);
|
|||
|
const site = domain.replace(reStackExchange, '');
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'stackexchange'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$2,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: `${id}@${site}`,
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `https://${domain}.com/users/${id}?tab=profile`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.GENERIC,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://api.stackexchange.com/2.3/users/${id}?site=${site}&filter=!AH)b5JqVyImf`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['items', 'about_me']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$2 = [
|
|||
|
{
|
|||
|
uri: 'https://stackoverflow.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://stackoverflow.com/users/1234/alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://stackoverflow.com/users/1234?tab=topactivity',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://stackoverflow.com/users/1234/alice?tab=profile',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://meta.stackoverflow.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://pt.stackoverflow.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://pt.meta.stackoverflow.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://serverfault.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://meta.stackexchange.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://gaming.meta.stackexchange.com/users/1234',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://stackexchange.com/users/1234',
|
|||
|
shouldMatch: false
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.com/users/1234',
|
|||
|
shouldMatch: false
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://meta.domain.com/users/1234',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
|
|||
|
];
|
|||
|
|
|||
|
var stackexchange = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$2,
|
|||
|
reURI: reURI$2,
|
|||
|
tests: tests$2
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2023 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI$1 = /^https:\/\/keybase.io\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI$1 (uri) {
|
|||
|
const match = uri.match(reURI$1);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'keybase'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI$1,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri: `https://keybase.io/_/api/1.0/user/lookup.json?username=${match[1]}`,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.HTTP,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: `https://keybase.io/_/api/1.0/user/lookup.json?username=${match[1]}`,
|
|||
|
format: ProofFormat.JSON
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.FINGERPRINT,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['them', 'public_keys', 'primary', 'key_fingerprint']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests$1 = [
|
|||
|
{
|
|||
|
uri: 'https://keybase.io/Alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://keybase.io/Alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/Alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var keybase = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI$1,
|
|||
|
reURI: reURI$1,
|
|||
|
tests: tests$1
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2023 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const reURI = /^https:\/\/opencollective\.com\/(.*)\/?/;
|
|||
|
|
|||
|
/**
|
|||
|
* @function
|
|||
|
* @param {string} uri
|
|||
|
*/
|
|||
|
function processURI (uri) {
|
|||
|
const match = uri.match(reURI);
|
|||
|
|
|||
|
return {
|
|||
|
serviceprovider: {
|
|||
|
type: 'web',
|
|||
|
name: 'opencollective'
|
|||
|
},
|
|||
|
match: {
|
|||
|
regularExpression: reURI,
|
|||
|
isAmbiguous: false
|
|||
|
},
|
|||
|
profile: {
|
|||
|
display: match[1],
|
|||
|
uri,
|
|||
|
qr: null
|
|||
|
},
|
|||
|
proof: {
|
|||
|
uri,
|
|||
|
request: {
|
|||
|
fetcher: Fetcher.GRAPHQL,
|
|||
|
access: ProofAccess.NOCORS,
|
|||
|
format: ProofFormat.JSON,
|
|||
|
data: {
|
|||
|
url: 'https://api.opencollective.com/graphql/v2',
|
|||
|
query: `{ "query": "query { collective(slug: \\"${match[1]}\\") { longDescription } }" }`
|
|||
|
}
|
|||
|
}
|
|||
|
},
|
|||
|
claim: [{
|
|||
|
format: ClaimFormat.URI,
|
|||
|
encoding: EntityEncodingFormat.PLAIN,
|
|||
|
relation: ClaimRelation.CONTAINS,
|
|||
|
path: ['data', 'collective', 'longDescription']
|
|||
|
}]
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const tests = [
|
|||
|
{
|
|||
|
uri: 'https://opencollective.com/Alice',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://opencollective.com/Alice/',
|
|||
|
shouldMatch: true
|
|||
|
},
|
|||
|
{
|
|||
|
uri: 'https://domain.org/Alice',
|
|||
|
shouldMatch: false
|
|||
|
}
|
|||
|
];
|
|||
|
|
|||
|
var opencollective = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
processURI: processURI,
|
|||
|
reURI: reURI,
|
|||
|
tests: tests
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const _data = {
|
|||
|
dns,
|
|||
|
irc,
|
|||
|
xmpp,
|
|||
|
matrix,
|
|||
|
telegram,
|
|||
|
twitter,
|
|||
|
reddit,
|
|||
|
liberapay,
|
|||
|
lichess,
|
|||
|
hackernews,
|
|||
|
lobsters,
|
|||
|
forem,
|
|||
|
// forgejo,
|
|||
|
gitea,
|
|||
|
gitlab,
|
|||
|
github,
|
|||
|
activitypub,
|
|||
|
discourse,
|
|||
|
owncast,
|
|||
|
stackexchange,
|
|||
|
keybase,
|
|||
|
opencollective
|
|||
|
};
|
|||
|
|
|||
|
const list = Object.keys(_data);
|
|||
|
|
|||
|
var index = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
data: _data,
|
|||
|
list: list
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Contains default values
|
|||
|
* @module defaults
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* The default options used throughout the library
|
|||
|
* @constant {object}
|
|||
|
* @property {object} proxy - Options related to the proxy
|
|||
|
* @property {string|null} proxy.hostname - The hostname of the proxy
|
|||
|
* @property {string} proxy.policy - The policy that defines when to use a proxy ({@link module:enums~ProxyPolicy|here})
|
|||
|
* @property {object} claims - Options related to claim verification
|
|||
|
* @property {object} claims.activitypub - Options related to the verification of activitypub claims
|
|||
|
* @property {string|null} claims.activitypub.url - The URL of the verifier account
|
|||
|
* @property {string|null} claims.activitypub.privateKey - The private key to sign the request
|
|||
|
* @property {object} claims.irc - Options related to the verification of IRC claims
|
|||
|
* @property {string|null} claims.irc.nick - The nick that the library uses to connect to the IRC server
|
|||
|
* @property {object} claims.matrix - Options related to the verification of Matrix claims
|
|||
|
* @property {string|null} claims.matrix.instance - The server hostname on which the library can log in
|
|||
|
* @property {string|null} claims.matrix.accessToken - The access token required to identify the library ({@link https://www.matrix.org/docs/guides/client-server-api|Matrix docs})
|
|||
|
* @property {object} claims.telegram - Options related to the verification of Telegram claims
|
|||
|
* @property {string|null} claims.telegram.token - The Telegram API's token ({@link https://core.telegram.org/bots/api#authorizing-your-bot|Telegram docs})
|
|||
|
* @property {object} claims.xmpp - Options related to the verification of XMPP claims
|
|||
|
* @property {string|null} claims.xmpp.service - The server hostname on which the library can log in
|
|||
|
* @property {string|null} claims.xmpp.username - The username used to log in
|
|||
|
* @property {string|null} claims.xmpp.password - The password used to log in
|
|||
|
*/
|
|||
|
const opts = {
|
|||
|
proxy: {
|
|||
|
hostname: null,
|
|||
|
policy: ProxyPolicy.NEVER
|
|||
|
},
|
|||
|
claims: {
|
|||
|
activitypub: {
|
|||
|
url: null,
|
|||
|
privateKey: null
|
|||
|
},
|
|||
|
irc: {
|
|||
|
nick: null
|
|||
|
},
|
|||
|
matrix: {
|
|||
|
instance: null,
|
|||
|
accessToken: null
|
|||
|
},
|
|||
|
telegram: {
|
|||
|
token: null
|
|||
|
},
|
|||
|
xmpp: {
|
|||
|
service: null,
|
|||
|
username: null,
|
|||
|
password: null
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var defaults$3 = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
opts: opts
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @class
|
|||
|
* @classdesc OpenPGP-based identity claim
|
|||
|
* @property {string} uri - The claim's URI
|
|||
|
* @property {string} fingerprint - The fingerprint to verify the claim against
|
|||
|
* @property {string} status - The current status of the claim
|
|||
|
* @property {Array<object>} matches - The claim definitions matched against the URI
|
|||
|
* @property {object} verification - The result of the verification process
|
|||
|
*/
|
|||
|
class Claim {
|
|||
|
/**
|
|||
|
* Initialize a Claim object
|
|||
|
* @constructor
|
|||
|
* @param {string|object} [uri] - The URI of the identity claim or a JSONified Claim instance
|
|||
|
* @param {string} [fingerprint] - The fingerprint of the OpenPGP key
|
|||
|
* @example
|
|||
|
* const claim = doip.Claim();
|
|||
|
* const claim = doip.Claim('dns:domain.tld?type=TXT');
|
|||
|
* const claim = doip.Claim('dns:domain.tld?type=TXT', '123abc123abc');
|
|||
|
* const claimAlt = doip.Claim(JSON.stringify(claim));
|
|||
|
*/
|
|||
|
constructor (uri, fingerprint) {
|
|||
|
// Import JSON
|
|||
|
if (typeof uri === 'object' && 'claimVersion' in uri) {
|
|||
|
const data = uri;
|
|||
|
switch (data.claimVersion) {
|
|||
|
case 1:
|
|||
|
this._uri = data.uri;
|
|||
|
this._fingerprint = data.fingerprint;
|
|||
|
this._status = data.status;
|
|||
|
this._matches = data.matches;
|
|||
|
this._verification = data.verification;
|
|||
|
break
|
|||
|
|
|||
|
default:
|
|||
|
throw new Error('Invalid claim version')
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Verify validity of URI
|
|||
|
if (uri && !validUrlExports.isUri(uri)) {
|
|||
|
throw new Error('Invalid URI')
|
|||
|
}
|
|||
|
|
|||
|
// Verify validity of fingerprint
|
|||
|
if (fingerprint) {
|
|||
|
try {
|
|||
|
// @ts-ignore
|
|||
|
_default.default(fingerprint);
|
|||
|
} catch (err) {
|
|||
|
throw new Error('Invalid fingerprint')
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
this._uri = uri || '';
|
|||
|
this._fingerprint = fingerprint || '';
|
|||
|
this._status = ClaimStatus.INIT;
|
|||
|
this._matches = [];
|
|||
|
this._verification = {};
|
|||
|
}
|
|||
|
|
|||
|
get uri () {
|
|||
|
return this._uri
|
|||
|
}
|
|||
|
|
|||
|
get fingerprint () {
|
|||
|
return this._fingerprint
|
|||
|
}
|
|||
|
|
|||
|
get status () {
|
|||
|
return this._status
|
|||
|
}
|
|||
|
|
|||
|
get matches () {
|
|||
|
if (this._status === ClaimStatus.INIT) {
|
|||
|
throw new Error('This claim has not yet been matched')
|
|||
|
}
|
|||
|
return this._matches
|
|||
|
}
|
|||
|
|
|||
|
get verification () {
|
|||
|
if (this._status !== ClaimStatus.VERIFIED) {
|
|||
|
throw new Error('This claim has not yet been verified')
|
|||
|
}
|
|||
|
return this._verification
|
|||
|
}
|
|||
|
|
|||
|
set uri (uri) {
|
|||
|
if (this._status !== ClaimStatus.INIT) {
|
|||
|
throw new Error(
|
|||
|
'Cannot change the URI, this claim has already been matched'
|
|||
|
)
|
|||
|
}
|
|||
|
// Verify validity of URI
|
|||
|
if (uri.length > 0 && !validUrlExports.isUri(uri)) {
|
|||
|
throw new Error('The URI was invalid')
|
|||
|
}
|
|||
|
// Remove leading and trailing spaces
|
|||
|
uri = uri.replace(/^\s+|\s+$/g, '');
|
|||
|
|
|||
|
this._uri = uri;
|
|||
|
}
|
|||
|
|
|||
|
set fingerprint (fingerprint) {
|
|||
|
if (this._status === ClaimStatus.VERIFIED) {
|
|||
|
throw new Error(
|
|||
|
'Cannot change the fingerprint, this claim has already been verified'
|
|||
|
)
|
|||
|
}
|
|||
|
this._fingerprint = fingerprint;
|
|||
|
}
|
|||
|
|
|||
|
set status (anything) {
|
|||
|
throw new Error("Cannot change a claim's status")
|
|||
|
}
|
|||
|
|
|||
|
set matches (anything) {
|
|||
|
throw new Error("Cannot change a claim's matches")
|
|||
|
}
|
|||
|
|
|||
|
set verification (anything) {
|
|||
|
throw new Error("Cannot change a claim's verification result")
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Match the claim's URI to candidate definitions
|
|||
|
* @function
|
|||
|
*/
|
|||
|
match () {
|
|||
|
if (this._status !== ClaimStatus.INIT) {
|
|||
|
throw new Error('This claim was already matched')
|
|||
|
}
|
|||
|
if (this._uri.length === 0 || !validUrlExports.isUri(this._uri)) {
|
|||
|
throw new Error('This claim has no URI')
|
|||
|
}
|
|||
|
|
|||
|
this._matches = [];
|
|||
|
|
|||
|
list.every((name, i) => {
|
|||
|
const def = _data[name];
|
|||
|
|
|||
|
// If the candidate is invalid, continue matching
|
|||
|
if (!def.reURI.test(this._uri)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
|
|||
|
const candidate = def.processURI(this._uri);
|
|||
|
// If the candidate could not be processed, continue matching
|
|||
|
if (!candidate) {
|
|||
|
return true
|
|||
|
}
|
|||
|
|
|||
|
if (candidate.match.isAmbiguous) {
|
|||
|
// Add to the possible candidates
|
|||
|
this._matches.push(candidate);
|
|||
|
} else {
|
|||
|
// Set a single candidate and stop
|
|||
|
this._matches = [candidate];
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
// Continue matching
|
|||
|
return true
|
|||
|
});
|
|||
|
|
|||
|
this._status = ClaimStatus.MATCHED;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Verify the claim. The proof for each candidate is sequentially fetched and
|
|||
|
* checked for the fingerprint. The verification stops when either a positive
|
|||
|
* result was obtained, or an unambiguous claim definition was processed
|
|||
|
* regardless of the result.
|
|||
|
* @async
|
|||
|
* @function
|
|||
|
* @param {object} [opts] - Options for proxy, fetchers
|
|||
|
*/
|
|||
|
async verify (opts$1) {
|
|||
|
if (this._status === ClaimStatus.INIT) {
|
|||
|
throw new Error('This claim has not yet been matched')
|
|||
|
}
|
|||
|
if (this._status === ClaimStatus.VERIFIED) {
|
|||
|
throw new Error('This claim has already been verified')
|
|||
|
}
|
|||
|
if (this._fingerprint.length === 0) {
|
|||
|
throw new Error('This claim has no fingerprint')
|
|||
|
}
|
|||
|
|
|||
|
// Handle options
|
|||
|
opts$1 = mergeOptions$1(opts, opts$1 || {});
|
|||
|
|
|||
|
// If there are no matches
|
|||
|
if (this._matches.length === 0) {
|
|||
|
this._verification = {
|
|||
|
result: false,
|
|||
|
completed: true,
|
|||
|
proof: {},
|
|||
|
errors: ['No matches for claim']
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
// For each match
|
|||
|
for (let index = 0; index < this._matches.length; index++) {
|
|||
|
let claimData = this._matches[index];
|
|||
|
|
|||
|
let verificationResult = null;
|
|||
|
let proofData = null;
|
|||
|
let proofFetchError;
|
|||
|
|
|||
|
try {
|
|||
|
proofData = await fetch$2(claimData, opts$1);
|
|||
|
} catch (err) {
|
|||
|
proofFetchError = err;
|
|||
|
}
|
|||
|
|
|||
|
if (proofData) {
|
|||
|
// Run the verification process
|
|||
|
verificationResult = await run(
|
|||
|
proofData.result,
|
|||
|
claimData,
|
|||
|
this._fingerprint
|
|||
|
);
|
|||
|
verificationResult.proof = {
|
|||
|
fetcher: proofData.fetcher,
|
|||
|
viaProxy: proofData.viaProxy
|
|||
|
};
|
|||
|
|
|||
|
// Post process the data
|
|||
|
const def = _data[claimData.serviceprovider.name];
|
|||
|
if (def.functions?.postprocess) {
|
|||
|
try {
|
|||
|
({ claimData, proofData } = def.functions.postprocess(claimData, proofData));
|
|||
|
} catch (_) {}
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Consider the proof completed but with a negative result
|
|||
|
verificationResult = verificationResult || {
|
|||
|
result: false,
|
|||
|
completed: true,
|
|||
|
proof: {},
|
|||
|
errors: [proofFetchError]
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
if (this.isAmbiguous() && !verificationResult.result) {
|
|||
|
// Assume a wrong match and continue
|
|||
|
continue
|
|||
|
}
|
|||
|
|
|||
|
if (verificationResult.completed) {
|
|||
|
// Store the result, keep a single match and stop verifying
|
|||
|
this._verification = verificationResult;
|
|||
|
this._matches = [claimData];
|
|||
|
index = this._matches.length;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Fail safe verification result
|
|||
|
this._verification = Object.keys(this._verification).length > 0
|
|||
|
? this._verification
|
|||
|
: {
|
|||
|
result: false,
|
|||
|
completed: true,
|
|||
|
proof: {},
|
|||
|
errors: []
|
|||
|
};
|
|||
|
|
|||
|
this._status = ClaimStatus.VERIFIED;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine the ambiguity of the claim. A claim is only unambiguous if any
|
|||
|
* of the candidates is unambiguous. An ambiguous claim should never be
|
|||
|
* displayed in an user interface when its result is negative.
|
|||
|
* @function
|
|||
|
* @returns {boolean}
|
|||
|
*/
|
|||
|
isAmbiguous () {
|
|||
|
if (this._status === ClaimStatus.INIT) {
|
|||
|
throw new Error('The claim has not been matched yet')
|
|||
|
}
|
|||
|
if (this._matches.length === 0) {
|
|||
|
throw new Error('The claim has no matches')
|
|||
|
}
|
|||
|
return this._matches.length > 1 || this._matches[0].match.isAmbiguous
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get a JSON representation of the Claim object. Useful when transferring
|
|||
|
* data between instances/machines.
|
|||
|
* @function
|
|||
|
* @returns {object}
|
|||
|
*/
|
|||
|
toJSON () {
|
|||
|
return {
|
|||
|
claimVersion: 1,
|
|||
|
uri: this._uri,
|
|||
|
fingerprint: this._fingerprint,
|
|||
|
status: this._status,
|
|||
|
matches: this._matches,
|
|||
|
verification: this._verification
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2023 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
// eslint-disable-next-line
|
|||
|
|
|||
|
/**
|
|||
|
* A persona with identity claims
|
|||
|
* @class
|
|||
|
* @constructor
|
|||
|
* @public
|
|||
|
* @example
|
|||
|
* const claim = Claim('https://alice.tld', '123');
|
|||
|
* const pers = Persona('Alice', 'About Alice', [claim]);
|
|||
|
*/
|
|||
|
class Persona {
|
|||
|
/**
|
|||
|
* @param {string} name
|
|||
|
* @param {string} [description]
|
|||
|
* @param {Claim[]} [claims]
|
|||
|
*/
|
|||
|
constructor (name, description, claims) {
|
|||
|
/**
|
|||
|
* Name to be displayed on the profile page
|
|||
|
* @type {string}
|
|||
|
* @public
|
|||
|
*/
|
|||
|
this.name = name;
|
|||
|
/**
|
|||
|
* Description to be displayed on the profile page
|
|||
|
* @type {string}
|
|||
|
* @public
|
|||
|
*/
|
|||
|
this.description = description;
|
|||
|
/**
|
|||
|
* List of identity claims
|
|||
|
* @type {Array<Claim>}
|
|||
|
* @public
|
|||
|
*/
|
|||
|
this.claims = claims;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2023 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
// eslint-disable-next-line
|
|||
|
|
|||
|
/**
|
|||
|
* A profile of personas with identity claims
|
|||
|
* @function
|
|||
|
* @param {Array<Persona>} personas
|
|||
|
* @public
|
|||
|
* @example
|
|||
|
* const claim = Claim('https://alice.tld', '123');
|
|||
|
* const pers = Persona('Alice', 'About Alice', [claim]);
|
|||
|
* const profile = Profile([pers]);
|
|||
|
*/
|
|||
|
class Profile {
|
|||
|
/**
|
|||
|
* Create a new profile
|
|||
|
* @function
|
|||
|
* @param {Array<Persona>} personas
|
|||
|
* @public
|
|||
|
*/
|
|||
|
constructor (personas) {
|
|||
|
/**
|
|||
|
* List of personas
|
|||
|
* @type {Array<Persona>}
|
|||
|
* @public
|
|||
|
*/
|
|||
|
this.personas = personas || [];
|
|||
|
/**
|
|||
|
* Index of primary persona (to be displayed first or prominently)
|
|||
|
* @type {Number}
|
|||
|
* @public
|
|||
|
*/
|
|||
|
this.primaryPersona = -1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var axios$3 = {exports: {}};
|
|||
|
|
|||
|
var bind$2 = function bind(fn, thisArg) {
|
|||
|
return function wrap() {
|
|||
|
var args = new Array(arguments.length);
|
|||
|
for (var i = 0; i < args.length; i++) {
|
|||
|
args[i] = arguments[i];
|
|||
|
}
|
|||
|
return fn.apply(thisArg, args);
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
var bind$1 = bind$2;
|
|||
|
|
|||
|
// utils is a library of generic helper functions non-specific to axios
|
|||
|
|
|||
|
var toString = Object.prototype.toString;
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is an Array
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is an Array, otherwise false
|
|||
|
*/
|
|||
|
function isArray(val) {
|
|||
|
return Array.isArray(val);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is undefined
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if the value is undefined, otherwise false
|
|||
|
*/
|
|||
|
function isUndefined(val) {
|
|||
|
return typeof val === 'undefined';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a Buffer
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a Buffer, otherwise false
|
|||
|
*/
|
|||
|
function isBuffer(val) {
|
|||
|
return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
|
|||
|
&& typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is an ArrayBuffer
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is an ArrayBuffer, otherwise false
|
|||
|
*/
|
|||
|
function isArrayBuffer(val) {
|
|||
|
return toString.call(val) === '[object ArrayBuffer]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a FormData
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is an FormData, otherwise false
|
|||
|
*/
|
|||
|
function isFormData(val) {
|
|||
|
return toString.call(val) === '[object FormData]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a view on an ArrayBuffer
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
|
|||
|
*/
|
|||
|
function isArrayBufferView(val) {
|
|||
|
var result;
|
|||
|
if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
|
|||
|
result = ArrayBuffer.isView(val);
|
|||
|
} else {
|
|||
|
result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a String
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a String, otherwise false
|
|||
|
*/
|
|||
|
function isString(val) {
|
|||
|
return typeof val === 'string';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a Number
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a Number, otherwise false
|
|||
|
*/
|
|||
|
function isNumber(val) {
|
|||
|
return typeof val === 'number';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is an Object
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is an Object, otherwise false
|
|||
|
*/
|
|||
|
function isObject$1(val) {
|
|||
|
return val !== null && typeof val === 'object';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a plain Object
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @return {boolean} True if value is a plain Object, otherwise false
|
|||
|
*/
|
|||
|
function isPlainObject(val) {
|
|||
|
if (toString.call(val) !== '[object Object]') {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
var prototype = Object.getPrototypeOf(val);
|
|||
|
return prototype === null || prototype === Object.prototype;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a Date
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a Date, otherwise false
|
|||
|
*/
|
|||
|
function isDate(val) {
|
|||
|
return toString.call(val) === '[object Date]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a File
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a File, otherwise false
|
|||
|
*/
|
|||
|
function isFile(val) {
|
|||
|
return toString.call(val) === '[object File]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a Blob
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a Blob, otherwise false
|
|||
|
*/
|
|||
|
function isBlob(val) {
|
|||
|
return toString.call(val) === '[object Blob]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a Function
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a Function, otherwise false
|
|||
|
*/
|
|||
|
function isFunction(val) {
|
|||
|
return toString.call(val) === '[object Function]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a Stream
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a Stream, otherwise false
|
|||
|
*/
|
|||
|
function isStream(val) {
|
|||
|
return isObject$1(val) && isFunction(val.pipe);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a value is a URLSearchParams object
|
|||
|
*
|
|||
|
* @param {Object} val The value to test
|
|||
|
* @returns {boolean} True if value is a URLSearchParams object, otherwise false
|
|||
|
*/
|
|||
|
function isURLSearchParams(val) {
|
|||
|
return toString.call(val) === '[object URLSearchParams]';
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Trim excess whitespace off the beginning and end of a string
|
|||
|
*
|
|||
|
* @param {String} str The String to trim
|
|||
|
* @returns {String} The String freed of excess whitespace
|
|||
|
*/
|
|||
|
function trim(str) {
|
|||
|
return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if we're running in a standard browser environment
|
|||
|
*
|
|||
|
* This allows axios to run in a web worker, and react-native.
|
|||
|
* Both environments support XMLHttpRequest, but not fully standard globals.
|
|||
|
*
|
|||
|
* web workers:
|
|||
|
* typeof window -> undefined
|
|||
|
* typeof document -> undefined
|
|||
|
*
|
|||
|
* react-native:
|
|||
|
* navigator.product -> 'ReactNative'
|
|||
|
* nativescript
|
|||
|
* navigator.product -> 'NativeScript' or 'NS'
|
|||
|
*/
|
|||
|
function isStandardBrowserEnv() {
|
|||
|
if (typeof navigator !== 'undefined' && (navigator.product === 'ReactNative' ||
|
|||
|
navigator.product === 'NativeScript' ||
|
|||
|
navigator.product === 'NS')) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
return (
|
|||
|
typeof window !== 'undefined' &&
|
|||
|
typeof document !== 'undefined'
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Iterate over an Array or an Object invoking a function for each item.
|
|||
|
*
|
|||
|
* If `obj` is an Array callback will be called passing
|
|||
|
* the value, index, and complete array for each item.
|
|||
|
*
|
|||
|
* If 'obj' is an Object callback will be called passing
|
|||
|
* the value, key, and complete object for each property.
|
|||
|
*
|
|||
|
* @param {Object|Array} obj The object to iterate
|
|||
|
* @param {Function} fn The callback to invoke for each item
|
|||
|
*/
|
|||
|
function forEach(obj, fn) {
|
|||
|
// Don't bother if no value provided
|
|||
|
if (obj === null || typeof obj === 'undefined') {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// Force an array if not already something iterable
|
|||
|
if (typeof obj !== 'object') {
|
|||
|
/*eslint no-param-reassign:0*/
|
|||
|
obj = [obj];
|
|||
|
}
|
|||
|
|
|||
|
if (isArray(obj)) {
|
|||
|
// Iterate over array values
|
|||
|
for (var i = 0, l = obj.length; i < l; i++) {
|
|||
|
fn.call(null, obj[i], i, obj);
|
|||
|
}
|
|||
|
} else {
|
|||
|
// Iterate over object keys
|
|||
|
for (var key in obj) {
|
|||
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|||
|
fn.call(null, obj[key], key, obj);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Accepts varargs expecting each argument to be an object, then
|
|||
|
* immutably merges the properties of each object and returns result.
|
|||
|
*
|
|||
|
* When multiple objects contain the same key the later object in
|
|||
|
* the arguments list will take precedence.
|
|||
|
*
|
|||
|
* Example:
|
|||
|
*
|
|||
|
* ```js
|
|||
|
* var result = merge({foo: 123}, {foo: 456});
|
|||
|
* console.log(result.foo); // outputs 456
|
|||
|
* ```
|
|||
|
*
|
|||
|
* @param {Object} obj1 Object to merge
|
|||
|
* @returns {Object} Result of all merge properties
|
|||
|
*/
|
|||
|
function merge(/* obj1, obj2, obj3, ... */) {
|
|||
|
var result = {};
|
|||
|
function assignValue(val, key) {
|
|||
|
if (isPlainObject(result[key]) && isPlainObject(val)) {
|
|||
|
result[key] = merge(result[key], val);
|
|||
|
} else if (isPlainObject(val)) {
|
|||
|
result[key] = merge({}, val);
|
|||
|
} else if (isArray(val)) {
|
|||
|
result[key] = val.slice();
|
|||
|
} else {
|
|||
|
result[key] = val;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
for (var i = 0, l = arguments.length; i < l; i++) {
|
|||
|
forEach(arguments[i], assignValue);
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Extends object a by mutably adding to it the properties of object b.
|
|||
|
*
|
|||
|
* @param {Object} a The object to be extended
|
|||
|
* @param {Object} b The object to copy properties from
|
|||
|
* @param {Object} thisArg The object to bind function to
|
|||
|
* @return {Object} The resulting value of object a
|
|||
|
*/
|
|||
|
function extend(a, b, thisArg) {
|
|||
|
forEach(b, function assignValue(val, key) {
|
|||
|
if (thisArg && typeof val === 'function') {
|
|||
|
a[key] = bind$1(val, thisArg);
|
|||
|
} else {
|
|||
|
a[key] = val;
|
|||
|
}
|
|||
|
});
|
|||
|
return a;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
|
|||
|
*
|
|||
|
* @param {string} content with BOM
|
|||
|
* @return {string} content value without BOM
|
|||
|
*/
|
|||
|
function stripBOM(content) {
|
|||
|
if (content.charCodeAt(0) === 0xFEFF) {
|
|||
|
content = content.slice(1);
|
|||
|
}
|
|||
|
return content;
|
|||
|
}
|
|||
|
|
|||
|
var utils$8 = {
|
|||
|
isArray: isArray,
|
|||
|
isArrayBuffer: isArrayBuffer,
|
|||
|
isBuffer: isBuffer,
|
|||
|
isFormData: isFormData,
|
|||
|
isArrayBufferView: isArrayBufferView,
|
|||
|
isString: isString,
|
|||
|
isNumber: isNumber,
|
|||
|
isObject: isObject$1,
|
|||
|
isPlainObject: isPlainObject,
|
|||
|
isUndefined: isUndefined,
|
|||
|
isDate: isDate,
|
|||
|
isFile: isFile,
|
|||
|
isBlob: isBlob,
|
|||
|
isFunction: isFunction,
|
|||
|
isStream: isStream,
|
|||
|
isURLSearchParams: isURLSearchParams,
|
|||
|
isStandardBrowserEnv: isStandardBrowserEnv,
|
|||
|
forEach: forEach,
|
|||
|
merge: merge,
|
|||
|
extend: extend,
|
|||
|
trim: trim,
|
|||
|
stripBOM: stripBOM
|
|||
|
};
|
|||
|
|
|||
|
var utils$7 = utils$8;
|
|||
|
|
|||
|
function encode$1(val) {
|
|||
|
return encodeURIComponent(val).
|
|||
|
replace(/%3A/gi, ':').
|
|||
|
replace(/%24/g, '$').
|
|||
|
replace(/%2C/gi, ',').
|
|||
|
replace(/%20/g, '+').
|
|||
|
replace(/%5B/gi, '[').
|
|||
|
replace(/%5D/gi, ']');
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Build a URL by appending params to the end
|
|||
|
*
|
|||
|
* @param {string} url The base of the url (e.g., http://www.google.com)
|
|||
|
* @param {object} [params] The params to be appended
|
|||
|
* @returns {string} The formatted url
|
|||
|
*/
|
|||
|
var buildURL$1 = function buildURL(url, params, paramsSerializer) {
|
|||
|
/*eslint no-param-reassign:0*/
|
|||
|
if (!params) {
|
|||
|
return url;
|
|||
|
}
|
|||
|
|
|||
|
var serializedParams;
|
|||
|
if (paramsSerializer) {
|
|||
|
serializedParams = paramsSerializer(params);
|
|||
|
} else if (utils$7.isURLSearchParams(params)) {
|
|||
|
serializedParams = params.toString();
|
|||
|
} else {
|
|||
|
var parts = [];
|
|||
|
|
|||
|
utils$7.forEach(params, function serialize(val, key) {
|
|||
|
if (val === null || typeof val === 'undefined') {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (utils$7.isArray(val)) {
|
|||
|
key = key + '[]';
|
|||
|
} else {
|
|||
|
val = [val];
|
|||
|
}
|
|||
|
|
|||
|
utils$7.forEach(val, function parseValue(v) {
|
|||
|
if (utils$7.isDate(v)) {
|
|||
|
v = v.toISOString();
|
|||
|
} else if (utils$7.isObject(v)) {
|
|||
|
v = JSON.stringify(v);
|
|||
|
}
|
|||
|
parts.push(encode$1(key) + '=' + encode$1(v));
|
|||
|
});
|
|||
|
});
|
|||
|
|
|||
|
serializedParams = parts.join('&');
|
|||
|
}
|
|||
|
|
|||
|
if (serializedParams) {
|
|||
|
var hashmarkIndex = url.indexOf('#');
|
|||
|
if (hashmarkIndex !== -1) {
|
|||
|
url = url.slice(0, hashmarkIndex);
|
|||
|
}
|
|||
|
|
|||
|
url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
|
|||
|
}
|
|||
|
|
|||
|
return url;
|
|||
|
};
|
|||
|
|
|||
|
var utils$6 = utils$8;
|
|||
|
|
|||
|
function InterceptorManager$1() {
|
|||
|
this.handlers = [];
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Add a new interceptor to the stack
|
|||
|
*
|
|||
|
* @param {Function} fulfilled The function to handle `then` for a `Promise`
|
|||
|
* @param {Function} rejected The function to handle `reject` for a `Promise`
|
|||
|
*
|
|||
|
* @return {Number} An ID used to remove interceptor later
|
|||
|
*/
|
|||
|
InterceptorManager$1.prototype.use = function use(fulfilled, rejected, options) {
|
|||
|
this.handlers.push({
|
|||
|
fulfilled: fulfilled,
|
|||
|
rejected: rejected,
|
|||
|
synchronous: options ? options.synchronous : false,
|
|||
|
runWhen: options ? options.runWhen : null
|
|||
|
});
|
|||
|
return this.handlers.length - 1;
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Remove an interceptor from the stack
|
|||
|
*
|
|||
|
* @param {Number} id The ID that was returned by `use`
|
|||
|
*/
|
|||
|
InterceptorManager$1.prototype.eject = function eject(id) {
|
|||
|
if (this.handlers[id]) {
|
|||
|
this.handlers[id] = null;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Iterate over all the registered interceptors
|
|||
|
*
|
|||
|
* This method is particularly useful for skipping over any
|
|||
|
* interceptors that may have become `null` calling `eject`.
|
|||
|
*
|
|||
|
* @param {Function} fn The function to call for each interceptor
|
|||
|
*/
|
|||
|
InterceptorManager$1.prototype.forEach = function forEach(fn) {
|
|||
|
utils$6.forEach(this.handlers, function forEachHandler(h) {
|
|||
|
if (h !== null) {
|
|||
|
fn(h);
|
|||
|
}
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
var InterceptorManager_1 = InterceptorManager$1;
|
|||
|
|
|||
|
var utils$5 = utils$8;
|
|||
|
|
|||
|
var normalizeHeaderName = function normalizeHeaderName(headers, normalizedName) {
|
|||
|
utils$5.forEach(headers, function processHeader(value, name) {
|
|||
|
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
|
|||
|
headers[normalizedName] = value;
|
|||
|
delete headers[name];
|
|||
|
}
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Update an Error with the specified config, error code, and response.
|
|||
|
*
|
|||
|
* @param {Error} error The error to update.
|
|||
|
* @param {Object} config The config.
|
|||
|
* @param {string} [code] The error code (for example, 'ECONNABORTED').
|
|||
|
* @param {Object} [request] The request.
|
|||
|
* @param {Object} [response] The response.
|
|||
|
* @returns {Error} The error.
|
|||
|
*/
|
|||
|
var enhanceError = function enhanceError(error, config, code, request, response) {
|
|||
|
error.config = config;
|
|||
|
if (code) {
|
|||
|
error.code = code;
|
|||
|
}
|
|||
|
|
|||
|
error.request = request;
|
|||
|
error.response = response;
|
|||
|
error.isAxiosError = true;
|
|||
|
|
|||
|
error.toJSON = function toJSON() {
|
|||
|
return {
|
|||
|
// Standard
|
|||
|
message: this.message,
|
|||
|
name: this.name,
|
|||
|
// Microsoft
|
|||
|
description: this.description,
|
|||
|
number: this.number,
|
|||
|
// Mozilla
|
|||
|
fileName: this.fileName,
|
|||
|
lineNumber: this.lineNumber,
|
|||
|
columnNumber: this.columnNumber,
|
|||
|
stack: this.stack,
|
|||
|
// Axios
|
|||
|
config: this.config,
|
|||
|
code: this.code,
|
|||
|
status: this.response && this.response.status ? this.response.status : null
|
|||
|
};
|
|||
|
};
|
|||
|
return error;
|
|||
|
};
|
|||
|
|
|||
|
var createError;
|
|||
|
var hasRequiredCreateError;
|
|||
|
|
|||
|
function requireCreateError () {
|
|||
|
if (hasRequiredCreateError) return createError;
|
|||
|
hasRequiredCreateError = 1;
|
|||
|
|
|||
|
var enhanceError$1 = enhanceError;
|
|||
|
|
|||
|
/**
|
|||
|
* Create an Error with the specified message, config, error code, request and response.
|
|||
|
*
|
|||
|
* @param {string} message The error message.
|
|||
|
* @param {Object} config The config.
|
|||
|
* @param {string} [code] The error code (for example, 'ECONNABORTED').
|
|||
|
* @param {Object} [request] The request.
|
|||
|
* @param {Object} [response] The response.
|
|||
|
* @returns {Error} The created error.
|
|||
|
*/
|
|||
|
createError = function createError(message, config, code, request, response) {
|
|||
|
var error = new Error(message);
|
|||
|
return enhanceError$1(error, config, code, request, response);
|
|||
|
};
|
|||
|
return createError;
|
|||
|
}
|
|||
|
|
|||
|
var settle;
|
|||
|
var hasRequiredSettle;
|
|||
|
|
|||
|
function requireSettle () {
|
|||
|
if (hasRequiredSettle) return settle;
|
|||
|
hasRequiredSettle = 1;
|
|||
|
|
|||
|
var createError = requireCreateError();
|
|||
|
|
|||
|
/**
|
|||
|
* Resolve or reject a Promise based on response status.
|
|||
|
*
|
|||
|
* @param {Function} resolve A function that resolves the promise.
|
|||
|
* @param {Function} reject A function that rejects the promise.
|
|||
|
* @param {object} response The response.
|
|||
|
*/
|
|||
|
settle = function settle(resolve, reject, response) {
|
|||
|
var validateStatus = response.config.validateStatus;
|
|||
|
if (!response.status || !validateStatus || validateStatus(response.status)) {
|
|||
|
resolve(response);
|
|||
|
} else {
|
|||
|
reject(createError(
|
|||
|
'Request failed with status code ' + response.status,
|
|||
|
response.config,
|
|||
|
null,
|
|||
|
response.request,
|
|||
|
response
|
|||
|
));
|
|||
|
}
|
|||
|
};
|
|||
|
return settle;
|
|||
|
}
|
|||
|
|
|||
|
var cookies;
|
|||
|
var hasRequiredCookies;
|
|||
|
|
|||
|
function requireCookies () {
|
|||
|
if (hasRequiredCookies) return cookies;
|
|||
|
hasRequiredCookies = 1;
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
|
|||
|
cookies = (
|
|||
|
utils.isStandardBrowserEnv() ?
|
|||
|
|
|||
|
// Standard browser envs support document.cookie
|
|||
|
(function standardBrowserEnv() {
|
|||
|
return {
|
|||
|
write: function write(name, value, expires, path, domain, secure) {
|
|||
|
var cookie = [];
|
|||
|
cookie.push(name + '=' + encodeURIComponent(value));
|
|||
|
|
|||
|
if (utils.isNumber(expires)) {
|
|||
|
cookie.push('expires=' + new Date(expires).toGMTString());
|
|||
|
}
|
|||
|
|
|||
|
if (utils.isString(path)) {
|
|||
|
cookie.push('path=' + path);
|
|||
|
}
|
|||
|
|
|||
|
if (utils.isString(domain)) {
|
|||
|
cookie.push('domain=' + domain);
|
|||
|
}
|
|||
|
|
|||
|
if (secure === true) {
|
|||
|
cookie.push('secure');
|
|||
|
}
|
|||
|
|
|||
|
document.cookie = cookie.join('; ');
|
|||
|
},
|
|||
|
|
|||
|
read: function read(name) {
|
|||
|
var match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
|
|||
|
return (match ? decodeURIComponent(match[3]) : null);
|
|||
|
},
|
|||
|
|
|||
|
remove: function remove(name) {
|
|||
|
this.write(name, '', Date.now() - 86400000);
|
|||
|
}
|
|||
|
};
|
|||
|
})() :
|
|||
|
|
|||
|
// Non standard browser env (web workers, react-native) lack needed support.
|
|||
|
(function nonStandardBrowserEnv() {
|
|||
|
return {
|
|||
|
write: function write() {},
|
|||
|
read: function read() { return null; },
|
|||
|
remove: function remove() {}
|
|||
|
};
|
|||
|
})()
|
|||
|
);
|
|||
|
return cookies;
|
|||
|
}
|
|||
|
|
|||
|
var isAbsoluteURL;
|
|||
|
var hasRequiredIsAbsoluteURL;
|
|||
|
|
|||
|
function requireIsAbsoluteURL () {
|
|||
|
if (hasRequiredIsAbsoluteURL) return isAbsoluteURL;
|
|||
|
hasRequiredIsAbsoluteURL = 1;
|
|||
|
|
|||
|
/**
|
|||
|
* Determines whether the specified URL is absolute
|
|||
|
*
|
|||
|
* @param {string} url The URL to test
|
|||
|
* @returns {boolean} True if the specified URL is absolute, otherwise false
|
|||
|
*/
|
|||
|
isAbsoluteURL = function isAbsoluteURL(url) {
|
|||
|
// A URL is considered absolute if it begins with "<scheme>://" or "//" (protocol-relative URL).
|
|||
|
// RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed
|
|||
|
// by any combination of letters, digits, plus, period, or hyphen.
|
|||
|
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
|
|||
|
};
|
|||
|
return isAbsoluteURL;
|
|||
|
}
|
|||
|
|
|||
|
var combineURLs;
|
|||
|
var hasRequiredCombineURLs;
|
|||
|
|
|||
|
function requireCombineURLs () {
|
|||
|
if (hasRequiredCombineURLs) return combineURLs;
|
|||
|
hasRequiredCombineURLs = 1;
|
|||
|
|
|||
|
/**
|
|||
|
* Creates a new URL by combining the specified URLs
|
|||
|
*
|
|||
|
* @param {string} baseURL The base URL
|
|||
|
* @param {string} relativeURL The relative URL
|
|||
|
* @returns {string} The combined URL
|
|||
|
*/
|
|||
|
combineURLs = function combineURLs(baseURL, relativeURL) {
|
|||
|
return relativeURL
|
|||
|
? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
|
|||
|
: baseURL;
|
|||
|
};
|
|||
|
return combineURLs;
|
|||
|
}
|
|||
|
|
|||
|
var buildFullPath;
|
|||
|
var hasRequiredBuildFullPath;
|
|||
|
|
|||
|
function requireBuildFullPath () {
|
|||
|
if (hasRequiredBuildFullPath) return buildFullPath;
|
|||
|
hasRequiredBuildFullPath = 1;
|
|||
|
|
|||
|
var isAbsoluteURL = requireIsAbsoluteURL();
|
|||
|
var combineURLs = requireCombineURLs();
|
|||
|
|
|||
|
/**
|
|||
|
* Creates a new URL by combining the baseURL with the requestedURL,
|
|||
|
* only when the requestedURL is not already an absolute URL.
|
|||
|
* If the requestURL is absolute, this function returns the requestedURL untouched.
|
|||
|
*
|
|||
|
* @param {string} baseURL The base URL
|
|||
|
* @param {string} requestedURL Absolute or relative URL to combine
|
|||
|
* @returns {string} The combined full path
|
|||
|
*/
|
|||
|
buildFullPath = function buildFullPath(baseURL, requestedURL) {
|
|||
|
if (baseURL && !isAbsoluteURL(requestedURL)) {
|
|||
|
return combineURLs(baseURL, requestedURL);
|
|||
|
}
|
|||
|
return requestedURL;
|
|||
|
};
|
|||
|
return buildFullPath;
|
|||
|
}
|
|||
|
|
|||
|
var parseHeaders;
|
|||
|
var hasRequiredParseHeaders;
|
|||
|
|
|||
|
function requireParseHeaders () {
|
|||
|
if (hasRequiredParseHeaders) return parseHeaders;
|
|||
|
hasRequiredParseHeaders = 1;
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
|
|||
|
// Headers whose duplicates are ignored by node
|
|||
|
// c.f. https://nodejs.org/api/http.html#http_message_headers
|
|||
|
var ignoreDuplicateOf = [
|
|||
|
'age', 'authorization', 'content-length', 'content-type', 'etag',
|
|||
|
'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since',
|
|||
|
'last-modified', 'location', 'max-forwards', 'proxy-authorization',
|
|||
|
'referer', 'retry-after', 'user-agent'
|
|||
|
];
|
|||
|
|
|||
|
/**
|
|||
|
* Parse headers into an object
|
|||
|
*
|
|||
|
* ```
|
|||
|
* Date: Wed, 27 Aug 2014 08:58:49 GMT
|
|||
|
* Content-Type: application/json
|
|||
|
* Connection: keep-alive
|
|||
|
* Transfer-Encoding: chunked
|
|||
|
* ```
|
|||
|
*
|
|||
|
* @param {String} headers Headers needing to be parsed
|
|||
|
* @returns {Object} Headers parsed into an object
|
|||
|
*/
|
|||
|
parseHeaders = function parseHeaders(headers) {
|
|||
|
var parsed = {};
|
|||
|
var key;
|
|||
|
var val;
|
|||
|
var i;
|
|||
|
|
|||
|
if (!headers) { return parsed; }
|
|||
|
|
|||
|
utils.forEach(headers.split('\n'), function parser(line) {
|
|||
|
i = line.indexOf(':');
|
|||
|
key = utils.trim(line.substr(0, i)).toLowerCase();
|
|||
|
val = utils.trim(line.substr(i + 1));
|
|||
|
|
|||
|
if (key) {
|
|||
|
if (parsed[key] && ignoreDuplicateOf.indexOf(key) >= 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
if (key === 'set-cookie') {
|
|||
|
parsed[key] = (parsed[key] ? parsed[key] : []).concat([val]);
|
|||
|
} else {
|
|||
|
parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return parsed;
|
|||
|
};
|
|||
|
return parseHeaders;
|
|||
|
}
|
|||
|
|
|||
|
var isURLSameOrigin;
|
|||
|
var hasRequiredIsURLSameOrigin;
|
|||
|
|
|||
|
function requireIsURLSameOrigin () {
|
|||
|
if (hasRequiredIsURLSameOrigin) return isURLSameOrigin;
|
|||
|
hasRequiredIsURLSameOrigin = 1;
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
|
|||
|
isURLSameOrigin = (
|
|||
|
utils.isStandardBrowserEnv() ?
|
|||
|
|
|||
|
// Standard browser envs have full support of the APIs needed to test
|
|||
|
// whether the request URL is of the same origin as current location.
|
|||
|
(function standardBrowserEnv() {
|
|||
|
var msie = /(msie|trident)/i.test(navigator.userAgent);
|
|||
|
var urlParsingNode = document.createElement('a');
|
|||
|
var originURL;
|
|||
|
|
|||
|
/**
|
|||
|
* Parse a URL to discover it's components
|
|||
|
*
|
|||
|
* @param {String} url The URL to be parsed
|
|||
|
* @returns {Object}
|
|||
|
*/
|
|||
|
function resolveURL(url) {
|
|||
|
var href = url;
|
|||
|
|
|||
|
if (msie) {
|
|||
|
// IE needs attribute set twice to normalize properties
|
|||
|
urlParsingNode.setAttribute('href', href);
|
|||
|
href = urlParsingNode.href;
|
|||
|
}
|
|||
|
|
|||
|
urlParsingNode.setAttribute('href', href);
|
|||
|
|
|||
|
// urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
|
|||
|
return {
|
|||
|
href: urlParsingNode.href,
|
|||
|
protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
|
|||
|
host: urlParsingNode.host,
|
|||
|
search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
|
|||
|
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
|
|||
|
hostname: urlParsingNode.hostname,
|
|||
|
port: urlParsingNode.port,
|
|||
|
pathname: (urlParsingNode.pathname.charAt(0) === '/') ?
|
|||
|
urlParsingNode.pathname :
|
|||
|
'/' + urlParsingNode.pathname
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
originURL = resolveURL(window.location.href);
|
|||
|
|
|||
|
/**
|
|||
|
* Determine if a URL shares the same origin as the current location
|
|||
|
*
|
|||
|
* @param {String} requestURL The URL to test
|
|||
|
* @returns {boolean} True if URL shares the same origin, otherwise false
|
|||
|
*/
|
|||
|
return function isURLSameOrigin(requestURL) {
|
|||
|
var parsed = (utils.isString(requestURL)) ? resolveURL(requestURL) : requestURL;
|
|||
|
return (parsed.protocol === originURL.protocol &&
|
|||
|
parsed.host === originURL.host);
|
|||
|
};
|
|||
|
})() :
|
|||
|
|
|||
|
// Non standard browser envs (web workers, react-native) lack needed support.
|
|||
|
(function nonStandardBrowserEnv() {
|
|||
|
return function isURLSameOrigin() {
|
|||
|
return true;
|
|||
|
};
|
|||
|
})()
|
|||
|
);
|
|||
|
return isURLSameOrigin;
|
|||
|
}
|
|||
|
|
|||
|
var Cancel_1;
|
|||
|
var hasRequiredCancel;
|
|||
|
|
|||
|
function requireCancel () {
|
|||
|
if (hasRequiredCancel) return Cancel_1;
|
|||
|
hasRequiredCancel = 1;
|
|||
|
|
|||
|
/**
|
|||
|
* A `Cancel` is an object that is thrown when an operation is canceled.
|
|||
|
*
|
|||
|
* @class
|
|||
|
* @param {string=} message The message.
|
|||
|
*/
|
|||
|
function Cancel(message) {
|
|||
|
this.message = message;
|
|||
|
}
|
|||
|
|
|||
|
Cancel.prototype.toString = function toString() {
|
|||
|
return 'Cancel' + (this.message ? ': ' + this.message : '');
|
|||
|
};
|
|||
|
|
|||
|
Cancel.prototype.__CANCEL__ = true;
|
|||
|
|
|||
|
Cancel_1 = Cancel;
|
|||
|
return Cancel_1;
|
|||
|
}
|
|||
|
|
|||
|
var xhr;
|
|||
|
var hasRequiredXhr;
|
|||
|
|
|||
|
function requireXhr () {
|
|||
|
if (hasRequiredXhr) return xhr;
|
|||
|
hasRequiredXhr = 1;
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
var settle = requireSettle();
|
|||
|
var cookies = requireCookies();
|
|||
|
var buildURL = buildURL$1;
|
|||
|
var buildFullPath = requireBuildFullPath();
|
|||
|
var parseHeaders = requireParseHeaders();
|
|||
|
var isURLSameOrigin = requireIsURLSameOrigin();
|
|||
|
var createError = requireCreateError();
|
|||
|
var defaults = requireDefaults();
|
|||
|
var Cancel = requireCancel();
|
|||
|
|
|||
|
xhr = function xhrAdapter(config) {
|
|||
|
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
|||
|
var requestData = config.data;
|
|||
|
var requestHeaders = config.headers;
|
|||
|
var responseType = config.responseType;
|
|||
|
var onCanceled;
|
|||
|
function done() {
|
|||
|
if (config.cancelToken) {
|
|||
|
config.cancelToken.unsubscribe(onCanceled);
|
|||
|
}
|
|||
|
|
|||
|
if (config.signal) {
|
|||
|
config.signal.removeEventListener('abort', onCanceled);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (utils.isFormData(requestData)) {
|
|||
|
delete requestHeaders['Content-Type']; // Let the browser set it
|
|||
|
}
|
|||
|
|
|||
|
var request = new XMLHttpRequest();
|
|||
|
|
|||
|
// HTTP basic authentication
|
|||
|
if (config.auth) {
|
|||
|
var username = config.auth.username || '';
|
|||
|
var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
|
|||
|
requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
|
|||
|
}
|
|||
|
|
|||
|
var fullPath = buildFullPath(config.baseURL, config.url);
|
|||
|
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
|
|||
|
|
|||
|
// Set the request timeout in MS
|
|||
|
request.timeout = config.timeout;
|
|||
|
|
|||
|
function onloadend() {
|
|||
|
if (!request) {
|
|||
|
return;
|
|||
|
}
|
|||
|
// Prepare the response
|
|||
|
var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
|
|||
|
var responseData = !responseType || responseType === 'text' || responseType === 'json' ?
|
|||
|
request.responseText : request.response;
|
|||
|
var response = {
|
|||
|
data: responseData,
|
|||
|
status: request.status,
|
|||
|
statusText: request.statusText,
|
|||
|
headers: responseHeaders,
|
|||
|
config: config,
|
|||
|
request: request
|
|||
|
};
|
|||
|
|
|||
|
settle(function _resolve(value) {
|
|||
|
resolve(value);
|
|||
|
done();
|
|||
|
}, function _reject(err) {
|
|||
|
reject(err);
|
|||
|
done();
|
|||
|
}, response);
|
|||
|
|
|||
|
// Clean up request
|
|||
|
request = null;
|
|||
|
}
|
|||
|
|
|||
|
if ('onloadend' in request) {
|
|||
|
// Use onloadend if available
|
|||
|
request.onloadend = onloadend;
|
|||
|
} else {
|
|||
|
// Listen for ready state to emulate onloadend
|
|||
|
request.onreadystatechange = function handleLoad() {
|
|||
|
if (!request || request.readyState !== 4) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
// The request errored out and we didn't get a response, this will be
|
|||
|
// handled by onerror instead
|
|||
|
// With one exception: request that using file: protocol, most browsers
|
|||
|
// will return status as 0 even though it's a successful request
|
|||
|
if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
|
|||
|
return;
|
|||
|
}
|
|||
|
// readystate handler is calling before onerror or ontimeout handlers,
|
|||
|
// so we should call onloadend on the next 'tick'
|
|||
|
setTimeout(onloadend);
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
// Handle browser request cancellation (as opposed to a manual cancellation)
|
|||
|
request.onabort = function handleAbort() {
|
|||
|
if (!request) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
reject(createError('Request aborted', config, 'ECONNABORTED', request));
|
|||
|
|
|||
|
// Clean up request
|
|||
|
request = null;
|
|||
|
};
|
|||
|
|
|||
|
// Handle low level network errors
|
|||
|
request.onerror = function handleError() {
|
|||
|
// Real errors are hidden from us by the browser
|
|||
|
// onerror should only fire if it's a network error
|
|||
|
reject(createError('Network Error', config, null, request));
|
|||
|
|
|||
|
// Clean up request
|
|||
|
request = null;
|
|||
|
};
|
|||
|
|
|||
|
// Handle timeout
|
|||
|
request.ontimeout = function handleTimeout() {
|
|||
|
var timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
|
|||
|
var transitional = config.transitional || defaults.transitional;
|
|||
|
if (config.timeoutErrorMessage) {
|
|||
|
timeoutErrorMessage = config.timeoutErrorMessage;
|
|||
|
}
|
|||
|
reject(createError(
|
|||
|
timeoutErrorMessage,
|
|||
|
config,
|
|||
|
transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',
|
|||
|
request));
|
|||
|
|
|||
|
// Clean up request
|
|||
|
request = null;
|
|||
|
};
|
|||
|
|
|||
|
// Add xsrf header
|
|||
|
// This is only done if running in a standard browser environment.
|
|||
|
// Specifically not if we're in a web worker, or react-native.
|
|||
|
if (utils.isStandardBrowserEnv()) {
|
|||
|
// Add xsrf header
|
|||
|
var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
|
|||
|
cookies.read(config.xsrfCookieName) :
|
|||
|
undefined;
|
|||
|
|
|||
|
if (xsrfValue) {
|
|||
|
requestHeaders[config.xsrfHeaderName] = xsrfValue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Add headers to the request
|
|||
|
if ('setRequestHeader' in request) {
|
|||
|
utils.forEach(requestHeaders, function setRequestHeader(val, key) {
|
|||
|
if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
|
|||
|
// Remove Content-Type if data is undefined
|
|||
|
delete requestHeaders[key];
|
|||
|
} else {
|
|||
|
// Otherwise add header to the request
|
|||
|
request.setRequestHeader(key, val);
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// Add withCredentials to request if needed
|
|||
|
if (!utils.isUndefined(config.withCredentials)) {
|
|||
|
request.withCredentials = !!config.withCredentials;
|
|||
|
}
|
|||
|
|
|||
|
// Add responseType to request if needed
|
|||
|
if (responseType && responseType !== 'json') {
|
|||
|
request.responseType = config.responseType;
|
|||
|
}
|
|||
|
|
|||
|
// Handle progress if needed
|
|||
|
if (typeof config.onDownloadProgress === 'function') {
|
|||
|
request.addEventListener('progress', config.onDownloadProgress);
|
|||
|
}
|
|||
|
|
|||
|
// Not all browsers support upload events
|
|||
|
if (typeof config.onUploadProgress === 'function' && request.upload) {
|
|||
|
request.upload.addEventListener('progress', config.onUploadProgress);
|
|||
|
}
|
|||
|
|
|||
|
if (config.cancelToken || config.signal) {
|
|||
|
// Handle cancellation
|
|||
|
// eslint-disable-next-line func-names
|
|||
|
onCanceled = function(cancel) {
|
|||
|
if (!request) {
|
|||
|
return;
|
|||
|
}
|
|||
|
reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);
|
|||
|
request.abort();
|
|||
|
request = null;
|
|||
|
};
|
|||
|
|
|||
|
config.cancelToken && config.cancelToken.subscribe(onCanceled);
|
|||
|
if (config.signal) {
|
|||
|
config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!requestData) {
|
|||
|
requestData = null;
|
|||
|
}
|
|||
|
|
|||
|
// Send the request
|
|||
|
request.send(requestData);
|
|||
|
});
|
|||
|
};
|
|||
|
return xhr;
|
|||
|
}
|
|||
|
|
|||
|
var defaults_1;
|
|||
|
var hasRequiredDefaults;
|
|||
|
|
|||
|
function requireDefaults () {
|
|||
|
if (hasRequiredDefaults) return defaults_1;
|
|||
|
hasRequiredDefaults = 1;
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
var normalizeHeaderName$1 = normalizeHeaderName;
|
|||
|
var enhanceError$1 = enhanceError;
|
|||
|
|
|||
|
var DEFAULT_CONTENT_TYPE = {
|
|||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|||
|
};
|
|||
|
|
|||
|
function setContentTypeIfUnset(headers, value) {
|
|||
|
if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
|
|||
|
headers['Content-Type'] = value;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getDefaultAdapter() {
|
|||
|
var adapter;
|
|||
|
if (typeof XMLHttpRequest !== 'undefined') {
|
|||
|
// For browsers use XHR adapter
|
|||
|
adapter = requireXhr();
|
|||
|
} else if (typeof browser$1 !== 'undefined' && Object.prototype.toString.call(browser$1) === '[object process]') {
|
|||
|
// For node use HTTP adapter
|
|||
|
adapter = requireXhr();
|
|||
|
}
|
|||
|
return adapter;
|
|||
|
}
|
|||
|
|
|||
|
function stringifySafely(rawValue, parser, encoder) {
|
|||
|
if (utils.isString(rawValue)) {
|
|||
|
try {
|
|||
|
(parser || JSON.parse)(rawValue);
|
|||
|
return utils.trim(rawValue);
|
|||
|
} catch (e) {
|
|||
|
if (e.name !== 'SyntaxError') {
|
|||
|
throw e;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return (encoder || JSON.stringify)(rawValue);
|
|||
|
}
|
|||
|
|
|||
|
var defaults = {
|
|||
|
|
|||
|
transitional: {
|
|||
|
silentJSONParsing: true,
|
|||
|
forcedJSONParsing: true,
|
|||
|
clarifyTimeoutError: false
|
|||
|
},
|
|||
|
|
|||
|
adapter: getDefaultAdapter(),
|
|||
|
|
|||
|
transformRequest: [function transformRequest(data, headers) {
|
|||
|
normalizeHeaderName$1(headers, 'Accept');
|
|||
|
normalizeHeaderName$1(headers, 'Content-Type');
|
|||
|
|
|||
|
if (utils.isFormData(data) ||
|
|||
|
utils.isArrayBuffer(data) ||
|
|||
|
utils.isBuffer(data) ||
|
|||
|
utils.isStream(data) ||
|
|||
|
utils.isFile(data) ||
|
|||
|
utils.isBlob(data)
|
|||
|
) {
|
|||
|
return data;
|
|||
|
}
|
|||
|
if (utils.isArrayBufferView(data)) {
|
|||
|
return data.buffer;
|
|||
|
}
|
|||
|
if (utils.isURLSearchParams(data)) {
|
|||
|
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8');
|
|||
|
return data.toString();
|
|||
|
}
|
|||
|
if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) {
|
|||
|
setContentTypeIfUnset(headers, 'application/json');
|
|||
|
return stringifySafely(data);
|
|||
|
}
|
|||
|
return data;
|
|||
|
}],
|
|||
|
|
|||
|
transformResponse: [function transformResponse(data) {
|
|||
|
var transitional = this.transitional || defaults.transitional;
|
|||
|
var silentJSONParsing = transitional && transitional.silentJSONParsing;
|
|||
|
var forcedJSONParsing = transitional && transitional.forcedJSONParsing;
|
|||
|
var strictJSONParsing = !silentJSONParsing && this.responseType === 'json';
|
|||
|
|
|||
|
if (strictJSONParsing || (forcedJSONParsing && utils.isString(data) && data.length)) {
|
|||
|
try {
|
|||
|
return JSON.parse(data);
|
|||
|
} catch (e) {
|
|||
|
if (strictJSONParsing) {
|
|||
|
if (e.name === 'SyntaxError') {
|
|||
|
throw enhanceError$1(e, this, 'E_JSON_PARSE');
|
|||
|
}
|
|||
|
throw e;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return data;
|
|||
|
}],
|
|||
|
|
|||
|
/**
|
|||
|
* A timeout in milliseconds to abort a request. If set to 0 (default) a
|
|||
|
* timeout is not created.
|
|||
|
*/
|
|||
|
timeout: 0,
|
|||
|
|
|||
|
xsrfCookieName: 'XSRF-TOKEN',
|
|||
|
xsrfHeaderName: 'X-XSRF-TOKEN',
|
|||
|
|
|||
|
maxContentLength: -1,
|
|||
|
maxBodyLength: -1,
|
|||
|
|
|||
|
validateStatus: function validateStatus(status) {
|
|||
|
return status >= 200 && status < 300;
|
|||
|
},
|
|||
|
|
|||
|
headers: {
|
|||
|
common: {
|
|||
|
'Accept': 'application/json, text/plain, */*'
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
utils.forEach(['delete', 'get', 'head'], function forEachMethodNoData(method) {
|
|||
|
defaults.headers[method] = {};
|
|||
|
});
|
|||
|
|
|||
|
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
|
|||
|
defaults.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
|
|||
|
});
|
|||
|
|
|||
|
defaults_1 = defaults;
|
|||
|
return defaults_1;
|
|||
|
}
|
|||
|
|
|||
|
var utils$4 = utils$8;
|
|||
|
var defaults$2 = requireDefaults();
|
|||
|
|
|||
|
/**
|
|||
|
* Transform the data for a request or a response
|
|||
|
*
|
|||
|
* @param {Object|String} data The data to be transformed
|
|||
|
* @param {Array} headers The headers for the request or response
|
|||
|
* @param {Array|Function} fns A single function or Array of functions
|
|||
|
* @returns {*} The resulting transformed data
|
|||
|
*/
|
|||
|
var transformData$1 = function transformData(data, headers, fns) {
|
|||
|
var context = this || defaults$2;
|
|||
|
/*eslint no-param-reassign:0*/
|
|||
|
utils$4.forEach(fns, function transform(fn) {
|
|||
|
data = fn.call(context, data, headers);
|
|||
|
});
|
|||
|
|
|||
|
return data;
|
|||
|
};
|
|||
|
|
|||
|
var isCancel$1;
|
|||
|
var hasRequiredIsCancel;
|
|||
|
|
|||
|
function requireIsCancel () {
|
|||
|
if (hasRequiredIsCancel) return isCancel$1;
|
|||
|
hasRequiredIsCancel = 1;
|
|||
|
|
|||
|
isCancel$1 = function isCancel(value) {
|
|||
|
return !!(value && value.__CANCEL__);
|
|||
|
};
|
|||
|
return isCancel$1;
|
|||
|
}
|
|||
|
|
|||
|
var utils$3 = utils$8;
|
|||
|
var transformData = transformData$1;
|
|||
|
var isCancel = requireIsCancel();
|
|||
|
var defaults$1 = requireDefaults();
|
|||
|
var Cancel = requireCancel();
|
|||
|
|
|||
|
/**
|
|||
|
* Throws a `Cancel` if cancellation has been requested.
|
|||
|
*/
|
|||
|
function throwIfCancellationRequested(config) {
|
|||
|
if (config.cancelToken) {
|
|||
|
config.cancelToken.throwIfRequested();
|
|||
|
}
|
|||
|
|
|||
|
if (config.signal && config.signal.aborted) {
|
|||
|
throw new Cancel('canceled');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Dispatch a request to the server using the configured adapter.
|
|||
|
*
|
|||
|
* @param {object} config The config that is to be used for the request
|
|||
|
* @returns {Promise} The Promise to be fulfilled
|
|||
|
*/
|
|||
|
var dispatchRequest$1 = function dispatchRequest(config) {
|
|||
|
throwIfCancellationRequested(config);
|
|||
|
|
|||
|
// Ensure headers exist
|
|||
|
config.headers = config.headers || {};
|
|||
|
|
|||
|
// Transform request data
|
|||
|
config.data = transformData.call(
|
|||
|
config,
|
|||
|
config.data,
|
|||
|
config.headers,
|
|||
|
config.transformRequest
|
|||
|
);
|
|||
|
|
|||
|
// Flatten headers
|
|||
|
config.headers = utils$3.merge(
|
|||
|
config.headers.common || {},
|
|||
|
config.headers[config.method] || {},
|
|||
|
config.headers
|
|||
|
);
|
|||
|
|
|||
|
utils$3.forEach(
|
|||
|
['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
|
|||
|
function cleanHeaderConfig(method) {
|
|||
|
delete config.headers[method];
|
|||
|
}
|
|||
|
);
|
|||
|
|
|||
|
var adapter = config.adapter || defaults$1.adapter;
|
|||
|
|
|||
|
return adapter(config).then(function onAdapterResolution(response) {
|
|||
|
throwIfCancellationRequested(config);
|
|||
|
|
|||
|
// Transform response data
|
|||
|
response.data = transformData.call(
|
|||
|
config,
|
|||
|
response.data,
|
|||
|
response.headers,
|
|||
|
config.transformResponse
|
|||
|
);
|
|||
|
|
|||
|
return response;
|
|||
|
}, function onAdapterRejection(reason) {
|
|||
|
if (!isCancel(reason)) {
|
|||
|
throwIfCancellationRequested(config);
|
|||
|
|
|||
|
// Transform response data
|
|||
|
if (reason && reason.response) {
|
|||
|
reason.response.data = transformData.call(
|
|||
|
config,
|
|||
|
reason.response.data,
|
|||
|
reason.response.headers,
|
|||
|
config.transformResponse
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return Promise.reject(reason);
|
|||
|
});
|
|||
|
};
|
|||
|
|
|||
|
var utils$2 = utils$8;
|
|||
|
|
|||
|
/**
|
|||
|
* Config-specific merge-function which creates a new config-object
|
|||
|
* by merging two configuration objects together.
|
|||
|
*
|
|||
|
* @param {Object} config1
|
|||
|
* @param {Object} config2
|
|||
|
* @returns {Object} New object resulting from merging config2 to config1
|
|||
|
*/
|
|||
|
var mergeConfig$2 = function mergeConfig(config1, config2) {
|
|||
|
// eslint-disable-next-line no-param-reassign
|
|||
|
config2 = config2 || {};
|
|||
|
var config = {};
|
|||
|
|
|||
|
function getMergedValue(target, source) {
|
|||
|
if (utils$2.isPlainObject(target) && utils$2.isPlainObject(source)) {
|
|||
|
return utils$2.merge(target, source);
|
|||
|
} else if (utils$2.isPlainObject(source)) {
|
|||
|
return utils$2.merge({}, source);
|
|||
|
} else if (utils$2.isArray(source)) {
|
|||
|
return source.slice();
|
|||
|
}
|
|||
|
return source;
|
|||
|
}
|
|||
|
|
|||
|
// eslint-disable-next-line consistent-return
|
|||
|
function mergeDeepProperties(prop) {
|
|||
|
if (!utils$2.isUndefined(config2[prop])) {
|
|||
|
return getMergedValue(config1[prop], config2[prop]);
|
|||
|
} else if (!utils$2.isUndefined(config1[prop])) {
|
|||
|
return getMergedValue(undefined, config1[prop]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// eslint-disable-next-line consistent-return
|
|||
|
function valueFromConfig2(prop) {
|
|||
|
if (!utils$2.isUndefined(config2[prop])) {
|
|||
|
return getMergedValue(undefined, config2[prop]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// eslint-disable-next-line consistent-return
|
|||
|
function defaultToConfig2(prop) {
|
|||
|
if (!utils$2.isUndefined(config2[prop])) {
|
|||
|
return getMergedValue(undefined, config2[prop]);
|
|||
|
} else if (!utils$2.isUndefined(config1[prop])) {
|
|||
|
return getMergedValue(undefined, config1[prop]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// eslint-disable-next-line consistent-return
|
|||
|
function mergeDirectKeys(prop) {
|
|||
|
if (prop in config2) {
|
|||
|
return getMergedValue(config1[prop], config2[prop]);
|
|||
|
} else if (prop in config1) {
|
|||
|
return getMergedValue(undefined, config1[prop]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var mergeMap = {
|
|||
|
'url': valueFromConfig2,
|
|||
|
'method': valueFromConfig2,
|
|||
|
'data': valueFromConfig2,
|
|||
|
'baseURL': defaultToConfig2,
|
|||
|
'transformRequest': defaultToConfig2,
|
|||
|
'transformResponse': defaultToConfig2,
|
|||
|
'paramsSerializer': defaultToConfig2,
|
|||
|
'timeout': defaultToConfig2,
|
|||
|
'timeoutMessage': defaultToConfig2,
|
|||
|
'withCredentials': defaultToConfig2,
|
|||
|
'adapter': defaultToConfig2,
|
|||
|
'responseType': defaultToConfig2,
|
|||
|
'xsrfCookieName': defaultToConfig2,
|
|||
|
'xsrfHeaderName': defaultToConfig2,
|
|||
|
'onUploadProgress': defaultToConfig2,
|
|||
|
'onDownloadProgress': defaultToConfig2,
|
|||
|
'decompress': defaultToConfig2,
|
|||
|
'maxContentLength': defaultToConfig2,
|
|||
|
'maxBodyLength': defaultToConfig2,
|
|||
|
'transport': defaultToConfig2,
|
|||
|
'httpAgent': defaultToConfig2,
|
|||
|
'httpsAgent': defaultToConfig2,
|
|||
|
'cancelToken': defaultToConfig2,
|
|||
|
'socketPath': defaultToConfig2,
|
|||
|
'responseEncoding': defaultToConfig2,
|
|||
|
'validateStatus': mergeDirectKeys
|
|||
|
};
|
|||
|
|
|||
|
utils$2.forEach(Object.keys(config1).concat(Object.keys(config2)), function computeConfigValue(prop) {
|
|||
|
var merge = mergeMap[prop] || mergeDeepProperties;
|
|||
|
var configValue = merge(prop);
|
|||
|
(utils$2.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue);
|
|||
|
});
|
|||
|
|
|||
|
return config;
|
|||
|
};
|
|||
|
|
|||
|
var data;
|
|||
|
var hasRequiredData;
|
|||
|
|
|||
|
function requireData () {
|
|||
|
if (hasRequiredData) return data;
|
|||
|
hasRequiredData = 1;
|
|||
|
data = {
|
|||
|
"version": "0.25.0"
|
|||
|
};
|
|||
|
return data;
|
|||
|
}
|
|||
|
|
|||
|
var VERSION = requireData().version;
|
|||
|
|
|||
|
var validators$1 = {};
|
|||
|
|
|||
|
// eslint-disable-next-line func-names
|
|||
|
['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach(function(type, i) {
|
|||
|
validators$1[type] = function validator(thing) {
|
|||
|
return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type;
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
var deprecatedWarnings = {};
|
|||
|
|
|||
|
/**
|
|||
|
* Transitional option validator
|
|||
|
* @param {function|boolean?} validator - set to false if the transitional option has been removed
|
|||
|
* @param {string?} version - deprecated version / removed since version
|
|||
|
* @param {string?} message - some message with additional info
|
|||
|
* @returns {function}
|
|||
|
*/
|
|||
|
validators$1.transitional = function transitional(validator, version, message) {
|
|||
|
function formatMessage(opt, desc) {
|
|||
|
return '[Axios v' + VERSION + '] Transitional option \'' + opt + '\'' + desc + (message ? '. ' + message : '');
|
|||
|
}
|
|||
|
|
|||
|
// eslint-disable-next-line func-names
|
|||
|
return function(value, opt, opts) {
|
|||
|
if (validator === false) {
|
|||
|
throw new Error(formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')));
|
|||
|
}
|
|||
|
|
|||
|
if (version && !deprecatedWarnings[opt]) {
|
|||
|
deprecatedWarnings[opt] = true;
|
|||
|
// eslint-disable-next-line no-console
|
|||
|
console.warn(
|
|||
|
formatMessage(
|
|||
|
opt,
|
|||
|
' has been deprecated since v' + version + ' and will be removed in the near future'
|
|||
|
)
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return validator ? validator(value, opt, opts) : true;
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Assert object's properties type
|
|||
|
* @param {object} options
|
|||
|
* @param {object} schema
|
|||
|
* @param {boolean?} allowUnknown
|
|||
|
*/
|
|||
|
|
|||
|
function assertOptions(options, schema, allowUnknown) {
|
|||
|
if (typeof options !== 'object') {
|
|||
|
throw new TypeError('options must be an object');
|
|||
|
}
|
|||
|
var keys = Object.keys(options);
|
|||
|
var i = keys.length;
|
|||
|
while (i-- > 0) {
|
|||
|
var opt = keys[i];
|
|||
|
var validator = schema[opt];
|
|||
|
if (validator) {
|
|||
|
var value = options[opt];
|
|||
|
var result = value === undefined || validator(value, opt, options);
|
|||
|
if (result !== true) {
|
|||
|
throw new TypeError('option ' + opt + ' must be ' + result);
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
if (allowUnknown !== true) {
|
|||
|
throw Error('Unknown option ' + opt);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var validator$1 = {
|
|||
|
assertOptions: assertOptions,
|
|||
|
validators: validators$1
|
|||
|
};
|
|||
|
|
|||
|
var utils$1 = utils$8;
|
|||
|
var buildURL = buildURL$1;
|
|||
|
var InterceptorManager = InterceptorManager_1;
|
|||
|
var dispatchRequest = dispatchRequest$1;
|
|||
|
var mergeConfig$1 = mergeConfig$2;
|
|||
|
var validator = validator$1;
|
|||
|
|
|||
|
var validators = validator.validators;
|
|||
|
/**
|
|||
|
* Create a new instance of Axios
|
|||
|
*
|
|||
|
* @param {Object} instanceConfig The default config for the instance
|
|||
|
*/
|
|||
|
function Axios$1(instanceConfig) {
|
|||
|
this.defaults = instanceConfig;
|
|||
|
this.interceptors = {
|
|||
|
request: new InterceptorManager(),
|
|||
|
response: new InterceptorManager()
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Dispatch a request
|
|||
|
*
|
|||
|
* @param {Object} config The config specific for this request (merged with this.defaults)
|
|||
|
*/
|
|||
|
Axios$1.prototype.request = function request(configOrUrl, config) {
|
|||
|
/*eslint no-param-reassign:0*/
|
|||
|
// Allow for axios('example/url'[, config]) a la fetch API
|
|||
|
if (typeof configOrUrl === 'string') {
|
|||
|
config = config || {};
|
|||
|
config.url = configOrUrl;
|
|||
|
} else {
|
|||
|
config = configOrUrl || {};
|
|||
|
}
|
|||
|
|
|||
|
if (!config.url) {
|
|||
|
throw new Error('Provided config url is not valid');
|
|||
|
}
|
|||
|
|
|||
|
config = mergeConfig$1(this.defaults, config);
|
|||
|
|
|||
|
// Set config.method
|
|||
|
if (config.method) {
|
|||
|
config.method = config.method.toLowerCase();
|
|||
|
} else if (this.defaults.method) {
|
|||
|
config.method = this.defaults.method.toLowerCase();
|
|||
|
} else {
|
|||
|
config.method = 'get';
|
|||
|
}
|
|||
|
|
|||
|
var transitional = config.transitional;
|
|||
|
|
|||
|
if (transitional !== undefined) {
|
|||
|
validator.assertOptions(transitional, {
|
|||
|
silentJSONParsing: validators.transitional(validators.boolean),
|
|||
|
forcedJSONParsing: validators.transitional(validators.boolean),
|
|||
|
clarifyTimeoutError: validators.transitional(validators.boolean)
|
|||
|
}, false);
|
|||
|
}
|
|||
|
|
|||
|
// filter out skipped interceptors
|
|||
|
var requestInterceptorChain = [];
|
|||
|
var synchronousRequestInterceptors = true;
|
|||
|
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
|
|||
|
if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
|
|||
|
|
|||
|
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
|
|||
|
});
|
|||
|
|
|||
|
var responseInterceptorChain = [];
|
|||
|
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
|
|||
|
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
|
|||
|
});
|
|||
|
|
|||
|
var promise;
|
|||
|
|
|||
|
if (!synchronousRequestInterceptors) {
|
|||
|
var chain = [dispatchRequest, undefined];
|
|||
|
|
|||
|
Array.prototype.unshift.apply(chain, requestInterceptorChain);
|
|||
|
chain = chain.concat(responseInterceptorChain);
|
|||
|
|
|||
|
promise = Promise.resolve(config);
|
|||
|
while (chain.length) {
|
|||
|
promise = promise.then(chain.shift(), chain.shift());
|
|||
|
}
|
|||
|
|
|||
|
return promise;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
var newConfig = config;
|
|||
|
while (requestInterceptorChain.length) {
|
|||
|
var onFulfilled = requestInterceptorChain.shift();
|
|||
|
var onRejected = requestInterceptorChain.shift();
|
|||
|
try {
|
|||
|
newConfig = onFulfilled(newConfig);
|
|||
|
} catch (error) {
|
|||
|
onRejected(error);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
try {
|
|||
|
promise = dispatchRequest(newConfig);
|
|||
|
} catch (error) {
|
|||
|
return Promise.reject(error);
|
|||
|
}
|
|||
|
|
|||
|
while (responseInterceptorChain.length) {
|
|||
|
promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
|
|||
|
}
|
|||
|
|
|||
|
return promise;
|
|||
|
};
|
|||
|
|
|||
|
Axios$1.prototype.getUri = function getUri(config) {
|
|||
|
if (!config.url) {
|
|||
|
throw new Error('Provided config url is not valid');
|
|||
|
}
|
|||
|
config = mergeConfig$1(this.defaults, config);
|
|||
|
return buildURL(config.url, config.params, config.paramsSerializer).replace(/^\?/, '');
|
|||
|
};
|
|||
|
|
|||
|
// Provide aliases for supported request methods
|
|||
|
utils$1.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
|
|||
|
/*eslint func-names:0*/
|
|||
|
Axios$1.prototype[method] = function(url, config) {
|
|||
|
return this.request(mergeConfig$1(config || {}, {
|
|||
|
method: method,
|
|||
|
url: url,
|
|||
|
data: (config || {}).data
|
|||
|
}));
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
utils$1.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
|
|||
|
/*eslint func-names:0*/
|
|||
|
Axios$1.prototype[method] = function(url, data, config) {
|
|||
|
return this.request(mergeConfig$1(config || {}, {
|
|||
|
method: method,
|
|||
|
url: url,
|
|||
|
data: data
|
|||
|
}));
|
|||
|
};
|
|||
|
});
|
|||
|
|
|||
|
var Axios_1 = Axios$1;
|
|||
|
|
|||
|
var CancelToken_1;
|
|||
|
var hasRequiredCancelToken;
|
|||
|
|
|||
|
function requireCancelToken () {
|
|||
|
if (hasRequiredCancelToken) return CancelToken_1;
|
|||
|
hasRequiredCancelToken = 1;
|
|||
|
|
|||
|
var Cancel = requireCancel();
|
|||
|
|
|||
|
/**
|
|||
|
* A `CancelToken` is an object that can be used to request cancellation of an operation.
|
|||
|
*
|
|||
|
* @class
|
|||
|
* @param {Function} executor The executor function.
|
|||
|
*/
|
|||
|
function CancelToken(executor) {
|
|||
|
if (typeof executor !== 'function') {
|
|||
|
throw new TypeError('executor must be a function.');
|
|||
|
}
|
|||
|
|
|||
|
var resolvePromise;
|
|||
|
|
|||
|
this.promise = new Promise(function promiseExecutor(resolve) {
|
|||
|
resolvePromise = resolve;
|
|||
|
});
|
|||
|
|
|||
|
var token = this;
|
|||
|
|
|||
|
// eslint-disable-next-line func-names
|
|||
|
this.promise.then(function(cancel) {
|
|||
|
if (!token._listeners) return;
|
|||
|
|
|||
|
var i;
|
|||
|
var l = token._listeners.length;
|
|||
|
|
|||
|
for (i = 0; i < l; i++) {
|
|||
|
token._listeners[i](cancel);
|
|||
|
}
|
|||
|
token._listeners = null;
|
|||
|
});
|
|||
|
|
|||
|
// eslint-disable-next-line func-names
|
|||
|
this.promise.then = function(onfulfilled) {
|
|||
|
var _resolve;
|
|||
|
// eslint-disable-next-line func-names
|
|||
|
var promise = new Promise(function(resolve) {
|
|||
|
token.subscribe(resolve);
|
|||
|
_resolve = resolve;
|
|||
|
}).then(onfulfilled);
|
|||
|
|
|||
|
promise.cancel = function reject() {
|
|||
|
token.unsubscribe(_resolve);
|
|||
|
};
|
|||
|
|
|||
|
return promise;
|
|||
|
};
|
|||
|
|
|||
|
executor(function cancel(message) {
|
|||
|
if (token.reason) {
|
|||
|
// Cancellation has already been requested
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
token.reason = new Cancel(message);
|
|||
|
resolvePromise(token.reason);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Throws a `Cancel` if cancellation has been requested.
|
|||
|
*/
|
|||
|
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
|
|||
|
if (this.reason) {
|
|||
|
throw this.reason;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Subscribe to the cancel signal
|
|||
|
*/
|
|||
|
|
|||
|
CancelToken.prototype.subscribe = function subscribe(listener) {
|
|||
|
if (this.reason) {
|
|||
|
listener(this.reason);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (this._listeners) {
|
|||
|
this._listeners.push(listener);
|
|||
|
} else {
|
|||
|
this._listeners = [listener];
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Unsubscribe from the cancel signal
|
|||
|
*/
|
|||
|
|
|||
|
CancelToken.prototype.unsubscribe = function unsubscribe(listener) {
|
|||
|
if (!this._listeners) {
|
|||
|
return;
|
|||
|
}
|
|||
|
var index = this._listeners.indexOf(listener);
|
|||
|
if (index !== -1) {
|
|||
|
this._listeners.splice(index, 1);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
/**
|
|||
|
* Returns an object that contains a new `CancelToken` and a function that, when called,
|
|||
|
* cancels the `CancelToken`.
|
|||
|
*/
|
|||
|
CancelToken.source = function source() {
|
|||
|
var cancel;
|
|||
|
var token = new CancelToken(function executor(c) {
|
|||
|
cancel = c;
|
|||
|
});
|
|||
|
return {
|
|||
|
token: token,
|
|||
|
cancel: cancel
|
|||
|
};
|
|||
|
};
|
|||
|
|
|||
|
CancelToken_1 = CancelToken;
|
|||
|
return CancelToken_1;
|
|||
|
}
|
|||
|
|
|||
|
var spread;
|
|||
|
var hasRequiredSpread;
|
|||
|
|
|||
|
function requireSpread () {
|
|||
|
if (hasRequiredSpread) return spread;
|
|||
|
hasRequiredSpread = 1;
|
|||
|
|
|||
|
/**
|
|||
|
* Syntactic sugar for invoking a function and expanding an array for arguments.
|
|||
|
*
|
|||
|
* Common use case would be to use `Function.prototype.apply`.
|
|||
|
*
|
|||
|
* ```js
|
|||
|
* function f(x, y, z) {}
|
|||
|
* var args = [1, 2, 3];
|
|||
|
* f.apply(null, args);
|
|||
|
* ```
|
|||
|
*
|
|||
|
* With `spread` this example can be re-written.
|
|||
|
*
|
|||
|
* ```js
|
|||
|
* spread(function(x, y, z) {})([1, 2, 3]);
|
|||
|
* ```
|
|||
|
*
|
|||
|
* @param {Function} callback
|
|||
|
* @returns {Function}
|
|||
|
*/
|
|||
|
spread = function spread(callback) {
|
|||
|
return function wrap(arr) {
|
|||
|
return callback.apply(null, arr);
|
|||
|
};
|
|||
|
};
|
|||
|
return spread;
|
|||
|
}
|
|||
|
|
|||
|
var isAxiosError;
|
|||
|
var hasRequiredIsAxiosError;
|
|||
|
|
|||
|
function requireIsAxiosError () {
|
|||
|
if (hasRequiredIsAxiosError) return isAxiosError;
|
|||
|
hasRequiredIsAxiosError = 1;
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
|
|||
|
/**
|
|||
|
* Determines whether the payload is an error thrown by Axios
|
|||
|
*
|
|||
|
* @param {*} payload The value to test
|
|||
|
* @returns {boolean} True if the payload is an error thrown by Axios, otherwise false
|
|||
|
*/
|
|||
|
isAxiosError = function isAxiosError(payload) {
|
|||
|
return utils.isObject(payload) && (payload.isAxiosError === true);
|
|||
|
};
|
|||
|
return isAxiosError;
|
|||
|
}
|
|||
|
|
|||
|
var utils = utils$8;
|
|||
|
var bind = bind$2;
|
|||
|
var Axios = Axios_1;
|
|||
|
var mergeConfig = mergeConfig$2;
|
|||
|
var defaults = requireDefaults();
|
|||
|
|
|||
|
/**
|
|||
|
* Create an instance of Axios
|
|||
|
*
|
|||
|
* @param {Object} defaultConfig The default config for the instance
|
|||
|
* @return {Axios} A new instance of Axios
|
|||
|
*/
|
|||
|
function createInstance(defaultConfig) {
|
|||
|
var context = new Axios(defaultConfig);
|
|||
|
var instance = bind(Axios.prototype.request, context);
|
|||
|
|
|||
|
// Copy axios.prototype to instance
|
|||
|
utils.extend(instance, Axios.prototype, context);
|
|||
|
|
|||
|
// Copy context to instance
|
|||
|
utils.extend(instance, context);
|
|||
|
|
|||
|
// Factory for creating new instances
|
|||
|
instance.create = function create(instanceConfig) {
|
|||
|
return createInstance(mergeConfig(defaultConfig, instanceConfig));
|
|||
|
};
|
|||
|
|
|||
|
return instance;
|
|||
|
}
|
|||
|
|
|||
|
// Create the default instance to be exported
|
|||
|
var axios$2 = createInstance(defaults);
|
|||
|
|
|||
|
// Expose Axios class to allow class inheritance
|
|||
|
axios$2.Axios = Axios;
|
|||
|
|
|||
|
// Expose Cancel & CancelToken
|
|||
|
axios$2.Cancel = requireCancel();
|
|||
|
axios$2.CancelToken = requireCancelToken();
|
|||
|
axios$2.isCancel = requireIsCancel();
|
|||
|
axios$2.VERSION = requireData().version;
|
|||
|
|
|||
|
// Expose all/spread
|
|||
|
axios$2.all = function all(promises) {
|
|||
|
return Promise.all(promises);
|
|||
|
};
|
|||
|
axios$2.spread = requireSpread();
|
|||
|
|
|||
|
// Expose isAxiosError
|
|||
|
axios$2.isAxiosError = requireIsAxiosError();
|
|||
|
|
|||
|
axios$3.exports = axios$2;
|
|||
|
|
|||
|
// Allow use of default import syntax in TypeScript
|
|||
|
axios$3.exports.default = axios$2;
|
|||
|
|
|||
|
var axiosExports = axios$3.exports;
|
|||
|
|
|||
|
var axios = axiosExports;
|
|||
|
|
|||
|
var axios$1 = /*@__PURE__*/getDefaultExportFromCjs(axios);
|
|||
|
|
|||
|
var _nodeResolve_empty = {};
|
|||
|
|
|||
|
var _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
default: _nodeResolve_empty
|
|||
|
});
|
|||
|
|
|||
|
var require$$2 = /*@__PURE__*/getAugmentedNamespace(_nodeResolve_empty$1);
|
|||
|
|
|||
|
// hkp-client - A HKP client implementation in javascript
|
|||
|
// Copyright (C) 2015 Tankred Hase
|
|||
|
//
|
|||
|
// This library is free software; you can redistribute it and/or
|
|||
|
// modify it under the terms of the GNU Lesser General Public
|
|||
|
// License as published by the Free Software Foundation; either
|
|||
|
// version 3.0 of the License, or (at your option) any later version.
|
|||
|
//
|
|||
|
// This library is distributed in the hope that it will be useful,
|
|||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
// Lesser General Public License for more details.
|
|||
|
//
|
|||
|
// You should have received a copy of the GNU Lesser General Public
|
|||
|
// License along with this library; if not, write to the Free Software
|
|||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
|
|||
|
/**
|
|||
|
* This class implements a client for the OpenPGP HTTP Keyserver Protocol (HKP)
|
|||
|
* in order to lookup and upload keys on standard public key servers.
|
|||
|
*/
|
|||
|
class HKP {
|
|||
|
/**
|
|||
|
* Initialize the HKP client and configure it with the key server url and fetch function.
|
|||
|
* @param {String} [keyServerBaseUrl] - The HKP key server base url including
|
|||
|
* the protocol to use, e.g. 'https://pgp.mit.edu'; defaults to
|
|||
|
* openpgp.config.keyserver (https://keyserver.ubuntu.com)
|
|||
|
* @param {Object} [config] - Full configuration, defaults to openpgp.config
|
|||
|
*/
|
|||
|
constructor(keyServerBaseUrl = 'https://keyserver.ubuntu.com') {
|
|||
|
this._baseUrl = keyServerBaseUrl;
|
|||
|
this._fetch = typeof globalThis.fetch === 'function' ? globalThis.fetch : require$$2;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Search for a public key on the key server either by key ID or part of the user ID.
|
|||
|
* @param {String} options.keyId The long public key ID.
|
|||
|
* @param {String} options.query This can be any part of the key user ID such as name
|
|||
|
* or email address.
|
|||
|
* @returns {String} The ascii armored public key.
|
|||
|
* @async
|
|||
|
*/
|
|||
|
lookup(options) {
|
|||
|
let uri = this._baseUrl + '/pks/lookup?op=get&options=mr&search=';
|
|||
|
const fetch = this._fetch;
|
|||
|
|
|||
|
if (options.keyId) {
|
|||
|
uri += '0x' + encodeURIComponent(options.keyId);
|
|||
|
} else if (options.query) {
|
|||
|
uri += encodeURIComponent(options.query);
|
|||
|
} else {
|
|||
|
throw new Error('You must provide a query parameter!');
|
|||
|
}
|
|||
|
|
|||
|
return fetch(uri).then(function(response) {
|
|||
|
if (response.status === 200) {
|
|||
|
return response.text();
|
|||
|
}
|
|||
|
}).then(function(publicKeyArmored) {
|
|||
|
if (!publicKeyArmored || publicKeyArmored.indexOf('-----END PGP PUBLIC KEY BLOCK-----') < 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
return publicKeyArmored.trim();
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Upload a public key to the server.
|
|||
|
* @param {String} publicKeyArmored - An ascii armored public key to be uploaded.
|
|||
|
* @returns {Promise}
|
|||
|
* @async
|
|||
|
*/
|
|||
|
upload(publicKeyArmored) {
|
|||
|
const uri = this._baseUrl + '/pks/add';
|
|||
|
const fetch = this._fetch;
|
|||
|
|
|||
|
return fetch(uri, {
|
|||
|
method: 'post',
|
|||
|
headers: {
|
|||
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
|
|||
|
},
|
|||
|
body: 'keytext=' + encodeURIComponent(publicKeyArmored)
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var hkp = HKP;
|
|||
|
|
|||
|
var HKP$1 = /*@__PURE__*/getDefaultExportFromCjs(hkp);
|
|||
|
|
|||
|
var _polyfillNode_crypto = {};
|
|||
|
|
|||
|
var _polyfillNode_crypto$1 = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
default: _polyfillNode_crypto
|
|||
|
});
|
|||
|
|
|||
|
var require$$1 = /*@__PURE__*/getAugmentedNamespace(_polyfillNode_crypto$1);
|
|||
|
|
|||
|
// wkd-client - A WKD client implementation in javascript
|
|||
|
// Copyright (C) 2018 Wiktor Kwapisiewicz
|
|||
|
//
|
|||
|
// This library is free software; you can redistribute it and/or
|
|||
|
// modify it under the terms of the GNU Lesser General Public
|
|||
|
// License as published by the Free Software Foundation; either
|
|||
|
// version 3.0 of the License, or (at your option) any later version.
|
|||
|
//
|
|||
|
// This library is distributed in the hope that it will be useful,
|
|||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|||
|
// Lesser General Public License for more details.
|
|||
|
//
|
|||
|
// You should have received a copy of the GNU Lesser General Public
|
|||
|
// License along with this library; if not, write to the Free Software
|
|||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
|
|||
|
/**
|
|||
|
* This class implements a client for the Web Key Directory (WKD) protocol
|
|||
|
* in order to lookup keys on designated servers.
|
|||
|
* @see https://datatracker.ietf.org/doc/draft-koch-openpgp-webkey-service/
|
|||
|
*/
|
|||
|
class WKD {
|
|||
|
/**
|
|||
|
* Initialize the WKD client
|
|||
|
*/
|
|||
|
constructor() {
|
|||
|
this._fetch = typeof globalThis.fetch === 'function' ? globalThis.fetch : require$$2;
|
|||
|
const { subtle } = globalThis.crypto || require$$1.webcrypto || new (require$$2.Crypto)();
|
|||
|
this._subtle = subtle;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Search for a public key using Web Key Directory protocol.
|
|||
|
* @param {String} options.email User's email.
|
|||
|
* @returns {Uint8Array} The public key.
|
|||
|
* @async
|
|||
|
*/
|
|||
|
async lookup(options) {
|
|||
|
const fetch = this._fetch;
|
|||
|
|
|||
|
if (!options.email) {
|
|||
|
throw new Error('You must provide an email parameter!');
|
|||
|
}
|
|||
|
|
|||
|
if (typeof options.email !== 'string' || !options.email.includes('@')) {
|
|||
|
throw new Error('Invalid e-mail address.');
|
|||
|
}
|
|||
|
|
|||
|
const [localPart, domain] = options.email.split('@');
|
|||
|
const localPartEncoded = new TextEncoder().encode(localPart.toLowerCase());
|
|||
|
const localPartHashed = new Uint8Array(await this._subtle.digest('SHA-1', localPartEncoded));
|
|||
|
const localPartBase32 = encodeZBase32(localPartHashed);
|
|||
|
const localPartEscaped = encodeURIComponent(localPart);
|
|||
|
|
|||
|
const urlAdvanced = `https://openpgpkey.${domain}/.well-known/openpgpkey/${domain}/hu/${localPartBase32}?l=${localPartEscaped}`;
|
|||
|
const urlDirect = `https://${domain}/.well-known/openpgpkey/hu/${localPartBase32}?l=${localPartEscaped}`;
|
|||
|
|
|||
|
let response;
|
|||
|
try {
|
|||
|
response = await fetch(urlAdvanced);
|
|||
|
if (response.status !== 200) {
|
|||
|
throw new Error('Advanced WKD lookup failed: ' + response.statusText);
|
|||
|
}
|
|||
|
} catch (err) {
|
|||
|
response = await fetch(urlDirect);
|
|||
|
if (response.status !== 200) {
|
|||
|
throw new Error('Direct WKD lookup failed: ' + response.statusText);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return new Uint8Array(await response.arrayBuffer());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Encode input buffer using Z-Base32 encoding.
|
|||
|
* See: https://tools.ietf.org/html/rfc6189#section-5.1.6
|
|||
|
*
|
|||
|
* @param {Uint8Array} data - The binary data to encode
|
|||
|
* @returns {String} Binary data encoded using Z-Base32.
|
|||
|
*/
|
|||
|
function encodeZBase32(data) {
|
|||
|
if (data.length === 0) {
|
|||
|
return "";
|
|||
|
}
|
|||
|
const ALPHABET = "ybndrfg8ejkmcpqxot1uwisza345h769";
|
|||
|
const SHIFT = 5;
|
|||
|
const MASK = 31;
|
|||
|
let buffer = data[0];
|
|||
|
let index = 1;
|
|||
|
let bitsLeft = 8;
|
|||
|
let result = '';
|
|||
|
while (bitsLeft > 0 || index < data.length) {
|
|||
|
if (bitsLeft < SHIFT) {
|
|||
|
if (index < data.length) {
|
|||
|
buffer <<= 8;
|
|||
|
buffer |= data[index++] & 0xff;
|
|||
|
bitsLeft += 8;
|
|||
|
} else {
|
|||
|
const pad = SHIFT - bitsLeft;
|
|||
|
buffer <<= pad;
|
|||
|
bitsLeft += pad;
|
|||
|
}
|
|||
|
}
|
|||
|
bitsLeft -= SHIFT;
|
|||
|
result += ALPHABET[MASK & (buffer >> bitsLeft)];
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
var wkd = WKD;
|
|||
|
|
|||
|
var WKD$1 = /*@__PURE__*/getDefaultExportFromCjs(wkd);
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Functions related to the fetching and handling of keys
|
|||
|
* @module keys
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key using keyservers
|
|||
|
* @function
|
|||
|
* @param {string} identifier - Fingerprint or email address
|
|||
|
* @param {string} [keyserverDomain=keys.openpgp.org] - Domain of the keyserver
|
|||
|
* @returns {Promise<PublicKey>}
|
|||
|
* @example
|
|||
|
* const key1 = doip.keys.fetchHKP('alice@domain.tld');
|
|||
|
* const key2 = doip.keys.fetchHKP('123abc123abc');
|
|||
|
*/
|
|||
|
async function fetchHKP (identifier, keyserverDomain) {
|
|||
|
const keyserverBaseUrl = keyserverDomain
|
|||
|
? `https://${keyserverDomain}`
|
|||
|
: 'https://keys.openpgp.org';
|
|||
|
|
|||
|
// @ts-ignore
|
|||
|
const hkp = new HKP$1(keyserverBaseUrl);
|
|||
|
const lookupOpts = {
|
|||
|
query: identifier
|
|||
|
};
|
|||
|
|
|||
|
const publicKey = await hkp
|
|||
|
.lookup(lookupOpts)
|
|||
|
.catch((error) => {
|
|||
|
throw new Error(`Key does not exist or could not be fetched (${error})`)
|
|||
|
});
|
|||
|
|
|||
|
if (!publicKey) {
|
|||
|
throw new Error('Key does not exist or could not be fetched')
|
|||
|
}
|
|||
|
|
|||
|
return await openpgp.readKey({
|
|||
|
armoredKey: publicKey
|
|||
|
})
|
|||
|
.catch((error) => {
|
|||
|
throw new Error(`Key could not be read (${error})`)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key using Web Key Directory
|
|||
|
* @function
|
|||
|
* @param {string} identifier - Identifier of format 'username@domain.tld`
|
|||
|
* @returns {Promise<PublicKey>}
|
|||
|
* @example
|
|||
|
* const key = doip.keys.fetchWKD('alice@domain.tld');
|
|||
|
*/
|
|||
|
async function fetchWKD (identifier) {
|
|||
|
// @ts-ignore
|
|||
|
const wkd = new WKD$1();
|
|||
|
const lookupOpts = {
|
|||
|
email: identifier
|
|||
|
};
|
|||
|
|
|||
|
const publicKey = await wkd
|
|||
|
.lookup(lookupOpts)
|
|||
|
.catch((/** @type {Error} */ error) => {
|
|||
|
throw new Error(`Key does not exist or could not be fetched (${error})`)
|
|||
|
});
|
|||
|
|
|||
|
if (!publicKey) {
|
|||
|
throw new Error('Key does not exist or could not be fetched')
|
|||
|
}
|
|||
|
|
|||
|
return await openpgp.readKey({
|
|||
|
binaryKey: publicKey
|
|||
|
})
|
|||
|
.catch((error) => {
|
|||
|
throw new Error(`Key could not be read (${error})`)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key from Keybase
|
|||
|
* @function
|
|||
|
* @param {string} username - Keybase username
|
|||
|
* @param {string} fingerprint - Fingerprint of key
|
|||
|
* @returns {Promise<PublicKey>}
|
|||
|
* @example
|
|||
|
* const key = doip.keys.fetchKeybase('alice', '123abc123abc');
|
|||
|
*/
|
|||
|
async function fetchKeybase (username, fingerprint) {
|
|||
|
const keyLink = `https://keybase.io/${username}/pgp_keys.asc?fingerprint=${fingerprint}`;
|
|||
|
let rawKeyContent;
|
|||
|
try {
|
|||
|
rawKeyContent = await axios$1.get(
|
|||
|
keyLink,
|
|||
|
{
|
|||
|
responseType: 'text'
|
|||
|
}
|
|||
|
)
|
|||
|
.then((/** @type {import('axios').AxiosResponse} */ response) => {
|
|||
|
if (response.status === 200) {
|
|||
|
return response
|
|||
|
}
|
|||
|
})
|
|||
|
.then((/** @type {import('axios').AxiosResponse} */ response) => response.data);
|
|||
|
} catch (e) {
|
|||
|
throw new Error(`Error fetching Keybase key: ${e.message}`)
|
|||
|
}
|
|||
|
|
|||
|
return await openpgp.readKey({
|
|||
|
armoredKey: rawKeyContent
|
|||
|
})
|
|||
|
.catch((error) => {
|
|||
|
throw new Error(`Key does not exist or could not be fetched (${error})`)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Get a public key from plaintext data
|
|||
|
* @function
|
|||
|
* @param {string} rawKeyContent - Plaintext ASCII-formatted public key data
|
|||
|
* @returns {Promise<PublicKey>}
|
|||
|
* @example
|
|||
|
* const plainkey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|||
|
*
|
|||
|
* mQINBF0mIsIBEADacleiyiV+z6FIunvLWrO6ZETxGNVpqM+WbBQKdW1BVrJBBolg
|
|||
|
* [...]
|
|||
|
* =6lib
|
|||
|
* -----END PGP PUBLIC KEY BLOCK-----`
|
|||
|
* const key = doip.keys.fetchPlaintext(plainkey);
|
|||
|
*/
|
|||
|
async function fetchPlaintext (rawKeyContent) {
|
|||
|
const publicKey = await openpgp.readKey({
|
|||
|
armoredKey: rawKeyContent
|
|||
|
})
|
|||
|
.catch((error) => {
|
|||
|
throw new Error(`Key could not be read (${error})`)
|
|||
|
});
|
|||
|
|
|||
|
return publicKey
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key using an URI
|
|||
|
* @function
|
|||
|
* @param {string} uri - URI that defines the location of the key
|
|||
|
* @returns {Promise<PublicKey>}
|
|||
|
* @example
|
|||
|
* const key1 = doip.keys.fetchURI('hkp:alice@domain.tld');
|
|||
|
* const key2 = doip.keys.fetchURI('hkp:123abc123abc');
|
|||
|
* const key3 = doip.keys.fetchURI('wkd:alice@domain.tld');
|
|||
|
*/
|
|||
|
async function fetchURI (uri) {
|
|||
|
if (!validUrlExports.isUri(uri)) {
|
|||
|
throw new Error('Invalid URI')
|
|||
|
}
|
|||
|
|
|||
|
const re = /([a-zA-Z0-9]*):([a-zA-Z0-9@._=+-]*)(?::([a-zA-Z0-9@._=+-]*))?/;
|
|||
|
const match = uri.match(re);
|
|||
|
|
|||
|
if (!match[1]) {
|
|||
|
throw new Error('Invalid URI')
|
|||
|
}
|
|||
|
|
|||
|
switch (match[1]) {
|
|||
|
case 'hkp':
|
|||
|
return await fetchHKP(
|
|||
|
match[3] ? match[3] : match[2],
|
|||
|
match[3] ? match[2] : null
|
|||
|
)
|
|||
|
|
|||
|
case 'wkd':
|
|||
|
return await fetchWKD(match[2])
|
|||
|
|
|||
|
case 'kb':
|
|||
|
return await fetchKeybase(match[2], match.length >= 4 ? match[3] : null)
|
|||
|
|
|||
|
default:
|
|||
|
throw new Error('Invalid URI protocol')
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key
|
|||
|
*
|
|||
|
* This function will attempt to detect the identifier and fetch the key
|
|||
|
* accordingly. If the identifier is an email address, it will first try and
|
|||
|
* fetch the key using WKD and then HKP. Otherwise, it will try HKP only.
|
|||
|
*
|
|||
|
* This function will also try and parse the input as a plaintext key
|
|||
|
* @function
|
|||
|
* @param {string} identifier - URI that defines the location of the key
|
|||
|
* @returns {Promise<PublicKey>}
|
|||
|
* @example
|
|||
|
* const key1 = doip.keys.fetch('alice@domain.tld');
|
|||
|
* const key2 = doip.keys.fetch('123abc123abc');
|
|||
|
*/
|
|||
|
async function fetch$1 (identifier) {
|
|||
|
const re = /([a-zA-Z0-9@._=+-]*)(?::([a-zA-Z0-9@._=+-]*))?/;
|
|||
|
const match = identifier.match(re);
|
|||
|
|
|||
|
let pubKey = null;
|
|||
|
|
|||
|
// Attempt plaintext
|
|||
|
if (!pubKey) {
|
|||
|
try {
|
|||
|
pubKey = await fetchPlaintext(identifier);
|
|||
|
} catch (e) {}
|
|||
|
}
|
|||
|
|
|||
|
// Attempt WKD
|
|||
|
if (!pubKey && identifier.includes('@')) {
|
|||
|
try {
|
|||
|
pubKey = await fetchWKD(match[1]);
|
|||
|
} catch (e) {}
|
|||
|
}
|
|||
|
|
|||
|
// Attempt HKP
|
|||
|
if (!pubKey) {
|
|||
|
pubKey = await fetchHKP(
|
|||
|
match[2] ? match[2] : match[1],
|
|||
|
match[2] ? match[1] : null
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
if (!pubKey) {
|
|||
|
throw new Error('Key does not exist or could not be fetched')
|
|||
|
}
|
|||
|
|
|||
|
return pubKey
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Process a public key to get user data and claims
|
|||
|
* @function
|
|||
|
* @param {PublicKey} publicKey - The public key to process
|
|||
|
* @returns {Promise<object>}
|
|||
|
* @example
|
|||
|
* const key = doip.keys.fetchURI('hkp:alice@domain.tld');
|
|||
|
* const data = doip.keys.process(key);
|
|||
|
* data.users[0].claims.forEach(claim => {
|
|||
|
* console.log(claim.uri);
|
|||
|
* });
|
|||
|
*/
|
|||
|
async function process$1 (publicKey) {
|
|||
|
if (!(publicKey && (publicKey instanceof openpgp.PublicKey))) {
|
|||
|
throw new Error('Invalid public key')
|
|||
|
}
|
|||
|
|
|||
|
const fingerprint = publicKey.getFingerprint();
|
|||
|
const primaryUser = await publicKey.getPrimaryUser();
|
|||
|
const users = publicKey.users;
|
|||
|
const usersOutput = [];
|
|||
|
|
|||
|
users.forEach((user, i) => {
|
|||
|
usersOutput[i] = {
|
|||
|
userData: {
|
|||
|
id: user.userID ? user.userID.userID : null,
|
|||
|
name: user.userID ? user.userID.name : null,
|
|||
|
email: user.userID ? user.userID.email : null,
|
|||
|
comment: user.userID ? user.userID.comment : null,
|
|||
|
isPrimary: primaryUser.index === i,
|
|||
|
isRevoked: false
|
|||
|
},
|
|||
|
claims: []
|
|||
|
};
|
|||
|
|
|||
|
if ('selfCertifications' in user && user.selfCertifications.length > 0) {
|
|||
|
const selfCertification = user.selfCertifications.sort((e1, e2) => e2.created.getTime() - e1.created.getTime())[0];
|
|||
|
|
|||
|
const notations = selfCertification.rawNotations;
|
|||
|
usersOutput[i].claims = notations
|
|||
|
.filter(
|
|||
|
({ name, humanReadable }) =>
|
|||
|
humanReadable && (name === 'proof@ariadne.id' || name === 'proof@metacode.biz')
|
|||
|
)
|
|||
|
.map(
|
|||
|
({ value }) =>
|
|||
|
new Claim(new TextDecoder().decode(value), fingerprint)
|
|||
|
);
|
|||
|
|
|||
|
usersOutput[i].userData.isRevoked = selfCertification.revoked;
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
return {
|
|||
|
fingerprint,
|
|||
|
users: usersOutput,
|
|||
|
primaryUserIndex: primaryUser.index,
|
|||
|
key: {
|
|||
|
data: publicKey,
|
|||
|
fetchMethod: null,
|
|||
|
uri: null
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var keys = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
fetch: fetch$1,
|
|||
|
fetchHKP: fetchHKP,
|
|||
|
fetchKeybase: fetchKeybase,
|
|||
|
fetchPlaintext: fetchPlaintext,
|
|||
|
fetchURI: fetchURI,
|
|||
|
fetchWKD: fetchWKD,
|
|||
|
process: process$1
|
|||
|
});
|
|||
|
|
|||
|
var crypto$1 = crypto;
|
|||
|
const isCryptoKey = (key) => key instanceof CryptoKey;
|
|||
|
|
|||
|
const digest = async (algorithm, data) => {
|
|||
|
const subtleDigest = `SHA-${algorithm.slice(-3)}`;
|
|||
|
return new Uint8Array(await crypto$1.subtle.digest(subtleDigest, data));
|
|||
|
};
|
|||
|
|
|||
|
const encoder = new TextEncoder();
|
|||
|
const decoder = new TextDecoder();
|
|||
|
function concat(...buffers) {
|
|||
|
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|||
|
const buf = new Uint8Array(size);
|
|||
|
let i = 0;
|
|||
|
buffers.forEach((buffer) => {
|
|||
|
buf.set(buffer, i);
|
|||
|
i += buffer.length;
|
|||
|
});
|
|||
|
return buf;
|
|||
|
}
|
|||
|
|
|||
|
const encodeBase64 = (input) => {
|
|||
|
let unencoded = input;
|
|||
|
if (typeof unencoded === 'string') {
|
|||
|
unencoded = encoder.encode(unencoded);
|
|||
|
}
|
|||
|
const CHUNK_SIZE = 0x8000;
|
|||
|
const arr = [];
|
|||
|
for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) {
|
|||
|
arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE)));
|
|||
|
}
|
|||
|
return btoa(arr.join(''));
|
|||
|
};
|
|||
|
const encode = (input) => {
|
|||
|
return encodeBase64(input).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
|
|||
|
};
|
|||
|
const decodeBase64 = (encoded) => {
|
|||
|
const binary = atob(encoded);
|
|||
|
const bytes = new Uint8Array(binary.length);
|
|||
|
for (let i = 0; i < binary.length; i++) {
|
|||
|
bytes[i] = binary.charCodeAt(i);
|
|||
|
}
|
|||
|
return bytes;
|
|||
|
};
|
|||
|
const decode$1 = (input) => {
|
|||
|
let encoded = input;
|
|||
|
if (encoded instanceof Uint8Array) {
|
|||
|
encoded = decoder.decode(encoded);
|
|||
|
}
|
|||
|
encoded = encoded.replace(/-/g, '+').replace(/_/g, '/').replace(/\s/g, '');
|
|||
|
try {
|
|||
|
return decodeBase64(encoded);
|
|||
|
}
|
|||
|
catch (_a) {
|
|||
|
throw new TypeError('The input to be decoded is not correctly encoded.');
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
class JOSEError extends Error {
|
|||
|
static get code() {
|
|||
|
return 'ERR_JOSE_GENERIC';
|
|||
|
}
|
|||
|
constructor(message) {
|
|||
|
var _a;
|
|||
|
super(message);
|
|||
|
this.code = 'ERR_JOSE_GENERIC';
|
|||
|
this.name = this.constructor.name;
|
|||
|
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|||
|
}
|
|||
|
}
|
|||
|
class JOSEAlgNotAllowed extends JOSEError {
|
|||
|
constructor() {
|
|||
|
super(...arguments);
|
|||
|
this.code = 'ERR_JOSE_ALG_NOT_ALLOWED';
|
|||
|
}
|
|||
|
static get code() {
|
|||
|
return 'ERR_JOSE_ALG_NOT_ALLOWED';
|
|||
|
}
|
|||
|
}
|
|||
|
class JOSENotSupported extends JOSEError {
|
|||
|
constructor() {
|
|||
|
super(...arguments);
|
|||
|
this.code = 'ERR_JOSE_NOT_SUPPORTED';
|
|||
|
}
|
|||
|
static get code() {
|
|||
|
return 'ERR_JOSE_NOT_SUPPORTED';
|
|||
|
}
|
|||
|
}
|
|||
|
class JWSInvalid extends JOSEError {
|
|||
|
constructor() {
|
|||
|
super(...arguments);
|
|||
|
this.code = 'ERR_JWS_INVALID';
|
|||
|
}
|
|||
|
static get code() {
|
|||
|
return 'ERR_JWS_INVALID';
|
|||
|
}
|
|||
|
}
|
|||
|
class JWKInvalid extends JOSEError {
|
|||
|
constructor() {
|
|||
|
super(...arguments);
|
|||
|
this.code = 'ERR_JWK_INVALID';
|
|||
|
}
|
|||
|
static get code() {
|
|||
|
return 'ERR_JWK_INVALID';
|
|||
|
}
|
|||
|
}
|
|||
|
class JWSSignatureVerificationFailed extends JOSEError {
|
|||
|
constructor() {
|
|||
|
super(...arguments);
|
|||
|
this.code = 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
|
|||
|
this.message = 'signature verification failed';
|
|||
|
}
|
|||
|
static get code() {
|
|||
|
return 'ERR_JWS_SIGNATURE_VERIFICATION_FAILED';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function unusable(name, prop = 'algorithm.name') {
|
|||
|
return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|||
|
}
|
|||
|
function isAlgorithm(algorithm, name) {
|
|||
|
return algorithm.name === name;
|
|||
|
}
|
|||
|
function getHashLength(hash) {
|
|||
|
return parseInt(hash.name.slice(4), 10);
|
|||
|
}
|
|||
|
function getNamedCurve(alg) {
|
|||
|
switch (alg) {
|
|||
|
case 'ES256':
|
|||
|
return 'P-256';
|
|||
|
case 'ES384':
|
|||
|
return 'P-384';
|
|||
|
case 'ES512':
|
|||
|
return 'P-521';
|
|||
|
default:
|
|||
|
throw new Error('unreachable');
|
|||
|
}
|
|||
|
}
|
|||
|
function checkUsage(key, usages) {
|
|||
|
if (usages.length && !usages.some((expected) => key.usages.includes(expected))) {
|
|||
|
let msg = 'CryptoKey does not support this operation, its usages must include ';
|
|||
|
if (usages.length > 2) {
|
|||
|
const last = usages.pop();
|
|||
|
msg += `one of ${usages.join(', ')}, or ${last}.`;
|
|||
|
}
|
|||
|
else if (usages.length === 2) {
|
|||
|
msg += `one of ${usages[0]} or ${usages[1]}.`;
|
|||
|
}
|
|||
|
else {
|
|||
|
msg += `${usages[0]}.`;
|
|||
|
}
|
|||
|
throw new TypeError(msg);
|
|||
|
}
|
|||
|
}
|
|||
|
function checkSigCryptoKey(key, alg, ...usages) {
|
|||
|
switch (alg) {
|
|||
|
case 'HS256':
|
|||
|
case 'HS384':
|
|||
|
case 'HS512': {
|
|||
|
if (!isAlgorithm(key.algorithm, 'HMAC'))
|
|||
|
throw unusable('HMAC');
|
|||
|
const expected = parseInt(alg.slice(2), 10);
|
|||
|
const actual = getHashLength(key.algorithm.hash);
|
|||
|
if (actual !== expected)
|
|||
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'RS256':
|
|||
|
case 'RS384':
|
|||
|
case 'RS512': {
|
|||
|
if (!isAlgorithm(key.algorithm, 'RSASSA-PKCS1-v1_5'))
|
|||
|
throw unusable('RSASSA-PKCS1-v1_5');
|
|||
|
const expected = parseInt(alg.slice(2), 10);
|
|||
|
const actual = getHashLength(key.algorithm.hash);
|
|||
|
if (actual !== expected)
|
|||
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'PS256':
|
|||
|
case 'PS384':
|
|||
|
case 'PS512': {
|
|||
|
if (!isAlgorithm(key.algorithm, 'RSA-PSS'))
|
|||
|
throw unusable('RSA-PSS');
|
|||
|
const expected = parseInt(alg.slice(2), 10);
|
|||
|
const actual = getHashLength(key.algorithm.hash);
|
|||
|
if (actual !== expected)
|
|||
|
throw unusable(`SHA-${expected}`, 'algorithm.hash');
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'EdDSA': {
|
|||
|
if (key.algorithm.name !== 'Ed25519' && key.algorithm.name !== 'Ed448') {
|
|||
|
throw unusable('Ed25519 or Ed448');
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'ES256':
|
|||
|
case 'ES384':
|
|||
|
case 'ES512': {
|
|||
|
if (!isAlgorithm(key.algorithm, 'ECDSA'))
|
|||
|
throw unusable('ECDSA');
|
|||
|
const expected = getNamedCurve(alg);
|
|||
|
const actual = key.algorithm.namedCurve;
|
|||
|
if (actual !== expected)
|
|||
|
throw unusable(expected, 'algorithm.namedCurve');
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
throw new TypeError('CryptoKey does not support this operation');
|
|||
|
}
|
|||
|
checkUsage(key, usages);
|
|||
|
}
|
|||
|
|
|||
|
function message(msg, actual, ...types) {
|
|||
|
if (types.length > 2) {
|
|||
|
const last = types.pop();
|
|||
|
msg += `one of type ${types.join(', ')}, or ${last}.`;
|
|||
|
}
|
|||
|
else if (types.length === 2) {
|
|||
|
msg += `one of type ${types[0]} or ${types[1]}.`;
|
|||
|
}
|
|||
|
else {
|
|||
|
msg += `of type ${types[0]}.`;
|
|||
|
}
|
|||
|
if (actual == null) {
|
|||
|
msg += ` Received ${actual}`;
|
|||
|
}
|
|||
|
else if (typeof actual === 'function' && actual.name) {
|
|||
|
msg += ` Received function ${actual.name}`;
|
|||
|
}
|
|||
|
else if (typeof actual === 'object' && actual != null) {
|
|||
|
if (actual.constructor && actual.constructor.name) {
|
|||
|
msg += ` Received an instance of ${actual.constructor.name}`;
|
|||
|
}
|
|||
|
}
|
|||
|
return msg;
|
|||
|
}
|
|||
|
var invalidKeyInput = (actual, ...types) => {
|
|||
|
return message('Key must be ', actual, ...types);
|
|||
|
};
|
|||
|
function withAlg(alg, actual, ...types) {
|
|||
|
return message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|||
|
}
|
|||
|
|
|||
|
var isKeyLike = (key) => {
|
|||
|
return isCryptoKey(key);
|
|||
|
};
|
|||
|
const types = ['CryptoKey'];
|
|||
|
|
|||
|
const isDisjoint = (...headers) => {
|
|||
|
const sources = headers.filter(Boolean);
|
|||
|
if (sources.length === 0 || sources.length === 1) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
let acc;
|
|||
|
for (const header of sources) {
|
|||
|
const parameters = Object.keys(header);
|
|||
|
if (!acc || acc.size === 0) {
|
|||
|
acc = new Set(parameters);
|
|||
|
continue;
|
|||
|
}
|
|||
|
for (const parameter of parameters) {
|
|||
|
if (acc.has(parameter)) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
acc.add(parameter);
|
|||
|
}
|
|||
|
}
|
|||
|
return true;
|
|||
|
};
|
|||
|
|
|||
|
function isObjectLike(value) {
|
|||
|
return typeof value === 'object' && value !== null;
|
|||
|
}
|
|||
|
function isObject(input) {
|
|||
|
if (!isObjectLike(input) || Object.prototype.toString.call(input) !== '[object Object]') {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (Object.getPrototypeOf(input) === null) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
let proto = input;
|
|||
|
while (Object.getPrototypeOf(proto) !== null) {
|
|||
|
proto = Object.getPrototypeOf(proto);
|
|||
|
}
|
|||
|
return Object.getPrototypeOf(input) === proto;
|
|||
|
}
|
|||
|
|
|||
|
var checkKeyLength = (alg, key) => {
|
|||
|
if (alg.startsWith('RS') || alg.startsWith('PS')) {
|
|||
|
const { modulusLength } = key.algorithm;
|
|||
|
if (typeof modulusLength !== 'number' || modulusLength < 2048) {
|
|||
|
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
function subtleMapping(jwk) {
|
|||
|
let algorithm;
|
|||
|
let keyUsages;
|
|||
|
switch (jwk.kty) {
|
|||
|
case 'oct': {
|
|||
|
switch (jwk.alg) {
|
|||
|
case 'HS256':
|
|||
|
case 'HS384':
|
|||
|
case 'HS512':
|
|||
|
algorithm = { name: 'HMAC', hash: `SHA-${jwk.alg.slice(-3)}` };
|
|||
|
keyUsages = ['sign', 'verify'];
|
|||
|
break;
|
|||
|
case 'A128CBC-HS256':
|
|||
|
case 'A192CBC-HS384':
|
|||
|
case 'A256CBC-HS512':
|
|||
|
throw new JOSENotSupported(`${jwk.alg} keys cannot be imported as CryptoKey instances`);
|
|||
|
case 'A128GCM':
|
|||
|
case 'A192GCM':
|
|||
|
case 'A256GCM':
|
|||
|
case 'A128GCMKW':
|
|||
|
case 'A192GCMKW':
|
|||
|
case 'A256GCMKW':
|
|||
|
algorithm = { name: 'AES-GCM' };
|
|||
|
keyUsages = ['encrypt', 'decrypt'];
|
|||
|
break;
|
|||
|
case 'A128KW':
|
|||
|
case 'A192KW':
|
|||
|
case 'A256KW':
|
|||
|
algorithm = { name: 'AES-KW' };
|
|||
|
keyUsages = ['wrapKey', 'unwrapKey'];
|
|||
|
break;
|
|||
|
case 'PBES2-HS256+A128KW':
|
|||
|
case 'PBES2-HS384+A192KW':
|
|||
|
case 'PBES2-HS512+A256KW':
|
|||
|
algorithm = { name: 'PBKDF2' };
|
|||
|
keyUsages = ['deriveBits'];
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'RSA': {
|
|||
|
switch (jwk.alg) {
|
|||
|
case 'PS256':
|
|||
|
case 'PS384':
|
|||
|
case 'PS512':
|
|||
|
algorithm = { name: 'RSA-PSS', hash: `SHA-${jwk.alg.slice(-3)}` };
|
|||
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|||
|
break;
|
|||
|
case 'RS256':
|
|||
|
case 'RS384':
|
|||
|
case 'RS512':
|
|||
|
algorithm = { name: 'RSASSA-PKCS1-v1_5', hash: `SHA-${jwk.alg.slice(-3)}` };
|
|||
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|||
|
break;
|
|||
|
case 'RSA-OAEP':
|
|||
|
case 'RSA-OAEP-256':
|
|||
|
case 'RSA-OAEP-384':
|
|||
|
case 'RSA-OAEP-512':
|
|||
|
algorithm = {
|
|||
|
name: 'RSA-OAEP',
|
|||
|
hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`,
|
|||
|
};
|
|||
|
keyUsages = jwk.d ? ['decrypt', 'unwrapKey'] : ['encrypt', 'wrapKey'];
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'EC': {
|
|||
|
switch (jwk.alg) {
|
|||
|
case 'ES256':
|
|||
|
algorithm = { name: 'ECDSA', namedCurve: 'P-256' };
|
|||
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|||
|
break;
|
|||
|
case 'ES384':
|
|||
|
algorithm = { name: 'ECDSA', namedCurve: 'P-384' };
|
|||
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|||
|
break;
|
|||
|
case 'ES512':
|
|||
|
algorithm = { name: 'ECDSA', namedCurve: 'P-521' };
|
|||
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|||
|
break;
|
|||
|
case 'ECDH-ES':
|
|||
|
case 'ECDH-ES+A128KW':
|
|||
|
case 'ECDH-ES+A192KW':
|
|||
|
case 'ECDH-ES+A256KW':
|
|||
|
algorithm = { name: 'ECDH', namedCurve: jwk.crv };
|
|||
|
keyUsages = jwk.d ? ['deriveBits'] : [];
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
case 'OKP': {
|
|||
|
switch (jwk.alg) {
|
|||
|
case 'EdDSA':
|
|||
|
algorithm = { name: jwk.crv };
|
|||
|
keyUsages = jwk.d ? ['sign'] : ['verify'];
|
|||
|
break;
|
|||
|
case 'ECDH-ES':
|
|||
|
case 'ECDH-ES+A128KW':
|
|||
|
case 'ECDH-ES+A192KW':
|
|||
|
case 'ECDH-ES+A256KW':
|
|||
|
algorithm = { name: jwk.crv };
|
|||
|
keyUsages = jwk.d ? ['deriveBits'] : [];
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
|
|||
|
}
|
|||
|
return { algorithm, keyUsages };
|
|||
|
}
|
|||
|
const parse$1 = async (jwk) => {
|
|||
|
var _a, _b;
|
|||
|
if (!jwk.alg) {
|
|||
|
throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
|
|||
|
}
|
|||
|
const { algorithm, keyUsages } = subtleMapping(jwk);
|
|||
|
const rest = [
|
|||
|
algorithm,
|
|||
|
(_a = jwk.ext) !== null && _a !== void 0 ? _a : false,
|
|||
|
(_b = jwk.key_ops) !== null && _b !== void 0 ? _b : keyUsages,
|
|||
|
];
|
|||
|
if (algorithm.name === 'PBKDF2') {
|
|||
|
return crypto$1.subtle.importKey('raw', decode$1(jwk.k), ...rest);
|
|||
|
}
|
|||
|
const keyData = { ...jwk };
|
|||
|
delete keyData.alg;
|
|||
|
delete keyData.use;
|
|||
|
return crypto$1.subtle.importKey('jwk', keyData, ...rest);
|
|||
|
};
|
|||
|
var asKeyObject = parse$1;
|
|||
|
|
|||
|
async function importJWK(jwk, alg, octAsKeyObject) {
|
|||
|
var _a;
|
|||
|
if (!isObject(jwk)) {
|
|||
|
throw new TypeError('JWK must be an object');
|
|||
|
}
|
|||
|
alg || (alg = jwk.alg);
|
|||
|
switch (jwk.kty) {
|
|||
|
case 'oct':
|
|||
|
if (typeof jwk.k !== 'string' || !jwk.k) {
|
|||
|
throw new TypeError('missing "k" (Key Value) Parameter value');
|
|||
|
}
|
|||
|
octAsKeyObject !== null && octAsKeyObject !== void 0 ? octAsKeyObject : (octAsKeyObject = jwk.ext !== true);
|
|||
|
if (octAsKeyObject) {
|
|||
|
return asKeyObject({ ...jwk, alg, ext: (_a = jwk.ext) !== null && _a !== void 0 ? _a : false });
|
|||
|
}
|
|||
|
return decode$1(jwk.k);
|
|||
|
case 'RSA':
|
|||
|
if (jwk.oth !== undefined) {
|
|||
|
throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
|
|||
|
}
|
|||
|
case 'EC':
|
|||
|
case 'OKP':
|
|||
|
return asKeyObject({ ...jwk, alg });
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const symmetricTypeCheck = (alg, key) => {
|
|||
|
if (key instanceof Uint8Array)
|
|||
|
return;
|
|||
|
if (!isKeyLike(key)) {
|
|||
|
throw new TypeError(withAlg(alg, key, ...types, 'Uint8Array'));
|
|||
|
}
|
|||
|
if (key.type !== 'secret') {
|
|||
|
throw new TypeError(`${types.join(' or ')} instances for symmetric algorithms must be of type "secret"`);
|
|||
|
}
|
|||
|
};
|
|||
|
const asymmetricTypeCheck = (alg, key, usage) => {
|
|||
|
if (!isKeyLike(key)) {
|
|||
|
throw new TypeError(withAlg(alg, key, ...types));
|
|||
|
}
|
|||
|
if (key.type === 'secret') {
|
|||
|
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithms must not be of type "secret"`);
|
|||
|
}
|
|||
|
if (usage === 'sign' && key.type === 'public') {
|
|||
|
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm signing must be of type "private"`);
|
|||
|
}
|
|||
|
if (usage === 'decrypt' && key.type === 'public') {
|
|||
|
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm decryption must be of type "private"`);
|
|||
|
}
|
|||
|
if (key.algorithm && usage === 'verify' && key.type === 'private') {
|
|||
|
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm verifying must be of type "public"`);
|
|||
|
}
|
|||
|
if (key.algorithm && usage === 'encrypt' && key.type === 'private') {
|
|||
|
throw new TypeError(`${types.join(' or ')} instances for asymmetric algorithm encryption must be of type "public"`);
|
|||
|
}
|
|||
|
};
|
|||
|
const checkKeyType = (alg, key, usage) => {
|
|||
|
const symmetric = alg.startsWith('HS') ||
|
|||
|
alg === 'dir' ||
|
|||
|
alg.startsWith('PBES2') ||
|
|||
|
/^A\d{3}(?:GCM)?KW$/.test(alg);
|
|||
|
if (symmetric) {
|
|||
|
symmetricTypeCheck(alg, key);
|
|||
|
}
|
|||
|
else {
|
|||
|
asymmetricTypeCheck(alg, key, usage);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|||
|
if (joseHeader.crit !== undefined && protectedHeader.crit === undefined) {
|
|||
|
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|||
|
}
|
|||
|
if (!protectedHeader || protectedHeader.crit === undefined) {
|
|||
|
return new Set();
|
|||
|
}
|
|||
|
if (!Array.isArray(protectedHeader.crit) ||
|
|||
|
protectedHeader.crit.length === 0 ||
|
|||
|
protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) {
|
|||
|
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|||
|
}
|
|||
|
let recognized;
|
|||
|
if (recognizedOption !== undefined) {
|
|||
|
recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
|
|||
|
}
|
|||
|
else {
|
|||
|
recognized = recognizedDefault;
|
|||
|
}
|
|||
|
for (const parameter of protectedHeader.crit) {
|
|||
|
if (!recognized.has(parameter)) {
|
|||
|
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|||
|
}
|
|||
|
if (joseHeader[parameter] === undefined) {
|
|||
|
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|||
|
}
|
|||
|
else if (recognized.get(parameter) && protectedHeader[parameter] === undefined) {
|
|||
|
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|||
|
}
|
|||
|
}
|
|||
|
return new Set(protectedHeader.crit);
|
|||
|
}
|
|||
|
|
|||
|
const validateAlgorithms = (option, algorithms) => {
|
|||
|
if (algorithms !== undefined &&
|
|||
|
(!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) {
|
|||
|
throw new TypeError(`"${option}" option must be an array of strings`);
|
|||
|
}
|
|||
|
if (!algorithms) {
|
|||
|
return undefined;
|
|||
|
}
|
|||
|
return new Set(algorithms);
|
|||
|
};
|
|||
|
|
|||
|
function subtleDsa(alg, algorithm) {
|
|||
|
const hash = `SHA-${alg.slice(-3)}`;
|
|||
|
switch (alg) {
|
|||
|
case 'HS256':
|
|||
|
case 'HS384':
|
|||
|
case 'HS512':
|
|||
|
return { hash, name: 'HMAC' };
|
|||
|
case 'PS256':
|
|||
|
case 'PS384':
|
|||
|
case 'PS512':
|
|||
|
return { hash, name: 'RSA-PSS', saltLength: alg.slice(-3) >> 3 };
|
|||
|
case 'RS256':
|
|||
|
case 'RS384':
|
|||
|
case 'RS512':
|
|||
|
return { hash, name: 'RSASSA-PKCS1-v1_5' };
|
|||
|
case 'ES256':
|
|||
|
case 'ES384':
|
|||
|
case 'ES512':
|
|||
|
return { hash, name: 'ECDSA', namedCurve: algorithm.namedCurve };
|
|||
|
case 'EdDSA':
|
|||
|
return { name: algorithm.name };
|
|||
|
default:
|
|||
|
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getCryptoKey(alg, key, usage) {
|
|||
|
if (isCryptoKey(key)) {
|
|||
|
checkSigCryptoKey(key, alg, usage);
|
|||
|
return key;
|
|||
|
}
|
|||
|
if (key instanceof Uint8Array) {
|
|||
|
if (!alg.startsWith('HS')) {
|
|||
|
throw new TypeError(invalidKeyInput(key, ...types));
|
|||
|
}
|
|||
|
return crypto$1.subtle.importKey('raw', key, { hash: `SHA-${alg.slice(-3)}`, name: 'HMAC' }, false, [usage]);
|
|||
|
}
|
|||
|
throw new TypeError(invalidKeyInput(key, ...types, 'Uint8Array'));
|
|||
|
}
|
|||
|
|
|||
|
const verify = async (alg, key, signature, data) => {
|
|||
|
const cryptoKey = await getCryptoKey(alg, key, 'verify');
|
|||
|
checkKeyLength(alg, cryptoKey);
|
|||
|
const algorithm = subtleDsa(alg, cryptoKey.algorithm);
|
|||
|
try {
|
|||
|
return await crypto$1.subtle.verify(algorithm, cryptoKey, signature, data);
|
|||
|
}
|
|||
|
catch (_a) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
async function flattenedVerify(jws, key, options) {
|
|||
|
var _a;
|
|||
|
if (!isObject(jws)) {
|
|||
|
throw new JWSInvalid('Flattened JWS must be an object');
|
|||
|
}
|
|||
|
if (jws.protected === undefined && jws.header === undefined) {
|
|||
|
throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members');
|
|||
|
}
|
|||
|
if (jws.protected !== undefined && typeof jws.protected !== 'string') {
|
|||
|
throw new JWSInvalid('JWS Protected Header incorrect type');
|
|||
|
}
|
|||
|
if (jws.payload === undefined) {
|
|||
|
throw new JWSInvalid('JWS Payload missing');
|
|||
|
}
|
|||
|
if (typeof jws.signature !== 'string') {
|
|||
|
throw new JWSInvalid('JWS Signature missing or incorrect type');
|
|||
|
}
|
|||
|
if (jws.header !== undefined && !isObject(jws.header)) {
|
|||
|
throw new JWSInvalid('JWS Unprotected Header incorrect type');
|
|||
|
}
|
|||
|
let parsedProt = {};
|
|||
|
if (jws.protected) {
|
|||
|
try {
|
|||
|
const protectedHeader = decode$1(jws.protected);
|
|||
|
parsedProt = JSON.parse(decoder.decode(protectedHeader));
|
|||
|
}
|
|||
|
catch (_b) {
|
|||
|
throw new JWSInvalid('JWS Protected Header is invalid');
|
|||
|
}
|
|||
|
}
|
|||
|
if (!isDisjoint(parsedProt, jws.header)) {
|
|||
|
throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint');
|
|||
|
}
|
|||
|
const joseHeader = {
|
|||
|
...parsedProt,
|
|||
|
...jws.header,
|
|||
|
};
|
|||
|
const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader);
|
|||
|
let b64 = true;
|
|||
|
if (extensions.has('b64')) {
|
|||
|
b64 = parsedProt.b64;
|
|||
|
if (typeof b64 !== 'boolean') {
|
|||
|
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|||
|
}
|
|||
|
}
|
|||
|
const { alg } = joseHeader;
|
|||
|
if (typeof alg !== 'string' || !alg) {
|
|||
|
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|||
|
}
|
|||
|
const algorithms = options && validateAlgorithms('algorithms', options.algorithms);
|
|||
|
if (algorithms && !algorithms.has(alg)) {
|
|||
|
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed');
|
|||
|
}
|
|||
|
if (b64) {
|
|||
|
if (typeof jws.payload !== 'string') {
|
|||
|
throw new JWSInvalid('JWS Payload must be a string');
|
|||
|
}
|
|||
|
}
|
|||
|
else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) {
|
|||
|
throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance');
|
|||
|
}
|
|||
|
let resolvedKey = false;
|
|||
|
if (typeof key === 'function') {
|
|||
|
key = await key(parsedProt, jws);
|
|||
|
resolvedKey = true;
|
|||
|
}
|
|||
|
checkKeyType(alg, key, 'verify');
|
|||
|
const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload);
|
|||
|
const signature = decode$1(jws.signature);
|
|||
|
const verified = await verify(alg, key, signature, data);
|
|||
|
if (!verified) {
|
|||
|
throw new JWSSignatureVerificationFailed();
|
|||
|
}
|
|||
|
let payload;
|
|||
|
if (b64) {
|
|||
|
payload = decode$1(jws.payload);
|
|||
|
}
|
|||
|
else if (typeof jws.payload === 'string') {
|
|||
|
payload = encoder.encode(jws.payload);
|
|||
|
}
|
|||
|
else {
|
|||
|
payload = jws.payload;
|
|||
|
}
|
|||
|
const result = { payload };
|
|||
|
if (jws.protected !== undefined) {
|
|||
|
result.protectedHeader = parsedProt;
|
|||
|
}
|
|||
|
if (jws.header !== undefined) {
|
|||
|
result.unprotectedHeader = jws.header;
|
|||
|
}
|
|||
|
if (resolvedKey) {
|
|||
|
return { ...result, key };
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
async function compactVerify(jws, key, options) {
|
|||
|
if (jws instanceof Uint8Array) {
|
|||
|
jws = decoder.decode(jws);
|
|||
|
}
|
|||
|
if (typeof jws !== 'string') {
|
|||
|
throw new JWSInvalid('Compact JWS must be a string or Uint8Array');
|
|||
|
}
|
|||
|
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split('.');
|
|||
|
if (length !== 3) {
|
|||
|
throw new JWSInvalid('Invalid Compact JWS');
|
|||
|
}
|
|||
|
const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);
|
|||
|
const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
|
|||
|
if (typeof key === 'function') {
|
|||
|
return { ...result, key: verified.key };
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
const check = (value, description) => {
|
|||
|
if (typeof value !== 'string' || !value) {
|
|||
|
throw new JWKInvalid(`${description} missing or invalid`);
|
|||
|
}
|
|||
|
};
|
|||
|
async function calculateJwkThumbprint(jwk, digestAlgorithm) {
|
|||
|
if (!isObject(jwk)) {
|
|||
|
throw new TypeError('JWK must be an object');
|
|||
|
}
|
|||
|
digestAlgorithm !== null && digestAlgorithm !== void 0 ? digestAlgorithm : (digestAlgorithm = 'sha256');
|
|||
|
if (digestAlgorithm !== 'sha256' &&
|
|||
|
digestAlgorithm !== 'sha384' &&
|
|||
|
digestAlgorithm !== 'sha512') {
|
|||
|
throw new TypeError('digestAlgorithm must one of "sha256", "sha384", or "sha512"');
|
|||
|
}
|
|||
|
let components;
|
|||
|
switch (jwk.kty) {
|
|||
|
case 'EC':
|
|||
|
check(jwk.crv, '"crv" (Curve) Parameter');
|
|||
|
check(jwk.x, '"x" (X Coordinate) Parameter');
|
|||
|
check(jwk.y, '"y" (Y Coordinate) Parameter');
|
|||
|
components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
|
|||
|
break;
|
|||
|
case 'OKP':
|
|||
|
check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter');
|
|||
|
check(jwk.x, '"x" (Public Key) Parameter');
|
|||
|
components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
|
|||
|
break;
|
|||
|
case 'RSA':
|
|||
|
check(jwk.e, '"e" (Exponent) Parameter');
|
|||
|
check(jwk.n, '"n" (Modulus) Parameter');
|
|||
|
components = { e: jwk.e, kty: jwk.kty, n: jwk.n };
|
|||
|
break;
|
|||
|
case 'oct':
|
|||
|
check(jwk.k, '"k" (Key Value) Parameter');
|
|||
|
components = { k: jwk.k, kty: jwk.kty };
|
|||
|
break;
|
|||
|
default:
|
|||
|
throw new JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported');
|
|||
|
}
|
|||
|
const data = encoder.encode(JSON.stringify(components));
|
|||
|
return encode(await digest(digestAlgorithm, data));
|
|||
|
}
|
|||
|
|
|||
|
const decode = decode$1;
|
|||
|
|
|||
|
function decodeProtectedHeader(token) {
|
|||
|
let protectedB64u;
|
|||
|
if (typeof token === 'string') {
|
|||
|
const parts = token.split('.');
|
|||
|
if (parts.length === 3 || parts.length === 5) {
|
|||
|
[protectedB64u] = parts;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (typeof token === 'object' && token) {
|
|||
|
if ('protected' in token) {
|
|||
|
protectedB64u = token.protected;
|
|||
|
}
|
|||
|
else {
|
|||
|
throw new TypeError('Token does not contain a Protected Header');
|
|||
|
}
|
|||
|
}
|
|||
|
try {
|
|||
|
if (typeof protectedB64u !== 'string' || !protectedB64u) {
|
|||
|
throw new Error();
|
|||
|
}
|
|||
|
const result = JSON.parse(decoder.decode(decode(protectedB64u)));
|
|||
|
if (!isObject(result)) {
|
|||
|
throw new Error();
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
catch (_a) {
|
|||
|
throw new TypeError('Invalid Token or Protected Header formatting');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var lib = {};
|
|||
|
|
|||
|
Object.defineProperty(lib, '__esModule', { value: true });
|
|||
|
|
|||
|
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
|||
|
function parse(string, encoding, opts) {
|
|||
|
var _opts$out;
|
|||
|
|
|||
|
if (opts === void 0) {
|
|||
|
opts = {};
|
|||
|
}
|
|||
|
|
|||
|
// Build the character lookup table:
|
|||
|
if (!encoding.codes) {
|
|||
|
encoding.codes = {};
|
|||
|
|
|||
|
for (var i = 0; i < encoding.chars.length; ++i) {
|
|||
|
encoding.codes[encoding.chars[i]] = i;
|
|||
|
}
|
|||
|
} // The string must have a whole number of bytes:
|
|||
|
|
|||
|
|
|||
|
if (!opts.loose && string.length * encoding.bits & 7) {
|
|||
|
throw new SyntaxError('Invalid padding');
|
|||
|
} // Count the padding bytes:
|
|||
|
|
|||
|
|
|||
|
var end = string.length;
|
|||
|
|
|||
|
while (string[end - 1] === '=') {
|
|||
|
--end; // If we get a whole number of bytes, there is too much padding:
|
|||
|
|
|||
|
if (!opts.loose && !((string.length - end) * encoding.bits & 7)) {
|
|||
|
throw new SyntaxError('Invalid padding');
|
|||
|
}
|
|||
|
} // Allocate the output:
|
|||
|
|
|||
|
|
|||
|
var out = new ((_opts$out = opts.out) != null ? _opts$out : Uint8Array)(end * encoding.bits / 8 | 0); // Parse the data:
|
|||
|
|
|||
|
var bits = 0; // Number of bits currently in the buffer
|
|||
|
|
|||
|
var buffer = 0; // Bits waiting to be written out, MSB first
|
|||
|
|
|||
|
var written = 0; // Next byte to write
|
|||
|
|
|||
|
for (var _i = 0; _i < end; ++_i) {
|
|||
|
// Read one character from the string:
|
|||
|
var value = encoding.codes[string[_i]];
|
|||
|
|
|||
|
if (value === undefined) {
|
|||
|
throw new SyntaxError('Invalid character ' + string[_i]);
|
|||
|
} // Append the bits to the buffer:
|
|||
|
|
|||
|
|
|||
|
buffer = buffer << encoding.bits | value;
|
|||
|
bits += encoding.bits; // Write out some bits if the buffer has a byte's worth:
|
|||
|
|
|||
|
if (bits >= 8) {
|
|||
|
bits -= 8;
|
|||
|
out[written++] = 0xff & buffer >> bits;
|
|||
|
}
|
|||
|
} // Verify that we have received just enough bits:
|
|||
|
|
|||
|
|
|||
|
if (bits >= encoding.bits || 0xff & buffer << 8 - bits) {
|
|||
|
throw new SyntaxError('Unexpected end of data');
|
|||
|
}
|
|||
|
|
|||
|
return out;
|
|||
|
}
|
|||
|
function stringify(data, encoding, opts) {
|
|||
|
if (opts === void 0) {
|
|||
|
opts = {};
|
|||
|
}
|
|||
|
|
|||
|
var _opts = opts,
|
|||
|
_opts$pad = _opts.pad,
|
|||
|
pad = _opts$pad === void 0 ? true : _opts$pad;
|
|||
|
var mask = (1 << encoding.bits) - 1;
|
|||
|
var out = '';
|
|||
|
var bits = 0; // Number of bits currently in the buffer
|
|||
|
|
|||
|
var buffer = 0; // Bits waiting to be written out, MSB first
|
|||
|
|
|||
|
for (var i = 0; i < data.length; ++i) {
|
|||
|
// Slurp data into the buffer:
|
|||
|
buffer = buffer << 8 | 0xff & data[i];
|
|||
|
bits += 8; // Write out as much as we can:
|
|||
|
|
|||
|
while (bits > encoding.bits) {
|
|||
|
bits -= encoding.bits;
|
|||
|
out += encoding.chars[mask & buffer >> bits];
|
|||
|
}
|
|||
|
} // Partial character:
|
|||
|
|
|||
|
|
|||
|
if (bits) {
|
|||
|
out += encoding.chars[mask & buffer << encoding.bits - bits];
|
|||
|
} // Add padding characters until we hit a byte boundary:
|
|||
|
|
|||
|
|
|||
|
if (pad) {
|
|||
|
while (out.length * encoding.bits & 7) {
|
|||
|
out += '=';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return out;
|
|||
|
}
|
|||
|
|
|||
|
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
|||
|
var base16Encoding = {
|
|||
|
chars: '0123456789ABCDEF',
|
|||
|
bits: 4
|
|||
|
};
|
|||
|
var base32Encoding = {
|
|||
|
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567',
|
|||
|
bits: 5
|
|||
|
};
|
|||
|
var base32HexEncoding = {
|
|||
|
chars: '0123456789ABCDEFGHIJKLMNOPQRSTUV',
|
|||
|
bits: 5
|
|||
|
};
|
|||
|
var base64Encoding = {
|
|||
|
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
|
|||
|
bits: 6
|
|||
|
};
|
|||
|
var base64UrlEncoding = {
|
|||
|
chars: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_',
|
|||
|
bits: 6
|
|||
|
};
|
|||
|
var base16 = {
|
|||
|
parse: function parse$1(string, opts) {
|
|||
|
return parse(string.toUpperCase(), base16Encoding, opts);
|
|||
|
},
|
|||
|
stringify: function stringify$1(data, opts) {
|
|||
|
return stringify(data, base16Encoding, opts);
|
|||
|
}
|
|||
|
};
|
|||
|
var base32$1 = {
|
|||
|
parse: function parse$1(string, opts) {
|
|||
|
if (opts === void 0) {
|
|||
|
opts = {};
|
|||
|
}
|
|||
|
|
|||
|
return parse(opts.loose ? string.toUpperCase().replace(/0/g, 'O').replace(/1/g, 'L').replace(/8/g, 'B') : string, base32Encoding, opts);
|
|||
|
},
|
|||
|
stringify: function stringify$1(data, opts) {
|
|||
|
return stringify(data, base32Encoding, opts);
|
|||
|
}
|
|||
|
};
|
|||
|
var base32hex = {
|
|||
|
parse: function parse$1(string, opts) {
|
|||
|
return parse(string, base32HexEncoding, opts);
|
|||
|
},
|
|||
|
stringify: function stringify$1(data, opts) {
|
|||
|
return stringify(data, base32HexEncoding, opts);
|
|||
|
}
|
|||
|
};
|
|||
|
var base64 = {
|
|||
|
parse: function parse$1(string, opts) {
|
|||
|
return parse(string, base64Encoding, opts);
|
|||
|
},
|
|||
|
stringify: function stringify$1(data, opts) {
|
|||
|
return stringify(data, base64Encoding, opts);
|
|||
|
}
|
|||
|
};
|
|||
|
var base64url$1 = {
|
|||
|
parse: function parse$1(string, opts) {
|
|||
|
return parse(string, base64UrlEncoding, opts);
|
|||
|
},
|
|||
|
stringify: function stringify$1(data, opts) {
|
|||
|
return stringify(data, base64UrlEncoding, opts);
|
|||
|
}
|
|||
|
};
|
|||
|
var codec = {
|
|||
|
parse: parse,
|
|||
|
stringify: stringify
|
|||
|
};
|
|||
|
|
|||
|
lib.base16 = base16;
|
|||
|
lib.base32 = base32$1;
|
|||
|
lib.base32hex = base32hex;
|
|||
|
lib.base64 = base64;
|
|||
|
lib.base64url = base64url$1;
|
|||
|
lib.codec = codec;
|
|||
|
|
|||
|
// Generated by rollup-plugin-mjs-entry
|
|||
|
|
|||
|
|
|||
|
lib.base16;
|
|||
|
const base32 = lib.base32;
|
|||
|
lib.base32hex;
|
|||
|
lib.base64;
|
|||
|
const base64url = lib.base64url;
|
|||
|
lib.codec;
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2023 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
const SupportedCryptoAlg = ['EdDSA', 'ES256', 'ES256K', 'ES384', 'ES512'];
|
|||
|
|
|||
|
/**
|
|||
|
* Functions related to Ariadne Signature Profiles
|
|||
|
* @module asp
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key using Web Key Directory
|
|||
|
* @function
|
|||
|
* @param {string} uri - ASPE URI
|
|||
|
* @returns {Promise<Profile>}
|
|||
|
* @example
|
|||
|
* const key = doip.aspe.fetchASPE('aspe:domain.tld:1234567890');
|
|||
|
*/
|
|||
|
async function fetchASPE (uri) {
|
|||
|
const re = /aspe:(.*):(.*)/;
|
|||
|
|
|||
|
if (!re.test(uri)) {
|
|||
|
throw new Error('Invalid ASPE URI')
|
|||
|
}
|
|||
|
|
|||
|
const matches = uri.match(re);
|
|||
|
const domainPart = matches[1];
|
|||
|
const localPart = matches[2].toUpperCase();
|
|||
|
|
|||
|
const profileUrl = `https://${domainPart}/.well-known/aspe/id/${localPart}`;
|
|||
|
let profileJws;
|
|||
|
|
|||
|
try {
|
|||
|
profileJws = await axios$1.get(
|
|||
|
profileUrl,
|
|||
|
{
|
|||
|
responseType: 'text'
|
|||
|
}
|
|||
|
)
|
|||
|
.then((/** @type {import('axios').AxiosResponse} */ response) => {
|
|||
|
if (response.status === 200) {
|
|||
|
return response
|
|||
|
}
|
|||
|
})
|
|||
|
.then((/** @type {import('axios').AxiosResponse} */ response) => response.data);
|
|||
|
} catch (e) {
|
|||
|
throw new Error(`Error fetching Keybase key: ${e.message}`)
|
|||
|
}
|
|||
|
|
|||
|
return await parseProfileJws(profileJws, uri)
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Fetch a public key using Web Key Directory
|
|||
|
* @function
|
|||
|
* @param {string} profileJws - Compact-Serialized profile JWS
|
|||
|
* @param {string} uri - The ASPE URI associated with the profile
|
|||
|
* @returns {Promise<Profile>}
|
|||
|
* @example
|
|||
|
* const key = doip.aspe.parseProfileJws('...');
|
|||
|
*/
|
|||
|
async function parseProfileJws (profileJws, uri) {
|
|||
|
const matches = uri.match(/aspe:(.*):(.*)/);
|
|||
|
const localPart = matches[2].toUpperCase();
|
|||
|
|
|||
|
// Decode the headers
|
|||
|
const protectedHeader = decodeProtectedHeader(profileJws);
|
|||
|
|
|||
|
// Extract the JWK
|
|||
|
if (!SupportedCryptoAlg.includes(protectedHeader.alg)) {
|
|||
|
throw new Error('Invalid profile JWS: wrong key algorithm')
|
|||
|
}
|
|||
|
if (!protectedHeader.kid) {
|
|||
|
throw new Error('Invalid profile JWS: missing key identifier')
|
|||
|
}
|
|||
|
if (!protectedHeader.jwk) {
|
|||
|
throw new Error('Invalid profile JWS: missing key')
|
|||
|
}
|
|||
|
const publicKey = await importJWK(protectedHeader.jwk, protectedHeader.alg);
|
|||
|
|
|||
|
// Compute and verify the fingerprint
|
|||
|
const fp = await computeJwkFingerprint(protectedHeader.jwk);
|
|||
|
|
|||
|
if (fp !== protectedHeader.kid) {
|
|||
|
throw new Error('Invalid profile JWS: wrong key')
|
|||
|
}
|
|||
|
if (localPart && fp !== localPart) {
|
|||
|
throw new Error('Invalid profile JWS: wrong key')
|
|||
|
}
|
|||
|
|
|||
|
// Decode the payload
|
|||
|
const { payload } = await compactVerify(profileJws, publicKey);
|
|||
|
const payloadJson = JSON.parse(new TextDecoder().decode(payload));
|
|||
|
|
|||
|
// Verify the payload
|
|||
|
if (!(Object.prototype.hasOwnProperty.call(payloadJson, 'http://ariadne.id/type') && payloadJson['http://ariadne.id/type'] === 'profile')) {
|
|||
|
throw new Error('Invalid profile JWS: JWS is not a profile')
|
|||
|
}
|
|||
|
if (!(Object.prototype.hasOwnProperty.call(payloadJson, 'http://ariadne.id/version') && payloadJson['http://ariadne.id/version'] === 0)) {
|
|||
|
throw new Error('Invalid profile JWS: profile version not supported')
|
|||
|
}
|
|||
|
|
|||
|
// Extract data from the payload
|
|||
|
/** @type {string} */
|
|||
|
const profileName = payloadJson['http://ariadne.id/name'];
|
|||
|
/** @type {string} */
|
|||
|
const profileDescription = payloadJson['http://ariadne.id/description'];
|
|||
|
/** @type {string[]} */
|
|||
|
const profileClaims = payloadJson['http://ariadne.id/claims'];
|
|||
|
|
|||
|
const profileClaimsParsed = profileClaims.map(x => new Claim(x, uri));
|
|||
|
|
|||
|
const pe = new Persona(profileName, profileDescription || '', profileClaimsParsed);
|
|||
|
const pr = new Profile([pe]);
|
|||
|
pr.primaryPersona = 0;
|
|||
|
|
|||
|
return pr
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Compute the fingerprint for JWK keys
|
|||
|
* @function
|
|||
|
* @param {import('jose').JWK} key
|
|||
|
* @returns {Promise<string>}
|
|||
|
*/
|
|||
|
async function computeJwkFingerprint (key) {
|
|||
|
const thumbprint = await calculateJwkThumbprint(key, 'sha512');
|
|||
|
const fingerprintBytes = base64url.parse(thumbprint, { loose: true }).slice(0, 16);
|
|||
|
const fingerprint = base32.stringify(fingerprintBytes, { pad: false });
|
|||
|
|
|||
|
return fingerprint
|
|||
|
}
|
|||
|
|
|||
|
var asp = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
computeJwkFingerprint: computeJwkFingerprint,
|
|||
|
fetchASPE: fetchASPE,
|
|||
|
parseProfileJws: parseProfileJws
|
|||
|
});
|
|||
|
|
|||
|
/*
|
|||
|
Copyright 2021 Yarmo Mackenbach
|
|||
|
|
|||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
you may not use this file except in compliance with the License.
|
|||
|
You may obtain a copy of the License at
|
|||
|
|
|||
|
http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
|
|||
|
Unless required by applicable law or agreed to in writing, software
|
|||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
See the License for the specific language governing permissions and
|
|||
|
limitations under the License.
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* @module signatures
|
|||
|
*/
|
|||
|
|
|||
|
/**
|
|||
|
* Extract data from a signature and fetch the associated key
|
|||
|
* @async
|
|||
|
* @param {string} signature - The plaintext signature to process
|
|||
|
* @returns {Promise<object>}
|
|||
|
*/
|
|||
|
async function process (signature) {
|
|||
|
/** @type {import('openpgp').CleartextMessage} */
|
|||
|
let sigData;
|
|||
|
const result = {
|
|||
|
fingerprint: null,
|
|||
|
users: [
|
|||
|
{
|
|||
|
userData: {},
|
|||
|
claims: []
|
|||
|
}
|
|||
|
],
|
|||
|
primaryUserIndex: null,
|
|||
|
key: {
|
|||
|
data: null,
|
|||
|
fetchMethod: null,
|
|||
|
uri: null
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
// Read the signature
|
|||
|
try {
|
|||
|
sigData = await openpgp.readCleartextMessage({
|
|||
|
cleartextMessage: signature
|
|||
|
});
|
|||
|
} catch (e) {
|
|||
|
throw new Error(`Signature could not be read (${e.message})`)
|
|||
|
}
|
|||
|
|
|||
|
// @ts-ignore
|
|||
|
const issuerKeyID = sigData.signature.packets[0].issuerKeyID.toHex();
|
|||
|
// @ts-ignore
|
|||
|
const signersUserID = sigData.signature.packets[0].signersUserID;
|
|||
|
const preferredKeyServer =
|
|||
|
// @ts-ignore
|
|||
|
sigData.signature.packets[0].preferredKeyServer ||
|
|||
|
'https://keys.openpgp.org/';
|
|||
|
const text = sigData.getText();
|
|||
|
const sigKeys = [];
|
|||
|
|
|||
|
text.split('\n').forEach((line, i) => {
|
|||
|
const match = line.match(/^([a-zA-Z0-9]*)=(.*)$/i);
|
|||
|
if (!match) {
|
|||
|
return
|
|||
|
}
|
|||
|
switch (match[1].toLowerCase()) {
|
|||
|
case 'key':
|
|||
|
sigKeys.push(match[2]);
|
|||
|
break
|
|||
|
|
|||
|
case 'proof':
|
|||
|
result.users[0].claims.push(new Claim(match[2]));
|
|||
|
break
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// Try overruling key
|
|||
|
if (sigKeys.length > 0) {
|
|||
|
try {
|
|||
|
result.key.uri = sigKeys[0];
|
|||
|
result.key.data = await fetchURI(result.key.uri);
|
|||
|
result.key.fetchMethod = result.key.uri.split(':')[0];
|
|||
|
} catch (e) {}
|
|||
|
}
|
|||
|
// Try WKD
|
|||
|
if (!result.key.data && signersUserID) {
|
|||
|
try {
|
|||
|
result.key.uri = `wkd:${signersUserID}`;
|
|||
|
result.key.data = await fetchURI(result.key.uri);
|
|||
|
result.key.fetchMethod = 'wkd';
|
|||
|
} catch (e) {}
|
|||
|
}
|
|||
|
// Try HKP
|
|||
|
if (!result.key.data) {
|
|||
|
try {
|
|||
|
const match = preferredKeyServer.match(/^(.*:\/\/)?([^/]*)(?:\/)?$/i);
|
|||
|
result.key.uri = `hkp:${match[2]}:${issuerKeyID || signersUserID}`;
|
|||
|
result.key.data = await fetchURI(result.key.uri);
|
|||
|
result.key.fetchMethod = 'hkp';
|
|||
|
} catch (e) {
|
|||
|
throw new Error('Public key not found')
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Verify the signature
|
|||
|
const verificationResult = await openpgp.verify({
|
|||
|
// @ts-ignore
|
|||
|
message: sigData,
|
|||
|
verificationKeys: result.key.data
|
|||
|
});
|
|||
|
const { verified } = verificationResult.signatures[0];
|
|||
|
try {
|
|||
|
await verified;
|
|||
|
} catch (e) {
|
|||
|
throw new Error(`Signature could not be verified (${e.message})`)
|
|||
|
}
|
|||
|
|
|||
|
result.fingerprint = result.key.data.keyPacket.getFingerprint();
|
|||
|
|
|||
|
result.users[0].claims.forEach((claim) => {
|
|||
|
claim.fingerprint = result.fingerprint;
|
|||
|
});
|
|||
|
|
|||
|
const primaryUserData = await result.key.data.getPrimaryUser();
|
|||
|
let userData;
|
|||
|
|
|||
|
if (signersUserID) {
|
|||
|
result.key.data.users.forEach((/** @type {{ userID: { email: string; }; }} */ user) => {
|
|||
|
if (user.userID.email === signersUserID) {
|
|||
|
userData = user;
|
|||
|
}
|
|||
|
});
|
|||
|
}
|
|||
|
if (!userData) {
|
|||
|
userData = primaryUserData.user;
|
|||
|
}
|
|||
|
|
|||
|
result.users[0].userData = {
|
|||
|
id: userData.userID ? userData.userID.userID : null,
|
|||
|
name: userData.userID ? userData.userID.name : null,
|
|||
|
email: userData.userID ? userData.userID.email : null,
|
|||
|
comment: userData.userID ? userData.userID.comment : null,
|
|||
|
isPrimary: primaryUserData.user.userID.userID === userData.userID.userID
|
|||
|
};
|
|||
|
|
|||
|
result.primaryUserIndex = result.users[0].userData.isPrimary ? 0 : null;
|
|||
|
|
|||
|
return result
|
|||
|
}
|
|||
|
|
|||
|
var signatures = /*#__PURE__*/Object.freeze({
|
|||
|
__proto__: null,
|
|||
|
process: process
|
|||
|
});
|
|||
|
|
|||
|
exports.fetcher = fetcher__namespace;
|
|||
|
exports.Claim = Claim;
|
|||
|
exports.Persona = Persona;
|
|||
|
exports.Profile = Profile;
|
|||
|
exports.asp = asp;
|
|||
|
exports.claimDefinitions = index;
|
|||
|
exports.defaults = defaults$3;
|
|||
|
exports.enums = enums;
|
|||
|
exports.keys = keys;
|
|||
|
exports.proofs = proofs;
|
|||
|
exports.signatures = signatures;
|
|||
|
exports.utils = utils$9;
|
|||
|
exports.verifications = verifications;
|
|||
|
|
|||
|
return exports;
|
|||
|
|
|||
|
})({}, doipFetchers, openpgp);
|