1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
|
package main
import (
"bufio"
"fmt"
"golang.org/x/term"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
// Basic constant definitions
const (
normNum = 10 // Number of normal passwords
specNum = 6 // Number of special passwords
passNum = 6 // Number of passphrases
maxLength = 255 // Maximum length of passwords
rangeMax = 42 // Maximum range for password length
rangeMin = 8 // Minimum range for password length
passWords = 8 // Number of words in passphrases
lower = "abcdefghijklmnopqrstuvwxyz"
upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
digit = "0123456789"
other = "!$%&#/()=?+-_,.;:<>[]{}|@*" // Special characters for special passwords
defaultFile = "/usr/share/dict/words" // Default path to the file of words used for passphrases
)
// Variables for different types of passwords
var (
alpha []string = strings.Split(lower+upper, "") // Array of alphabets (lowercase and uppercase)
alnum []string = append(alpha, strings.Split(digit, "")...) // Array of alphanumeric characters
every []string = append(alnum, strings.Split(other, "")...) // Array of all characters (alphabet, digit and special)
normal []string = append(alnum, "-", "_") // Characters for normal passwords
special []string = every // Characters for special passwords
wordlist string = defaultFile // Path to a dictionary to use for passphrases
length int = 0 // Length of passwords
)
func main() {
//
// Error handling
//
var err error
// Checking command line argument and environment variable for password length
if len(os.Args) == 2 {
length, err = strconv.Atoi(os.Args[1])
} else if len(os.Getenv("MAKEPASS_DEFAULT_LENGTH")) > 0 {
length, err = strconv.Atoi(os.Getenv("MAKEPASS_DEFAULT_LENGTH"))
}
// If there is an error in conversion, or if the length is not within limits, exit the program with an error message
if err != nil || (length > maxLength || length < 0) {
fmt.Printf("Error: Argument must be a whole number between 0 and %d.\n", maxLength)
os.Exit(1)
}
// Get wordlist from env
if len(os.Getenv("MAKEPASS_WORDLIST")) > 0 {
wordlist = os.Getenv("MAKEPASS_WORDLIST")
}
// Check if the wordlist file exists
if _, err := os.Stat(wordlist); os.IsNotExist(err) {
fmt.Println("The file", wordlist, "does not exist")
os.Exit(1)
}
//
// move on
//
// initialise the random seed
// TODO: Get seed from /dev/random, like we do in the perl- and zsh-versions?
rand.Seed(time.Now().UnixNano())
// get screen width
termWidth, _, err := term.GetSize(0)
// Read wordlist from file
file, err := os.Open(wordlist)
if err != nil {
fmt.Printf("failed to open file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var text []string
for scanner.Scan() {
text = append(text, scanner.Text())
}
file.Close()
//
// print passwords
//
// Generate and print normal and special passwords
printColumns("Normal passwords:", 10, normal, termWidth)
fmt.Println("")
printColumns("Passwords with special characters:", 6, special, termWidth)
fmt.Println("")
// Generate and print passphrases
for i := 0; i < passNum; i++ {
fmt.Println(passphrase(&text))
}
}
// Function to generate a random string of given length from given characters
func randstring(chars []string) string {
l := length
if length == 0 { // Random length if not specified
l = rand.Intn(rangeMax-rangeMin) + rangeMin
}
var str strings.Builder
// Add random characters to str
for i := 1; i <= l; i++ {
if i == 1 || i == l { // don't want passwords to start or end with special characters
str.WriteString(alnum[rand.Intn(len(alnum))])
} else {
str.WriteString(chars[rand.Intn(len(chars))])
}
}
return str.String()
}
// Function to generate and print passwords
func printColumns(title string, num int, chars []string, termWidth int) {
// column width
colWidth := rangeMax + 2
if length > 0 {
colWidth = length + 2
}
// number of colums
columns := termWidth / colWidth
if columns == 0 {
columns = 1
}
// Print title
fmt.Println(title)
// Print passwords in columns
for i := 1; i <= num; i++ {
fmt.Printf("%-[1]*[2]s", colWidth, randstring(chars))
if i%columns == 0 || (i == num && i%columns > 0) { // Add newlines
fmt.Println("")
}
}
}
// Function to generate passphrases
func passphrase(arrh *[]string) string {
text := *arrh
var str strings.Builder
for i := 0; i < passWords; i++ {
str.WriteString(text[rand.Intn(len(text))]) // Write a random word to the passphrase
if i != passWords-1 {
str.WriteString("-") // Add hyphen between words
}
}
return str.String()
}
|