Skip to content

Commit

Permalink
Add masked commands to history
Browse files Browse the repository at this point in the history
Respect variable references when deciding whether to add to history
  • Loading branch information
jgogstad committed Jun 19, 2021
1 parent 509b261 commit 070e441
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 19 deletions.
71 changes: 57 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,38 @@
# Passwordless ZSH history

Keep passwords out of your ZSH history
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

ZSH will let you recover the previous command from history immediately after it has been run. After that it will not be added to history if it matches `HISTORY_EXCLUDE_PATTERN`

- [Installation](#installation)
- [Customization](#customization)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

This ZSH plugin masks secrets in your ZSH history

Example:

```bash
❯ curl -H 'Authorization: Bearer eyJhbGciOiJIUzUxMiIsInR5c' https://example.com
❯ curl -u foo:bar https://example.com
❯ curl https://foo:[email protected]
❯ AWS_SECRET_ACCESS_KEY=key aws s3 ls s3://example
export DB_PASSWORD=foo
history | tail
1 curl -H 'Authorization: ...' https://example.com > /dev/null
2 curl -u ... https://example.com > /dev/null
3 curl https://[email protected] > /dev/null
4 AWS_SECRET_ACCESS_KEY=... aws s3 ls s3://example
5 export DB_PASSWORD=...
```

ZSH will let you recover the previous command with secrets immediately after execution:

```bash
> curl http://username:[email protected]/foo
> # <up-arrow> recovers command with password
> # curl command is not available in history here
> # <up-arrow> recovers command with password immediately after execution
> # <up-arrow> recovers masked command here
```

To exclude _any_ command from history, prefix with a space. It behaves the same as above:
Expand All @@ -17,41 +42,59 @@ To exclude _any_ command from history, prefix with a space. It behaves the same
> # Not available here
```

Control what secrets are catched by setting the environment variable `HISTORY_EXCLUDE_PATTERN`. If the pattern includes a single group, that group is substituted with `...`. The default `HISTORY_EXCLUDE_PATTERN` is

```bash
echo $HISTORY_EXCLUDE_PATTERN
^ |//([^/]+:[^/]+)@|KEY=([^ ]+)|TOKEN=([^ ]+)|BEARER=([^ ]+)|PASSWORD=([^ ]+)|Authorization: *([^'\"]+)|-us?e?r? ([^:]+:[^:]+)
```
## Installation
**Antibody**
Using **Plain zsh**
Download [passwordless-history.plugin.zsh](passwordless-history.plugin.zsh), then add to `.zshrc`
```
antibody bundle jgogstad/passwordless-history
source /path/to/passwordless-history.plugin.zsh
```
**Antigen**
Using [**Antibody**](https://getantibody.github.io)
```
antigen bundle jgogstad/passwordless-history
antibody bundle jgogstad/passwordless-history
```
**Plain zsh**
Using [**ZInit**](https://github.com/zdharma/zinit)
Add to `.zshrc`
Add the following to `.zshrc`
```bash
zinit light jgogstad/passwordless-history
```
. /path/to/passwordless-history.plugin.zsh
Using [**ZPlug**](https://github.com/zplug/zplug)
Add the following to `.zshrc`
```bash
zplug 'jgogstad/passwordless-history'
```
## Customization
Default exclusion pattern is
```bash
> echo $HISTORY_EXCLUDE_PATTERN
^ |password|//[^/]+:[^/]+@|(KEY|TOKEN|SECRET)=|Authorization:
echo $HISTORY_EXCLUDE_PATTERN
^ |//([^/]+:[^/]+)@|KEY=([^ ]+)|TOKEN=([^ ]+)|BEARER=([^ ]+)|PASSWORD=([^ ]+)|Authorization: *([^'\"]+)|-us?e?r? ([^:]+:[^:]+)
```

Overwrite variable to customize

```bash
> export HISTORY_EXCLUDE_PATTERN="^ykchalresp|$HISTORY_EXCLUDE_PATTERN"
export HISTORY_EXCLUDE_PATTERN="^ykchalresp|$HISTORY_EXCLUDE_PATTERN"
```

The pattern is a regex and it's evaluated with zsh's `=~` operator using case insensitive evaluation.
28 changes: 23 additions & 5 deletions passwordless-history.plugin.zsh
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
# ZSH
#!/bin/env zsh

HISTORY_EXCLUDE_PATTERN='^ |password|//[^/]+:[^/]+@|(KEY|TOKEN|SECRET)=|Authorization: *[^ \$]'
HISTORY_EXCLUDE_PATTERN='^ |//([^/]+:[^/]+)@|KEY=([^ ]+)|TOKEN=([^ ]+)|BEARER=([^ ]+)|PASSWORD=([^ ]+)|Authorization: *([^'"'"'\"]+)|-us?e?r? ([^:]+:[^:]+) '

# See
# - https://zsh.sourceforge.io/Doc/Release/Functions.html for docs on zshaddhistory
# - https://zsh.sourceforge.io/Doc/Release/Shell-Builtin-Commands.html for docs on print
function zshaddhistory() {
emulate -L zsh
unsetopt case_match
if ! [[ "$1" =~ $HISTORY_EXCLUDE_PATTERN ]] ; then
print -Sr -- "${1%%$'\n'}"

input="${1%%$'\n'}"
[[ "$input" =~ "$HISTORY_EXCLUDE_PATTERN" ]]

if [[ -z "$MATCH" ]]; then
print -Sr -- "$input"
else
return 1
nonempty=($match)

if [[ $#nonempty -gt 0 ]]; then
for m in "$nonempty[@]"; do
n="${m##[\"\']}"
input="${input/${n%%[\"\']}/...}"
done

print -Sr -- "$input"
fi
return 1
unset match
fi
}

0 comments on commit 070e441

Please sign in to comment.