Platform restructured into crates/, added AI service and detector,
migrated control-center-ui to Leptos 0.8
171 lines
3.8 KiB
TypeScript
171 lines
3.8 KiB
TypeScript
/**
|
|
* Vault Secrets API Client
|
|
*
|
|
* API client for interacting with vault secrets endpoints
|
|
*/
|
|
|
|
import {
|
|
Secret,
|
|
SecretWithValue,
|
|
SecretHistory,
|
|
CreateSecretRequest,
|
|
UpdateSecretRequest,
|
|
ListSecretsQuery,
|
|
ListSecretsResponse,
|
|
ApiError,
|
|
} from '../types/secrets';
|
|
|
|
const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:8080';
|
|
|
|
class SecretsApiError extends Error {
|
|
constructor(public error: ApiError) {
|
|
super(error.message);
|
|
this.name = 'SecretsApiError';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get authorization token from storage
|
|
*/
|
|
function getAuthToken(): string | null {
|
|
return localStorage.getItem('auth_token');
|
|
}
|
|
|
|
/**
|
|
* Make authenticated API request
|
|
*/
|
|
async function apiRequest<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {}
|
|
): Promise<T> {
|
|
const token = getAuthToken();
|
|
|
|
const headers: HeadersInit = {
|
|
'Content-Type': 'application/json',
|
|
...options.headers,
|
|
};
|
|
|
|
if (token) {
|
|
headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
|
|
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
|
...options,
|
|
headers,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorData: ApiError = await response.json();
|
|
throw new SecretsApiError(errorData);
|
|
}
|
|
|
|
// Handle 204 No Content
|
|
if (response.status === 204) {
|
|
return null as T;
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
/**
|
|
* Secrets API Client
|
|
*/
|
|
export const secretsApi = {
|
|
/**
|
|
* Create a new secret
|
|
*/
|
|
async createSecret(request: CreateSecretRequest): Promise<Secret> {
|
|
return apiRequest<Secret>('/api/v1/secrets/vault', {
|
|
method: 'POST',
|
|
body: JSON.stringify(request),
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Get a secret value (decrypted)
|
|
*/
|
|
async getSecret(
|
|
path: string,
|
|
version?: number,
|
|
context?: string
|
|
): Promise<SecretWithValue> {
|
|
const params = new URLSearchParams();
|
|
if (version !== undefined) {
|
|
params.append('version', version.toString());
|
|
}
|
|
if (context) {
|
|
params.append('context', context);
|
|
}
|
|
|
|
const queryString = params.toString();
|
|
const endpoint = `/api/v1/secrets/vault/${encodeURIComponent(path)}${
|
|
queryString ? `?${queryString}` : ''
|
|
}`;
|
|
|
|
return apiRequest<SecretWithValue>(endpoint);
|
|
},
|
|
|
|
/**
|
|
* List secrets (metadata only)
|
|
*/
|
|
async listSecrets(query?: ListSecretsQuery): Promise<ListSecretsResponse> {
|
|
const params = new URLSearchParams();
|
|
if (query?.prefix) {
|
|
params.append('prefix', query.prefix);
|
|
}
|
|
if (query?.limit !== undefined) {
|
|
params.append('limit', query.limit.toString());
|
|
}
|
|
if (query?.offset !== undefined) {
|
|
params.append('offset', query.offset.toString());
|
|
}
|
|
|
|
const queryString = params.toString();
|
|
const endpoint = `/api/v1/secrets/vault${queryString ? `?${queryString}` : ''}`;
|
|
|
|
return apiRequest<ListSecretsResponse>(endpoint);
|
|
},
|
|
|
|
/**
|
|
* Update a secret (creates new version)
|
|
*/
|
|
async updateSecret(path: string, request: UpdateSecretRequest): Promise<Secret> {
|
|
return apiRequest<Secret>(`/api/v1/secrets/vault/${encodeURIComponent(path)}`, {
|
|
method: 'PUT',
|
|
body: JSON.stringify(request),
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Delete a secret
|
|
*/
|
|
async deleteSecret(path: string): Promise<void> {
|
|
return apiRequest<void>(`/api/v1/secrets/vault/${encodeURIComponent(path)}`, {
|
|
method: 'DELETE',
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Get secret history/versions
|
|
*/
|
|
async getSecretHistory(path: string): Promise<SecretHistory> {
|
|
return apiRequest<SecretHistory>(
|
|
`/api/v1/secrets/vault/${encodeURIComponent(path)}/history`
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Restore a specific version of a secret
|
|
*/
|
|
async restoreSecretVersion(path: string, version: number): Promise<Secret> {
|
|
return apiRequest<Secret>(
|
|
`/api/v1/secrets/vault/${encodeURIComponent(path)}/versions/${version}/restore`,
|
|
{
|
|
method: 'POST',
|
|
}
|
|
);
|
|
},
|
|
};
|
|
|
|
export { SecretsApiError };
|