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"
|
||||
|
||||
func generatePassword(sets [][]int, passwordLength int) []int {
|
||||
numSets := len(sets)
|
||||
totalLength := 0
|
||||
for _, set := range sets {
|
||||
totalLength += len(set)
|
||||
func generatePassword(sets [][]int, length int) []int {
|
||||
password := make([]int, length)
|
||||
|
||||
// Ensure at least one character from each set
|
||||
for i, charSet := range sets {
|
||||
password[i] = charSet[rand.IntN(len(charSet))]
|
||||
}
|
||||
|
||||
props := make([]float64, numSets)
|
||||
for i := range props {
|
||||
props[i] = float64(len(sets[i])) / float64(totalLength)
|
||||
}
|
||||
|
||||
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))])
|
||||
}
|
||||
// Fill the remaining positions with characters from all sets
|
||||
for i := range password[len(sets):] {
|
||||
charSetIndex := rand.IntN(len(sets))
|
||||
charSet := sets[charSetIndex]
|
||||
password[len(sets)+i] = charSet[rand.IntN(len(charSet))]
|
||||
}
|
||||
|
||||
// Shuffle
|
||||
rand.Shuffle(len(password), func(i, j int) {
|
||||
password[i], password[j] = password[j], password[i]
|
||||
})
|
||||
|
4
go.mod
4
go.mod
@ -1,5 +1,3 @@
|
||||
module gitea.stuzer.link/stuzer05/passgen
|
||||
|
||||
go 1.20
|
||||
|
||||
require golang.org/x/text v0.9.0 // indirect
|
||||
go 1.23
|
||||
|
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")
|
||||
flagSetSpecialChars := flag.Bool("s", false, "use special characters")
|
||||
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")
|
||||
flagSetUnicodeChinese := flag.Bool("unicode-chinese", false, "use unicode Chinese characters")
|
||||
flagSetUnicodeEmoji := flag.Bool("unicode-emoji", false, "use unicode emoji characters")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@ -42,12 +44,14 @@ func main() {
|
||||
*flagSetSpecialChars = true
|
||||
*flagSetSpaces = true
|
||||
|
||||
*flagSetUnicodeCyrillic = true
|
||||
*flagSetUnicodeJapanese = true
|
||||
*flagSetUnicodeChinese = true
|
||||
*flagSetUnicodeEmoji = true
|
||||
}
|
||||
|
||||
// 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
|
||||
*flagSetAsciiUppercase = true
|
||||
*flagSetNumbers = true
|
||||
@ -73,12 +77,18 @@ func main() {
|
||||
}
|
||||
|
||||
// unicode
|
||||
if *flagSetUnicodeCyrillic {
|
||||
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Cyrillic()))
|
||||
}
|
||||
if *flagSetUnicodeJapanese {
|
||||
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Japanese()))
|
||||
}
|
||||
if *flagSetUnicodeChinese {
|
||||
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Chinese()))
|
||||
}
|
||||
if *flagSetUnicodeEmoji {
|
||||
characterSets = append(characterSets, dictionary.ShuffleDictionarySet(sets.Emoji()))
|
||||
}
|
||||
|
||||
// generate passwords
|
||||
for i := 0; i < *flagCount; i++ {
|
||||
@ -87,5 +97,10 @@ func main() {
|
||||
for _, i := range password {
|
||||
fmt.Printf("%c", i)
|
||||
}
|
||||
|
||||
// new line
|
||||
if i < *flagCount {
|
||||
fmt.Print("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user