Initial
This commit is contained in:
@@ -7,7 +7,8 @@ function normalizeConnection(body, existing = {}) {
|
||||
const parsed = vcenterConnectionSchema.parse({
|
||||
...existing,
|
||||
...body,
|
||||
password: body.password || ''
|
||||
password: body.password || '',
|
||||
credentialId: body.credentialId ?? existing.credentialId ?? existing.credential_id ?? null
|
||||
});
|
||||
const targetType = parsed.targetType || 'vcenter';
|
||||
const apiMode = targetType === 'host'
|
||||
@@ -18,15 +19,55 @@ function normalizeConnection(body, existing = {}) {
|
||||
targetType,
|
||||
apiMode,
|
||||
baseUrl: String(parsed.baseUrl || '').trim().replace(/\/+$/, ''),
|
||||
credentialId: parsed.credentialId || null,
|
||||
username: parsed.username || '',
|
||||
groupId: parsed.visibility === 'group' ? parsed.groupId || null : null
|
||||
};
|
||||
}
|
||||
|
||||
export function listVCenterConnections(userId) {
|
||||
return db.prepare(`
|
||||
SELECT c.*, g.name AS group_name
|
||||
function connectionSelect() {
|
||||
return `
|
||||
SELECT c.*, g.name AS group_name, cred.name AS credential_name, cred.username AS credential_username,
|
||||
cred.kind AS credential_kind, cred.secret_cipher AS credential_secret_cipher,
|
||||
cred.secret_iv AS credential_secret_iv, cred.secret_tag AS credential_secret_tag
|
||||
FROM vcenter_connections c
|
||||
LEFT JOIN groups g ON g.id = c.group_id
|
||||
LEFT JOIN credentials cred ON cred.id = c.credential_id
|
||||
`;
|
||||
}
|
||||
|
||||
function getVisibleCredential(credentialId, userId) {
|
||||
if (!credentialId) return null;
|
||||
return db.prepare(`SELECT * FROM credentials WHERE id = ? AND ${visibleClause()}`).get(credentialId, userId, userId);
|
||||
}
|
||||
|
||||
function assertUsableCredential(credentialId, userId) {
|
||||
const credential = getVisibleCredential(credentialId, userId);
|
||||
if (!credential) throw new Error('Choose a visible Credential Vault entry for this VMware connection.');
|
||||
if (credential.kind !== 'username_password') throw new Error('VMware connections require a username/password Credential Vault entry.');
|
||||
if (!credential.username) throw new Error('The selected Credential Vault entry must include a username.');
|
||||
return credential;
|
||||
}
|
||||
|
||||
function attachSecret(row, includeSecret) {
|
||||
if (!includeSecret) return camelVCenterConnection(row);
|
||||
if (row.credential_id) {
|
||||
return {
|
||||
...row,
|
||||
username: row.credential_username || '',
|
||||
password: decryptSecret({
|
||||
secret_cipher: row.credential_secret_cipher,
|
||||
secret_iv: row.credential_secret_iv,
|
||||
secret_tag: row.credential_secret_tag
|
||||
})
|
||||
};
|
||||
}
|
||||
return { ...row, password: decryptSecret(row) };
|
||||
}
|
||||
|
||||
export function listVCenterConnections(userId) {
|
||||
return db.prepare(`
|
||||
${connectionSelect()}
|
||||
WHERE ${visibleClause('c')}
|
||||
ORDER BY c.name
|
||||
`).all(userId, userId).map(camelVCenterConnection);
|
||||
@@ -35,41 +76,42 @@ export function listVCenterConnections(userId) {
|
||||
export function getVCenterConnection(connectionId, userId, includeSecret = false) {
|
||||
if (!connectionId) return null;
|
||||
const row = db.prepare(`
|
||||
SELECT c.*, g.name AS group_name
|
||||
FROM vcenter_connections c
|
||||
LEFT JOIN groups g ON g.id = c.group_id
|
||||
${connectionSelect()}
|
||||
WHERE c.id = ? AND ${visibleClause('c')}
|
||||
`).get(connectionId, userId, userId);
|
||||
if (!row) return null;
|
||||
return includeSecret ? { ...row, password: decryptSecret(row) } : camelVCenterConnection(row);
|
||||
return attachSecret(row, includeSecret);
|
||||
}
|
||||
|
||||
export function getVCenterConnectionSystem(connectionId, includeSecret = false) {
|
||||
if (!connectionId) return null;
|
||||
const row = db.prepare('SELECT * FROM vcenter_connections WHERE id = ?').get(connectionId);
|
||||
const row = db.prepare(`${connectionSelect()} WHERE c.id = ?`).get(connectionId);
|
||||
if (!row) return null;
|
||||
return includeSecret ? { ...row, password: decryptSecret(row) } : camelVCenterConnection(row);
|
||||
return attachSecret(row, includeSecret);
|
||||
}
|
||||
|
||||
export function createVCenterConnection(body, userId) {
|
||||
const payload = normalizeConnection(body);
|
||||
const encrypted = encryptSecret(payload.password);
|
||||
const credential = payload.credentialId ? assertUsableCredential(payload.credentialId, userId) : null;
|
||||
if (!credential && !payload.password) throw new Error('Choose a Credential Vault entry for this VMware connection.');
|
||||
const encrypted = credential ? encryptSecret('') : encryptSecret(payload.password);
|
||||
const connectionId = id('vc');
|
||||
db.prepare(`
|
||||
INSERT INTO vcenter_connections (
|
||||
id, name, base_url, username, secret_cipher, secret_iv, secret_tag,
|
||||
id, name, base_url, username, secret_cipher, secret_iv, secret_tag, credential_id,
|
||||
target_type, api_mode, request_timeout_ms, allow_untrusted_tls, enabled,
|
||||
visibility, owner_user_id, group_id, created_by, created_at, updated_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
connectionId,
|
||||
payload.name,
|
||||
payload.baseUrl,
|
||||
payload.username,
|
||||
credential?.username || payload.username || '',
|
||||
encrypted.cipher,
|
||||
encrypted.iv,
|
||||
encrypted.tag,
|
||||
payload.credentialId,
|
||||
payload.targetType,
|
||||
payload.apiMode,
|
||||
payload.requestTimeoutMs,
|
||||
@@ -92,6 +134,7 @@ export function updateVCenterConnection(connectionId, body, userId) {
|
||||
name: existing.name,
|
||||
baseUrl: existing.base_url,
|
||||
username: existing.username,
|
||||
credentialId: existing.credential_id,
|
||||
targetType: existing.target_type || 'vcenter',
|
||||
apiMode: existing.api_mode,
|
||||
requestTimeoutMs: existing.request_timeout_ms,
|
||||
@@ -100,24 +143,27 @@ export function updateVCenterConnection(connectionId, body, userId) {
|
||||
visibility: existing.visibility,
|
||||
groupId: existing.group_id
|
||||
});
|
||||
const encrypted = payload.password ? encryptSecret(payload.password) : {
|
||||
const credential = payload.credentialId ? assertUsableCredential(payload.credentialId, userId) : null;
|
||||
if (!credential && !payload.password && !existing.secret_cipher) throw new Error('Choose a Credential Vault entry for this VMware connection.');
|
||||
const encrypted = credential ? encryptSecret('') : payload.password ? encryptSecret(payload.password) : {
|
||||
cipher: existing.secret_cipher,
|
||||
iv: existing.secret_iv,
|
||||
tag: existing.secret_tag
|
||||
};
|
||||
db.prepare(`
|
||||
UPDATE vcenter_connections
|
||||
SET name = ?, base_url = ?, username = ?, secret_cipher = ?, secret_iv = ?, secret_tag = ?,
|
||||
SET name = ?, base_url = ?, username = ?, secret_cipher = ?, secret_iv = ?, secret_tag = ?, credential_id = ?,
|
||||
target_type = ?, api_mode = ?, request_timeout_ms = ?, allow_untrusted_tls = ?, enabled = ?,
|
||||
visibility = ?, group_id = ?, updated_at = ?
|
||||
WHERE id = ?
|
||||
`).run(
|
||||
payload.name,
|
||||
payload.baseUrl,
|
||||
payload.username,
|
||||
credential?.username || payload.username || '',
|
||||
encrypted.cipher,
|
||||
encrypted.iv,
|
||||
encrypted.tag,
|
||||
payload.credentialId,
|
||||
payload.targetType,
|
||||
payload.apiMode,
|
||||
payload.requestTimeoutMs,
|
||||
|
||||
Reference in New Issue
Block a user