{"id":34024071,"url":"https://github.com/rmlibre/tiny_gnupg","last_synced_at":"2026-04-06T01:02:18.504Z","repository":{"id":65375526,"uuid":"227109776","full_name":"rmlibre/tiny_gnupg","owner":"rmlibre","description":"tiny_gnupg - A small-as-possible solution for handling GnuPG ed25519 ECC keys.","archived":false,"fork":false,"pushed_at":"2024-03-12T05:03:39.000Z","size":846,"stargazers_count":2,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-15T05:29:43.297Z","etag":null,"topics":["accessibility","adapter-pattern","aiohttp","anonymous","asyncio","automation","await","clean-code","communications","ed25519","elliptic-curve-cryptography","elliptic-curves","gnupg2","gpg","pgp","pgp-key","pgp-keyserver","security-tools","socks5","tor"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/tiny-gnupg/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rmlibre.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGES.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-10T12:00:37.000Z","updated_at":"2024-03-12T04:52:40.000Z","dependencies_parsed_at":"2023-01-20T05:15:51.919Z","dependency_job_id":null,"html_url":"https://github.com/rmlibre/tiny_gnupg","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/rmlibre/tiny_gnupg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmlibre%2Ftiny_gnupg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmlibre%2Ftiny_gnupg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmlibre%2Ftiny_gnupg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmlibre%2Ftiny_gnupg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rmlibre","download_url":"https://codeload.github.com/rmlibre/tiny_gnupg/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmlibre%2Ftiny_gnupg/sbom","scorecard":{"id":779053,"data":{"date":"2025-08-11","repo":{"name":"github.com/rmlibre/tiny_gnupg","commit":"32dc91d165835f3be572eda5ab48f1a9f661f645"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.4,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/pythonpackage.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpackage.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/rmlibre/tiny_gnupg/pythonpackage.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpackage.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/rmlibre/tiny_gnupg/pythonpackage.yml/main?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/pythonpackage.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/pythonpackage.yml:25","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-23T04:26:07.444Z","repository_id":65375526,"created_at":"2025-08-23T04:26:07.445Z","updated_at":"2025-08-23T04:26:07.445Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31455474,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T21:22:52.476Z","status":"ssl_error","status_checked_at":"2026-04-05T21:22:51.943Z","response_time":75,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accessibility","adapter-pattern","aiohttp","anonymous","asyncio","automation","await","clean-code","communications","ed25519","elliptic-curve-cryptography","elliptic-curves","gnupg2","gpg","pgp","pgp-key","pgp-keyserver","security-tools","socks5","tor"],"created_at":"2025-12-13T16:04:33.487Z","updated_at":"2026-04-06T01:02:18.495Z","avatar_url":"https://github.com/rmlibre.png","language":"Python","readme":"tiny_gnupg - A small-as-possible solution for handling GnuPG ed25519 ECC keys.\n==============================================================================\n\nA linux specific, small, simple \u0026 intuitive wrapper for creating, using\nand managing GnuPG's Ed25519 curve keys. In our design, we favor\nreducing code size \u0026 complexity with strong, bias defaults over\nflexibility in the api. Our goal is to turn the powerful, complex,\nlegacy gnupg system into a fun and safe tool to develop with.\n\nThis project is currently in unstable beta. It works like a charm, but\nthere's likely, and often bugs floating around, and the api is subject\nto change. Contributions are welcome.\n\n\n\n\n.. image:: https://badge.fury.io/py/tiny-gnupg.svg\n    :target: https://badge.fury.io/py/tiny-gnupg\n\n.. image:: https://img.shields.io/badge/License-GPL%20v3-red.svg\n    :target: https://img.shields.io/badge/License-GPL%20v3-red.svg\n    :alt: license\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://img.shields.io/badge/code%20style-black-000000.svg\n\n.. image:: https://github.com/rmlibre/tiny_gnupg/workflows/Python%20package/badge.svg\n    :target: https://github.com/rmlibre/tiny_gnupg/workflows/Python%20package/badge.svg\n\n\n\n\nTable Of Contents \n----------------- \n\n#)  `Install`_ \n\n#)  `Basic Commands`_ \n\n#)  `Networking Examples`_ \n\n#)  `About Torification`_ \n\n#)  `More Commands`_ \n\n#)  `Retiring Keys`_ \n\n\n\n\n_`Install` \n---------- \n\n.. code:: shell\n\n    sudo apt-get install tor torsocks gnupg2 gpg-agent \n    \n    pip install --user --upgrade tiny_gnupg \n\n\n\n\n_`Basic Commands` \n----------------- \n\nThe ``GnuPG`` class's instances are the primary interface for running commands \u0026 managing keys using the gpg2 executable. \n\n.. code:: python\n\n    from tiny_gnupg import GnuPG, run \n\n\n    PATH_TO_GPG_BINARY = \"/usr/bin/gpg2\" \n\n    gpg = GnuPG( \n        \n        email_address=\"bob@user.net\", \n        \n        passphrase=\"bobs's passphrase\", \n        \n        executable=PATH_TO_GPG_BINARY, \n    \n    ) \n    \n    \n    # This will generate a primary ed25519 ECC certifying key, and three \n    \n    # subkeys, one each for the authentication, encryption, and signing \n    \n    # functionalities. \n    \n    gpg.generate_key() \n    \n    \n    # Now this fingerprint can be used with arbitrary gpg2 commands. \n    \n    gpg.fingerprint \n    \n    \n    # The list of keys in the package's environment can be accessed \n    \n    # from the list_keys() method, which returns a dict -\u003e \n    \n    gpg.list_keys() \n    \u003e\u003e\u003e {fingerprint: email_address, ...} \n\n\n    # Or retrieve a specific key where a searchable portion of its uid \n    \n    # information is known, like an email address or fingerprint -\u003e \n    \n    gpg.list_keys(\"bob@user.net\") \n    \u003e\u003e\u003e {\"EE36F0584971280730D76CEC94A470B77ABA6E81\": \"bob@user.net\"} \n\n\n    # Let's try encrypting a message to Alice, whose public key is \n    \n    # stored on keys.openpgp.org/ \n\n\n    # First, we'll import Alice's key from the keyserver (This requires \n    \n    # a Tor system installation. Or an open TorBrowser, and the tor_port \n    \n    # attribute set to 9150) -\u003e\n\n    # Optional: gpg.keyserver.network.tor_port = 9150\n    \n    run(gpg.network_import(uid=\"alice@email.domain\")) \n    \n\n    # Then encrypt a message with Alice's key and sign it -\u003e \n    \n    msg = \"So, what's the plan this Sunday, Alice?\" \n    \n    encrypted_message = gpg.encrypt( \n    \n        message=msg, uid=\"alice@email.domain\", sign=True  # True is the default \n        \n    ) \n\n\n    # The process of encrypting a message to a peer whose public key \n    \n    # might not be in the local package keyring is conveniently available \n    \n    # in a single method. It automatically searches for the recipient's \n    \n    # key on the keyserver so it can be used to encrypt the message -\u003e \n    \n    run(gpg.auto_encrypt(msg, \"alice@email.domain\"))  # Signs by default\n    \n\n    # We could directly send a copy of our key to Alice, or upload it to \n    \n    # the keyserver. Alice will need a copy so the signature on the \n    \n    # message can be verified. So let's upload it to the keyserver -\u003e \n    \n    run(gpg.network_export(uid=\"bob@user.net\")) \n    \n\n    # Alice could now import our key (after we do an email verification \n    \n    # with the keyserver) -\u003e \n    \n    run(gpg.network_import(\"bob@user.net\")) \n    \n\n    # Then Alice can simply receive the encrypted message and decrypt it -\u003e \n    \n    decrypted_msg = gpg.decrypt(encrypted_message) \n\n\n    # The process of decrypting a encrypted \u0026 signed message from a peer \n    \n    # whose public key might not be in the local package keyring is \n    \n    # conveniently available in a single method. It automatically determines \n    \n    # the signing key fingerprint, and searches for it on the keyserver \n    \n    # to verify the signature -\u003e \n    \n    decrypted_msg = run(gpg.auto_decrypt(encrypted_message))\n\n\nOn most systems, because of a bug in GnuPG_, email verification of uploaded keys will be necessary for others to import them from the keyserver. That's because GnuPG will throw an error immediately upon trying to import keys with their uid information stripped off.\n\nThe package no longer comes with its own gpg2 binary. Your system gpg2 executable is probably located at: /usr/bin/gpg2. You could also type: ``whereis gpg2`` to find it. If it's not installed, you'll have to install it with your system's equivalent of: ``sudo apt-get install gnupg2``\n\n.. _GnuPG: https://dev.gnupg.org/T4393\n\n\n\n\n_`Networking Examples` \n---------------------- \n\n.. code:: python\n\n    # Since we use SOCKSv5 over Tor for all of our networking, as well \n    \n    # as the user-friendly aiohttp + aiohttp_socks libraries, the Tor \n    \n    # networking interface is also available to users. These utilities \n    \n    # allow arbitrary POST and GET requests to clearnet, or onionland, \n    \n    # websites -\u003e \n    \n    from tiny_gnupg import GnuPG, Network, run \n\n\n    client = Network(tor_port=9050)\n\n\n    async def read_url(client, url): \n        \"\"\" \n        Use the instance's interface to read the page located at the url \n        with a wrapper around an `aiohttp.ClientSession` context manager. \n        \"\"\" \n        async with client.context_get(url) as response: \n        \n            return await response.text() \n\n\n    # Now we can read webpages with GET requests -\u003e \n    \n    page_html = run(read_url(client, \"https://keys.openpgp.org/\")) \n    \n\n    # Let's try onionland -\u003e \n    \n    url = \"http://zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad.onion/\" \n    \n    onion_page_html = run(read_url(client, url)) \n\n\n    # Check your ip address for fun -\u003e \n    \n    ip_addr = run(read_url(client, \"https://icanhazip.com/\")) \n    \n\n    # There's a convenience function built into the class that \n    \n    # basically mimics read_url() -\u003e \n    \n    ip_addr = run(client.get(\"https://icanhazip.com/\")) \n    \n\n    # POST requests can also be sent with the context_post() method. \n    \n    # Let's use a POST request to send the keyserver a new key we \n    \n    # create -\u003e \n    \n    async def post_data(client, url, payload=\"\"): \n        \"\"\" \n        Use the instance's interface to post the api payload to the \n        keyserver with a wrapper around an `aiohttp.ClientSession` \n        context manager. \n        \"\"\" \n        async with client.context_post(url, json=payload) as response: \n        \n            return await response.text() \n\n\n    gpg = GnuPG(email_address=\"bob@user.net\", passphrase=\"bobs's passphrase\")\n    \n    gpg.generate_key() \n    \n    url = gpg.keyserver._key_export_api_url \n    \n    payload = {\"keytext\": gpg.text_export(uid=gpg.fingerprint)} \n\n    api_token_json = run(post_data(client, url, payload)) \n\n\n    # There's also a convenience function built into the class that \n    \n    # mimics post_data() -\u003e \n    \n    api_token_json = run(client.post(url, json=payload)) \n\n\n    # Of course, this is just for demonstration. The method that should \n\n    # be used for uploading a key to the keyserver is network_export -\u003e\n\n    run(gpg.network_export(gpg.fingerprint))\n    \n\n    # And there we have it, it's super simple. And these requests have \n    \n    # the added benefit of being completely routed through Tor. The \n    \n    # keyserver here also has a v3 onion address which we use to query, \n    \n    # upload, and import keys. This provides a nice, default layer of \n    \n    # privacy to our communication needs. \n\n\nThese networking tools work off instances of aiohttp.ClientSession. To learn more about how to use their POST and GET requests, you can read the docs here_.\n\n.. _here: https://docs.aiohttp.org/en/stable/client_advanced.html#client-session\n\n\n\n\n_`About Torification` \n--------------------- \n\nA user can make sure that any connections the gnupg binary makes with the network are always run through Tor by setting ``torify=True`` during initialization. \n\n.. code:: python\n\n    from tiny_gnupg import GnuPG\n    \n    \n    gpg = GnuPG(**user_details, torify=True) \n    \n\nThis is helpful because there are gnupg settings which cause certain commands to do automatic connections to the web. For instance, when encrypting, gnupg may be set to automatically search for the recipient's key on a keyserver if it's not in the local keyring. This doesn't normally effect `tiny_gnupg` because it doesn't use gnupg's networking interface. It ensures Tor connections through the `aiohttp_socks` library. But, if gnupg does make these kinds of connections silently, using torify can prevent a user's IP address from being inadvertently revealed. \n\nUsing torify requires a Tor installation on the user system. If the user is running Debian / Ubuntu, then this guide_ could be helpful. \n\n.. _guide: https://2019.www.torproject.org/docs/debian.html.en\n\n\n\n\n_`More Commands` \n---------------- \n\n.. code:: python\n\n    # An instance can also be constructed from lower-level objects -\u003e \n    \n    from tiny_gnupg import BaseGnuPG, User, GnuPGConfig, run \n    \n    \n    PATH_TO_GPG_BINARY = \"/usr/bin/gpg2\" \n    \n    \n    # Passphrases can contain any characters, even emojis -\u003e \n    \n    user = User(email_address=\"bob@user.net\", passphrase=\"✅🐎🔋📌\") \n    \n    config = GnuPGConfig(executable=PATH_TO_GPG_BINARY, torify=True) \n    \n    gpg = BaseGnuPG(user, config=config) \n    \n    \n    # It turns out that the encrypt() method automatically signs the \n    \n    # message being encrypted. So, the `sign=False` flag only has to be \n    \n    # passed when a user doesn't want to sign a message -\u003e \n    \n    encrypted_unsigned_message = gpg.encrypt( \n    \n        message=\"sending message as an unidentified sender\", \n        \n        uid=\"alice@email.domain\",  # sending to alice, \n        \n        sign=False,  # no sender identification \n        \n    ) \n    \n    \n    # It also turns out, a user can sign things independently from \n    \n    # encrypting -\u003e \n    \n    message_to_verify = \"maybe a hash of a file?\"\n    \n    signed_data = gpg.sign(target=message_to_verify) \n    \n    assert message_to_verify == gpg.decrypt(signed_data)\n    \n    \n    # And verify a signature without checking the signed value -\u003e \n    \n    gpg.verify(message=signed_data)  # throws if invalid \n    \n    \n    # Or sign a key in the package's keyring -\u003e \n    \n    gpg.sign(\"alice@email.domain\", key=True) \n    \n    \n    # Importing key files is also a thing -\u003e \n    \n    path_to_file = \"/home/user/keyfiles/\" \n    \n    gpg.file_import(path=path_to_file + \"alices_key.asc\") \n    \n    \n    # As well as exporting public keys -\u003e \n    \n    gpg.file_export(path=path_to_file, uid=gpg.user.email_address) \n    \n    \n    # And secret keys, but really, keep those safe! -\u003e \n    \n    gpg.file_export(\n    \n        path=path_to_file, uid=gpg.user.email_address, secret=True\n    \n    ) \n    \n\n    # The keys don't have to be exported to a file. Instead they can \n    \n    # be exported as strings -\u003e \n    \n    my_key = gpg.text_export(uid=gpg.fingerprint) \n    \n\n    # So can secret keys (Be careful!) -\u003e \n    \n    my_secret_key = gpg.text_export(gpg.fingerprint, secret=True) \n    \n\n    # And they can just as easily be imported from strings -\u003e \n    \n    gpg.text_import(key=my_key) \n\n\n    # The generated keys are stored in the package's local keyring. \n    \n    # To talk to the package's gpg environment, an arbitrary command \n    \n    # can be constructed like this -\u003e \n    \n    # (an example) options = [\"list\", \"of\", \"options\", \"target\"]\n    \n    options = [\"--armor\", \"--encrypt\", \"-r\", gpg.fingerprint] \n    \n    command = gpg.encode_command(*options) \n    \n    inputs = gpg.encode_inputs(\"Message to myself\") \n    \n    encrypted_message = gpg.read_output(command, inputs) \n    \n    \n    # If a command would invoke the need for a passphrase, the \n    \n    # with_passphrase kwarg should be set to True -\u003e \n    \n    command = gpg.encode_command(*options, with_passphrase=True) \n    \n\n    # The passphrase then needs to be the first arg passed to \n    \n    # encode_inputs -\u003e \n    \n    inputs = gpg.encode_inputs(gpg.user.passphrase, *other_inputs) \n\n\n\n\n_`Retiring Keys` \n---------------- \n\nAfter a user no longer considers a key useful, or wants to dissociate from the key, then they have some options:\n\n.. code:: python\n\n    from tiny_gnupg import GnuPG, run \n    \n    \n    PATH_TO_GPG_BINARY = \"/usr/bin/gpg2\" \n    \n    gpg = GnuPG( \n    \n        email_address=\"bob@user.net\", \n        \n        passphrase=\"bobs's passphrase\", \n        \n        executable=PATH_TO_GPG_BINARY, \n        \n    ) \n    \n    \n    # They can revoke their key then distribute it publicly (somehow) \n    \n    # (the keyserver can't currently handle key revocations) -\u003e \n    \n    revoked_key = gpg.revoke(gpg.fingerprint)  # \u003c--  Distribute this! \n    \n    \n    # Uploading the revoked key will only strip the user ID information \n    \n    # from the key on the keyserver. It won't explicitly let others know \n    \n    # the key has been retired. However, this action cannot be undone -\u003e \n    \n    run(gpg.network_export(gpg.fingerprint)) \n    \n    \n    # The key can also be deleted from the package keyring like this -\u003e \n    \n    gpg.delete(uid=\"bob@user.net\") \n\n\n.. _key revocations: https://gitlab.com/hagrid-keyserver/hagrid/issues/137\n\n\n\n\n``Known Issues``\n=================\n\n-  Because of Debian `bug #930665`_, \u0026 related GnuPG `bug #T4393`_,\n   importing keys from the default keyserver `keys.openpgp.org`_ doesn’t\n   work automatically on all systems. Not without email confirmation, at\n   least. That’s because the keyserver will not publish uid information\n   attached to a key before a user confirms access to the email address\n   assigned to the uploaded key. And, because GnuPG folks are still\n   holding up the merging, \u0026 back-porting, of patches that would allow\n   GnuPG to automatically handle keys without uids gracefully. This\n   effects the ``network_import()`` method specifically, but also the\n   ``text_import()`` \u0026 ``file_import()`` methods, if they happen to be\n   passed a key or filename argument which refers to a key without uid\n   information. The gpg2 binary in this package can be replaced manually\n   if a user’s system has access to a patched version.\n-  Because of GnuPG `bug #T3065`_, \u0026 related `bug #1788190`_, the\n   ``--keyserver`` \u0026 ``--keyserver-options http-proxy`` options won’t\n   work with onion addresses, \u0026 they cause a crash if a keyserver\n   lookup is attempted. This is not entirely an issue for us since we\n   don’t use gnupg’s networking interface. In fact, we set these\n   environment variables anyway to crash on purpose if gnupg tries to\n   make a network connection. And in case the bug ever gets fixed (it\n   won’t), or by accident the options do work in the future, then a tor\n   SOCKSv5 connection will be used instead of a raw connection.\n-  This program may only be reliably compatible with keys that are also\n   created with this program. That’s because our terminal parsing is\n   reliant on specific metadata to be similar across all encountered\n   keys. It seems most keys have successfully been parsed with recent\n   updates, though more testing is needed.\n-  The tests don’t currently work when a tester’s system has a system\n   installation of tiny_gnupg, \u0026 the tests are being run from a local\n   git repo directory. That’s because the tests import tiny_gnupg, but\n   if the program is installed in the system, then python will get\n   confused about which keyring to use during the tests. This will lead\n   to crashes \u0026 failed tests. Git clone testers probably have to run\n   the test script closer to their system installation, one directory up\n   \u0026 into a tests folder. Or pip uninstall tiny_gnupg. OR, send a pull\n   request with an import fix.\n-  Currently, the package is part synchronous, \u0026 part asynchronous.\n   This is not ideal, so a decision has to be made: either to stay mixed\n   style, or choose one consistent style.\n-  We’re still in unstable beta \u0026 have to build out our test suite.\n   Contributions welcome.\n-  The tests seems to fail on some systems because of a torsocks \n   filter [1_][2_] which blocks some syscalls. This may be patched or not\n   applicable on non-linux operating systems.\n\n.. _bug #930665: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=930665\n.. _bug #T4393: https://dev.gnupg.org/T4393\n.. _keys.openpgp.org: https://keys.openpgp.org/\n.. _bug #T3065: https://dev.gnupg.org/T3065#111023\n.. _bug #1788190: https://bugs.launchpad.net/ubuntu/+source/gnupg2/+bug/1788190\n.. _1: https://stackoverflow.com/questions/46634215/torsocks-and-unsupported-syscalls\n.. _2: https://gitlab.torproject.org/legacy/trac/-/issues/28861\n\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmlibre%2Ftiny_gnupg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frmlibre%2Ftiny_gnupg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmlibre%2Ftiny_gnupg/lists"}