1
0
Fork 0
VaultUI/src/api/API.ts
ChaotiCryptidz b2e1ab3057 lint code
2022-01-11 14:56:39 +00:00

688 lines
19 KiB
TypeScript

import { AuthListAPIType, AuthListType } from "./types/auth";
import { BaseAPIResponse } from "./types/api";
import { CapabilitiesType } from "./types/capabilities";
import {
DecryptionPayload,
DecryptionResult,
EncryptionPayload,
EncryptionResult,
RewrapPayload,
RewrapResult,
TransitKeyType,
} from "./types/transit";
import { DoesNotExistError } from "../types/internalErrors";
import { MountType, MountsType, NewMountParams } from "./types/mount";
import { NewTOTPData, NewTOTPResp } from "./types/totp";
import { SealStatusType } from "./types/seal";
import { SecretMetadataType } from "./types/secret";
import { Settings } from "../settings/Settings";
import { TokenInfo } from "./types/token";
import { UserType, UserTypeAPIResp } from "./types/user";
import { getObjectKeys, removeDoubleSlash } from "../utils";
async function checkResponse(resp: Response): Promise<void> {
if (resp.ok) return;
if (resp.status == 404) throw DoesNotExistError;
let json: BaseAPIResponse;
try {
json = (await resp.json()) as BaseAPIResponse;
} catch {
// Do Nothing
}
if (json?.errors?.length >= 1) {
throw new Error(json.errors[0]);
}
}
export class API {
private settings: Settings;
constructor(settings: Settings) {
this.settings = settings;
}
getHeaders(): Record<string, string> {
return {
"X-Vault-Token": this.settings.token,
};
}
appendAPIURL(url: string): string {
return this.settings.apiURL + url;
}
// List all supported auth methods
async listAuth(): Promise<AuthListType> {
const request = new Request(this.appendAPIURL(`/v1/sys/auth`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as AuthListAPIType;
return data.data;
}
// Tries to login with username and password, returns token
async usernameLogin(username: string, password: string): Promise<string> {
const request = new Request(this.appendAPIURL(`/v1/auth/userpass/login/${username}`), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ username: username, password: password }),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as {
auth: { client_token: string };
};
return data.auth.client_token;
}
async createOrUpdateUserPassUser(
path: string,
username: string,
data: Partial<UserType>,
): Promise<void> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/auth/${path}/users/${username}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(data, null, 0),
},
);
const resp = await fetch(request);
await checkResponse(resp);
}
async deleteUserPassUser(path: string, username: string): Promise<void> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/auth/${path}/users/${username}`)),
{
method: "DELETE",
headers: this.getHeaders(),
},
);
const resp = await fetch(request);
await checkResponse(resp);
}
async getUserPassUser(path: string, username: string): Promise<UserType> {
const request = new Request(this.appendAPIURL(`/v1/auth/${path}/users/${username}`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as UserTypeAPIResp;
return data.data;
}
async listUserPassUsers(path: string): Promise<string[]> {
const request = new Request(this.appendAPIURL(`/v1/auth/${path}/users?list=true`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { keys: string[] } };
return data.data.keys;
}
async getMount(mountName: string): Promise<MountType> {
const request = new Request(this.appendAPIURL("/v1/sys/internal/ui/mounts/" + mountName), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: MountType };
return data.data;
}
async getMounts(): Promise<MountsType> {
const request = new Request(this.appendAPIURL("/v1/sys/internal/ui/mounts"), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { secret: MountsType } };
return data.data.secret;
}
async newMount(parms: NewMountParams): Promise<void> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/sys/mounts/${parms.name}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(parms),
},
);
const resp = await fetch(request);
await checkResponse(resp);
}
async deleteMount(mountPath: string): Promise<void> {
const request = new Request(this.appendAPIURL("/v1/sys/mounts/" + mountPath), {
method: "DELETE",
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async getCapabilitiesPath(path: string | string[]): Promise<CapabilitiesType> {
if (!Array.isArray(path)) {
path = [path];
}
const request = new Request(this.appendAPIURL("/v1/sys/capabilities-self"), {
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify({
paths: path,
}),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { capabilities: string[] };
return data;
}
async getCapsPath(path: string | string[]): Promise<string[]> {
return (await this.getCapabilitiesPath(path)).capabilities;
}
async getCapabilities(
baseMount: string,
secretPath: string[],
name: string,
): Promise<CapabilitiesType> {
return await this.getCapabilitiesPath(
removeDoubleSlash(baseMount + secretPath.join("/") + "/" + name),
);
}
async sealVault(): Promise<void> {
const request = new Request(this.appendAPIURL("/v1/sys/seal"), {
method: "PUT",
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async submitUnsealKey(key: string): Promise<void> {
const request = new Request(this.appendAPIURL("/v1/sys/unseal"), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
key: key,
}),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async getSealStatus(): Promise<SealStatusType> {
const request = new Request(this.appendAPIURL("/v1/sys/seal-status"));
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as SealStatusType;
return data;
}
async lookupSelf(): Promise<TokenInfo> {
const request = new Request(this.appendAPIURL("/v1/auth/token/lookup-self"), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: TokenInfo };
return data.data;
}
async renewSelf(): Promise<void> {
const request = new Request(this.appendAPIURL("/v1/auth/token/renew-self"), {
method: "POST",
headers: {
...this.getHeaders(),
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async createOrUpdatePolicy(name: string, policy_data: string): Promise<void> {
const request = new Request(this.appendAPIURL("/v1/sys/policies/acl/" + name), {
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify({ policy: policy_data }, null, 0),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async deletePolicy(name: string): Promise<void> {
const request = new Request(this.appendAPIURL("/v1/sys/policies/acl/" + name), {
method: "DELETE",
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async getPolicies(): Promise<string[]> {
const request = new Request(this.appendAPIURL("/v1/sys/policies/acl?list=true"), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { keys: string[] } };
return data.data.keys;
}
async getPolicy(name: string): Promise<string> {
const request = new Request(this.appendAPIURL("/v1/sys/policies/acl/" + name), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { policy: string } };
return data.data.policy;
}
async createOrUpdateSecret(
baseMount: string,
secretPath: string[],
name: string,
data: Record<string, unknown>,
): Promise<void> {
let secretURL = "";
let APIData = {};
const mountInfo = await this.getMount(baseMount);
if (mountInfo.options.version == "2") {
secretURL = `/v1/${baseMount}/data/${secretPath.join("/")}/${name}`;
APIData = { data: data };
} else {
secretURL = `/v1/${baseMount}/${secretPath.join("/")}/${name}`;
APIData = data;
}
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
const request = new Request(this.appendAPIURL(secretURL), {
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(APIData, null, 0),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async deleteSecret(
baseMount: string,
secretPath: string[],
name: string,
version = "null",
): Promise<void> {
let secretURL = "";
let request: Request;
const mountInfo = await this.getMount(baseMount);
const mountVersion = mountInfo.options.version;
if (mountVersion == "2" && version != "null") {
secretURL = `/v1/${baseMount}/delete/${secretPath.join("/")}/${name}`;
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
request = new Request(this.appendAPIURL(secretURL), {
method: "POST",
headers: {
...this.getHeaders(),
"Content-Type": "application/json",
},
body: JSON.stringify({ versions: [version] }),
});
} else {
if (mountVersion == "2") {
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("/")}/${name}`;
} else {
secretURL = `/v1/${baseMount}/${secretPath.join("/")}/${name}`;
}
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
request = new Request(this.appendAPIURL(secretURL), {
method: "DELETE",
headers: this.getHeaders(),
});
}
const resp = await fetch(request);
await checkResponse(resp);
}
async undeleteSecret(
baseMount: string,
secretPath: string[],
name: string,
version = "null",
): Promise<void> {
let secretURL = `/v1/${baseMount}/undelete/${secretPath.join("/")}/${name}`;
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
if (version == "null") {
const meta = await this.getSecretMetadata(baseMount, secretPath, name);
const versions = getObjectKeys(meta.versions);
version = String(versions[versions.length - 1]);
}
const request = new Request(this.appendAPIURL(secretURL), {
method: "POST",
headers: {
...this.getHeaders(),
"Content-Type": "application/json",
},
body: JSON.stringify({ versions: [version] }),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async getSecretKV1(
baseMount: string,
secretPath: string[],
name: string,
): Promise<Record<string, unknown>> {
const request = new Request(
this.appendAPIURL(`/v1/${baseMount}/${secretPath.join("/")}/${name}`),
{
headers: this.getHeaders(),
},
);
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as unknown;
return (data as { data: Record<string, unknown> }).data;
}
async getSecretKV2(
baseMount: string,
secretPath: string[],
name: string,
version = "null",
): Promise<Record<string, unknown>> {
let secretURL = "";
secretURL = `/v1/${baseMount}/data/${secretPath.join("/")}/${name}`;
if (version != "null") secretURL += `?version=${version}`;
const request = new Request(this.appendAPIURL(secretURL), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as unknown;
return (data as { data: { data: Record<string, unknown> } }).data.data;
}
async getSecret(
baseMount: string,
secretPath: string[],
name: string,
version = "null",
): Promise<Record<string, unknown>> {
const mountInfo = await this.getMount(baseMount);
if (mountInfo.options.version == "2") {
return await this.getSecretKV2(baseMount, secretPath, name, version);
} else {
return await this.getSecretKV1(baseMount, secretPath, name);
}
}
async getSecretMetadata(
baseMount: string,
secretPath: string[],
name: string,
): Promise<SecretMetadataType> {
const request = new Request(
this.appendAPIURL(`/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`),
{
headers: this.getHeaders(),
},
);
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: SecretMetadataType };
return data.data;
}
async getSecrets(baseMount: string, secretPath: string[]): Promise<string[]> {
let secretURL = "";
const mountInfo = await this.getMount(baseMount);
if (mountInfo.options.version == "2") {
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("/")}?list=true`;
} else {
secretURL = `/v1/${baseMount}/${secretPath.join("/")}?list=true`;
}
const request = new Request(this.appendAPIURL(secretURL), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { keys: string[] } };
return data.data.keys;
}
async addNewTOTP(baseMount: string, parms: NewTOTPData): Promise<NewTOTPResp> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/keys/${parms.name}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(parms),
},
);
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: NewTOTPResp };
return data.data;
}
async deleteTOTP(baseMount: string, name: string): Promise<void> {
const request = new Request(this.appendAPIURL(`/v1/${baseMount}/keys/${name}`), {
method: "DELETE",
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
}
async getTOTPCode(baseMount: string, name: string): Promise<string> {
const request = new Request(this.appendAPIURL(`/v1/${baseMount}/code/${name}`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { code: string } };
return data.data.code;
}
async getTOTPKeys(baseMount: string): Promise<string[]> {
const request = new Request(this.appendAPIURL(`/v1/${baseMount}/keys?list=true`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { keys: string[] } };
return data.data.keys;
}
async getTransitKey(baseMount: string, name: string): Promise<TransitKeyType> {
const request = new Request(this.appendAPIURL(`/v1/${baseMount}/keys/${name}`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: TransitKeyType };
return data.data;
}
async getTransitKeys(baseMount: string): Promise<string[]> {
const request = new Request(this.appendAPIURL(`/v1/${baseMount}/keys?list=true`), {
headers: this.getHeaders(),
});
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as { data: { keys: string[] } };
return data.data.keys;
}
async newTransitKey(baseMount: string, parms: { name: string; type: string }): Promise<void> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/keys/${parms.name}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(parms),
},
);
const resp = await fetch(request);
await checkResponse(resp);
}
async transitDecrypt(
baseMount: string,
name: string,
payload: DecryptionPayload,
): Promise<DecryptionResult> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/decrypt/${name}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(payload),
},
);
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as {
data?: DecryptionResult;
};
return data.data;
}
async transitEncrypt(
baseMount: string,
name: string,
payload: EncryptionPayload,
): Promise<EncryptionResult> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/encrypt/${name}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(payload),
},
);
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as {
data?: EncryptionResult;
};
return data.data;
}
async transitRewrap(
baseMount: string,
name: string,
payload: RewrapPayload,
): Promise<RewrapResult> {
const request = new Request(
this.appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/rewrap/${name}`)),
{
method: "POST",
headers: {
"Content-Type": "application/json",
...this.getHeaders(),
},
body: JSON.stringify(payload),
},
);
const resp = await fetch(request);
await checkResponse(resp);
const data = (await resp.json()) as {
data?: RewrapResult;
};
return data.data;
}
}