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.
182 lines • 20.6 kB
JavaScript
"use strict";
/**
* Plugin API
*
* High-level API for creating and using plugins
*
* @module plugins/api
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPlugin = createPlugin;
exports.use = use;
exports.createBlacklistPlugin = createBlacklistPlugin;
exports.createRegexPlugin = createRegexPlugin;
exports.createLengthValidatorPlugin = createLengthValidatorPlugin;
exports.createKeywordDetectorPlugin = createKeywordDetectorPlugin;
const registry_1 = require("./registry");
/**
* Helper function to create a plugin
*/
function createPlugin(config) {
return {
id: config.id,
name: config.name,
version: config.version || '1.0.0',
description: config.description,
author: config.author,
category: config.category || 'custom',
enabled: config.enabled !== false,
priority: config.priority || 0,
execute: config.execute
};
}
/**
* Use a plugin (register and enable)
*/
function use(plugin) {
const registry = (0, registry_1.getPluginRegistry)();
registry.register(plugin);
}
/**
* Create a blacklist plugin
*/
function createBlacklistPlugin(blacklist, options) {
return createPlugin({
id: options?.id || 'blacklist',
name: options?.name || 'Blacklist Filter',
description: 'Detects blacklisted words',
category: 'security',
execute: (context) => {
const findings = [];
const content = options?.caseSensitive ? context.content : context.content.toLowerCase();
for (const word of blacklist) {
const searchWord = options?.caseSensitive ? word : word.toLowerCase();
if (content.includes(searchWord)) {
findings.push({
category: 'security',
severity: 'medium',
message: `Blacklisted term detected: ${word}`
});
}
}
return {
findings,
score: findings.length > 0 ? 0.5 : 0
};
}
});
}
/**
* Create a regex pattern plugin
*/
function createRegexPlugin(patterns, options) {
return createPlugin({
id: options?.id || 'regex-patterns',
name: options?.name || 'Regex Patterns',
description: 'Detects custom regex patterns',
category: 'custom',
execute: (context) => {
const findings = [];
for (const { pattern, message, severity } of patterns) {
try {
const matches = context.content.match(pattern);
if (matches) {
findings.push({
category: 'custom',
severity: severity || 'medium',
message: message
});
}
}
catch (error) {
console.error('Regex pattern error:', error);
}
}
return {
findings,
score: findings.length > 0 ? 0.5 : 0
};
}
});
}
/**
* Create a length validator plugin
*/
function createLengthValidatorPlugin(config, options) {
return createPlugin({
id: options?.id || 'length-validator',
name: options?.name || 'Length Validator',
description: 'Validates content length',
category: 'quality',
execute: (context) => {
const findings = [];
const length = context.content.length;
if (config.min && length < config.min) {
findings.push({
category: 'quality',
severity: 'low',
message: `Content too short: ${length} < ${config.min}`,
metadata: { length, min: config.min }
});
}
if (config.max && length > config.max) {
findings.push({
category: 'quality',
severity: 'medium',
message: `Content too long: ${length} > ${config.max}`,
metadata: { length, max: config.max }
});
}
return {
findings,
score: findings.length > 0 ? 0.3 : 0
};
}
});
}
/**
* Create a keyword detector plugin
*/
function createKeywordDetectorPlugin(keywords, options) {
return createPlugin({
id: options?.id || 'keyword-detector',
name: options?.name || 'Keyword Detector',
description: 'Detects required and forbidden keywords',
category: 'quality',
execute: (context) => {
const findings = [];
const content = options?.caseSensitive ? context.content : context.content.toLowerCase();
// Check required keywords
if (keywords.required) {
for (const keyword of keywords.required) {
const searchKeyword = options?.caseSensitive ? keyword : keyword.toLowerCase();
if (!content.includes(searchKeyword)) {
findings.push({
category: 'quality',
severity: 'medium',
message: `Required keyword missing: ${keyword}`
});
}
}
}
// Check forbidden keywords
if (keywords.forbidden) {
for (const keyword of keywords.forbidden) {
const searchKeyword = options?.caseSensitive ? keyword : keyword.toLowerCase();
if (content.includes(searchKeyword)) {
findings.push({
category: 'security',
severity: 'high',
message: `Forbidden keyword detected: ${keyword}`
});
}
}
}
return {
findings,
score: findings.length > 0 ? 0.6 : 0
};
}
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbnMvYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7O0FBT0gsb0NBc0JDO0FBS0Qsa0JBR0M7QUFLRCxzREErQkM7QUFLRCw4Q0FxQ0M7QUFLRCxrRUF3Q0M7QUFLRCxrRUFtREM7QUF0TkQseUNBQXVFO0FBRXZFOztHQUVHO0FBQ0gsU0FBZ0IsWUFBWSxDQUFDLE1BVTVCO0lBQ0MsT0FBTztRQUNMLEVBQUUsRUFBRSxNQUFNLENBQUMsRUFBRTtRQUNiLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSTtRQUNqQixPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sSUFBSSxPQUFPO1FBQ2xDLFdBQVcsRUFBRSxNQUFNLENBQUMsV0FBVztRQUMvQixNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDckIsUUFBUSxFQUFFLE1BQU0sQ0FBQyxRQUFRLElBQUksUUFBUTtRQUNyQyxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sS0FBSyxLQUFLO1FBQ2pDLFFBQVEsRUFBRSxNQUFNLENBQUMsUUFBUSxJQUFJLENBQUM7UUFDOUIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPO0tBQ3hCLENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixHQUFHLENBQUMsTUFBYztJQUNoQyxNQUFNLFFBQVEsR0FBRyxJQUFBLDRCQUFpQixHQUFFLENBQUM7SUFDckMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUM1QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFnQixxQkFBcUIsQ0FBQyxTQUFtQixFQUFFLE9BSTFEO0lBQ0MsT0FBTyxZQUFZLENBQUM7UUFDbEIsRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUFFLElBQUksV0FBVztRQUM5QixJQUFJLEVBQUUsT0FBTyxFQUFFLElBQUksSUFBSSxrQkFBa0I7UUFDekMsV0FBVyxFQUFFLDJC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Q0FBQyxJQUFJLENBQUM7NEJBQ1osUUFBUSxFQUFFLFVBQVU7NEJBQ3BCLFFBQVEsRUFBRSxNQUFNOzRCQUNoQixPQUFPLEVBQUUsK0JBQStCLE9BQU8sRUFBRTt5QkFDbEQsQ0FBQyxDQUFDO29CQUNMLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxPQUFPO2dCQUNMLFFBQVE7Z0JBQ1IsS0FBSyxFQUFFLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDckMsQ0FBQztRQUNKLENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQbHVnaW4gQVBJXG4gKiBcbiAqIEhpZ2gtbGV2ZWwgQVBJIGZvciBjcmVhdGluZyBhbmQgdXNpbmcgcGx1Z2luc1xuICogXG4gKiBAbW9kdWxlIHBsdWdpbnMvYXBpXG4gKi9cblxuaW1wb3J0IHsgUGx1Z2luLCBQbHVnaW5GdW5jdGlvbiwgZ2V0UGx1Z2luUmVnaXN0cnkgfSBmcm9tICcuL3JlZ2lzdHJ5JztcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gY3JlYXRlIGEgcGx1Z2luXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQbHVnaW4oY29uZmlnOiB7XG4gIGlkOiBzdHJpbmc7XG4gIG5hbWU6IHN0cmluZztcbiAgdmVyc2lvbj86IHN0cmluZztcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIGF1dGhvcj86IHN0cmluZztcbiAgY2F0ZWdvcnk/OiBQbHVnaW5bJ2NhdGVnb3J5J107XG4gIGVuYWJsZWQ/OiBib29sZWFuO1xuICBwcmlvcml0eT86IG51bWJlcjtcbiAgZXhlY3V0ZTogUGx1Z2luRnVuY3Rpb247XG59KTogUGx1Z2luIHtcbiAgcmV0dXJuIHtcbiAgICBpZDogY29uZmlnLmlkLFxuICAgIG5hbWU6IGNvbmZpZy5uYW1lLFxuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uIHx8ICcxLjAuMCcsXG4gICAgZGVzY3JpcHRpb246IGNvbmZpZy5kZXNjcmlwdGlvbixcbiAgICBhdXRob3I6IGNvbmZpZy5hdXRob3IsXG4gICAgY2F0ZWdvcnk6IGNvbmZpZy5jYXRlZ29yeSB8fCAnY3VzdG9tJyxcbiAgICBlbmFibGVkOiBjb25maWcuZW5hYmxlZCAhPT0gZmFsc2UsXG4gICAgcHJpb3JpdHk6IGNvbmZpZy5wcmlvcml0eSB8fCAwLFxuICAgIGV4ZWN1dGU6IGNvbmZpZy5leGVjdXRlXG4gIH07XG59XG5cbi8qKlxuICogVXNlIGEgcGx1Z2luIChyZWdpc3RlciBhbmQgZW5hYmxlKVxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlKHBsdWdpbjogUGx1Z2luKTogdm9pZCB7XG4gIGNvbnN0IHJlZ2lzdHJ5ID0gZ2V0UGx1Z2luUmVnaXN0cnkoKTtcbiAgcmVnaXN0cnkucmVnaXN0ZXIocGx1Z2luKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBibGFja2xpc3QgcGx1Z2luXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVCbGFja2xpc3RQbHVnaW4oYmxhY2tsaXN0OiBzdHJpbmdbXSwgb3B0aW9ucz86IHtcbiAgaWQ/OiBzdHJpbmc7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIGNhc2VTZW5zaXRpdmU/OiBib29sZWFuO1xufSk6IFBsdWdpbiB7XG4gIHJldHVybiBjcmVhdGVQbHVnaW4oe1xuICAgIGlkOiBvcHRpb25zPy5pZCB8fCAnYmxhY2tsaXN0JyxcbiAgICBuYW1lOiBvcHRpb25zPy5uYW1lIHx8ICdCbGFja2xpc3QgRmlsdGVyJyxcbiAgICBkZXNjcmlwdGlvbjogJ0RldGVjdHMgYmxhY2tsaXN0ZWQgd29yZHMnLFxuICAgIGNhdGVnb3J5OiAnc2VjdXJpdHknLFxuICAgIGV4ZWN1dGU6IChjb250ZXh0KSA9PiB7XG4gICAgICBjb25zdCBmaW5kaW5nczogYW55W10gPSBbXTtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBvcHRpb25zPy5jYXNlU2Vuc2l0aXZlID8gY29udGV4dC5jb250ZW50IDogY29udGV4dC5jb250ZW50LnRvTG93ZXJDYXNlKCk7XG4gICAgICBcbiAgICAgIGZvciAoY29uc3Qgd29yZCBvZiBibGFja2xpc3QpIHtcbiAgICAgICAgY29uc3Qgc2VhcmNoV29yZCA9IG9wdGlvbnM/LmNhc2VTZW5zaXRpdmUgPyB3b3JkIDogd29yZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICBpZiAoY29udGVudC5pbmNsdWRlcyhzZWFyY2hXb3JkKSkge1xuICAgICAgICAgIGZpbmRpbmdzLnB1c2goe1xuICAgICAgICAgICAgY2F0ZWdvcnk6ICdzZWN1cml0eScsXG4gICAgICAgICAgICBzZXZlcml0eTogJ21lZGl1bScsXG4gICAgICAgICAgICBtZXNzYWdlOiBgQmxhY2tsaXN0ZWQgdGVybSBkZXRlY3RlZDogJHt3b3JkfWBcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaW5kaW5ncyxcbiAgICAgICAgc2NvcmU6IGZpbmRpbmdzLmxlbmd0aCA+IDAgPyAwLjUgOiAwXG4gICAgICB9O1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgcmVnZXggcGF0dGVybiBwbHVnaW5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJlZ2V4UGx1Z2luKHBhdHRlcm5zOiBBcnJheTx7XG4gIHBhdHRlcm46IFJlZ0V4cDtcbiAgbWVzc2FnZTogc3RyaW5nO1xuICBzZXZlcml0eT86IHN0cmluZztcbn0+LCBvcHRpb25zPzoge1xuICBpZD86IHN0cmluZztcbiAgbmFtZT86IHN0cmluZztcbn0pOiBQbHVnaW4ge1xuICByZXR1cm4gY3JlYXRlUGx1Z2luKHtcbiAgICBpZDogb3B0aW9ucz8uaWQgfHwgJ3JlZ2V4LXBhdHRlcm5zJyxcbiAgICBuYW1lOiBvcHRpb25zPy5uYW1lIHx8ICdSZWdleCBQYXR0ZXJucycsXG4gICAgZGVzY3JpcHRpb246ICdEZXRlY3RzIGN1c3RvbSByZWdleCBwYXR0ZXJucycsXG4gICAgY2F0ZWdvcnk6ICdjdXN0b20nLFxuICAgIGV4ZWN1dGU6IChjb250ZXh0KSA9PiB7XG4gICAgICBjb25zdCBmaW5kaW5nczogYW55W10gPSBbXTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCB7IHBhdHRlcm4sIG1lc3NhZ2UsIHNldmVyaXR5IH0gb2YgcGF0dGVybnMpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCBtYXRjaGVzID0gY29udGV4dC5jb250ZW50Lm1hdGNoKHBhdHRlcm4pO1xuICAgICAgICAgIGlmIChtYXRjaGVzKSB7XG4gICAgICAgICAgICBmaW5kaW5ncy5wdXNoKHtcbiAgICAgICAgICAgICAgY2F0ZWdvcnk6ICdjdXN0b20nLFxuICAgICAgICAgICAgICBzZXZlcml0eTogc2V2ZXJpdHkgfHwgJ21lZGl1bScsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IG1lc3NhZ2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKCdSZWdleCBwYXR0ZXJuIGVycm9yOicsIGVycm9yKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaW5kaW5ncyxcbiAgICAgICAgc2NvcmU6IGZpbmRpbmdzLmxlbmd0aCA+IDAgPyAwLjUgOiAwXG4gICAgICB9O1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgbGVuZ3RoIHZhbGlkYXRvciBwbHVnaW5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUxlbmd0aFZhbGlkYXRvclBsdWdpbihjb25maWc6IHtcbiAgbWluPzogbnVtYmVyO1xuICBtYXg/OiBudW1iZXI7XG59LCBvcHRpb25zPzoge1xuICBpZD86IHN0cmluZztcbiAgbmFtZT86IHN0cmluZztcbn0pOiBQbHVnaW4ge1xuICByZXR1cm4gY3JlYXRlUGx1Z2luKHtcbiAgICBpZDogb3B0aW9ucz8uaWQgfHwgJ2xlbmd0aC12YWxpZGF0b3InLFxuICAgIG5hbWU6IG9wdGlvbnM/Lm5hbWUgfHwgJ0xlbmd0aCBWYWxpZGF0b3InLFxuICAgIGRlc2NyaXB0aW9uOiAnVmFsaWRhdGVzIGNvbnRlbnQgbGVuZ3RoJyxcbiAgICBjYXRlZ29yeTogJ3F1YWxpdHknLFxuICAgIGV4ZWN1dGU6IChjb250ZXh0KSA9PiB7XG4gICAgICBjb25zdCBmaW5kaW5nczogYW55W10gPSBbXTtcbiAgICAgIGNvbnN0IGxlbmd0aCA9IGNvbnRleHQuY29udGVudC5sZW5ndGg7XG4gICAgICBcbiAgICAgIGlmIChjb25maWcubWluICYmIGxlbmd0aCA8IGNvbmZpZy5taW4pIHtcbiAgICAgICAgZmluZGluZ3MucHVzaCh7XG4gICAgICAgICAgY2F0ZWdvcnk6ICdxdWFsaXR5JyxcbiAgICAgICAgICBzZXZlcml0eTogJ2xvdycsXG4gICAgICAgICAgbWVzc2FnZTogYENvbnRlbnQgdG9vIHNob3J0OiAke2xlbmd0aH0gPCAke2NvbmZpZy5taW59YCxcbiAgICAgICAgICBtZXRhZGF0YTogeyBsZW5ndGgsIG1pbjogY29uZmlnLm1pbiB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgXG4gICAgICBpZiAoY29uZmlnLm1heCAmJiBsZW5ndGggPiBjb25maWcubWF4KSB7XG4gICAgICAgIGZpbmRpbmdzLnB1c2goe1xuICAgICAgICAgIGNhdGVnb3J5OiAncXVhbGl0eScsXG4gICAgICAgICAgc2V2ZXJpdHk6ICdtZWRpdW0nLFxuICAgICAgICAgIG1lc3NhZ2U6IGBDb250ZW50IHRvbyBsb25nOiAke2xlbmd0aH0gPiAke2NvbmZpZy5tYXh9YCxcbiAgICAgICAgICBtZXRhZGF0YTogeyBsZW5ndGgsIG1heDogY29uZmlnLm1heCB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgXG4gICAgICByZXR1cm4ge1xuICAgICAgICBmaW5kaW5ncyxcbiAgICAgICAgc2NvcmU6IGZpbmRpbmdzLmxlbmd0aCA+IDAgPyAwLjMgOiAwXG4gICAgICB9O1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGEga2V5d29yZCBkZXRlY3RvciBwbHVnaW5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUtleXdvcmREZXRlY3RvclBsdWdpbihrZXl3b3Jkczoge1xuICByZXF1aXJlZD86IHN0cmluZ1tdO1xuICBmb3JiaWRkZW4/OiBzdHJpbmdbXTtcbn0sIG9wdGlvbnM/OiB7XG4gIGlkPzogc3RyaW5nO1xuICBuYW1lPzogc3RyaW5nO1xuICBjYXNlU2Vuc2l0aXZlPzogYm9vbGVhbjtcbn0pOiBQbHVnaW4ge1xuICByZXR1cm4gY3JlYXRlUGx1Z2luKHtcbiAgICBpZDogb3B0aW9ucz8uaWQgfHwgJ2tleXdvcmQtZGV0ZWN0b3InLFxuICAgIG5hbWU6IG9wdGlvbnM/Lm5hbWUgfHwgJ0tleXdvcmQgRGV0ZWN0b3InLFxuICAgIGRlc2NyaXB0aW9uOiAnRGV0ZWN0cyByZXF1aXJlZCBhbmQgZm9yYmlkZGVuIGtleXdvcmRzJyxcbiAgICBjYXRlZ29yeTogJ3F1YWxpdHknLFxuICAgIGV4ZWN1dGU6IChjb250ZXh0KSA9PiB7XG4gICAgICBjb25zdCBmaW5kaW5nczogYW55W10gPSBbXTtcbiAgICAgIGNvbnN0IGNvbnRlbnQgPSBvcHRpb25zPy5jYXNlU2Vuc2l0aXZlID8gY29udGV4dC5jb250ZW50IDogY29udGV4dC5jb250ZW50LnRvTG93ZXJDYXNlKCk7XG4gICAgICBcbiAgICAgIC8vIENoZWNrIHJlcXVpcmVkIGtleXdvcmRzXG4gICAgICBpZiAoa2V5d29yZHMucmVxdWlyZWQpIHtcbiAgICAgICAgZm9yIChjb25zdCBrZXl3b3JkIG9mIGtleXdvcmRzLnJlcXVpcmVkKSB7XG4gICAgICAgICAgY29uc3Qgc2VhcmNoS2V5d29yZCA9IG9wdGlvbnM/LmNhc2VTZW5zaXRpdmUgPyBrZXl3b3JkIDoga2V5d29yZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgIGlmICghY29udGVudC5pbmNsdWRlcyhzZWFyY2hLZXl3b3JkKSkge1xuICAgICAgICAgICAgZmluZGluZ3MucHVzaCh7XG4gICAgICAgICAgICAgIGNhdGVnb3J5OiAncXVhbGl0eScsXG4gICAgICAgICAgICAgIHNldmVyaXR5OiAnbWVkaXVtJyxcbiAgICAgICAgICAgICAgbWVzc2FnZTogYFJlcXVpcmVkIGtleXdvcmQgbWlzc2luZzogJHtrZXl3b3JkfWBcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBDaGVjayBmb3JiaWRkZW4ga2V5d29yZHNcbiAgICAgIGlmIChrZXl3b3Jkcy5mb3JiaWRkZW4pIHtcbiAgICAgICAgZm9yIChjb25zdCBrZXl3b3JkIG9mIGtleXdvcmRzLmZvcmJpZGRlbikge1xuICAgICAgICAgIGNvbnN0IHNlYXJjaEtleXdvcmQgPSBvcHRpb25zPy5jYXNlU2Vuc2l0aXZlID8ga2V5d29yZCA6IGtleXdvcmQudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICBpZiAoY29udGVudC5pbmNsdWRlcyhzZWFyY2hLZXl3b3JkKSkge1xuICAgICAgICAgICAgZmluZGluZ3MucHVzaCh7XG4gICAgICAgICAgICAgIGNhdGVnb3J5OiAnc2VjdXJpdHknLFxuICAgICAgICAgICAgICBzZXZlcml0eTogJ2hpZ2gnLFxuICAgICAgICAgICAgICBtZXNzYWdlOiBgRm9yYmlkZGVuIGtleXdvcmQgZGV0ZWN0ZWQ6ICR7a2V5d29yZH1gXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZmluZGluZ3MsXG4gICAgICAgIHNjb3JlOiBmaW5kaW5ncy5sZW5ndGggPiAwID8gMC42IDogMFxuICAgICAgfTtcbiAgICB9XG4gIH0pO1xufVxuIl19