├── .build-and-release.sh ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── alfred-workflow-release.yml │ ├── markdownlint.yml │ ├── pr-title.yml │ └── stale-bot.yml ├── .gitignore ├── .markdownlint.yaml ├── .rsync-exclude ├── Justfile ├── LICENSE ├── README.md ├── icon.png ├── info.plist └── scripts ├── auto-push.sh ├── clear-clipboard.sh ├── copy-pw.sh ├── delete-pw.sh ├── generate-random-password.js ├── pass-cli-search.js ├── pw-generate.sh ├── select-folder-for-new-pw.js ├── show-properties.js └── update-pw.sh /.build-and-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | #─────────────────────────────────────────────────────────────────────────────── 3 | 4 | # goto git root 5 | cd "$(git rev-parse --show-toplevel)" || return 1 6 | 7 | # Prompt for next version number 8 | current_version=$(plutil -extract version xml1 -o - info.plist | sed -n 's/.*\(.*\)<\/string>.*/\1/p') 9 | echo "current version: $current_version" 10 | echo -n " next version: " 11 | read -r next_version 12 | echo "────────────────────────" 13 | 14 | # GUARD 15 | if [[ -z "$next_version" || "$next_version" == "$current_version" ]]; then 16 | print "\033[1;31mInvalid version number.\033[0m" 17 | return 1 18 | fi 19 | 20 | # update version number in THE REPO'S `info.plist` 21 | plutil -replace version -string "$next_version" info.plist 22 | 23 | #─────────────────────────────────────────────────────────────────────────────── 24 | # INFO this assumes the local folder is named the same as the github repo 25 | # 1. update version number in LOCAL `info.plist` 26 | # 2. convenience: copy download link for current version 27 | 28 | # update version number in LOCAL `info.plist` 29 | prefs_location=$(defaults read com.runningwithcrayons.Alfred-Preferences syncfolder | sed "s|^~|$HOME|") 30 | workflow_uid="$(basename "$PWD")" 31 | local_info_plist="$prefs_location/Alfred.alfredpreferences/workflows/$workflow_uid/info.plist" 32 | if [[ -f "$local_info_plist" ]] ; then 33 | plutil -replace version -string "$next_version" "$local_info_plist" 34 | else 35 | print "\033[1;33mCould not increment version, local \`info.plist\` not found: '$local_info_plist'\033[0m" 36 | return 1 37 | fi 38 | 39 | # copy download link for current version 40 | msg="Available in the Alfred Gallery in 1-2 days, or directly by downloading the latest release here:" 41 | github_user=$(git remote --verbose | head -n1 | sed -E 's/.*github.com[:\](.*)\/.*/\1/') 42 | url="https://github.com/$github_user/$workflow_uid/releases/download/$next_version/${workflow_uid}.alfredworkflow" 43 | echo -n "$msg $url" | pbcopy 44 | 45 | #─────────────────────────────────────────────────────────────────────────────── 46 | 47 | # commit and push 48 | git add --all && 49 | git commit -m "release: $next_version" && 50 | git pull --no-progress && 51 | git push --no-progress && 52 | git tag "$next_version" && # pushing a tag triggers the github release action 53 | git push --no-progress origin --tags 54 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/displaying-a-sponsor-button-in-your-repository 2 | 3 | custom: https://www.paypal.me/ChrisGrieser 4 | ko_fi: pseudometa 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: textarea 7 | id: bug-description 8 | attributes: 9 | label: Bug Description 10 | description: A clear and concise description of the bug. 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: screenshot 15 | attributes: 16 | label: Relevant Screenshot 17 | description: If applicable, add screenshots or a screen recording to help explain your problem. 18 | - type: textarea 19 | id: reproduction-steps 20 | attributes: 21 | label: To Reproduce 22 | description: Steps to reproduce the problem 23 | placeholder: | 24 | For example: 25 | 1. Go to '...' 26 | 2. Click on '...' 27 | 3. Scroll down to '...' 28 | - type: textarea 29 | id: debugging-log 30 | attributes: 31 | label: Debugging Log 32 | description: "You can get a debugging log by opening the workflow in Alfred preferences and pressing `⌘ + D`. A small window will open up which will log everything happening during the execution of the Workflow. Use the malfunctioning part of the workflow once more, copy the content of the log window, and paste it here. If the debugging log is long, please attach it as file instead of pasting everything in here." 33 | render: Text 34 | validations: 35 | required: true 36 | - type: textarea 37 | id: workflow-configuration 38 | attributes: 39 | label: Workflow Configuration 40 | description: "Please add a screenshot of all your [workflow configuration](https://www.alfredapp.com/help/workflows/user-configuration/)." 41 | validations: 42 | required: true 43 | - type: checkboxes 44 | id: checklist 45 | attributes: 46 | label: Checklist 47 | options: 48 | - label: I have [updated to the latest version](https://github.com/chrisgrieser/alfred-pass/releases/latest) of this workflow. 49 | required: true 50 | - label: I am using Alfred 5. (Older versions are not supported anymore.) 51 | required: true 52 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Suggest an idea 3 | title: "Feature Request: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: feature-requested 8 | attributes: 9 | label: Feature Requested 10 | description: A clear and concise description of the feature. 11 | validations: 12 | required: true 13 | - type: textarea 14 | id: screenshot 15 | attributes: 16 | label: Relevant Screenshot 17 | description: If applicable, add screenshots or a screen recording to help explain the request. 18 | - type: checkboxes 19 | id: checklist 20 | attributes: 21 | label: Checklist 22 | options: 23 | - label: The feature would be useful to more users than just me. 24 | required: true 25 | 26 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | commit-message: 8 | prefix: "chore(dependabot): " 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## What problem does this PR solve? 2 | 3 | ## How does the PR solve it? 4 | 5 | ## Checklist 6 | - [ ] Used only `camelCase` variable names. 7 | - [ ] If functionality is added or modified, also made respective changes to the 8 | `README.md` and the internal workflow documentation. 9 | -------------------------------------------------------------------------------- /.github/workflows/alfred-workflow-release.yml: -------------------------------------------------------------------------------- 1 | name: Alfred Workflow Release 2 | 3 | on: 4 | push: 5 | tags: ["*"] 6 | 7 | env: 8 | WORKFLOW_NAME: ${{ github.event.repository.name }} 9 | 10 | #─────────────────────────────────────────────────────────────────────────────── 11 | 12 | jobs: 13 | build: 14 | runs-on: macos-latest 15 | permissions: { contents: write } 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | 20 | - name: Build .alfredworkflow 21 | run: | 22 | zip --recurse-paths --symlinks "${{ env.WORKFLOW_NAME }}.alfredworkflow" . \ 23 | --exclude "README.md" ".git*" "Justfile" ".build-and-release.sh" \ 24 | ".rsync-exclude" ".editorconfig" ".typos.toml" ".markdownlint.*" 25 | 26 | - name: Create release notes 27 | id: release_notes 28 | uses: mikepenz/release-changelog-builder-action@v5 29 | env: 30 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 31 | with: 32 | mode: "COMMIT" 33 | configurationJson: | 34 | { 35 | "label_extractor": [{ 36 | "pattern": "^(\\w+)(\\([\\w\\-\\.]+\\))?(!)?: .+", 37 | "on_property": "title", 38 | "target": "$1" 39 | }], 40 | "categories": [ 41 | { "title": "## ⚠️ Breaking changes", "labels": ["break"] }, 42 | { "title": "## 🚀 New features", "labels": ["feat", "improv"] }, 43 | { "title": "## 🛠️ Fixes", "labels": ["fix", "perf", "chore"] }, 44 | { "title": "## 👾 Other", "labels": [] } 45 | ], 46 | "ignore_labels": ["release", "bump"] 47 | } 48 | 49 | - name: Release 50 | uses: softprops/action-gh-release@v2 51 | with: 52 | token: ${{ secrets.GITHUB_TOKEN }} 53 | body: ${{ steps.release_notes.outputs.changelog }} 54 | files: ${{ env.WORKFLOW_NAME }}.alfredworkflow 55 | -------------------------------------------------------------------------------- /.github/workflows/markdownlint.yml: -------------------------------------------------------------------------------- 1 | name: Markdownlint check 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | paths: 7 | - "**.md" 8 | - ".github/workflows/markdownlint.yml" 9 | - ".markdownlint.*" # markdownlint config files 10 | pull_request: 11 | paths: 12 | - "**.md" 13 | 14 | jobs: 15 | markdownlint: 16 | name: Markdownlint 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: DavidAnson/markdownlint-cli2-action@v20 21 | with: 22 | globs: "**/*.md" 23 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: PR title 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | - reopened 10 | - ready_for_review 11 | 12 | permissions: 13 | pull-requests: read 14 | 15 | jobs: 16 | semantic-pull-request: 17 | name: Check PR title 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: amannn/action-semantic-pull-request@v5 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | with: 24 | requireScope: false 25 | subjectPattern: ^(?![A-Z]).+$ # disallow title starting with capital 26 | types: | # add `improv` to the list of allowed types 27 | improv 28 | fix 29 | feat 30 | refactor 31 | build 32 | ci 33 | style 34 | test 35 | chore 36 | perf 37 | docs 38 | break 39 | revert 40 | -------------------------------------------------------------------------------- /.github/workflows/stale-bot.yml: -------------------------------------------------------------------------------- 1 | name: Stale bot 2 | on: 3 | schedule: 4 | - cron: "18 04 * * 3" 5 | 6 | permissions: 7 | issues: write 8 | pull-requests: write 9 | 10 | jobs: 11 | stale: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Close stale issues 15 | uses: actions/stale@v9 16 | with: 17 | repo-token: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | # DOCS https://github.com/actions/stale#all-options 20 | days-before-stale: 180 21 | days-before-close: 7 22 | stale-issue-label: "Stale" 23 | stale-issue-message: | 24 | This issue has been automatically marked as stale. 25 | **If this issue is still affecting you, please leave any comment**, for example "bump", and it will be kept open. 26 | close-issue-message: | 27 | This issue has been closed due to inactivity, and will not be monitored. 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | 4 | # Alfred 5 | prefs.plist 6 | *.alfredworkflow 7 | -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Defaults https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml 2 | # DOCS https://github.com/markdownlint/markdownlint/blob/main/docs/RULES.md 3 | #─────────────────────────────────────────────────────────────────────────────── 4 | 5 | # MODIFIED SETTINGS 6 | blanks-around-headings: 7 | lines_below: 0 # space waster 8 | ul-style: { style: sublist } 9 | 10 | # not autofixable 11 | ol-prefix: { style: ordered } 12 | line-length: 13 | tables: false 14 | code_blocks: false 15 | no-inline-html: 16 | allowed_elements: [img, details, summary, kbd, a, br] 17 | 18 | #───────────────────────────────────────────────────────────────────────────── 19 | # DISABLED 20 | ul-indent: false # not compatible with using tabs 21 | no-hard-tabs: false # taken care of by editorconfig 22 | blanks-around-lists: false # space waster 23 | first-line-heading: false # e.g., ignore-comments 24 | no-emphasis-as-heading: false # sometimes useful 25 | -------------------------------------------------------------------------------- /.rsync-exclude: -------------------------------------------------------------------------------- 1 | # vim: ft=gitignore 2 | #─────────────────────────────────────────────────────────────────────────────── 3 | 4 | # git 5 | .git/ 6 | .gitignore 7 | 8 | # Alfred 9 | prefs.plist 10 | .rsync-exclude 11 | 12 | # docs 13 | docs/ 14 | LICENSE 15 | # INFO leading `/` -> ignore only the README in the root, not in subfolders 16 | /README.md 17 | 18 | # build 19 | Justfile 20 | .github/ 21 | .build-and-release.sh 22 | 23 | # linter & types 24 | .typos.toml 25 | .editorconfig 26 | .markdownlint.yaml 27 | jxa-globals.d.ts 28 | jsconfig.json 29 | alfred.d.ts 30 | -------------------------------------------------------------------------------- /Justfile: -------------------------------------------------------------------------------- 1 | set quiet := true 2 | 3 | # REQUIRED local workflow uses same folder name 4 | 5 | workflow_uid := `basename "$PWD"` 6 | prefs_location := `defaults read com.runningwithcrayons.Alfred-Preferences syncfolder | sed "s|^~|$HOME|"` 7 | local_workflow := prefs_location / "Alfred.alfredpreferences/workflows" / workflow_uid 8 | 9 | #─────────────────────────────────────────────────────────────────────────────── 10 | 11 | transfer-changes-FROM-local: 12 | #!/usr/bin/env zsh 13 | rsync --archive --delete --exclude-from="$PWD/.rsync-exclude" "{{ local_workflow }}/" "$PWD" 14 | git status --short 15 | 16 | transfer-changes-TO-local: 17 | #!/usr/bin/env zsh 18 | rsync --archive --delete --exclude-from="$PWD/.rsync-exclude" "$PWD/" "{{ local_workflow }}" 19 | cd "{{ local_workflow }}" 20 | print "\e[1;34mChanges at the local workflow:\e[0m" 21 | git status --short . 22 | 23 | [macos] 24 | open-local-workflow-in-alfred: 25 | #!/usr/bin/env zsh 26 | # using JXA and URI for redundancy, as both are not 100 % reliable https://www.alfredforum.com/topic/18390-get-currently-edited-workflow-uri/ 27 | open "alfredpreferences://navigateto/workflows>workflow>{{ workflow_uid }}" 28 | osascript -e 'tell application id "com.runningwithcrayons.Alfred" to reveal workflow "{{ workflow_uid }}"' 29 | 30 | release: 31 | ./.build-and-release.sh 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Christopher Grieser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alfred Client for the Pass-CLI 2 | ![GitHub Downloads](https://img.shields.io/github/downloads/chrisgrieser/alfred-pass/total?label=GitHub%20Downloads&style=plastic&logo=github) 3 | ![Alfred Gallery Downloads](https://img.shields.io/badge/dynamic/yaml?url=https%3A%2F%2Fraw.githubusercontent.com%2Fchrisgrieser%2F.config%2Frefs%2Fheads%2Fmain%2FAlfred.alfredpreferences%2Falfred-workflow-download-count.yaml&query=alfred-pass&style=plastic&logo=alfred&label=Gallery%20Downloads&color=%235C1F87) 4 | ![Latest Release](https://img.shields.io/github/v/release/chrisgrieser/alfred-pass?label=Latest%20Release&style=plastic) 5 | 6 | Alfred-based UI for [pass](https://www.passwordstore.org/). 7 | 8 | showcase 9 | 10 | 11 | 12 | - [Features](#features) 13 | - [Requirements & Installation](#requirements--installation) 14 | - [Configuration](#configuration) 15 | - [Usage](#usage) 16 | - [Notes on security](#notes-on-security) 17 | - [Credits](#credits) 18 | 19 | 20 | 21 | ## Features 22 | - Copy password to the clipboard. 23 | - Create a new entry. 24 | - Delete an entry. 25 | - Update the password of an entry. 26 | - Inspect and copy non-password properties of an entry. 27 | - [Inherits settings from your `.zshenv`.](#configuration) 28 | - Optionally trigger `pass git push` automatically after any change. 29 | - As opposed to regular usage of `pass`, the copied password is treated as 30 | transient, meaning it does not appear in Alfred's clipboard history. 31 | 32 | ## Requirements & Installation 33 | 1. [➡️ Download the latest release](https://github.com/chrisgrieser/alfred-pass/releases/latest) 34 | 2. Install the requirements 35 | 36 | ```bash 37 | brew install pass pinentry-mac 38 | ``` 39 | 40 | 3. Setup `pass` with a GPG key. See the [pass 41 | website](https://www.passwordstore.org/) for further information. 42 | 4. Setup `pinentry-mac` as your `pinentry-program`: 43 | 44 | ```bash 45 | [[ -d "$HOME/.gnupg" ]] || mkdir "$HOME/.gnupg" 46 | echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" > $HOME/.gnupg/gpg-agent.conf 47 | gpgconf --kill gpg-agent # restart the agent 48 | ``` 49 | 50 | ## Configuration 51 | This workflow reads all `PASSWORD_STORE_*` environment variables that have been 52 | added to your `~/.zshenv`, so most configuration is done by exporting respective 53 | variables in `~/.zshenv`. Example: `export PASSWORD_STORE_GENERATED_LENGTH=32`. 54 | 55 | For information about the available environment variables, see the [pass man 56 | page](https://git.zx2c4.com/password-store/about/). 57 | 58 | > [!NOTE] 59 | > If you are using a custom password-store directory, you **must** export your 60 | > `PASSWORD_STORE_DIR` in your `~/.zshenv` for this workflow to work. 61 | 62 | ## Usage 63 | - Search your passwords via the keyword `pw`. 64 | + : Copy password to the clipboard. 65 | + : Edit entry in your Terminal, using [the Terminal 66 | configured in your Alfred 67 | settings](https://www.alfredapp.com/help/features/terminal/) and your 68 | `$EDITOR`. 69 | + : Reveal `.gpg` file of the entry in Finder. 70 | + : Delete the entry. (⚠️ This is irreversible if you 71 | are not using git.) 72 | + : Show details of the entry. Select one of them 73 | to copy the value to your clipboard. 74 | + Fn: Generate a new password and overwrite this 75 | entry's password with it. Afterward, copy the new password. (⚠️ This removes 76 | the old password and is not reversible if you are not using git.) 77 | - Use the keyword `pw new` to create a new entry. You are then prompted for a 78 | folder to place the new entry in. The password of the new entry is 79 | auto-generated based on your `pass` settings, or can be inserted from your 80 | clipboard. 81 | - Use `pw gen` to generate a new password without creating a new entry. 82 | 83 | ## Notes on security 84 | - All contents copied by this clipboard are marked as "transient," meaning most 85 | clipboard history apps will ignore them, including Alfred's clipboard history. 86 | - This workflow is just a convenient UI for `pass`. As such, no password is ever 87 | stored by this workflow in any way. The workflow is completely open source. 88 | 89 | ## Credits 90 | In my day job, I am a sociologist studying the social mechanisms underlying the 91 | digital economy. For my PhD project, I investigate the governance of the app 92 | economy and how software ecosystems manage the tension between innovation and 93 | compatibility. If you are interested in this subject, feel free to get in touch. 94 | 95 | - [Academic Website](https://chris-grieser.de/) 96 | - [Mastodon](https://pkm.social/@pseudometa) 97 | - [ResearchGate](https://www.researchgate.net/profile/Christopher-Grieser) 98 | - [LinkedIn](https://www.linkedin.com/in/christopher-grieser-ba693b17a/) 99 | 100 | 101 | Buy Me a Coffee at ko-fi.com 108 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisgrieser/alfred-pass/60af4e02173237700ae7f8aea2b64bf36b88702f/icon.png -------------------------------------------------------------------------------- /info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | de.chris-grieser.pass-client-alfred 7 | category 8 | ⭐️ 9 | connections 10 | 11 | 09192EC9-2C76-4174-868D-22699F041C5D 12 | 13 | 14 | destinationuid 15 | 462A9DED-FC24-4D19-8ED2-C2D7162239B2 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | vitoclose 21 | 22 | 23 | 24 | destinationuid 25 | 0BC9A821-35ED-45C1-AA5A-A64A696BBFC8 26 | modifiers 27 | 0 28 | modifiersubtext 29 | 30 | vitoclose 31 | 32 | 33 | 34 | 0F6DB773-7447-4D7C-900E-59F3E9C69B19 35 | 36 | 37 | destinationuid 38 | 5654C2AF-88C2-4D89-A2E4-D26F2B3DEF0B 39 | modifiers 40 | 0 41 | modifiersubtext 42 | 43 | vitoclose 44 | 45 | 46 | 47 | 1C410C15-19B5-445B-B5B9-A406076C5E6D 48 | 49 | 50 | destinationuid 51 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 52 | modifiers 53 | 0 54 | modifiersubtext 55 | 56 | vitoclose 57 | 58 | 59 | 60 | 1E6D758F-172E-4E35-AD9C-3226C9D252C3 61 | 62 | 63 | destinationuid 64 | 3B6DB61F-2CEA-4A7D-A907-2740E8C4FCD6 65 | modifiers 66 | 0 67 | modifiersubtext 68 | 69 | vitoclose 70 | 71 | 72 | 73 | 24B77922-B082-4744-B4A1-6EAD37FFD88C 74 | 75 | 76 | destinationuid 77 | 92E44739-4524-4ADF-8D4B-C4FCE41A4D5F 78 | modifiers 79 | 0 80 | modifiersubtext 81 | 82 | vitoclose 83 | 84 | 85 | 86 | destinationuid 87 | E0554F56-4E6E-435D-9F25-4A4E089BE7F0 88 | modifiers 89 | 8388608 90 | modifiersubtext 91 | fn: Overwrite password with new generated one. Copy new password. (⚠️ Removes old password.) 92 | vitoclose 93 | 94 | 95 | 96 | destinationuid 97 | 6B581416-D12E-4AC2-B604-895443940F98 98 | modifiers 99 | 262144 100 | modifiersubtext 101 | ⌃: Delete Password 102 | vitoclose 103 | 104 | 105 | 106 | destinationuid 107 | B23E7DD4-F41F-4969-83C0-A44AD034C37F 108 | modifiers 109 | 131072 110 | modifiersubtext 111 | ⇧: Copy other property (⚠ requires unlocked gpg) 112 | vitoclose 113 | 114 | 115 | 116 | destinationuid 117 | E28BAD26-7C03-414A-A567-4F44432F9FD7 118 | modifiers 119 | 524288 120 | modifiersubtext 121 | ⌥: Show in Finder 122 | vitoclose 123 | 124 | 125 | 126 | destinationuid 127 | F19DCDE8-CB71-48BC-AFD8-EB381C71E346 128 | modifiers 129 | 1048576 130 | modifiersubtext 131 | ⌘: Edit Entry in Terminal 132 | vitoclose 133 | 134 | 135 | 136 | 2862B2B6-1294-4469-AFBF-558B7D805B7E 137 | 138 | 139 | destinationuid 140 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 141 | modifiers 142 | 0 143 | modifiersubtext 144 | 145 | vitoclose 146 | 147 | 148 | 149 | 2C2A79DD-A7C9-47A9-8AA4-0EEACB92D441 150 | 151 | 152 | destinationuid 153 | AC64DCEB-7AA1-422C-A8F9-81E1A91381E9 154 | modifiers 155 | 0 156 | modifiersubtext 157 | 158 | vitoclose 159 | 160 | 161 | 162 | 3B6DB61F-2CEA-4A7D-A907-2740E8C4FCD6 163 | 164 | 165 | destinationuid 166 | 8DFAB981-4135-40F5-BA81-DEDA35D0F632 167 | modifiers 168 | 0 169 | modifiersubtext 170 | 171 | vitoclose 172 | 173 | 174 | 175 | 462A9DED-FC24-4D19-8ED2-C2D7162239B2 176 | 177 | 178 | destinationuid 179 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 180 | modifiers 181 | 0 182 | modifiersubtext 183 | 184 | sourceoutputuid 185 | 09E3118E-E1F0-4A89-81D4-60E2B1A3F0B5 186 | vitoclose 187 | 188 | 189 | 190 | 5654C2AF-88C2-4D89-A2E4-D26F2B3DEF0B 191 | 192 | 193 | destinationuid 194 | 2F29A336-1599-4915-8D23-5C4FB4D51D19 195 | modifiers 196 | 0 197 | modifiersubtext 198 | 199 | sourceoutputuid 200 | 09E3118E-E1F0-4A89-81D4-60E2B1A3F0B5 201 | vitoclose 202 | 203 | 204 | 205 | destinationuid 206 | 09192EC9-2C76-4174-868D-22699F041C5D 207 | modifiers 208 | 0 209 | modifiersubtext 210 | 211 | vitoclose 212 | 213 | 214 | 215 | 6B581416-D12E-4AC2-B604-895443940F98 216 | 217 | 218 | destinationuid 219 | A5733344-CBEB-486B-87D4-DE52472EB5A5 220 | modifiers 221 | 0 222 | modifiersubtext 223 | 224 | vitoclose 225 | 226 | 227 | 228 | 6DEB3631-BC94-4826-A0A0-09A177B749C3 229 | 230 | 231 | destinationuid 232 | 2862B2B6-1294-4469-AFBF-558B7D805B7E 233 | modifiers 234 | 0 235 | modifiersubtext 236 | 237 | vitoclose 238 | 239 | 240 | 241 | destinationuid 242 | 0BC9A821-35ED-45C1-AA5A-A64A696BBFC8 243 | modifiers 244 | 0 245 | modifiersubtext 246 | 247 | vitoclose 248 | 249 | 250 | 251 | 83941436-919A-42A2-BCCA-4EB78802E09E 252 | 253 | 254 | destinationuid 255 | 0F6DB773-7447-4D7C-900E-59F3E9C69B19 256 | modifiers 257 | 0 258 | modifiersubtext 259 | 260 | vitoclose 261 | 262 | 263 | 264 | 8DFAB981-4135-40F5-BA81-DEDA35D0F632 265 | 266 | 267 | destinationuid 268 | D1151344-66AB-453F-8468-097748113645 269 | modifiers 270 | 0 271 | modifiersubtext 272 | 273 | vitoclose 274 | 275 | 276 | 277 | 92E44739-4524-4ADF-8D4B-C4FCE41A4D5F 278 | 279 | 280 | destinationuid 281 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 282 | modifiers 283 | 0 284 | modifiersubtext 285 | 286 | vitoclose 287 | 288 | 289 | 290 | 97B7CC9A-ED41-492D-A2F4-2D905A5EAE0C 291 | 292 | 293 | destinationuid 294 | 3FADF261-E630-4B7D-A39C-32D20770CF51 295 | modifiers 296 | 0 297 | modifiersubtext 298 | 299 | vitoclose 300 | 301 | 302 | 303 | A5733344-CBEB-486B-87D4-DE52472EB5A5 304 | 305 | 306 | destinationuid 307 | 0BC9A821-35ED-45C1-AA5A-A64A696BBFC8 308 | modifiers 309 | 0 310 | modifiersubtext 311 | 312 | vitoclose 313 | 314 | 315 | 316 | A5A50E6D-235D-44F3-ACFA-B80578EA0558 317 | 318 | 319 | destinationuid 320 | 0F6DB773-7447-4D7C-900E-59F3E9C69B19 321 | modifiers 322 | 0 323 | modifiersubtext 324 | 325 | vitoclose 326 | 327 | 328 | 329 | ABCD927B-BC30-42C8-865D-98D4D4CF4F59 330 | 331 | 332 | destinationuid 333 | 83941436-919A-42A2-BCCA-4EB78802E09E 334 | modifiers 335 | 0 336 | modifiersubtext 337 | 338 | vitoclose 339 | 340 | 341 | 342 | destinationuid 343 | A5A50E6D-235D-44F3-ACFA-B80578EA0558 344 | modifiers 345 | 1048576 346 | modifiersubtext 347 | ⌘↵: Insert password from clipboard 348 | vitoclose 349 | 350 | 351 | 352 | AC64DCEB-7AA1-422C-A8F9-81E1A91381E9 353 | 354 | 355 | destinationuid 356 | 1C410C15-19B5-445B-B5B9-A406076C5E6D 357 | modifiers 358 | 0 359 | modifiersubtext 360 | 361 | vitoclose 362 | 363 | 364 | 365 | B23E7DD4-F41F-4969-83C0-A44AD034C37F 366 | 367 | 368 | destinationuid 369 | 97B7CC9A-ED41-492D-A2F4-2D905A5EAE0C 370 | modifiers 371 | 0 372 | modifiersubtext 373 | 374 | vitoclose 375 | 376 | 377 | 378 | destinationuid 379 | 8B196ABE-DF0D-4D44-BB9B-CB731B0CC995 380 | modifiers 381 | 1048576 382 | modifiersubtext 383 | ⌘: Open URL in Browser 384 | vitoclose 385 | 386 | 387 | 388 | CA9D5F1A-6D6F-43AE-93FA-A482699EEA31 389 | 390 | 391 | destinationuid 392 | FEBD93EE-FAF9-4E4E-8627-84BEC380B964 393 | modifiers 394 | 0 395 | modifiersubtext 396 | 397 | vitoclose 398 | 399 | 400 | 401 | D1151344-66AB-453F-8468-097748113645 402 | 403 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 404 | 405 | 406 | destinationuid 407 | 1E6D758F-172E-4E35-AD9C-3226C9D252C3 408 | modifiers 409 | 0 410 | modifiersubtext 411 | 412 | vitoclose 413 | 414 | 415 | 416 | E0554F56-4E6E-435D-9F25-4A4E089BE7F0 417 | 418 | 419 | destinationuid 420 | 6DEB3631-BC94-4826-A0A0-09A177B749C3 421 | modifiers 422 | 0 423 | modifiersubtext 424 | 425 | vitoclose 426 | 427 | 428 | 429 | E28BAD26-7C03-414A-A567-4F44432F9FD7 430 | 431 | F19DCDE8-CB71-48BC-AFD8-EB381C71E346 432 | 433 | 434 | destinationuid 435 | F46688E5-F719-4EE2-89C5-FB26A5D6977F 436 | modifiers 437 | 0 438 | modifiersubtext 439 | 440 | sourceoutputuid 441 | BCD3864F-3522-4AF9-893A-21B8EBB5B4C6 442 | vitoclose 443 | 444 | 445 | 446 | destinationuid 447 | 7C6B7643-4B16-4307-ADA8-14D6837FEE59 448 | modifiers 449 | 0 450 | modifiersubtext 451 | 452 | vitoclose 453 | 454 | 455 | 456 | FEBD93EE-FAF9-4E4E-8627-84BEC380B964 457 | 458 | 459 | destinationuid 460 | ABCD927B-BC30-42C8-865D-98D4D4CF4F59 461 | modifiers 462 | 0 463 | modifiersubtext 464 | 465 | vitoclose 466 | 467 | 468 | 469 | 470 | createdby 471 | Chris Grieser 472 | description 473 | Client for the pass-cli 474 | disabled 475 | 476 | name 477 | Pass 478 | objects 479 | 480 | 481 | config 482 | 483 | alfredfiltersresults 484 | 485 | alfredfiltersresultsmatchmode 486 | 0 487 | argumenttreatemptyqueryasnil 488 | 489 | argumenttrimmode 490 | 0 491 | argumenttype 492 | 1 493 | escaping 494 | 0 495 | queuedelaycustom 496 | 3 497 | queuedelayimmediatelyinitially 498 | 499 | queuedelaymode 500 | 0 501 | queuemode 502 | 1 503 | runningsubtext 504 | 505 | script 506 | 507 | scriptargtype 508 | 1 509 | scriptfile 510 | ./scripts/select-folder-for-new-pw.js 511 | subtext 512 | 513 | title 514 | Select folder for new entry… 515 | type 516 | 8 517 | withspace 518 | 519 | 520 | type 521 | alfred.workflow.input.scriptfilter 522 | uid 523 | FEBD93EE-FAF9-4E4E-8627-84BEC380B964 524 | version 525 | 3 526 | 527 | 528 | config 529 | 530 | argumenttype 531 | 0 532 | subtext 533 | ↵: Autogenerate password ⌘↵: Password from clipboard 534 | text 535 | Name of Password: '{query}' 536 | withspace 537 | 538 | 539 | type 540 | alfred.workflow.input.keyword 541 | uid 542 | ABCD927B-BC30-42C8-865D-98D4D4CF4F59 543 | version 544 | 1 545 | 546 | 547 | config 548 | 549 | lastpathcomponent 550 | 551 | onlyshowifquerypopulated 552 | 553 | removeextension 554 | 555 | text 556 | {var:entry} 557 | title 558 | ⚠️ Entry already exists. Aborting. 559 | 560 | type 561 | alfred.workflow.output.notification 562 | uid 563 | 2F29A336-1599-4915-8D23-5C4FB4D51D19 564 | version 565 | 1 566 | 567 | 568 | config 569 | 570 | argumenttype 571 | 2 572 | keyword 573 | pw new 574 | subtext 575 | Store as new entry 576 | text 577 | ❇️ New password 578 | withspace 579 | 580 | 581 | type 582 | alfred.workflow.input.keyword 583 | uid 584 | CA9D5F1A-6D6F-43AE-93FA-A482699EEA31 585 | version 586 | 1 587 | 588 | 589 | config 590 | 591 | concurrently 592 | 593 | escaping 594 | 0 595 | script 596 | 597 | scriptargtype 598 | 1 599 | scriptfile 600 | scripts/pw-generate.sh 601 | type 602 | 8 603 | 604 | type 605 | alfred.workflow.action.script 606 | uid 607 | 0F6DB773-7447-4D7C-900E-59F3E9C69B19 608 | version 609 | 2 610 | 611 | 612 | config 613 | 614 | argument 615 | {query} 616 | passthroughargument 617 | 618 | variables 619 | 620 | entry 621 | {var:folder}/{query} 622 | generatePassword 623 | true 624 | 625 | 626 | type 627 | alfred.workflow.utility.argument 628 | uid 629 | 83941436-919A-42A2-BCCA-4EB78802E09E 630 | version 631 | 1 632 | 633 | 634 | config 635 | 636 | conditions 637 | 638 | 639 | inputstring 640 | 641 | matchcasesensitive 642 | 643 | matchmode 644 | 0 645 | matchstring 646 | ALREADY EXISTS 647 | outputlabel 648 | already exists 649 | uid 650 | 09E3118E-E1F0-4A89-81D4-60E2B1A3F0B5 651 | 652 | 653 | elselabel 654 | valid 655 | hideelse 656 | 657 | 658 | type 659 | alfred.workflow.utility.conditional 660 | uid 661 | 5654C2AF-88C2-4D89-A2E4-D26F2B3DEF0B 662 | version 663 | 1 664 | 665 | 666 | config 667 | 668 | argument 669 | {query} 670 | passthroughargument 671 | 672 | variables 673 | 674 | entry 675 | {var:folder}/{query} 676 | generatePassword 677 | false 678 | 679 | 680 | type 681 | alfred.workflow.utility.argument 682 | uid 683 | A5A50E6D-235D-44F3-ACFA-B80578EA0558 684 | version 685 | 1 686 | 687 | 688 | config 689 | 690 | lastpathcomponent 691 | 692 | onlyshowifquerypopulated 693 | 694 | removeextension 695 | 696 | text 697 | {var:entry} 698 | title 699 | ✅ New entry created 700 | 701 | type 702 | alfred.workflow.output.notification 703 | uid 704 | 09192EC9-2C76-4174-868D-22699F041C5D 705 | version 706 | 1 707 | 708 | 709 | config 710 | 711 | argumenttype 712 | 2 713 | keyword 714 | pw gen 715 | subtext 716 | Generate & copy it WITHOUT creating new entry 717 | text 718 | ✴️ New password 719 | withspace 720 | 721 | 722 | type 723 | alfred.workflow.input.keyword 724 | uid 725 | 2C2A79DD-A7C9-47A9-8AA4-0EEACB92D441 726 | version 727 | 1 728 | 729 | 730 | config 731 | 732 | concurrently 733 | 734 | escaping 735 | 0 736 | script 737 | 738 | scriptargtype 739 | 1 740 | scriptfile 741 | ./scripts/generate-random-password.js 742 | type 743 | 8 744 | 745 | type 746 | alfred.workflow.action.script 747 | uid 748 | AC64DCEB-7AA1-422C-A8F9-81E1A91381E9 749 | version 750 | 2 751 | 752 | 753 | config 754 | 755 | conditions 756 | 757 | 758 | inputstring 759 | 760 | matchcasesensitive 761 | 762 | matchmode 763 | 1 764 | matchstring 765 | INSERTED 766 | outputlabel 767 | generated 768 | uid 769 | 09E3118E-E1F0-4A89-81D4-60E2B1A3F0B5 770 | 771 | 772 | elselabel 773 | generated 774 | hideelse 775 | 776 | 777 | type 778 | alfred.workflow.utility.conditional 779 | uid 780 | 462A9DED-FC24-4D19-8ED2-C2D7162239B2 781 | version 782 | 1 783 | 784 | 785 | config 786 | 787 | argument 788 | {query} 789 | passthroughargument 790 | 791 | variables 792 | 793 | entry 794 | Generated 795 | 796 | 797 | type 798 | alfred.workflow.utility.argument 799 | uid 800 | 1C410C15-19B5-445B-B5B9-A406076C5E6D 801 | version 802 | 1 803 | 804 | 805 | config 806 | 807 | lastpathcomponent 808 | 809 | onlyshowifquerypopulated 810 | 811 | removeextension 812 | 813 | text 814 | 815 | title 816 | 📋 Clipboard cleared 817 | 818 | type 819 | alfred.workflow.output.notification 820 | uid 821 | D1151344-66AB-453F-8468-097748113645 822 | version 823 | 1 824 | 825 | 826 | config 827 | 828 | concurrently 829 | 830 | escaping 831 | 0 832 | script 833 | 834 | scriptargtype 835 | 1 836 | scriptfile 837 | ./scripts/clear-clipboard.sh 838 | type 839 | 8 840 | 841 | type 842 | alfred.workflow.action.script 843 | uid 844 | 8DFAB981-4135-40F5-BA81-DEDA35D0F632 845 | version 846 | 2 847 | 848 | 849 | config 850 | 851 | autopaste 852 | 853 | clipboardtext 854 | {query} 855 | ignoredynamicplaceholders 856 | 857 | transient 858 | 859 | 860 | type 861 | alfred.workflow.output.clipboard 862 | uid 863 | 1E6D758F-172E-4E35-AD9C-3226C9D252C3 864 | version 865 | 3 866 | 867 | 868 | config 869 | 870 | lastpathcomponent 871 | 872 | onlyshowifquerypopulated 873 | 874 | removeextension 875 | 876 | text 877 | {var:entry} 878 | title 879 | 📋 Copied {var:new}password for 880 | 881 | type 882 | alfred.workflow.output.notification 883 | uid 884 | 3B6DB61F-2CEA-4A7D-A907-2740E8C4FCD6 885 | version 886 | 1 887 | 888 | 889 | config 890 | 891 | matchmode 892 | 1 893 | matchstring 894 | \n$ 895 | regexcaseinsensitive 896 | 897 | regexmultiline 898 | 899 | replacestring 900 | 901 | 902 | type 903 | alfred.workflow.utility.replace 904 | uid 905 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 906 | version 907 | 2 908 | 909 | 910 | config 911 | 912 | concurrently 913 | 914 | escaping 915 | 0 916 | script 917 | 918 | scriptargtype 919 | 1 920 | scriptfile 921 | scripts/copy-pw.sh 922 | type 923 | 8 924 | 925 | type 926 | alfred.workflow.action.script 927 | uid 928 | 92E44739-4524-4ADF-8D4B-C4FCE41A4D5F 929 | version 930 | 2 931 | 932 | 933 | config 934 | 935 | alfredfiltersresults 936 | 937 | alfredfiltersresultsmatchmode 938 | 2 939 | argumenttreatemptyqueryasnil 940 | 941 | argumenttrimmode 942 | 0 943 | argumenttype 944 | 1 945 | escaping 946 | 0 947 | keyword 948 | pw 949 | queuedelaycustom 950 | 3 951 | queuedelayimmediatelyinitially 952 | 953 | queuedelaymode 954 | 0 955 | queuemode 956 | 2 957 | runningsubtext 958 | 959 | script 960 | 961 | scriptargtype 962 | 1 963 | scriptfile 964 | ./scripts/pass-cli-search.js 965 | subtext 966 | Loading... 967 | title 968 | Search Passwords in Pass 969 | type 970 | 8 971 | withspace 972 | 973 | 974 | type 975 | alfred.workflow.input.scriptfilter 976 | uid 977 | 24B77922-B082-4744-B4A1-6EAD37FFD88C 978 | version 979 | 3 980 | 981 | 982 | config 983 | 984 | argument 985 | {query} 986 | passthroughargument 987 | 988 | variables 989 | 990 | new 991 | new 992 | 993 | 994 | type 995 | alfred.workflow.utility.argument 996 | uid 997 | 2862B2B6-1294-4469-AFBF-558B7D805B7E 998 | version 999 | 1 1000 | 1001 | 1002 | config 1003 | 1004 | concurrently 1005 | 1006 | escaping 1007 | 0 1008 | script 1009 | 1010 | scriptargtype 1011 | 1 1012 | scriptfile 1013 | ./scripts/auto-push.sh 1014 | type 1015 | 8 1016 | 1017 | type 1018 | alfred.workflow.action.script 1019 | uid 1020 | 0BC9A821-35ED-45C1-AA5A-A64A696BBFC8 1021 | version 1022 | 2 1023 | 1024 | 1025 | config 1026 | 1027 | concurrently 1028 | 1029 | escaping 1030 | 0 1031 | script 1032 | 1033 | scriptargtype 1034 | 1 1035 | scriptfile 1036 | scripts/update-pw.sh 1037 | type 1038 | 8 1039 | 1040 | type 1041 | alfred.workflow.action.script 1042 | uid 1043 | E0554F56-4E6E-435D-9F25-4A4E089BE7F0 1044 | version 1045 | 2 1046 | 1047 | 1048 | config 1049 | 1050 | lastpathcomponent 1051 | 1052 | onlyshowifquerypopulated 1053 | 1054 | removeextension 1055 | 1056 | text 1057 | {var:entry} 1058 | title 1059 | ✅ Password updated for 1060 | 1061 | type 1062 | alfred.workflow.output.notification 1063 | uid 1064 | 6DEB3631-BC94-4826-A0A0-09A177B749C3 1065 | version 1066 | 1 1067 | 1068 | 1069 | config 1070 | 1071 | lastpathcomponent 1072 | 1073 | onlyshowifquerypopulated 1074 | 1075 | removeextension 1076 | 1077 | text 1078 | {var:entry} 1079 | title 1080 | ✅ Entry deleted 1081 | 1082 | type 1083 | alfred.workflow.output.notification 1084 | uid 1085 | A5733344-CBEB-486B-87D4-DE52472EB5A5 1086 | version 1087 | 1 1088 | 1089 | 1090 | config 1091 | 1092 | concurrently 1093 | 1094 | escaping 1095 | 0 1096 | script 1097 | 1098 | scriptargtype 1099 | 1 1100 | scriptfile 1101 | scripts/delete-pw.sh 1102 | type 1103 | 8 1104 | 1105 | type 1106 | alfred.workflow.action.script 1107 | uid 1108 | 6B581416-D12E-4AC2-B604-895443940F98 1109 | version 1110 | 2 1111 | 1112 | 1113 | config 1114 | 1115 | autopaste 1116 | 1117 | clipboardtext 1118 | {query} 1119 | ignoredynamicplaceholders 1120 | 1121 | transient 1122 | 1123 | 1124 | type 1125 | alfred.workflow.output.clipboard 1126 | uid 1127 | 97B7CC9A-ED41-492D-A2F4-2D905A5EAE0C 1128 | version 1129 | 3 1130 | 1131 | 1132 | config 1133 | 1134 | lastpathcomponent 1135 | 1136 | onlyshowifquerypopulated 1137 | 1138 | removeextension 1139 | 1140 | text 1141 | {query} 1142 | title 1143 | 📋 Copied 1144 | 1145 | type 1146 | alfred.workflow.output.notification 1147 | uid 1148 | 3FADF261-E630-4B7D-A39C-32D20770CF51 1149 | version 1150 | 1 1151 | 1152 | 1153 | config 1154 | 1155 | alfredfiltersresults 1156 | 1157 | alfredfiltersresultsmatchmode 1158 | 0 1159 | argumenttreatemptyqueryasnil 1160 | 1161 | argumenttrimmode 1162 | 0 1163 | argumenttype 1164 | 1 1165 | escaping 1166 | 102 1167 | queuedelaycustom 1168 | 3 1169 | queuedelayimmediatelyinitially 1170 | 1171 | queuedelaymode 1172 | 0 1173 | queuemode 1174 | 1 1175 | runningsubtext 1176 | 1177 | script 1178 | 1179 | scriptargtype 1180 | 1 1181 | scriptfile 1182 | ./scripts/show-properties.js 1183 | subtext 1184 | 1185 | title 1186 | Show other entry fields… 1187 | type 1188 | 8 1189 | withspace 1190 | 1191 | 1192 | type 1193 | alfred.workflow.input.scriptfilter 1194 | uid 1195 | B23E7DD4-F41F-4969-83C0-A44AD034C37F 1196 | version 1197 | 3 1198 | 1199 | 1200 | config 1201 | 1202 | browser 1203 | 1204 | skipqueryencode 1205 | 1206 | skipvarencode 1207 | 1208 | spaces 1209 | 1210 | url 1211 | 1212 | 1213 | type 1214 | alfred.workflow.action.openurl 1215 | uid 1216 | 8B196ABE-DF0D-4D44-BB9B-CB731B0CC995 1217 | version 1218 | 1 1219 | 1220 | 1221 | config 1222 | 1223 | path 1224 | 1225 | 1226 | type 1227 | alfred.workflow.action.revealfile 1228 | uid 1229 | E28BAD26-7C03-414A-A567-4F44432F9FD7 1230 | version 1231 | 1 1232 | 1233 | 1234 | config 1235 | 1236 | escaping 1237 | 0 1238 | script 1239 | pass edit "{query}" && sleep 0.5 && pass git push 1240 | 1241 | type 1242 | alfred.workflow.action.terminalcommand 1243 | uid 1244 | F46688E5-F719-4EE2-89C5-FB26A5D6977F 1245 | version 1246 | 1 1247 | 1248 | 1249 | config 1250 | 1251 | conditions 1252 | 1253 | 1254 | inputstring 1255 | {var:auto_push} 1256 | matchcasesensitive 1257 | 1258 | matchmode 1259 | 0 1260 | matchstring 1261 | 1 1262 | outputlabel 1263 | yes 1264 | uid 1265 | BCD3864F-3522-4AF9-893A-21B8EBB5B4C6 1266 | 1267 | 1268 | elselabel 1269 | no 1270 | hideelse 1271 | 1272 | 1273 | type 1274 | alfred.workflow.utility.conditional 1275 | uid 1276 | F19DCDE8-CB71-48BC-AFD8-EB381C71E346 1277 | version 1278 | 1 1279 | 1280 | 1281 | config 1282 | 1283 | escaping 1284 | 0 1285 | script 1286 | pass edit "{query}" 1287 | 1288 | type 1289 | alfred.workflow.action.terminalcommand 1290 | uid 1291 | 7C6B7643-4B16-4307-ADA8-14D6837FEE59 1292 | version 1293 | 1 1294 | 1295 | 1296 | readme 1297 | # Alfred Client for the Pass-CLI 1298 | ## Setup 1299 | 1. Install the requirements: `brew install pass pinentry-mac`. 1300 | 2. Setup `pass` with an GPG key. See the [pass website](https://www.passwordstore.org/) for further information. 1301 | 3. Setup `pinentry-mac` as your `pinentry-program`: 1302 | 1303 | ```bash 1304 | [[ -d "$HOME/.gnupg" ]] || mkdir "$HOME/.gnupg" 1305 | echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" > $HOME/.gnupg/gpg-agent.conf 1306 | gpgconf --kill gpg-agent # restart the agent 1307 | ``` 1308 | 1309 | ## Configuration 1310 | This workflow is reads all your `PASSWORD_STORE_*` environment variables that 1311 | have been added to your `~/.zshenv`, so most configuration is done by exporting 1312 | respective variables in `~/.zshenv`. Example: `export 1313 | PASSWORD_STORE_GENERATED_LENGTH=32`. 1314 | 1315 | For information about the available environment variables, see the [pass man 1316 | page](https://git.zx2c4.com/password-store/about/). 1317 | 1318 | > If you are using a custom password-store directory, you **must** export your 1319 | > `PASSWORD_STORE_DIR` in your `~/.zshenv` for this workflow to work. 1320 | 1321 | ## Usage 1322 | - Search your passwords via the keyword `pw`. 1323 | + <kbd>⏎</kbd>: Copy password to the clipboard. 1324 | + <kbd>⌘</kbd><kbd>⏎</kbd>: Edit entry in your Terminal, using [the Terminal 1325 | configured in your Alfred 1326 | settings](https://www.alfredapp.com/help/features/terminal/) and your 1327 | `$EDITOR`. 1328 | + <kbd>⌥</kbd><kbd>⏎</kbd>: Reveal `.gpg` file of the entry in Finder. 1329 | + <kbd>⌃</kbd><kbd>⏎</kbd>: Delete the entry. (⚠️ This is irreversible if you 1330 | are not using git.) 1331 | + <kbd>⇧</kbd><kbd>⏎</kbd>: Show details of the entry. Select one of them 1332 | to copy the value to your clipboard. 1333 | + <kbd>Fn</kbd><kbd>⏎</kbd>: Generate a new password and overwrite this 1334 | entry's password with it. Afterward, copy the new password. (⚠️ This removes 1335 | the old password and is not reversible if you are not using git.) 1336 | - Use the keyword `pw new` to create a new entry. You are then prompted for a 1337 | folder to place the new entry in. The password of the new entry is 1338 | auto-generated based on your `pass` settings, or can be inserted from your 1339 | clipboard. 1340 | - Use `pw gen` to generate a new password without creating a new entry. 1341 | 1342 | 1343 | 1344 | ## Credits 1345 | Created by [Chris Grieser](https://chris-grieser.de/). 1346 | uidata 1347 | 1348 | 09192EC9-2C76-4174-868D-22699F041C5D 1349 | 1350 | colorindex 1351 | 5 1352 | xpos 1353 | 865 1354 | ypos 1355 | 130 1356 | 1357 | 0BC9A821-35ED-45C1-AA5A-A64A696BBFC8 1358 | 1359 | colorindex 1360 | 10 1361 | note 1362 | auto-push 1363 | xpos 1364 | 1110 1365 | ypos 1366 | 430 1367 | 1368 | 0F6DB773-7447-4D7C-900E-59F3E9C69B19 1369 | 1370 | colorindex 1371 | 5 1372 | note 1373 | generate 1374 | xpos 1375 | 585 1376 | ypos 1377 | 15 1378 | 1379 | 1C410C15-19B5-445B-B5B9-A406076C5E6D 1380 | 1381 | colorindex 1382 | 2 1383 | note 1384 | set entry name to "Generated" 1385 | xpos 1386 | 365 1387 | ypos 1388 | 180 1389 | 1390 | 1E6D758F-172E-4E35-AD9C-3226C9D252C3 1391 | 1392 | colorindex 1393 | 1 1394 | note 1395 | copy as transient 1396 | (= avoids clipboard history) 1397 | xpos 1398 | 1190 1399 | ypos 1400 | 230 1401 | 1402 | 24B77922-B082-4744-B4A1-6EAD37FFD88C 1403 | 1404 | colorindex 1405 | 7 1406 | note 1407 | search passwords 1408 | xpos 1409 | 35 1410 | ypos 1411 | 350 1412 | 1413 | 2862B2B6-1294-4469-AFBF-558B7D805B7E 1414 | 1415 | colorindex 1416 | 7 1417 | note 1418 | set "new" var (display purposes only) 1419 | xpos 1420 | 765 1421 | ypos 1422 | 390 1423 | 1424 | 2C2A79DD-A7C9-47A9-8AA4-0EEACB92D441 1425 | 1426 | colorindex 1427 | 2 1428 | xpos 1429 | 30 1430 | ypos 1431 | 150 1432 | 1433 | 2F29A336-1599-4915-8D23-5C4FB4D51D19 1434 | 1435 | colorindex 1436 | 5 1437 | xpos 1438 | 865 1439 | ypos 1440 | 15 1441 | 1442 | 3B6DB61F-2CEA-4A7D-A907-2740E8C4FCD6 1443 | 1444 | colorindex 1445 | 1 1446 | xpos 1447 | 1335 1448 | ypos 1449 | 230 1450 | 1451 | 3FADF261-E630-4B7D-A39C-32D20770CF51 1452 | 1453 | colorindex 1454 | 7 1455 | xpos 1456 | 720 1457 | ypos 1458 | 685 1459 | 1460 | 462A9DED-FC24-4D19-8ED2-C2D7162239B2 1461 | 1462 | colorindex 1463 | 5 1464 | note 1465 | if password is generated 1466 | xpos 1467 | 1050 1468 | ypos 1469 | 160 1470 | 1471 | 5654C2AF-88C2-4D89-A2E4-D26F2B3DEF0B 1472 | 1473 | colorindex 1474 | 5 1475 | note 1476 | password 1477 | xpos 1478 | 730 1479 | ypos 1480 | 35 1481 | 1482 | 6B581416-D12E-4AC2-B604-895443940F98 1483 | 1484 | colorindex 1485 | 7 1486 | note 1487 | delete pw 1488 | xpos 1489 | 365 1490 | ypos 1491 | 560 1492 | 1493 | 6DEB3631-BC94-4826-A0A0-09A177B749C3 1494 | 1495 | colorindex 1496 | 7 1497 | xpos 1498 | 570 1499 | ypos 1500 | 430 1501 | 1502 | 7C6B7643-4B16-4307-ADA8-14D6837FEE59 1503 | 1504 | colorindex 1505 | 7 1506 | note 1507 | edit 1508 | xpos 1509 | 570 1510 | ypos 1511 | 1070 1512 | 1513 | 83941436-919A-42A2-BCCA-4EB78802E09E 1514 | 1515 | colorindex 1516 | 5 1517 | xpos 1518 | 495 1519 | ypos 1520 | 20 1521 | 1522 | 8B196ABE-DF0D-4D44-BB9B-CB731B0CC995 1523 | 1524 | colorindex 1525 | 7 1526 | xpos 1527 | 570 1528 | ypos 1529 | 800 1530 | 1531 | 8DFAB981-4135-40F5-BA81-DEDA35D0F632 1532 | 1533 | colorindex 1534 | 1 1535 | note 1536 | delayed clearing of the clipboard 1537 | xpos 1538 | 1480 1539 | ypos 1540 | 230 1541 | 1542 | 92E44739-4524-4ADF-8D4B-C4FCE41A4D5F 1543 | 1544 | colorindex 1545 | 7 1546 | note 1547 | copy pw 1548 | xpos 1549 | 365 1550 | ypos 1551 | 290 1552 | 1553 | 97B7CC9A-ED41-492D-A2F4-2D905A5EAE0C 1554 | 1555 | colorindex 1556 | 7 1557 | xpos 1558 | 570 1559 | ypos 1560 | 685 1561 | 1562 | A5733344-CBEB-486B-87D4-DE52472EB5A5 1563 | 1564 | colorindex 1565 | 7 1566 | xpos 1567 | 570 1568 | ypos 1569 | 560 1570 | 1571 | A5A50E6D-235D-44F3-ACFA-B80578EA0558 1572 | 1573 | colorindex 1574 | 5 1575 | note 1576 | set entry & auto-generation choice 1577 | xpos 1578 | 495 1579 | ypos 1580 | 80 1581 | 1582 | ABCD927B-BC30-42C8-865D-98D4D4CF4F59 1583 | 1584 | colorindex 1585 | 5 1586 | xpos 1587 | 330 1588 | ypos 1589 | 15 1590 | 1591 | AC64DCEB-7AA1-422C-A8F9-81E1A91381E9 1592 | 1593 | colorindex 1594 | 2 1595 | xpos 1596 | 180 1597 | ypos 1598 | 150 1599 | 1600 | B23E7DD4-F41F-4969-83C0-A44AD034C37F 1601 | 1602 | colorindex 1603 | 7 1604 | note 1605 | select property 1606 | xpos 1607 | 365 1608 | ypos 1609 | 735 1610 | 1611 | CA9D5F1A-6D6F-43AE-93FA-A482699EEA31 1612 | 1613 | colorindex 1614 | 5 1615 | xpos 1616 | 30 1617 | ypos 1618 | 15 1619 | 1620 | D1151344-66AB-453F-8468-097748113645 1621 | 1622 | colorindex 1623 | 1 1624 | xpos 1625 | 1625 1626 | ypos 1627 | 230 1628 | 1629 | D2367F46-8E60-4205-A0EA-E66B7F3ADF69 1630 | 1631 | colorindex 1632 | 1 1633 | note 1634 | remove \n 1635 | xpos 1636 | 1115 1637 | ypos 1638 | 260 1639 | 1640 | E0554F56-4E6E-435D-9F25-4A4E089BE7F0 1641 | 1642 | colorindex 1643 | 7 1644 | note 1645 | update & copy pw 1646 | xpos 1647 | 365 1648 | ypos 1649 | 430 1650 | 1651 | E28BAD26-7C03-414A-A567-4F44432F9FD7 1652 | 1653 | colorindex 1654 | 7 1655 | xpos 1656 | 365 1657 | ypos 1658 | 875 1659 | 1660 | F19DCDE8-CB71-48BC-AFD8-EB381C71E346 1661 | 1662 | colorindex 1663 | 7 1664 | note 1665 | auto-push 1666 | xpos 1667 | 406 1668 | ypos 1669 | 1025 1670 | 1671 | F46688E5-F719-4EE2-89C5-FB26A5D6977F 1672 | 1673 | colorindex 1674 | 7 1675 | note 1676 | edit & push 1677 | xpos 1678 | 570 1679 | ypos 1680 | 935 1681 | 1682 | FEBD93EE-FAF9-4E4E-8627-84BEC380B964 1683 | 1684 | colorindex 1685 | 5 1686 | xpos 1687 | 180 1688 | ypos 1689 | 15 1690 | 1691 | 1692 | userconfigurationconfig 1693 | 1694 | 1695 | config 1696 | 1697 | default 1698 | 1699 | required 1700 | 1701 | text 1702 | Run `pass git push` after any changes. 1703 | 1704 | description 1705 | 1706 | label 1707 | Auto-Push 1708 | type 1709 | checkbox 1710 | variable 1711 | auto_push 1712 | 1713 | 1714 | version 1715 | 3.1.2 1716 | webaddress 1717 | https://chris-grieser.de/ 1718 | 1719 | 1720 | -------------------------------------------------------------------------------- /scripts/auto-push.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # shellcheck disable=2154 4 | [[ "$auto_push" == "1" ]] && pass git push 5 | -------------------------------------------------------------------------------- /scripts/clear-clipboard.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # INFO password clearing is implemented via this script rather than using pass' 3 | # built-in functionality because the built-in functionality requires using `pass 4 | # --clip` which saves the password a non-transiently, meaning it is readable in 5 | # Alfred's clipboard history. Not using `pass --clip` however means that the 6 | # automatic password clearance after after PASSWORD_STORE_CLIP_TIME seconds does 7 | # not take place and therefore needs to be implemented manually here. 8 | 9 | #─────────────────────────────────────────────────────────────────────────────── 10 | 11 | password="$*" 12 | 13 | delay=${PASSWORD_STORE_CLIP_TIME-45} # read from .zshenv, default value 45s 14 | sleep "$delay" 15 | 16 | # clear the clipboard only if it is currently in the clipboard, to not override 17 | # other clipboard content 18 | if [[ "$password" == "$(pbpaste)" ]]; then 19 | pbcopy < /dev/null 20 | echo -n "cleared" # triggers Alfred notification 21 | fi 22 | -------------------------------------------------------------------------------- /scripts/copy-pw.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # not using `echo -n` due to #2 4 | entry="$*" 5 | pass show "$entry" | head -n1 6 | -------------------------------------------------------------------------------- /scripts/delete-pw.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | entry="$*" 4 | pass delete "$entry" &>/dev/null 5 | -------------------------------------------------------------------------------- /scripts/generate-random-password.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 8 | function run() { 9 | // CONFIG 10 | const pwCharacters = "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 11 | const pwLength = 12 | Number.parseInt(app.doShellScript("exec zsh -c 'echo \"$PASSWORD_STORE_GENERATED_LENGTH\"'")) || 13 | 25; 14 | 15 | let newPassword = ""; 16 | for (let i = 0; i < pwLength; i++) { 17 | newPassword += pwCharacters.charAt(Math.floor(Math.random() * pwCharacters.length)); 18 | } 19 | 20 | return newPassword; 21 | } 22 | -------------------------------------------------------------------------------- /scripts/pass-cli-search.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @param {string} str */ 8 | function camelCaseMatch(str) { 9 | const subwords = str.replace(/[-_./]/g, " "); 10 | const fullword = str.replace(/[-_./]/g, ""); 11 | const camelCaseSeparated = str.replace(/([A-Z])/g, " $1"); 12 | return [subwords, camelCaseSeparated, fullword, str].join(" ") + " "; 13 | } 14 | 15 | //────────────────────────────────────────────────────────────────────────────── 16 | 17 | /** @type {AlfredRun} */ 18 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 19 | function run() { 20 | const passwordStore = 21 | // executing `zsh` instead of sourcing because https://github.com/chrisgrieser/alfred-pass/issues/4 22 | app.doShellScript("exec zsh -c 'echo \"$PASSWORD_STORE_DIR\"'") || 23 | app.pathTo("home folder") + "/.password-store"; 24 | 25 | // GUARD 26 | if (!Application("Finder").exists(Path(passwordStore))) { 27 | return JSON.stringify({ 28 | items: { title: "⚠️ Password store not found.", subtitle: passwordStore, valid: false }, 29 | }); 30 | } 31 | 32 | /** @type{AlfredItem[]} */ 33 | const passwords = app 34 | .doShellScript(`cd "${passwordStore}" ; find . -type f -name "*.gpg" -not -path "./.git*"`) 35 | .split("\r") 36 | .map((gpgFile) => { 37 | const id = gpgFile.slice(2, -4); 38 | const pathParts = id.split("/"); 39 | const name = pathParts.pop() || "ERROR"; 40 | const group = pathParts.join("/"); 41 | const path = `${passwordStore}/${gpgFile}`; 42 | const matcher = camelCaseMatch(name) + camelCaseMatch(group); 43 | 44 | return { 45 | title: name, 46 | subtitle: group, 47 | arg: id, 48 | uid: id, 49 | match: matcher, 50 | variables: { entry: id }, 51 | mods: { 52 | alt: { arg: path }, // revealing in Finder needs path 53 | shift: { arg: "" }, // keep next Alfred prompt clear 54 | }, 55 | }; 56 | }); 57 | 58 | return JSON.stringify({ items: passwords }); 59 | } 60 | -------------------------------------------------------------------------------- /scripts/pw-generate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # shellcheck disable=2154 3 | 4 | # remove illegal characters 5 | entry_name=$(echo "$*" | tr -d ":/\\") 6 | entry="$folder/$entry_name" 7 | 8 | # GUARD password file already exists 9 | dir=${PASSWORD_STORE_DIR-$HOME/.password-store} 10 | if [[ -f "$dir/$entry.gpg" ]]; then 11 | echo -n "ALREADY EXISTS" 12 | exit 1 13 | fi 14 | 15 | #─────────────────────────────────────────────────────────────────────────────── 16 | 17 | if [[ "$generatePassword" == "true" ]]; then 18 | pass generate "$entry" &> /dev/null 19 | 20 | # pass to Alfred for copying (not using `echo -n` due to #2) 21 | pass show "$entry" | head -n1 22 | 23 | elif [[ "$generatePassword" == "false" ]]; then 24 | # create new password (`--echo` needed to skip confirmation) 25 | pbpaste | pass insert --echo "$entry" &> /dev/null 26 | 27 | # indicate to Alfred that password was inserted 28 | echo -n "INSERTED" 29 | fi 30 | -------------------------------------------------------------------------------- /scripts/select-folder-for-new-pw.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @type {AlfredRun} */ 8 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 9 | function run() { 10 | const passwordStore = 11 | // executing `zsh` instead of sourcing because https://github.com/chrisgrieser/alfred-pass/issues/4 12 | app.doShellScript("exec zsh -c 'echo \"$PASSWORD_STORE_DIR\"'") || 13 | app.pathTo("home folder") + "/.password-store"; 14 | 15 | /** @type{AlfredItem[]} */ 16 | const passwordFolders = []; 17 | 18 | const shellCmd = `cd "${passwordStore}" ; find . -type d -mindepth 1 -not -path "./.git*"`; 19 | const stdout = app.doShellScript(shellCmd); 20 | const userHasFolders = stdout.trim() !== ""; 21 | if (userHasFolders) { 22 | stdout.split("\r").map((/** @type {string} */ folder) => { 23 | folder = folder.slice(2); // remove `./` 24 | passwordFolders.push({ 25 | title: "📂 " + folder, 26 | uid: folder, // remember user choice for next time 27 | arg: "", // empty for next Alfred prompt 28 | variables: { folder: folder }, 29 | }); 30 | }); 31 | } 32 | 33 | // add root at the bottom of the list 34 | passwordFolders.push({ 35 | title: "📂 * root", 36 | arg: "", 37 | uid: ".", 38 | variables: { folder: "." }, 39 | }); 40 | 41 | return JSON.stringify({ items: passwordFolders }); 42 | } 43 | -------------------------------------------------------------------------------- /scripts/show-properties.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env osascript -l JavaScript 2 | ObjC.import("stdlib"); 3 | const app = Application.currentApplication(); 4 | app.includeStandardAdditions = true; 5 | //────────────────────────────────────────────────────────────────────────────── 6 | 7 | /** @type {AlfredRun} */ 8 | // biome-ignore lint/correctness/noUnusedVariables: Alfred run 9 | function run() { 10 | const entryId = $.getenv("entry"); 11 | 12 | /** @type{AlfredItem[]} */ 13 | const properties = app 14 | .doShellScript(`exec zsh -c 'pass show "${entryId}"'`) 15 | .split("\r") 16 | .slice(1) // first entry is password which can can already be accessed directly 17 | .filter((line) => line.trim() !== "") 18 | .map((property) => { 19 | const valid = property.includes(":"); 20 | const key = valid ? property.split(":")[0].trim() : ""; 21 | const value = valid 22 | ? property.slice(property.indexOf(":") + 1).trim() 23 | : property.toUpperCase(); 24 | const isUrl = 25 | key.toLowerCase() === "url" || 26 | key.toLowerCase() === "website" || 27 | Boolean(value.match(/^https?:\/\//)); 28 | 29 | return { 30 | title: value, 31 | match: property, 32 | subtitle: isUrl ? key + " (⌘: Open URL in Browser)" : key, 33 | arg: value, 34 | valid: valid, 35 | mods: { 36 | cmd: { 37 | valid: isUrl, 38 | subtitle: isUrl ? "⌘: Open URL in Browser" : "⌘: 🚫 Not a URL", 39 | }, 40 | }, 41 | }; 42 | }); 43 | 44 | return JSON.stringify({ items: properties }); 45 | } 46 | -------------------------------------------------------------------------------- /scripts/update-pw.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | entry="$*" 4 | pass generate --in-place "$entry" > /dev/null 5 | pass show "$entry" | head -n1 6 | --------------------------------------------------------------------------------