Skip to content

A python API to query a 1Password account using the 'op' command-line tool, supporting 'op' v1.x

License

Notifications You must be signed in to change notification settings

zcutlip/pyonepassword-legacy

Repository files navigation

PYONEPASSWORD-LEGACY

Description

A Python API to sign into and query a 1Password account using the deprecated 1.x versions of the op command.

Note: This project is intended only to support legacy op 1.x versions. It DOES NOT work with op versions >= 2.0.0. Although serious bugfixes will be considered, this project should not be considered actively maintained. Users of the new op version 2, should use the main project, which IS actively maintained: https://github.com/zcutlip/pyonepassword.

Requirements

A Quick Favor

I don't have a way of knowing how widely this project is used. If you're using it, I would love for you to drop me a tweet (@zcutlip) or an email (see the commit history) and let me know. I'm interested in how it's going for you, how you're using it (if you're able to share), if there are things that are working well or not working well, etc.

Installation

python3 -m pip install git+https://github.com/zcutlip/pyonepassword-legacy

Example Usage

A Note about Initial Sign-in

Initial sign-in, which was supported in earlier versions of pyonepassword is now deprecated. The reasons for this are:

  • Use of multifactor authentication is highly encouraged for all users, but is not supported via pyonepassword
  • If there was a way to perform mutlifactor authentication programatically, this would represent a failure of MFA; one of its main purposes is to capture user intent. If pyonepassword can automate MFA, so can malicious code.

Code that was previously relying on initial sign-in support in pyonepassword, must now be updated to continue working. It is necessary to import a different, deprecated class. A one line change should allow existing code to continue working for the time being:

Change:

from pyonepassword import OP

To:

from pyonepassword import OP_ as OP

Other than deprecation warnings (via Python's warnings.warn()), everything should then function as normal. Be aware that this functionality will be removed in a future update, without additional warning.

Sign-in and item retrieval

Below is an example demonstrating:

  • Sign-in
  • Specifying a default vault for queries
  • Retrieving an item from 1Password by name or by UUID
  • Overriding the default vault to retrieve a subsequent item from 1Password
import getpass

from pyonepassword import (  # noqa: E402
    OP,
    OPSigninException,
    OPGetItemException,
    OPNotFoundException,
    OPConfigNotFoundException
)


def do_signin():
    # If you've already signed in at least once, you don't need to provide all
    # account details on future sign-ins. Just master password
    my_password = getpass.getpass(prompt="1Password master password:\n")
    # You may optionally provide an account shorthand if you used a custom one during initial sign-in
    # shorthand = "arbitrary_account_shorthand"
    # return OP(account_shorthand=shorthand, password=my_password)
    # Or we'll try to look up account shorthand from your latest sign-in in op's config file
    return OP(vault="Test Data", password=my_password)


def main():
  	op = do_signin()
    item_password = op.get_item_password("Example Login")

  	# We can also look up the item by its UUID
    # as well as retrieve from an alternate vault
    item_password = op.get_item_password(
      "ykhsbhhv2vf6hn2u4qwblfrmg4", vault="Private")

Document retrieval

Below is an example demonstrating:

  • Retrieving a document and its file name from 1Password, based on item name
  • Retrieving a document & file name from 1Password, based on UUID
op = do_signin()
# File name and document title in 1Password are often different.
# so we get back the file name, and the bytes object representing the document
file_name, document_bytes = op.get_document("Example Login - 1Password Logo")

# we can also look up the document by UUID
file_name, document_bytes = op.get_document(
    "bmxpvuthureo7e52uqmvqcr4dy")
open(file_name, "wb").write(document_bytes)

Signing out of 1Password

Below is an example demonstrating:

  • Signing in, then signing out of 1Password
  • Signing out and also forgetting a 1Password account

Note: Currently pyonepassword's sign-out & forget support requires a signed-in session. It is not yet possible to forget an arbitrary account.

def main():
	  op = do_signin()

    # do signout
    op.signout()

    try:
		    print(op.get_item_password("Example Login"))
     except OPGetItemException:
      	# lookup fails since we signed out
        pass

    # now let's sign in again, then signout with forget=True
    op = do_signin()
    op.signout(forget=True)

    try:
        do_signin()
    except OPSigninException:
				# Sign-in fails since we erased the initial sign-in with forget=True
				pass

Getting Details for a User

op = OP(password=my_password)

# User's name:
user: OPUser = op.get_user("Firstname Lastname")

# or the user's UUID
user: OPUser = op.get_user(user_uuid)

Getting Details for a Group

op = OP(password=my_password)

# Group name:
group: OPGroup = op.get_group("Team Members")

# or the group's UUID
group: OPGroup = op.get_group("yhdg6ovhkjcfhn3u25cp2bnl6e")

Getting Details for a Vault

op = OP(password=my_password)

# Group name:
vault: OPVault = op.get_vault("Test Data")

# or the group's UUID
vault: OPVault = op.get_vault("yhdg6ovhkjcfhn3u25cp2bnl6e")

Item Creation

As of version 2.0, pyonepassword supports creation of entries in 1Password vaults. In order to do this, an "item template" class must be used that inherits from OPItemTemplateMixin along with one of the item classes (e.g., OPLoginItem). Currently, two classes are provided that do this: OPLoginItemTemplate and OPServerItemTemplate.

Examples

Below are a couple of examples creating a login item.

Creating a Login Item

The OP class provides a convenience method to create a login item.

op = do_signin()
username = "testuser"
password = "testpass"
url = "https://example.website"
item_name = "login 3"

result: OPLoginItem
result = op.create_login_item(item_name, username, password, url=url)
# result is an actual OPLoginItem object queried from 1Password after item creation
# Among other things it provides the UUID of the created object
print(f"Item UUID: {result.uuid}")

Creating a Login Item with Custom Sections

Rather than use the convenience method, you may add custom sections and section fields to the item template before creation.

newlogin = OPLoginItemTemplate(username, password)

# user-visible section title is required
# section name (not user visible) is optional and will be randomly generated if not provided
#                 section title -----v                 v-------- section name
# section = newlogin.add_section("New Section", "new_section")
section = newlogin.add_section("New Section")

# field name is not user visible
# field label is user visible
section.add_field("example field name", "example value", "string", "example field label")

op.create_item(newlogin, "login 3")

Notes

  • You need the op 1Password command-line tool. On a Mac with homebrew, you can do brew install 1password-cli
  • For item creation, op v1.12.1 or higher is required
    • On earlier versions, an OPCreateItemNotSupportedException will be raised if on attempted item creation

TODO

TODO list has moved to GitHub Issues

About

A python API to query a 1Password account using the 'op' command-line tool, supporting 'op' v1.x

Resources

License

Stars

Watchers

Forks

Packages

No packages published