Skip to content
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
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,18 +87,18 @@ Operations:
- [x] [Create items](https://developer.1password.com/docs/sdks/manage-items#create-an-item)
- [x] [Update items](https://developer.1password.com/docs/sdks/manage-items#update-an-item)
- [x] [Delete items](https://developer.1password.com/docs/sdks/manage-items#delete-an-item)
- [x] Archive items
- [x] [Archive items](https://developer.1password.com/docs/sdks/manage-items/#archive-an-item)
- [x] [List items](https://developer.1password.com/docs/sdks/list-vaults-items/)
- [x] Share items
- [x] Generate PIN, random and memorable passwords
- [x] [Share items](https://developer.1password.com/docs/sdks/share-items) (items with files cannot be shared)
- [x] [Generate PIN, random and memorable passwords](https://developer.1password.com/docs/sdks/manage-items#generate-a-password)

Field types:
- [x] API Keys
- [x] Passwords
- [x] Concealed fields
- [x] Text fields
- [x] Notes
- [x] SSH private keys, public keys, fingerprint and key type (partially supported: supported in resolving secret references, not yet supported in item create/get/update)
- [x] SSH private keys, public keys, fingerprint and key type
- [x] One-time passwords
- [x] URLs
- [x] Websites (used to suggest and autofill logins)
Expand All @@ -108,8 +108,10 @@ Field types:
- [x] Emails
- [x] References to other items
- [ ] Address
- [ ] Date / MM/YY
- [ ] Files attachments and Document items
- [ ] Date
- [x] MM/YY
- [x] Files attachments and Document items
- [x] Menu

### Vault management
- [ ] Retrieve vaults
Expand Down
156 changes: 156 additions & 0 deletions example/example.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import asyncio
import os
from pathlib import Path

# [developer-docs.sdk.python.sdk-import]-start
from onepassword import *

# [developer-docs.sdk.python.sdk-import]-end
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization


async def main():
Expand Down Expand Up @@ -167,6 +171,12 @@ async def main():

await share_item(client, created_item.vault_id, updated_item.id)

await create_ssh_key_item(client)

await create_and_replace_document_item(client)

await create_attach_and_delete_file_field_item(client)

# [developer-docs.sdk.python.delete-item]-start
# Delete a item from your vault.
await client.items.delete(created_item.vault_id, updated_item.id)
Expand Down Expand Up @@ -218,5 +228,151 @@ async def share_item(client: Client, vault_id: str, item_id: str):
# [developer-docs.sdk.python.item-share-create-share]-end


async def create_ssh_key_item(client: Client):
# Generate a 2048-bit RSA private key
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
)

# Serialize the private key in PKCS8 format (PEM)
ssh_key_pkcs8_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)

# [developer-docs.sdk.python.create-sshkey-item]-start
# Create an Item containing SSH Key and add it to your vault.
to_create = ItemCreateParams(
title="SSH Key Item Created With Python SDK",
category=ItemCategory.SSHKEY,
vault_id="7turaasywpymt3jecxoxk5roli",
fields=[
ItemField(
id="private_key",
title="private key",
field_type=ItemFieldType.SSHKEY,
value=ssh_key_pkcs8_pem,
sectionId="",
),
],
sections=[
ItemSection(id="", title=""),
],
)
created_item = await client.items.create(to_create)

print(created_item.fields[0].value)
print(created_item.fields[0].details.content.public_key)
print(created_item.fields[0].details.content.fingerprint)
print(created_item.fields[0].details.content.key_type)
# [developer-docs.sdk.python.create-sshkey-item]-end
await client.items.delete(created_item.vault_id, created_item.id)


async def create_and_replace_document_item(client: Client):
# [developer-docs.sdk.python.create-document-item]-start
# Create a Document Item
to_create = ItemCreateParams(
title="Document Item Created with Python SDK",
category=ItemCategory.DOCUMENT,
vault_id="7turaasywpymt3jecxoxk5roli",
sections=[
ItemSection(id="", title=""),
],
document=DocumentCreateParams(
name="file.txt", content=Path("./example/file.txt").read_bytes()
),
)
created_item = await client.items.create(to_create)
# [developer-docs.sdk.python.create-document-item]-end

# [developer-docs.sdk.python.replace-document-item]-start
# Replace the document in the item
replaced_item = await client.items.files.replace_document(
created_item,
DocumentCreateParams(
name="file2.txt", content=Path("./example/file2.txt").read_bytes()
),
)
# [developer-docs.sdk.python.replace-document-item]-end

# [developer-docs.sdk.python.read-document-item]-start
# Read the document in the item
content = await client.items.files.read(
replaced_item.vault_id, replaced_item.id, replaced_item.document
)
# [developer-docs.sdk.python.read-document-item]-end

print(content.decode())

await client.items.delete(replaced_item.vault_id, replaced_item.id)


async def create_attach_and_delete_file_field_item(client: Client):
# [developer-docs.sdk.python.create-item-with-file-field]-start
# Create a File Field Item
to_create = ItemCreateParams(
title="FileField Item created with Python SDK",
category=ItemCategory.LOGIN,
vault_id="7turaasywpymt3jecxoxk5roli",
fields=[
ItemField(
id="username",
title="username",
field_type=ItemFieldType.TEXT,
value="mynameisjeff",
),
ItemField(
id="password",
title="password",
field_type=ItemFieldType.CONCEALED,
value="jeff",
),
],
sections=[
ItemSection(id="", title=""),
],
files=[
FileCreateParams(
name="file.txt",
content=Path("./example/file.txt").read_bytes(),
sectionId="",
fieldId="file_field",
)
],
)

created_item = await client.items.create(to_create)
# [developer-docs.sdk.python.create-item-with-file-field]-end

# [developer-docs.sdk.python.attach-file-field-item]-start
# Attach a file field to the item
attached_item = await client.items.files.attach(
created_item,
FileCreateParams(
name="file2.txt",
content=Path("./example/file2.txt").read_bytes(),
sectionId="",
fieldId="new_file_field",
),
)
# [developer-docs.sdk.python.attach-file-field-item]-end

# [developer-docs.sdk.python.delete-file-field-item]-start
# Delete a file field from an item
deleted_file_item = await client.items.files.delete(
attached_item,
attached_item.files[1].section_id,
attached_item.files[1].field_id,
)
# [developer-docs.sdk.python.delete-file-field-item]-end

print(len(deleted_file_item.files))

await client.items.delete(deleted_file_item.vault_id, deleted_file_item.id)


if __name__ == "__main__":
asyncio.run(main())
1 change: 1 addition & 0 deletions example/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello World!
1 change: 1 addition & 0 deletions example/file2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello again, world!
2 changes: 1 addition & 1 deletion src/onepassword/build_number.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SDK_BUILD_NUMBER = "0010701"
SDK_BUILD_NUMBER = "0020001"
16 changes: 14 additions & 2 deletions src/onepassword/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

from onepassword.errors import raise_typed_exception

# In empirical tests, we determined that maximum message size that can cross the FFI boundary
# is ~128MB. Past this limit, FFI will throw an error and the program will crash.
# We set the limit to 50MB to be safe and consistent with the other SDKs (where this limit is 64MB), to be reconsidered upon further testing
MESSAGE_LIMIT = 50 * 1024 * 1024

machine_arch = platform.machine().lower()

Expand All @@ -26,16 +30,24 @@ async def _init_client(client_config):

# Invoke calls specified business logic from the SDK core.
async def _invoke(invoke_config):
serialized_config = json.dumps(invoke_config)
if len(serialized_config.encode()) > MESSAGE_LIMIT:
raise ValueError(
f"message size exceeds the limit of {MESSAGE_LIMIT} bytes, please contact 1Password at [email protected] or https://developer.1password.com/joinslack if you need help.")
try:
return await core.invoke(json.dumps(invoke_config))
return await core.invoke(serialized_config)
except Exception as e:
raise_typed_exception(e)


# Invoke calls specified business logic from the SDK core.
def _invoke_sync(invoke_config):
serialized_config = json.dumps(invoke_config)
if len(serialized_config.encode()) > MESSAGE_LIMIT:
raise ValueError(
f"message size exceeds the limit of {MESSAGE_LIMIT} bytes, please contact 1Password at [email protected] or https://developer.1password.com/joinslack if you need help.")
try:
return core.invoke_sync(json.dumps(invoke_config))
return core.invoke_sync(serialized_config)
except Exception as e:
raise_typed_exception(e)

Expand Down
3 changes: 3 additions & 0 deletions src/onepassword/items.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Code generated by op-codegen - DO NO EDIT MANUALLY

from .core import _invoke, _invoke_sync

Check failure on line 3 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:3:28: F401 `.core._invoke_sync` imported but unused

Check failure on line 3 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:3:28: F401 `.core._invoke_sync` imported but unused

Check failure on line 3 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:3:28: F401 `.core._invoke_sync` imported but unused

Check failure on line 3 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:3:28: F401 `.core._invoke_sync` imported but unused
from .iterator import SDKIterator
from typing import Optional, List

Check failure on line 5 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:5:20: F401 `typing.Optional` imported but unused

Check failure on line 5 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:5:20: F401 `typing.Optional` imported but unused

Check failure on line 5 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:5:20: F401 `typing.Optional` imported but unused

Check failure on line 5 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items.py:5:20: F401 `typing.Optional` imported but unused
from pydantic import TypeAdapter
from .items_shares import ItemsShares
from .items_files import ItemsFiles
from .types import Item, ItemCreateParams, ItemOverview


Expand All @@ -17,6 +18,8 @@
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.
Expand Down Expand Up @@ -78,7 +81,7 @@
"""
Delete an item.
"""
response = await _invoke(

Check failure on line 84 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:84:9: F841 Local variable `response` is assigned to but never used

Check failure on line 84 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:84:9: F841 Local variable `response` is assigned to but never used

Check failure on line 84 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:84:9: F841 Local variable `response` is assigned to but never used

Check failure on line 84 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:84:9: F841 Local variable `response` is assigned to but never used
{
"invocation": {
"clientId": self.client_id,
Expand All @@ -96,7 +99,7 @@
"""
Archive an item.
"""
response = await _invoke(

Check failure on line 102 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:102:9: F841 Local variable `response` is assigned to but never used

Check failure on line 102 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:102:9: F841 Local variable `response` is assigned to but never used

Check failure on line 102 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:102:9: F841 Local variable `response` is assigned to but never used

Check failure on line 102 in src/onepassword/items.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F841)

src/onepassword/items.py:102:9: F841 Local variable `response` is assigned to but never used
{
"invocation": {
"clientId": self.client_id,
Expand Down
104 changes: 104 additions & 0 deletions src/onepassword/items_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Code generated by op-codegen - DO NO EDIT MANUALLY

from .core import _invoke, _invoke_sync

Check failure on line 3 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:3:28: F401 `.core._invoke_sync` imported but unused

Check failure on line 3 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:3:28: F401 `.core._invoke_sync` imported but unused

Check failure on line 3 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:3:28: F401 `.core._invoke_sync` imported but unused

Check failure on line 3 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:3:28: F401 `.core._invoke_sync` imported but unused
from .iterator import SDKIterator

Check failure on line 4 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:4:23: F401 `.iterator.SDKIterator` imported but unused

Check failure on line 4 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:4:23: F401 `.iterator.SDKIterator` imported but unused

Check failure on line 4 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:4:23: F401 `.iterator.SDKIterator` imported but unused

Check failure on line 4 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:4:23: F401 `.iterator.SDKIterator` imported but unused
from typing import Optional, List

Check failure on line 5 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:5:20: F401 `typing.Optional` imported but unused

Check failure on line 5 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:5:20: F401 `typing.Optional` imported but unused

Check failure on line 5 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:5:20: F401 `typing.Optional` imported but unused

Check failure on line 5 in src/onepassword/items_files.py

View workflow job for this annotation

GitHub Actions / Lint

Ruff (F401)

src/onepassword/items_files.py:5:20: F401 `typing.Optional` imported but unused
from pydantic import TypeAdapter
from .types import DocumentCreateParams, FileAttributes, FileCreateParams, Item


class ItemsFiles:
def __init__(self, client_id):
self.client_id = client_id

async def attach(self, item: Item, file_params: FileCreateParams) -> 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, section_id: str, field_id: str) -> Item:
"""
Delete a field file from Item using the section and field IDs
"""
response = await _invoke(
{
"invocation": {
"clientId": self.client_id,
"parameters": {
"name": "ItemsFilesDelete",
"parameters": {
"item": item.model_dump(by_alias=True),
"section_id": section_id,
"field_id": field_id,
},
},
}
}
)

response = TypeAdapter(Item).validate_json(response)
return response

async def replace_document(
self, item: Item, doc_params: DocumentCreateParams
) -> Item:
"""
Replace the document file within a document item
"""
response = await _invoke(
{
"invocation": {
"clientId": self.client_id,
"parameters": {
"name": "ItemsFilesReplaceDocument",
"parameters": {
"item": item.model_dump(by_alias=True),
"doc_params": doc_params.model_dump(by_alias=True),
},
},
}
}
)

response = TypeAdapter(Item).validate_json(response)
return response
2 changes: 2 additions & 0 deletions src/onepassword/iterator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Code generated by op-codegen - DO NOT EDIT MANUALLY

import asyncio
from typing import AsyncIterator, Iterable, TypeVar

Expand Down
Binary file modified src/onepassword/lib/aarch64/libop_uniffi_core.dylib
Binary file not shown.
Binary file modified src/onepassword/lib/aarch64/libop_uniffi_core.so
Binary file not shown.
Binary file modified src/onepassword/lib/x86_64/libop_uniffi_core.dylib
Binary file not shown.
Binary file modified src/onepassword/lib/x86_64/libop_uniffi_core.so
Binary file not shown.
Binary file modified src/onepassword/lib/x86_64/op_uniffi_core.dll
Binary file not shown.
Loading
Loading