{"id":23315369,"url":"https://github.com/lexndru/unlocker","last_synced_at":"2025-08-28T05:36:05.029Z","repository":{"id":62586464,"uuid":"144511844","full_name":"lexndru/unlocker","owner":"lexndru","description":"A keychain and CLI credentials manager","archived":false,"fork":false,"pushed_at":"2018-09-22T15:47:08.000Z","size":131,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-22T15:52:34.180Z","etag":null,"topics":["cli","credentials","encryption","keychain","passwordless"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lexndru.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2018-08-13T00:44:38.000Z","updated_at":"2023-01-15T12:48:26.000Z","dependencies_parsed_at":"2022-11-03T22:09:57.953Z","dependency_job_id":null,"html_url":"https://github.com/lexndru/unlocker","commit_stats":null,"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/lexndru/unlocker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexndru%2Funlocker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexndru%2Funlocker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexndru%2Funlocker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexndru%2Funlocker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lexndru","download_url":"https://codeload.github.com/lexndru/unlocker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lexndru%2Funlocker/sbom","scorecard":{"id":586609,"data":{"date":"2025-08-11","repo":{"name":"github.com/lexndru/unlocker","commit":"19950a7da374f6691ec525e4e8539e0d98faabeb"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.2,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","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":"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":"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":"Code-Review","score":0,"reason":"Found 0/20 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":"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":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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":"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":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating alpine:3.7 to alpine:3.7@sha256:8421d9a84432575381bfabd248f1eb56f3aa21d9d7cd2511583c68c9b7511d10","Warn: downloadThenRun not pinned by hash: Dockerfile:92-113","Warn: pipCommand not pinned by hash: Dockerfile:119","Info:   0 out of   1 containerImage dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned","Info:   0 out of   1 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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"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"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T20:41:01.337Z","repository_id":62586464,"created_at":"2025-08-20T20:41:01.337Z","updated_at":"2025-08-20T20:41:01.337Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272446706,"owners_count":24936518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-28T02:00:10.768Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["cli","credentials","encryption","keychain","passwordless"],"created_at":"2024-12-20T15:34:18.792Z","updated_at":"2025-08-28T05:36:04.983Z","avatar_url":"https://github.com/lexndru.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unlocker\n[![Build Status](https://travis-ci.org/lexndru/unlocker.svg?branch=master)](https://travis-ci.org/lexndru/unlocker)\n\nUnlocker is a keychain and a CLI credentials manager. Useful when you use a terminal often than GUI applications for remote connections (e.g. databases, SSH, rsync). It can store passwords and private keys. It comes with additional helper shells to encrypt your secrets and quick connect to servers passwordless.\n\n## System requirements\n- cPython \u003e= 2.7.12\n- pip \u003e= 9.0.2\n- gdbm\n\n## Install\n```\n$ pip install unlocker\n```\n\n## Build from sources\n```\n$ python setup.py install\n```\n\n## Important note\nThis software is in a **beta** phase, it is highly recommended to keep a copy of your credentials in a safe place! Also, please report any faulty runtime or unexpected behavior of Unlocker. Thank you!\n\n## Getting started\nUnlocker is a simple storage for passwords and private keys. The main purpose of *unlocker* is to be a manager for such data and give CRUD-like options to add, update, read and delete sets of credentials.\n\nStored credentials are kept inside a keychain-type database. In *unlocker* context, the keychain storage is called *secrets* and has a versioning system. Secrets stored in older versions of Unlocker may not be directly compatible, thus it's needed to migrate them before using. All stored sensible credentials are compressed and encoded.\n\nAs a side feature, Unlocker has additional helper shell scripts that make it easier to use in day-to-day life. These scripts can be installed directly from unlocker's addons option: `unlocker install`. The result of this operation are two (2) new scripts in your `~/bin` directory: an `unlock` wrapper script to make passwordless connections to known servers; and a `lock` script to encrypt your *secrets*.\n\nNotice: if for any reasons you have scripts named `lock` and `unlock` in your `~/bin` directory, *unlocker* will abort the installation of these scripts.\n\n```\n$ unlocker\n              _            _\n  _   _ _ __ | | ___   ___| | _____ _ __\n | | | | '_ \\| |/ _ \\ / __| |/ / _ \\ '__|\n | |_| | | | | | (_) | (__|   \u003c  __/ |\n  \\__,_|_| |_|_|\\___/ \\___|_|\\_\\___|_|\n\nUnlocker - CLI credentials manager\n\nUsage:\n  init          Create local keychain\n  list          List known hosts from keychain\n  recall        Retrieve secrets by name or signature (slower than lookup)\n  forget        Forget secrets by name or signature (slower than remove)\n  append        Add new set of credentials to keychain\n  update        Update password or private key to keychain\n  remove        Remove credentials from keychain\n  lookup        Find password for provided host, port and user\n  install       Install helper scripts\n  migrate       Migrate secrets to current unlocker version\n\n```\n\n## Options table\n\nOption | Meaning\n------ | -------\n`init` | Create the keychain on the current machine inside your `$HOME` directory (optional)\n`list` | Displays table-like list of existing credentials from keychain\n`update` | Update *secrets* or bounce server for an existing server\n`remove` | Remove set of credentials from keychain\n`forget` | Like *remove*, but handles names and signatures\n`lookup` | Lookup *secrets* from keychain\n`recall` | Like *lookup*, but handles names and signatures\n`install` | Installs two (2) new POSIX shell scripts as *unlocker* wrappers\n`migrate` | Migrate secrets to current version of *unlocker*\n\n\n## Features and conventions\nUnlocker comes with a few tricks out of the box, it is written with some conventions in mind and tries to make it easier for developers to follow a defined \"way of doing things\" and work faster, although it's not mandatory and ignoring this section does not affect the usage of *unlocker* in any way.\n\n#### Named servers with tags\nGive your server a name otherwise it will receive a random string as name. You know better what's the purpose of each server. Follow this small convention when naming a server: `tag:the_name_you_want` where tag is something *unlocker* recognizes as being part of the name. If you set the tag `live` or `prod` to your server, *unlocker* will warn you before connecting to this server (e.g. in case you made a mistake when typing the name) and requires your direct confirmation to continue (this means you have to press a key to continue).\n```\n$ unlock ssh live:that_cool_server  # unlocker recognizes \"live\" tag and gives a heads up\nNotice: Production server ahead!\nNotice: You are connecting to a LIVE production server...\nNotice: Proceed with caution\nConnecting to ssh://username@localhost:22 (live:that_cool_server) using password\nPress any key to continue or ^C to exit...\n```\n\n#### Notification on `root` users\n*Unlocker* does't make a difference between one user or another, it just keeps your credentials for later use. But for a developer or for a sysadmin there's a huge difference between a `root` user and the next one. Whenever you attempt to connect to a server with a `root` user, *unlocker* will notify you and it requires your direct input as a confirmation (just as the `live` tag on named servers, it means a press of a key). The `root` user will always be the last option for an ambiguous connection.\n```\n$ unlock ssh localhost              # you haven't specified what user to use...\n                                    # unlocker will query all possible options\n                                    # from the known servers and choose the first\n                                    # non-root user or fallback to root and alert\n...\n\n$ unlock ssh root@localhst\nNotice: Root user ahead!\nNotice: You are connecting to a server with ROOT privileges...\nNotice: Proceed with caution\nConnecting to ssh://root@localhost:22 using password\nPress any key to continue or ^C to exit...\n```\n\n#### Switching protocols\nWhen connecting via a named server (e.g. `live:that_cool_server`) *unlocker* has a special feature of detecting protocol mistakes. If you, for some whatever reason, type `mysql` instead of `ssh` for your named server and there is no `mysql` known connection for that named server, then *unlocker* can detect other supported protocols and advise you to switch.\n```\n$ unlock redis live:that_cool_server\nYou requested redis, but only ssh is available for this server\nSwitch to ssh? [yN] y\n```\n\n#### Jump servers\nUnlocker can save credentials to a server, but it can also save a jump server for that connection to work. Mostly useful when you have connections on localhost servers (such as databases binded to `localhost` on a VPC) or are behind a firewall and accessible only though SSH tunnels. E.g. if you have a MySQL server binded to 127.0.0.1 on your my.server.tld, then you have to save the SSH server first, afterwards you'll be able to get the signature of the server and add the MySQL connection as well.\n```\n$ unlocker append -h my.server.tld -p 22 -u an_user -s ssh -a privatekey -n live:that_cool_server\nPath to private key: /tmp/secret.key\n\n  Secrets successfully added!\n\n  an_user@0.0.0.0:22           # this will be the IP address of my.server.tld\n\n\n$ unlocker list\n   hash    |   bounce   | protocol |      ipv4       | port  |       hostname       |     user      |    friendly name    \n========== | ========== | ======== | =============== | ===== | ==================== | ============= | ====================\n fa565262  |     ~      |   ssh    |     0.0.0.0     |  22   |    my.server.tld     |    an_user    | live:that_cool_server\n```\n\n```\n$ unlocker append -h localhost -p 3306 -u another_user -s mysql -a password -n db:my_mysql_server -j fa565262\nPassword: *****\n\n  Secrets successfully added!\n\n  another_user@127.0.0.1:3306\n\n\n$ unlocker list\n   hash    |   bounce   | protocol |      ipv4       | port  |       hostname       |     user      |    friendly name    \n========== | ========== | ======== | =============== | ===== | ==================== | ============= | ====================\n fa565262  |     ~      |   ssh    |     0.0.0.0     |  22   |    my.server.tld     |    an_user    | live:that_cool_server  \n 7c2ffc13  |  fa565262  |  mysql   |    127.0.0.1    | 3306  |      localhost       | another_user  |  db:my_mysql_server\n```\n\n## Examples\n\n#### Add localhost MySQL server and quick connect\n```\n$ unlocker install\nOK\n$ unlocker append -h localhost -p 3306 -u user -s mysql -a password -n dev:mysql_server\nPassword: \u003cyour password\u003e\n...\n\n  Secrets successfully added!\n\n  user@127.0.0.1:3306\n\n...\n$ unlock mysql dev:mysql_server\n  OR\n$ unlock mysql user@localhost\n  OR\n$ unlock mysql localhost\n```\n\n#### Save server with private key\n```\n$ unlocker append -h private.server.tld -p 22 -u root -s ssh -a privatekey -n prod:server\nPath to private key: /var/keys/rsa.pk\n...\n\n  Secrets successfully added!\n\n  root@10.0.2.1:22\n\n...\n```\n\n#### Retrieve password for MySQL server\n```\n$ unlocker lookup -n dev:mysql_server\n  OR\n$ unlocker recall dev:mysql_server\n...\n\n  Secret password for localhost\n\n  user@127.0.0.1:3306    #############     \u003c-- masked if shell supports, otherwise plain\n\n...\n```\n\n#### Permanently remove server\n```\n$ unlocker remove -n dev:mysql_server\n  OR\n$ unlocker forget dev:mysql_server\n...\n\n  Permanently removed secret password for localhost!\n\n  This is the last chance to save this secret.\n\n  user@127.0.0.1:3306    #############     \u003c-- masked if shell supports, otherwise plain\n\n...\n```\n\n#### Update a password or a private key for a server\n```\n$ unlocker update -n dev:mysql_server -a password\nPassword: \u003cyour password\u003e\n...\n\n  Secrets successfully updated!\n\n  user@127.0.0.1:3306\n\n...\n```\n\n#### Recreate keychain (only if you know what you're doing!)\n```\n$ rm -r ~/.unlocker\n$ unlocker init\nOK\n```\n\n#### Migrate secrets over different versions\n```\n$ unlocker migrate\nOK\n```\n\n#### Export all secrets to unlocker file (.unl)\n```\n$ unlocker migrate --export \u003e /tmp/secrets.unl\nOK\n```\n\n#### Export only certain secrets to unlocker file (.unl)\n```\n$ unlocker migrate --export name_1 name_2 name_3 \u003e /tmp/secrets.unl\nOK\n```\n*Notice: export tool does not check for jump servers. It's up to the user to select all needed servers to export*\n\n#### Import secrets from unlocker file (.unl)\n```\n$ unlocker migrate --import \u003c /tmp/secrets.unl\nOK\n```\n*Notice: current version of import does not map jump servers. It's up to the user to manually map imported servers*\n\n#### Encrypt your secrets\n```\n$ unlocker install\nOK\n$ lock\n...\nSecrets are now encrypted. Don't forget the password!\n```\n\n## Next steps\n- [x] Additional helper script to unlock servers\n- [x] Encrypt secrets file\n- [x] Support secrets with connections through tunnels and jump servers\n- [x] Implement named records\n- [x] Better support for unicode\n- [ ] Create helper scripts for MacOS and Windows\n\n## License\nCopyright 2018 Alexandru Catrina\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flexndru%2Funlocker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flexndru%2Funlocker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flexndru%2Funlocker/lists"}