Skip to content

Commit

Permalink
Merge pull request #6 from camandel/refactor_flags
Browse files Browse the repository at this point in the history
refactor: flags and functions
  • Loading branch information
camandel authored Mar 27, 2021
2 parents d50ec56 + 102c033 commit f376091
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 66 deletions.
74 changes: 52 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

[![CI](https://github.com/camandel/check-password-strength/actions/workflows/ci.yml/badge.svg)](https://github.com/camandel/check-password-strength/actions/workflows/ci.yml) [![Build Release](https://github.com/camandel/check-password-strength/actions/workflows/release.yml/badge.svg)](https://github.com/camandel/check-password-strength/actions/workflows/release.yml)

check-password-strength is an open-source tool that could help you to check how your passwords are good. It reads a CSV file and assigns a score to each password within a range from 0 (worst) to 4 (best):
check-password-strength is a tool that runs on Linux, Windows and MacOS that could help you to check how your passwords are good. It reads data from a CSV file, user input or stdin and assigns a score to each password within a range from 0 (worst) to 4 (best):

```bash
$ ./check-password-strength password.csv
```
$ check-password-strength -f password.csv
```
![img](assets/img/screenshot.jpg?raw=true)

It supports CSV files from exported from the most popular Password Managers and Browsers and runs on Linux, Windows and MacOS.

It's based on the awesome [zxcvbn](https://github.com/dropbox/zxcvbn) library and its Go porting [zxcvbn-go](github.com/nbutton23/zxcvbn-go).

The passwords will be checked on:
Expand All @@ -20,8 +18,9 @@ The passwords will be checked on:
- common keyboards sequences
- l33t substitutions
- username as part of the password
- a custom dictionary can be loaded at runtime

## Suppoted CSV file formats
It supports `CSV files` exported from the most popular Password Managers and Browsers:

- [x] LastPass
- [x] Bitwarden
Expand All @@ -32,23 +31,45 @@ The passwords will be checked on:

(*) the custom CSV files must have a header with at least the following three fields: `url,username,password`

To check only one password at a time it can be used in `interactive` mode (password will not be displayed as you type):
```
$ check-password-strength -i
Enter Username: username
Enter Password:
URL | USERNAME | PASSWORD | SCORE (0-4) | ESTIMATED TIME TO CRACK
------+----------+----------+------------------+--------------------------
| username | p******d | 0 - Really bad | instant
```
or reading from `stdin`:
```
$ echo $PASSWORD | check-password-strength
URL | USERNAME | PASSWORD | SCORE (0-4) | ESTIMATED TIME TO CRACK
------+----------+----------+------------------+--------------------------
| | p******j | 4 - Strong | centuries
```
If you need to use it in a script you can use `-q` flag. It will display nothing on stdout and the `exit code` will contain the password score (it works only with single password):
```
$ echo $PASSWORD | ./check-password-strength -q
$ echo $?
4
```
## Getting started

### Install

Installation of check-password-strength is simple, just download [the release for your system](https://github.com/camandel/check-password-strength/releases) and run the binary passing a CSV file:
```bash
$ chmod +x ./check-password-strength
$ ./check-password-strength password.csv
Installation of check-password-strength is simple, just download [the release for your system](https://github.com/camandel/check-password-strength/releases) and run the binary:
```
$ chmod +x check-password-strength
$ ./check-password-strength -f password.csv
```
or run it in a Docker container:
```
$ docker run --rm --net none -v $PWD:/data:ro camandel/check-password-strength /data/password.csv
$ docker run --rm --net none -v $PWD:/data:ro camandel/check-password-strength -f /data/password.csv
```

### Building from source

```shell linux
```
$ git clone https://github.com/camandel/check-password-strength
$ cd check-password-strength
Expand Down Expand Up @@ -87,34 +108,43 @@ It will create a local image called `check-password-strength:latest`
You can use command line or the Docker image:

```
$ ./check-password-strength --help
$ check-password-strength -h
NAME:
check-password-strength - Check the passwords strength from csv file
check-password-strength - Check the passwords strength from csv file, console or stdin
USAGE:
check-password-strength [--debug] CSVFILE
check-password-strength [options]
VERSION:
v0.0.1
v0.0.2
COMMANDS:
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--debug, -d show debug logs (default: false)
--help, -h show help (default: false)
--version, -v print the version (default: false)
--filename CSVFILE, -f CSVFILE Check passwords from CSVFILE
--customdict JSONFILE, -c JSONFILE Load custom dictionary from JSONFILE
--interactive, -i enable interactive mode asking data from console (default: false)
--quiet, -q return score as exit code (valid only with single password) (default: false)
--debug, -d show debug logs (default: false)
--help, -h show help (default: false)
--version, -v print the version (default: false)
```

## How to add custom dictionaries
If you need to add your custom dictionaries create one ore more json file in `assets/data/' with the following format:
## How to add custom dictionary
If you need to add your custom dictionary to the integrated ones, create one json file in the following format:

```json
{
"words": [
"foo",
"bar",
"baz",
]
}
```
and recompile.
and load it at runtime with the `-c` flag:
```
$ check-password-strength -c customdict.json -f password.csv
```
Or add it directly into the binary copying the json file in `assets/data` and recompile.
4 changes: 2 additions & 2 deletions assets/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 50 additions & 9 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cmd

import (
"fmt"
"errors"
"os"

"github.com/urfave/cli/v2"
Expand All @@ -12,21 +12,37 @@ var log = New(Level).Sugar()
// Execute main function
func Execute() {

var debug bool
var customDict string
var interactive, quiet, debug bool
var username, filename, customDict string

app := &cli.App{
Name: "check-password-strength",
Usage: "Check the passwords strength from csv file",
UsageText: "check-password-strength [--customdict JSONFILE] [--debug] CSVFILE",
Usage: "Check the passwords strength from csv file, console or stdin",
UsageText: "check-password-strength [options]",
Version: Version,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "filename",
Aliases: []string{"f"},
Usage: "Check passwords from `CSVFILE`",
Destination: &filename,
},
&cli.StringFlag{
Name: "customdict",
Aliases: []string{"c"},
Usage: "Load custom dictionary from `JSONFILE`",
Destination: &customDict,
},
&cli.BoolFlag{Name: "interactive",
Aliases: []string{"i"},
Destination: &interactive,
Value: false,
Usage: "enable interactive mode asking data from console"},
&cli.BoolFlag{Name: "quiet",
Aliases: []string{"q"},
Destination: &quiet,
Value: false,
Usage: "return score as exit code (valid only with single password)"},
&cli.BoolFlag{Name: "debug",
Aliases: []string{"d"},
Destination: &debug,
Expand All @@ -40,12 +56,37 @@ func Execute() {
Level.SetLevel(DebugLevel)
}

if c.NArg() != 1 {
fmt.Print("One filename must be specified\n\n")
cli.ShowAppHelpAndExit(c, 1)
password, err := getPwdStdin()
if err != nil && !interactive && filename == "" {
cli.ShowAppHelpAndExit(c, -1)
}

log.Debugf("password from pipe: %s", redactPassword(password))

if filename != "" && interactive {
return errors.New("Can not use '-f' and '-i' flags at the same time")
}
if filename != "" && password != "" {
return errors.New("Can not use '-f' flag and read from stdin")
}
if interactive && password != "" {
return errors.New("Can not use '-i' flag and read from stdin")
}
if quiet && filename != "" {
return errors.New("Flag '-q' can be used only with '-i' flag or read from stdin")
}
if interactive {
username, password, err = askUsernamePassword()
if err != nil {
return err
}
}

if filename != "" {
return checkMultiplePassword(filename, customDict, interactive)
}
return checkSinglePassword(username, password, customDict, quiet)

return checkPassword(c.Args().First(), customDict)
},
}

Expand Down
Loading

0 comments on commit f376091

Please sign in to comment.