Compare commits
6 Commits
8889eccef6
...
master
Author | SHA1 | Date | |
---|---|---|---|
88e9502e5c
|
|||
1eff11b558
|
|||
615d03cc09
|
|||
05e148698a
|
|||
8e68218be8
|
|||
7291c3a19f
|
12
Makefile
Normal file
12
Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
.PHONY: build fmt lint
|
||||||
|
|
||||||
|
build: fmt lint
|
||||||
|
go build .
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
gofmt -w -r "interface{} -> any" .
|
||||||
|
go fmt ./...
|
||||||
|
|
||||||
|
lint:
|
||||||
|
go vet ./...
|
||||||
|
staticcheck ./...
|
29
README.md
Normal file
29
README.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Password generator
|
||||||
|
* can generate multiple passwords at once (separated by \n)
|
||||||
|
* can use Cyrillic/Japanese/Chinese/Emoji character sets
|
||||||
|
* uses at least one character from each character set
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go build .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```sh
|
||||||
|
Usage of ./passgen:
|
||||||
|
-L int length of the generated password (default 16)
|
||||||
|
-c int how many passwords to generate (default 1)
|
||||||
|
|
||||||
|
-l use lowercase ascii characters
|
||||||
|
-U use uppercase ascii characters
|
||||||
|
-n use numbers
|
||||||
|
-s use special characters
|
||||||
|
-S use spaces
|
||||||
|
--unicode-cyrillic use unicode Cyrillic characters
|
||||||
|
--unicode-chinese use unicode Chinese characters
|
||||||
|
--unicode-japanese use unicode Japanese characters
|
||||||
|
--unicode-emoji use unicode emoji characters
|
||||||
|
--all use all character sets
|
||||||
|
```
|
45
dictionary/sets/emoji.go
Normal file
45
dictionary/sets/emoji.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package sets
|
||||||
|
|
||||||
|
func emojiGenerateFromUnicodeRange(start, end rune) []int {
|
||||||
|
var emojis []int
|
||||||
|
for emoji := start; emoji <= end; emoji++ {
|
||||||
|
emojis = append(emojis, int(emoji))
|
||||||
|
|
||||||
|
// Variations with variation selectors
|
||||||
|
for vs := rune(0xFE00); vs <= rune(0xFE0F); vs++ {
|
||||||
|
combined := []rune{emoji, vs}
|
||||||
|
combinedStr := string(combined)
|
||||||
|
emojis = append(emojis, int([]rune(combinedStr)[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variations with skin tone modifiers
|
||||||
|
for st := rune(0x1F3FB); st <= rune(0x1F3FF); st++ {
|
||||||
|
combined := []rune{emoji, st}
|
||||||
|
combinedStr := string(combined)
|
||||||
|
emojis = append(emojis, int([]rune(combinedStr)[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return emojis
|
||||||
|
}
|
||||||
|
|
||||||
|
func Emoji() (dict []int) {
|
||||||
|
// Unicode ranges for emojis
|
||||||
|
ranges := [][]rune{
|
||||||
|
{0x1F600, 0x1F64F}, // Emoticons
|
||||||
|
{0x1F300, 0x1F5FF}, // Miscellaneous Symbols and Pictographs
|
||||||
|
{0x1F900, 0x1F9FF}, // Supplemental Symbols and Pictographs
|
||||||
|
{0x1F1E6, 0x1F1FF}, // Enclosed Alphanumeric Supplement (for flags)
|
||||||
|
{0x1F680, 0x1F6FF}, // Transport and Map Symbols
|
||||||
|
{0x2600, 0x26FF}, // Miscellaneous Symbols
|
||||||
|
{0x2700, 0x27BF}, // Dingbats
|
||||||
|
{0xFE00, 0xFE0F}, // Variation Selectors
|
||||||
|
{0x1F1E6, 0x1F1FF}, // Regional Indicator Symbols
|
||||||
|
{0xE0030, 0xE0039}, // Variation Selectors Supplement
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range ranges {
|
||||||
|
dict = append(dict, emojiGenerateFromUnicodeRange(r[0], r[1])...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
46
generator.go
46
generator.go
@ -2,44 +2,22 @@ package main
|
|||||||
|
|
||||||
import "math/rand/v2"
|
import "math/rand/v2"
|
||||||
|
|
||||||
func generatePassword(sets [][]int, passwordLength int) []int {
|
func generatePassword(sets [][]int, length int) []int {
|
||||||
numSets := len(sets)
|
password := make([]int, length)
|
||||||
totalLength := 0
|
|
||||||
for _, set := range sets {
|
// Ensure at least one character from each set
|
||||||
totalLength += len(set)
|
for i, charSet := range sets {
|
||||||
|
password[i] = charSet[rand.IntN(len(charSet))]
|
||||||
}
|
}
|
||||||
|
|
||||||
props := make([]float64, numSets)
|
// Fill the remaining positions with characters from all sets
|
||||||
for i := range props {
|
for i := range password[len(sets):] {
|
||||||
props[i] = float64(len(sets[i])) / float64(totalLength)
|
charSetIndex := rand.IntN(len(sets))
|
||||||
}
|
charSet := sets[charSetIndex]
|
||||||
|
password[len(sets)+i] = charSet[rand.IntN(len(charSet))]
|
||||||
numChars := make([]int, numSets)
|
|
||||||
for i := range numChars {
|
|
||||||
numChars[i] = int(props[i] * float64(passwordLength))
|
|
||||||
if numChars[i] == 0 {
|
|
||||||
numChars[i] = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalChars := 0
|
|
||||||
for _, n := range numChars {
|
|
||||||
totalChars += n
|
|
||||||
}
|
|
||||||
|
|
||||||
if totalChars < passwordLength {
|
|
||||||
numChars[0]++
|
|
||||||
} else if totalChars > passwordLength {
|
|
||||||
numChars[numSets-1]--
|
|
||||||
}
|
|
||||||
|
|
||||||
password := make([]int, 0, passwordLength)
|
|
||||||
for i, set := range sets {
|
|
||||||
for j := 0; j < numChars[i]; j++ {
|
|
||||||
password = append(password, set[rand.IntN(len(set))])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shuffle
|
||||||
rand.Shuffle(len(password), func(i, j int) {
|
rand.Shuffle(len(password), func(i, j int) {
|
||||||
password[i], password[j] = password[j], password[i]
|
password[i], password[j] = password[j], password[i]
|
||||||
})
|
})
|
||||||
|
4
go.mod
4
go.mod
@ -1,5 +1,3 @@
|
|||||||
module gitea.stuzer.link/stuzer05/passgen
|
module gitea.stuzer.link/stuzer05/passgen
|
||||||
|
|
||||||
go 1.20
|
go 1.23
|
||||||
|
|
||||||
require golang.org/x/text v0.9.0 // indirect
|
|
||||||
|
2
go.sum
2
go.sum
@ -1,2 +0,0 @@
|
|||||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|
||||||
|
17
main.go
17
main.go
@ -19,8 +19,10 @@ func main() {
|
|||||||
flagSetNumbers := flag.Bool("n", false, "use numbers")
|
flagSetNumbers := flag.Bool("n", false, "use numbers")
|
||||||
flagSetSpecialChars := flag.Bool("s", false, "use special characters")
|
flagSetSpecialChars := flag.Bool("s", false, "use special characters")
|
||||||
flagSetSpaces := flag.Bool("S", false, "use spaces")
|
flagSetSpaces := flag.Bool("S", false, "use spaces")
|
||||||
|
flagSetUnicodeCyrillic := flag.Bool("unicode-cyrillic", false, "use unicode cyrillic characters")
|
||||||
flagSetUnicodeJapanese := flag.Bool("unicode-japanese", false, "use unicode Japanese characters")
|
flagSetUnicodeJapanese := flag.Bool("unicode-japanese", false, "use unicode Japanese characters")
|
||||||
flagSetUnicodeChinese := flag.Bool("unicode-chinese", false, "use unicode Chinese characters")
|
flagSetUnicodeChinese := flag.Bool("unicode-chinese", false, "use unicode Chinese characters")
|
||||||
|
flagSetUnicodeEmoji := flag.Bool("unicode-emoji", false, "use unicode emoji characters")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@ -42,12 +44,14 @@ func main() {
|
|||||||
*flagSetSpecialChars = true
|
*flagSetSpecialChars = true
|
||||||
*flagSetSpaces = true
|
*flagSetSpaces = true
|
||||||
|
|
||||||
|
*flagSetUnicodeCyrillic = true
|
||||||
*flagSetUnicodeJapanese = true
|
*flagSetUnicodeJapanese = true
|
||||||
*flagSetUnicodeChinese = true
|
*flagSetUnicodeChinese = true
|
||||||
|
*flagSetUnicodeEmoji = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// use default password preset no sets were requested
|
// use default password preset no sets were requested
|
||||||
if !*flagSetAll && !*flagSetAsciiLowercase && !*flagSetAsciiUppercase && !*flagSetNumbers && !*flagSetSpecialChars && !*flagSetSpaces && !*flagSetUnicodeJapanese && !*flagSetUnicodeChinese {
|
if !*flagSetAll && !*flagSetAsciiLowercase && !*flagSetAsciiUppercase && !*flagSetNumbers && !*flagSetSpecialChars && !*flagSetSpaces && !*flagSetUnicodeCyrillic && !*flagSetUnicodeJapanese && !*flagSetUnicodeChinese && !*flagSetUnicodeEmoji {
|
||||||
*flagSetAsciiLowercase = true
|
*flagSetAsciiLowercase = true
|
||||||
*flagSetAsciiUppercase = true
|
*flagSetAsciiUppercase = true
|
||||||
*flagSetNumbers = true
|
*flagSetNumbers = true
|
||||||
@ -73,12 +77,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unicode
|
// unicode
|
||||||
|
if *flagSetUnicodeCyrillic {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Cyrillic()))
|
||||||
|
}
|
||||||
if *flagSetUnicodeJapanese {
|
if *flagSetUnicodeJapanese {
|
||||||
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Japanese()))
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Japanese()))
|
||||||
}
|
}
|
||||||
if *flagSetUnicodeChinese {
|
if *flagSetUnicodeChinese {
|
||||||
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Chinese()))
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Chinese()))
|
||||||
}
|
}
|
||||||
|
if *flagSetUnicodeEmoji {
|
||||||
|
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Emoji()))
|
||||||
|
}
|
||||||
|
|
||||||
// generate passwords
|
// generate passwords
|
||||||
for i := 0; i < *flagCount; i++ {
|
for i := 0; i < *flagCount; i++ {
|
||||||
@ -87,5 +97,10 @@ func main() {
|
|||||||
for _, i := range password {
|
for _, i := range password {
|
||||||
fmt.Printf("%c", i)
|
fmt.Printf("%c", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// new line
|
||||||
|
if i < *flagCount {
|
||||||
|
fmt.Print("\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user