@dollhousemcp/mcp-server 1.5.2 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/README.md +494 -111
- package/data/agents/code-reviewer.md +8 -1
- package/data/agents/research-assistant.md +8 -1
- package/data/agents/task-manager.md +8 -1
- package/data/ensembles/business-advisor.md +8 -1
- package/data/ensembles/creative-studio.md +8 -1
- package/data/ensembles/development-team.md +8 -1
- package/data/ensembles/security-analysis-team.md +8 -1
- package/data/memories/conversation-history.md +8 -1
- package/data/memories/learning-progress.md +8 -1
- package/data/memories/project-context.md +8 -1
- package/data/personas/business-consultant.md +8 -1
- package/data/personas/creative-writer.md +8 -1
- package/data/personas/debug-detective.md +8 -1
- package/data/personas/eli5-explainer.md +8 -1
- package/data/personas/security-analyst.md +8 -1
- package/data/personas/technical-analyst.md +8 -1
- package/data/skills/code-review.md +8 -1
- package/data/skills/creative-writing.md +8 -1
- package/data/skills/data-analysis.md +8 -1
- package/data/skills/penetration-testing.md +8 -1
- package/data/skills/research.md +8 -1
- package/data/skills/threat-modeling.md +8 -1
- package/data/skills/translation.md +8 -1
- package/data/templates/code-documentation.md +8 -1
- package/data/templates/email-professional.md +8 -1
- package/data/templates/meeting-notes.md +8 -1
- package/data/templates/penetration-test-report.md +8 -1
- package/data/templates/project-brief.md +8 -1
- package/data/templates/report-executive.md +8 -1
- package/data/templates/security-vulnerability-report.md +8 -1
- package/data/templates/threat-assessment-report.md +8 -1
- package/dist/auth/GitHubAuthManager.d.ts +6 -1
- package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
- package/dist/auth/GitHubAuthManager.js +45 -18
- package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
- package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
- package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
- package/dist/cache/CollectionCache.d.ts.map +1 -1
- package/dist/cache/CollectionCache.js +13 -3
- package/dist/cache/CollectionIndexCache.d.ts +77 -0
- package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
- package/dist/cache/CollectionIndexCache.js +349 -0
- package/dist/cache/LRUCache.d.ts +93 -0
- package/dist/cache/LRUCache.d.ts.map +1 -0
- package/dist/cache/LRUCache.js +299 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +2 -1
- package/dist/collection/CollectionBrowser.d.ts +21 -1
- package/dist/collection/CollectionBrowser.d.ts.map +1 -1
- package/dist/collection/CollectionBrowser.js +130 -10
- package/dist/collection/CollectionIndexManager.d.ts +151 -0
- package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
- package/dist/collection/CollectionIndexManager.js +499 -0
- package/dist/collection/CollectionSearch.d.ts +55 -0
- package/dist/collection/CollectionSearch.d.ts.map +1 -1
- package/dist/collection/CollectionSearch.js +338 -13
- package/dist/collection/CollectionSeeder.d.ts.map +1 -1
- package/dist/collection/CollectionSeeder.js +38 -1
- package/dist/collection/ElementInstaller.d.ts +31 -0
- package/dist/collection/ElementInstaller.d.ts.map +1 -1
- package/dist/collection/ElementInstaller.js +77 -15
- package/dist/collection/PersonaSubmitter.d.ts +1 -1
- package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
- package/dist/collection/PersonaSubmitter.js +2 -2
- package/dist/collection/index.d.ts +1 -0
- package/dist/collection/index.d.ts.map +1 -1
- package/dist/collection/index.js +2 -1
- package/dist/config/ConfigManager.d.ts +78 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +216 -0
- package/dist/config/element-types.d.ts +135 -0
- package/dist/config/element-types.d.ts.map +1 -0
- package/dist/config/element-types.js +108 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +3 -1
- package/dist/config/portfolio-constants.d.ts +83 -0
- package/dist/config/portfolio-constants.d.ts.map +1 -0
- package/dist/config/portfolio-constants.js +99 -0
- package/dist/elements/BaseElement.d.ts +14 -2
- package/dist/elements/BaseElement.d.ts.map +1 -1
- package/dist/elements/BaseElement.js +88 -6
- package/dist/elements/agents/Agent.d.ts +10 -1
- package/dist/elements/agents/Agent.d.ts.map +1 -1
- package/dist/elements/agents/Agent.js +66 -19
- package/dist/elements/agents/AgentManager.d.ts +2 -0
- package/dist/elements/agents/AgentManager.d.ts.map +1 -1
- package/dist/elements/agents/AgentManager.js +12 -10
- package/dist/elements/skills/Skill.d.ts +10 -1
- package/dist/elements/skills/Skill.d.ts.map +1 -1
- package/dist/elements/skills/Skill.js +40 -3
- package/dist/elements/skills/SkillManager.d.ts +1 -0
- package/dist/elements/skills/SkillManager.d.ts.map +1 -1
- package/dist/elements/skills/SkillManager.js +10 -4
- package/dist/elements/templates/Template.d.ts +10 -1
- package/dist/elements/templates/Template.d.ts.map +1 -1
- package/dist/elements/templates/Template.js +35 -18
- package/dist/elements/templates/TemplateManager.d.ts +1 -1
- package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
- package/dist/elements/templates/TemplateManager.js +6 -5
- package/dist/generated/version.d.ts +2 -2
- package/dist/generated/version.js +3 -3
- package/dist/index.barrel.d.ts +1 -2
- package/dist/index.barrel.d.ts.map +1 -1
- package/dist/index.barrel.js +2 -4
- package/dist/index.d.ts +143 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1883 -310
- package/dist/persona/PersonaElement.d.ts +10 -0
- package/dist/persona/PersonaElement.d.ts.map +1 -1
- package/dist/persona/PersonaElement.js +55 -32
- package/dist/persona/PersonaElementManager.d.ts.map +1 -1
- package/dist/persona/PersonaElementManager.js +13 -11
- package/dist/persona/PersonaLoader.d.ts.map +1 -1
- package/dist/persona/PersonaLoader.js +8 -2
- package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
- package/dist/persona/export-import/PersonaImporter.js +24 -5
- package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
- package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
- package/dist/persona/export-import/PersonaSharer.js +198 -22
- package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
- package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
- package/dist/portfolio/DefaultElementProvider.js +499 -7
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
- package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
- package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
- package/dist/portfolio/MigrationManager.d.ts.map +1 -1
- package/dist/portfolio/MigrationManager.js +136 -3
- package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
- package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioIndexManager.js +478 -0
- package/dist/portfolio/PortfolioManager.d.ts +5 -0
- package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
- package/dist/portfolio/PortfolioManager.js +61 -20
- package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
- package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
- package/dist/portfolio/PortfolioRepoManager.js +337 -0
- package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
- package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
- package/dist/portfolio/UnifiedIndexManager.js +1434 -0
- package/dist/portfolio/index.d.ts +15 -0
- package/dist/portfolio/index.d.ts.map +1 -0
- package/dist/portfolio/index.js +15 -0
- package/dist/portfolio/types.d.ts +7 -0
- package/dist/portfolio/types.d.ts.map +1 -1
- package/dist/portfolio/types.js +6 -1
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +50 -48
- package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
- package/dist/security/audit/SecurityAuditor.js +17 -9
- package/dist/security/audit/config/suppressions.d.ts.map +1 -1
- package/dist/security/audit/config/suppressions.js +19 -3
- package/dist/security/contentValidator.d.ts +2 -0
- package/dist/security/contentValidator.d.ts.map +1 -1
- package/dist/security/contentValidator.js +115 -4
- package/dist/security/secureYamlParser.d.ts +1 -0
- package/dist/security/secureYamlParser.d.ts.map +1 -1
- package/dist/security/secureYamlParser.js +29 -7
- package/dist/security/securityMonitor.d.ts +1 -1
- package/dist/security/securityMonitor.d.ts.map +1 -1
- package/dist/security/securityMonitor.js +1 -1
- package/dist/security/tokenManager.d.ts +1 -1
- package/dist/security/tokenManager.d.ts.map +1 -1
- package/dist/security/tokenManager.js +30 -10
- package/dist/server/ServerSetup.d.ts +22 -2
- package/dist/server/ServerSetup.d.ts.map +1 -1
- package/dist/server/ServerSetup.js +77 -12
- package/dist/server/tools/AuthTools.d.ts.map +1 -1
- package/dist/server/tools/AuthTools.js +33 -1
- package/dist/server/tools/BuildInfoTools.d.ts +25 -0
- package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
- package/dist/server/tools/BuildInfoTools.js +36 -0
- package/dist/server/tools/CollectionTools.d.ts.map +1 -1
- package/dist/server/tools/CollectionTools.js +55 -46
- package/dist/server/tools/ConfigTools.d.ts.map +1 -1
- package/dist/server/tools/ConfigTools.js +29 -1
- package/dist/server/tools/PersonaTools.d.ts +4 -2
- package/dist/server/tools/PersonaTools.d.ts.map +1 -1
- package/dist/server/tools/PersonaTools.js +5 -152
- package/dist/server/tools/PortfolioTools.d.ts +12 -0
- package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
- package/dist/server/tools/PortfolioTools.js +221 -0
- package/dist/server/tools/index.d.ts +3 -1
- package/dist/server/tools/index.d.ts.map +1 -1
- package/dist/server/tools/index.js +4 -2
- package/dist/server/types.d.ts +40 -5
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js +1 -1
- package/dist/services/BuildInfoService.d.ts +84 -0
- package/dist/services/BuildInfoService.d.ts.map +1 -0
- package/dist/services/BuildInfoService.js +271 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
- package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
- package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
- package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
- package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
- package/dist/tools/portfolio/types.d.ts +41 -0
- package/dist/tools/portfolio/types.d.ts.map +1 -0
- package/dist/tools/portfolio/types.js +15 -0
- package/dist/types/collection.d.ts +51 -0
- package/dist/types/collection.d.ts.map +1 -1
- package/dist/types/collection.js +1 -1
- package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
- package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
- package/dist/utils/EarlyTerminationSearch.js +164 -0
- package/dist/utils/ErrorHandler.d.ts +86 -0
- package/dist/utils/ErrorHandler.d.ts.map +1 -0
- package/dist/utils/ErrorHandler.js +201 -0
- package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
- package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
- package/dist/utils/FileDiscoveryUtil.js +169 -0
- package/dist/utils/GitHubRateLimiter.d.ts +88 -0
- package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
- package/dist/utils/GitHubRateLimiter.js +315 -0
- package/dist/utils/PerformanceMonitor.d.ts +134 -0
- package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
- package/dist/utils/PerformanceMonitor.js +347 -0
- package/dist/utils/RateLimiter.d.ts.map +1 -0
- package/dist/utils/RateLimiter.js +172 -0
- package/dist/utils/SecureDownloader.d.ts +241 -0
- package/dist/utils/SecureDownloader.d.ts.map +1 -0
- package/dist/utils/SecureDownloader.js +759 -0
- package/dist/utils/ToolCache.d.ts +82 -0
- package/dist/utils/ToolCache.d.ts.map +1 -0
- package/dist/utils/ToolCache.js +196 -0
- package/dist/utils/errorCodes.d.ts +136 -0
- package/dist/utils/errorCodes.d.ts.map +1 -0
- package/dist/utils/errorCodes.js +87 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -1
- package/dist/utils/installation.d.ts +1 -1
- package/dist/utils/installation.d.ts.map +1 -1
- package/dist/utils/installation.js +9 -8
- package/dist/utils/searchUtils.d.ts +31 -0
- package/dist/utils/searchUtils.d.ts.map +1 -1
- package/dist/utils/searchUtils.js +62 -1
- package/package.json +17 -7
- package/dist/config/updateConfig.d.ts +0 -84
- package/dist/config/updateConfig.d.ts.map +0 -1
- package/dist/config/updateConfig.js +0 -148
- package/dist/server/tools/UpdateTools.d.ts +0 -10
- package/dist/server/tools/UpdateTools.d.ts.map +0 -1
- package/dist/server/tools/UpdateTools.js +0 -85
- package/dist/update/BackupManager.d.ts +0 -63
- package/dist/update/BackupManager.d.ts.map +0 -1
- package/dist/update/BackupManager.js +0 -370
- package/dist/update/DependencyChecker.d.ts +0 -41
- package/dist/update/DependencyChecker.d.ts.map +0 -1
- package/dist/update/DependencyChecker.js +0 -132
- package/dist/update/RateLimiter.d.ts.map +0 -1
- package/dist/update/RateLimiter.js +0 -172
- package/dist/update/SignatureVerifier.d.ts +0 -71
- package/dist/update/SignatureVerifier.d.ts.map +0 -1
- package/dist/update/SignatureVerifier.js +0 -214
- package/dist/update/UpdateChecker.d.ts +0 -132
- package/dist/update/UpdateChecker.d.ts.map +0 -1
- package/dist/update/UpdateChecker.js +0 -506
- package/dist/update/UpdateManager.d.ts +0 -60
- package/dist/update/UpdateManager.d.ts.map +0 -1
- package/dist/update/UpdateManager.js +0 -730
- package/dist/update/VersionManager.d.ts +0 -31
- package/dist/update/VersionManager.d.ts.map +0 -1
- package/dist/update/VersionManager.js +0 -181
- package/dist/update/index.d.ts +0 -9
- package/dist/update/index.d.ts.map +0 -1
- package/dist/update/index.js +0 -9
- /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BuildInfoService - Provides build and runtime information
|
|
3
|
+
* Separated from main index.ts to avoid making that file larger
|
|
4
|
+
*
|
|
5
|
+
* SECURITY FIX (PR #614):
|
|
6
|
+
* 1. DMCP-SEC-004: FALSE POSITIVE SUPPRESSION - No user input Unicode normalization needed
|
|
7
|
+
* This service only processes system information (git, package.json, environment variables)
|
|
8
|
+
* The MCP tool 'get_build_info' takes NO parameters (empty inputSchema)
|
|
9
|
+
* No user-provided data flows through this service that requires Unicode normalization
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'fs/promises';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import { fileURLToPath } from 'url';
|
|
14
|
+
import { execSync } from 'child_process';
|
|
15
|
+
import { logger } from '../utils/logger.js';
|
|
16
|
+
export class BuildInfoService {
|
|
17
|
+
static instance;
|
|
18
|
+
startTime;
|
|
19
|
+
packageInfo;
|
|
20
|
+
constructor() {
|
|
21
|
+
this.startTime = new Date();
|
|
22
|
+
}
|
|
23
|
+
static getInstance() {
|
|
24
|
+
if (!BuildInfoService.instance) {
|
|
25
|
+
BuildInfoService.instance = new BuildInfoService();
|
|
26
|
+
}
|
|
27
|
+
return BuildInfoService.instance;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get comprehensive build information
|
|
31
|
+
* SECURITY NOTE: This method processes only system-generated data
|
|
32
|
+
* No user input is involved - all data comes from filesystem, git, and Node.js process
|
|
33
|
+
*/
|
|
34
|
+
async getBuildInfo() {
|
|
35
|
+
const [packageInfo, gitInfo, dockerInfo] = await Promise.all([
|
|
36
|
+
this.getPackageInfo(),
|
|
37
|
+
this.getGitInfo(),
|
|
38
|
+
this.getDockerInfo()
|
|
39
|
+
]);
|
|
40
|
+
const buildTimestamp = await this.getBuildTimestamp();
|
|
41
|
+
return {
|
|
42
|
+
package: packageInfo,
|
|
43
|
+
build: {
|
|
44
|
+
timestamp: buildTimestamp,
|
|
45
|
+
type: gitInfo.commit ? 'git' : buildTimestamp ? 'npm' : 'unknown',
|
|
46
|
+
gitCommit: gitInfo.commit,
|
|
47
|
+
gitBranch: gitInfo.branch
|
|
48
|
+
},
|
|
49
|
+
runtime: {
|
|
50
|
+
nodeVersion: process.version,
|
|
51
|
+
platform: process.platform,
|
|
52
|
+
arch: process.arch,
|
|
53
|
+
uptime: process.uptime(),
|
|
54
|
+
memoryUsage: process.memoryUsage()
|
|
55
|
+
},
|
|
56
|
+
environment: {
|
|
57
|
+
nodeEnv: process.env.NODE_ENV,
|
|
58
|
+
isProduction: process.env.NODE_ENV === 'production',
|
|
59
|
+
isDevelopment: process.env.NODE_ENV === 'development',
|
|
60
|
+
isDebug: process.env.DEBUG === 'true' || process.env.DEBUG === '1',
|
|
61
|
+
isDocker: dockerInfo.isDocker,
|
|
62
|
+
dockerInfo: dockerInfo.info
|
|
63
|
+
},
|
|
64
|
+
server: {
|
|
65
|
+
startTime: this.startTime,
|
|
66
|
+
uptime: Date.now() - this.startTime.getTime(),
|
|
67
|
+
mcpConnection: true // We're connected if this method is being called via MCP
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Format build info as user-friendly markdown
|
|
73
|
+
* SECURITY NOTE: Only formats system-generated data - no user input processing
|
|
74
|
+
* All input data comes from getBuildInfo() which only reads system information
|
|
75
|
+
*/
|
|
76
|
+
formatBuildInfo(info) {
|
|
77
|
+
const lines = [];
|
|
78
|
+
lines.push('# 🔧 Build Information\n');
|
|
79
|
+
// Package info
|
|
80
|
+
lines.push('## 📦 Package');
|
|
81
|
+
lines.push(`- **Name**: ${info.package.name}`);
|
|
82
|
+
lines.push(`- **Version**: ${info.package.version}`);
|
|
83
|
+
lines.push('');
|
|
84
|
+
// Build info
|
|
85
|
+
lines.push('## 🏗️ Build');
|
|
86
|
+
lines.push(`- **Type**: ${info.build.type}`);
|
|
87
|
+
if (info.build.timestamp) {
|
|
88
|
+
lines.push(`- **Timestamp**: ${info.build.timestamp}`);
|
|
89
|
+
}
|
|
90
|
+
if (info.build.gitCommit) {
|
|
91
|
+
lines.push(`- **Git Commit**: \`${info.build.gitCommit}\``);
|
|
92
|
+
}
|
|
93
|
+
if (info.build.gitBranch) {
|
|
94
|
+
lines.push(`- **Git Branch**: ${info.build.gitBranch}`);
|
|
95
|
+
}
|
|
96
|
+
lines.push('');
|
|
97
|
+
// Runtime info
|
|
98
|
+
lines.push('## 💻 Runtime');
|
|
99
|
+
lines.push(`- **Node.js**: ${info.runtime.nodeVersion}`);
|
|
100
|
+
lines.push(`- **Platform**: ${info.runtime.platform}`);
|
|
101
|
+
lines.push(`- **Architecture**: ${info.runtime.arch}`);
|
|
102
|
+
lines.push(`- **Process Uptime**: ${this.formatUptime(info.runtime.uptime)}`);
|
|
103
|
+
lines.push(`- **Memory Usage**: ${this.formatMemory(info.runtime.memoryUsage.heapUsed)} / ${this.formatMemory(info.runtime.memoryUsage.heapTotal)}`);
|
|
104
|
+
lines.push('');
|
|
105
|
+
// Environment info
|
|
106
|
+
lines.push('## ⚙️ Environment');
|
|
107
|
+
lines.push(`- **NODE_ENV**: ${info.environment.nodeEnv || 'not set'}`);
|
|
108
|
+
lines.push(`- **Mode**: ${info.environment.isProduction ? 'Production' : info.environment.isDevelopment ? 'Development' : 'Unknown'}`);
|
|
109
|
+
lines.push(`- **Debug**: ${info.environment.isDebug ? 'Enabled' : 'Disabled'}`);
|
|
110
|
+
lines.push(`- **Docker**: ${info.environment.isDocker ? 'Yes' : 'No'}`);
|
|
111
|
+
if (info.environment.dockerInfo) {
|
|
112
|
+
lines.push(`- **Container**: ${info.environment.dockerInfo}`);
|
|
113
|
+
}
|
|
114
|
+
lines.push('');
|
|
115
|
+
// Server info
|
|
116
|
+
lines.push('## 🚀 Server');
|
|
117
|
+
lines.push(`- **Started**: ${info.server.startTime.toISOString()}`);
|
|
118
|
+
lines.push(`- **Uptime**: ${this.formatUptime(info.server.uptime / 1000)}`);
|
|
119
|
+
lines.push(`- **MCP Connection**: ${info.server.mcpConnection ? '✅ Connected' : '❌ Disconnected'}`);
|
|
120
|
+
return lines.join('\n');
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* SECURITY NOTE: No Unicode normalization needed - reads application's own package.json
|
|
124
|
+
* Data source: Controlled file system path, no user input
|
|
125
|
+
*/
|
|
126
|
+
async getPackageInfo() {
|
|
127
|
+
if (this.packageInfo) {
|
|
128
|
+
return this.packageInfo;
|
|
129
|
+
}
|
|
130
|
+
try {
|
|
131
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
132
|
+
const __dirname = path.dirname(__filename);
|
|
133
|
+
// Try multiple paths to find package.json
|
|
134
|
+
// This handles both normal execution and compiled test scenarios
|
|
135
|
+
const possiblePaths = [
|
|
136
|
+
path.join(__dirname, '..', '..', 'package.json'), // Normal: dist/services -> root
|
|
137
|
+
path.join(__dirname, '..', '..', '..', 'package.json'), // Test: dist/test/services -> root
|
|
138
|
+
path.join(__dirname, '..', '..', '..', '..', 'package.json'), // Deep test: dist/test/deep/services -> root
|
|
139
|
+
path.join(process.cwd(), 'package.json') // Fallback to current working directory
|
|
140
|
+
];
|
|
141
|
+
let pkg = null;
|
|
142
|
+
for (const packagePath of possiblePaths) {
|
|
143
|
+
try {
|
|
144
|
+
// SECURITY NOTE: Reading our own package.json file - not user input
|
|
145
|
+
// This file is controlled by the application, no Unicode normalization needed
|
|
146
|
+
const content = await fs.readFile(packagePath, 'utf-8');
|
|
147
|
+
pkg = JSON.parse(content);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// Try next path
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!pkg) {
|
|
156
|
+
throw new Error('Could not find package.json in any expected location');
|
|
157
|
+
}
|
|
158
|
+
this.packageInfo = {
|
|
159
|
+
name: pkg.name || 'unknown',
|
|
160
|
+
version: pkg.version || 'unknown'
|
|
161
|
+
};
|
|
162
|
+
return this.packageInfo;
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
logger.debug('Failed to read package.json:', error);
|
|
166
|
+
return { name: 'unknown', version: 'unknown' };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* SECURITY NOTE: No Unicode normalization needed - reads build-generated version file
|
|
171
|
+
* Data source: Build system output file, no user input
|
|
172
|
+
*/
|
|
173
|
+
async getBuildTimestamp() {
|
|
174
|
+
try {
|
|
175
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
176
|
+
const __dirname = path.dirname(__filename);
|
|
177
|
+
// Try multiple paths to find version.json
|
|
178
|
+
// This handles both normal execution and compiled test scenarios
|
|
179
|
+
const possiblePaths = [
|
|
180
|
+
path.join(__dirname, '..', '..', 'dist', 'version.json'), // Normal location
|
|
181
|
+
path.join(__dirname, '..', '..', '..', 'dist', 'version.json'), // Test scenario
|
|
182
|
+
path.join(process.cwd(), 'dist', 'version.json') // Fallback to cwd
|
|
183
|
+
];
|
|
184
|
+
for (const versionPath of possiblePaths) {
|
|
185
|
+
try {
|
|
186
|
+
const content = await fs.readFile(versionPath, 'utf-8');
|
|
187
|
+
const version = JSON.parse(content);
|
|
188
|
+
return version.buildTime || version.timestamp;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Try next path
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Version file might not exist, that's okay
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Version file might not exist, that's okay
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* SECURITY NOTE: No Unicode normalization needed - executes system git commands
|
|
205
|
+
* Data source: Git CLI output (system-controlled), no user input
|
|
206
|
+
*/
|
|
207
|
+
async getGitInfo() {
|
|
208
|
+
try {
|
|
209
|
+
// SECURITY NOTE: Git commands return system-controlled data - not user input
|
|
210
|
+
// Git commit hashes and branch names are controlled by git, no Unicode normalization needed
|
|
211
|
+
const commit = execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim();
|
|
212
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
|
|
213
|
+
return { commit, branch };
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Not in a git repository or git not available
|
|
217
|
+
return {};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* SECURITY NOTE: No Unicode normalization needed - reads container runtime files
|
|
222
|
+
* Data source: System cgroup files (container-controlled), no user input
|
|
223
|
+
*/
|
|
224
|
+
async getDockerInfo() {
|
|
225
|
+
try {
|
|
226
|
+
// SECURITY NOTE: Reading system cgroup file - controlled by container runtime, not user input
|
|
227
|
+
// Container runtime generates this file content, no Unicode normalization needed
|
|
228
|
+
const cgroupContent = await fs.readFile('/proc/1/cgroup', 'utf-8');
|
|
229
|
+
const isDocker = cgroupContent.includes('docker') || cgroupContent.includes('containerd');
|
|
230
|
+
if (isDocker) {
|
|
231
|
+
// Try to get container ID
|
|
232
|
+
const containerId = cgroupContent
|
|
233
|
+
.split('\n')
|
|
234
|
+
.find(line => line.includes('docker'))
|
|
235
|
+
?.split('/')
|
|
236
|
+
.pop()
|
|
237
|
+
?.substring(0, 12);
|
|
238
|
+
return {
|
|
239
|
+
isDocker: true,
|
|
240
|
+
info: containerId ? `Container ID: ${containerId}` : 'Running in Docker'
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
return { isDocker: false };
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Not in Docker or /proc not available
|
|
247
|
+
return { isDocker: false };
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
formatUptime(seconds) {
|
|
251
|
+
const days = Math.floor(seconds / 86400);
|
|
252
|
+
const hours = Math.floor((seconds % 86400) / 3600);
|
|
253
|
+
const minutes = Math.floor((seconds % 3600) / 60);
|
|
254
|
+
const secs = Math.floor(seconds % 60);
|
|
255
|
+
const parts = [];
|
|
256
|
+
if (days > 0)
|
|
257
|
+
parts.push(`${days}d`);
|
|
258
|
+
if (hours > 0)
|
|
259
|
+
parts.push(`${hours}h`);
|
|
260
|
+
if (minutes > 0)
|
|
261
|
+
parts.push(`${minutes}m`);
|
|
262
|
+
if (secs > 0 || parts.length === 0)
|
|
263
|
+
parts.push(`${secs}s`);
|
|
264
|
+
return parts.join(' ');
|
|
265
|
+
}
|
|
266
|
+
formatMemory(bytes) {
|
|
267
|
+
const mb = bytes / 1024 / 1024;
|
|
268
|
+
return `${mb.toFixed(1)} MB`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnVpbGRJbmZvU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9CdWlsZEluZm9TZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDcEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFtQzVDLE1BQU0sT0FBTyxnQkFBZ0I7SUFDbkIsTUFBTSxDQUFDLFFBQVEsQ0FBbUI7SUFDekIsU0FBUyxDQUFPO0lBQ3pCLFdBQVcsQ0FBcUM7SUFFeEQ7UUFDRSxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVNLE1BQU0sQ0FBQyxXQUFXO1FBQ3ZCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMvQixnQkFBZ0IsQ0FBQyxRQUFRLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3JELENBQUM7UUFDRCxPQUFPLGdCQUFnQixDQUFDLFFBQVEsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEtBQUssQ0FBQyxZQUFZO1FBQ3ZCLE1BQU0sQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLFVBQVUsQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUMzRCxJQUFJLENBQUMsY0FBYyxFQUFFO1lBQ3JCLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDakIsSUFBSSxDQUFDLGFBQWEsRUFBRTtTQUNyQixDQUFDLENBQUM7UUFFSCxNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxp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SyxDQUFDLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBRXRDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztRQUMzQixJQUFJLElBQUksR0FBRyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsSUFBSSxLQUFLLEdBQUcsQ0FBQztZQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksT0FBTyxHQUFHLENBQUM7WUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJLElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFFM0QsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFTyxZQUFZLENBQUMsS0FBYTtRQUNoQyxNQUFNLEVBQUUsR0FBRyxLQUFLLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztRQUMvQixPQUFPLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnVpbGRJbmZvU2VydmljZSAtIFByb3ZpZGVzIGJ1aWxkIGFuZCBydW50aW1lIGluZm9ybWF0aW9uXG4gKiBTZXBhcmF0ZWQgZnJvbSBtYWluIGluZGV4LnRzIHRvIGF2b2lkIG1ha2luZyB0aGF0IGZpbGUgbGFyZ2VyXG4gKiBcbiAqIFNFQ1VSSVRZIEZJWCAoUFIgIzYxNCk6XG4gKiAxLiBETUNQLVNFQy0wMDQ6IEZBTFNFIFBPU0lUSVZFIFNVUFBSRVNTSU9OIC0gTm8gdXNlciBpbnB1dCBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkXG4gKiAgICBUaGlzIHNlcnZpY2Ugb25seSBwcm9jZXNzZXMgc3lzdGVtIGluZm9ybWF0aW9uIChnaXQsIHBhY2thZ2UuanNvbiwgZW52aXJvbm1lbnQgdmFyaWFibGVzKVxuICogICAgVGhlIE1DUCB0b29sICdnZXRfYnVpbGRfaW5mbycgdGFrZXMgTk8gcGFyYW1ldGVycyAoZW1wdHkgaW5wdXRTY2hlbWEpXG4gKiAgICBObyB1c2VyLXByb3ZpZGVkIGRhdGEgZmxvd3MgdGhyb3VnaCB0aGlzIHNlcnZpY2UgdGhhdCByZXF1aXJlcyBVbmljb2RlIG5vcm1hbGl6YXRpb25cbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XG5pbXBvcnQgeyBleGVjU3luYyB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBCdWlsZEluZm8ge1xuICBwYWNrYWdlOiB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgfTtcbiAgYnVpbGQ6IHtcbiAgICB0aW1lc3RhbXA/OiBzdHJpbmc7XG4gICAgdHlwZTogJ2dpdCcgfCAnbnBtJyB8ICd1bmtub3duJztcbiAgICBnaXRDb21taXQ/OiBzdHJpbmc7XG4gICAgZ2l0QnJhbmNoPzogc3RyaW5nO1xuICB9O1xuICBydW50aW1lOiB7XG4gICAgbm9kZVZlcnNpb246IHN0cmluZztcbiAgICBwbGF0Zm9ybTogc3RyaW5nO1xuICAgIGFyY2g6IHN0cmluZztcbiAgICB1cHRpbWU6IG51bWJlcjtcbiAgICBtZW1vcnlVc2FnZTogTm9kZUpTLk1lbW9yeVVzYWdlO1xuICB9O1xuICBlbnZpcm9ubWVudDoge1xuICAgIG5vZGVFbnY/OiBzdHJpbmc7XG4gICAgaXNQcm9kdWN0aW9uOiBib29sZWFuO1xuICAgIGlzRGV2ZWxvcG1lbnQ6IGJvb2xlYW47XG4gICAgaXNEZWJ1ZzogYm9vbGVhbjtcbiAgICBpc0RvY2tlcjogYm9vbGVhbjtcbiAgICBkb2NrZXJJbmZvPzogc3RyaW5nO1xuICB9O1xuICBzZXJ2ZXI6IHtcbiAgICBzdGFydFRpbWU6IERhdGU7XG4gICAgdXB0aW1lOiBudW1iZXI7XG4gICAgbWNwQ29ubmVjdGlvbjogYm9vbGVhbjtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIEJ1aWxkSW5mb1NlcnZpY2Uge1xuICBwcml2YXRlIHN0YXRpYyBpbnN0YW5jZTogQnVpbGRJbmZvU2VydmljZTtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGFydFRpbWU6IERhdGU7XG4gIHByaXZhdGUgcGFja2FnZUluZm8/OiB7IG5hbWU6IHN0cmluZzsgdmVyc2lvbjogc3RyaW5nIH07XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLnN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XG4gIH1cblxuICBwdWJsaWMgc3RhdGljIGdldEluc3RhbmNlKCk6IEJ1aWxkSW5mb1NlcnZpY2Uge1xuICAgIGlmICghQnVpbGRJbmZvU2VydmljZS5pbnN0YW5jZSkge1xuICAgICAgQnVpbGRJbmZvU2VydmljZS5pbnN0YW5jZSA9IG5ldyBCdWlsZEluZm9TZXJ2aWNlKCk7XG4gICAgfVxuICAgIHJldHVybiBCdWlsZEluZm9TZXJ2aWNlLmluc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjb21wcmVoZW5zaXZlIGJ1aWxkIGluZm9ybWF0aW9uXG4gICAqIFNFQ1VSSVRZIE5PVEU6IFRoaXMgbWV0aG9kIHByb2Nlc3NlcyBvbmx5IHN5c3RlbS1nZW5lcmF0ZWQgZGF0YVxuICAgKiBObyB1c2VyIGlucHV0IGlzIGludm9sdmVkIC0gYWxsIGRhdGEgY29tZXMgZnJvbSBmaWxlc3lzdGVtLCBnaXQsIGFuZCBOb2RlLmpzIHByb2Nlc3NcbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRCdWlsZEluZm8oKTogUHJvbWlzZTxCdWlsZEluZm8+IHtcbiAgICBjb25zdCBbcGFja2FnZUluZm8sIGdpdEluZm8sIGRvY2tlckluZm9dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgdGhpcy5nZXRQYWNrYWdlSW5mbygpLFxuICAgICAgdGhpcy5nZXRHaXRJbmZvKCksXG4gICAgICB0aGlzLmdldERvY2tlckluZm8oKVxuICAgIF0pO1xuXG4gICAgY29uc3QgYnVpbGRUaW1lc3RhbXAgPSBhd2FpdCB0aGlzLmdldEJ1aWxkVGltZXN0YW1wKCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgcGFja2FnZTogcGFja2FnZUluZm8sXG4gICAgICBidWlsZDoge1xuICAgICAgICB0aW1lc3RhbXA6IGJ1aWxkVGltZXN0YW1wLFxuICAgICAgICB0eXBlOiBnaXRJbmZvLmNvbW1pdCA/ICdnaXQnIDogYnVpbGRUaW1lc3RhbXAgPyAnbnBtJyA6ICd1bmtub3duJyxcbiAgICAgICAgZ2l0Q29tbWl0OiBnaXRJbmZvLmNvbW1pdCxcbiAgICAgICAgZ2l0QnJhbmNoOiBnaXRJbmZvLmJyYW5jaFxuICAgICAgfSxcbiAgICAgIHJ1bnRpbWU6IHtcbiAgICAgICAgbm9kZVZlcnNpb246IHByb2Nlc3MudmVyc2lvbixcbiAgICAgICAgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0sXG4gICAgICAgIGFyY2g6IHByb2Nlc3MuYXJjaCxcbiAgICAgICAgdXB0aW1lOiBwcm9jZXNzLnVwdGltZSgpLFxuICAgICAgICBtZW1vcnlVc2FnZTogcHJvY2Vzcy5tZW1vcnlVc2FnZSgpXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgbm9kZUVudjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYsXG4gICAgICAgIGlzUHJvZHVjdGlvbjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdwcm9kdWN0aW9uJyxcbiAgICAgICAgaXNEZXZlbG9wbWVudDogcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcsXG4gICAgICAgIGlzRGVidWc6IHByb2Nlc3MuZW52LkRFQlVHID09PSAndHJ1ZScgfHwgcHJvY2Vzcy5lbnYuREVCVUcgPT09ICcxJyxcbiAgICAgICAgaXNEb2NrZXI6IGRvY2tlckluZm8uaXNEb2NrZXIsXG4gICAgICAgIGRvY2tlckluZm86IGRvY2tlckluZm8uaW5mb1xuICAgICAgfSxcbiAgICAgIHNlcnZlcjoge1xuICAgICAgICBzdGFydFRpbWU6IHRoaXMuc3RhcnRUaW1lLFxuICAgICAgICB1cHRpbWU6IERhdGUubm93KCkgLSB0aGlzLnN0YXJ0VGltZS5nZXRUaW1lKCksXG4gICAgICAgIG1jcENvbm5lY3Rpb246IHRydWUgLy8gV2UncmUgY29ubmVjdGVkIGlmIHRoaXMgbWV0aG9kIGlzIGJlaW5nIGNhbGxlZCB2aWEgTUNQXG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JtYXQgYnVpbGQgaW5mbyBhcyB1c2VyLWZyaWVuZGx5IG1hcmtkb3duXG4gICAqIFNFQ1VSSVRZIE5PVEU6IE9ubHkgZm9ybWF0cyBzeXN0ZW0tZ2VuZXJhdGVkIGRhdGEgLSBubyB1c2VyIGlucHV0IHByb2Nlc3NpbmdcbiAgICogQWxsIGlucHV0IGRhdGEgY29tZXMgZnJvbSBnZXRCdWlsZEluZm8oKSB3aGljaCBvbmx5IHJlYWRzIHN5c3RlbSBpbmZvcm1hdGlvblxuICAgKi9cbiAgcHVibGljIGZvcm1hdEJ1aWxkSW5mbyhpbmZvOiBCdWlsZEluZm8pOiBzdHJpbmcge1xuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIGxpbmVzLnB1c2goJyMg8J+UpyBCdWlsZCBJbmZvcm1hdGlvblxcbicpO1xuICAgIFxuICAgIC8vIFBhY2thZ2UgaW5mb1xuICAgIGxpbmVzLnB1c2goJyMjIPCfk6YgUGFja2FnZScpO1xuICAgIGxpbmVzLnB1c2goYC0gKipOYW1lKio6ICR7aW5mby5wYWNrYWdlLm5hbWV9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlZlcnNpb24qKjogJHtpbmZvLnBhY2thZ2UudmVyc2lvbn1gKTtcbiAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICBcbiAgICAvLyBCdWlsZCBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg8J+Pl++4jyBCdWlsZCcpO1xuICAgIGxpbmVzLnB1c2goYC0gKipUeXBlKio6ICR7aW5mby5idWlsZC50eXBlfWApO1xuICAgIGlmIChpbmZvLmJ1aWxkLnRpbWVzdGFtcCkge1xuICAgICAgbGluZXMucHVzaChgLSAqKlRpbWVzdGFtcCoqOiAke2luZm8uYnVpbGQudGltZXN0YW1wfWApO1xuICAgIH1cbiAgICBpZiAoaW5mby5idWlsZC5naXRDb21taXQpIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipHaXQgQ29tbWl0Kio6IFxcYCR7aW5mby5idWlsZC5naXRDb21taXR9XFxgYCk7XG4gICAgfVxuICAgIGlmIChpbmZvLmJ1aWxkLmdpdEJyYW5jaCkge1xuICAgICAgbGluZXMucHVzaChgLSAqKkdpdCBCcmFuY2gqKjogJHtpbmZvLmJ1aWxkLmdpdEJyYW5jaH1gKTtcbiAgICB9XG4gICAgbGluZXMucHVzaCgnJyk7XG4gICAgXG4gICAgLy8gUnVudGltZSBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg8J+SuyBSdW50aW1lJyk7XG4gICAgbGluZXMucHVzaChgLSAqKk5vZGUuanMqKjogJHtpbmZvLnJ1bnRpbWUubm9kZVZlcnNpb259YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlBsYXRmb3JtKio6ICR7aW5mby5ydW50aW1lLnBsYXRmb3JtfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipBcmNoaXRlY3R1cmUqKjogJHtpbmZvLnJ1bnRpbWUuYXJjaH1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqUHJvY2VzcyBVcHRpbWUqKjogJHt0aGlzLmZvcm1hdFVwdGltZShpbmZvLnJ1bnRpbWUudXB0aW1lKX1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTWVtb3J5IFVzYWdlKio6ICR7dGhpcy5mb3JtYXRNZW1vcnkoaW5mby5ydW50aW1lLm1lbW9yeVVzYWdlLmhlYXBVc2VkKX0gLyAke3RoaXMuZm9ybWF0TWVtb3J5KGluZm8ucnVudGltZS5tZW1vcnlVc2FnZS5oZWFwVG90YWwpfWApO1xuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIFxuICAgIC8vIEVudmlyb25tZW50IGluZm9cbiAgICBsaW5lcy5wdXNoKCcjIyDimpnvuI8gRW52aXJvbm1lbnQnKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTk9ERV9FTlYqKjogJHtpbmZvLmVudmlyb25tZW50Lm5vZGVFbnYgfHwgJ25vdCBzZXQnfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipNb2RlKio6ICR7aW5mby5lbnZpcm9ubWVudC5pc1Byb2R1Y3Rpb24gPyAnUHJvZHVjdGlvbicgOiBpbmZvLmVudmlyb25tZW50LmlzRGV2ZWxvcG1lbnQgPyAnRGV2ZWxvcG1lbnQnIDogJ1Vua25vd24nfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipEZWJ1ZyoqOiAke2luZm8uZW52aXJvbm1lbnQuaXNEZWJ1ZyA/ICdFbmFibGVkJyA6ICdEaXNhYmxlZCd9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKkRvY2tlcioqOiAke2luZm8uZW52aXJvbm1lbnQuaXNEb2NrZXIgPyAnWWVzJyA6ICdObyd9YCk7XG4gICAgaWYgKGluZm8uZW52aXJvbm1lbnQuZG9ja2VySW5mbykge1xuICAgICAgbGluZXMucHVzaChgLSAqKkNvbnRhaW5lcioqOiAke2luZm8uZW52aXJvbm1lbnQuZG9ja2VySW5mb31gKTtcbiAgICB9XG4gICAgbGluZXMucHVzaCgnJyk7XG4gICAgXG4gICAgLy8gU2VydmVyIGluZm9cbiAgICBsaW5lcy5wdXNoKCcjIyDwn5qAIFNlcnZlcicpO1xuICAgIGxpbmVzLnB1c2goYC0gKipTdGFydGVkKio6ICR7aW5mby5zZXJ2ZXIuc3RhcnRUaW1lLnRvSVNPU3RyaW5nKCl9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlVwdGltZSoqOiAke3RoaXMuZm9ybWF0VXB0aW1lKGluZm8uc2VydmVyLnVwdGltZSAvIDEwMDApfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipNQ1AgQ29ubmVjdGlvbioqOiAke2luZm8uc2VydmVyLm1jcENvbm5lY3Rpb24gPyAn4pyFIENvbm5lY3RlZCcgOiAn4p2MIERpc2Nvbm5lY3RlZCd9YCk7XG4gICAgXG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNFQ1VSSVRZIE5PVEU6IE5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBuZWVkZWQgLSByZWFkcyBhcHBsaWNhdGlvbidzIG93biBwYWNrYWdlLmpzb25cbiAgICogRGF0YSBzb3VyY2U6IENvbnRyb2xsZWQgZmlsZSBzeXN0ZW0gcGF0aCwgbm8gdXNlciBpbnB1dFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRQYWNrYWdlSW5mbygpOiBQcm9taXNlPHsgbmFtZTogc3RyaW5nOyB2ZXJzaW9uOiBzdHJpbmcgfT4ge1xuICAgIGlmICh0aGlzLnBhY2thZ2VJbmZvKSB7XG4gICAgICByZXR1cm4gdGhpcy5wYWNrYWdlSW5mbztcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcbiAgICAgIGNvbnN0IF9fZGlybmFtZSA9IHBhdGguZGlybmFtZShfX2ZpbGVuYW1lKTtcbiAgICAgIFxuICAgICAgLy8gVHJ5IG11bHRpcGxlIHBhdGhzIHRvIGZpbmQgcGFja2FnZS5qc29uXG4gICAgICAvLyBUaGlzIGhhbmRsZXMgYm90aCBub3JtYWwgZXhlY3V0aW9uIGFuZCBjb21waWxlZCB0ZXN0IHNjZW5hcmlvc1xuICAgICAgY29uc3QgcG9zc2libGVQYXRocyA9IFtcbiAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJ3BhY2thZ2UuanNvbicpLCAvLyBOb3JtYWw6IGRpc3Qvc2VydmljZXMgLT4gcm9vdFxuICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnLi4nLCAncGFja2FnZS5qc29uJyksIC8vIFRlc3Q6IGRpc3QvdGVzdC9zZXJ2aWNlcyAtPiByb290XG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICcuLicsICcuLicsICdwYWNrYWdlLmpzb24nKSwgLy8gRGVlcCB0ZXN0OiBkaXN0L3Rlc3QvZGVlcC9zZXJ2aWNlcyAtPiByb290XG4gICAgICAgIHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAncGFja2FnZS5qc29uJykgLy8gRmFsbGJhY2sgdG8gY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeVxuICAgICAgXTtcbiAgICAgIFxuICAgICAgbGV0IHBrZzogYW55ID0gbnVsbDtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBwYWNrYWdlUGF0aCBvZiBwb3NzaWJsZVBhdGhzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gU0VDVVJJVFkgTk9URTogUmVhZGluZyBvdXIgb3duIHBhY2thZ2UuanNvbiBmaWxlIC0gbm90IHVzZXIgaW5wdXRcbiAgICAgICAgICAvLyBUaGlzIGZpbGUgaXMgY29udHJvbGxlZCBieSB0aGUgYXBwbGljYXRpb24sIG5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBuZWVkZWRcbiAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUocGFja2FnZVBhdGgsICd1dGYtOCcpO1xuICAgICAgICAgIHBrZyA9IEpTT04ucGFyc2UoY29udGVudCk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIFRyeSBuZXh0IHBhdGhcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICBpZiAoIXBrZykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBmaW5kIHBhY2thZ2UuanNvbiBpbiBhbnkgZXhwZWN0ZWQgbG9jYXRpb24nKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgdGhpcy5wYWNrYWdlSW5mbyA9IHtcbiAgICAgICAgbmFtZTogcGtnLm5hbWUgfHwgJ3Vua25vd24nLFxuICAgICAgICB2ZXJzaW9uOiBwa2cudmVyc2lvbiB8fCAndW5rbm93bidcbiAgICAgIH07XG4gICAgICBcbiAgICAgIHJldHVybiB0aGlzLnBhY2thZ2VJbmZvO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0ZhaWxlZCB0byByZWFkIHBhY2thZ2UuanNvbjonLCBlcnJvcik7XG4gICAgICByZXR1cm4geyBuYW1lOiAndW5rbm93bicsIHZlcnNpb246ICd1bmtub3duJyB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTRUNVUklUWSBOT1RFOiBObyBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkIC0gcmVhZHMgYnVpbGQtZ2VuZXJhdGVkIHZlcnNpb24gZmlsZVxuICAgKiBEYXRhIHNvdXJjZTogQnVpbGQgc3lzdGVtIG91dHB1dCBmaWxlLCBubyB1c2VyIGlucHV0XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdldEJ1aWxkVGltZXN0YW1wKCk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IF9fZmlsZW5hbWUgPSBmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCk7XG4gICAgICBjb25zdCBfX2Rpcm5hbWUgPSBwYXRoLmRpcm5hbWUoX19maWxlbmFtZSk7XG4gICAgICBcbiAgICAgIC8vIFRyeSBtdWx0aXBsZSBwYXRocyB0byBmaW5kIHZlcnNpb24uanNvblxuICAgICAgLy8gVGhpcyBoYW5kbGVzIGJvdGggbm9ybWFsIGV4ZWN1dGlvbiBhbmQgY29tcGlsZWQgdGVzdCBzY2VuYXJpb3NcbiAgICAgIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdkaXN0JywgJ3ZlcnNpb24uanNvbicpLCAvLyBOb3JtYWwgbG9jYXRpb25cbiAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJy4uJywgJ2Rpc3QnLCAndmVyc2lvbi5qc29uJyksIC8vIFRlc3Qgc2NlbmFyaW9cbiAgICAgICAgcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksICdkaXN0JywgJ3ZlcnNpb24uanNvbicpIC8vIEZhbGxiYWNrIHRvIGN3ZFxuICAgICAgXTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCB2ZXJzaW9uUGF0aCBvZiBwb3NzaWJsZVBhdGhzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHZlcnNpb25QYXRoLCAndXRmLTgnKTtcbiAgICAgICAgICBjb25zdCB2ZXJzaW9uID0gSlNPTi5wYXJzZShjb250ZW50KTtcbiAgICAgICAgICByZXR1cm4gdmVyc2lvbi5idWlsZFRpbWUgfHwgdmVyc2lvbi50aW1lc3RhbXA7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIFRyeSBuZXh0IHBhdGhcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBWZXJzaW9uIGZpbGUgbWlnaHQgbm90IGV4aXN0LCB0aGF0J3Mgb2theVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFZlcnNpb24gZmlsZSBtaWdodCBub3QgZXhpc3QsIHRoYXQncyBva2F5XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTRUNVUklUWSBOT1RFOiBObyBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkIC0gZXhlY3V0ZXMgc3lzdGVtIGdpdCBjb21tYW5kc1xuICAgKiBEYXRhIHNvdXJjZTogR2l0IENMSSBvdXRwdXQgKHN5c3RlbS1jb250cm9sbGVkKSwgbm8gdXNlciBpbnB1dFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRHaXRJbmZvKCk6IFByb21pc2U8eyBjb21taXQ/OiBzdHJpbmc7IGJyYW5jaD86IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFNFQ1VSSVRZIE5PVEU6IEdpdCBjb21tYW5kcyByZXR1cm4gc3lzdGVtLWNvbnRyb2xsZWQgZGF0YSAtIG5vdCB1c2VyIGlucHV0XG4gICAgICAvLyBHaXQgY29tbWl0IGhhc2hlcyBhbmQgYnJhbmNoIG5hbWVzIGFyZSBjb250cm9sbGVkIGJ5IGdpdCwgbm8gVW5pY29kZSBub3JtYWxpemF0aW9uIG5lZWRlZFxuICAgICAgY29uc3QgY29tbWl0ID0gZXhlY1N5bmMoJ2dpdCByZXYtcGFyc2UgLS1zaG9ydCBIRUFEJywgeyBlbmNvZGluZzogJ3V0Zi04JyB9KS50cmltKCk7XG4gICAgICBjb25zdCBicmFuY2ggPSBleGVjU3luYygnZ2l0IHJldi1wYXJzZSAtLWFiYnJldi1yZWYgSEVBRCcsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSkudHJpbSgpO1xuICAgICAgXG4gICAgICByZXR1cm4geyBjb21taXQsIGJyYW5jaCB9O1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTm90IGluIGEgZ2l0IHJlcG9zaXRvcnkgb3IgZ2l0IG5vdCBhdmFpbGFibGVcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU0VDVVJJVFkgTk9URTogTm8gVW5pY29kZSBub3JtYWxpemF0aW9uIG5lZWRlZCAtIHJlYWRzIGNvbnRhaW5lciBydW50aW1lIGZpbGVzXG4gICAqIERhdGEgc291cmNlOiBTeXN0ZW0gY2dyb3VwIGZpbGVzIChjb250YWluZXItY29udHJvbGxlZCksIG5vIHVzZXIgaW5wdXRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0RG9ja2VySW5mbygpOiBQcm9taXNlPHsgaXNEb2NrZXI6IGJvb2xlYW47IGluZm8/OiBzdHJpbmcgfT4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBTRUNVUklUWSBOT1RFOiBSZWFkaW5nIHN5c3RlbSBjZ3JvdXAgZmlsZSAtIGNvbnRyb2xsZWQgYnkgY29udGFpbmVyIHJ1bnRpbWUsIG5vdCB1c2VyIGlucHV0XG4gICAgICAvLyBDb250YWluZXIgcnVudGltZSBnZW5lcmF0ZXMgdGhpcyBmaWxlIGNvbnRlbnQsIG5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBuZWVkZWRcbiAgICAgIGNvbnN0IGNncm91cENvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZSgnL3Byb2MvMS9jZ3JvdXAnLCAndXRmLTgnKTtcbiAgICAgIGNvbnN0IGlzRG9ja2VyID0gY2dyb3VwQ29udGVudC5pbmNsdWRlcygnZG9ja2VyJykgfHwgY2dyb3VwQ29udGVudC5pbmNsdWRlcygnY29udGFpbmVyZCcpO1xuICAgICAgXG4gICAgICBpZiAoaXNEb2NrZXIpIHtcbiAgICAgICAgLy8gVHJ5IHRvIGdldCBjb250YWluZXIgSURcbiAgICAgICAgY29uc3QgY29udGFpbmVySWQgPSBjZ3JvdXBDb250ZW50XG4gICAgICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgICAgIC5maW5kKGxpbmUgPT4gbGluZS5pbmNsdWRlcygnZG9ja2VyJykpXG4gICAgICAgICAgPy5zcGxpdCgnLycpXG4gICAgICAgICAgLnBvcCgpXG4gICAgICAgICAgPy5zdWJzdHJpbmcoMCwgMTIpO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBpc0RvY2tlcjogdHJ1ZSxcbiAgICAgICAgICBpbmZvOiBjb250YWluZXJJZCA/IGBDb250YWluZXIgSUQ6ICR7Y29udGFpbmVySWR9YCA6ICdSdW5uaW5nIGluIERvY2tlcidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHsgaXNEb2NrZXI6IGZhbHNlIH07XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBOb3QgaW4gRG9ja2VyIG9yIC9wcm9jIG5vdCBhdmFpbGFibGVcbiAgICAgIHJldHVybiB7IGlzRG9ja2VyOiBmYWxzZSB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0VXB0aW1lKHNlY29uZHM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgZGF5cyA9IE1hdGguZmxvb3Ioc2Vjb25kcyAvIDg2NDAwKTtcbiAgICBjb25zdCBob3VycyA9IE1hdGguZmxvb3IoKHNlY29uZHMgJSA4NjQwMCkgLyAzNjAwKTtcbiAgICBjb25zdCBtaW51dGVzID0gTWF0aC5mbG9vcigoc2Vjb25kcyAlIDM2MDApIC8gNjApO1xuICAgIGNvbnN0IHNlY3MgPSBNYXRoLmZsb29yKHNlY29uZHMgJSA2MCk7XG4gICAgXG4gICAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW107XG4gICAgaWYgKGRheXMgPiAwKSBwYXJ0cy5wdXNoKGAke2RheXN9ZGApO1xuICAgIGlmIChob3VycyA+IDApIHBhcnRzLnB1c2goYCR7aG91cnN9aGApO1xuICAgIGlmIChtaW51dGVzID4gMCkgcGFydHMucHVzaChgJHttaW51dGVzfW1gKTtcbiAgICBpZiAoc2VjcyA+IDAgfHwgcGFydHMubGVuZ3RoID09PSAwKSBwYXJ0cy5wdXNoKGAke3NlY3N9c2ApO1xuICAgIFxuICAgIHJldHVybiBwYXJ0cy5qb2luKCcgJyk7XG4gIH1cblxuICBwcml2YXRlIGZvcm1hdE1lbW9yeShieXRlczogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBjb25zdCBtYiA9IGJ5dGVzIC8gMTAyNCAvIDEwMjQ7XG4gICAgcmV0dXJuIGAke21iLnRvRml4ZWQoMSl9IE1CYDtcbiAgfVxufSJdfQ==
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter to convert simple portfolio elements to full IElement interface
|
|
3
|
+
* This resolves type safety issues without complex type casting
|
|
4
|
+
*
|
|
5
|
+
* FIXES IMPLEMENTED (PR #503):
|
|
6
|
+
* 1. TYPE SAFETY (Issue #497): Eliminates complex type casting with adapter pattern
|
|
7
|
+
* 2. SECURITY FIX DMCP-SEC-004 (MEDIUM): Added Unicode normalization for all user input
|
|
8
|
+
* 3. SECURITY FIX DMCP-SEC-006 (LOW): Added audit logging for element creation
|
|
9
|
+
* 4. PERFORMANCE: Helper methods for efficient string normalization
|
|
10
|
+
*/
|
|
11
|
+
import { IElement, IElementMetadata, ElementValidationResult, ElementStatus } from '../../types/elements/IElement.js';
|
|
12
|
+
import { ElementType } from '../../portfolio/types.js';
|
|
13
|
+
import { PortfolioElement } from './submitToPortfolioTool.js';
|
|
14
|
+
/**
|
|
15
|
+
* Adapter class that wraps a simple PortfolioElement and implements IElement
|
|
16
|
+
* This allows us to pass portfolio elements to methods expecting IElement
|
|
17
|
+
* without complex type casting
|
|
18
|
+
*/
|
|
19
|
+
export declare class PortfolioElementAdapter implements IElement {
|
|
20
|
+
readonly id: string;
|
|
21
|
+
readonly type: ElementType;
|
|
22
|
+
readonly version: string;
|
|
23
|
+
readonly metadata: IElementMetadata;
|
|
24
|
+
private readonly portfolioElement;
|
|
25
|
+
constructor(element: PortfolioElement);
|
|
26
|
+
/**
|
|
27
|
+
* Helper to normalize string values safely
|
|
28
|
+
*/
|
|
29
|
+
private normalizeString;
|
|
30
|
+
/**
|
|
31
|
+
* Validate the element
|
|
32
|
+
*/
|
|
33
|
+
validate(): ElementValidationResult;
|
|
34
|
+
/**
|
|
35
|
+
* Serialize the element to markdown with YAML frontmatter
|
|
36
|
+
* FIX: Changed from JSON to markdown format for GitHub portfolio compatibility
|
|
37
|
+
* SECURITY FIX #544: Parse and validate existing frontmatter instead of returning as-is
|
|
38
|
+
* SECURITY FIX #543: Use gray-matter for robust frontmatter detection
|
|
39
|
+
*/
|
|
40
|
+
serialize(): string;
|
|
41
|
+
/**
|
|
42
|
+
* Deserialize from string (not implemented for adapter)
|
|
43
|
+
*/
|
|
44
|
+
deserialize(data: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Get element status
|
|
47
|
+
*/
|
|
48
|
+
getStatus(): ElementStatus;
|
|
49
|
+
/**
|
|
50
|
+
* Get the original portfolio element content
|
|
51
|
+
*/
|
|
52
|
+
getContent(): string;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=PortfolioElementAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortfolioElementAdapter.d.ts","sourceRoot":"","sources":["../../../src/tools/portfolio/PortfolioElementAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EAGd,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAQ9D;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,QAAQ;IACtD,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,IAAI,EAAE,WAAW,CAAC;IAClC,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,QAAQ,EAAE,gBAAgB,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,EAAE,gBAAgB;IAsDrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,QAAQ,IAAI,uBAAuB;IAyBnC;;;;;OAKG;IACH,SAAS,IAAI,MAAM;IA2GnB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,SAAS,IAAI,aAAa;IAI1B;;OAEG;IACH,UAAU,IAAI,MAAM;CAGrB"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter to convert simple portfolio elements to full IElement interface
|
|
3
|
+
* This resolves type safety issues without complex type casting
|
|
4
|
+
*
|
|
5
|
+
* FIXES IMPLEMENTED (PR #503):
|
|
6
|
+
* 1. TYPE SAFETY (Issue #497): Eliminates complex type casting with adapter pattern
|
|
7
|
+
* 2. SECURITY FIX DMCP-SEC-004 (MEDIUM): Added Unicode normalization for all user input
|
|
8
|
+
* 3. SECURITY FIX DMCP-SEC-006 (LOW): Added audit logging for element creation
|
|
9
|
+
* 4. PERFORMANCE: Helper methods for efficient string normalization
|
|
10
|
+
*/
|
|
11
|
+
import { ElementStatus } from '../../types/elements/IElement.js';
|
|
12
|
+
import { UnicodeValidator } from '../../security/validators/unicodeValidator.js';
|
|
13
|
+
import { SecurityMonitor } from '../../security/securityMonitor.js';
|
|
14
|
+
import { logger } from '../../utils/logger.js';
|
|
15
|
+
import * as yaml from 'js-yaml';
|
|
16
|
+
import matter from 'gray-matter';
|
|
17
|
+
import { ContentValidator } from '../../security/contentValidator.js';
|
|
18
|
+
/**
|
|
19
|
+
* Adapter class that wraps a simple PortfolioElement and implements IElement
|
|
20
|
+
* This allows us to pass portfolio elements to methods expecting IElement
|
|
21
|
+
* without complex type casting
|
|
22
|
+
*/
|
|
23
|
+
export class PortfolioElementAdapter {
|
|
24
|
+
id;
|
|
25
|
+
type;
|
|
26
|
+
version;
|
|
27
|
+
metadata;
|
|
28
|
+
portfolioElement;
|
|
29
|
+
constructor(element) {
|
|
30
|
+
// SECURITY FIX #2 (DMCP-SEC-004): Normalize and validate all user input
|
|
31
|
+
// Previously: User input was used directly without validation
|
|
32
|
+
// Now: All string inputs go through UnicodeValidator to prevent homograph attacks
|
|
33
|
+
const normalizedName = UnicodeValidator.normalize(element.metadata.name);
|
|
34
|
+
if (!normalizedName.isValid) {
|
|
35
|
+
// Log security event for invalid Unicode
|
|
36
|
+
SecurityMonitor.logSecurityEvent({
|
|
37
|
+
type: 'UNICODE_VALIDATION_ERROR',
|
|
38
|
+
severity: 'MEDIUM',
|
|
39
|
+
source: 'PortfolioElementAdapter.constructor',
|
|
40
|
+
details: `Invalid Unicode in element name: ${normalizedName.detectedIssues?.[0] || 'unknown'}`
|
|
41
|
+
});
|
|
42
|
+
logger.warn('Invalid Unicode detected in element name', {
|
|
43
|
+
issues: normalizedName.detectedIssues
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
this.portfolioElement = element;
|
|
47
|
+
this.type = element.type;
|
|
48
|
+
this.version = element.metadata.version || '1.0.0';
|
|
49
|
+
// Generate ID from type and normalized name
|
|
50
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
51
|
+
const safeName = normalizedName.normalizedContent || element.metadata.name;
|
|
52
|
+
const nameSlug = safeName.toLowerCase().replace(/\s+/g, '-');
|
|
53
|
+
this.id = `${element.type}_${nameSlug}_${timestamp}`;
|
|
54
|
+
// Convert metadata to IElementMetadata format with normalized values
|
|
55
|
+
this.metadata = {
|
|
56
|
+
name: safeName,
|
|
57
|
+
description: this.normalizeString(element.metadata.description || ''),
|
|
58
|
+
author: this.normalizeString(element.metadata.author || ''),
|
|
59
|
+
version: element.metadata.version,
|
|
60
|
+
created: element.metadata.created,
|
|
61
|
+
modified: element.metadata.updated,
|
|
62
|
+
tags: []
|
|
63
|
+
};
|
|
64
|
+
// SECURITY FIX #3 (DMCP-SEC-006): Log element creation for audit trail
|
|
65
|
+
// Previously: No audit logging for portfolio operations
|
|
66
|
+
// Now: Complete audit trail using SecurityMonitor.logSecurityEvent()
|
|
67
|
+
SecurityMonitor.logSecurityEvent({
|
|
68
|
+
type: 'ELEMENT_CREATED',
|
|
69
|
+
severity: 'LOW',
|
|
70
|
+
source: 'PortfolioElementAdapter.constructor',
|
|
71
|
+
details: `Created portfolio element adapter: ${this.id}`,
|
|
72
|
+
metadata: {
|
|
73
|
+
elementType: this.type,
|
|
74
|
+
elementId: this.id
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Helper to normalize string values safely
|
|
80
|
+
*/
|
|
81
|
+
normalizeString(value) {
|
|
82
|
+
if (!value)
|
|
83
|
+
return value;
|
|
84
|
+
const normalized = UnicodeValidator.normalize(value);
|
|
85
|
+
return normalized.normalizedContent || value;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Validate the element
|
|
89
|
+
*/
|
|
90
|
+
validate() {
|
|
91
|
+
const errors = [];
|
|
92
|
+
const warnings = [];
|
|
93
|
+
if (!this.metadata.name) {
|
|
94
|
+
errors.push({
|
|
95
|
+
field: 'name',
|
|
96
|
+
message: 'Element name is required'
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (!this.portfolioElement.content) {
|
|
100
|
+
errors.push({
|
|
101
|
+
field: 'content',
|
|
102
|
+
message: 'Element content is required'
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
valid: errors.length === 0,
|
|
107
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
108
|
+
warnings: warnings.length > 0 ? warnings : undefined
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Serialize the element to markdown with YAML frontmatter
|
|
113
|
+
* FIX: Changed from JSON to markdown format for GitHub portfolio compatibility
|
|
114
|
+
* SECURITY FIX #544: Parse and validate existing frontmatter instead of returning as-is
|
|
115
|
+
* SECURITY FIX #543: Use gray-matter for robust frontmatter detection
|
|
116
|
+
*/
|
|
117
|
+
serialize() {
|
|
118
|
+
// SECURITY FIX #543: Use gray-matter for robust frontmatter detection
|
|
119
|
+
// This handles different line endings, whitespace variations, and malformed YAML
|
|
120
|
+
let contentToProcess = this.portfolioElement.content;
|
|
121
|
+
let existingMetadata = {};
|
|
122
|
+
let bodyContent = contentToProcess;
|
|
123
|
+
// Try to parse existing frontmatter if present
|
|
124
|
+
try {
|
|
125
|
+
// gray-matter handles all edge cases:
|
|
126
|
+
// - Different line endings (\n, \r\n)
|
|
127
|
+
// - Whitespace variations
|
|
128
|
+
// - Malformed YAML (returns empty data object)
|
|
129
|
+
// - Missing closing delimiter
|
|
130
|
+
const parsed = matter(contentToProcess);
|
|
131
|
+
if (parsed.data && Object.keys(parsed.data).length > 0) {
|
|
132
|
+
// SECURITY FIX #544: Validate existing frontmatter instead of bypassing
|
|
133
|
+
logger.debug('Found existing frontmatter, validating before merge');
|
|
134
|
+
// Validate the parsed frontmatter
|
|
135
|
+
const validationResult = ContentValidator.validateAndSanitize(yaml.dump(parsed.data));
|
|
136
|
+
if (!validationResult.isValid && validationResult.severity === 'critical') {
|
|
137
|
+
// Log security event for malicious frontmatter
|
|
138
|
+
SecurityMonitor.logSecurityEvent({
|
|
139
|
+
type: 'CONTENT_INJECTION_ATTEMPT',
|
|
140
|
+
severity: 'HIGH',
|
|
141
|
+
source: 'PortfolioElementAdapter.serialize',
|
|
142
|
+
details: `Critical security issues in frontmatter: ${validationResult.detectedPatterns?.join(', ')}`,
|
|
143
|
+
metadata: {
|
|
144
|
+
elementId: this.id,
|
|
145
|
+
elementType: this.type
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
// Don't use the malicious frontmatter, create new
|
|
149
|
+
existingMetadata = {};
|
|
150
|
+
bodyContent = contentToProcess; // Use original content
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// Frontmatter is safe, merge with our metadata
|
|
154
|
+
existingMetadata = parsed.data;
|
|
155
|
+
bodyContent = parsed.content;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
// If gray-matter fails to parse, treat as content without frontmatter
|
|
161
|
+
logger.warn('Failed to parse potential frontmatter, treating as plain content', {
|
|
162
|
+
error: error instanceof Error ? error.message : String(error)
|
|
163
|
+
});
|
|
164
|
+
// Continue with empty metadata and full content
|
|
165
|
+
}
|
|
166
|
+
// Merge metadata, with our metadata taking precedence for security
|
|
167
|
+
// This ensures critical fields like ID and type are always from our validated source
|
|
168
|
+
const mergedMetadata = {
|
|
169
|
+
...existingMetadata, // Existing metadata first
|
|
170
|
+
...this.metadata, // Our validated metadata overwrites
|
|
171
|
+
id: this.id, // Always use our ID
|
|
172
|
+
type: this.type, // Always use our type
|
|
173
|
+
version: this.version // Always use our version
|
|
174
|
+
};
|
|
175
|
+
// Validate the final merged metadata
|
|
176
|
+
const metadataYaml = yaml.dump(mergedMetadata, {
|
|
177
|
+
noRefs: true,
|
|
178
|
+
sortKeys: false,
|
|
179
|
+
lineWidth: -1
|
|
180
|
+
});
|
|
181
|
+
// Final security check on the complete metadata
|
|
182
|
+
const finalValidation = ContentValidator.validateAndSanitize(metadataYaml);
|
|
183
|
+
if (!finalValidation.isValid && finalValidation.severity === 'critical') {
|
|
184
|
+
// This shouldn't happen with our sanitized data, but log if it does
|
|
185
|
+
SecurityMonitor.logSecurityEvent({
|
|
186
|
+
type: 'UNICODE_VALIDATION_ERROR',
|
|
187
|
+
severity: 'MEDIUM',
|
|
188
|
+
source: 'PortfolioElementAdapter.serialize',
|
|
189
|
+
details: 'Final metadata validation failed after merge',
|
|
190
|
+
metadata: { elementId: this.id }
|
|
191
|
+
});
|
|
192
|
+
// Fall back to minimal safe metadata
|
|
193
|
+
const safeMetadata = {
|
|
194
|
+
id: this.id,
|
|
195
|
+
type: this.type,
|
|
196
|
+
version: this.version,
|
|
197
|
+
name: this.normalizeString(this.metadata.name || 'Untitled'),
|
|
198
|
+
description: this.normalizeString(this.metadata.description || '')
|
|
199
|
+
};
|
|
200
|
+
const safeFrontmatter = yaml.dump(safeMetadata, {
|
|
201
|
+
noRefs: true,
|
|
202
|
+
sortKeys: false,
|
|
203
|
+
lineWidth: -1
|
|
204
|
+
});
|
|
205
|
+
return `---\n${safeFrontmatter}---\n\n${bodyContent}`;
|
|
206
|
+
}
|
|
207
|
+
// Return validated and sanitized markdown with frontmatter
|
|
208
|
+
return `---\n${metadataYaml}---\n\n${bodyContent}`;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Deserialize from string (not implemented for adapter)
|
|
212
|
+
*/
|
|
213
|
+
deserialize(data) {
|
|
214
|
+
throw new Error('Deserialization not supported for PortfolioElementAdapter');
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Get element status
|
|
218
|
+
*/
|
|
219
|
+
getStatus() {
|
|
220
|
+
return ElementStatus.INACTIVE;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get the original portfolio element content
|
|
224
|
+
*/
|
|
225
|
+
getContent() {
|
|
226
|
+
return this.portfolioElement.content;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdG9vbHMvcG9ydGZvbGlvL1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sRUFJTCxhQUFhLEVBR2QsTUFBTSxrQ0FBa0MsQ0FBQztBQUcxQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUNqRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sS0FBSyxJQUFJLE1BQU0sU0FBUyxDQUFDO0FBQ2hDLE9BQU8sTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUNqQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUV0RTs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLHVCQUF1QjtJQUNsQixFQUFFLENBQVM7SUFDWCxJQUFJLENBQWM7SUFDbEIsT0FBTyxDQUFTO0lBQ2hCLFFBQVEsQ0FBbUI7SUFDMUIsZ0JBQWdCLENBQW1CO0lBRXBELFlBQVksT0FBeUI7UUFDbkMsd0VBQXdFO1FBQ3hFLDhEQUE4RDtRQUM5RCxrRkFBa0Y7UUFDbEYsTUFBTSxjQUFjLEdBQUcsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM1Qix5Q0FBeUM7WUFDekMsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsMEJBQTBCO2dCQUNoQyxRQUFRLEVBQUUsUUFBUTtnQkFDbEIsTUFBTSxFQUFFLHFDQUFxQztnQkFDN0MsT0FBTyxFQUFFLG9DQUFvQyxjQUFjLENBQUMs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QUM7WUFFRixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRTtnQkFDOUMsTUFBTSxFQUFFLElBQUk7Z0JBQ1osUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsU0FBUyxFQUFFLENBQUMsQ0FBQzthQUNkLENBQUMsQ0FBQztZQUVILE9BQU8sUUFBUSxlQUFlLFVBQVUsV0FBVyxFQUFFLENBQUM7UUFDeEQsQ0FBQztRQUVELDJEQUEyRDtRQUMzRCxPQUFPLFFBQVEsWUFBWSxVQUFVLFdBQVcsRUFBRSxDQUFDO0lBQ3JELENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVcsQ0FBQyxJQUFZO1FBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxTQUFTO1FBQ1AsT0FBTyxhQUFhLENBQUMsUUFBUSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNILFVBQVU7UUFDUixPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUM7SUFDdkMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBZGFwdGVyIHRvIGNvbnZlcnQgc2ltcGxlIHBvcnRmb2xpbyBlbGVtZW50cyB0byBmdWxsIElFbGVtZW50IGludGVyZmFjZVxuICogVGhpcyByZXNvbHZlcyB0eXBlIHNhZmV0eSBpc3N1ZXMgd2l0aG91dCBjb21wbGV4IHR5cGUgY2FzdGluZ1xuICogXG4gKiBGSVhFUyBJTVBMRU1FTlRFRCAoUFIgIzUwMyk6XG4gKiAxLiBUWVBFIFNBRkVUWSAoSXNzdWUgIzQ5Nyk6IEVsaW1pbmF0ZXMgY29tcGxleCB0eXBlIGNhc3Rpbmcgd2l0aCBhZGFwdGVyIHBhdHRlcm5cbiAqIDIuIFNFQ1VSSVRZIEZJWCBETUNQLVNFQy0wMDQgKE1FRElVTSk6IEFkZGVkIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBmb3IgYWxsIHVzZXIgaW5wdXRcbiAqIDMuIFNFQ1VSSVRZIEZJWCBETUNQLVNFQy0wMDYgKExPVyk6IEFkZGVkIGF1ZGl0IGxvZ2dpbmcgZm9yIGVsZW1lbnQgY3JlYXRpb25cbiAqIDQuIFBFUkZPUk1BTkNFOiBIZWxwZXIgbWV0aG9kcyBmb3IgZWZmaWNpZW50IHN0cmluZyBub3JtYWxpemF0aW9uXG4gKi9cblxuaW1wb3J0IHsgXG4gIElFbGVtZW50LCBcbiAgSUVsZW1lbnRNZXRhZGF0YSwgXG4gIEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0LCBcbiAgRWxlbWVudFN0YXR1cyxcbiAgVmFsaWRhdGlvbkVycm9yLFxuICBWYWxpZGF0aW9uV2FybmluZ1xufSBmcm9tICcuLi8uLi90eXBlcy9lbGVtZW50cy9JRWxlbWVudC5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uLy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBQb3J0Zm9saW9FbGVtZW50IH0gZnJvbSAnLi9zdWJtaXRUb1BvcnRmb2xpb1Rvb2wuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgbWF0dGVyIGZyb20gJ2dyYXktbWF0dGVyJztcbmltcG9ydCB7IENvbnRlbnRWYWxpZGF0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9jb250ZW50VmFsaWRhdG9yLmpzJztcblxuLyoqXG4gKiBBZGFwdGVyIGNsYXNzIHRoYXQgd3JhcHMgYSBzaW1wbGUgUG9ydGZvbGlvRWxlbWVudCBhbmQgaW1wbGVtZW50cyBJRWxlbWVudFxuICogVGhpcyBhbGxvd3MgdXMgdG8gcGFzcyBwb3J0Zm9saW8gZWxlbWVudHMgdG8gbWV0aG9kcyBleHBlY3RpbmcgSUVsZW1lbnRcbiAqIHdpdGhvdXQgY29tcGxleCB0eXBlIGNhc3RpbmdcbiAqL1xuZXhwb3J0IGNsYXNzIFBvcnRmb2xpb0VsZW1lbnRBZGFwdGVyIGltcGxlbWVudHMgSUVsZW1lbnQge1xuICBwdWJsaWMgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IHR5cGU6IEVsZW1lbnRUeXBlO1xuICBwdWJsaWMgcmVhZG9ubHkgdmVyc2lvbjogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgbWV0YWRhdGE6IElFbGVtZW50TWV0YWRhdGE7XG4gIHByaXZhdGUgcmVhZG9ubHkgcG9ydGZvbGlvRWxlbWVudDogUG9ydGZvbGlvRWxlbWVudDtcblxuICBjb25zdHJ1Y3RvcihlbGVtZW50OiBQb3J0Zm9saW9FbGVtZW50KSB7XG4gICAgLy8gU0VDVVJJVFkgRklYICMyIChETUNQLVNFQy0wMDQpOiBOb3JtYWxpemUgYW5kIHZhbGlkYXRlIGFsbCB1c2VyIGlucHV0XG4gICAgLy8gUHJldmlvdXNseTogVXNlciBpbnB1dCB3YXMgdXNlZCBkaXJlY3RseSB3aXRob3V0IHZhbGlkYXRpb25cbiAgICAvLyBOb3c6IEFsbCBzdHJpbmcgaW5wdXRzIGdvIHRocm91Z2ggVW5pY29kZVZhbGlkYXRvciB0byBwcmV2ZW50IGhvbW9ncmFwaCBhdHRhY2tzXG4gICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShlbGVtZW50Lm1ldGFkYXRhLm5hbWUpO1xuICAgIGlmICghbm9ybWFsaXplZE5hbWUuaXNWYWxpZCkge1xuICAgICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBpbnZhbGlkIFVuaWNvZGVcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1VOSUNPREVfVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuY29uc3RydWN0b3InLFxuICAgICAgICBkZXRhaWxzOiBgSW52YWxpZCBVbmljb2RlIGluIGVsZW1lbnQgbmFtZTogJHtub3JtYWxpemVkTmFtZS5kZXRlY3RlZElzc3Vlcz8uWzBdIHx8ICd1bmtub3duJ31gXG4gICAgICB9KTtcbiAgICAgIGxvZ2dlci53YXJuKCdJbnZhbGlkIFVuaWNvZGUgZGV0ZWN0ZWQgaW4gZWxlbWVudCBuYW1lJywge1xuICAgICAgICBpc3N1ZXM6IG5vcm1hbGl6ZWROYW1lLmRldGVjdGVkSXNzdWVzXG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgdGhpcy5wb3J0Zm9saW9FbGVtZW50ID0gZWxlbWVudDtcbiAgICB0aGlzLnR5cGUgPSBlbGVtZW50LnR5cGU7XG4gICAgdGhpcy52ZXJzaW9uID0gZWxlbWVudC5tZXRhZGF0YS52ZXJzaW9uIHx8ICcxLjAuMCc7XG4gICAgXG4gICAgLy8gR2VuZXJhdGUgSUQgZnJvbSB0eXBlIGFuZCBub3JtYWxpemVkIG5hbWVcbiAgICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvWzouXS9nLCAnLScpO1xuICAgIGNvbnN0IHNhZmVOYW1lID0gbm9ybWFsaXplZE5hbWUubm9ybWFsaXplZENvbnRlbnQgfHwgZWxlbWVudC5tZXRhZGF0YS5uYW1lO1xuICAgIGNvbnN0IG5hbWVTbHVnID0gc2FmZU5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9cXHMrL2csICctJyk7XG4gICAgdGhpcy5pZCA9IGAke2VsZW1lbnQudHlwZX1fJHtuYW1lU2x1Z31fJHt0aW1lc3RhbXB9YDtcbiAgICBcbiAgICAvLyBDb252ZXJ0IG1ldGFkYXRhIHRvIElFbGVtZW50TWV0YWRhdGEgZm9ybWF0IHdpdGggbm9ybWFsaXplZCB2YWx1ZXNcbiAgICB0aGlzLm1ldGFkYXRhID0ge1xuICAgICAgbmFtZTogc2FmZU5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogdGhpcy5ub3JtYWxpemVTdHJpbmcoZWxlbWVudC5tZXRhZGF0YS5kZXNjcmlwdGlvbiB8fCAnJyksXG4gICAgICBhdXRob3I6IHRoaXMubm9ybWFsaXplU3RyaW5nKGVsZW1lbnQubWV0YWRhdGEuYXV0aG9yIHx8ICcnKSxcbiAgICAgIHZlcnNpb246IGVsZW1lbnQubWV0YWRhdGEudmVyc2lvbixcbiAgICAgIGNyZWF0ZWQ6IGVsZW1lbnQubWV0YWRhdGEuY3JlYXRlZCxcbiAgICAgIG1vZGlmaWVkOiBlbGVtZW50Lm1ldGFkYXRhLnVwZGF0ZWQsXG4gICAgICB0YWdzOiBbXVxuICAgIH07XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYICMzIChETUNQLVNFQy0wMDYpOiBMb2cgZWxlbWVudCBjcmVhdGlvbiBmb3IgYXVkaXQgdHJhaWxcbiAgICAvLyBQcmV2aW91c2x5OiBObyBhdWRpdCBsb2dnaW5nIGZvciBwb3J0Zm9saW8gb3BlcmF0aW9uc1xuICAgIC8vIE5vdzogQ29tcGxldGUgYXVkaXQgdHJhaWwgdXNpbmcgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoKVxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdFTEVNRU5UX0NSRUFURUQnLFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuY29uc3RydWN0b3InLFxuICAgICAgZGV0YWlsczogYENyZWF0ZWQgcG9ydGZvbGlvIGVsZW1lbnQgYWRhcHRlcjogJHt0aGlzLmlkfWAsXG4gICAgICBtZXRhZGF0YToge1xuICAgICAgICBlbGVtZW50VHlwZTogdGhpcy50eXBlLFxuICAgICAgICBlbGVtZW50SWQ6IHRoaXMuaWRcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEhlbHBlciB0byBub3JtYWxpemUgc3RyaW5nIHZhbHVlcyBzYWZlbHlcbiAgICovXG4gIHByaXZhdGUgbm9ybWFsaXplU3RyaW5nKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICghdmFsdWUpIHJldHVybiB2YWx1ZTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUodmFsdWUpO1xuICAgIHJldHVybiBub3JtYWxpemVkLm5vcm1hbGl6ZWRDb250ZW50IHx8IHZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoZSBlbGVtZW50XG4gICAqL1xuICB2YWxpZGF0ZSgpOiBFbGVtZW50VmFsaWRhdGlvblJlc3VsdCB7XG4gICAgY29uc3QgZXJyb3JzOiBWYWxpZGF0aW9uRXJyb3JbXSA9IFtdO1xuICAgIGNvbnN0IHdhcm5pbmdzOiBWYWxpZGF0aW9uV2FybmluZ1tdID0gW107XG5cbiAgICBpZiAoIXRoaXMubWV0YWRhdGEubmFtZSkge1xuICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICBmaWVsZDogJ25hbWUnLFxuICAgICAgICBtZXNzYWdlOiAnRWxlbWVudCBuYW1lIGlzIHJlcXVpcmVkJ1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmICghdGhpcy5wb3J0Zm9saW9FbGVtZW50LmNvbnRlbnQpIHtcbiAgICAgIGVycm9ycy5wdXNoKHtcbiAgICAgICAgZmllbGQ6ICdjb250ZW50JyxcbiAgICAgICAgbWVzc2FnZTogJ0VsZW1lbnQgY29udGVudCBpcyByZXF1aXJlZCdcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICB2YWxpZDogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9yczogZXJyb3JzLmxlbmd0aCA+IDAgPyBlcnJvcnMgOiB1bmRlZmluZWQsXG4gICAgICB3YXJuaW5nczogd2FybmluZ3MubGVuZ3RoID4gMCA/IHdhcm5pbmdzIDogdW5kZWZpbmVkXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXJpYWxpemUgdGhlIGVsZW1lbnQgdG8gbWFya2Rvd24gd2l0aCBZQU1MIGZyb250bWF0dGVyXG4gICAqIEZJWDogQ2hhbmdlZCBmcm9tIEpTT04gdG8gbWFya2Rvd24gZm9ybWF0IGZvciBHaXRIdWIgcG9ydGZvbGlvIGNvbXBhdGliaWxpdHlcbiAgICogU0VDVVJJVFkgRklYICM1NDQ6IFBhcnNlIGFuZCB2YWxpZGF0ZSBleGlzdGluZyBmcm9udG1hdHRlciBpbnN0ZWFkIG9mIHJldHVybmluZyBhcy1pc1xuICAgKiBTRUNVUklUWSBGSVggIzU0MzogVXNlIGdyYXktbWF0dGVyIGZvciByb2J1c3QgZnJvbnRtYXR0ZXIgZGV0ZWN0aW9uXG4gICAqL1xuICBzZXJpYWxpemUoKTogc3RyaW5nIHtcbiAgICAvLyBTRUNVUklUWSBGSVggIzU0MzogVXNlIGdyYXktbWF0dGVyIGZvciByb2J1c3QgZnJvbnRtYXR0ZXIgZGV0ZWN0aW9uXG4gICAgLy8gVGhpcyBoYW5kbGVzIGRpZmZlcmVudCBsaW5lIGVuZGluZ3MsIHdoaXRlc3BhY2UgdmFyaWF0aW9ucywgYW5kIG1hbGZvcm1lZCBZQU1MXG4gICAgbGV0IGNvbnRlbnRUb1Byb2Nlc3MgPSB0aGlzLnBvcnRmb2xpb0VsZW1lbnQuY29udGVudDtcbiAgICBsZXQgZXhpc3RpbmdNZXRhZGF0YTogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIGxldCBib2R5Q29udGVudCA9IGNvbnRlbnRUb1Byb2Nlc3M7XG4gICAgXG4gICAgLy8gVHJ5IHRvIHBhcnNlIGV4aXN0aW5nIGZyb250bWF0dGVyIGlmIHByZXNlbnRcbiAgICB0cnkge1xuICAgICAgLy8gZ3JheS1tYXR0ZXIgaGFuZGxlcyBhbGwgZWRnZSBjYXNlczpcbiAgICAgIC8vIC0gRGlmZmVyZW50IGxpbmUgZW5kaW5ncyAoXFxuLCBcXHJcXG4pXG4gICAgICAvLyAtIFdoaXRlc3BhY2UgdmFyaWF0aW9uc1xuICAgICAgLy8gLSBNYWxmb3JtZWQgWUFNTCAocmV0dXJucyBlbXB0eSBkYXRhIG9iamVjdClcbiAgICAgIC8vIC0gTWlzc2luZyBjbG9zaW5nIGRlbGltaXRlclxuICAgICAgY29uc3QgcGFyc2VkID0gbWF0dGVyKGNvbnRlbnRUb1Byb2Nlc3MpO1xuICAgICAgXG4gICAgICBpZiAocGFyc2VkLmRhdGEgJiYgT2JqZWN0LmtleXMocGFyc2VkLmRhdGEpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgLy8gU0VDVVJJVFkgRklYICM1NDQ6IFZhbGlkYXRlIGV4aXN0aW5nIGZyb250bWF0dGVyIGluc3RlYWQgb2YgYnlwYXNzaW5nXG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnRm91bmQgZXhpc3RpbmcgZnJvbnRtYXR0ZXIsIHZhbGlkYXRpbmcgYmVmb3JlIG1lcmdlJyk7XG4gICAgICAgIFxuICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgcGFyc2VkIGZyb250bWF0dGVyXG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUoXG4gICAgICAgICAgeWFtbC5kdW1wKHBhcnNlZC5kYXRhKVxuICAgICAgICApO1xuICAgICAgICBcbiAgICAgICAgaWYgKCF2YWxpZGF0aW9uUmVzdWx0LmlzVmFsaWQgJiYgdmFsaWRhdGlvblJlc3VsdC5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgbWFsaWNpb3VzIGZyb250bWF0dGVyXG4gICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogJ0NPTlRFTlRfSU5KRUNUSU9OX0FUVEVNUFQnLFxuICAgICAgICAgICAgc2V2ZXJpdHk6ICdISUdIJyxcbiAgICAgICAgICAgIHNvdXJjZTogJ1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLnNlcmlhbGl6ZScsXG4gICAgICAgICAgICBkZXRhaWxzOiBgQ3JpdGljYWwgc2VjdXJpdHkgaXNzdWVzIGluIGZyb250bWF0dGVyOiAke3ZhbGlkYXRpb25SZXN1bHQuZGV0ZWN0ZWRQYXR0ZXJucz8uam9pbignLCAnKX1gLFxuICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgZWxlbWVudElkOiB0aGlzLmlkLFxuICAgICAgICAgICAgICBlbGVtZW50VHlwZTogdGhpcy50eXBlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gRG9uJ3QgdXNlIHRoZSBtYWxpY2lvdXMgZnJvbnRtYXR0ZXIsIGNyZWF0ZSBuZXdcbiAgICAgICAgICBleGlzdGluZ01ldGFkYXRhID0ge307XG4gICAgICAgICAgYm9keUNvbnRlbnQgPSBjb250ZW50VG9Qcm9jZXNzOyAvLyBVc2Ugb3JpZ2luYWwgY29udGVudFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIEZyb250bWF0dGVyIGlzIHNhZmUsIG1lcmdlIHdpdGggb3VyIG1ldGFkYXRhXG4gICAgICAgICAgZXhpc3RpbmdNZXRhZGF0YSA9IHBhcnNlZC5kYXRhO1xuICAgICAgICAgIGJvZHlDb250ZW50ID0gcGFyc2VkLmNvbnRlbnQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gSWYgZ3JheS1tYXR0ZXIgZmFpbHMgdG8gcGFyc2UsIHRyZWF0IGFzIGNvbnRlbnQgd2l0aG91dCBmcm9udG1hdHRlclxuICAgICAgbG9nZ2VyLndhcm4oJ0ZhaWxlZCB0byBwYXJzZSBwb3RlbnRpYWwgZnJvbnRtYXR0ZXIsIHRyZWF0aW5nIGFzIHBsYWluIGNvbnRlbnQnLCB7XG4gICAgICAgIGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcilcbiAgICAgIH0pO1xuICAgICAgLy8gQ29udGludWUgd2l0aCBlbXB0eSBtZXRhZGF0YSBhbmQgZnVsbCBjb250ZW50XG4gICAgfVxuICAgIFxuICAgIC8vIE1lcmdlIG1ldGFkYXRhLCB3aXRoIG91ciBtZXRhZGF0YSB0YWtpbmcgcHJlY2VkZW5jZSBmb3Igc2VjdXJpdHlcbiAgICAvLyBUaGlzIGVuc3VyZXMgY3JpdGljYWwgZmllbGRzIGxpa2UgSUQgYW5kIHR5cGUgYXJlIGFsd2F5cyBmcm9tIG91ciB2YWxpZGF0ZWQgc291cmNlXG4gICAgY29uc3QgbWVyZ2VkTWV0YWRhdGEgPSB7XG4gICAgICAuLi5leGlzdGluZ01ldGFkYXRhLCAvLyBFeGlzdGluZyBtZXRhZGF0YSBmaXJzdFxuICAgICAgLi4udGhpcy5tZXRhZGF0YSwgICAgLy8gT3VyIHZhbGlkYXRlZCBtZXRhZGF0YSBvdmVyd3JpdGVzXG4gICAgICBpZDogdGhpcy5pZCwgICAgICAgICAvLyBBbHdheXMgdXNlIG91ciBJRFxuICAgICAgdHlwZTogdGhpcy50eXBlLCAgICAgLy8gQWx3YXlzIHVzZSBvdXIgdHlwZVxuICAgICAgdmVyc2lvbjogdGhpcy52ZXJzaW9uIC8vIEFsd2F5cyB1c2Ugb3VyIHZlcnNpb25cbiAgICB9O1xuICAgIFxuICAgIC8vIFZhbGlkYXRlIHRoZSBmaW5hbCBtZXJnZWQgbWV0YWRhdGFcbiAgICBjb25zdCBtZXRhZGF0YVlhbWwgPSB5YW1sLmR1bXAobWVyZ2VkTWV0YWRhdGEsIHtcbiAgICAgIG5vUmVmczogdHJ1ZSxcbiAgICAgIHNvcnRLZXlzOiBmYWxzZSxcbiAgICAgIGxpbmVXaWR0aDogLTFcbiAgICB9KTtcbiAgICBcbiAgICAvLyBGaW5hbCBzZWN1cml0eSBjaGVjayBvbiB0aGUgY29tcGxldGUgbWV0YWRhdGFcbiAgICBjb25zdCBmaW5hbFZhbGlkYXRpb24gPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUobWV0YWRhdGFZYW1sKTtcbiAgICBcbiAgICBpZiAoIWZpbmFsVmFsaWRhdGlvbi5pc1ZhbGlkICYmIGZpbmFsVmFsaWRhdGlvbi5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgLy8gVGhpcyBzaG91bGRuJ3QgaGFwcGVuIHdpdGggb3VyIHNhbml0aXplZCBkYXRhLCBidXQgbG9nIGlmIGl0IGRvZXNcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1VOSUNPREVfVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuc2VyaWFsaXplJyxcbiAgICAgICAgZGV0YWlsczogJ0ZpbmFsIG1ldGFkYXRhIHZhbGlkYXRpb24gZmFpbGVkIGFmdGVyIG1lcmdlJyxcbiAgICAgICAgbWV0YWRhdGE6IHsgZWxlbWVudElkOiB0aGlzLmlkIH1cbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBGYWxsIGJhY2sgdG8gbWluaW1hbCBzYWZlIG1ldGFkYXRhXG4gICAgICBjb25zdCBzYWZlTWV0YWRhdGEgPSB7XG4gICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICAgIHZlcnNpb246IHRoaXMudmVyc2lvbixcbiAgICAgICAgbmFtZTogdGhpcy5ub3JtYWxpemVTdHJpbmcodGhpcy5tZXRhZGF0YS5uYW1lIHx8ICdVbnRpdGxlZCcpLFxuICAgICAgICBkZXNjcmlwdGlvbjogdGhpcy5ub3JtYWxpemVTdHJpbmcodGhpcy5tZXRhZGF0YS5kZXNjcmlwdGlvbiB8fCAnJylcbiAgICAgIH07XG4gICAgICBcbiAgICAgIGNvbnN0IHNhZmVGcm9udG1hdHRlciA9IHlhbWwuZHVtcChzYWZlTWV0YWRhdGEsIHtcbiAgICAgICAgbm9SZWZzOiB0cnVlLFxuICAgICAgICBzb3J0S2V5czogZmFsc2UsXG4gICAgICAgIGxpbmVXaWR0aDogLTFcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICByZXR1cm4gYC0tLVxcbiR7c2FmZUZyb250bWF0dGVyfS0tLVxcblxcbiR7Ym9keUNvbnRlbnR9YDtcbiAgICB9XG4gICAgXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBhbmQgc2FuaXRpemVkIG1hcmtkb3duIHdpdGggZnJvbnRtYXR0ZXJcbiAgICByZXR1cm4gYC0tLVxcbiR7bWV0YWRhdGFZYW1sfS0tLVxcblxcbiR7Ym9keUNvbnRlbnR9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNlcmlhbGl6ZSBmcm9tIHN0cmluZyAobm90IGltcGxlbWVudGVkIGZvciBhZGFwdGVyKVxuICAgKi9cbiAgZGVzZXJpYWxpemUoZGF0YTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdEZXNlcmlhbGl6YXRpb24gbm90IHN1cHBvcnRlZCBmb3IgUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXInKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZWxlbWVudCBzdGF0dXNcbiAgICovXG4gIGdldFN0YXR1cygpOiBFbGVtZW50U3RhdHVzIHtcbiAgICByZXR1cm4gRWxlbWVudFN0YXR1cy5JTkFDVElWRTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIG9yaWdpbmFsIHBvcnRmb2xpbyBlbGVtZW50IGNvbnRlbnRcbiAgICovXG4gIGdldENvbnRlbnQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wb3J0Zm9saW9FbGVtZW50LmNvbnRlbnQ7XG4gIH1cbn0iXX0=
|