Skip to content

Commit

Permalink
feat: "generate password" and "generate uuid" commands
Browse files Browse the repository at this point in the history
  • Loading branch information
mkloubert committed Jan 4, 2025
1 parent b770760 commit a16f7e7
Show file tree
Hide file tree
Showing 8 changed files with 264 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log (go-package-manager)

## 0.31.0

- feat: `generate password` command
- feat: `generate uuid` command

## 0.30.0

- feat: `gpm update` now supports update of specific modules as well
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- [Docker shorthands](#docker-shorthands-)
- [Execute shell command](#execute-shell-command-)
- [Generate documentation](#generate-documentation-)
- [Generate passwords or UUIDs](#generate-passwords-or-uuids-)
- [Generate project](#generate-project-)
- [Import aliases](#import-aliases-)
- [Import projects](#import-projects-)
Expand Down Expand Up @@ -312,6 +313,20 @@ The following video does demonstrate this (keep in mind: replace replace `go run

![Generate project demo 1](./img/demos/generate-project-demo-1.gif)

#### Generate passwords or UUIDs [<a href="#commands-">↑</a>]

To generate passwords or UUIDs/GUIDs simply run

```bash
gpm generate password
```

or

```bash
gpm generate uuid
```

#### Import aliases [<a href="#commands-">↑</a>]

```bash
Expand Down
2 changes: 2 additions & 0 deletions aliases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ aliases:
- https://github.com/gizak/termui/v3
tview:
- https://github.com/rivo/tview
uuid:
- github.com/google/uuid
version:
- https://github.com/hashicorp/go-version
yaml:
Expand Down
File renamed without changes.
217 changes: 217 additions & 0 deletions commands/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,22 @@ package commands

import (
"bufio"
cryptoRand "crypto/rand"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"math/big"
"net/url"
"os"
"path/filepath"
"runtime"
"strings"
"time"

"github.com/atotto/clipboard"
"github.com/charmbracelet/glamour"
"github.com/google/uuid"
"github.com/mkloubert/go-package-manager/types"
"github.com/mkloubert/go-package-manager/utils"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -127,6 +132,133 @@ func init_generate_documentation_command(parentCmd *cobra.Command, app *types.Ap
)
}

func init_generate_password_command(parentCmd *cobra.Command, app *types.AppContext) {
var allBytes bool
var base64Output bool
var count uint16
var charset string
var copyToClipboard bool
var length uint16
var minLength uint16
var noOutput bool
var waitTime int

var generatePasswordCmd = &cobra.Command{
Use: "password",
Aliases: []string{"passwd", "passwds", "passwords", "pwd", "pwds"},
Short: "Generate password",
Long: `Generates one or more passwords.`,
Run: func(cmd *cobra.Command, args []string) {
clipboardContent := ""

var addClipboardContent func(text string)
if copyToClipboard {
addClipboardContent = func(text string) {
clipboardContent += text
}
} else {
addClipboardContent = func(text string) {
// dummy
}
}

if minLength > 0 {
if minLength > length {
utils.CheckForError(fmt.Errorf("min-length %v cannot be greater then length %v", minLength, length))
}
}

var i uint16 = 0
for {
if i == count {
break
}

i++
if i > 1 {
fmt.Println()
addClipboardContent(fmt.Sprintln())

time.Sleep(time.Duration(waitTime) * time.Millisecond)
}

app.Debug(fmt.Sprintf("Generating passwords %v ...", i))

var passwordLength uint16
if minLength > 0 {
randVal := utils.GenerateRandomUint16()

passwordLength = utils.MaxUint16(randVal%length, minLength)
} else {
passwordLength = length
}

app.Debug(fmt.Sprintf("Password length %v ...", passwordLength))

password := make([]byte, int(passwordLength))

if allBytes {
// use any byte
app.Debug("Will use no charset ...")

_, err := cryptoRand.Read(password)
utils.CheckForError(err)
} else {
passwordCharset := charset
if passwordCharset == "" {
passwordCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}<>?/|"
}

app.Debug(fmt.Sprintf("Will use charset: %s", charset))

for j := range password {
index, err := cryptoRand.Int(cryptoRand.Reader, big.NewInt(int64(len(passwordCharset))))
utils.CheckForError(err)

password[j] = passwordCharset[index.Int64()]
}
}

var passwordToOutput string
if base64Output {
app.Debug("Base64 output ...")

passwordToOutput = base64.URLEncoding.EncodeToString(password)
} else {
passwordToOutput = string(password)
}

if !noOutput {
fmt.Print(passwordToOutput)
}

addClipboardContent(passwordToOutput)
}

if copyToClipboard {
app.Debug("Copy all to clipboard ...")

err := clipboard.WriteAll(clipboardContent)
utils.CheckForError(err)
}
},
}

generatePasswordCmd.Flags().BoolVarP(&allBytes, "all-bytes", "", false, "use any byte for password")
generatePasswordCmd.Flags().BoolVarP(&base64Output, "base64", "", false, "output as Base64 string")
generatePasswordCmd.Flags().StringVarP(&charset, "charset", "", "", "custom charset")
generatePasswordCmd.Flags().BoolVarP(&copyToClipboard, "copy", "", false, "copy final content to clipboard")
generatePasswordCmd.Flags().Uint16VarP(&count, "count", "", 1, "custom number password to generate at once")
generatePasswordCmd.Flags().Uint16VarP(&length, "length", "", 20, "custom length of password")
generatePasswordCmd.Flags().Uint16VarP(&minLength, "min-length", "", 0, "if defined the length of password will be flexible")
generatePasswordCmd.Flags().BoolVarP(&noOutput, "no-output", "", false, "do not output to console")
generatePasswordCmd.Flags().IntVarP(&waitTime, "wait-time", "", 0, "the time in millieconds to wait between two steps")

parentCmd.AddCommand(
generatePasswordCmd,
)
}

func init_generate_project_command(parentCmd *cobra.Command, app *types.AppContext) {
var alwaysYes bool
var customModel string
Expand Down Expand Up @@ -588,6 +720,89 @@ require (
)
}

func init_generate_uuid_command(parentCmd *cobra.Command, app *types.AppContext) {
var base64Output bool
var count uint16
var copyToClipboard bool
var length uint16
var noOutput bool
var waitTime int

var generatePasswordCmd = &cobra.Command{
Use: "guid",
Aliases: []string{"guids", "uuid", "uuids"},
Short: "Generate UUID",
Long: `Generates one or more UUIDs/GUIDs.`,
Run: func(cmd *cobra.Command, args []string) {
clipboardContent := ""

var addClipboardContent func(text string)
if copyToClipboard {
addClipboardContent = func(text string) {
clipboardContent += text
}
} else {
addClipboardContent = func(text string) {
// dummy
}
}

var i uint16 = 0
for {
if i == count {
break
}

i++
if i > 1 {
fmt.Println()
addClipboardContent(fmt.Sprintln())

time.Sleep(time.Duration(waitTime) * time.Millisecond)
}

app.Debug(fmt.Sprintf("Generating passwords %v ...", i))

guid, err := uuid.NewRandom()
utils.CheckForError(err)

var passwordToOutput string
if base64Output {
app.Debug("Base64 output ...")

passwordToOutput = base64.URLEncoding.EncodeToString(guid[:])
} else {
passwordToOutput = guid.String()
}

if !noOutput {
fmt.Print(passwordToOutput)
}

addClipboardContent(passwordToOutput)
}

if copyToClipboard {
app.Debug("Copy all to clipboard ...")

err := clipboard.WriteAll(clipboardContent)
utils.CheckForError(err)
}
},
}

generatePasswordCmd.Flags().BoolVarP(&base64Output, "base64", "", false, "output as Base64 string")
generatePasswordCmd.Flags().BoolVarP(&copyToClipboard, "copy", "", false, "copy final content to clipboard")
generatePasswordCmd.Flags().Uint16VarP(&count, "count", "", 1, "custom number password to generate at once")
generatePasswordCmd.Flags().Uint16VarP(&length, "length", "", 20, "custom length of password")
generatePasswordCmd.Flags().BoolVarP(&noOutput, "no-output", "", false, "do not output to console")
generatePasswordCmd.Flags().IntVarP(&waitTime, "wait-time", "", 0, "the time in millieconds to wait between two steps")

parentCmd.AddCommand(
generatePasswordCmd,
)
}

func Init_Generate_Command(parentCmd *cobra.Command, app *types.AppContext) {
var generateCmd = &cobra.Command{
Use: "generate [resource]",
Expand All @@ -600,7 +815,9 @@ func Init_Generate_Command(parentCmd *cobra.Command, app *types.AppContext) {
}

init_generate_documentation_command(generateCmd, app)
init_generate_password_command(generateCmd, app)
init_generate_project_command(generateCmd, app)
init_generate_uuid_command(generateCmd, app)

parentCmd.AddCommand(
generateCmd,
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/gdamore/tcell/v2 v2.7.4
github.com/gizak/termui/v3 v3.1.0
github.com/goccy/go-yaml v1.15.13
github.com/google/uuid v1.6.0
github.com/hashicorp/go-version v1.7.0
github.com/jedib0t/go-pretty/v6 v6.6.5
github.com/joho/godotenv v1.5.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ github.com/goccy/go-yaml v1.15.13 h1:Xd87Yddmr2rC1SLLTm2MNDcTjeO/GYo0JGiww6gSTDg
github.com/goccy/go-yaml v1.15.13/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
Expand Down
22 changes: 22 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"bufio"
"fmt"
"io"
mathRand "math/rand"
"net/http"
"net/url"
"os"
Expand Down Expand Up @@ -165,6 +166,11 @@ func EnsureMaxSliceLength[T any](slice []T, maxLength int) []T {
return slice
}

// GenerateRandomUint16() - creates a new random uint16 value
func GenerateRandomUint16() uint16 {
return uint16(mathRand.Intn(1 << 16)) // 1 << 16 is 65536, the range of uint16
}

// GetAIChatTemperature() - returns the value for AI chat conversation temperature
func GetAIChatTemperature(defaultValue float32) float32 {
GPM_AI_CHAT_TEMPERATURE := strings.TrimSpace(os.Getenv("GPM_AI_CHAT_TEMPERATURE"))
Expand Down Expand Up @@ -408,6 +414,22 @@ func ListFiles(dir string, pattern string) ([]string, error) {
return matchingFiles, err
}

// MaxUint16() - returns the maximum uint16 value
func MaxUint16(a, b uint16, more ...uint16) uint16 {
var result uint16 = b
if a > b {
result = a
}

for _, c := range more {
if c > result {
result = c
}
}

return result
}

// OpenUrl() - opens a URL by the default application handler
func OpenUrl(url string) error {
var args []string
Expand Down

0 comments on commit a16f7e7

Please sign in to comment.