vulnmatter-extension
Version:
VS Code extension for CVE vulnerability analysis using the VulnMatter API with X-API-Key. See CHANGELOG.md for release notes.
390 lines (359 loc) • 14.1 kB
JavaScript
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ([
/* 0 */
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.activate = activate;
exports.getStoredApiKey = getStoredApiKey;
exports.deactivate = deactivate;
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = __importStar(__webpack_require__(1));
// This method is called when your extension is activated
// Your extension is activated the very first time the command is executed
function activate(context) {
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "vulnmatter-cli" is now active!');
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
const disposable = vscode.commands.registerCommand('vulnmatter-cli.helloWorld', () => {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World from Mi Primera Extension!');
});
// Command to configure API Key
const configureApiKeyDisposable = vscode.commands.registerCommand('vulnmatter-cli.configureApiKey', () => {
createApiKeyConfigPanel(context);
});
// Command to test MCP connection (example usage of stored API key)
const testMcpConnectionDisposable = vscode.commands.registerCommand('vulnmatter-cli.testMcpConnection', async () => {
const apiKey = await getStoredApiKey(context);
if (apiKey) {
vscode.window.showInformationMessage(`MCP Connection Test: API Key found (${apiKey.substring(0, 8)}...)`);
// Here you would implement the actual MCP connection logic
console.log('API Key available for MCP connection:', apiKey.substring(0, 8) + '...');
}
else {
const result = await vscode.window.showWarningMessage('No API Key configured. Would you like to configure it now?', 'Configure API Key');
if (result === 'Configure API Key') {
vscode.commands.executeCommand('vulnmatter-cli.configureApiKey');
}
}
});
context.subscriptions.push(disposable);
context.subscriptions.push(configureApiKeyDisposable);
context.subscriptions.push(testMcpConnectionDisposable);
}
function createApiKeyConfigPanel(context) {
// Create and show a new webview panel
const panel = vscode.window.createWebviewPanel('apiKeyConfig', // Identifies the type of the webview
'Configure X-API-Key', // Title of the panel displayed to the user
vscode.ViewColumn.One, // Editor column to show the new webview panel in
{
// Enable scripts in the webview
enableScripts: true,
// Restrict the webview to only load content from our extension's directory
localResourceRoots: [context.extensionUri]
});
// Set the HTML content for the webview with strict CSP and nonce
panel.webview.html = getWebviewContent(panel.webview);
// Handle messages from the webview
panel.webview.onDidReceiveMessage(async (message) => {
switch (message.command) {
case 'saveApiKey':
if (message.apiKey && message.apiKey.trim()) {
// Store the API key securely
await context.secrets.store('vulnmatter.x-api-key', message.apiKey.trim());
vscode.window.showInformationMessage('X-API-Key saved successfully!');
panel.dispose();
}
else {
vscode.window.showErrorMessage('Please enter a valid API key');
}
break;
case 'loadApiKey':
// Load existing API key (if any) and send it to the webview
const existingKey = await context.secrets.get('vulnmatter.x-api-key');
panel.webview.postMessage({
command: 'displayApiKey',
apiKey: existingKey || ''
});
break;
case 'clearApiKey':
await context.secrets.delete('vulnmatter.x-api-key');
vscode.window.showInformationMessage('X-API-Key cleared successfully!');
panel.webview.postMessage({
command: 'displayApiKey',
apiKey: ''
});
break;
case 'ready':
// Send existing API key to webview when it's ready
const readyKey = await context.secrets.get('vulnmatter.x-api-key');
panel.webview.postMessage({
command: 'displayApiKey',
apiKey: readyKey || ''
});
break;
}
}, undefined, context.subscriptions);
}
function getWebviewContent(webview) {
const nonce = getNonce();
const cspSource = webview.cspSource;
return `
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src ${cspSource} https:; style-src ${cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}';">
<title>Configure X-API-Key</title>
<style>
body {
font-family: var(--vscode-font-family);
color: var(--vscode-foreground);
background-color: var(--vscode-editor-background);
padding: 20px;
max-width: 600px;
}
h1 {
color: var(--vscode-titleBar-activeForeground);
margin-bottom: 20px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}
input[type="password"], input[type="text"] {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--vscode-input-border);
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border-radius: 3px;
font-size: 14px;
box-sizing: border-box;
}
input[type="password"]:focus, input[type="text"]:focus {
outline: none;
border-color: var(--vscode-focusBorder);
}
.button-group {
display: flex;
gap: 10px;
margin-top: 20px;
}
button {
padding: 8px 16px;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 14px;
background-color: var(--vscode-button-background);
color: var(--vscode-button-foreground);
}
button:hover {
background-color: var(--vscode-button-hoverBackground);
}
.secondary-button {
background-color: var(--vscode-button-secondaryBackground) !important;
color: var(--vscode-button-secondaryForeground) !important;
}
.secondary-button:hover {
background-color: var(--vscode-button-secondaryHoverBackground) !important;
}
.danger-button {
background-color: var(--vscode-inputValidation-errorBackground) !important;
color: var(--vscode-inputValidation-errorForeground) !important;
}
.info {
background-color: var(--vscode-editorWidget-background);
border: 1px solid var(--vscode-editorWidget-border);
padding: 15px;
margin: 20px 0;
border-radius: 3px;
font-size: 13px;
}
.toggle-container {
display: flex;
align-items: center;
gap: 10px;
margin-top: 10px;
}
.toggle-container input[type="checkbox"] {
width: auto;
}
</style>
</head>
<body>
<h1>🔐 Configure X-API-Key</h1>
<div class="info">
<strong>ℹ️ Información:</strong><br>
Esta clave API se almacenará de forma segura en tu sistema y será utilizada para conectar con servicios MCP (Model Context Protocol).
</div>
<div class="form-group">
<label for="apiKeyInput">X-API-Key:</label>
<input type="password" id="apiKeyInput" placeholder="Ingresa tu clave API..." />
<div class="toggle-container">
<input type="checkbox" id="showPassword" />
<label for="showPassword">Mostrar clave</label>
</div>
</div>
<div class="button-group">
<button id="saveButton">💾 Guardar Clave</button>
<button id="testButton" class="secondary-button">🧪 Probar Conexión</button>
<button id="clearButton" class="danger-button">🗑️ Limpiar</button>
</div>
<script nonce="${nonce}">
const vscode = acquireVsCodeApi();
const apiKeyInput = document.getElementById('apiKeyInput');
const showPasswordCheckbox = document.getElementById('showPassword');
const saveButton = document.getElementById('saveButton');
const testButton = document.getElementById('testButton');
const clearButton = document.getElementById('clearButton');
// Toggle password visibility
showPasswordCheckbox.addEventListener('change', function() {
apiKeyInput.type = this.checked ? 'text' : 'password';
});
// Save API key
saveButton.addEventListener('click', () => {
const apiKey = apiKeyInput.value;
if (apiKey.trim()) {
vscode.postMessage({ command: 'saveApiKey', apiKey });
} else {
alert('Por favor, ingresa una clave API válida.');
}
});
// Test connection (placeholder for future implementation)
testButton.addEventListener('click', () => {
const apiKey = apiKeyInput.value.trim();
if (apiKey) {
alert('Funcionalidad de prueba: Próximamente se implementará la verificación de conectividad MCP.');
} else {
alert('Por favor, ingresa una clave API para probar.');
}
});
// Clear API key
clearButton.addEventListener('click', () => {
if (confirm('¿Estás seguro de que deseas eliminar la clave API almacenada?')) {
vscode.postMessage({ command: 'clearApiKey' });
}
});
// Listen for messages from the extension
window.addEventListener('message', event => {
const message = event.data;
if (message?.command === 'displayApiKey') {
apiKeyInput.value = message.apiKey || '';
}
});
// Notify extension that webview is ready
vscode.postMessage({ command: 'ready' });
// Allow Enter key to save
apiKeyInput.addEventListener('keypress', function(event) {
if (event.key === 'Enter') {
saveButton.click();
}
});
</script>
</body>
</html>
`;
}
// Helper function to get stored API key (for use in other parts of the extension)
async function getStoredApiKey(context) {
return await context.secrets.get('vulnmatter.x-api-key');
}
// This method is called when your extension is deactivated
function deactivate() { }
// Generate a nonce for Content Security Policy
function getNonce() {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
/***/ }),
/* 1 */
/***/ ((module) => {
module.exports = require("vscode");
/***/ })
/******/ ]);
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module is referenced by other modules so it can't be inlined
/******/ var __webpack_exports__ = __webpack_require__(0);
/******/ module.exports = __webpack_exports__;
/******/
/******/ })()
;
//# sourceMappingURL=extension.js.map