Skip to content

Commit dd4ea87

Browse files
committed
Update code to latestcore data passing model
1 parent 381023a commit dd4ea87

File tree

6 files changed

+80
-44
lines changed

6 files changed

+80
-44
lines changed

example/desktop_app.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# [developer-docs.sdk.python.sdk-import]-start
2+
from onepassword import *
3+
import asyncio
4+
5+
6+
async def main():
7+
# [developer-docs.sdk.python.client-initialization]-start
8+
# Connects to the 1Password desktop app.
9+
client = await Client.authenticate(
10+
auth=DesktopAuth(
11+
account_name="AndiTituTest" # Set to your 1Password account name.
12+
),
13+
# Set the following to your own integration name and version.
14+
integration_name="My 1Password Integration",
15+
integration_version="v1.0.0",
16+
)
17+
18+
# [developer-docs.sdk.python.list-vaults]-start
19+
vaults = await client.vaults.list()
20+
for vault in vaults:
21+
print(vault)
22+
# [developer-docs.sdk.python.list-vaults]-end
23+
24+
# [developer-docs.sdk.python.list-items]-start
25+
overviews = await client.items.list("xw33qlvug6moegr3wkk5zkenoa")
26+
for overview in overviews:
27+
print(overview.title)
28+
# [developer-docs.sdk.python.list-items]-end
29+
30+
31+
if __name__ == "__main__":
32+
asyncio.run(main())

src/onepassword/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ async def authenticate(
2525
integration_version=integration_version,
2626
)
2727

28-
if isinstance(auth, str):
28+
if isinstance(auth, DesktopAuth):
29+
core = DesktopCore(auth.account_name)
30+
else:
2931
core = UniffiCore()
30-
elif isinstance(auth, DesktopAuth):
31-
core = DesktopCore()
3232

3333
client_id = int(await core.init_client(config))
3434

src/onepassword/defaults.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,5 @@ def new_default_config(auth: DesktopAuth | str, integration_name, integration_ve
3434
}
3535
if isinstance(auth, str):
3636
client_config_dict["serviceAccountToken"] = auth
37-
elif isinstance(auth, DesktopAuth):
38-
client_config_dict["accountName"] = auth.account_name
3937

4038
return client_config_dict

src/onepassword/desktop_core.py

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,16 @@
11
import ctypes
22
import json
33
import os
4-
import platform
5-
import sys
4+
import base64
65
from ctypes import c_uint8, c_size_t, c_int32, POINTER, byref, c_void_p
76
from .core import UniffiCore
7+
from onepassword.errors import raise_typed_exception
88

99

1010
def find_1password_lib_path():
11-
host_os = platform.system().lower() # "darwin", "linux", "windows"
12-
13-
core = UniffiCore()
14-
if core is None:
15-
raise RuntimeError("failed to get ExtismCore")
16-
17-
locations_raw = core.invoke({
18-
"invocation": {
19-
"parameters": {
20-
"methodName": "GetDesktopAppIPCClientLocations",
21-
"serializedParams": {"host_os": host_os},
22-
}
23-
}
24-
})
25-
26-
try:
27-
locations = json.loads(locations_raw)
28-
except Exception as e:
29-
raise RuntimeError(f"failed to parse core response: {e}")
11+
locations = [
12+
"/Users/andititu/core/target/debug/libop_sdk_ipc_client.dylib"
13+
]
3014

3115
for lib_path in locations:
3216
if os.path.exists(lib_path):
@@ -35,11 +19,12 @@ def find_1password_lib_path():
3519
raise FileNotFoundError("1Password desktop application not found")
3620

3721
class DesktopCore:
38-
def __init__(self):
22+
def __init__(self, account_name: str):
3923
# Determine the path to the desktop app.
4024
path = find_1password_lib_path()
4125

4226
self.lib = ctypes.CDLL(path)
27+
self.account_name = account_name
4328

4429
# Bind the Rust-exported functions
4530
self.send_message = self.lib.op_sdk_ipc_send_message
@@ -56,43 +41,59 @@ def __init__(self):
5641
self.free_message.argtypes = [POINTER(c_uint8), c_size_t, c_size_t]
5742
self.free_message.restype = None
5843

59-
def call_shared_library(self, payload: bytes) -> bytes:
44+
def call_shared_library(self, payload: str, operation_kind: str) -> bytes:
45+
# Prepare the input
46+
encoded_payload = base64.b64encode(payload.encode("utf-8")).decode("utf-8")
47+
data = {
48+
"kind": operation_kind,
49+
"account_name": self.account_name,
50+
"payload": encoded_payload,
51+
}
52+
message = json.dumps(data).encode("utf-8")
53+
54+
# Prepare output parameters
6055
out_buf = POINTER(c_uint8)()
6156
out_len = c_size_t()
6257
out_cap = c_size_t()
6358

6459
ret = self.send_message(
65-
(ctypes.cast(payload, POINTER(c_uint8))),
66-
len(payload),
60+
(ctypes.cast(message, POINTER(c_uint8))),
61+
len(message),
6762
byref(out_buf),
6863
byref(out_len),
6964
byref(out_cap),
7065
)
7166

7267
if ret != 0:
73-
raise RuntimeError(f"send_message failed with code {ret}")
68+
raise RuntimeError(f"send_message failed with code {ret}. Please make sure the Desktop app intehration setting is enabled, or contact 1Password support.")
7469

7570
# Copy bytes into Python
7671
data = ctypes.string_at(out_buf, out_len.value)
7772

7873
# Free memory via Rust's exported function
7974
self.free_message(out_buf, out_len, out_cap)
8075

81-
return data
76+
parsed = json.loads(data)
77+
payload = bytes(parsed.get("payload", [])).decode("utf-8")
78+
79+
success = parsed.get("success", False)
80+
if not success:
81+
raise_typed_exception(Exception(str(payload)))
82+
83+
return payload
8284

83-
def init_client(self, config: dict) -> int:
84-
payload = json.dumps(config).encode("utf-8")
85-
resp = self.call_shared_library(payload)
85+
async def init_client(self, config: dict) -> int:
86+
payload = json.dumps(config)
87+
resp = self.call_shared_library(payload, "init_client")
8688
return json.loads(resp)
8789

88-
def invoke(self, invoke_config: dict) -> str:
89-
payload = json.dumps(invoke_config).encode("utf-8")
90-
resp = self.call_shared_library(payload)
91-
return resp.decode("utf-8")
90+
async def invoke(self, invoke_config: dict) -> str:
91+
payload = json.dumps(invoke_config)
92+
return self.call_shared_library(payload, "invoke")
9293

9394
def release_client(self, client_id: int):
94-
payload = json.dumps(client_id).encode("utf-8")
95+
payload = json.dumps(client_id)
9596
try:
96-
self.call_shared_library(payload)
97+
self.call_shared_library(payload, "release_client")
9798
except Exception as e:
9899
print(f"failed to release client: {e}")

src/onepassword/types.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,3 +1159,8 @@ class WordListType(str, Enum):
11591159
"""
11601160
Three (random) letter "words"
11611161
"""
1162+
1163+
class VaultListParams(BaseModel):
1164+
model_config = ConfigDict(populate_by_name=True)
1165+
1166+
decrypt_details: Optional[bool] = Field(alias="decryptDetails", default=None)

src/onepassword/vaults.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .core import Core
44
from typing import Optional, List
55
from pydantic import TypeAdapter
6-
from .types import VaultOverview
6+
from .types import VaultOverview, VaultListParams
77

88

99
class Vaults:
@@ -15,15 +15,15 @@ def __init__(self, client_id, core):
1515
self.client_id = client_id
1616
self.core = core
1717

18-
async def list(self) -> List[VaultOverview]:
18+
async def list(self, params: Optional[VaultListParams] = None) -> List[VaultOverview]:
1919
"""
2020
List all vaults
2121
"""
2222
response = await self.core.invoke(
2323
{
2424
"invocation": {
2525
"clientId": self.client_id,
26-
"parameters": {"name": "VaultsList", "parameters": {}},
26+
"parameters": {"name": "VaultsList", "parameters": {"params": params.model_dump(by_alias=True) if params else {}}},
2727
}
2828
}
2929
)

0 commit comments

Comments
 (0)