GithubHelp home page GithubHelp logo

1password / connect-sdk-python Goto Github PK

View Code? Open in Web Editor NEW
199.0 17.0 31.0 274 KB

Python SDK for 1Password Connect

Home Page: https://developer.1password.com/docs/connect

License: MIT License

Python 96.82% Makefile 1.23% Shell 1.87% Dockerfile 0.08%
1password 1password-connect connect-sdk python secrets-management

connect-sdk-python's People

Contributors

davidtran001 avatar dckcode avatar dependabot[bot] avatar edif2008 avatar haddadjoe avatar hculea avatar itjamie avatar jillianwilson avatar jpcoenen avatar justintether avatar marton6 avatar melwil avatar mjpieters avatar raphapassini avatar simonbarendse avatar tdb avatar verkaufer avatar volodymyrzotov avatar williamhpark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

connect-sdk-python's Issues

AttributeError: type object 'type' has no attribute '__annotations__'

Hi!
Im trying to initialize my config via load method:

class Config:
    SECRET: 'opitem:"Secret key" opvault:vault_id opfield:.password' = None

onepasswordconnectsdk.load(client, Config)

But I have the error on this line

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/code.py", line 90, in runcode
    exec(code, self.locals)
  File "<console>", line 1, in <module>
  File "/usr/local/lib/python3.9/site-packages/onepasswordconnectsdk/config.py", line 110, in load
    annotations = config.__class__.__annotations__
AttributeError: type object 'type' has no attribute '__annotations__'

The correct way of getting annotations is

annotations = config.__annotations__

Python 3.9
onepasswordconnectsdk==1.0.1

get_item fails if pass item title of 26characters in length

What happened?

get_item fails if pass item title of 26 characters in length.

 if is_valid_uuid(item):
            return self.get_item_by_id(item, vault_id)
else:
            return self.get_item_by_title(item, vault_id)

What did you expect to happen?

It should search by item title if title is has a length of 26. We try to get it by ID, and if that fails, try by title instead.

Steps to reproduce

use get_item and pass item params as random 26 chars random string

Invalid value for `type` (OTP), must be one of ['STRING', 'EMAIL', 'CONCEALED', 'URL', 'TOTP', 'DATE', 'MONTH_YEAR', 'MENU']

Your environment

SDK Version: 1.0.1

Connect Server Version: 1.0.0

OS: Windows10

Python Version: 3.9.4

What happened?

attempting to retrieve data
client.get_item("vaultID","itemID")

What did you expect to happen?

Should have returned item details1

Steps to reproduce

create a login on the 1password website, set a field to be used as a one time password with code then attempt to retrieve the data

Notes & Logs

Traceback (most recent call last):
File "c:\python_testing\1password-test.py", line 14, in
print(client.get_item("vaultID--retracted", "itemID--retracted"))
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 76, in get_item
return self.deserialize(response.content, "Item")
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 294, in deserialize
return self.__deserialize(data, response_type)
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 377, in __deserialize
return self.__deserialize_model(data, klass)
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 461, in __deserialize_model
kwargs[attr] = self.__deserialize(value, attr_type)
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 354, in __deserialize
return [self.__deserialize(sub_data, sub_kls) for sub_data in data] # noqa: E501
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 354, in
return [self.__deserialize(sub_data, sub_kls) for sub_data in data] # noqa: E501
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 377, in __deserialize
return self.__deserialize_model(data, klass)
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\client.py", line 463, in __deserialize_model
instance = klass(**kwargs)
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\models\field.py", line 70, in init
self.type = type
File "C:\Python39\lib\site-packages\onepasswordconnectsdk\models\field.py", line 144, in type
raise ValueError(
ValueError: Invalid value for type (OTP), must be one of ['STRING', 'EMAIL', 'CONCEALED', 'URL', 'TOTP', 'DATE', 'MONTH_YEAR', 'MENU']

Upgrade 'certifi' package version

There is a security vulnerability found in one of our dependencies certifi

Certifi 2023.07.22 removes root certificates from "e-Tugra" from the root store. These are in the process of being removed from Mozilla's trust store.

e-Tugra's root certificates are being removed pursuant to an investigation prompted by reporting of security issues in their systems. Conclusions of Mozilla's investigation can be found [here](https://groups.google.com/a/mozilla.org/g/dev-security-policy/c/C-HrP1SEq1A).

Link to Depenabot alert

Add option to enable / disable async to new_client_from_env()

Summary

Allow the program to decide on async vs sync client use when loading the credentials from the environment.

Use cases

Whether or not an async client is needed is a choice for the specific application code, not the environment. Please allow me to load an async client in an async codebase, and a sync client in a sync codebase:

def sync_main():
    client = new_client_from_env(is_async=False)

async def async_main():
    client = new_client_from_env(is_async=True)

Proposed solution

Add a new is_async keyword argument to new_client_from_env(), defaulting to None. If it is left to the default, the environment variable is used, otherwise the value is passed on directly to new_client():

from typing import Optional

# ...

def new_client_from_environment(
    url: Optional[str] = None, token: Optional[str] = None, is_async: Optional[bool] = None
):
    # ...
    if is_async is None:
        is_async = os.environ.get(ENV_IS_ASYNC_CLIENT).lower() in ("t", "true", "1")
    # ...
    return new_client(url, token, is_async=is_async)

(I made the test for ENV_IS_ASYNC_CLIENT a little broader to also accept T, true, 1, etc, as signalling 'true')

Is there a workaround to accomplish this today?

I have to options right now:

  • set the ENV_IS_ASYNC_CLIENT environment variable manually before calling new_client_from_environment(). This feels very, very janky. I should not have to manipulate the environment variables visible to a 3rd-party SDK to switch between async modes for my code base.
  • use new_client() directly but then miss out on the helpful validation that new_client_from_environment() also provides.

Retrieve items and fields based on op://.* url

Summary

Allow item details to be retrieved using it's op:// url. For example, when secret reference is created it would be nice to have the text directly retrieved by the sdk.

Use cases

It would be more secure as only that field would be pulled rather than pulling the whole secret. This would also avoid useless parsing of big dict of items returned by the api and allow direct reference of a certain field.

Proposed solution

Create .get_item_by_url that will either pull a whole item or a specific field based on the passed url. for example op://vault/item/[section/]field

Is there a workaround to accomplish this today?

Not that i'm aware of. Happy to hear if there's any?!

FailedToRetrieveVaultException: Unable to retrieve vaults.

Hi,

Playing around with Secrets Automation and trying to use the Python SDK for this.
I've deployed the Connect server via the docker-compose file that is on the 1password website and can see this is running a connect-sync and connect-api container.

from onepasswordconnectsdk.client import (
    Client,
    new_client_from_environment,
    new_client
)

client: Client = new_client_from_environment("http://localhost:8080")
print(client.get_vaults())

When run with my OP_CONNECT_TOKEN set, returns:
onepasswordconnectsdk.client.FailedToRetrieveVaultException: Unable to retrieve vaults. Received 500 for /v1/vaults with message failed to initiate, review service logs for details

Logs in the API container show:

op-connect-api_1   | {"log_message":"(I) GET /v1/vaults","timestamp":"2021-04-14T08:08:57.118532Z","level":3,"scope":{"request_id":"b4c0866b-2f73-4037-8e71-99ededcc54cc"}}
op-connect-api_1   | {"log_message":"(I) notifying syncer of new token","timestamp":"2021-04-14T08:08:57.120932Z","level":3,"scope":{"request_id":"b4c0866b-2f73-4037-8e71-99ededcc54cc","jti":"dxrh5akt7p7s4iumyc5hpl275m"}}
op-connect-api_1   | {"log_message":"(I) awaiting healthy syncer before continuing","timestamp":"2021-04-14T08:08:57.124482Z","level":3,"scope":{"request_id":"b4c0866b-2f73-4037-8e71-99ededcc54cc","jti":"dxrh5akt7p7s4iumyc5hpl275m"}}
op-connect-api_1   | {"log_message":"(E) syncer did not become healthy, terminating request","timestamp":"2021-04-14T08:09:07.127257Z","level":1,"scope":{"request_id":"b4c0866b-2f73-4037-8e71-99ededcc54cc","jti":"dxrh5akt7p7s4iumyc5hpl275m"}}
op-connect-api_1   | {"log_message":"(I) GET /v1/vaults completed (500: Internal Server Error)","timestamp":"2021-04-14T08:09:07.12877Z","level":3,"scope":{"request_id":"b4c0866b-2f73-4037-8e71-99ededcc54cc","jti":"dxrh5akt7p7s4iumyc5hpl275m"}}

From what I can see, 1 key part stands out:
(E) syncer did not become healthy, terminating request

beyond this log message, it is not clear where the issue is or how I could continue to debug this so apologies for not providing
more info.

Updating an existing item changes the layout of field

Your environment

SDK Version: v1.1.0

Connect Server Version: Docker image 1password/connect-sync@sha256:ea4ee8de21de22edcf35b4218fe4ce0c18f3806b7e3b259e5a7e0f98065fed45, created around 2021-05-20

OS: Ubuntu 20.04

Python Version: 3.8

What happened?

We created a default password item in a vault, here's the initial structure:

{
  "id": "6go6qftma5enrxxxxxxxx",
  "title": "AWS_ACCESS_KEY_ID",
  "version": 1,
  "vault": { "id": "akvk5ifqsjge7xxxxxxxxx" },
  "category": "PASSWORD",
  "sections": [{ "id": "linked items", "label": "Related Items" }],
  "fields": [
    {
      "id": "password",
      "type": "CONCEALED",
      "purpose": "PASSWORD",
      "label": "password",
      "value": "xxxxxxxxxxxxxxxxxx"
    },
    {
      "id": "notesPlain",
      "type": "STRING",
      "purpose": "NOTES",
      "label": "notesPlain"
    }
  ],
  "lastEditedBy": "xxxxxxxxxxxxx",
  "createdAt": "2022-01-17T23:41:32Z",
  "updatedAt": "2022-01-17T23:41:32Z"
}

Then, we used the API to update the password

    # Update 1Password item
    item = Item(
        vault=ItemVault(id=op_vault),
        id=op_uuid_access_key,
        sections=[{ "id": "linked items", "label": "Related Items" }],
        fields=[
            Field(
                id="password",
                type="CONCEALED",
                label="password",
                value=response["AccessKey"]["AccessKeyId"],
            )
        ],
    )
    op_client.update_item(op_uuid_access_key, op_vault, item)

However, instead of modifying the first element in the fields area, the Python SDK adds a new one to the bottom, like this"

{
  "id": "6go6qftma5enrxxxxxxxx",
  "title": "AWS_ACCESS_KEY_ID",
  "version": 2,
  "vault": { "id": "akvk5ifqsjge7xxxxxxxxx" },
  "category": "PASSWORD",
  "sections": [{ "id": "linked items", "label": "Related Items" }],
  "fields": [
    {
      "id": "password",
      "type": "CONCEALED",
      "purpose": "PASSWORD",
      "label": "password"
    },
    {
      "id": "notesPlain",
      "type": "STRING",
      "purpose": "NOTES",
      "label": "notesPlain"
    },
    {
      "id": "password",
      "type": "CONCEALED",
      "label": "password",
      "value": "xxxxxxxxxxxxxxxxxxxxxxxxx"
    }
  ],
  "lastEditedBy": "xxxxxxxxxxxxx",
  "createdAt": "2022-01-17T23:41:32Z",
  "updatedAt": "2022-01-17T23:41:32Z"
}

What did you expect to happen?

The SDK should modify the existing one.

Steps to reproduce

  1. Create a normal Password item
  2. Save its original structure
  3. Use the scripts above to edit it
  4. Compare the updated structure

Notes & Logs

Upgrade to 1Password CLI 2

1 Password has released a new version of their command line client.

The upgrade is a breaking change, it makes the use of the cli more intuitive, but due to the new syntax breaks this SDK.
It's not obvious to new users of this SDK to download the old v1 of the op cli.

Releasing a new major version of the SDK appears to be a good idea.

Reference: https://developer.1password.com/docs/cli/upgrade/

Wrong return type hint for load_dict

  • SDK Version: 1.3.0
  • Connect Server Version: 1.6.0
  • OS: ubuntu-22.04
  • Python Version: 3.10

What happened?

The type hint for the return value of load_dict is Dict[str, str] (as stated in config.py line 60) but the actual return type is dict[str, str | None], or dict[str, Optional[str]] if you prefer.

How to reproduce

Add a text field with no value to an item in 1Password. It will not be shown in the client, but when you click Edit you can see it is still there; you can also verify this with e.g. curl.

Then call load_dict and you will see that the value of the field is None.

Undeclared dependency: six (in generated code)

While looking into the codebase to potentially help out with PRs, I noticed that the onepasswordconnectsdk.models.generator_recipe module includes:

import six

# ...

        for attr, _ in six.iteritems(self.openapi_types):

The import is undeclared as a dependency of the project; the only reason this hasn't been an issue so far is because it is a transitive dependency for python-dateutil. There is no guarantee that all future python-dateutil releases will include six as a dependency.

The import can trivially be removed as connect-sdk-python now requires Python 3.7 and up; the following line would be equivalent, more efficient and removes the need to import six:

        for attr in self.openapi_types:

I note that the specific OpenAPI code generator now only supports Python 3.7 and up, so you could just re-generate the code.

Another option is to use pyupgrade to rewrite the code for you to remove the Python 2.x support altogether, but you'll have to manually remove the import six line in that case, and pyupgrade would rewrite the above to use for attr, _ in self.openapi_types.items():, missing the iteration-over-dictionaries-yields-keys trick (the values are ignored in the loop, so .items() is overkill here).

'UseClientDefault' object cannot be interpreted as an integer

Your environment

SDK Version: 1.5.0

Connect Server Version: unk.

OS: Linux (Ubuntu 20.04.6 LTS)

Python Version: 3.12

What happened?

When running in docker, get_item_by_title using new_client_from_environment results in timeout value raising TypeError: 'UseClientDefault' object cannot be interpreted as an integer most likely due to the new get_timeout function returning httpx.USE_CLIENT_DEFAULT (instance of UseClientDefault) when environment variable ENV_CLIENT_REQUEST_TIMEOUT ("OP_CONNECT_CLIENT_REQ_TIMEOUT") is not present.

What did you expect to happen?

No error.

Steps to reproduce

Minimal example:

  1. In Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY . /app
RUN pip install --no-cache-dir onepasswordconnectsdk
CMD ["python3", "app.py"]
  1. In app.py:
import os 
from onepasswordconnectsdk.client import new_client_from_environment

os.environ['OP_CONNECT_HOST'] = '...'
os.environ['OP_CONNECT_TOKEN'] = '...'
client = new_client_from_environment()
item_by_title = client.get_item_by_title('...', '...')
  1. docker build -t "test-image" .
  2. docker container run "test-image"

Notes & Logs

Full traceback:

Traceback (most recent call last):                                                                                                                                                    
  File "/app/app.py", line 7, in <module>
    item_by_title = client.get_item_by_title('...', '....')
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/onepasswordconnectsdk/client.py", line 156, in get_item_by_title
    response = self.build_request("GET", url)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/onepasswordconnectsdk/client.py", line 374, in build_request
    response = self.session.request(method, path)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 821, in request
    return self.send(request, auth=auth, follow_redirects=follow_redirects)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 908, in send
    response = self._send_handling_auth(
               ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 936, in _send_handling_auth
    response = self._send_handling_redirects(
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 973, in _send_handling_redirects
    response = self._send_single_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpx/_client.py", line 1009, in _send_single_request
    response = transport.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpx/_transports/default.py", line 218, in handle_request
    resp = self._pool.handle_request(req)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py", line 253, in handle_request
    raise exc
  File "/usr/local/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py", line 237, in handle_request
    response = connection.handle_request(request)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpcore/_sync/connection.py", line 86, in handle_request
    raise exc
  File "/usr/local/lib/python3.12/site-packages/httpcore/_sync/connection.py", line 63, in handle_request
    stream = self._connect(request)
             ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpcore/_sync/connection.py", line 111, in _connect
    stream = self._network_backend.connect_tcp(**kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/httpcore/backends/sync.py", line 94, in connect_tcp
    sock = socket.create_connection(
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/socket.py", line 834, in create_connection
    sock.settimeout(timeout)
TypeError: 'UseClientDefault' object cannot be interpreted as an integer

Docker version:

Client: Docker Engine - Community
 Version:           25.0.4
 API version:       1.44
 Go version:        go1.21.8
 Git commit:        1a576c5
 Built:             Wed Mar  6 16:32:14 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          25.0.4
  API version:      1.44 (minimum version 1.24)
  Go version:       go1.21.8
  Git commit:       061aa95
  Built:            Wed Mar  6 16:32:14 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.28
  GitCommit:        ae07eda36dd25f8a1b98dfbf587313b99c0190bb
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

Allow customization of environment variable names

Summary

It would be nice to be able to change the environment variable names from OP_CONNECT_HOST and/or OP_CONNECT_TOKEN to variables of our choosing when calling new_client_from_environment(). TOKEN is the more important one, since the host can be passed in already.

Use cases

My primary use case is having a single VM that runs multiple applications (not in docker) that need different tokens.

Is there a workaround to accomplish this today?

There are other ways to scope environment env variables. For instance, I could set them in the processes' systemd service files, although then I shift to the problem to having to manage the secrets in those files in my repository and during deployment.

Possiblity to create item share

Summary

Allow the SDK/API to create shares of items.

Use cases

The use case is self-explanatory. If it was possible to share the item via API, as in, configuring expiration timers, adding emails, etc. and getting the link you can automate any process that requires sharing credentials/TOTP. This can be useful in many scenarios:

  • Provisioning user accounts
  • Automatically sharing created credentials with customers/third parties/employees
  • Increasing reliability of processes that depend on temporary credentials that include TOTP
  • etc.

Proposed solution

That is an API design choice. But perhaps extend the /item/ endpoint to include a /item/{itemID}/share where a GET request can recover the share information of the item, a POST allows to creation of the share and a PATCH allows to change of an active share and a DELETE removes the share from the item.

Is there a workaround to accomplish this today?

Not that I'm aware of. If there is I would be interested to know.

References & Prior Work

1Password already has the feature, it isn't accessible via API.

Pass client configuration in 'new_client' function

Currently, there is no possibility of configuring httpx.Client when initializing the client using new_client function. The purpose of this issue to add the configuration ability to the new_client function so it would look like this:

def new_client(url: str, token: str, is_async: bool = False, config: httpx.BaseClient) -> Union[AsyncClient, Client]:

The config parameter should be of type httpx.BaseClient so we can pass any options that httpx.Client and httpx.AsyncClient have.

No wheel for 1.2.0

Hello, because this library depends on cryptography one can end up in a bit of mess trying to install from source, as building cryptography requires following dependencies:

  • gcc
  • libcffi
  • rust toolchain (!)

The previous release contained a wheel:

https://pypi.org/project/onepasswordconnectsdk/1.1.0/#files

Unlike 1.2.0

https://pypi.org/project/onepasswordconnectsdk/1.2.0/#files

Please publish a wheel! I spent about an hour messing about with dependencies in docker files before giving up and going back to 1.1.0 😄

List by tag

Summary

I have existing CLI scripts which list secrets as k:v pairs by tag, using the v1 version of op. I'd like to be able to do this with v2 and Connect.

Use cases

I don't want to list ALL secrets. I don't want to fetch many by name. I want to list by a specific tag.

Proposed solution

I'm interested in contributing a solution, but I see a bunch of the code is autogenerated somehow. If you can advise then maybe I can implement what I need!

load_dict fails when looking up keys with periods in them

Your environment

SDK Version: 1.2.0

  • installed via pip install onepasswordconnectsdk
    Connect Server Version:
    OS: Ubuntu 20.04
    Python Version: 3.8.10

What happened?

Using load_dict against a key with a period in it generates an error: onepasswordconnectsdk.config.InvalidFieldPathException

What did you expect to happen?

Retrieval of value matching that key

Steps to reproduce

Attempt to retreive a value matching a key with a . in it.
My case has been part of a Section.
`
from onepasswordconnectsdk.client import (
Client,
new_client_from_environment,
new_client
)
from onepasswordconnectsdk import (
load_dict
)

client: Client = new_client_from_environment()
account="[email protected]"
creds = load_dict(client, {
"pass": {
"opitem": "My Account",
"opfield": "Main Login." + account
}
})
`

Notes & Logs

Traceback (most recent call last):
File "test.py", line 45, in
creds = load_dict(client, {
File "/home/dev1/.local/lib/python3.8/site-packages/onepasswordconnectsdk/config.py", line 80, in load_dict
_set_values_for_item(client=client,
File "/home/dev1/.local/lib/python3.8/site-packages/onepasswordconnectsdk/config.py", line 185, in _set_values_for_item
raise InvalidFieldPathException(
onepasswordconnectsdk.config.InvalidFieldPathException: Invalid field path format for pass

It's understandable that the '.' is normally chaining fields to get one field deeper but keys with email addresses are common and keys with ip addresses are not uncommon in our particular setup.
I would expect either an attempt to look for keys with '.'s in them if it fails or a way to wrap it to escape the '.'s

SSH_KEY is an invalid value for 'category'

Hello !
I'm trying to get an SSH key from 1Password Connect Server with the API. But I'm getting the following issue :

ValueError: Invalid value for `category` (SSH_KEY), must be one of ['LOGIN', 'PASSWORD', 'SERVER', 'DATABASE', 'CREDIT_CARD', 'MEMBERSHIP', 'PASSPORT', 'SOFTWARE_LICENSE', 'OUTDOOR_LICENSE', 'SECURE_NOTE', 'WIRELESS_ROUTER', 'BANK_ACCOUNT', 'DRIVER_LICENSE', 'IDENTITY', 'REWARD_PROGRAM', 'DOCUMENT', 'EMAIL_ACCOUNT', 'SOCIAL_SECURITY_NUMBER', 'API_CREDENTIAL', 'CUSTOM']

Do I only need to submit a new PR ? including the new category type "SSH_KEY"

Example for onepasswordconnectsdk.load_dict is incorrect

Your environment

SDK Version: N/A

Connect Server Version: N/A

OS: N/A

Python Version: N/A

What happened?

I am admittedly unsure what category to file this under, but I have discovered an error in USAGE.md. The load_dict example is inaccurate and will result in errors unless each item has opvault defined. If run without the fix (as below, though with values filled in) you get the following Traceback (or similar). This traceback also explicitly states the problem, which my pull request resolves.

# example dict configuration for onepasswordconnectsdk.load_dict(connect_client, CONFIG)
CONFIG = {
    "server": {
        "opitem": "My database item",
        "opfield": "specific_section.hostname",
        "opvault": "some_vault_id",
    },
    "database": {
        "opitem": "My database item",
        "opfield": ".database",
    },
    "username": {
        "opitem": "My database item",
        "opfield": ".username",
    },
    "password": {
        "opitem": "My database item",
        "opfield": ".password",
    },
}

values_dict = onepasswordconnectsdk.load_dict(connect_client, CONFIG)
Traceback (most recent call last):
  File "/Users/kylewilson/Documents/1PasswordTest/passwordtest.py", line 96, in <module>
    values_dict = onepasswordconnectsdk.load_dict(connect_client, CONFIG)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kylewilson/Documents/1PasswordTest/.venv/lib/python3.11/site-packages/onepasswordconnectsdk/config.py", line 65, in load_dict
    item_vault = _vault_uuid_for_field(field=field, vault_tag=vault_tag)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/kylewilson/Documents/1PasswordTest/.venv/lib/python3.11/site-packages/onepasswordconnectsdk/config.py", line 158, in _vault_uuid_for_field
    raise NoVaultSetForFieldException(
onepasswordconnectsdk.config.NoVaultSetForFieldException: There         is no vault for database field

What did you expect to happen?

It should be as follows. This actually functions when tested:

# example dict configuration for onepasswordconnectsdk.load_dict(connect_client, CONFIG)
CONFIG = {
    "server": {
        "opitem": "My database item",
        "opfield": "specific_section.hostname",
        "opvault": "some_vault_id",
    },
    "database": {
        "opitem": "My database item",
        "opfield": ".database",
        "opvault": "some_vault_id",
    },
    "username": {
        "opitem": "My database item",
        "opfield": ".username",
        "opvault": "some_vault_id",
    },
    "password": {
        "opitem": "My database item",
        "opfield": ".password",
        "opvault": "some_vault_id",
    },
}

values_dict = onepasswordconnectsdk.load_dict(connect_client, CONFIG)

Steps to reproduce

  1. Run the example as-is, though obviously filling in the opitem and opvault fields where already present. Do not add any other fields.

Notes & Logs

SDK to support async operations

Summary

When downloading a bunch of items to initialize our app, we would like to benefit from async io operation to perform multiple bulk downloads. Current implementation force us to download these sequentially or having to resort to using threading which create a large overhead.

Use cases

Initializing an app on runtime to download all needed passwords

Proposed solution

Implement the internal request builder using built-in async.io or any other async library

Is there a workaround to accomplish this today?

yes, running using threads

References & Prior Work

no sure

How does one determine a fileId/documentId using the python SDK?

Your environment

Built from main, commit 678d60 from November 9th (because the document support committed in October hasn't been released yet)

Connect Server Version: 1.5.0

OS: macOS 11.6.3

Python Version: 3.9.10

What happened?

The API for download_file, consistent with the library's other file APIs, expects a file ID, an item ID, and a vault ID.

Starting from a vault name and an item name, I can determine the vault ID and the item ID, but the output of get_item doesn't include a file ID. It is included in the CLI output of get item, under a different name:

op get item <document-item-id> --vault <vault-id> | jq -r .details.documentAttributes.documentId

The same documentId is shown via the Copy JSON command in the Mac app, and when I feed that identifier to the download_file API, it succeeds. But it isn't useful if I can't programmatically determine the ID, and I am not seeing any way to do that.

What did you expect to happen?

I should be able to use the python library, vault access, and knowledge of a file's name to access the file.

Notes & Logs

Here's the output of get_item:

{'category': 'DOCUMENT',
 'created_at': datetime.datetime(2022, 2, 8, 0, 10, 12, tzinfo=tzutc()),
 'favorite': False,
 'fields': [{'entropy': None,
             'generate': False,
             'id': 'notesPlain',
             'label': 'notesPlain',
             'purpose': 'NOTES',
             'section': None,
             'type': 'STRING',
             'value': None}],
 'id': 'a7qk2fixrbalrifv3heqcxntyi',
 'last_edited_by': 'FRAQH4JNUJG6XPMLJO2GVA72T4',
 'sections': None,
 'tags': None,
 'title': 'redacted-file-title',
 'trashed': False,
 'updated_at': datetime.datetime(2022, 2, 8, 0, 10, 13, tzinfo=tzutc()),
 'urls': None,
 'vault': {'id': 'jm4ixdhaljgodbzehdxjxxwagy'},
 'version': 1}

Thanks for your time.

Error calling onepasswordconnectsdk.load_dict()

Your environment

SDK Version: 1.1.0

Connect Server Version:1.5.0

OS: Ubuntu 20.04

Python Version: 3.8.2

What happened?

When following the instructions to create a dict to limit the fields returned, I receive the following error:
load_dict() missing 1 required positional argument: 'config'
If I copy and paste the text from the README, I get the same error.

What did you expect to happen?

The variable values_dict to be set with the the value returned from onepasswordconnectsdk.load_dict(CONFIG)

Steps to reproduce

import onepasswordconnectsdk

CONFIG = {
    "server": {
        "opitem": "My database item",
        "opfield": "specific_section.hostname",
        "opvault": "some_vault_id",
    },
    "database": {
        "opitem": "My database item",
        "opfield": ".database",
    },
    "username": {
        "opitem": "My database item",
        "opfield": ".username",
    },
    "password": {
        "opitem": "My database item",
        "opfield": ".password",
    },
}

values_dict = onepasswordconnectsdk.load_dict(CONFIG)

SSLError

Your environment

SDK Version: 1.3.0
Connect Server Version: 1.5.7
OS: macOS Ventura
Python Version: 3.9

What happened?

I was doing some update operations through my connect server but after a while my script started failing, when i try to debug my script i recognized that there is a SSLError

Here is my test script:
from onepasswordconnectsdk.client import ( Client, new_client_from_environment, new_client ) client_from_token: Client = new_client( "connect server url", "my connnect server bearer token") client_from_token.get_vaults()

What did you expect to happen?

I expect to list all vaults.

Steps to reproduce

  1. Run the simple script above on macOS Ventura with a 1password Connect Server

Notes & Logs

`Traceback (most recent call last):
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 703, in urlopen
httplib_response = self._make_request(
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 386, in _make_request
self._validate_conn(conn)
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 1042, in validate_conn
conn.connect()
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/connection.py", line 414, in connect
self.sock = ssl_wrap_socket(
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/util/ssl
.py", line 449, in ssl_wrap_socket
ssl_sock = ssl_wrap_socket_impl(
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/util/ssl
.py", line 493, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/ssl.py", line 500, in wrap_socket
return self.sslsocket_class._create(
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/ssl.py", line 1040, in _create
self.do_handshake()
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/ssl.py", line 1309, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:1129)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/requests/adapters.py", line 489, in send
resp = conn.urlopen(
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/connectionpool.py", line 787, in urlopen
retries = retries.increment(
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/urllib3/util/retry.py", line 592, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='xxx.xxx.xxx', port=443): Max retries exceeded with url: /v1/vaults (Caused by SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:1129)')))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/furkan/PycharmProjects/testProject_1password/main.py", line 14, in
client_from_token.get_vaults()
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/onepasswordconnectsdk/client.py", line 363, in get_vaults
response = self.build_request("GET", url)
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/onepasswordconnectsdk/client.py", line 391, in build_request
response = self.session.request(method, url)
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/requests/sessions.py", line 587, in request
resp = self.send(prep, **send_kwargs)
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/requests/sessions.py", line 701, in send
r = adapter.send(request, **kwargs)
File "/Users/furkan/PycharmProjects/testProject_1password/env/lib/python3.9/site-packages/requests/adapters.py", line 563, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='xxx.xxx.xxx', port=443): Max retries exceeded with url: /v1/vaults (Caused by SSLError(SSLError(1, '[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:1129)')))`

Can't list items from vault with `API_CREDENTIAL` item

Your environment

SDK Version: 1.0.1

Connect Server Version: 1.1.0

OS: Ubuntu 20.04

Python Version: 3.8.5

What happened?

I have created an API_CREDENTIAL item on my vault. When I run client.get_items("{vault_id"), I get the following error:

ValueError: Invalid value for `category` (API_CREDENTIAL), must be one of ['LOGIN', 'PASSWORD', 'SERVER', 'DATABASE', 'CREDIT_CARD', 'MEMBERSHIP', 'PASSPORT', 'SOFTWARE_LICENSE', 'OUTDOOR_LICENSE', 'SECURE_NOTE', 'WIRELESS_ROUTER', 'BANK_ACCOUNT', 'DRIVER_LICENSE', 'IDENTITY', 'REWARD_PROGRAM', 'DOCUMENT', 'EMAIL_ACCOUNT', 'SOCIAL_SECURITY_NUMBER', 'CUSTOM']

What did you expect to happen?

I expected to get a list of items in the vault.

Steps to reproduce

Run client.get_items("{vault_id") on a vault that has an item of the API_CREDENTIAL category.

Notes & Logs

[{'attribute_version': 1,
 'content_version': 3,
 'created_at': datetime.datetime(2021, 5, 6, 8, 43, 21, tzinfo=tzlocal()),
 'description': None,
 'id': 'REDACTED',
 'items': 2,
 'name': 'Development',
 'type': 'USER_CREATED',
 'updated_at': datetime.datetime(2021, 5, 6, 8, 44, 33, tzinfo=tzlocal())}]
Traceback (most recent call last):
  File "get_env.py", line 16, in <module>
    main()
  File "get_env.py", line 12, in main
    client.get_items("REDACTED")
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/client.py", line 131, in get_items
    return self.deserialize(response.content, "list[SummaryItem]")
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/client.py", line 294, in deserialize
    return self.__deserialize(data, response_type)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/client.py", line 354, in __deserialize
    return [self.__deserialize(sub_data, sub_kls) for sub_data in data]  # noqa: E501
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/client.py", line 354, in <listcomp>
    return [self.__deserialize(sub_data, sub_kls) for sub_data in data]  # noqa: E501
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/client.py", line 377, in __deserialize
    return self.__deserialize_model(data, klass)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/client.py", line 463, in __deserialize_model
    instance = klass(**kwargs)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/models/summary_item.py", line 84, in __init__
    self.category = category
  File "/home/ubuntu/.local/lib/python3.8/site-packages/onepasswordconnectsdk/models/summary_item.py", line 185, in category
    raise ValueError(
ValueError: Invalid value for `category` (API_CREDENTIAL), must be one of ['LOGIN', 'PASSWORD', 'SERVER', 'DATABASE', 'CREDIT_CARD', 'MEMBERSHIP', 'PASSPORT', 'SOFTWARE_LICENSE', 'OUTDOOR_LICENSE', 'SECURE_NOTE', 'WIRELESS_ROUTER', 'BANK_ACCOUNT', 'DRIVER_LICENSE', 'IDENTITY', 'REWARD_PROGRAM', 'DOCUMENT', 'EMAIL_ACCOUNT', 'SOCIAL_SECURITY_NUMBER', 'CUSTOM']

new_client_from_environment() requires a URL passed in as an argument

Your environment

SDK Version: onepasswordconnectsdk==1.0.1

Connect Server Version: 1.2.0

OS: macOS 11.4 Intel

Python Version: Python 3.8.2

What happened?

After setting OP_CONNECT_TOKEN and OP_CONNECT_HOST I called client_from_env: Client = new_client_from_environment()

This caused an error, because I was missing an argument.

Traceback (most recent call last):
  File "./experiment.py", line 27, in main
    client_from_env: Client = new_client_from_environment()
TypeError: new_client_from_environment() missing 1 required positional argument: 'url'

What did you expect to happen?

I expected a client to be created.

I worked around this issue by adding the url to the call. client_from_env: Client = new_client_from_environment(os.getenv('OP_CONNECT_HOST'))

Steps to reproduce

Script output:

./experiment.py --log DEBUG 
DEBUG:root:OP_CONNECT_HOST: http://localhost:8080
DEBUG:root:OP_CONNECT_TOKEN length: 665. (To show the environment variable is set)
DEBUG:root:use sample code to create a client using my environment
ERROR:root:Unable to create a client with new_client_from_environment()
Traceback (most recent call last):
  File "./experiment.py", line 27, in main
    client_from_env: Client = new_client_from_environment()
TypeError: new_client_from_environment() missing 1 required positional argument: 'url'
DEBUG:root:modify sample code to pass in url
INFO:root:Client created with a modified call to new_client_from_environment
DEBUG:root:Get a list of vaults
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): localhost:8080
DEBUG:urllib3.connectionpool:http://localhost:8080 "GET /v1/vaults HTTP/1.1" 200 202
[{'attribute_version': 1,
 'content_version': 5,
 'created_at': datetime.datetime(2021, 5, 27, 13, 53, 6, tzinfo=tzutc()),
 'description': None,
 'id': 't2tabyg7x33bybglznejs2loz4',
 'items': 2,
 'name': 'sa test vault',
 'type': 'USER_CREATED',
 'updated_at': datetime.datetime(2021, 5, 27, 14, 3, 20, tzinfo=tzutc())}]

Script:

#!/usr/bin/env python3

import logging
import argparse
import sys
import os
import onepasswordconnectsdk

if sys.version_info < (3, 6):
    print('Please upgrade your Python version to 3.6.0 or higher')
    sys.exit()

def main():
    from onepasswordconnectsdk.client import (
        Client,
        new_client_from_environment,
        new_client
    )

    logging.debug(f"OP_CONNECT_HOST: {os.getenv('OP_CONNECT_HOST')}")
    logging.debug(f"OP_CONNECT_TOKEN length: {len(os.getenv('OP_CONNECT_TOKEN'))}. (To show the environment variable is set)")

    client_from_env = None

    try:
        logging.debug(f"use sample code to create a client using my environment")
        client_from_env: Client = new_client_from_environment()
        logging.info("client created using sample code")
    except: 
        logging.exception("Unable to create a client with new_client_from_environment()")

    try:
        logging.debug(f"modify sample code to pass in url")
        client_from_env: Client = new_client_from_environment(os.getenv('OP_CONNECT_HOST'))
        logging.info("Client created with a modified call to new_client_from_environment")
    except: 
        logging.error("Unable to create a client")

    logging.debug("Get a list of vaults")
    print(client_from_env.get_vaults())

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--log', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'], default = os.getenv("LOG_LEVEL", 'INFO'), help="Can also be set as env var LOG_LEVEL")
    args = parser.parse_args()
    logging.getLogger().setLevel(args.log)
    main()

Notes & Logs

  • I was basing my steps on the README.md. It's possible that only that file needs to be updated.
  • I was also confused by the example. I originally set OP_CONNECT_HOST to localhost:8080 without the http:// protocol on front.

Support service accounts

Summary

It would be nice if this SDK supports authenticating with the new Service Accounts feature https://developer.1password.com/docs/service-accounts/.

Use cases

I use Pyinfra and Pulumi to manage infrastructure and I'm using 1Password for secret management. Using service accounts will reduce the complexity of the infrastructure by being able to directly call 1Password (instead of going through the connect server) which is good enough for the small infrastructure I manage.

Is there a workaround to accomplish this today?

Do subprocess calls to the 1password-cli which already supports service account authentication.

Add the get_document() method to the client

Summary

SSH Private Key is in the vault, saved as a Document category item. There's no get_document() call, but there is one in the non-connect python sdk

Use cases

Current get_item() call will return the Item object type, but it has no methods to download the actual doc?

Proposed solution

Add this method, it already was working fine with non-connect 1password client

Is there a workaround to accomplish this today?

None that I'm aware of

References & Prior Work

N/A

Failure to update items with files

Your environment

SDK Version: 1.3.0
Connect Server Version: 1.5.7
OS: MacOS Montery 12.6
Python Version: 3.7.5

What happened?

Updating an item that contains a file fails with error

onepasswordconnectsdk.client.FailedToRetrieveItemException: Unable to post item. Received 400                    for /v1/vaults/********/items/***** with message: Validation: (validateVaultItem failed to Validate), Couldn't validate the item: "[ItemValidator] has found 1 errors, 0 warnings: \nErrors:{1. Field of unexpected type \"\" at \"item.details.documentAttributes\". Requires one of [\"object\"]}"

What did you expect to happen?

After downloading the item be able to update it from the sdk

Steps to reproduce

  1. Create json document secret using the json below. I tried with different combinations all jsons break it for us.
  2. run this code (silly code, update without any modification)
client_from_token: Client = new_client()
item_title = "your_item"
vault_title = "your_vault"
item = client_from_token.get_item(item_title, vault_title)
client_from_token.update_item(item.id, item.vault.id, item)

Notes & Logs

had to zip, github does not allow json files uploads. bla.json.zip

Add support for self-signed certificates

Summary

The one connect python SDK does not currently allow for self-signed certificates to be authenticated when creating a new client, these will always fail.

Use cases

Self-signed certificates are inexpensive (free) and suitable for use in non-public facing applications.

Proposed solution

Supporting optional self-signed certificates through minor modifications to client.py.

Is there a workaround to accomplish this today?

Not using python.

References & Prior Work

Retrieved SummaryItem lacks "fields" attribute under released library versions (1.1 and 1.0)

Your environment

SDK Version: 1.0, 1.1, and tip of main (c809bfa)

Connect Server Version: 1.5.0

OS: macOS 11.6.4

Python Version: 3.9.10, 3.9.11, 3.10.2, 3.10.3

What happened?

Upon upgrading from Python 3.9.10 to last week's 3.9.11, some pretty basic 1Password item retrieval code broke. On later examination, 3.9.10 only continued to work because I had previously built the library locally to troubleshoot #36 — the problem was in the released library versions.

Here's the complete json skeleton from a synthesized item I'm trying to retrieve:

{
  "createdAt": "2022-03-22T03:09:41.000Z",
  "details": {
    "notesPlain": "for something super important",
    "password": "K_.xqKvqrEAPAt63yfwGJU3z9bwBaR",
    "sections": [
      {
        "name": "linked items",
        "title": "Related Items"
      },
      {
        "fields": [
          {
            "k": "string",
            "n": "06836A624EC14D51A2BB4D5791213010",
            "t": "Key ID",
            "v": "2E1B839B-3EE2-42FA-ADE5-7BDC4E3ECA91"
          }
        ],
        "name": "Section_4144107279A848498B832C61BABC5E00",
        "title": ""
      }
    ]
  },
  "overview": {
    "ainfo": "Mar 21, 2022 at 8:09:41 PM",
    "pbe": 177.81768798828125,
    "pgrng": true,
    "ps": 100,
    "tags": [
      "team:Foo"
    ],
    "title": "Sanitized Item"
  },
  "templateUuid": "005",
  "trashed": "N",
  "updatedAt": "2022-03-22T03:10:40.000Z",
  "uuid": "yiapgssbg5hfxfbu2kczeprnuy"
}

Here's some code to retrieve it:

#!/usr/bin/env python

import os
import onepasswordconnectsdk
from pprint import pprint
from onepasswordconnectsdk.client import new_client
from onepasswordconnectsdk.models import (
    ItemVault, 
    Field, 
    Section, 
    FieldSection
)

item_name = "Sanitized item"
vault_id = "kmbbwba32eyx2qz5flk3z2frra"

client = new_client("http://localhost:8080", os.environ['OP_CONNECT_TOKEN'])

try:
    item = client.get_item_by_title(item_name, vault_id)
except onepasswordconnectsdk.client.FailedToRetrieveItemException as e:
    raise e 

pprint(item)

item_password = [item.value for item in item.fields if item.purpose == "PASSWORD"][0]
print(item_password)

Versions 1.0 and 1.1 of onepasswordconnectsdk get back a SummaryItem object which doesn't contain any fields attribute, which is where all my stuff is. pprint(item) on the failing versions returns this:

{'category': 'PASSWORD',
 'created_at': datetime.datetime(2022, 3, 22, 3, 9, 41, tzinfo=tzutc()),
 'favorite': False,
 'id': 'yiapgssbg5hfxfbu2kczeprnuy',
 'last_edited_by': 'FRAQH4JNUJG6XPMLJO2GVA72T4',
 'tags': ['team:Foo'],
 'title': 'Sanitized Item',
 'trashed': False,
 'updated_at': datetime.datetime(2022, 3, 22, 3, 10, 40, tzinfo=tzutc()),
 'urls': None,
 'vault': {'id': 'kmbbwba32eyx2qz5flk3z2frra'},
 'version': 2}

What did you expect to happen?

When I build c809bfa0f locally and install it, the pprint output looks like this:

{'category': 'PASSWORD',
 'created_at': datetime.datetime(2022, 3, 22, 3, 9, 41, tzinfo=tzutc()),
 'favorite': False,
 'fields': [{'entropy': 177.81768798828125,
             'generate': False,
             'id': 'password',
             'label': 'password',
             'purpose': 'PASSWORD',
             'section': None,
             'type': 'CONCEALED',
             'value': 'K_.xqKvqrEAPAt63yfwGJU3z9bwBaR'},
            {'entropy': None,
             'generate': False,
             'id': 'notesPlain',
             'label': 'notesPlain',
             'purpose': 'NOTES',
             'section': None,
             'type': 'STRING',
             'value': 'for something super important'},
            {'entropy': None,
             'generate': False,
             'id': '06836A624EC14D51A2BB4D5791213010',
             'label': 'Key ID',
             'purpose': None,
             'section': {'id': 'Section_4144107279A848498B832C61BABC5E00'},
             'type': 'STRING',
             'value': '2E1B839B-3EE2-42FA-ADE5-7BDC4E3ECA91'}],
 'id': 'yiapgssbg5hfxfbu2kczeprnuy',
 'last_edited_by': 'FRAQH4JNUJG6XPMLJO2GVA72T4',
 'sections': [{'id': 'Section_4144107279A848498B832C61BABC5E00', 'label': None},
              {'id': 'linked items', 'label': 'Related Items'}],
 'tags': ['team:Foo'],
 'title': 'Sanitized Item',
 'trashed': False,
 'updated_at': datetime.datetime(2022, 3, 22, 3, 10, 40, tzinfo=tzutc()),
 'urls': None,
 'vault': {'id': 'kmbbwba32eyx2qz5flk3z2frra'},
 'version': 2}

In the library version built from c809bfa0f, the list comprehension in the second-to-last line successfully squeezes a password out of this item. In the released versions, the list comprehension results in: "AttributeError: 'SummaryItem' object has no attribute 'fields'".

move the minimum required version of requests back a couple of minor versions

Summary

currently, the minimum requests version is 2.24.0

another library i depend on has requests pinned to requests==2.23. i can't install the connect sdk in that project as a result, because the project uses poetry, which identifies the dependency version conflict.

Use cases

requests is a widely used python library & chances are any python project will already have requests as a dependency. poetry will refuse to install libraries if dependency resolution fails. it would help adoption of the connect client if it were more permissive in its dependency on requests.

Proposed solution

pushing the minimum version to 2.23.0 would solve my issue, but maybe it would be beneficial for adoption if the minimum version was always at least 2 years old

load_dict and load work with field id and label

Summary

Extend load_dict and load functions work with field.id and field.label.
Currently, it works only with field.label.

"opfield": "section_name.field_id" # finds value by field_id

"opfield": "section_name.field_label" # finds value by field_label

Implement search flow in a next way:

  1. Try to find a field by provided string assuming it's a label (aka find by label). If found, great.
  2. If none is found, try to find a section by provided string assuming it's ID (aka find by id). If found, great.
  3. If none is found, throw the error.

Allow default values for load_dict

It would be very convenient if a default value could be provided for load_dict keys in case the field is not present in the vault item.

Can't Install from git url using poetry

Your environment

SDK Version: 1.0.1

Connect Server Version: not-applicable

OS: ubuntul 20.04

Python Version: 3.8

What happened?

poetry can't install this library from a git url. i get the following error.

Updating dependencies
Resolving dependencies... (0.4s)
  CalledProcessError
  Command '['git', '--git-dir', '/tmp/pypoetry-git-connect-sdk-python4l7tbflx/.git', '--work-tree', '/tmp/pypoetry-git-connect-sdk-python4l7tbflx', 'checkout', 'master']' returned non-zero exit status 1.
  at ~/.poetry/lib/poetry/utils/_compat.py:217 in run
      213│                 process.wait()
      214│                 raise
      215│             retcode = process.poll()
      216│             if check and retcode:
    → 217│                 raise CalledProcessError(
      218│                     retcode, process.args, output=stdout, stderr=stderr
      219│                 )
      220│         finally:
      221│             # None because our context manager __exit__ does not use them.

What did you expect to happen?

i expected it to work

Steps to reproduce

poetry add git+https://github.com/1Password/connect-sdk-python.git

Notes & Logs

Get Items do not work with svc account auth

Your environment

SDK Version: 1.0.7

OS: Ubuntu 20.04

Python Version: 3.1

What happened?

Basically if I'm not mistaken, this SDK is nothing but another layer of abstraction on top of the op cli.

And if you're using the op cli and tries to get an Item when running the authentication with a svc account you will receive this:
Screenshot 2024-05-16 at 17 33 39
In short, you need to specify the vault whenever trying to get an item. And the problem is that, although we're able to do it using the cli, the sdk get_item method does not have a way to inform the vault.

What did you expect to happen?

Maybe having a vault optional param?
something like:
Screenshot 2024-05-16 at 19 38 05

Steps to reproduce

  1. Auth using a service account
  2. Try to get an item using the sdk

`download_file` function uses the wrong file UUID in the API route

Starting with Connect 1.5.4, the file_id in the item representation is no longer the file ID, but the wrapping field's ID. (see the difference between the content_path's last token and the ID, in any item response that contains files).

The download_file function of the Python Client builds the API route itself, using this file ID and disregarding the content_path attribute. This makes the route broken, and a 404 is consistently returned, when calling this endpoint.

The fix should be rather simple: use the content_path, possibly similar to how the Go SDK does it (see https://github.com/1Password/connect-sdk-go/blob/main/connect/client.go#L552)

Drop Python 2 Support

Summary

Python 2 end of life was almost 3 years ago. The sdk should drop support for that and remove the six package.

Use cases

We're trying to use the python sdk in a modern project however due to old requirements, our dependency manager is failing to install the sdk with other incompatible libraries.

Proposed solution

  • Drop support for python2 and make necessary modifications to support python3
  • Remove six package
  • Test code on newer versions of python
  • Optional: Upgrade request version

Is there a workaround to accomplish this today?

Not that i'm aware off (without potentially breaking some library dependencies)

References & Prior Work

Again, happy to open PRs if it's a direction you'd explore

Updating an item field replaces that field type with text

Your environment

SDK Version: 1.3.0

Connect Server Version:1.6.1

OS: Windows, Mac

Python Version: 3.10.10

What happened?

Updating an item field with purpose throw error while removing purpose will change the field type.

Update an item password like this:

  Field(
            id='password',  
            label='password',
            purpose='PASSWORD',
            value='my password'),

will receive this error:

Logic: (Unable to parse Item), Validation: (too many "password" fields in Apply()), You can only use one "password" field.

Update an item without purpose will not throw an error but will change password type from password to text.

What did you expect to happen?

Updating an item with purpose should work and not throw error.

Steps to reproduce

Code_drvCaVvyhM.mp4

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.