mirror of
https://github.com/siteboon/claudecodeui.git
synced 2025-12-12 13:19:43 +00:00
feat(api): add API for one-shot prompt generatio, key authentication system and git commit message generation
Implement comprehensive API key management functionality including generation, validation, and CRUD operations. Changes: - Add API key database schema and operations (create, validate, delete, toggle) - Generating a commit message will now work properly with claude sdk and cursor cli and return a suggested commit message - Implement crypto-based key generation with 'ck_' prefix - Add session ID tracking in claude-sdk.js and cursor-cli.js - Update database layer with API key validation and last_used tracking - Support multi-user API key management with user association This enables secure programmatic access to the agent service
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import Database from 'better-sqlite3';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import crypto from 'crypto';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
@@ -94,8 +95,169 @@ const userDb = {
|
||||
}
|
||||
};
|
||||
|
||||
// API Keys database operations
|
||||
const apiKeysDb = {
|
||||
// Generate a new API key
|
||||
generateApiKey: () => {
|
||||
return 'ck_' + crypto.randomBytes(32).toString('hex');
|
||||
},
|
||||
|
||||
// Create a new API key
|
||||
createApiKey: (userId, keyName) => {
|
||||
try {
|
||||
const apiKey = apiKeysDb.generateApiKey();
|
||||
const stmt = db.prepare('INSERT INTO api_keys (user_id, key_name, api_key) VALUES (?, ?, ?)');
|
||||
const result = stmt.run(userId, keyName, apiKey);
|
||||
return { id: result.lastInsertRowid, keyName, apiKey };
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Get all API keys for a user
|
||||
getApiKeys: (userId) => {
|
||||
try {
|
||||
const rows = db.prepare('SELECT id, key_name, api_key, created_at, last_used, is_active FROM api_keys WHERE user_id = ? ORDER BY created_at DESC').all(userId);
|
||||
return rows;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Validate API key and get user
|
||||
validateApiKey: (apiKey) => {
|
||||
try {
|
||||
const row = db.prepare(`
|
||||
SELECT u.id, u.username, ak.id as api_key_id
|
||||
FROM api_keys ak
|
||||
JOIN users u ON ak.user_id = u.id
|
||||
WHERE ak.api_key = ? AND ak.is_active = 1 AND u.is_active = 1
|
||||
`).get(apiKey);
|
||||
|
||||
if (row) {
|
||||
// Update last_used timestamp
|
||||
db.prepare('UPDATE api_keys SET last_used = CURRENT_TIMESTAMP WHERE id = ?').run(row.api_key_id);
|
||||
}
|
||||
|
||||
return row;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Delete an API key
|
||||
deleteApiKey: (userId, apiKeyId) => {
|
||||
try {
|
||||
const stmt = db.prepare('DELETE FROM api_keys WHERE id = ? AND user_id = ?');
|
||||
const result = stmt.run(apiKeyId, userId);
|
||||
return result.changes > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Toggle API key active status
|
||||
toggleApiKey: (userId, apiKeyId, isActive) => {
|
||||
try {
|
||||
const stmt = db.prepare('UPDATE api_keys SET is_active = ? WHERE id = ? AND user_id = ?');
|
||||
const result = stmt.run(isActive ? 1 : 0, apiKeyId, userId);
|
||||
return result.changes > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// User credentials database operations (for GitHub tokens, GitLab tokens, etc.)
|
||||
const credentialsDb = {
|
||||
// Create a new credential
|
||||
createCredential: (userId, credentialName, credentialType, credentialValue, description = null) => {
|
||||
try {
|
||||
const stmt = db.prepare('INSERT INTO user_credentials (user_id, credential_name, credential_type, credential_value, description) VALUES (?, ?, ?, ?, ?)');
|
||||
const result = stmt.run(userId, credentialName, credentialType, credentialValue, description);
|
||||
return { id: result.lastInsertRowid, credentialName, credentialType };
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Get all credentials for a user, optionally filtered by type
|
||||
getCredentials: (userId, credentialType = null) => {
|
||||
try {
|
||||
let query = 'SELECT id, credential_name, credential_type, description, created_at, is_active FROM user_credentials WHERE user_id = ?';
|
||||
const params = [userId];
|
||||
|
||||
if (credentialType) {
|
||||
query += ' AND credential_type = ?';
|
||||
params.push(credentialType);
|
||||
}
|
||||
|
||||
query += ' ORDER BY created_at DESC';
|
||||
|
||||
const rows = db.prepare(query).all(...params);
|
||||
return rows;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Get active credential value for a user by type (returns most recent active)
|
||||
getActiveCredential: (userId, credentialType) => {
|
||||
try {
|
||||
const row = db.prepare('SELECT credential_value FROM user_credentials WHERE user_id = ? AND credential_type = ? AND is_active = 1 ORDER BY created_at DESC LIMIT 1').get(userId, credentialType);
|
||||
return row?.credential_value || null;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Delete a credential
|
||||
deleteCredential: (userId, credentialId) => {
|
||||
try {
|
||||
const stmt = db.prepare('DELETE FROM user_credentials WHERE id = ? AND user_id = ?');
|
||||
const result = stmt.run(credentialId, userId);
|
||||
return result.changes > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
},
|
||||
|
||||
// Toggle credential active status
|
||||
toggleCredential: (userId, credentialId, isActive) => {
|
||||
try {
|
||||
const stmt = db.prepare('UPDATE user_credentials SET is_active = ? WHERE id = ? AND user_id = ?');
|
||||
const result = stmt.run(isActive ? 1 : 0, credentialId, userId);
|
||||
return result.changes > 0;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Backward compatibility - keep old names pointing to new system
|
||||
const githubTokensDb = {
|
||||
createGithubToken: (userId, tokenName, githubToken, description = null) => {
|
||||
return credentialsDb.createCredential(userId, tokenName, 'github_token', githubToken, description);
|
||||
},
|
||||
getGithubTokens: (userId) => {
|
||||
return credentialsDb.getCredentials(userId, 'github_token');
|
||||
},
|
||||
getActiveGithubToken: (userId) => {
|
||||
return credentialsDb.getActiveCredential(userId, 'github_token');
|
||||
},
|
||||
deleteGithubToken: (userId, tokenId) => {
|
||||
return credentialsDb.deleteCredential(userId, tokenId);
|
||||
},
|
||||
toggleGithubToken: (userId, tokenId, isActive) => {
|
||||
return credentialsDb.toggleCredential(userId, tokenId, isActive);
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
db,
|
||||
initializeDatabase,
|
||||
userDb
|
||||
userDb,
|
||||
apiKeysDb,
|
||||
credentialsDb,
|
||||
githubTokensDb // Backward compatibility
|
||||
};
|
||||
Reference in New Issue
Block a user