extract-auth-config.jsโข14.6 kB
#!/usr/bin/env node
/**
* Authentication Configuration Extractor v1.0.0
* Extract authentication data from active Composer session for direct API use
*
* Purpose: One-time extraction of localStorage data to enable direct API authentication
* Status: UTILITY - Preserves current v5.2.0 system, enables direct API alternative
*
* @version 1.0.0 (January 15, 2025)
*/
import { chromium } from 'playwright';
import fs from 'fs';
import path from 'path';
class AuthConfigExtractor {
constructor() {
this.extractedData = null;
this.configPath = path.join(process.cwd(), 'config', 'direct-api-auth.json');
this.envPath = path.join(process.cwd(), 'config', 'direct-api.env');
}
/**
* Extract authentication configuration from active Composer session
*/
async extractFromActiveSession() {
console.log('๐ Authentication Configuration Extractor v1.0.0');
console.log('Purpose: Extract auth data for direct API authentication');
console.log('Status: Current v5.2.0 system preserved\n');
let browser = null;
let page = null;
try {
console.log('๐ฑ Step 1: Opening EuConquisto Composer...');
browser = await chromium.launch({
headless: false,
args: ['--disable-web-security', '--disable-features=VizDisplayCompositor']
});
page = await browser.newPage();
await page.goto('https://composer.euconquisto.com');
console.log('โณ Step 2: Waiting for authentication (please log in if needed)...');
console.log(' The browser will stay open for 30 seconds');
console.log(' Please ensure you are logged in to the Composer');
// Wait for potential authentication/loading
await page.waitForTimeout(30000);
console.log('๐ Step 3: Extracting authentication data...');
const authData = await page.evaluate(() => {
console.log('=== AUTH CONFIG EXTRACTION v1.0.0 ===');
const activeProject = localStorage.getItem('rdp-composer-active-project');
const userData = localStorage.getItem('rdp-composer-user-data');
console.log('Raw activeProject present:', !!activeProject);
console.log('Raw userData present:', !!userData);
if (!activeProject) {
return { success: false, error: 'Active project data not found in localStorage' };
}
if (!userData) {
return { success: false, error: 'User data not found in localStorage' };
}
let projectData, userDataParsed;
try {
projectData = JSON.parse(activeProject);
userDataParsed = JSON.parse(userData);
} catch (e) {
return { success: false, error: 'Failed to parse localStorage data: ' + e.message };
}
if (!projectData.uid) {
return { success: false, error: 'Project UID not found in active project data' };
}
if (!userDataParsed.access_token) {
return { success: false, error: 'Access token not found in user data' };
}
if (!projectData.connectors || !Array.isArray(projectData.connectors)) {
return { success: false, error: 'Connectors array not found or invalid in project data' };
}
// Extract all necessary data
const result = {
success: true,
extractedAt: new Date().toISOString(),
accessToken: userDataParsed.access_token,
tokenType: userDataParsed.token_type || 'Bearer',
projectUid: projectData.uid,
projectName: projectData.name || 'Unknown Project',
connectors: projectData.connectors.map(c => ({
uid: c.uid,
name: c.name,
type: c.type,
permissions: c.permissions || []
})),
userInfo: {
uid: userDataParsed.uid,
name: userDataParsed.name,
email: userDataParsed.email
},
// Store full raw data for debugging (tokens will be filtered out in output)
rawUserData: userDataParsed,
rawProjectData: projectData
};
console.log('Extraction successful:', {
projectUid: result.projectUid,
projectName: result.projectName,
connectorsCount: result.connectors.length,
hasAccessToken: !!result.accessToken,
tokenType: result.tokenType,
tokenLength: result.accessToken.length,
userUid: result.userInfo.uid,
userName: result.userInfo.name
});
return result;
});
this.extractedData = authData;
if (authData.success) {
console.log('โ
Authentication data extracted successfully!');
console.log(` Project: ${authData.projectName} (${authData.projectUid})`);
console.log(` User: ${authData.userInfo.name} (${authData.userInfo.email})`);
console.log(` Token Type: ${authData.tokenType}`);
console.log(` Token Length: ${authData.accessToken.length} characters`);
console.log(` Connectors: ${authData.connectors.length} available`);
// List connectors
console.log('\n๐ก Available Connectors:');
authData.connectors.forEach((connector, index) => {
console.log(` ${index + 1}. ${connector.name || 'Unnamed'} (${connector.uid})`);
if (connector.permissions.length > 0) {
console.log(` Permissions: ${connector.permissions.join(', ')}`);
}
});
await this.saveConfiguration();
await this.generateEnvironmentFile();
await this.generateMCPConfig();
} else {
console.log('โ Failed to extract authentication data:');
console.log(` Error: ${authData.error}`);
}
} catch (error) {
console.error('โ Extraction error:', error.message);
this.extractedData = { success: false, error: error.message };
} finally {
if (browser) {
console.log('\n๐ Closing browser...');
await browser.close();
}
}
return this.extractedData;
}
/**
* Save configuration to JSON file
*/
async saveConfiguration() {
if (!this.extractedData || !this.extractedData.success) {
return;
}
try {
// Create config directory if it doesn't exist
const configDir = path.dirname(this.configPath);
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
}
// Prepare config data (remove sensitive full tokens from saved file)
const configData = {
extractedAt: this.extractedData.extractedAt,
tokenType: this.extractedData.tokenType,
projectUid: this.extractedData.projectUid,
projectName: this.extractedData.projectName,
connectors: this.extractedData.connectors,
userInfo: this.extractedData.userInfo,
// Store token preview only in JSON file
accessTokenPreview: this.extractedData.accessToken.substring(0, 50) + '...',
note: 'Full access token stored in environment file for security'
};
fs.writeFileSync(this.configPath, JSON.stringify(configData, null, 2));
console.log(`\n๐พ Configuration saved to: ${this.configPath}`);
} catch (error) {
console.error('โ Failed to save configuration:', error.message);
}
}
/**
* Generate environment file with full authentication data
*/
async generateEnvironmentFile() {
if (!this.extractedData || !this.extractedData.success) {
return;
}
try {
const envContent = [
'# EuConquisto Composer Direct API Authentication',
'# Generated on: ' + new Date().toISOString(),
'# Source: Active Composer session localStorage extraction',
'',
'# Full JWT Access Token',
`EUCONQUISTO_ACCESS_TOKEN="${this.extractedData.accessToken}"`,
'',
'# Token Type (usually Bearer)',
`EUCONQUISTO_TOKEN_TYPE="${this.extractedData.tokenType}"`,
'',
'# Project Information',
`EUCONQUISTO_PROJECT_UID="${this.extractedData.projectUid}"`,
`EUCONQUISTO_PROJECT_NAME="${this.extractedData.projectName}"`,
'',
'# Connectors (JSON format)',
`EUCONQUISTO_CONNECTORS='${JSON.stringify(this.extractedData.connectors)}'`,
'',
'# User Information (optional)',
`EUCONQUISTO_USER_UID="${this.extractedData.userInfo.uid}"`,
`EUCONQUISTO_USER_NAME="${this.extractedData.userInfo.name}"`,
`EUCONQUISTO_USER_EMAIL="${this.extractedData.userInfo.email}"`,
'',
'# Usage:',
'# source config/direct-api.env',
'# export $(grep -v "^#" config/direct-api.env | xargs)',
''
].join('\n');
fs.writeFileSync(this.envPath, envContent);
console.log(`๐พ Environment file saved to: ${this.envPath}`);
console.log(' Use: source config/direct-api.env');
} catch (error) {
console.error('โ Failed to generate environment file:', error.message);
}
}
/**
* Generate MCP configuration for Claude Desktop
*/
async generateMCPConfig() {
if (!this.extractedData || !this.extractedData.success) {
return;
}
try {
const mcpConfig = {
"mcpServers": {
"euconquisto-composer-direct": {
"command": "node",
"args": [
"--max-old-space-size=4096",
path.resolve(process.cwd(), "dist", "index.js")
],
"env": {
"NODE_ENV": "production",
"EUCONQUISTO_ACCESS_TOKEN": this.extractedData.accessToken,
"EUCONQUISTO_TOKEN_TYPE": this.extractedData.tokenType,
"EUCONQUISTO_PROJECT_UID": this.extractedData.projectUid,
"EUCONQUISTO_CONNECTORS": JSON.stringify(this.extractedData.connectors),
"EUCONQUISTO_USER_UID": this.extractedData.userInfo.uid,
"EUCONQUISTO_USER_NAME": this.extractedData.userInfo.name
}
}
}
};
const mcpConfigPath = path.join(process.cwd(), 'config', 'claude-desktop-config-direct-api.json');
fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));
console.log(`๐พ MCP configuration saved to: ${mcpConfigPath}`);
console.log(' Add this to your Claude Desktop configuration');
} catch (error) {
console.error('โ Failed to generate MCP configuration:', error.message);
}
}
/**
* Test the extracted configuration
*/
async testConfiguration() {
if (!this.extractedData || !this.extractedData.success) {
console.log('โ No valid configuration to test');
return false;
}
console.log('\n๐งช Testing extracted configuration...');
try {
// Import and test direct API client
const { DirectAPIClient } = await import('../src/tools/direct-api-client.js');
const config = {
accessToken: this.extractedData.accessToken,
tokenType: this.extractedData.tokenType,
projectUid: this.extractedData.projectUid,
connectors: this.extractedData.connectors
};
const client = new DirectAPIClient(config);
const validationResult = await client.validateConnection();
if (validationResult.success) {
console.log('โ
Direct API configuration test successful!');
console.log('๐ฏ Direct API authentication is ready for use');
return true;
} else {
console.log('โ Direct API configuration test failed:');
console.log(' Error:', validationResult.error);
return false;
}
} catch (error) {
console.log('โ Configuration test error:', error.message);
return false;
}
}
/**
* Output summary and next steps
*/
outputSummary() {
console.log('\n' + '='.repeat(70));
console.log('๐ AUTHENTICATION EXTRACTION SUMMARY');
console.log('='.repeat(70));
if (this.extractedData && this.extractedData.success) {
console.log('\nโ
EXTRACTION SUCCESSFUL');
console.log(` Project: ${this.extractedData.projectName}`);
console.log(` User: ${this.extractedData.userInfo.name}`);
console.log(` Connectors: ${this.extractedData.connectors.length} available`);
console.log(` Extracted: ${this.extractedData.extractedAt}`);
console.log('\n๐ FILES CREATED:');
console.log(` Configuration: ${this.configPath}`);
console.log(` Environment: ${this.envPath}`);
console.log(` MCP Config: config/claude-desktop-config-direct-api.json`);
console.log('\n๐ฏ NEXT STEPS:');
console.log(' 1. Load environment: source config/direct-api.env');
console.log(' 2. Test direct API: node src/tools/direct-api-client.js');
console.log(' 3. Update Claude Desktop config if desired');
console.log(' 4. Consider replacing JWT redirect server with direct API calls');
console.log('\n๐ SECURITY NOTE:');
console.log(' โข Full JWT token stored in config/direct-api.env');
console.log(' โข Add config/direct-api.env to .gitignore');
console.log(' โข Token expires - re-extract when needed');
} else {
console.log('\nโ EXTRACTION FAILED');
if (this.extractedData) {
console.log(` Error: ${this.extractedData.error}`);
}
console.log('\n๐ฏ TROUBLESHOOTING:');
console.log(' 1. Ensure you are logged into EuConquisto Composer');
console.log(' 2. Wait for the page to fully load before extraction');
console.log(' 3. Check browser console for localStorage data');
console.log(' 4. Verify network connectivity to composer.euconquisto.com');
}
console.log('\n๐ CURRENT PROJECT STATUS:');
console.log(' v5.2.0 FULLY OPERATIONAL system is preserved and unchanged');
console.log(' This extraction enables optional direct API approach');
console.log('\n' + '='.repeat(70) + '\n');
}
}
// Execute extraction if run directly
if (import.meta.url === `file://${process.argv[1]}`) {
const extractor = new AuthConfigExtractor();
extractor.extractFromActiveSession()
.then(async (result) => {
if (result && result.success) {
await extractor.testConfiguration();
}
extractor.outputSummary();
})
.catch(error => {
console.error('โ Extraction process error:', error.message);
process.exit(1);
});
}
export { AuthConfigExtractor };