{"id":20887959,"url":"https://github.com/canop/safecloset","last_synced_at":"2025-04-13T00:48:22.361Z","repository":{"id":46022049,"uuid":"398821369","full_name":"Canop/safecloset","owner":"Canop","description":"Cross-platform Secure TUI Secret Locker","archived":false,"fork":false,"pushed_at":"2024-11-04T09:59:40.000Z","size":1171,"stargazers_count":90,"open_issues_count":2,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-13T00:48:15.984Z","etag":null,"topics":["cross-platform","cryptography","rust","secret","tui"],"latest_commit_sha":null,"homepage":"https://dystroy.org/safecloset","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Canop.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["Canop"]}},"created_at":"2021-08-22T14:35:00.000Z","updated_at":"2025-01-13T20:59:10.000Z","dependencies_parsed_at":"2024-11-04T10:39:23.472Z","dependency_job_id":null,"html_url":"https://github.com/Canop/safecloset","commit_stats":{"total_commits":133,"total_committers":2,"mean_commits":66.5,"dds":"0.015037593984962405","last_synced_commit":"8f36ebf2dc9f5a9c0c10def2da7dbccaded3d228"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fsafecloset","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fsafecloset/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fsafecloset/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Canop%2Fsafecloset/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Canop","download_url":"https://codeload.github.com/Canop/safecloset/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248650437,"owners_count":21139672,"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","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":["cross-platform","cryptography","rust","secret","tui"],"created_at":"2024-11-18T08:23:32.609Z","updated_at":"2025-04-13T00:48:22.335Z","avatar_url":"https://github.com/Canop.png","language":"Rust","funding_links":["https://github.com/sponsors/Canop"],"categories":[],"sub_categories":[],"readme":"[![Latest Version][s1]][l1] [![Chat on Miaou][s2]][l2]\n\n[s1]: https://img.shields.io/crates/v/safecloset.svg\n[l1]: https://crates.io/crates/safecloset\n\n[s2]: https://miaou.dystroy.org/static/shields/room.svg\n[l2]: https://miaou.dystroy.org/3768?rust\n\n**SafeCloset** keeps your secrets in password protected files.\n**SafeCloset** is designed to be convenient and avoid common weaknesses like external editing or temporary files written on disk.\n\n\n**[SafeCloset documentation](https://dystroy.org/safecloset)**\n\n# Warning\n\n**SafeCloset** hasn't been independently audited and comes with **absolutely** no guarantee.\nAnd I can do nothing for you if you lose the secrets you stored in SafeCloset.\n\n# Overview\n\nA closet is stored in a file that you can backup, keep with you on an USB key, etc.\n\nA closet contains drawers, each one is found and open with its own password.\n\nA drawer contains a list of (key, value). Values are texts in which you can store a code, a password, comments, a poem, some data, etc.\n\nA drawer can also contain deeper crypted drawers.\n\n![clear drawer](doc/clear-drawer.png)\n\n# Features\n\n* The closet contains several drawers, some of them automatically created with an unknown password so that nobody can determine which drawers you're able to open, or even how many\n* Each drawer is separately crypted with AES-GCM-SIV, with a random one-use nonce and the password/key of your choice. This gives an inherently long to test decrypt algorithm (but you should still use long passphrases for your drawers)\n* You can have one or several drawers with real content. You can be forced to open a drawer at gun point and still keep other drawers secret without any trace, either at the top level or deeper in the drawer you opened\n* When you open a drawer, with its password, you can read it, search it, edit it, close it\n* In an open drawer you can create new drawers, or open deeper drawers if you know their password\n* SafeCloset automatically quits on inactivity\n* The size of the drawer's content isn't observable\n* No clear file is ever created, edition is done directly in the TUI (external editors are usually the weakest point)\n* No clear data is ever given to any external library, widget, etc.\n* All data is viewed and edited in the TUI application\n* You can compile SafeCloset yourself. Its code is small and auditable\n* The code is 100% in Rust. I wouldn't trust anything else today for such a program\n* The format of the closet file is described so that another application could be written to decode your closet files in the future (assuming you have the password)\n* SafeCloset can't be queried by other applications, like browsers. This is a feature.\n* You may have all your secrets in one file easy to keep with you and backup\n* No company can die and lose your secrets: you keep everything, with as many copies as necessary, where you want\n* No company can be forced to add some secret stealing code: SafeCloset is small, open-source and repleacable\n* Fast and convenient to use - This is where the focus of the design was\n* Cross-platform because you don't know where you'll have to use your closet\n* \"I'm being watched\" mode in which unselected values are hidden. This mode is kept per drawer, always activated when you launch SafeCloset with the `--hide` option, and toggled with \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003eh\u003c/kbd\u003e\n\n# Non features\n\n* SafeCloset doesn't protect you against keyloggers\n* SafeCloset doesn't protect you from somebody watching your screen while a secret value is displayed (but the rest of the drawer can be kept hidden)\n\n# Usage\n\n*Those screenshots are small, to fit here, but you may use SafeCloset full screen if you want.*\n\n## Create your closet file\n\nRun\n\n```bash\nsafecloset some/name.closet\n```\n\n![new closet](doc/new-closet.png)\n\n## Have a glance at the help\n\nHit \u003ckbd\u003e?\u003c/kbd\u003e to go to the help screen, where you'll find the complete list of commands.\n\n![help](doc/help.png)\n\nHit \u003ckbd\u003eesc\u003c/kbd\u003e to get back to the previous screen.\n\n## Create your first drawer\n\nHit \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003en\u003c/kbd\u003e\n\n![drawer creation](doc/drawer-creation.png)\n\n![new drawer](doc/new-drawer.png)\n\nIf you want, you can create a deeper drawer there, at any time, by hitting \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003en\u003c/kbd\u003e.\n\nOr hit \u003ckbd\u003en\u003c/kbd\u003e to create a new entry, starting with its name then hitting \u003ckbd\u003etab\u003c/kbd\u003e to go fill its value.\n\n![typing entry](doc/typing-entry.png)\n\nChange the selection with the arrow keys.\nGo from input to input with the \u003ckbd\u003etab\u003c/kbd\u003e key. Or edit the currently selected field with \u003ckbd\u003ea\u003c/kbd\u003e.\n\nReorder entries with \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003e🠕\u003c/kbd\u003e and \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003e🠗\u003c/kbd\u003e.\n\nIn SafeCloset, when editing, searching, opening, etc., the \u003ckbd\u003eenter\u003c/kbd\u003e key validates the operation while the \u003ckbd\u003eesc\u003c/kbd\u003e key cancels or closes.\n\nYou may add newlines in values with \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003eenter\u003c/kbd\u003e or \u003ckbd\u003ealt\u003c/kbd\u003e\u003ckbd\u003eenter\u003c/kbd\u003e:\n\n![multiline](doc/multiline.png)\n\n*You may notice the values are rendered as Markdown.*\n\nDon't hesitate to store hundreds of secrets in the same drawer as you'll easily find them with the fuzzy search.\n\nSearch with the \u003ckbd\u003e/\u003c/kbd\u003e key:\n\n![search](doc/search.png)\n\nWhen in the search input, remove the search with \u003ckbd\u003eesc\u003c/kbd\u003e, freeze it with \u003ckbd\u003eenter\u003c/kbd\u003e.\n\n## Save and quit\n\nHit \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003es\u003c/kbd\u003e to save, then \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003eq\u003c/kbd\u003e to quit.\n\n## Reopen\n\nThe same command is used later on to open the closet again:\n\n```bash\nsafecloset some/name.closet\n```\n\nIt may be a good idea to define an alias so that you have your secrets easily available.\nYou could for example have this in you `.bashrc`:\n\n```bash\nfunction xx {\n\tsafecloset -o ~/some/name.closet\n}\n```\n\nThe `-o` argument makes safecloset immediately prompt for drawer password, so that you don't have to type \u003ckbd\u003ectrl\u003c/kbd\u003e\u003ckbd\u003eo\u003c/kbd\u003e.\n\nOn opening, just type the password of the drawer you want to open (all will be tested until the right one opens):\n\n![drawer opening](doc/drawer-opening.png)\n\n# Storage format\n\nThe storage format is described to ensure it's possible to replace SafeCloset with another software if needed.\n\nThe closet file is a [MessagePack](https://msgpack.org/index.html) encoded structure `Closet` with the following fields:\n\n* `comments`: a string\n* `salt`: a string\n* `drawers`: an array of `ClosedDrawer`\n\nThe MessagePack serialization preserves field names and allows future additions.\n\nAn instance of `ClosedDrawer` is a structure with the following fields:\n\n* `id`: a byte array\n* `nonce`: a byte array\n* `content`: a byte array\n\nThe `content` is the AES-GCM-SIV encryption of the serializied drawer with the included `nonce`.\nThe key used for this encryption is a 256 bits Argon2 hash of the password with the closet's salt.\n\nThe serialized drawer is a MessagePack encoded structure with the following fields:\n\n* `id`: a byte array\n* `entries`: an array of `Entry`\n* `settings`: an instance of `DrawerSettings`\n* `closet`: a deeper closet, containing drawers, etc.\n* `garbage`: a random byte array\n\nInstances of `Entry` contain the following fields:\n\n* `name`: a string\n* `value`: a string\n\nInstances of `DrawerSettings` contain the following fields:\n\n* `hide_values`: a boolean\n* `open_all_values`: a boolean (optional, false if not present)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanop%2Fsafecloset","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcanop%2Fsafecloset","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanop%2Fsafecloset/lists"}