diff --git a/src/onepassword/items.py b/src/onepassword/items.py index cfff2634..8d0bf013 100644 --- a/src/onepassword/items.py +++ b/src/onepassword/items.py @@ -5,6 +5,7 @@ from typing import Optional, List from pydantic import TypeAdapter from .items_shares import ItemsShares +from .items_files import ItemsFiles from .types import Item, ItemCreateParams, ItemOverview @@ -17,6 +18,8 @@ def __init__(self, client_id): self.client_id = client_id self.shares = ItemsShares(client_id) + self.files = ItemsFiles(client_id) + async def create(self, params: ItemCreateParams) -> Item: """ Create a new item. diff --git a/src/onepassword/items_files.py b/src/onepassword/items_files.py new file mode 100644 index 00000000..b4118e88 --- /dev/null +++ b/src/onepassword/items_files.py @@ -0,0 +1,79 @@ +# Code generated by op-codegen - DO NO EDIT MANUALLY + +from .core import _invoke, _invoke_sync +from .iterator import SDKIterator +from typing import Optional, List +from pydantic import TypeAdapter +from .types import FileAttachParams, FileAttributes, Item + + +class ItemsFiles: + def __init__(self, client_id): + self.client_id = client_id + + async def attach(self, item: Item, file_params: FileAttachParams) -> Item: + """ + Attach files to Items + """ + response = await _invoke( + { + "invocation": { + "clientId": self.client_id, + "parameters": { + "name": "ItemsFilesAttach", + "parameters": { + "item": item.model_dump(by_alias=True), + "file_params": file_params.model_dump(by_alias=True), + }, + }, + } + } + ) + + response = TypeAdapter(Item).validate_json(response) + return response + + async def read(self, vault_id: str, item_id: str, attr: FileAttributes) -> bytes: + """ + Read file content from the Item + """ + response = await _invoke( + { + "invocation": { + "clientId": self.client_id, + "parameters": { + "name": "ItemsFilesRead", + "parameters": { + "vault_id": vault_id, + "item_id": item_id, + "attr": attr.model_dump(by_alias=True), + }, + }, + } + } + ) + + response = bytes(TypeAdapter(List[int]).validate_json(response)) + return response + + async def delete(self, item: Item, file_id: str) -> Item: + """ + Delete files from Item + """ + response = await _invoke( + { + "invocation": { + "clientId": self.client_id, + "parameters": { + "name": "ItemsFilesDelete", + "parameters": { + "item": item.model_dump(by_alias=True), + "file_id": file_id, + }, + }, + } + } + ) + + response = TypeAdapter(Item).validate_json(response) + return response diff --git a/src/onepassword/lib/aarch64/libop_uniffi_core.dylib b/src/onepassword/lib/aarch64/libop_uniffi_core.dylib index 25af7a9e..7edf4f04 100755 Binary files a/src/onepassword/lib/aarch64/libop_uniffi_core.dylib and b/src/onepassword/lib/aarch64/libop_uniffi_core.dylib differ diff --git a/src/onepassword/lib/aarch64/libop_uniffi_core.so b/src/onepassword/lib/aarch64/libop_uniffi_core.so index 2295767d..e35514f4 100755 Binary files a/src/onepassword/lib/aarch64/libop_uniffi_core.so and b/src/onepassword/lib/aarch64/libop_uniffi_core.so differ diff --git a/src/onepassword/lib/x86_64/libop_uniffi_core.dylib b/src/onepassword/lib/x86_64/libop_uniffi_core.dylib index 4cb38755..64260813 100755 Binary files a/src/onepassword/lib/x86_64/libop_uniffi_core.dylib and b/src/onepassword/lib/x86_64/libop_uniffi_core.dylib differ diff --git a/src/onepassword/lib/x86_64/libop_uniffi_core.so b/src/onepassword/lib/x86_64/libop_uniffi_core.so index e5e3dfe6..ee8408a8 100755 Binary files a/src/onepassword/lib/x86_64/libop_uniffi_core.so and b/src/onepassword/lib/x86_64/libop_uniffi_core.so differ diff --git a/src/onepassword/lib/x86_64/op_uniffi_core.dll b/src/onepassword/lib/x86_64/op_uniffi_core.dll index 93f1b0ae..f4bf4549 100644 Binary files a/src/onepassword/lib/x86_64/op_uniffi_core.dll and b/src/onepassword/lib/x86_64/op_uniffi_core.dll differ diff --git a/src/onepassword/types.py b/src/onepassword/types.py index 66dce22f..0d460b4c 100644 --- a/src/onepassword/types.py +++ b/src/onepassword/types.py @@ -5,8 +5,92 @@ from __future__ import annotations from enum import Enum -from pydantic import BaseModel, ConfigDict, Field -from typing import List, Literal, Optional, Union +from pydantic import BaseModel, BeforeValidator, ConfigDict, Field, PlainSerializer +from typing import Annotated, List, Literal, Optional, Union + + +def serialize_binary_data(value: bytes) -> list[int]: + return list(value) + + +def deserialize_binary_data(value): + if isinstance(value, list): + if all(isinstance(x, int) and 0 <= x <= 255 for x in value): + return bytes(value) + raise ValueError("All elements must be integers in the range 0-255 (u8).") + elif isinstance(value, bytes): + return value + raise TypeError("Content must be a list of integers (0-255) or bytes.") + + +class FilePositionFieldFileInner(BaseModel): + """ + Generated type representing the anonymous struct variant `FieldFile` of the `FilePosition` Rust enum + """ + + model_config = ConfigDict(populate_by_name=True) + + section_id: str = Field(alias="sectionId") + field_id: str = Field(alias="fieldId") + + +class FilePositionTypes(str, Enum): + DOCUMENT = "Document" + FIELD_FILE = "FieldFile" + + +class FilePositionDocument(BaseModel): + """ + The document file saved in a Document item (can only be used with items of Document category) + """ + + type: Literal[FilePositionTypes.DOCUMENT] = FilePositionTypes.DOCUMENT + + +class FilePositionFieldFile(BaseModel): + """ + A file stored as an item field + """ + + type: Literal[FilePositionTypes.FIELD_FILE] = FilePositionTypes.FIELD_FILE + content: FilePositionFieldFileInner + + +FilePosition = Union[FilePositionDocument, FilePositionFieldFile] + + +class FileAttachParams(BaseModel): + name: str + """ + the name of the file + """ + content: Annotated[ + bytes, + BeforeValidator(deserialize_binary_data), + PlainSerializer(serialize_binary_data), + ] + """ + the content of the file + """ + position: FilePosition + """ + where the file is stored in the item + """ + + +class FileAttributes(BaseModel): + name: str + """ + The name of the file + """ + id: str + """ + The ID of the file retrieved from the server + """ + size: int + """ + The size of the file in bytes + """ class GeneratePasswordResponse(BaseModel): @@ -58,11 +142,14 @@ class ItemFieldType(str, Enum): TOTP = "Totp" EMAIL = "Email" REFERENCE = "Reference" + SSHKEY = "SshKey" + MENU = "Menu" UNSUPPORTED = "Unsupported" class ItemFieldDetailsTypes(str, Enum): OTP = "Otp" + SSH_KEY = "SshKey" class ItemFieldDetailsOtp(BaseModel): @@ -74,8 +161,17 @@ class ItemFieldDetailsOtp(BaseModel): content: OtpFieldDetails +class ItemFieldDetailsSshKey(BaseModel): + """ + Computed SSH Key attributes + """ + + type: Literal[ItemFieldDetailsTypes.SSH_KEY] = ItemFieldDetailsTypes.SSH_KEY + content: Optional[SshKeyAttributes] + + # Field type-specific attributes. -ItemFieldDetails = ItemFieldDetailsOtp +ItemFieldDetails = Union[ItemFieldDetailsOtp, ItemFieldDetailsSshKey] class ItemField(BaseModel): @@ -167,6 +263,17 @@ class Website(BaseModel): """ +class ItemFile(BaseModel): + attributes: FileAttributes + """ + the attributes of the file + """ + position: FilePosition + """ + where the file is stored in the item + """ + + class Item(BaseModel): """ Represents a 1Password item. @@ -214,6 +321,10 @@ class Item(BaseModel): """ The item's version """ + files: List[ItemFile] + """ + The item's files + """ class ItemCreateParams(BaseModel): @@ -251,6 +362,10 @@ class ItemCreateParams(BaseModel): """ The websites used for autofilling for items of the Login and Password categories. """ + files: Optional[List[FileAttachParams]] = Field(default=None) + """ + The item's files + """ class ItemOverview(BaseModel): @@ -453,6 +568,23 @@ class OtpFieldDetails(BaseModel): """ +class SshKeyAttributes(BaseModel): + model_config = ConfigDict(populate_by_name=True) + + public_key: str = Field(alias="publicKey") + """ + The public part of the SSH Key + """ + fingerprint: str + """ + The fingerprint of the SSH Key + """ + key_type: str = Field(alias="keyType") + """ + The key type ("Ed25519" or "RSA, {length}-bit") + """ + + class VaultOverview(BaseModel): """ Represents a decrypted 1Password vault.