Skip to content

Commit

Permalink
Merge pull request #18 from jalpp/dev
Browse files Browse the repository at this point in the history
Custom vault support and bug fixes
  • Loading branch information
jalpp authored Oct 27, 2024
2 parents 4e2a008 + 0d61501 commit e20ad96
Show file tree
Hide file tree
Showing 18 changed files with 501 additions and 151 deletions.
43 changes: 32 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ Because managing tokens, pins used in various dummy/dev apps require them to be
- Hash tokens/passwords with Argon2Id and Bcrypt
- Salt tokens/passwords
- Copy passwords to clipboard
- Automatically config password/token lengths and other settings
- Hashicorp Vault integration to connect to secure vault and store generated secrets on cloud
- 1Password integration to connect to secure vault and store generated secrets on cloud
- Custom vaults support via extend package in passdiy to allow you to connect to your own cloud vaults via passDiy UI

## Hashicorp Vault Commands
- hcpvaultconnect automatically connect to hcp vault via service principle
Expand All @@ -33,6 +35,8 @@ Because managing tokens, pins used in various dummy/dev apps require them to be
- 1passstore store secrets into the vault via name|password|url format
- 1passwordlist list secret names for connected vault

## Custom Vault
Don't see a vault you use, but not supported by PassDIY? No worries! write your own vaults driver code in `/extend` within provided functions and set `export USE_PASDIY_CUSTOM_VAULT=true`to connect PassDIY to your vault provider. Read `/extend/README.md`

## Demo

Expand All @@ -54,23 +58,40 @@ To allow PassDIY to connect to your 1Password Vault you would need to set [servi

`export OP_SERVICE_ACCOUNT_TOKEN=<your-service-account-token>`

## Config
## Config custom vault to use PassDIY TUI

you can config PassDIY's password/token/pin char lengths additional confiurations in `config/config.go` by changing below values
to config custom vaults that are not currently supported by Passdiy all you have to do is edit the interface.go file and define your custom implementation of the functions, then you set `export USE_PASDIY_CUSTOM_VAULT=true` and PassDIY will automatically interface the custom vault

```
const (
PIN_DIGIT_LENGTH int = 6 // number of ints in pin digit
API_TOKEN_CHAR_LENGTH int = 60 // number of chars in a API token
PASWORD_CHAR_LENGTH int = 40 // number of chars in a password
PASSPHRASE_COUNT_NUM int = 5 // number of words in passphrase
MULTIPLE_VALUE_COUNT int = 5 // how many password/tokens you want to output
LOTTERY_WHEEL_COUNT int = 100 // how many times you want to generate token/password/pins to randomly pick one (pass100, pass10000)
SALT_EXTRA_LENGTH int = 10 // how many extra chars you want to add to a password/token
```go
package extend

var (
VAULT_PREFIX = "pref"
VAULT_MAIN_DESC = "Manage token/password on " + VAULT_PREFIX
VAULT_SUBCOMMAND_NAMES = []string{VAULT_PREFIX + "store", VAULT_PREFIX + "list"}
VAULT_SUBCOMMAND_DESC = []string{"store", "lists"}
VAULT_DISPLAY_COLOR = "#E2EAF4"
)

func ConnectUI() string {
return Connect()
}

func StoreUI(userInput string) string {

var parser string

return Create(userInput, parser)
}

func ListUI() string {
return List()
}

```



## Installation

If you have `make` installed, follow these steps to build, run, and install **passdiy**:
Expand Down
156 changes: 100 additions & 56 deletions cmds/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package cmds

import (
"fmt"
"os"
"strings"
"time"

"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
"github.com/jalpp/passdiy/config"
custom "github.com/jalpp/passdiy/extend"
hcp "github.com/jalpp/passdiy/hcpvault"
opass "github.com/jalpp/passdiy/onepassword"
cmd "github.com/jalpp/passdiy/password"
Expand All @@ -19,21 +20,35 @@ type CommandItem struct {
}

var (
pwpDesc = fmt.Sprintf("Generate strong %d-word passphrase", config.PASSPHRASE_COUNT_NUM)
saltDesc = fmt.Sprintf("Generate password with extra %d-char salt on top", config.SALT_EXTRA_LENGTH)
pwpDesc = fmt.Sprintf("Generate strong %d-word passphrase", cmd.PASSPHRASE_COUNT_NUM)
saltDesc = fmt.Sprintf("Generate password with extra %d-char salt on top", cmd.SALT_EXTRA_LENGTH)
hashDesc = "Generate hash value of a password with Argon2id or bcrypthash"
argonhashDesc = "Generate hash value of a password with Argon2id"
bcrpthashDesc = "Generate hash value of a password with bcrypt algorithm"
hcpvaultstoreDesc = "Store a new secret to Hashicorp Vault"
hcpvaultconnectDesc = "Generate HCP API token and connect to Hashicorp Vault"
hcpvaultlistDesc = "List HCP Vault secrets log details"
opassstoreDesc = "Store a new secret to 1Password in password format"
opasslistDesc = "List 1Password Vault item names"
hcpvaultstoreDesc = hcp.VAULT_SUBCOMMAND_DESC[1]
hcpvaultconnectDesc = hcp.VAULT_SUBCOMMAND_DESC[0]
hcpvaultlistDesc = hcp.VAULT_SUBCOMMAND_DESC[2]
opassstoreDesc = opass.VAULT_SUBCOMMAND_DESC[0]
opasslistDesc = opass.VAULT_SUBCOMMAND_DESC[1]
mainpassDesc = "Generate strong passwords from various algorithms"
mainpinDesc = "Generate strong pins from various algorithms"
maintokenDesc = "Generate strong token from various algorithms"
hcpDesc = "Manage Token/Password on Hashicorp Vault"
opassDesc = "Manage Token/Password on 1Password"
hcpDesc = hcp.VAULT_MAIN_DESC
opassDesc = opass.VAULT_MAIN_DESC
configDesc = "Config PassDIY password, token, pin, salt char lengths"
)

const cf = cmd.LOTTERY_WHEEL_COUNT

var (
configItems = []CommandItem{
{title: "configpass", desc: cmd.CONFIG_PASS_DESC},
{title: "configtoken", desc: cmd.CONFIG_TOKEN_DESC},
{title: "configpin", desc: cmd.CONFIG_PIN_DESC},
{title: "configpwp", desc: cmd.CONFIG_PWP_WORD_DESC},
{title: "configmul", desc: cmd.CONFIG_MULTI_DESC},
{title: "configsalt", desc: cmd.CONFIG_SALT_DESC},
}
)

func (i CommandItem) Title() string { return i.title }
Expand All @@ -44,8 +59,8 @@ func GetSingleCommandInfo(cmd string) string {
return fmt.Sprintf("Generate a single %s", cmd)
}

func GetMulCommandInfo(cmd string) string {
return fmt.Sprintf("Generate %d multiple %s all at once", config.MULTIPLE_VALUE_COUNT, cmd)
func GetMulCommandInfo(cmds string) string {
return fmt.Sprintf("Generate %d multiple %s all at once", cmd.MULTIPLE_VALUE_COUNT, cmds)
}

func GetHundCommandInfo(cmd string) string {
Expand All @@ -57,42 +72,61 @@ func GetTenKCommandInfo(cmd string) string {
}

func CreateCommandItems() []list.Item {
const config = config.LOTTERY_WHEEL_COUNT

passItems := []CommandItem{
{title: "pass", desc: GetSingleCommandInfo("strong password")},
{title: "passmul", desc: GetMulCommandInfo("password")},
{title: fmt.Sprintf("pass%d", config), desc: GetHundCommandInfo("password")},
{title: fmt.Sprintf("pass%d", config*config), desc: GetTenKCommandInfo("password")},
{title: fmt.Sprintf("pass%d", cf), desc: GetHundCommandInfo("password")},
{title: fmt.Sprintf("pass%d", cf*cf), desc: GetTenKCommandInfo("password")},
}

pinItems := []CommandItem{
{title: "pin", desc: GetSingleCommandInfo("pin")},
{title: "pinmul", desc: GetMulCommandInfo("pin")},
{title: fmt.Sprintf("pin%d", config), desc: GetHundCommandInfo("pin")},
{title: fmt.Sprintf("pin%d", config*config), desc: GetTenKCommandInfo("pin")},
{title: fmt.Sprintf("pin%d", cf), desc: GetHundCommandInfo("pin")},
{title: fmt.Sprintf("pin%d", cf*cf), desc: GetTenKCommandInfo("pin")},
}

tokenItems := []CommandItem{
{title: "token", desc: GetSingleCommandInfo("token")},
{title: "tokenmul", desc: GetMulCommandInfo("token")},
{title: fmt.Sprintf("token%d", config), desc: GetHundCommandInfo("token")},
{title: fmt.Sprintf("token%d", config*config), desc: GetTenKCommandInfo("token")},
{title: fmt.Sprintf("token%d", cf), desc: GetHundCommandInfo("token")},
{title: fmt.Sprintf("token%d", cf*cf), desc: GetTenKCommandInfo("token")},
}
hashItems := []CommandItem{
{title: "argonhash", desc: argonhashDesc},
{title: "bcrypthash", desc: bcrpthashDesc},
}

hcpItems := []CommandItem{
{title: "hcpvaultstore", desc: hcpvaultstoreDesc},
{title: "hcpvaultconnect", desc: hcpvaultconnectDesc},
{title: "hcpvaultlist", desc: hcpvaultlistDesc},
{title: hcp.VAULT_SUBCOMMAND_NAMES[1], desc: hcpvaultstoreDesc},
{title: hcp.VAULT_SUBCOMMAND_NAMES[0], desc: hcpvaultconnectDesc},
{title: hcp.VAULT_SUBCOMMAND_NAMES[2], desc: hcpvaultlistDesc},
}

opassItems := []CommandItem{
{title: "1passstore", desc: opassstoreDesc},
{title: "1passlist", desc: opasslistDesc},
{title: opass.VAULT_SUBCOMMAND_NAMES[0], desc: opassstoreDesc},
{title: opass.VAULT_SUBCOMMAND_NAMES[1], desc: opasslistDesc},
}

customItems := []CommandItem{
{title: custom.VAULT_SUBCOMMAND_NAMES[0], desc: custom.VAULT_SUBCOMMAND_DESC[0]},
{title: custom.VAULT_SUBCOMMAND_NAMES[1], desc: custom.VAULT_SUBCOMMAND_DESC[1]},
}

if strings.ToLower(os.Getenv("USE_PASDIY_CUSTOM_VAULT")) == "true" {
return []list.Item{
CommandItem{title: "pass", desc: mainpassDesc, Subcmd: passItems},
CommandItem{title: "pin", desc: mainpinDesc, Subcmd: pinItems},
CommandItem{title: "token", desc: maintokenDesc, Subcmd: tokenItems},
CommandItem{title: "salt", desc: saltDesc},
CommandItem{title: "pwp", desc: pwpDesc},
CommandItem{title: "config", desc: configDesc, Subcmd: configItems},
CommandItem{title: "hash", desc: hashDesc, Subcmd: hashItems},
CommandItem{title: hcp.VAULT_PREFIX, desc: hcpDesc, Subcmd: hcpItems},
CommandItem{title: opass.VAULT_PREFIX, desc: opassDesc, Subcmd: opassItems},
CommandItem{title: custom.VAULT_PREFIX, desc: custom.VAULT_MAIN_DESC, Subcmd: customItems},
}
}

return []list.Item{
Expand All @@ -101,9 +135,10 @@ func CreateCommandItems() []list.Item {
CommandItem{title: "token", desc: maintokenDesc, Subcmd: tokenItems},
CommandItem{title: "salt", desc: saltDesc},
CommandItem{title: "pwp", desc: pwpDesc},
CommandItem{title: "config", desc: configDesc, Subcmd: configItems},
CommandItem{title: "hash", desc: hashDesc, Subcmd: hashItems},
CommandItem{title: "hcpvault", desc: hcpDesc, Subcmd: hcpItems},
CommandItem{title: "1pass", desc: opassDesc, Subcmd: opassItems},
CommandItem{title: hcp.VAULT_PREFIX, desc: hcpDesc, Subcmd: hcpItems},
CommandItem{title: opass.VAULT_PREFIX, desc: opassDesc, Subcmd: opassItems},
}
}

Expand All @@ -122,7 +157,7 @@ func ExecuteCommand(command, input string) tea.Cmd {
}

func HandleCommand(input, userInput string) string {
const config = config.LOTTERY_WHEEL_COUNT
const config = cmd.LOTTERY_WHEEL_COUNT
switch strings.TrimSpace(input) {
case "pass":
return cmd.GetStrongPassword()
Expand Down Expand Up @@ -156,35 +191,32 @@ func HandleCommand(input, userInput string) string {
return cmd.HashFunc(userInput)
case "bcrypthash":
return cmd.BcryptHash(userInput)
case "hash":
return cmd.HashFunc(userInput)
case "hcpvaultstore":
parts := strings.SplitN(userInput, "=", 2)
if len(parts) == 2 {
name := parts[0]
value := parts[1]
return hcp.Create(name, value)
}
return "Invalid format. Use 'name=value'."
case "hcpvaultconnect":
return hcp.Connect()
case "hcpvaultlist":
var list string = hcp.List()
if strings.Contains(list, "Unauthorized") {
return "Please connect to Hashicorp vault via hcpvaultconnect"
}
return list
case "1passstore":
parts := strings.SplitN(userInput, "|", 3)
if len(parts) == 3 {
user := parts[0]
pass := parts[1]
url := parts[2]
return opass.Create(user, pass, url)
}
return "Invalid format. use 'user|value|url'."
case "1passlist":
return opass.List()
case "configpass":
return cmd.SetPasswordLength(userInput)
case "configtoken":
return cmd.SetAPITokenLength(userInput)
case "configpin":
return cmd.SetPinLength(userInput)
case "configpwp":
return cmd.SetPwpWordCount(userInput)
case "configmul":
return cmd.SetMulCount(userInput)
case "configsalt":
return cmd.SetSaltLength(userInput)
case hcp.VAULT_SUBCOMMAND_NAMES[1]:
return hcp.StoreUI(userInput)
case hcp.VAULT_SUBCOMMAND_NAMES[0]:
return hcp.ConnectUI()
case hcp.VAULT_SUBCOMMAND_NAMES[2]:
return hcp.ListUI()
case opass.VAULT_SUBCOMMAND_NAMES[0]:
return opass.StoreUI(userInput)
case opass.VAULT_SUBCOMMAND_NAMES[1]:
return opass.ListUI()
case custom.VAULT_SUBCOMMAND_NAMES[0]:
return custom.StoreUI(userInput)
case custom.VAULT_SUBCOMMAND_NAMES[1]:
return custom.ListUI()
default:
return fmt.Sprintf("Unknown command: %s", input)
}
Expand All @@ -193,3 +225,15 @@ func HandleCommand(input, userInput string) string {
func CoverUp(pass string) string {
return cmd.CoverUp(pass)
}

func IsConfigCommand(command string) bool {
return strings.Contains(command, "config")
}

func IsHashCommand(command string) bool {
return command == "bcrypthash" || command == "argonhash"
}

func IsCommandInputMode(commandName string) bool {
return IsConfigCommand(commandName) || IsHashCommand(commandName) || commandName == "hcpvaultstore" || commandName == "1passstore"
}
11 changes: 0 additions & 11 deletions config/config.go

This file was deleted.

31 changes: 31 additions & 0 deletions extend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Config custom vault to use PassDIY TUI

to config custom vaults that are not currently supported by Passdiy all you have to do is edit the interface.go file and define your custom implementation of the functions, then you set `export USE_PASDIY_CUSTOM_VAULT=true` and PassDIY will automatically interface the custom vault

```go
package extend

var (
VAULT_PREFIX = "pref"
VAULT_MAIN_DESC = "Manage token/password on " + VAULT_PREFIX
VAULT_SUBCOMMAND_NAMES = []string{VAULT_PREFIX + "store", VAULT_PREFIX + "list"}
VAULT_SUBCOMMAND_DESC = []string{"store", "lists"}
VAULT_DISPLAY_COLOR = "#E2EAF4"
)

func ConnectUI() string {
return Connect()
}

func StoreUI(userInput string) string {

var parser string

return Create(userInput, parser)
}

func ListUI() string {
return List()
}

```
11 changes: 11 additions & 0 deletions extend/connect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package extend

// add connect implementation for vault here

func connectHelper() {

}

func Connect() string {
return "Extended Vault Connect Message"
}
11 changes: 11 additions & 0 deletions extend/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package extend

// add create implementation for vault here

func createHelper() {

}

func Create(name string, val string) string {
return "Extanded Vault Create Message"
}
Loading

0 comments on commit e20ad96

Please sign in to comment.