Skip to content
Open
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ This plugin relies on the following:
In any tmux mode:

- `prefix + u` - list login items in a bottom pane.
- `prefix + C` - clear the cache of tmux-1password.

## Install

Expand Down Expand Up @@ -77,8 +78,9 @@ sessions expires automatically after 30 minutes of inactivity.
### Configuring login items in 1Password

In order to show only relevant login items and to maintain compatibility with
[sudolikeaboss](https://github.com/ravenac95/sudolikeaboss), its required to set the value of the
`website` field for each login item with the value of `sudolikeaboss://local`.
[sudolikeaboss](https://github.com/ravenac95/sudolikeaboss), by default it is required to set the value of the
`website` field for each login item with the value of `sudolikeaboss://local`. To override this behavior and provide
customized filtering, see configuration options `@1password-enabled-url-filter` and `@1password-items-jq-filter` below.

## Configuration

Expand Down Expand Up @@ -121,6 +123,60 @@ set -g @1password-copy-to-clipboard 'on'

Default: `'off'`

#### Enabled URL Filter

By default, the plugin maintains compatibility with [sudolikeaboss](https://github.com/ravenac95/sudolikeaboss) by
filtering urls using the string "sudolikeaboss://local", by setting the following, the list of items will no longer be
filtered.

```
set -g @1password-enabled-url-filter 'off'
```

Default: `'on'`

#### Customize URL Filtering

If complete customization of url filtering is required, a `jq` filter can be provided to filter and map
items.

##### Filtering by tags

```
set -g @1password-items-jq-filter '.[] | [select(.overview.tags | map(select(. == "tag_name")) | length == 1)?] | map([ .overview.title, .uuid ] | join(",")) | .[]'
```

##### Filtering by custom url

```
set -g @1password-items-jq-filter '.[] | [select(.overview.URLs | map(select(.u == "myspecial-url-filter")) | length == 1)?] | map([ .overview.title, .uuid ] | join(",")) | .[]'
```

Default: `''`

Items come in the following format from which the filter operates:

```
[
{
"uuid": "some-long-uuid",
"overview": {
"URLs": [
{ "u": "sudolikeaboss://local" }
],
"title": "Some item",
"tags": ["tag_name"]
}
}
]
```

## Security

This plugin is based on using `op list-items` to get a filtered list of passwords from your vault, and them asking for the password you want with `op get-item`. To improve the performance, we've added a cache file which has a TTL of 30 minutes and stores a simple list containing your account names and the related IDs.

**No password is stored on the disk,** just a simple pointer to be used in the future when you ask to fetch a specific password.

## Prior art

Also see:
Expand Down
3 changes: 3 additions & 0 deletions plugin.tmux
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ main() {
done

local -r opt_key="$(get_tmux_option "@1password-key" "u")"
local -r clear_key="$(get_tmux_option "@1password-key" "C")"

tmux bind-key "$opt_key" \
run "tmux split-window -l 10 \"$CURRENT_DIR/scripts/main.sh '#{pane_id}'\""

tmux bind-key "$clear_key" run "$CURRENT_DIR/scripts/main.sh clear-cache"
}

main "$@"
80 changes: 71 additions & 9 deletions scripts/main.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ source "./spinner.sh"

# ------------------------------------------------------------------------------

declare -r TMP_TOKEN_FILE="$HOME/.op_tmux_token_tmp"
declare -r TMP_TOKEN_FILE="/tmp/tmux-op-token"
declare -r CACHE_FILE="/tmp/tmux-op-items"
declare -r CACHE_TTL=1800 # 30 minutes, since we cannot fetch passwords with invalid session token

declare -r OPT_SUBDOMAIN="$(get_tmux_option "@1password-subdomain" "my")"
declare -r OPT_VAULT="$(get_tmux_option "@1password-vault" "")"
declare -r OPT_COPY_TO_CLIPBOARD="$(get_tmux_option "@1password-copy-to-clipboard" "off")"
declare -r OPT_ENABLED_URL_FILTER="$(get_tmux_option "@1password-enabled-url-filter" "on")"
declare -r OPT_ITEMS_JQ_FILTER="$(get_tmux_option "@1password-items-jq-filter" "")"

declare spinner_pid=""

Expand Down Expand Up @@ -44,7 +48,29 @@ op_get_session() {
}

get_op_items() {
clear_old_cache

if [[ -e $CACHE_FILE ]]; then
echo "$(cat $CACHE_FILE)"
else
fetch_items
fi
}

clear_old_cache() {
if [[ -e $CACHE_FILE ]]; then
local last_update="$(stat -c %Y $CACHE_FILE)"
local now="$(date +%s)"
local seconds_since_last_update="$(($now-$last_update))"

# Remove cache file if last cache was from 30 minutes ago
if [[ $seconds_since_last_update < $CACHE_TTL ]]; then
rm $CACHE_FILE
fi
fi
}

fetch_items() {
# The structure (we need) looks like the following:
# [
# {
Expand All @@ -58,18 +84,38 @@ get_op_items() {
# }
# ]

local -r JQ_FILTER="
.[]
| [select(.overview.URLs | map(select(.u == \"sudolikeaboss://local\")) | length == 1)?]
| map([ .overview.title, .uuid ]
| join(\",\"))
| .[]
"
if [ -n "$OPT_ITEMS_JQ_FILTER" ]; then
local -r JQ_FILTER="$OPT_ITEMS_JQ_FILTER"
elif [ "$OPT_ENABLED_URL_FILTER" == "on" ]; then
local -r JQ_FILTER="
.[]
| [select(.overview.URLs | map(select(.u == \"sudolikeaboss://local\")) | length == 1)?]
| map([ .overview.title, .uuid ]
| join(\",\"))
| .[]
"
else
local -r JQ_FILTER="
.[]
| [select(.overview.URLs | map(select(.u)) | length == 1)?]
| map([ .overview.title, .uuid ]
| join(\",\"))
| .[]
"
fi

op list items --vault="$OPT_VAULT" --session="$(op_get_session)" 2> /dev/null \
| jq "$JQ_FILTER" --raw-output
}

cache_items() {
local items=$1

if ! [[ -e $CACHE_FILE ]]; then
echo "$items" > $CACHE_FILE
fi
}

get_op_item_password() {
local -r ITEM_UUID="$1"

Expand Down Expand Up @@ -113,6 +159,22 @@ get_op_item_password() {
# ------------------------------------------------------------------------------

main() {
local -r command=$@

if [[ $command == "clear-cache" ]]; then
clear_cache
else
prompt_op $@
fi
}

clear_cache() {
rm $CACHE_FILE

display_message "Cache cleared"
}

prompt_op() {
local -r ACTIVE_PANE="$1"

local items
Expand All @@ -139,6 +201,7 @@ main() {
spinner_stop
fi

cache_items "$items"
selected_item_name="$(echo "$items" | awk -F ',' '{ print $1 }' | fzf --no-multi)"

if [[ -n "$selected_item_name" ]]; then
Expand All @@ -156,7 +219,6 @@ main() {
# Clear clipboard
clear_clipboard 30
else

# Use `send-keys`
tmux send-keys -t "$ACTIVE_PANE" "$selected_item_password"
fi
Expand Down