{"id":16528679,"url":"https://github.com/zetlen/clortho","last_synced_at":"2025-09-12T19:32:03.037Z","repository":{"id":57104185,"uuid":"47501900","full_name":"zetlen/clortho","owner":"zetlen","description":":key: :ghost: friendly password handling for node scripts","archived":false,"fork":false,"pushed_at":"2021-01-19T14:51:30.000Z","size":57,"stargazers_count":15,"open_issues_count":5,"forks_count":9,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-08-09T03:24:35.953Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zetlen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-06T15:20:38.000Z","updated_at":"2023-02-27T14:29:08.000Z","dependencies_parsed_at":"2022-08-20T17:10:25.951Z","dependency_job_id":null,"html_url":"https://github.com/zetlen/clortho","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/zetlen/clortho","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zetlen%2Fclortho","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zetlen%2Fclortho/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zetlen%2Fclortho/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zetlen%2Fclortho/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zetlen","download_url":"https://codeload.github.com/zetlen/clortho/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zetlen%2Fclortho/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274863825,"owners_count":25364227,"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-09-12T02:00:09.324Z","response_time":60,"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":[],"created_at":"2024-10-11T17:41:13.003Z","updated_at":"2025-09-12T19:32:02.750Z","avatar_url":"https://github.com/zetlen.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"![The destructor is coming!](http://i.imgur.com/RiMmYgU.png])\n\n[![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg?style=flat-square)](https://github.com/Flet/semistandard)\n\n![Travis CI](https://travis-ci.org/zetlen/clortho.svg)\n\n**Clortho** is a library for asking for service passwords from node scripts. It is [not](https://github.com/pivotal/vinz-clortho) the [first](https://github.com/mozilla/vinz-clortho) library to be named after Louis Tully, but I chose a new form for him: that of a giant Slor!\n\n#### Use Clortho if:\n - You're using Node as a scripting language with user interaction, such as a Yeoman generator, or a Grunt or Gulp plugin.\n - You need to prompt the user for a password to some external service.\n - You want to prompt the user in a friendly way, using GUI tools where available.\n - You want to store the password securely.\n \n*Clortho combines keychain authentication with user prompting, so if user interaction isn't a part of your app--that is, if it's a server--then Clortho is not appropriate. If you just want keychain access, you're looking for [node-keytar][1].*\n\n### Usage\n\n`clortho` is a function that returns a promise for a credential. A credential is an object with `username` and `password` properties. The `password` will be in plaintext, so don't cross the streams with it.\n\n```js\n  const clortho = require('clortho');\n\n  clortho({\n    service: 'Gozer',\n    username: 'vinz@clortho.horse',\n    message: 'I am Vinz, Vinz Clortho, Keymaster of Gozer. Volguus Zildrohar, Lord of the Sebouillia. Are you the Gatekeeper?'\n  }).then(credential =\u003e {\n    console.log(credential.username);\n    console.log(credential.password);\n  });\n```\n\nThe above is the simplest usage; it should work for most cases, because it does some sane things.\n\n1. First, it checks your operating system's credential store or keychain for a password for the named `service` and `username`, using the `security` utility on OSX, a PowerShell script on Windows, or a simple in-memory storage (that never writes to disk) if neither are available.\n\n2. If it finds a password available in the keychain, it skips prompting the user and resolves the promise with the credential.\n\n3. If it doesn't find a password, it prompts the user with an OS-appropriate authentication prompt. In Windows 7 and above, it looks like this:\n\n  ![Windows PowerShell style](http://i.imgur.com/y79xLc7.png)\n\n  In OSX, it looks like this:\n\n  ![OSX AppleScript style](http://i.imgur.com/YWUxewA.png)\n\n  On other operating systems, or if the username was not supplied on OSX, the prompt occurs in the terminal running the program.\n\n  ![CLI terminal style](http://i.imgur.com/nMnyciR.png)\n\n4. If the user clicks \"Cancel\", the promise rejects. If the user enters a password, however...\n\n5. It stores the username and password in the system keychain.\n\n6. Then, it fulfills the promise with the credential object.\n\nThe available options for the `clortho(opts)` function are:\n - `service`: **Required.** Name of the service for which Clortho is getting a credential. This can be any arbitrary string, like \"zuul\" or \"AWS Sandbox\".\n - `username`: **Optional.** The username for which Clortho is getting a password. If this is not supplied, Clortho will ask for both a username and password.\n - `message`: **Optional.** A custom message to display with the password prompt, instead of the default \"Please enter your username and password\".\n - `cli`: **Optional.** If this is `true`, the prompt step will always use the CLI in-terminal prompt style. If it is `false`, the prompt step will *never* use that style. Default is `undefined`, which will allow Clortho to select an OS-appropriate prompt style.\n - `refresh`: **Optional.** If this is set to `true`, then Clortho will not check the keychain before prompting. This is appropriate to use if the password fails the first time. Default `false`.\n\n### API\n\nThe sensible default above doesn't work in every case. Fortunately, the default `clortho` function is composed of several functions that can be exposed as separate steps. For instance, this example:\n\n```js\n  const clortho = require('clortho');\n\n  clortho({\n    service: 'Gozer',\n    username: 'vinz@clortho.horse',\n    message: 'I am Vinz, Vinz Clortho, Keymaster of Gozer. Volguus Zildrohar, Lord of the Sebouillia. Are you the Gatekeeper?'\n  }).then(credential =\u003e {\n    console.log(credential.username);\n    console.log(credential.password);\n  });\n```\n\nis equivalent to:\n\n```js\n  const vinz = require('clortho').forService('Gozer');\n  \n  vinz.getFromKeychain('vinz@clortho.horse')\n  .catch(() =\u003e\n    vinz.prompt(\n      'vinz@clortho.horse'\n      'I am Vinz, Vinz Clortho, Keymaster of Gozer. Volguus Zildrohar, Lord of the Sebouillia. Are you the Gatekeeper?'\n    )\n    .then(vinz.trySaveToKeychain)\n  );\n```\n\nYou can obtain a decomposed object like the above, by running `clortho.forService(serviceName)`. It has the following methods, all of which return promises:\n\n##### `getFromKeychain(username)`\nTakes a string `username`. Queries the system keychain for the username under the service. Resolves with a credential object. Rejects if a credential is not found or the keychain query failed for another reason.\n\n##### `prompt(username, message, cli)`\nPrompts the user with a system-appropriate dialog or prompt. The `username` string is optional (though on OSX, a missing `username` will make the system fall back to CLI style). The `message` string is optional, and works as above in the main `clortho` function. The `cli` boolean is optional. If it is `true`, then the prompt will **always** use the CLI terminal style. If it is `false`, then the prompt will **never** use the CLI terminal style. If it is any other value, or missing, then the prompt will detect the appropriate style to use. Resolves with a credential object. Rejects if the user cancels.\n\n##### `saveToKeychain(username, password)`\nBoth arguments are required. Saves the password securely to the system keychain. Resolves `true` if save was successful. Rejects if save failed for any reason.\n\n##### `trySaveToKeychain(credential)`\nInstead of separate `username` and `password` arguments like `saveToKeychain`, this method takes a credential object with `username` and `password` properties, and attempts to save it to the system keychain. This method **always resolves with the credential again**. It is meant as a pass-through method that should not notify if it fails.\n\n##### `removeFromKeychain(username)`\nRemove the password from the keychain for the service. Resolves `true` if delete was successful.\n\n### Installation\n\nNPM:\n\n    npm install clortho\n\n[1]: https://github.com/atom/node-keytar \"node-keytar\"\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzetlen%2Fclortho","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzetlen%2Fclortho","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzetlen%2Fclortho/lists"}