UNPKG

llmverify

Version:

AI Output Verification Toolkit — Local-first LLM safety, hallucination detection, PII redaction, prompt injection defense, and runtime monitoring. Zero telemetry. OWASP LLM Top 10 aligned.

181 lines 21.6 kB
"use strict"; /** * JSON Validator Engine * * Validates JSON structure and optionally schema. * * @module engines/json-validator * @author Haiec * @license MIT */ Object.defineProperty(exports, "__esModule", { value: true }); exports.JSONValidatorEngine = void 0; class JSONValidatorEngine { constructor(_config) { this._config = _config; this.LIMITATIONS = [ 'Basic JSON structure validation', 'Simple schema validation (type checking only)', 'Does not validate semantic correctness', 'Limited repair capabilities' ]; this.METHODOLOGY = 'Parses JSON content and validates structure. Performs basic schema ' + 'validation if schema is provided. Attempts simple repairs for common issues.'; } async validate(content, schema) { let parsed = null; let valid = false; let repaired = false; let repairMethod; const issues = []; // Try to parse try { parsed = JSON.parse(content); valid = true; } catch (e) { // Try to repair const repairResult = this.attemptRepair(content); if (repairResult.success) { parsed = repairResult.parsed; valid = true; repaired = true; repairMethod = repairResult.method; issues.push(`Repaired: ${repairMethod}`); } else { issues.push(`Parse error: ${e.message}`); } } // Schema validation let schemaValid = true; const schemaErrors = []; if (valid && schema && parsed) { const schemaResult = this.validateSchema(parsed, schema); schemaValid = schemaResult.valid; schemaErrors.push(...schemaResult.errors); } // Structure analysis const structure = this.analyzeStructure(parsed); structure.issues.push(...issues); return { valid, parsed, schema, schemaValid, schemaErrors, repaired, repairMethod, structure, limitations: this.LIMITATIONS, methodology: this.METHODOLOGY }; } attemptRepair(content) { // Try common repairs const repairs = [ { name: 'trailing comma removal', fix: (s) => s.replace(/,\s*([\]}])/g, '$1') }, { name: 'single to double quotes', fix: (s) => s.replace(/'/g, '"') }, { name: 'unquoted keys', fix: (s) => s.replace(/(\{|,)\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*:/g, '$1"$2":') }, { name: 'extract JSON from text', fix: (s) => { const match = s.match(/\{[\s\S]*\}|\[[\s\S]*\]/); return match ? match[0] : s; } } ]; for (const repair of repairs) { try { const fixed = repair.fix(content); const parsed = JSON.parse(fixed); return { success: true, parsed, method: repair.name }; } catch { continue; } } return { success: false }; } validateSchema(data, schema) { const errors = []; if (typeof schema !== 'object' || schema === null) { return { valid: true, errors: [] }; } const schemaObj = schema; if (typeof data !== 'object' || data === null) { errors.push('Data is not an object'); return { valid: false, errors }; } const dataObj = data; // Simple type checking for (const [key, expectedType] of Object.entries(schemaObj)) { if (!(key in dataObj)) { errors.push(`Missing required field: ${key}`); continue; } const actualType = typeof dataObj[key]; if (expectedType === 'array') { if (!Array.isArray(dataObj[key])) { errors.push(`Field ${key}: expected array, got ${actualType}`); } } else if (actualType !== expectedType) { errors.push(`Field ${key}: expected ${expectedType}, got ${actualType}`); } } return { valid: errors.length === 0, errors }; } analyzeStructure(data) { if (data === null || data === undefined) { return { depth: 0, keyCount: 0, issues: ['No valid data to analyze'] }; } const depth = this.calculateDepth(data); const keyCount = this.countKeys(data); const issues = []; if (depth > 10) { issues.push('Deep nesting detected (>10 levels)'); } if (keyCount > 1000) { issues.push('Large object detected (>1000 keys)'); } return { depth, keyCount, issues }; } calculateDepth(data, current = 0) { if (typeof data !== 'object' || data === null) { return current; } if (Array.isArray(data)) { return Math.max(current, ...data.map(item => this.calculateDepth(item, current + 1))); } const values = Object.values(data); if (values.length === 0) return current; return Math.max(...values.map(v => this.calculateDepth(v, current + 1))); } countKeys(data) { if (typeof data !== 'object' || data === null) { return 0; } if (Array.isArray(data)) { return data.reduce((sum, item) => sum + this.countKeys(item), 0); } const obj = data; let count = Object.keys(obj).length; for (const value of Object.values(obj)) { count += this.countKeys(value); } return count; } } exports.JSONValidatorEngine = JSONValidatorEngine; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZW5naW5lcy9qc29uLXZhbGlkYXRvci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7OztBQUtILE1BQWEsbUJBQW1CO0lBWTlCLFlBQW9CLE9BQWU7UUFBZixZQUFPLEdBQVAsT0FBTyxDQUFRO1FBWGxCLGdCQUFXLEdBQUc7WUFDN0IsaUNBQWlDO1lBQ2pDLCtDQUErQztZQUMvQyx3Q0FBd0M7WUFDeEMsNkJBQTZCO1NBQzlCLENBQUM7UUFFZSxnQkFBVyxHQUMxQixxRUFBcUU7WUFDckUsOEVBQThFLENBQUM7SUFFM0MsQ0FBQztJQUV2QyxLQUFLLENBQUMsUUFBUSxDQUFDLE9BQWUsRUFBRSxNQUFnQjtRQUM5QyxJQUFJLE1BQU0sR0FBWSxJQUFJLENBQUM7UUFDM0IsSUFBSSxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ2xCLElBQUksUUFBUSxHQUFHLEtBQUssQ0FBQztRQUNyQixJQUFJLFlBQWdDLENBQUM7UUFDckMsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO1FBRTVCLGVBQWU7UUFDZixJQUFJLENBQUM7WUFDSCxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM3QixLQUFLLEdBQUcsSUFBSSxDQUFDO1FBQ2YsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxnQkFBZ0I7WUFDaEIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNqRCxJQUFJLFlBQVksQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDekIsTUFBTSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUM7Z0JBQzdCLEtBQUssR0FBRyxJQUFJLENBQUM7Z0JBQ2IsUUFBUSxHQUFHLElBQUksQ0FBQztnQkFDaEIsWUFBWSxHQUFHLFlBQVksQ0FBQyxNQUFNLENBQUM7Z0JB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QUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7Q0FDRjtBQXJNRCxrREFxTUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEpTT04gVmFsaWRhdG9yIEVuZ2luZVxuICogXG4gKiBWYWxpZGF0ZXMgSlNPTiBzdHJ1Y3R1cmUgYW5kIG9wdGlvbmFsbHkgc2NoZW1hLlxuICogXG4gKiBAbW9kdWxlIGVuZ2luZXMvanNvbi12YWxpZGF0b3JcbiAqIEBhdXRob3IgSGFpZWNcbiAqIEBsaWNlbnNlIE1JVFxuICovXG5cbmltcG9ydCB7IENvbmZpZyB9IGZyb20gJy4uLy4uL3R5cGVzL2NvbmZpZyc7XG5pbXBvcnQgeyBKU09OUmVzdWx0IH0gZnJvbSAnLi4vLi4vdHlwZXMvcmVzdWx0cyc7XG5cbmV4cG9ydCBjbGFzcyBKU09OVmFsaWRhdG9yRW5naW5lIHtcbiAgcHJpdmF0ZSByZWFkb25seSBMSU1JVEFUSU9OUyA9IFtcbiAgICAnQmFzaWMgSlNPTiBzdHJ1Y3R1cmUgdmFsaWRhdGlvbicsXG4gICAgJ1NpbXBsZSBzY2hlbWEgdmFsaWRhdGlvbiAodHlwZSBjaGVja2luZyBvbmx5KScsXG4gICAgJ0RvZXMgbm90IHZhbGlkYXRlIHNlbWFudGljIGNvcnJlY3RuZXNzJyxcbiAgICAnTGltaXRlZCByZXBhaXIgY2FwYWJpbGl0aWVzJ1xuICBdO1xuICBcbiAgcHJpdmF0ZSByZWFkb25seSBNRVRIT0RPTE9HWSA9IFxuICAgICdQYXJzZXMgSlNPTiBjb250ZW50IGFuZCB2YWxpZGF0ZXMgc3RydWN0dXJlLiBQZXJmb3JtcyBiYXNpYyBzY2hlbWEgJyArXG4gICAgJ3ZhbGlkYXRpb24gaWYgc2NoZW1hIGlzIHByb3ZpZGVkLiBBdHRlbXB0cyBzaW1wbGUgcmVwYWlycyBmb3IgY29tbW9uIGlzc3Vlcy4nO1xuICBcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBfY29uZmlnOiBDb25maWcpIHt9XG4gIFxuICBhc3luYyB2YWxpZGF0ZShjb250ZW50OiBzdHJpbmcsIHNjaGVtYT86IHVua25vd24pOiBQcm9taXNlPEpTT05SZXN1bHQ+IHtcbiAgICBsZXQgcGFyc2VkOiB1bmtub3duID0gbnVsbDtcbiAgICBsZXQgdmFsaWQgPSBmYWxzZTtcbiAgICBsZXQgcmVwYWlyZWQgPSBmYWxzZTtcbiAgICBsZXQgcmVwYWlyTWV0aG9kOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgY29uc3QgaXNzdWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIC8vIFRyeSB0byBwYXJzZVxuICAgIHRyeSB7XG4gICAgICBwYXJzZWQgPSBKU09OLnBhcnNlKGNvbnRlbnQpO1xuICAgICAgdmFsaWQgPSB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIC8vIFRyeSB0byByZXBhaXJcbiAgICAgIGNvbnN0IHJlcGFpclJlc3VsdCA9IHRoaXMuYXR0ZW1wdFJlcGFpcihjb250ZW50KTtcbiAgICAgIGlmIChyZXBhaXJSZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICBwYXJzZWQgPSByZXBhaXJSZXN1bHQucGFyc2VkO1xuICAgICAgICB2YWxpZCA9IHRydWU7XG4gICAgICAgIHJlcGFpcmVkID0gdHJ1ZTtcbiAgICAgICAgcmVwYWlyTWV0aG9kID0gcmVwYWlyUmVzdWx0Lm1ldGhvZDtcbiAgICAgICAgaXNzdWVzLnB1c2goYFJlcGFpcmVkOiAke3JlcGFpck1ldGhvZH1gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlzc3Vlcy5wdXNoKGBQYXJzZSBlcnJvcjogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gU2NoZW1hIHZhbGlkYXRpb25cbiAgICBsZXQgc2NoZW1hVmFsaWQgPSB0cnVlO1xuICAgIGNvbnN0IHNjaGVtYUVycm9yczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICBpZiAodmFsaWQgJiYgc2NoZW1hICYmIHBhcnNlZCkge1xuICAgICAgY29uc3Qgc2NoZW1hUmVzdWx0ID0gdGhpcy52YWxpZGF0ZVNjaGVtYShwYXJzZWQsIHNjaGVtYSk7XG4gICAgICBzY2hlbWFWYWxpZCA9IHNjaGVtYVJlc3VsdC52YWxpZDtcbiAgICAgIHNjaGVtYUVycm9ycy5wdXNoKC4uLnNjaGVtYVJlc3VsdC5lcnJvcnMpO1xuICAgIH1cbiAgICBcbiAgICAvLyBTdHJ1Y3R1cmUgYW5hbHlzaXNcbiAgICBjb25zdCBzdHJ1Y3R1cmUgPSB0aGlzLmFuYWx5emVTdHJ1Y3R1cmUocGFyc2VkKTtcbiAgICBzdHJ1Y3R1cmUuaXNzdWVzLnB1c2goLi4uaXNzdWVzKTtcbiAgICBcbiAgICByZXR1cm4ge1xuICAgICAgdmFsaWQsXG4gICAgICBwYXJzZWQsXG4gICAgICBzY2hlbWEsXG4gICAgICBzY2hlbWFWYWxpZCxcbiAgICAgIHNjaGVtYUVycm9ycyxcbiAgICAgIHJlcGFpcmVkLFxuICAgICAgcmVwYWlyTWV0aG9kLFxuICAgICAgc3RydWN0dXJlLFxuICAgICAgbGltaXRhdGlvbnM6IHRoaXMuTElNSVRBVElPTlMsXG4gICAgICBtZXRob2RvbG9neTogdGhpcy5NRVRIT0RPTE9HWVxuICAgIH07XG4gIH1cbiAgXG4gIHByaXZhdGUgYXR0ZW1wdFJlcGFpcihjb250ZW50OiBzdHJpbmcpOiB7IHN1Y2Nlc3M6IGJvb2xlYW47IHBhcnNlZD86IHVua25vd247IG1ldGhvZD86IHN0cmluZyB9IHtcbiAgICAvLyBUcnkgY29tbW9uIHJlcGFpcnNcbiAgICBjb25zdCByZXBhaXJzID0gW1xuICAgICAge1xuICAgICAgICBuYW1lOiAndHJhaWxpbmcgY29tbWEgcmVtb3ZhbCcsXG4gICAgICAgIGZpeDogKHM6IHN0cmluZykgPT4gcy5yZXBsYWNlKC8sXFxzKihbXFxdfV0pL2csICckMScpXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBuYW1lOiAnc2luZ2xlIHRvIGRvdWJsZSBxdW90ZXMnLFxuICAgICAgICBmaXg6IChzOiBzdHJpbmcpID0+IHMucmVwbGFjZSgvJy9nLCAnXCInKVxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgbmFtZTogJ3VucXVvdGVkIGtleXMnLFxuICAgICAgICBmaXg6IChzOiBzdHJpbmcpID0+IHMucmVwbGFjZSgvKFxce3wsKVxccyooW2EtekEtWl9dW2EtekEtWjAtOV9dKilcXHMqOi9nLCAnJDFcIiQyXCI6JylcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIG5hbWU6ICdleHRyYWN0IEpTT04gZnJvbSB0ZXh0JyxcbiAgICAgICAgZml4OiAoczogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgY29uc3QgbWF0Y2ggPSBzLm1hdGNoKC9cXHtbXFxzXFxTXSpcXH18XFxbW1xcc1xcU10qXFxdLyk7XG4gICAgICAgICAgcmV0dXJuIG1hdGNoID8gbWF0Y2hbMF0gOiBzO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgXTtcbiAgICBcbiAgICBmb3IgKGNvbnN0IHJlcGFpciBvZiByZXBhaXJzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBmaXhlZCA9IHJlcGFpci5maXgoY29udGVudCk7XG4gICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoZml4ZWQpO1xuICAgICAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlLCBwYXJzZWQsIG1ldGhvZDogcmVwYWlyLm5hbWUgfTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UgfTtcbiAgfVxuICBcbiAgcHJpdmF0ZSB2YWxpZGF0ZVNjaGVtYShcbiAgICBkYXRhOiB1bmtub3duLCBcbiAgICBzY2hlbWE6IHVua25vd25cbiAgKTogeyB2YWxpZDogYm9vbGVhbjsgZXJyb3JzOiBzdHJpbmdbXSB9IHtcbiAgICBjb25zdCBlcnJvcnM6IHN0cmluZ1tdID0gW107XG4gICAgXG4gICAgaWYgKHR5cGVvZiBzY2hlbWEgIT09ICdvYmplY3QnIHx8IHNjaGVtYSA9PT0gbnVsbCkge1xuICAgICAgcmV0dXJuIHsgdmFsaWQ6IHRydWUsIGVycm9yczogW10gfTtcbiAgICB9XG4gICAgXG4gICAgY29uc3Qgc2NoZW1hT2JqID0gc2NoZW1hIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIFxuICAgIGlmICh0eXBlb2YgZGF0YSAhPT0gJ29iamVjdCcgfHwgZGF0YSA9PT0gbnVsbCkge1xuICAgICAgZXJyb3JzLnB1c2goJ0RhdGEgaXMgbm90IGFuIG9iamVjdCcpO1xuICAgICAgcmV0dXJuIHsgdmFsaWQ6IGZhbHNlLCBlcnJvcnMgfTtcbiAgICB9XG4gICAgXG4gICAgY29uc3QgZGF0YU9iaiA9IGRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgXG4gICAgLy8gU2ltcGxlIHR5cGUgY2hlY2tpbmdcbiAgICBmb3IgKGNvbnN0IFtrZXksIGV4cGVjdGVkVHlwZV0gb2YgT2JqZWN0LmVudHJpZXMoc2NoZW1hT2JqKSkge1xuICAgICAgaWYgKCEoa2V5IGluIGRhdGFPYmopKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBNaXNzaW5nIHJlcXVpcmVkIGZpZWxkOiAke2tleX1gKTtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBcbiAgICAgIGNvbnN0IGFjdHVhbFR5cGUgPSB0eXBlb2YgZGF0YU9ialtrZXldO1xuICAgICAgXG4gICAgICBpZiAoZXhwZWN0ZWRUeXBlID09PSAnYXJyYXknKSB7XG4gICAgICAgIGlmICghQXJyYXkuaXNBcnJheShkYXRhT2JqW2tleV0pKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goYEZpZWxkICR7a2V5fTogZXhwZWN0ZWQgYXJyYXksIGdvdCAke2FjdHVhbFR5cGV9YCk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoYWN0dWFsVHlwZSAhPT0gZXhwZWN0ZWRUeXBlKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGBGaWVsZCAke2tleX06IGV4cGVjdGVkICR7ZXhwZWN0ZWRUeXBlfSwgZ290ICR7YWN0dWFsVHlwZX1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHsgdmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsIGVycm9ycyB9O1xuICB9XG4gIFxuICBwcml2YXRlIGFuYWx5emVTdHJ1Y3R1cmUoZGF0YTogdW5rbm93bik6IHsgZGVwdGg6IG51bWJlcjsga2V5Q291bnQ6IG51bWJlcjsgaXNzdWVzOiBzdHJpbmdbXSB9IHtcbiAgICBpZiAoZGF0YSA9PT0gbnVsbCB8fCBkYXRhID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB7IGRlcHRoOiAwLCBrZXlDb3VudDogMCwgaXNzdWVzOiBbJ05vIHZhbGlkIGRhdGEgdG8gYW5hbHl6ZSddIH07XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IGRlcHRoID0gdGhpcy5jYWxjdWxhdGVEZXB0aChkYXRhKTtcbiAgICBjb25zdCBrZXlDb3VudCA9IHRoaXMuY291bnRLZXlzKGRhdGEpO1xuICAgIGNvbnN0IGlzc3Vlczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICBpZiAoZGVwdGggPiAxMCkge1xuICAgICAgaXNzdWVzLnB1c2goJ0RlZXAgbmVzdGluZyBkZXRlY3RlZCAoPjEwIGxldmVscyknKTtcbiAgICB9XG4gICAgXG4gICAgaWYgKGtleUNvdW50ID4gMTAwMCkge1xuICAgICAgaXNzdWVzLnB1c2goJ0xhcmdlIG9iamVjdCBkZXRlY3RlZCAoPjEwMDAga2V5cyknKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIHsgZGVwdGgsIGtleUNvdW50LCBpc3N1ZXMgfTtcbiAgfVxuICBcbiAgcHJpdmF0ZSBjYWxjdWxhdGVEZXB0aChkYXRhOiB1bmtub3duLCBjdXJyZW50ID0gMCk6IG51bWJlciB7XG4gICAgaWYgKHR5cGVvZiBkYXRhICE9PSAnb2JqZWN0JyB8fCBkYXRhID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gY3VycmVudDtcbiAgICB9XG4gICAgXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIHJldHVybiBNYXRoLm1heChjdXJyZW50LCAuLi5kYXRhLm1hcChpdGVtID0+IHRoaXMuY2FsY3VsYXRlRGVwdGgoaXRlbSwgY3VycmVudCArIDEpKSk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IHZhbHVlcyA9IE9iamVjdC52YWx1ZXMoZGF0YSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPik7XG4gICAgaWYgKHZhbHVlcy5sZW5ndGggPT09IDApIHJldHVybiBjdXJyZW50O1xuICAgIFxuICAgIHJldHVybiBNYXRoLm1heCguLi52YWx1ZXMubWFwKHYgPT4gdGhpcy5jYWxjdWxhdGVEZXB0aCh2LCBjdXJyZW50ICsgMSkpKTtcbiAgfVxuICBcbiAgcHJpdmF0ZSBjb3VudEtleXMoZGF0YTogdW5rbm93bik6IG51bWJlciB7XG4gICAgaWYgKHR5cGVvZiBkYXRhICE9PSAnb2JqZWN0JyB8fCBkYXRhID09PSBudWxsKSB7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoZGF0YSkpIHtcbiAgICAgIHJldHVybiBkYXRhLnJlZHVjZSgoc3VtLCBpdGVtKSA9PiBzdW0gKyB0aGlzLmNvdW50S2V5cyhpdGVtKSwgMCk7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IG9iaiA9IGRhdGEgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgbGV0IGNvdW50ID0gT2JqZWN0LmtleXMob2JqKS5sZW5ndGg7XG4gICAgXG4gICAgZm9yIChjb25zdCB2YWx1ZSBvZiBPYmplY3QudmFsdWVzKG9iaikpIHtcbiAgICAgIGNvdW50ICs9IHRoaXMuY291bnRLZXlzKHZhbHVlKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGNvdW50O1xuICB9XG59XG4iXX0=