@tamyla/clodo-framework 1.0.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 +564 -0
- package/LICENSE +21 -0
- package/README.md +1393 -0
- package/bin/README.md +71 -0
- package/bin/clodo-service.js +416 -0
- package/bin/security/security-cli.js +96 -0
- package/bin/service-management/README.md +74 -0
- package/bin/service-management/create-service.js +129 -0
- package/bin/service-management/init-service.js +102 -0
- package/bin/service-management/init-service.js.backup +889 -0
- package/bin/shared/config/customer-cli.js +293 -0
- package/dist/config/ConfigurationManager.js +159 -0
- package/dist/config/CustomerConfigCLI.js +220 -0
- package/dist/config/FeatureManager.js +426 -0
- package/dist/config/customers.js +441 -0
- package/dist/config/domains.js +180 -0
- package/dist/config/features.js +225 -0
- package/dist/config/index.js +6 -0
- package/dist/database/database-orchestrator.js +730 -0
- package/dist/database/index.js +4 -0
- package/dist/deployment/auditor.js +971 -0
- package/dist/deployment/index.js +10 -0
- package/dist/deployment/rollback-manager.js +523 -0
- package/dist/deployment/testers/api-tester.js +80 -0
- package/dist/deployment/testers/auth-tester.js +129 -0
- package/dist/deployment/testers/core.js +217 -0
- package/dist/deployment/testers/database-tester.js +105 -0
- package/dist/deployment/testers/index.js +74 -0
- package/dist/deployment/testers/load-tester.js +120 -0
- package/dist/deployment/testers/performance-tester.js +105 -0
- package/dist/deployment/validator.js +558 -0
- package/dist/deployment/wrangler-deployer.js +574 -0
- package/dist/handlers/GenericRouteHandler.js +532 -0
- package/dist/index.js +39 -0
- package/dist/migration/MigrationAdapters.js +562 -0
- package/dist/modules/ModuleManager.js +668 -0
- package/dist/modules/security.js +98 -0
- package/dist/orchestration/cross-domain-coordinator.js +1083 -0
- package/dist/orchestration/index.js +5 -0
- package/dist/orchestration/modules/DeploymentCoordinator.js +258 -0
- package/dist/orchestration/modules/DomainResolver.js +196 -0
- package/dist/orchestration/modules/StateManager.js +332 -0
- package/dist/orchestration/multi-domain-orchestrator.js +255 -0
- package/dist/routing/EnhancedRouter.js +158 -0
- package/dist/schema/SchemaManager.js +778 -0
- package/dist/security/ConfigurationValidator.js +490 -0
- package/dist/security/DeploymentManager.js +208 -0
- package/dist/security/SecretGenerator.js +142 -0
- package/dist/security/SecurityCLI.js +228 -0
- package/dist/security/index.js +51 -0
- package/dist/security/patterns/environment-rules.js +66 -0
- package/dist/security/patterns/insecure-patterns.js +21 -0
- package/dist/service-management/ConfirmationEngine.js +411 -0
- package/dist/service-management/ErrorTracker.js +294 -0
- package/dist/service-management/GenerationEngine.js +3109 -0
- package/dist/service-management/InputCollector.js +237 -0
- package/dist/service-management/ServiceCreator.js +229 -0
- package/dist/service-management/ServiceInitializer.js +448 -0
- package/dist/service-management/ServiceOrchestrator.js +638 -0
- package/dist/service-management/handlers/ConfigMutator.js +130 -0
- package/dist/service-management/handlers/ConfirmationHandler.js +71 -0
- package/dist/service-management/handlers/GenerationHandler.js +80 -0
- package/dist/service-management/handlers/InputHandler.js +59 -0
- package/dist/service-management/handlers/ValidationHandler.js +203 -0
- package/dist/service-management/index.js +7 -0
- package/dist/services/GenericDataService.js +488 -0
- package/dist/shared/cloudflare/domain-discovery.js +562 -0
- package/dist/shared/cloudflare/domain-manager.js +912 -0
- package/dist/shared/cloudflare/index.js +8 -0
- package/dist/shared/cloudflare/ops.js +387 -0
- package/dist/shared/config/cache.js +1167 -0
- package/dist/shared/config/command-config-manager.js +174 -0
- package/dist/shared/config/customer-cli.js +258 -0
- package/dist/shared/config/index.js +9 -0
- package/dist/shared/config/manager.js +289 -0
- package/dist/shared/database/connection-manager.js +338 -0
- package/dist/shared/database/index.js +7 -0
- package/dist/shared/database/orchestrator.js +632 -0
- package/dist/shared/deployment/auditor.js +971 -0
- package/dist/shared/deployment/index.js +10 -0
- package/dist/shared/deployment/rollback-manager.js +523 -0
- package/dist/shared/deployment/validator.js +558 -0
- package/dist/shared/index.js +32 -0
- package/dist/shared/monitoring/health-checker.js +250 -0
- package/dist/shared/monitoring/index.js +8 -0
- package/dist/shared/monitoring/memory-manager.js +382 -0
- package/dist/shared/monitoring/production-monitor.js +390 -0
- package/dist/shared/production-tester/api-tester.js +80 -0
- package/dist/shared/production-tester/auth-tester.js +129 -0
- package/dist/shared/production-tester/core.js +217 -0
- package/dist/shared/production-tester/database-tester.js +105 -0
- package/dist/shared/production-tester/index.js +74 -0
- package/dist/shared/production-tester/load-tester.js +120 -0
- package/dist/shared/production-tester/performance-tester.js +105 -0
- package/dist/shared/security/api-token-manager.js +296 -0
- package/dist/shared/security/index.js +8 -0
- package/dist/shared/security/secret-generator.js +918 -0
- package/dist/shared/security/secure-token-manager.js +379 -0
- package/dist/shared/utils/error-recovery.js +240 -0
- package/dist/shared/utils/graceful-shutdown-manager.js +380 -0
- package/dist/shared/utils/index.js +9 -0
- package/dist/shared/utils/interactive-prompts.js +134 -0
- package/dist/shared/utils/rate-limiter.js +249 -0
- package/dist/utils/ErrorHandler.js +173 -0
- package/dist/utils/deployment/config-cache.js +1160 -0
- package/dist/utils/deployment/index.js +6 -0
- package/dist/utils/deployment/interactive-prompts.js +97 -0
- package/dist/utils/deployment/secret-generator.js +896 -0
- package/dist/utils/dirname-helper.js +35 -0
- package/dist/utils/domain-config.js +159 -0
- package/dist/utils/error-recovery.js +240 -0
- package/dist/utils/esm-helper.js +52 -0
- package/dist/utils/framework-config.js +481 -0
- package/dist/utils/graceful-shutdown-manager.js +379 -0
- package/dist/utils/health-checker.js +114 -0
- package/dist/utils/index.js +36 -0
- package/dist/utils/prompt-handler.js +98 -0
- package/dist/utils/usage-tracker.js +252 -0
- package/dist/utils/validation.js +112 -0
- package/dist/version/VersionDetector.js +723 -0
- package/dist/worker/index.js +4 -0
- package/dist/worker/integration.js +332 -0
- package/docs/FRAMEWORK-ARCHITECTURE-OVERVIEW.md +206 -0
- package/docs/INTEGRATION_GUIDE.md +2045 -0
- package/docs/README.md +82 -0
- package/docs/SECURITY.md +242 -0
- package/docs/deployment/deployment-guide.md +540 -0
- package/docs/overview.md +280 -0
- package/package.json +176 -0
- package/types/index.d.ts +575 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Token Manager
|
|
3
|
+
* Secure management of external service API tokens (Cloudflare, etc.)
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Secure token storage with encryption
|
|
7
|
+
* - Interactive token collection
|
|
8
|
+
* - Token validation and testing
|
|
9
|
+
* - Automatic token refresh and management
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
13
|
+
import { join, dirname } from 'path';
|
|
14
|
+
import { createHash, createCipheriv, createDecipheriv, randomBytes } from 'crypto';
|
|
15
|
+
import { askUser, askPassword } from '../utils/interactive-prompts.js';
|
|
16
|
+
import { fileURLToPath } from 'url';
|
|
17
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
18
|
+
const __dirname = dirname(__filename);
|
|
19
|
+
export class ApiTokenManager {
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.projectRoot = options.projectRoot || join(__dirname, '..', '..');
|
|
22
|
+
this.configPath = join(this.projectRoot, '.config-cache', 'api-tokens.json');
|
|
23
|
+
this.encryptionKey = this.getOrCreateEncryptionKey();
|
|
24
|
+
|
|
25
|
+
// Ensure config directory exists
|
|
26
|
+
this.ensureDirectory(dirname(this.configPath));
|
|
27
|
+
|
|
28
|
+
// Load existing tokens
|
|
29
|
+
this.tokens = this.loadTokens();
|
|
30
|
+
console.log('š API Token Manager initialized');
|
|
31
|
+
console.log(`š Config: ${this.configPath}`);
|
|
32
|
+
console.log(`š Encrypted storage: ${this.isEncrypted() ? 'Yes' : 'No'}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get or create encryption key for secure token storage
|
|
37
|
+
*/
|
|
38
|
+
getOrCreateEncryptionKey() {
|
|
39
|
+
const keyPath = join(this.projectRoot, '.config-cache', '.token-key');
|
|
40
|
+
if (existsSync(keyPath)) {
|
|
41
|
+
return readFileSync(keyPath, 'utf-8').trim();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Generate new encryption key
|
|
45
|
+
const key = randomBytes(32).toString('hex');
|
|
46
|
+
this.ensureDirectory(dirname(keyPath));
|
|
47
|
+
writeFileSync(keyPath, key, {
|
|
48
|
+
mode: 0o600
|
|
49
|
+
}); // Secure file permissions
|
|
50
|
+
|
|
51
|
+
return key;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load tokens from encrypted storage
|
|
56
|
+
*/
|
|
57
|
+
loadTokens() {
|
|
58
|
+
if (!existsSync(this.configPath)) {
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const data = readFileSync(this.configPath, 'utf-8');
|
|
63
|
+
const config = JSON.parse(data);
|
|
64
|
+
|
|
65
|
+
// Decrypt tokens if they're encrypted
|
|
66
|
+
if (config.encrypted) {
|
|
67
|
+
const decryptedTokens = {};
|
|
68
|
+
for (const [service, encryptedToken] of Object.entries(config.tokens)) {
|
|
69
|
+
try {
|
|
70
|
+
decryptedTokens[service] = this.decryptToken(encryptedToken);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.warn(`ā ļø Failed to decrypt token for ${service}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return decryptedTokens;
|
|
76
|
+
}
|
|
77
|
+
return config.tokens || {};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.warn('ā ļø Failed to load API tokens, starting fresh');
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Save tokens to encrypted storage
|
|
86
|
+
*/
|
|
87
|
+
saveTokens() {
|
|
88
|
+
try {
|
|
89
|
+
const encryptedTokens = {};
|
|
90
|
+
|
|
91
|
+
// Encrypt each token
|
|
92
|
+
for (const [service, token] of Object.entries(this.tokens)) {
|
|
93
|
+
encryptedTokens[service] = this.encryptToken(token);
|
|
94
|
+
}
|
|
95
|
+
const config = {
|
|
96
|
+
encrypted: true,
|
|
97
|
+
lastUpdated: new Date().toISOString(),
|
|
98
|
+
services: Object.keys(this.tokens),
|
|
99
|
+
tokens: encryptedTokens
|
|
100
|
+
};
|
|
101
|
+
writeFileSync(this.configPath, JSON.stringify(config, null, 2), {
|
|
102
|
+
mode: 0o600
|
|
103
|
+
});
|
|
104
|
+
console.log(`ā
API tokens saved securely to ${this.configPath}`);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error('ā Failed to save API tokens:', error.message);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Encrypt token for secure storage
|
|
113
|
+
*/
|
|
114
|
+
encryptToken(token) {
|
|
115
|
+
try {
|
|
116
|
+
const algorithm = 'aes-256-cbc';
|
|
117
|
+
const iv = randomBytes(16);
|
|
118
|
+
const cipher = createCipheriv(algorithm, Buffer.from(this.encryptionKey, 'hex'), iv);
|
|
119
|
+
let encrypted = cipher.update(token, 'utf8', 'hex');
|
|
120
|
+
encrypted += cipher.final('hex');
|
|
121
|
+
return iv.toString('hex') + ':' + encrypted;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.warn('ā ļø Token encryption failed, storing in plain text');
|
|
124
|
+
return token;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Decrypt token from storage
|
|
130
|
+
*/
|
|
131
|
+
decryptToken(encryptedToken) {
|
|
132
|
+
try {
|
|
133
|
+
const algorithm = 'aes-256-cbc';
|
|
134
|
+
const parts = encryptedToken.split(':');
|
|
135
|
+
if (parts.length !== 2) {
|
|
136
|
+
// Old format or plain text, return as is
|
|
137
|
+
return encryptedToken;
|
|
138
|
+
}
|
|
139
|
+
const iv = Buffer.from(parts[0], 'hex');
|
|
140
|
+
const encrypted = parts[1];
|
|
141
|
+
const decipher = createDecipheriv(algorithm, Buffer.from(this.encryptionKey, 'hex'), iv);
|
|
142
|
+
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
143
|
+
decrypted += decipher.final('utf8');
|
|
144
|
+
return decrypted;
|
|
145
|
+
} catch (error) {
|
|
146
|
+
// If decryption fails, assume it's plain text (backward compatibility)
|
|
147
|
+
return encryptedToken;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get API token for a service, prompting if not available
|
|
153
|
+
*/
|
|
154
|
+
async getToken(service, options = {}) {
|
|
155
|
+
const serviceName = service.toLowerCase();
|
|
156
|
+
|
|
157
|
+
// Check if token already exists
|
|
158
|
+
if (this.tokens[serviceName]) {
|
|
159
|
+
console.log(`š Using cached ${service} API token`);
|
|
160
|
+
return this.tokens[serviceName];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Prompt user for token
|
|
164
|
+
console.log(`\\nš ${service} API Token Required`);
|
|
165
|
+
console.log('ā'.repeat(40));
|
|
166
|
+
if (options.description) {
|
|
167
|
+
console.log(`š ${options.description}`);
|
|
168
|
+
}
|
|
169
|
+
if (options.instructions) {
|
|
170
|
+
console.log('š” Instructions:');
|
|
171
|
+
options.instructions.forEach(instruction => {
|
|
172
|
+
console.log(` ⢠${instruction}`);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
const token = await askPassword(`Enter your ${service} API token:`);
|
|
176
|
+
if (!token || token.trim() === '') {
|
|
177
|
+
throw new Error(`${service} API token is required but not provided`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Validate token if validator provided
|
|
181
|
+
if (options.validator) {
|
|
182
|
+
console.log(`š Validating ${service} API token...`);
|
|
183
|
+
try {
|
|
184
|
+
const isValid = await options.validator(token.trim());
|
|
185
|
+
if (!isValid) {
|
|
186
|
+
throw new Error(`Invalid ${service} API token`);
|
|
187
|
+
}
|
|
188
|
+
console.log(`ā
${service} API token validated successfully`);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
console.error(`ā Token validation failed: ${error.message}`);
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Store token
|
|
196
|
+
this.tokens[serviceName] = token.trim();
|
|
197
|
+
this.saveTokens();
|
|
198
|
+
console.log(`ā
${service} API token saved securely`);
|
|
199
|
+
return this.tokens[serviceName];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Check if token exists for a service
|
|
204
|
+
*/
|
|
205
|
+
hasToken(service) {
|
|
206
|
+
return !!this.tokens[service.toLowerCase()];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Remove token for a service
|
|
211
|
+
*/
|
|
212
|
+
removeToken(service) {
|
|
213
|
+
const serviceName = service.toLowerCase();
|
|
214
|
+
if (this.tokens[serviceName]) {
|
|
215
|
+
delete this.tokens[serviceName];
|
|
216
|
+
this.saveTokens();
|
|
217
|
+
console.log(`šļø Removed ${service} API token`);
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* List available tokens (without revealing actual values)
|
|
225
|
+
*/
|
|
226
|
+
listTokens() {
|
|
227
|
+
const services = Object.keys(this.tokens);
|
|
228
|
+
if (services.length === 0) {
|
|
229
|
+
console.log('š No API tokens stored');
|
|
230
|
+
return [];
|
|
231
|
+
}
|
|
232
|
+
console.log('š Stored API tokens:');
|
|
233
|
+
services.forEach(service => {
|
|
234
|
+
const token = this.tokens[service];
|
|
235
|
+
const preview = token.substring(0, 8) + '...';
|
|
236
|
+
console.log(` ⢠${service}: ${preview}`);
|
|
237
|
+
});
|
|
238
|
+
return services;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Utility methods
|
|
243
|
+
*/
|
|
244
|
+
isEncrypted() {
|
|
245
|
+
return !!this.encryptionKey;
|
|
246
|
+
}
|
|
247
|
+
ensureDirectory(dirPath) {
|
|
248
|
+
if (!existsSync(dirPath)) {
|
|
249
|
+
mkdirSync(dirPath, {
|
|
250
|
+
recursive: true,
|
|
251
|
+
mode: 0o700
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Cloudflare API Token Manager
|
|
259
|
+
* Specialized manager for Cloudflare API tokens with validation
|
|
260
|
+
*/
|
|
261
|
+
export class CloudflareTokenManager extends ApiTokenManager {
|
|
262
|
+
constructor(options = {}) {
|
|
263
|
+
super(options);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get Cloudflare API token with validation
|
|
268
|
+
*/
|
|
269
|
+
async getCloudflareToken() {
|
|
270
|
+
return this.getToken('cloudflare', {
|
|
271
|
+
description: 'Cloudflare API token is required for domain verification and deployment operations.',
|
|
272
|
+
instructions: ['Go to Cloudflare Dashboard ā My Profile ā API Tokens', 'Create a token with Zone:Read and Worker:Edit permissions', 'Copy the token (it will only be shown once)'],
|
|
273
|
+
validator: this.validateCloudflareToken.bind(this)
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Validate Cloudflare API token
|
|
279
|
+
*/
|
|
280
|
+
async validateCloudflareToken(token) {
|
|
281
|
+
try {
|
|
282
|
+
const response = await fetch('https://api.cloudflare.com/client/v4/user/tokens/verify', {
|
|
283
|
+
headers: {
|
|
284
|
+
'Authorization': `Bearer ${token}`,
|
|
285
|
+
'Content-Type': 'application/json'
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
const data = await response.json();
|
|
289
|
+
return response.ok && data.success;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.warn('ā ļø Token validation failed (network error)');
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
export default ApiTokenManager;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Module
|
|
3
|
+
* Exports all security and authentication related utilities
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { ApiTokenManager } from './api-token-manager.js';
|
|
7
|
+
export { SecureTokenManager } from './secure-token-manager.js';
|
|
8
|
+
export { SecretGenerator } from './secret-generator.js';
|