@universis/common
Version:
Universis - common directives and services
179 lines (178 loc) • 21 kB
JavaScript
import { Injectable } from '@angular/core';
import { Args } from '@themost/client';
import { X509 } from 'jsrsasign';
import * as i0 from "@angular/core";
export class CertificateService {
constructor() { }
/**
*
* It returns a X509 certificate from the raw certificate sting
*
* @param {string} certificate The raw user certificate
*
* @returns {X509} The certificate object in x509 format
*
*/
getX509Certificate(certificate) {
const formatted = this.formatCertificate(certificate);
const x509 = new X509();
x509.readCertPEM(formatted);
return x509;
}
/**
*
* Parses a certificate from a continuous string of chars in a PEM formatted
* certificate
*
* @param {string} certificate The x509 certificate in raw format
*
* @returns {X509} The certificate object in x509 format
*
*/
formatCertificate(certificate) {
Args.notNull(certificate, 'Certificate must be defined');
Args.notEmpty(certificate, 'Certificate can not be empty');
const certHead = `-----BEGIN CERTIFICATE-----`;
const certTail = `-----END CERTIFICATE-----`;
const splittedCert = this.splitStringToChunks(certificate, 64);
const parts = [certHead, ...splittedCert, certTail];
return parts.join('\n');
}
/**
*
* Splits a string of text in an array of same length characters
*
* @param {string} payload The string to be split
* @param {number} lineLength The number of characters in line
*
* @returns {Array<string>} The split string parts
*
*/
splitStringToChunks(payload, lineLength) {
Args.notNull(payload, 'Certificate must be defined');
Args.notEmpty(payload, 'Certificate can not be empty');
if (!lineLength || lineLength <= 0) {
throw new Error('Line length can not be negative or zero');
}
let index = 0;
let remainingChars = payload.length;
let maximumIteration = payload.length + 1;
const parts = [];
// split the certificate in 64-character length lines
while (remainingChars > 0) {
if (index > maximumIteration) {
throw new Error('Maximum number of iterations exceeded');
}
parts.push(payload.substring(index * lineLength, (index + 1) * lineLength));
remainingChars = payload.length - (index + 1) * lineLength;
index++;
}
return parts;
}
/**
*
* Parses a jsrsasign to a Date object
*
* @param {string} date The date as is returned form jsrsasign library in UTC 0
*
* @returns {Date} The parsed date
*/
parseCertificateDate(date) {
const parts = date.match(/.{1,2}/g); //split the date to 2-char wide parts
const yearPrefix = new Date().getFullYear().toString().substring(0, 2); // The current millennium
parts[0] = yearPrefix + parts[0];
// construct a js-friendly date string
const asString = `${parts[0]}-${parts[1]}-${parts[2]} ${parts[3]}:${parts[4]}:${parts[5]}.000Z`;
return new Date(asString);
}
/**
* Gets certificate extensions attributes
*
*/
static getCertificateParams(certificate) {
const extension = certificate.parseExt();
if (extension !== -1 && Array.isArray(certificate.aExtInfo)) {
return certificate.getExtParamArray();
}
return [];
}
/**
* Extracts key usages from the certificate:
* It parses X509 v3 key and extended key usages
* and returns an array with the purposes.
* @param {X509} certificate
*/
extractPurposes(certificate) {
const params = CertificateService.getCertificateParams(certificate);
if ((params.filter(x => x.extname === 'extKeyUsage')).length > 0) {
const commonOIDs = CertificateService.mapOIDToString();
let purposes = certificate.getExtExtKeyUsage();
if (purposes && purposes.array) {
purposes = purposes.array;
}
let keyUsage = params.filter(x => x.extname === 'keyUsage');
purposes = [...purposes, ...keyUsage[0].names];
purposes = purposes.map(purpose => {
if (commonOIDs.has(purpose)) {
purpose = commonOIDs.get(purpose);
}
return purpose;
});
return Array.from(new Set(purposes));
}
}
/**
* Creates a map of common keyUsage OIDs
* to their name
* @return {Map<string,string>}
*/
static mapOIDToString() {
const commonOIDs = new Map();
// Any OID starting with 1.3.6.1.5.5.7.3 is
// directly defined in x509 v3 req key purposes
commonOIDs.set("1.3.6.1.5.5.7.3.1", "serverAuth");
commonOIDs.set("1.3.6.1.5.5.7.3.2", "clientAuth");
commonOIDs.set("1.3.6.1.5.5.7.3.3", "codeSigning");
commonOIDs.set("1.3.6.1.5.5.7.3.4", "emailProtection");
commonOIDs.set("1.3.6.1.5.5.7.3.8", "timestamping");
// Any OID starting with 1.3.6.1.4.1.311
// is provided by Microsoft
commonOIDs.set("1.3.6.1.4.1.311.20.2.2", "smartCardLogon");
commonOIDs.set("1.3.6.1.4.1.311.10.3.12", "documentSign");
commonOIDs.set("1.3.6.1.4.1.311.80.1", "documentEnc");
commonOIDs.set("2.5.29.37.0", "any");
return commonOIDs;
}
/**
* Extract the owner of the certificate:
* In an X509 certificate the subject contains
* information on the user and the common name
* is the name of the user that the certificate
* was issued to by the certificate authority.
* @param {X509} certificate
*/
extractCertificateOwner(certificate) {
const subjectCN = (certificate.getSubjectString())
.split('/')
.filter(x => x.includes('CN'))
.join(',')
.split('=')[1];
let fullName = subjectCN.split(" ");
if (fullName.length === 1) {
fullName = [...fullName, ""];
}
return {
givenName: fullName[0],
familyName: fullName[1]
};
}
}
CertificateService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
CertificateService.ctorParameters = () => [];
CertificateService.ngInjectableDef = i0.defineInjectable({ factory: function CertificateService_Factory() { return new CertificateService(); }, token: CertificateService, providedIn: "root" });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2VydGlmaWNhdGUtc2VydmljZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6Im5nOi8vQHVuaXZlcnNpcy9jb21tb24vIiwic291cmNlcyI6WyJzaGFyZWQvc2VydmljZXMvY2VydGlmaWNhdGUtc2VydmljZS9jZXJ0aWZpY2F0ZS1zZXJ2aWNlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDdkMsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQzs7QUFLakMsTUFBTTtJQUVKLGdCQUFnQixDQUFDO0lBRWpCOzs7Ozs7OztPQVFHO0lBQ0gsa0JBQWtCLENBQUMsV0FBVztRQUM1QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDdEQsTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzVCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILGlCQUFpQixDQUFDLFdBQW1CO1FBQ25DLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLDZCQUE2QixDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsOEJBQThCLENBQUMsQ0FBQztRQUUzRCxNQUFNLFFBQVEsR0FBRyw2QkFBNkIsQ0FBQztRQUMvQyxNQUFNLFFBQVEsR0FBRywyQkFBMkIsQ0FBQztRQUM3QyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsbUJBQW1CLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELE1BQU0sS0FBSyxHQUFHLENBQUMsUUFBUSxFQUFFLEdBQUcsWUFBWSxFQUFHLFFBQVEsQ0FB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Q0FBQztTQUN4QixDQUFBO0lBQ0gsQ0FBQzs7O1lBdExGLFVBQVUsU0FBQztnQkFDVixVQUFVLEVBQUUsTUFBTTthQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFyZ3MgfSBmcm9tICdAdGhlbW9zdC9jbGllbnQnO1xuaW1wb3J0IHsgWDUwOSB9IGZyb20gJ2pzcnNhc2lnbic7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIENlcnRpZmljYXRlU2VydmljZSB7XG5cbiAgY29uc3RydWN0b3IoKSB7IH1cblxuICAvKipcbiAgICpcbiAgICogSXQgcmV0dXJucyBhIFg1MDkgY2VydGlmaWNhdGUgZnJvbSB0aGUgcmF3IGNlcnRpZmljYXRlIHN0aW5nXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjZXJ0aWZpY2F0ZSBUaGUgcmF3IHVzZXIgY2VydGlmaWNhdGVcbiAgICpcbiAgICogQHJldHVybnMge1g1MDl9IFRoZSBjZXJ0aWZpY2F0ZSBvYmplY3QgaW4geDUwOSBmb3JtYXRcbiAgICpcbiAgICovXG4gIGdldFg1MDlDZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZSkge1xuICAgIGNvbnN0IGZvcm1hdHRlZCA9IHRoaXMuZm9ybWF0Q2VydGlmaWNhdGUoY2VydGlmaWNhdGUpO1xuICAgIGNvbnN0IHg1MDkgPSBuZXcgWDUwOSgpO1xuICAgIHg1MDkucmVhZENlcnRQRU0oZm9ybWF0dGVkKTtcbiAgICByZXR1cm4geDUwOTtcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBQYXJzZXMgYSBjZXJ0aWZpY2F0ZSBmcm9tIGEgY29udGludW91cyBzdHJpbmcgb2YgY2hhcnMgaW4gYSBQRU0gZm9ybWF0dGVkXG4gICAqIGNlcnRpZmljYXRlXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjZXJ0aWZpY2F0ZSBUaGUgeDUwOSBjZXJ0aWZpY2F0ZSBpbiByYXcgZm9ybWF0XG4gICAqXG4gICAqIEByZXR1cm5zIHtYNTA5fSBUaGUgY2VydGlmaWNhdGUgb2JqZWN0IGluIHg1MDkgZm9ybWF0XG4gICAqXG4gICAqL1xuICBmb3JtYXRDZXJ0aWZpY2F0ZShjZXJ0aWZpY2F0ZTogc3RyaW5nKTogWDUwOSB7XG4gICAgQXJncy5ub3ROdWxsKGNlcnRpZmljYXRlLCAnQ2VydGlmaWNhdGUgbXVzdCBiZSBkZWZpbmVkJyk7XG4gICAgQXJncy5ub3RFbXB0eShjZXJ0aWZpY2F0ZSwgJ0NlcnRpZmljYXRlIGNhbiBub3QgYmUgZW1wdHknKTtcblxuICAgIGNvbnN0IGNlcnRIZWFkID0gYC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLWA7XG4gICAgY29uc3QgY2VydFRhaWwgPSBgLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLWA7XG4gICAgY29uc3Qgc3BsaXR0ZWRDZXJ0ID0gdGhpcy5zcGxpdFN0cmluZ1RvQ2h1bmtzKGNlcnRpZmljYXRlLCA2NCk7XG4gICAgY29uc3QgcGFydHMgPSBbY2VydEhlYWQsIC4uLnNwbGl0dGVkQ2VydCwgIGNlcnRUYWlsXTtcbiAgICByZXR1cm4gcGFydHMuam9pbignXFxuJyk7XG4gIH1cblxuICAvKipcbiAgICpcbiAgICogU3BsaXRzIGEgc3RyaW5nIG9mIHRleHQgaW4gYW4gYXJyYXkgb2Ygc2FtZSBsZW5ndGggY2hhcmFjdGVyc1xuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcGF5bG9hZCBUaGUgc3RyaW5nIHRvIGJlIHNwbGl0XG4gICAqIEBwYXJhbSB7bnVtYmVyfSBsaW5lTGVuZ3RoIFRoZSBudW1iZXIgIG9mIGNoYXJhY3RlcnMgaW4gbGluZVxuICAgKlxuICAgKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gVGhlIHNwbGl0IHN0cmluZyBwYXJ0c1xuICAgKlxuICAgKi9cbiAgc3BsaXRTdHJpbmdUb0NodW5rcyhwYXlsb2FkOiBzdHJpbmcsIGxpbmVMZW5ndGg6IG51bWJlcik6IHN0cmluZ1tdIHtcbiAgICBBcmdzLm5vdE51bGwocGF5bG9hZCwgJ0NlcnRpZmljYXRlIG11c3QgYmUgZGVmaW5lZCcpO1xuICAgIEFyZ3Mubm90RW1wdHkocGF5bG9hZCwgJ0NlcnRpZmljYXRlIGNhbiBub3QgYmUgZW1wdHknKTtcbiAgICBpZiAoIWxpbmVMZW5ndGggfHwgbGluZUxlbmd0aCA8PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0xpbmUgbGVuZ3RoIGNhbiBub3QgYmUgbmVnYXRpdmUgb3IgemVybycpO1xuICAgIH1cblxuICAgIGxldCBpbmRleCA9IDA7XG4gICAgbGV0IHJlbWFpbmluZ0NoYXJzID0gcGF5bG9hZC5sZW5ndGg7XG4gICAgbGV0IG1heGltdW1JdGVyYXRpb24gPSBwYXlsb2FkLmxlbmd0aCArIDE7XG5cbiAgICBjb25zdCBwYXJ0czogc3RyaW5nW10gPSBbXTtcbiAgICAvLyBzcGxpdCB0aGUgY2VydGlmaWNhdGUgaW4gNjQtY2hhcmFjdGVyIGxlbmd0aCBsaW5lc1xuICAgIHdoaWxlKHJlbWFpbmluZ0NoYXJzID4gMCkge1xuXG4gICAgICBpZiAoaW5kZXggPiBtYXhpbXVtSXRlcmF0aW9uKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTWF4aW11bSBudW1iZXIgb2YgIGl0ZXJhdGlvbnMgZXhjZWVkZWQnKTtcbiAgICAgIH1cblxuICAgICAgcGFydHMucHVzaChwYXlsb2FkLnN1YnN0cmluZyhpbmRleCpsaW5lTGVuZ3RoLCAoaW5kZXgrMSkqbGluZUxlbmd0aCkpO1xuICAgICAgcmVtYWluaW5nQ2hhcnMgPSBwYXlsb2FkLmxlbmd0aCAtIChpbmRleCArIDEpICogbGluZUxlbmd0aDtcbiAgICAgIGluZGV4Kys7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcnRzO1xuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIFBhcnNlcyBhIGpzcnNhc2lnbiB0byBhIERhdGUgb2JqZWN0XG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBkYXRlIFRoZSBkYXRlIGFzIGlzIHJldHVybmVkIGZvcm0ganNyc2FzaWduIGxpYnJhcnkgaW4gVVRDIDBcbiAgICpcbiAgICogQHJldHVybnMge0RhdGV9IFRoZSBwYXJzZWQgZGF0ZVxuICAgKi9cbiAgcGFyc2VDZXJ0aWZpY2F0ZURhdGUoZGF0ZTogc3RyaW5nKTogRGF0ZSB7XG4gICAgY29uc3QgcGFydHMgPSBkYXRlLm1hdGNoKC8uezEsMn0vZyk7IC8vc3BsaXQgdGhlIGRhdGUgdG8gMi1jaGFyIHdpZGUgcGFydHNcbiAgICBjb25zdCB5ZWFyUHJlZml4ID0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpLnRvU3RyaW5nKCkuc3Vic3RyaW5nKDAsMik7IC8vIFRoZSBjdXJyZW50IG1pbGxlbm5pdW1cbiAgICBwYXJ0c1swXSA9IHllYXJQcmVmaXggKyBwYXJ0c1swXTtcblxuICAgIC8vIGNvbnN0cnVjdCBhIGpzLWZyaWVuZGx5IGRhdGUgc3RyaW5nXG4gICAgY29uc3QgYXNTdHJpbmcgPSBgJHtwYXJ0c1swXX0tJHtwYXJ0c1sxXX0tJHtwYXJ0c1syXX0gJHtwYXJ0c1szXX06JHtwYXJ0c1s0XX06JHtwYXJ0c1s1XX0uMDAwWmA7XG4gICAgcmV0dXJuIG5ldyBEYXRlKGFzU3RyaW5nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXRzIGNlcnRpZmljYXRlIGV4dGVuc2lvbnMgYXR0cmlidXRlc1xuICAgKlxuICAgKi9cbiAgcHJpdmF0ZSBzdGF0aWMgZ2V0Q2VydGlmaWNhdGVQYXJhbXMoY2VydGlmaWNhdGU6IFg1MDkpOiBhbnlbXSB7XG4gICAgY29uc3QgZXh0ZW5zaW9uID0gY2VydGlmaWNhdGUucGFyc2VFeHQoKTtcbiAgICBpZihleHRlbnNpb24gIT09IC0xICYmIEFycmF5LmlzQXJyYXkoY2VydGlmaWNhdGUuYUV4dEluZm8pKXtcbiAgICAgIHJldHVybiBjZXJ0aWZpY2F0ZS5nZXRFeHRQYXJhbUFycmF5KCk7XG4gICAgfVxuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0cyBrZXkgdXNhZ2VzIGZyb20gdGhlIGNlcnRpZmljYXRlOlxuICAgKiBJdCBwYXJzZXMgWDUwOSB2MyBrZXkgYW5kIGV4dGVuZGVkIGtleSB1c2FnZXNcbiAgICogYW5kIHJldHVybnMgYW4gYXJyYXkgd2l0aCB0aGUgcHVycG9zZXMuXG4gICAqIEBwYXJhbSB7WDUwOX0gY2VydGlmaWNhdGVcbiAgICovXG4gIGV4dHJhY3RQdXJwb3NlcyhjZXJ0aWZpY2F0ZTpYNTA5KTogQXJyYXk8YW55PntcbiAgICBjb25zdCBwYXJhbXMgPSBDZXJ0aWZpY2F0ZVNlcnZpY2UuZ2V0Q2VydGlmaWNhdGVQYXJhbXMoY2VydGlmaWNhdGUpO1xuICAgIGlmICgocGFyYW1zLmZpbHRlcih4ID0+IHguZXh0bmFtZSA9PT0gJ2V4dEtleVVzYWdlJykpLmxlbmd0aCA+IDApe1xuICAgICAgY29uc3QgY29tbW9uT0lEcyA9IENlcnRpZmljYXRlU2VydmljZS5tYXBPSURUb1N0cmluZygpO1xuICAgICAgbGV0IHB1cnBvc2VzID1jZXJ0aWZpY2F0ZS5nZXRFeHRFeHRLZXlVc2FnZSgpO1xuICAgICAgaWYocHVycG9zZXMgJiYgcHVycG9zZXMuYXJyYXkpe1xuICAgICAgICBwdXJwb3Nlcz0gcHVycG9zZXMuYXJyYXk7XG4gICAgICB9XG4gICAgICBsZXQga2V5VXNhZ2UgPSBwYXJhbXMuZmlsdGVyKHggPT4geC5leHRuYW1lID09PSAna2V5VXNhZ2UnKTtcbiAgICAgIHB1cnBvc2VzID0gWy4uLnB1cnBvc2VzLCAgLi4ua2V5VXNhZ2VbMF0ubmFtZXNdO1xuICAgICAgcHVycG9zZXMgPSBwdXJwb3Nlcy5tYXAocHVycG9zZSA9PiB7XG4gICAgICAgIGlmKGNvbW1vbk9JRHMuaGFzKHB1cnBvc2UpKXtcbiAgICAgICAgICBwdXJwb3NlID0gY29tbW9uT0lEcy5nZXQocHVycG9zZSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHB1cnBvc2U7XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBBcnJheS5mcm9tKG5ldyBTZXQocHVycG9zZXMpKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIG1hcCBvZiBjb21tb24ga2V5VXNhZ2UgT0lEc1xuICAgKiB0byB0aGVpciBuYW1lXG4gICAqIEByZXR1cm4ge01hcDxzdHJpbmcsc3RyaW5nPn1cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIG1hcE9JRFRvU3RyaW5nKCl7XG4gICAgY29uc3QgY29tbW9uT0lEcyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgLy8gQW55IE9JRCBzdGFydGluZyB3aXRoIDEuMy42LjEuNS41LjcuMyBpc1xuICAgIC8vIGRpcmVjdGx5IGRlZmluZWQgaW4geDUwOSB2MyByZXEga2V5IHB1cnBvc2VzXG4gICAgY29tbW9uT0lEcy5zZXQoXCIxLjMuNi4xLjUuNS43LjMuMVwiLCBcInNlcnZlckF1dGhcIik7XG4gICAgY29tbW9uT0lEcy5zZXQoXCIxLjMuNi4xLjUuNS43LjMuMlwiLCBcImNsaWVudEF1dGhcIilcbiAgICBjb21tb25PSURzLnNldChcIjEuMy42LjEuNS41LjcuMy4zXCIsIFwiY29kZVNpZ25pbmdcIik7XG4gICAgY29tbW9uT0lEcy5zZXQoXCIxLjMuNi4xLjUuNS43LjMuNFwiLCBcImVtYWlsUHJvdGVjdGlvblwiKVxuICAgIGNvbW1vbk9JRHMuc2V0KFwiMS4zLjYuMS41LjUuNy4zLjhcIixcInRpbWVzdGFtcGluZ1wiKTtcbiAgICAvLyBBbnkgT0lEIHN0YXJ0aW5nIHdpdGggMS4zLjYuMS40LjEuMzExXG4gICAgLy8gaXMgcHJvdmlkZWQgYnkgTWljcm9zb2Z0XG4gICAgY29tbW9uT0lEcy5zZXQoXCIxLjMuNi4xLjQuMS4zMTEuMjAuMi4yXCIsIFwic21hcnRDYXJkTG9nb25cIik7XG4gICAgY29tbW9uT0lEcy5zZXQoXCIxLjMuNi4xLjQuMS4zMTEuMTAuMy4xMlwiLCBcImRvY3VtZW50U2lnblwiKTtcbiAgICBjb21tb25PSURzLnNldChcIjEuMy42LjEuNC4xLjMxMS44MC4xXCIsIFwiZG9jdW1lbnRFbmNcIik7XG4gICAgY29tbW9uT0lEcy5zZXQoXCIyLjUuMjkuMzcuMFwiLCBcImFueVwiKTtcbiAgICByZXR1cm4gY29tbW9uT0lEcztcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IHRoZSBvd25lciBvZiB0aGUgY2VydGlmaWNhdGU6XG4gICAqIEluIGFuIFg1MDkgY2VydGlmaWNhdGUgdGhlIHN1YmplY3QgY29udGFpbnNcbiAgICogaW5mb3JtYXRpb24gb24gdGhlIHVzZXIgYW5kIHRoZSBjb21tb24gbmFtZVxuICAgKiBpcyB0aGUgbmFtZSBvZiB0aGUgdXNlciB0aGF0IHRoZSBjZXJ0aWZpY2F0ZVxuICAgKiB3YXMgaXNzdWVkIHRvIGJ5IHRoZSBjZXJ0aWZpY2F0ZSBhdXRob3JpdHkuXG4gICAqIEBwYXJhbSB7WDUwOX0gY2VydGlmaWNhdGVcbiAgICovXG4gIGV4dHJhY3RDZXJ0aWZpY2F0ZU93bmVyKGNlcnRpZmljYXRlOiBYNTA5KSB7XG4gICAgY29uc3Qgc3ViamVjdENOID0gKGNlcnRpZmljYXRlLmdldFN1YmplY3RTdHJpbmcoKSlcbiAgICAgIC5zcGxpdCgnLycpXG4gICAgICAuZmlsdGVyKHggPT4geC5pbmNsdWRlcygnQ04nKSlcbiAgICAgIC5qb2luKCcsJylcbiAgICAgIC5zcGxpdCgnPScpWzFdO1xuICAgIGxldCBmdWxsTmFtZSA9IHN1YmplY3RDTi5zcGxpdChcIiBcIik7XG4gICAgaWYgKGZ1bGxOYW1lLmxlbmd0aCA9PT0gMSl7XG4gICAgICBmdWxsTmFtZSA9IFsuLi5mdWxsTmFtZSwgXCJcIl1cbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGdpdmVuTmFtZTogZnVsbE5hbWVbMF0sXG4gICAgICBmYW1pbHlOYW1lOiBmdWxsTmFtZVsxXVxuICAgIH1cbiAgfVxufVxuIl19