diff --git a/README.md b/README.md index e30b918..970efa3 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Install If you are on a Debian or Debian derived system, you can directly download and install the latest version. Check out the [releases](https://github.com/pythonhacker/varuh/releases) page and use `dpkg` to install the binary. - $ sudo dpkg -i varuh-${VERSION}_amd64.deb + $ sudo dpkg -i varuh-${VERSION}_amd64.deb The binary will be installed in `/usr/bin` folder. @@ -44,24 +44,24 @@ You need the [Go compiler](https://golang.org/dl/) to build the code. (This can Install `make` by using your native package manager. Something like, - $ sudo apt install make -y + $ sudo apt install make -y should work. Then, - $ make - Building varuh - go: downloading github.com/akamensky/argparse v1.3.1 - go: downloading golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - go: downloading github.com/atotto/clipboard v0.1.4 - go: downloading github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f - go: downloading github.com/pythonhacker/argparse v1.3.2 - go: downloading gorm.io/driver/sqlite v1.2.3 - ... + $ make + Building varuh + go: downloading github.com/akamensky/argparse v1.3.1 + go: downloading golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 + go: downloading github.com/atotto/clipboard v0.1.4 + go: downloading github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f + go: downloading github.com/pythonhacker/argparse v1.3.2 + go: downloading gorm.io/driver/sqlite v1.2.3 + ... - $ sudo make install - Installing varuh...done + $ sudo make install + Installing varuh...done The binary will be installed in `/usr/local/bin` folder. @@ -69,41 +69,42 @@ The binary will be installed in `/usr/local/bin` folder. Usage ===== - $ ./varuh -h - usage: varuh [-h|--help] [-I|--init ""] [-d|--decrypt ""] - [-C|--clone ""] [-R|--remove ""] [-U|--use-db - ""] [-f|--find ""] [-E|--edit ""] - [-l|--list-entry ""] [-x|--export ""] [-e|--encrypt] - [-A|--add] [-p|--path] [-a|--list-all] [-g|--genpass] [-s|--show] - [-c|--copy] [-v|--version] - - Password manager for the command line for Unix like operating - systems - - Options: - - -h --help Print help information - -I --init Initialize a new database - -d --decrypt Decrypt password database - -C --clone Clone an entry with - -R --remove Remove an entry with - -U --use-db Set as active database - -f --find Search entries with - -E --edit Edit entry by - -l --list-entry List entry by - -x --export Export all entries to - -e --encrypt Encrypt the current database - -A --add Add a new entry - -p --path Show current database path - -a --list-all List all entries in current database - -g --genpass Generate a strong password of length from 12 - 16 - -s --show Show passwords when listing entries - -c --copy Copy password to clipboard - -v --version Show version information and exit - - - AUTHORS - Copyright (C) 2021 Anand B Pillai + $ ./varuh -h + usage: varuh [-h|--help] [-I|--init ""] [-d|--decrypt ""] + [-C|--clone ""] [-R|--remove ""] [-U|--use-db + ""] [-f|--find ""] [-E|--edit ""] + [-l|--list-entry ""] [-x|--export ""] [-e|--encrypt] + [-A|--add] [-p|--path] [-a|--list-all] [-g|--genpass] [-s|--show] + [-c|--copy] [-y|--assume-yes] [-v|--version] + + Password manager for the command line for Unix like operating + systems + + Options: + + -h --help Print help information + -I --init Initialize a new database + -d --decrypt Decrypt password database + -C --clone Clone an entry with + -R --remove Remove an entry with or + -U --use-db Set as active database + -f --find Search entries with + -E --edit Edit entry by + -l --list-entry List entry by + -x --export Export all entries to + -e --encrypt Encrypt the current database + -A --add Add a new entry + -p --path Show current database path + -a --list-all List all entries in current database + -g --genpass Generate a strong password (length: 12 - 16) + -s --show Show passwords when listing entries + -c --copy Copy password to clipboard + -y --assume-yes Assume yes to actions requiring confirmation + -v --version Show version information and exit + + + AUTHORS + Copyright (C) 2021 Anand B Pillai Encryption and Security @@ -130,134 +131,134 @@ Databases ## Create a database - $ varuh -I mypasswds - Created new database - mypasswds - Updating active db path - /home/anand/mypasswds + $ varuh -I mypasswds + Created new database - mypasswds + Updating active db path - /home/anand/mypasswds - $ ls -lt mypasswds - -rw------- 1 anand anand 8192 Nov 9 23:06 mypasswds + $ ls -lt mypasswds + -rw------- 1 anand anand 8192 Nov 9 23:06 mypasswds The password database is created and is active now. You can start adding entries to it. ## Add an entry - $ varuh -A - Title: My Website Login - URL: mywebsite.name - Username: mememe - Password (enter to generate new): - Generating password ...done - Notes: Website uses Nginx auth - Do you want to add custom fields [y/N]: - Created new entry with id: 1 + $ varuh -A + Title: My Website Login + URL: mywebsite.name + Username: mememe + Password (enter to generate new): + Generating password ...done + Notes: Website uses Nginx auth + Do you want to add custom fields [y/N]: + Created new entry with id: 1 You can now list the entry with one of the list options. - $ varuh -l 1 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 1 - Title: My Website Login - User: mememe - URL: http://mywebsite.name - Password: **************** - Notes: Website uses Nginx auth - Modified: 2021-21-09 23:12:35 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + $ varuh -l 1 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 1 + Title: My Website Login + User: mememe + URL: http://mywebsite.name + Password: **************** + Notes: Website uses Nginx auth + Modified: 2021-21-09 23:12:35 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ## Add an entry with custom fields From version 0.3 onwards, custom fields are supported. - $ varuh -A - Title: Github token - URL: https://github.com/mydev/myproject - Username: mydev - Password (enter to generate new): ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp - Notes: Never Expires - Do you want to add custom fields [y/N]: y - Field Name: Domain - Value for Domain: github.com - Field Name: Type - Value for Type: Auth Token - Field Name: - Created new entry with id: 6 - - $ varuh -l 6 - ID: 6 - Title: Github token - User: mydev - URL: https://github.com/mydev/myproject - Password: ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp - Notes: Never Expires - Domain: github.com - Type: Auth Token - Modified: 2021-21-13 00:07:18 + $ varuh -A + Title: Github token + URL: https://github.com/mydev/myproject + Username: mydev + Password (enter to generate new): ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp + Notes: Never Expires + Do you want to add custom fields [y/N]: y + Field Name: Domain + Value for Domain: github.com + Field Name: Type + Value for Type: Auth Token + Field Name: + Created new entry with id: 6 + + $ varuh -l 6 + ID: 6 + Title: Github token + User: mydev + URL: https://github.com/mydev/myproject + Password: ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp + Notes: Never Expires + Domain: github.com + Type: Auth Token + Modified: 2021-21-13 00:07:18 For more on listing see the [Listing and Searching](#listing-and-searching) section below. ## Edit an entry - $ varuh -E 1 - Current Title: My Website Login - New Title: My Blog Login - Current URL: http://mywebsite.name - New URL: myblog.name - Current Username: mememe - New Username: meblog - Current Password: lTzC2z9kRppnYsYl - New Password ([y/Y] to generate new, enter will keep old one): - Current Notes: Website uses Nginx auth - New Notes: Website uses Apache - Do you want to add custom fields [y/N]: - Updated entry. - - $ varuh -l 1 -s - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 1 - Title: My Blog Login - User: meblog - URL: http://myblog.name - Password: myblog123 - Notes: Website uses Apache - Modified: 2021-21-09 23:15:29 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + $ varuh -E 1 + Current Title: My Website Login + New Title: My Blog Login + Current URL: http://mywebsite.name + New URL: myblog.name + Current Username: mememe + New Username: meblog + Current Password: lTzC2z9kRppnYsYl + New Password ([y/Y] to generate new, enter will keep old one): + Current Notes: Website uses Nginx auth + New Notes: Website uses Apache + Do you want to add custom fields [y/N]: + Updated entry. + + $ varuh -l 1 -s + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 1 + Title: My Blog Login + User: meblog + URL: http://myblog.name + Password: myblog123 + Notes: Website uses Apache + Modified: 2021-21-09 23:15:29 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ## Edit an entry with custom fields When you edit an entry with custom fields, you get the option to change the name of the fields or delete the fields entirely. - $ varuh -E 6 - Current Title: Github token - New Title: - Current URL: https://github.com/mydev/myproject - New URL: - Current Username: mydev - New Username: - Current Password: ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp - New Password ([y/Y] to generate new, enter will keep old one): - Current Notes: Never Expires - New Notes: - Editing/deleting custom fields - Field Name: Domain - New Field Name (Enter to keep, "x" to delete): x - Field Name: Type - New Field Name (Enter to keep, "x" to delete): Token Type - Field Value: Auth Token + $ varuh -E 6 + Current Title: Github token + New Title: + Current URL: https://github.com/mydev/myproject + New URL: + Current Username: mydev + New Username: + Current Password: ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp + New Password ([y/Y] to generate new, enter will keep old one): + Current Notes: Never Expires + New Notes: + Editing/deleting custom fields + Field Name: Domain + New Field Name (Enter to keep, "x" to delete): x + Field Name: Type + New Field Name (Enter to keep, "x" to delete): Token Type + Field Value: Auth Token New Field Value (Enter to keep): - Do you want to add custom fields [y/N]: - Created 1 custom entries for entry: 21. - Updated entry. - - $ varuh -l 6 -s - ID: 6 - Title: Github token - User: mydev - URL: https://github.com/mydev/myproject - Password: ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp - Notes: Never Expires - Token Type: Auth Token - Modified: 2021-21-13 00:16:41 + Do you want to add custom fields [y/N]: + Created 1 custom entries for entry: 21. + Updated entry. + + $ varuh -l 6 -s + ID: 6 + Title: Github token + User: mydev + URL: https://github.com/mydev/myproject + Password: ghp_ipQrStuVwxYz1a2b3cdEF10ghI689kLaMnOp + Notes: Never Expires + Token Type: Auth Token + Modified: 2021-21-13 00:16:41 (*-s* turns on visible passwords) @@ -265,30 +266,59 @@ When you edit an entry with custom fields, you get the option to change the name To clone (copy) an entry, - $ $ varuh -C 1 - Cloned to new entry, id: 3 + $ $ varuh -C 1 + Cloned to new entry, id: 3 ## Remove an entry - $ varuh -R 1 - Entry with id 1 was removed from the database + $ varuh -R 1 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Title: My Website Login + User: mememe + URL: https://mywebsite.name + Modified: 2021-21-09 23:12:35 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + Please confirm removal [Y/n]: + Entry with id 1 was removed from the database It is an error if the id does not exist. - $ varuh -R 4 - No entry with id 4 was found + $ varuh -R 4 + No entry with id 4 was found + +## Remove a range of entries + +You can remove a range of entry ids from id1-id2 using the following command. + + $ varuh -R id1-id2 + +Example: + + $ varuh -R 1-4 + +This will remove entries from 1 to 4 inclusive, asking for confirmation from the user every time. + +## Removal without confirmation + +If you are very sure, you can avoid the confirmation prompt by passing the `-y` flag which will remove the entry without confirmation. + + $ varuh -R 2 -y + ... + ... + ... + Entry with id 2 was removed from the database ## Switch to a new database Once a database is active, creating another one automatically encrypts the current one and makes the new one the active database. The automatic encryption happens only if the configuration flag `auto_encrypt` is turned on (See section [Configuration](#configuration) below). - $ varuh -I mysecrets - Encrytping current database - /home/anand/mypasswds - Password: - Password again: - Encryption complete. - Created new database - mysecrets - Updating active db path - /home/anand/mysecrets + $ varuh -I mysecrets + Encrytping current database - /home/anand/mypasswds + Password: + Password again: + Encryption complete. + Created new database - mysecrets + Updating active db path - /home/anand/mysecrets The previous database is now encrypted with the configured block cipher using the password. Please make sure you remember the password. @@ -296,48 +326,48 @@ The previous database is now encrypted with the configured block cipher using th If you want to switch back to a previous database, you can use the `-U` option. The same process is repeated with the current database getting encrypted and the older one getting decrypted. - $ varuh -U mypasswds - Encrypting current active database - /home/anand/mysecrets - Password: - Password again: - Encryption complete. - Database /home/anand/mypasswds is encrypted, decrypting it - Password: - Decryption complete. - Switched active database successfully. - + $ varuh -U mypasswds + Encrypting current active database - /home/anand/mysecrets + Password: + Password again: + Encryption complete. + Database /home/anand/mypasswds is encrypted, decrypting it + Password: + Decryption complete. + Switched active database successfully. + ## Manual encryption and decryption You can manually encrypt the current database using the `-e` option. - $ varuh -e - Password: - Password again: - Encryption complete. + $ varuh -e + Password: + Password again: + Encryption complete. Note that once you encrypt the active database, you cannot use the listings any more unless it is decrypted. - $ varuh -l 2 - No decrypted active database found. + $ varuh -l 2 + No decrypted active database found. Manually decrypt the database using `-d` option. - $ varuh -d mypasswds - Password: - Decryption complete. + $ varuh -d mypasswds + Password: + Decryption complete. Now the database is active again and you can see the listings. - $ varuh -l 3 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 2 - Title: My Blog Login - User: myblog.name - URL: http://meblog - Password: ********* - Notes: Website uses Apache - Modified: 2021-21-09 23:21:32 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + $ varuh -l 3 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 2 + Title: My Blog Login + User: myblog.name + URL: http://meblog + Password: ********* + Notes: Website uses Apache + Modified: 2021-21-09 23:21:32 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ## Always on encryption @@ -345,20 +375,20 @@ If the config param `encrypt_on` is set to `true` along with `auto_encrypt` (def ### Example - $ varuh -f my -s - Password: - Decryption complete. - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 2 - Title: MY LOCAL BANK - User: banklogin - URL: https://my.localbank.com - Password: bankpass123 - Notes: - Modified: 2021-21-18 12:44:10 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - Encryption complete. + $ varuh -f my -s + Password: + Decryption complete. + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 2 + Title: MY LOCAL BANK + User: banklogin + URL: https://my.localbank.com + Password: bankpass123 + Notes: + Modified: 2021-21-18 12:44:10 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Encryption complete. In this mode, your data is provided maximum safety as the database remains decrypted only for a short while on the disk while the data is being read and once done is encrypted back again. @@ -369,79 +399,79 @@ Listing and Searching To list an entry using its id, - $ varuh -l 8 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 8 - Title: Google account - User: anandpillai@alumni.iitm.ac.in - URL: - Password: *********** - Notes: - Modified: 2021-21-25 15:02:50 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + $ varuh -l 8 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 8 + Title: Google account + User: anandpillai@alumni.iitm.ac.in + URL: + Password: *********** + Notes: + Modified: 2021-21-25 15:02:50 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ## To search an entry An entry can be searched on its title, username, URL or notes. Search is case-insensitive. - $ varuh -f google - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 8 - Title: Google account - User: anandpillai@alumni.iitm.ac.in - URL: - Password: ********** - Notes: - Modified: 2021-21-25 15:02:50 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 9 - Title: Google account - User: xyz@gmail.com - URL: - Password: ******** - Notes: - Modified: 2021-21-25 15:05:36 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 10 - Title: Google account - User: somethingaboutme@gmail.com - URL: - Password: *********** - Notes: - Modified: 2021-21-25 15:09:51 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + $ varuh -f google + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 8 + Title: Google account + User: anandpillai@alumni.iitm.ac.in + URL: + Password: ********** + Notes: + Modified: 2021-21-25 15:02:50 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 9 + Title: Google account + User: xyz@gmail.com + URL: + Password: ******** + Notes: + Modified: 2021-21-25 15:05:36 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 10 + Title: Google account + User: somethingaboutme@gmail.com + URL: + Password: *********** + Notes: + Modified: 2021-21-25 15:09:51 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ## To list all entries To list all entries, use the option `-a`. - $ varuh -a - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 1 - Title: My Bank #1 - User: myusername1 - URL: https://mysuperbank1.com - Password: *********** - Notes: - Modified: 2021-21-15 15:40:29 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 2 - Title: My Digital Locker #1 - User: mylockerusername - URL: https://mysuperlocker1.com - Password: ********** - Notes: - Modified: 2021-21-18 12:44:10 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ID: 3 - Title: My Bank Login #2 - User: mybankname2 - URL: https://myaveragebank.com - Password: ********** - Notes: - Modified: 2021-21-19 14:16:33 - +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - ... + $ varuh -a + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 1 + Title: My Bank #1 + User: myusername1 + URL: https://mysuperbank1.com + Password: *********** + Notes: + Modified: 2021-21-15 15:40:29 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 2 + Title: My Digital Locker #1 + User: mylockerusername + URL: https://mysuperlocker1.com + Password: ********** + Notes: + Modified: 2021-21-18 12:44:10 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ID: 3 + Title: My Bank Login #2 + User: mybankname2 + URL: https://myaveragebank.com + Password: ********** + Notes: + Modified: 2021-21-19 14:16:33 + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + ... By default the listing is in ascending ID order. This can be changed in the configuration (see below). @@ -457,8 +487,8 @@ This is useful to copy the password to a password input field in the browser for ## See current active database path - $ varuh -p - /home/anand/mypasswds + $ varuh -p + /home/anand/mypasswds Export ====== @@ -472,37 +502,37 @@ Export To export use the `-x` option. The type of file is automatically figured out from the filename extension. - $ varuh -x passwds.csv - !WARNING: Passwords are stored in plain-text! - Exported 14 records to passwds.csv . - Exported to passwds.csv. + $ varuh -x passwds.csv + !WARNING: Passwords are stored in plain-text! + Exported 14 records to passwds.csv . + Exported to passwds.csv. - $ varuh -x passwds.html - Exported to passwds.html. + $ varuh -x passwds.html + Exported to passwds.html. PDF export is supported if `pandoc` is installed along with the required `pdflatex` packages. The following command (on `Debian` and derived systems) should install the required dependencies. - $ sudo apt-get install pandoc texlive-latex-base texlive-fonts-recommended texlive-fonts-extra texlive-latex-extra texlive-xetex lmodern -y + $ sudo apt-get install pandoc texlive-latex-base texlive-fonts-recommended texlive-fonts-extra texlive-latex-extra texlive-xetex lmodern -y Then, - $ varuh -x passwds.pdf - pdftk not found, PDF won't be secure! + $ varuh -x passwds.pdf + pdftk not found, PDF won't be secure! - File passwds.pdf created without password. - Exported to passwds.pdf. + File passwds.pdf created without password. + Exported to passwds.pdf. PDF files are exported in landscape mode with 150 dpi and 600 columns. To avoid the data not fitting into one page the fields `Notes` and `URL` are not exported. If `pdftk` is installed, the PDF files will be encrypted with an (optional) password. - $ sudo apt-get install pdftk -y + $ sudo apt-get install pdftk -y - $ varuh -x passwds.pdf - PDF Encryption Password: ****** - File passwds.pdf created without password. - Added password to passwds.pdf. - Exported to passwds.pdf. + $ varuh -x passwds.pdf + PDF Encryption Password: ****** + File passwds.pdf created without password. + Added password to passwds.pdf. + Exported to passwds.pdf. Misc ==== @@ -513,14 +543,14 @@ Generate a strong password of length ranging from 12 - 16. A `strong` password is defined as a cryptographically secure string contaning at least one upper-case letter, one punctuation character and one number. - $ varuh -g - 7%zv/uzIgpqexJ + $ varuh -g + 7%zv/uzIgpqexJ - By passing the `-c` option, the password is also copied to the clipboard. + By passing the `-c` option, the password is also copied to the clipboard. - $ varuh -g -c - y6UpD$~uBI#8 - Password copied to clipboard + $ varuh -g -c + y6UpD$~uBI#8 + Password copied to clipboard Configuration @@ -530,19 +560,19 @@ Configuration The config file is named *config.json*. It looks as follows. - `{ - "active_db": "/home/anand/mypasswds", - "cipher": "aes", - "auto_encrypt": true, - "visible_passwords": false, - "encrypt_on": true, - "path": "/home/anand/.config/varuh/config.json", - "list_order": "id,asc", - "delimiter": "+", - "color": "default", - "bgcolor": "bgblack" - } - ` + `{ + "active_db": "/home/anand/mypasswds", + "cipher": "aes", + "auto_encrypt": true, + "visible_passwords": false, + "encrypt_on": true, + "path": "/home/anand/.config/varuh/config.json", + "list_order": "id,asc", + "delimiter": "+", + "color": "default", + "bgcolor": "bgblack" + } + ` You can modify the following variables. 1. `auto_encrypt` - Set this to true to enable automatic encryption/decryption when switching databases. Otherwise you have to do this manually. The default is `true`. @@ -555,7 +585,7 @@ You can modify the following variables. * `title` - Uses the `Title` field. * `username` - Uses the `User` field. - Always specify this configuration as `,`. Supported `` values are `asc` and `desc`. + Always specify this configuration as `,`. Supported `` values are `asc` and `desc`. 1. `delimiter` - This modifies the delimiter string when printing a listing. Only one character is allowed. 1. `color` - The foreground color of the text when printing listings. 1. `bgcolor` - The background color of the text when printing listings. diff --git a/actions.go b/actions.go index e413c78..35c8ae2 100644 --- a/actions.go +++ b/actions.go @@ -248,7 +248,7 @@ func addNewEntry() error { err, passwd = generateStrongPassword() fmt.Printf("done") } - // fmt.Printf("Password => %s\n", passwd) + // fmt.Printf("Password => %s\n", passwd) notes = readInput(reader, "\nNotes") @@ -405,7 +405,7 @@ func editCurrentEntry(idString string) error { fmt.Printf("\nGenerating new password ...") err, passwd = generateStrongPassword() } - // fmt.Printf("Password => %s\n", passwd) + // fmt.Printf("Password => %s\n", passwd) fmt.Printf("\nCurrent Notes: %s\n", entry.Notes) notes = readInput(reader, "New Notes") @@ -434,7 +434,7 @@ func listCurrentEntry(idString string) error { id, _ = strconv.Atoi(idString) - // fmt.Printf("Listing current entry - %d\n", id) + // fmt.Printf("Listing current entry - %d\n", id) err, entry = getEntryById(id) if err != nil || entry == nil { fmt.Printf("No entry found for id %d\n", id) @@ -444,7 +444,7 @@ func listCurrentEntry(idString string) error { err = printEntry(entry, true) if err == nil && settingsRider.CopyPassword { - // fmt.Printf("Copying password " + entry.Password + " to clipboard\n") + // fmt.Printf("Copying password " + entry.Password + " to clipboard\n") copyPasswordToClipboard(entry.Password) } @@ -547,17 +547,51 @@ func findCurrentEntry(term string) error { return err } +// Remove a range of entries - say 10-14 +func removeMultipleEntries(idRangeEntry string) error { + + var err error + var idRange []string + var id1, id2 int + + idRange = strings.Split(idRangeEntry, "-") + + if len(idRange) != 2 { + fmt.Println("Invalid id range - " + idRangeEntry) + return errors.New("Invalid id range - " + idRangeEntry) + } + + id1, _ = strconv.Atoi(idRange[0]) + id2, _ = strconv.Atoi(idRange[1]) + + if id1 >= id2 { + fmt.Println("Invalid id range - " + idRangeEntry) + return errors.New("Invalid id range - " + idRangeEntry) + } + + for idNum := id1; idNum <= id2; idNum++ { + err = removeCurrentEntry(fmt.Sprintf("%d", idNum)) + } + + return err +} + // Remove current entry by id func removeCurrentEntry(idString string) error { var err error var entry *Entry var id int + var response string if err = checkActiveDatabase(); err != nil { return err } + if strings.Contains(idString, "-") { + return removeMultipleEntries(idString) + } + id, _ = strconv.Atoi(idString) err, entry = getEntryById(id) @@ -566,10 +600,22 @@ func removeCurrentEntry(idString string) error { return err } - // Drop from the database - err = removeDatabaseEntry(entry) - if err == nil { - fmt.Printf("Entry with id %d was removed from the database\n", id) + printEntryMinimal(entry, true) + + if !settingsRider.AssumeYes { + response = readInput(bufio.NewReader(os.Stdin), "Please confirm removal [Y/n]: ") + } else { + response = "y" + } + + if strings.ToLower(response) != "n" { + // Drop from the database + err = removeDatabaseEntry(entry) + if err == nil { + fmt.Printf("Entry with id %d was removed from the database\n", id) + } + } else { + fmt.Println("Removal of entry cancelled by user.") } return err @@ -655,7 +701,7 @@ func encryptDatabase(dbPath string, givenPasswd *string) error { } } - // err = encryptFileAES(dbPath, passwd) + // err = encryptFileAES(dbPath, passwd) _, settings := getOrCreateLocalConfig(APP) switch settings.Cipher { @@ -796,7 +842,7 @@ func exportToMarkdown(fileName string) error { } } - // fmt.Printf("%+v\n", maxLengths) + // fmt.Printf("%+v\n", maxLengths) fh, err = os.Create(fileName) if err != nil { fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error()) @@ -810,7 +856,7 @@ func exportToMarkdown(fileName string) error { // Write markdown header for idx, length := range maxLengths { delta := length - len(headers[idx]) - // fmt.Printf("%d\n", delta) + // fmt.Printf("%d\n", delta) if delta > 0 { for i := 0; i < delta+2; i++ { headers[idx] += " " @@ -872,7 +918,7 @@ func exportToPDF(fileName string) error { } tmpFile = randomFileName(os.TempDir(), ".tmp") - // fmt.Printf("Temp file => %s\n", tmpFile) + // fmt.Printf("Temp file => %s\n", tmpFile) err = exportToMarkdownLimited(tmpFile) if err == nil { @@ -889,7 +935,7 @@ func exportToPDF(fileName string) error { if pdfTkFound && len(passwd) > 0 { tmpFile = randomFileName(".", ".pdf") - // fmt.Printf("pdf file => %s\n", tmpFile) + // fmt.Printf("pdf file => %s\n", tmpFile) args = []string{fileName, "output", tmpFile, "user_pw", passwd} cmd = exec.Command("pdftk", args...) _, err = cmd.Output() @@ -935,7 +981,7 @@ func exportToMarkdownLimited(fileName string) error { } } - // fmt.Printf("%+v\n", maxLengths) + // fmt.Printf("%+v\n", maxLengths) fh, err = os.Create(fileName) if err != nil { fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error()) @@ -949,7 +995,7 @@ func exportToMarkdownLimited(fileName string) error { // Write markdown header for idx, length := range maxLengths { delta := length - len(headers[idx]) - // fmt.Printf("%d\n", delta) + // fmt.Printf("%d\n", delta) if delta > 0 { for i := 0; i < delta+2; i++ { headers[idx] += " " @@ -1000,7 +1046,7 @@ func exportToHTML(fileName string) error { return err } - // fmt.Printf("%+v\n", maxLengths) + // fmt.Printf("%+v\n", maxLengths) fh, err = os.Create(fileName) if err != nil { fmt.Printf("Cannt open \"%s\" for writing - \"%s\"\n", fileName, err.Error()) diff --git a/main.go b/main.go index 0df1d8f..a182f13 100644 --- a/main.go +++ b/main.go @@ -32,7 +32,7 @@ type CmdOption struct { // Print the program's usage string and exit func printUsage() error { - // getopt.Usage() + // getopt.Usage() os.Exit(0) return nil @@ -102,8 +102,9 @@ func performAction(optMap map[string]interface{}) { } flagsActionsMap := map[string]voidFunc{ - "show": setShowPasswords, - "copy": setCopyPasswordToClipboard, + "show": setShowPasswords, + "copy": setCopyPasswordToClipboard, + "assume-yes": setAssumeYes, } // Flag actions - always done @@ -168,7 +169,7 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { {"I", "init", "Initialize a new database", "", ""}, {"d", "decrypt", "Decrypt password database", "", ""}, {"C", "clone", "Clone an entry with ", "", ""}, - {"R", "remove", "Remove an entry with ", "", ""}, + {"R", "remove", "Remove an entry with or ", "", ""}, {"U", "use-db", "Set as active database", "", ""}, {"f", "find", "Search entries with ", "", ""}, {"E", "edit", "Edit entry by ", "", ""}, @@ -188,6 +189,7 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { {"g", "genpass", "Generate a strong password (length: 12 - 16)", "", ""}, {"s", "show", "Show passwords when listing entries", "", ""}, {"c", "copy", "Copy password to clipboard", "", ""}, + {"y", "assume-yes", "Assume yes to actions requiring confirmation", "", ""}, {"v", "version", "Show version information and exit", "", ""}, {"h", "help", "Print this help message and exit", "", ""}, } diff --git a/utils.go b/utils.go index 440cad3..774b783 100644 --- a/utils.go +++ b/utils.go @@ -22,6 +22,7 @@ const DELIMSIZE int = 69 type SettingsOverride struct { ShowPasswords bool CopyPassword bool + AssumeYes bool } // Settings structure for local config @@ -104,7 +105,7 @@ func getOrCreateLocalConfig(app string) (error, *Settings) { } configFile = filepath.Join(configPath, "config.json") - // fmt.Printf("Config file, path => %s %s\n", configFile, configPath) + // fmt.Printf("Config file, path => %s %s\n", configFile, configPath) if _, err = os.Stat(configFile); err == nil { fh, err = os.Open(configFile) @@ -121,7 +122,7 @@ func getOrCreateLocalConfig(app string) (error, *Settings) { } } else { - // fmt.Printf("Creating default configuration ...") + // fmt.Printf("Creating default configuration ...") settings = Settings{"", "aes", true, true, false, configFile, "id,asc", "+", "default", "bgblack"} if err = writeSettings(&settings, configFile); err == nil { @@ -337,6 +338,42 @@ func printEntry(entry *Entry, delim bool) error { } +// Print an entry to the console with minimal data +func printEntryMinimal(entry *Entry, delim bool) error { + + var err error + var settings *Settings + + err, settings = getOrCreateLocalConfig(APP) + + if err != nil { + fmt.Printf("Error parsing config - \"%s\"\n", err.Error()) + return err + } + + fmt.Printf("%s", getColor(strings.ToLower(settings.Color))) + if strings.HasPrefix(settings.BgColor, "bg") { + fmt.Printf("%s", getColor(strings.ToLower(settings.BgColor))) + } + + if delim { + printDelim(settings.Delim, settings.Color) + } + + fmt.Printf("Title: %s\n", entry.Title) + fmt.Printf("User: %s\n", entry.User) + fmt.Printf("URL: %s\n", entry.Url) + fmt.Printf("Modified: %s\n", entry.Timestamp.Format("2006-06-02 15:04:05")) + + printDelim(settings.Delim, settings.Color) + + // Reset + fmt.Printf("%s", getColor("default")) + + return nil + +} + // Read user input and return entered value func readInput(reader *bufio.Reader, prompt string) string { @@ -397,7 +434,7 @@ func isActiveDatabaseEncryptedAndMaxKryptOn() (bool, string) { // (Temporarily) enable showing of passwords func setShowPasswords() error { - // fmt.Printf("Setting show passwords to true\n") + // fmt.Printf("Setting show passwords to true\n") settingsRider.ShowPasswords = true return nil } @@ -408,6 +445,11 @@ func setCopyPasswordToClipboard() error { return nil } +func setAssumeYes() error { + settingsRider.AssumeYes = true + return nil +} + func copyPasswordToClipboard(passwd string) { clipboard.WriteAll(passwd) }