Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SM-1086] Improve TS bindings #398

Merged
merged 8 commits into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions languages/js/example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { BitwardenClient: BitwardenClientWasm, LogLevel } = require("@bitwarden/sdk-wasm");
const sdk = require("@bitwarden/sdk-client");

async function main() {
const settings = {
apiUrl: process.env.API_URL,
identityUrl: process.env.IDENTITY_URL,
};

const client = new sdk.BitwardenClient(
new BitwardenClientWasm(JSON.stringify(settings), LogLevel.Debug),
);

const organization_id = process.env.ORGANIZATION_ID;
await client.accessTokenLogin(process.env.ACCESS_TOKEN);

const project = await client.projects().create("test", organization_id);
const projects = await client.projects().list(organization_id);
console.log(projects.data);

const secret = await client
.secrets()
.create("test-secret", "My secret!", "This is my secret", [project.id], organization_id);
const secrets = await client.secrets().list(organization_id);
console.log(secrets.data);

console.log(project, secret);

await client.projects().delete([project.id]);
await client.secrets().delete([secret.id]);
}
main();
34 changes: 34 additions & 0 deletions languages/js/example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions languages/js/example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "sdk-example",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"@bitwarden/sdk-client": "../sdk-client",
"@bitwarden/sdk-wasm": "../wasm"
}
}
185 changes: 111 additions & 74 deletions languages/js/sdk-client/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,50 @@
import {
Convert,
ResponseForFingerprintResponse,
ResponseForPasswordLoginResponse,
ResponseForSecretIdentifiersResponse,
ResponseForSecretResponse,
ResponseForSecretsDeleteResponse,
ResponseForSyncResponse,
ResponseForUserAPIKeyResponse,
ProjectResponse,
ProjectsDeleteResponse,
ProjectsResponse,
SecretIdentifiersResponse,
SecretResponse,
SecretsDeleteResponse,
} from "./schemas";

interface BitwardenSDKClient {
run_command(js_input: string): Promise<any>;
}

function handleResponse<T>(response: { success: boolean; errorMessage?: string; data?: T }): T {
if (!response.success) {
throw new Error(response.errorMessage);
}
return response.data as T;
}

export class BitwardenClient {
client: BitwardenSDKClient;

constructor(client: BitwardenSDKClient) {
this.client = client;
}

async login(email: string, password: string, pbkdf_iter: number): Promise<ResponseForPasswordLoginResponse> {
async accessTokenLogin(accessToken: string): Promise<void> {
const response = await this.client.run_command(
Convert.commandToJson({
passwordLogin: {
email: email,
password: password,
kdf: {
pBKDF2: {
iterations: pbkdf_iter,
}
},
accessTokenLogin: {
accessToken,
},
})
}),
);

return Convert.toResponseForPasswordLoginResponse(response);
handleResponse(Convert.toResponseForAccessTokenLoginResponse(response));
}

async getUserApiKey(
secret: string,
isOtp: boolean = false
): Promise<ResponseForUserAPIKeyResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
getUserApiKey: {
masterPassword: isOtp ? null : secret,
otp: isOtp ? secret : null,
},
})
);

return Convert.toResponseForUserAPIKeyResponse(response);
secrets(): SecretsClient {
return new SecretsClient(this.client);
}

async sync(excludeSubdomains: boolean = false): Promise<ResponseForSyncResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
sync: {
excludeSubdomains,
},
})
);

return Convert.toResponseForSyncResponse(response);
projects(): ProjectsClient {
return new ProjectsClient(this.client);
}

async fingerprint(fingerprintMaterial: string, publicKey: string): Promise<string> {
const response = await this.client.run_command(
Convert.commandToJson({
fingerprint: {
fingerprintMaterial: fingerprintMaterial,
publicKey: publicKey,
}
})
)

return Convert.toResponseForFingerprintResponse(response).data.fingerprint;
};
}

export class SecretsClient {
Expand All @@ -87,74 +54,144 @@ export class SecretsClient {
this.client = client;
}

async get(id: string): Promise<ResponseForSecretResponse> {
async get(id: string): Promise<SecretResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
secrets: {
get: { id },
},
})
}),
);

return Convert.toResponseForSecretResponse(response);
return handleResponse(Convert.toResponseForSecretResponse(response));
}

async create(
key: string,
value: string,
note: string,
projectIds: string[],
organizationId: string,
value: string
): Promise<ResponseForSecretResponse> {
): Promise<SecretResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
secrets: {
create: { key, note, organizationId, value },
create: { key, value, note, projectIds, organizationId },
},
})
}),
);

return Convert.toResponseForSecretResponse(response);
return handleResponse(Convert.toResponseForSecretResponse(response));
}

async list(organizationId: string): Promise<ResponseForSecretIdentifiersResponse> {
async list(organizationId: string): Promise<SecretIdentifiersResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
secrets: {
list: { organizationId },
},
})
}),
);

return Convert.toResponseForSecretIdentifiersResponse(response);
return handleResponse(Convert.toResponseForSecretIdentifiersResponse(response));
}

async update(
id: string,
key: string,
value: string,
note: string,
projectIds: string[],
organizationId: string,
value: string
): Promise<ResponseForSecretResponse> {
): Promise<SecretResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
secrets: {
update: { id, key, note, organizationId, value },
update: { id, key, value, note, projectIds, organizationId },
},
})
}),
);

return Convert.toResponseForSecretResponse(response);
return handleResponse(Convert.toResponseForSecretResponse(response));
}

async delete(ids: string[]): Promise<ResponseForSecretsDeleteResponse> {
async delete(ids: string[]): Promise<SecretsDeleteResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
secrets: {
delete: { ids },
},
})
}),
);

return handleResponse(Convert.toResponseForSecretsDeleteResponse(response));
}
}

export class ProjectsClient {
client: BitwardenSDKClient;

constructor(client: BitwardenSDKClient) {
this.client = client;
}

async get(id: string): Promise<ProjectResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
projects: {
get: { id },
},
}),
);

return handleResponse(Convert.toResponseForProjectResponse(response));
}

async create(name: string, organizationId: string): Promise<ProjectResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
projects: {
create: { name, organizationId },
},
}),
);

return handleResponse(Convert.toResponseForProjectResponse(response));
}

async list(organizationId: string): Promise<ProjectsResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
projects: {
list: { organizationId },
},
}),
);

return handleResponse(Convert.toResponseForProjectsResponse(response));
}

async update(id: string, name: string, organizationId: string): Promise<ProjectResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
projects: {
update: { id, name, organizationId },
},
}),
);

return handleResponse(Convert.toResponseForProjectResponse(response));
}

async delete(ids: string[]): Promise<ProjectsDeleteResponse> {
const response = await this.client.run_command(
Convert.commandToJson({
projects: {
delete: { ids },
},
}),
);

return Convert.toResponseForSecretsDeleteResponse(response);
return handleResponse(Convert.toResponseForProjectsDeleteResponse(response));
}
}
7 changes: 0 additions & 7 deletions languages/js/sdk-client/src/logging_level.ts

This file was deleted.

2 changes: 1 addition & 1 deletion languages/js/sdk-client/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"outDir": "./dist/",
"module": "esnext",
"module": "commonjs",
"target": "es5",
"moduleResolution": "node",
"sourceMap": true,
Expand Down
Loading