UNPKG

@universis/common

Version:

Universis - common directives and services

179 lines (178 loc) 21 kB
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