Skip to content

Commit

Permalink
Merge branch 'master' into feature/java-wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
lukpotSym authored Nov 27, 2023
2 parents 7df172c + 92a67b1 commit 40f07a5
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 50 deletions.
1 change: 1 addition & 0 deletions crates/sdk-schemas/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ fn main() -> Result<()> {
write_schema_for_response! {
bitwarden::auth::login::ApiKeyLoginResponse,
bitwarden::auth::login::PasswordLoginResponse,
bitwarden::auth::login::AccessTokenLoginResponse,
bitwarden::secrets_manager::secrets::SecretIdentifiersResponse,
bitwarden::secrets_manager::secrets::SecretResponse,
bitwarden::secrets_manager::secrets::SecretsResponse,
Expand Down
90 changes: 65 additions & 25 deletions languages/python/BitwardenClient/bitwarden_client.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json
from typing import Any, List
from typing import Any, List, Optional
from uuid import UUID
import bitwarden_py
from .schemas import ClientSettings, Command, PasswordLoginRequest, PasswordLoginResponse, ResponseForPasswordLoginResponse, ResponseForSecretIdentifiersResponse, ResponseForSecretResponse, ResponseForSecretsDeleteResponse, ResponseForSyncResponse, ResponseForUserAPIKeyResponse, SecretCreateRequest, SecretGetRequest, SecretIdentifiersRequest, SecretIdentifiersResponse, SecretPutRequest, SecretResponse, SecretVerificationRequest, SecretsCommand, SecretsDeleteRequest, SecretsDeleteResponse, SyncRequest, SyncResponse, UserAPIKeyResponse

from .schemas import ClientSettings, Command, ResponseForSecretIdentifiersResponse, ResponseForSecretResponse, ResponseForSecretsDeleteResponse, SecretCreateRequest, SecretGetRequest, SecretIdentifiersRequest, SecretIdentifiersResponse, SecretPutRequest, SecretResponse, SecretsCommand, SecretsDeleteRequest, SecretsDeleteResponse, AccessTokenLoginRequest, AccessTokenLoginResponse, ResponseForAccessTokenLoginResponse, ResponseForProjectResponse, ProjectsCommand, ProjectCreateRequest, ProjectGetRequest, ProjectPutRequest, ProjectsListRequest, ResponseForProjectsResponse, ResponseForProjectsDeleteResponse, ProjectsDeleteRequest

class BitwardenClient:
def __init__(self, settings: ClientSettings = None):
Expand All @@ -12,32 +12,25 @@ def __init__(self, settings: ClientSettings = None):
settings_json = json.dumps(settings.to_dict())
self.inner = bitwarden_py.BitwardenClient(settings_json)

def password_login(self, email: str, password: str) -> ResponseForPasswordLoginResponse:
result = self._run_command(
Command(password_login=PasswordLoginRequest(email, password))
)
return ResponseForPasswordLoginResponse.from_dict(result)

def get_user_api_key(self, secret: str, is_otp: bool = False) -> ResponseForUserAPIKeyResponse:
result = self._run_command(
Command(get_user_api_key=SecretVerificationRequest(
secret if not is_otp else None, secret if is_otp else None))
def access_token_login(self, access_token: str):
self._run_command(
Command(access_token_login=AccessTokenLoginRequest(access_token))
)
return ResponseForUserAPIKeyResponse.from_dict(result)

def sync(self, exclude_subdomains: bool = False) -> ResponseForSyncResponse:
result = self._run_command(
Command(sync=SyncRequest(exclude_subdomains))
)
return ResponseForSyncResponse.from_dict(result)

def secrets(self):
return SecretsClient(self)

def projects(self):
return ProjectsClient(self)

def _run_command(self, command: Command) -> Any:
response_json = self.inner.run_command(json.dumps(command.to_dict()))
return json.loads(response_json)
response = json.loads(response_json)

if response["success"] == False:
raise Exception(response["errorMessage"])

return response

class SecretsClient:
def __init__(self, client: BitwardenClient):
Expand All @@ -52,10 +45,12 @@ def get(self, id: str) -> ResponseForSecretResponse:
def create(self, key: str,
note: str,
organization_id: str,
value: str) -> ResponseForSecretResponse:
value: str,
project_ids: Optional[List[UUID]] = None
) -> ResponseForSecretResponse:
result = self.client._run_command(
Command(secrets=SecretsCommand(
create=SecretCreateRequest(key, note, organization_id, value)))
create=SecretCreateRequest(key, note, organization_id, value, project_ids)))
)
return ResponseForSecretResponse.from_dict(result)

Expand All @@ -70,10 +65,12 @@ def update(self, id: str,
key: str,
note: str,
organization_id: str,
value: str) -> ResponseForSecretResponse:
value: str,
project_ids: Optional[List[UUID]] = None
) -> ResponseForSecretResponse:
result = self.client._run_command(
Command(secrets=SecretsCommand(update=SecretPutRequest(
id, key, note, organization_id, value)))
id, key, note, organization_id, value, project_ids)))
)
return ResponseForSecretResponse.from_dict(result)

Expand All @@ -82,3 +79,46 @@ def delete(self, ids: List[str]) -> ResponseForSecretsDeleteResponse:
Command(secrets=SecretsCommand(delete=SecretsDeleteRequest(ids)))
)
return ResponseForSecretsDeleteResponse.from_dict(result)

class ProjectsClient:
def __init__(self, client: BitwardenClient):
self.client = client

def get(self, id: str) -> ResponseForProjectResponse:
result = self.client._run_command(
Command(projects=ProjectsCommand(get=ProjectGetRequest(id)))
)
return ResponseForProjectResponse.from_dict(result)

def create(self,
name: str,
organization_id: str,
) -> ResponseForProjectResponse:
result = self.client._run_command(
Command(projects=ProjectsCommand(
create=ProjectCreateRequest(name, organization_id)))
)
return ResponseForProjectResponse.from_dict(result)

def list(self, organization_id: str) -> ResponseForProjectsResponse:
result = self.client._run_command(
Command(projects=ProjectsCommand(
list=ProjectsListRequest(organization_id)))
)
return ResponseForProjectsResponse.from_dict(result)

def update(self, id: str,
name: str,
organization_id: str,
) -> ResponseForProjectResponse:
result = self.client._run_command(
Command(projects=ProjectsCommand(update=ProjectPutRequest(
id, name, organization_id)))
)
return ResponseForProjectResponse.from_dict(result)

def delete(self, ids: List[str]) -> ResponseForProjectsDeleteResponse:
result = self.client._run_command(
Command(projects=ProjectsCommand(delete=ProjectsDeleteRequest(ids)))
)
return ResponseForProjectsDeleteResponse.from_dict(result)
6 changes: 5 additions & 1 deletion languages/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
```bash
pip install setuptools_rust
```
- dateutil
```bash
pip install python-dateutil
```

# Installation

Expand All @@ -18,7 +22,7 @@ From the `languages/python/` directory,
python3 ./setup.py develop
```

Move the the resulting `.so` file to `bitwarden_py.so`, if it isn't already there.
Rename the the resulting `.so` file to `bitwarden_py.so`, if it isn't already there.

# Run

Expand Down
44 changes: 44 additions & 0 deletions languages/python/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import json
import logging
import sys
from BitwardenClient.bitwarden_client import BitwardenClient
from BitwardenClient.schemas import client_settings_from_dict, DeviceType

# Create the BitwardenClient, which is used to interact with the SDK
client = BitwardenClient(client_settings_from_dict({
"apiUrl": "http://localhost:4000",
"deviceType": DeviceType.SDK,
"identityUrl": "http://localhost:33656",
"userAgent": "Python",
}))

# Add some logging & set the org id
logging.basicConfig(level=logging.DEBUG)
organization_id = "org_id_here"

# Attempt to authenticate with the Secrets Manager Access Token
client.access_token_login("access_token_here")

# -- Example Project Commands --

project = client.projects().create("ProjectName", organization_id)
project2 = client.projects().create("Project - Don't Delete Me!", organization_id)
updated_project = client.projects().update(project.data.id, "Cool New Project Name", organization_id)
get_that_project = client.projects().get(project.data.id)

input("Press Enter to delete the project...")
client.projects().delete([project.data.id])

print(client.projects().list(organization_id))

# -- Example Secret Commands --

secret = client.secrets().create("TEST_SECRET", "This is a test secret", organization_id, "Secret1234!", [project2.data.id])
secret2 = client.secrets().create("Secret - Don't Delete Me!", "This is a test secret that will stay", organization_id, "Secret1234!", [project2.data.id])
secret_updated = client.secrets().update(secret.data.id, "TEST_SECRET_UPDATED", "This as an updated test secret", organization_id, "Secret1234!_updated", [project2.data.id])
secret_retrieved = client.secrets().get(secret.data.id)

input("Press Enter to delete the secret...")
client.secrets().delete([secret.data.id])

print(client.secrets().list(organization_id))
24 changes: 0 additions & 24 deletions languages/python/login.py

This file was deleted.

0 comments on commit 40f07a5

Please sign in to comment.