diff --git a/.cirrus.yml b/.cirrus.yml deleted file mode 100644 index 7a384ce..0000000 --- a/.cirrus.yml +++ /dev/null @@ -1,23 +0,0 @@ -container: - image: golang:latest - -env: - GOPROXY: https://proxy.golang.org - -lint_task: - name: GolangCI Lint - container: - image: golangci/golangci-lint:latest - run_script: golangci-lint run -v --timeout 5m0s --out-format json > lint-report.json - always: - golangci_artifacts: - path: lint-report.json - type: text/json - format: golangci - -build_task: - modules_cache: - folder: $GOPATH/pkg/mod - get_script: go get github.com/wneessen/apg-go/cmd/apg - build_script: go build github.com/wneessen/apg-go/cmd/apg - test_script: go test github.com/wneessen/apg-go/cmd/apg diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 05d855a..0000000 --- a/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib -apg -bin -.go -build - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index c652c0d..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,128 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -github+coc@neessen.net. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index a8ebb10..0000000 --- a/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -## Build first -FROM golang:latest as builder -RUN mkdir /builddir -ADD . /builddir/ -WORKDIR /builddir -RUN CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags '-w -s -extldflags "-static"' -o apg-go \ - github.com/wneessen/apg-go/cmd/apg - -## Create scratch image -FROM scratch -LABEL maintainer="wn@neessen.net" -COPY ["docker-files/passwd", "/etc/passwd"] -COPY ["docker-files/group", "/etc/group"] -COPY --from=builder ["/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/cert.pem"] -COPY --chown=apg-go ["LICENSE", "/apg-go/LICENSE"] -COPY --chown=apg-go ["README.md", "/apg-go/README.md"] -COPY --from=builder --chown=apg-go ["/builddir/apg-go", "/apg-go/apg-go"] -WORKDIR /apg-go -USER apg-go -ENTRYPOINT ["/apg-go/apg-go"] \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index fe50abb..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Winni Neessen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 59ca941..0000000 --- a/README.md +++ /dev/null @@ -1,272 +0,0 @@ -# A "Automated Password Generator"-clone -[![Go Reference](https://pkg.go.dev/badge/github.com/wneessen/apg-go.svg)](https://pkg.go.dev/github.com/wneessen/apg-go) [![Go Report Card](https://goreportcard.com/badge/github.com/wneessen/apg-go)](https://goreportcard.com/report/github.com/wneessen/apg-go) [![Build Status](https://api.cirrus-ci.com/github/wneessen/apg-go.svg)](https://cirrus-ci.com/github/wneessen/apg-go) ![CodeQL workflow](https://github.com/wneessen/apg-go/actions/workflows/codeql-analysis.yml/badge.svg) buy ma a coffee - -_apg-go_ is a simple APG-like password generator written in Go. It tries to replicate the -functionality of the -"[Automated Password Generator](https://web.archive.org/web/20130313042424/http://www.adel.nursat.kz:80/apg)", -which hasn't been maintained since 2003. Since more and more Unix distributions are abondoning the tool, I was -looking for an alternative. FreeBSD for example recommends "security/makepasswd", which is written in Perl -but requires a lot of dependency packages and doesn't offer the feature-set/flexibility of APG. - -Since FIPS-181 (pronouncable passwords) has been withdrawn in 2015, apg-go does not follow this standard. Instead -it implements the [Koremutake Syllables System](https://shorl.com/koremutake.php) in its pronouncable password mode. - -## Installation - -### Docker -There is a ready-to-use Docker image hosted on Github. - -* Download the image: - ```shell - $ docker pull ghcr.io/wneessen/apg-go:main - ``` -* Run the image: - ```shell - $ docker run ghcr.io/wneessen/apg-go:main - ``` - -### Ports/Packages -#### FreeBSD -apg-go can be found as `/security/apg` in the [FreeBSD ports](https://cgit.freebsd.org/ports/tree/security/apg) -tree. -#### Arch Linux -Find apg-go in [Arch Linux AUR](https://aur.archlinux.org/packages/apg-go/). \ -Alternatively use the [PKGBUILD](https://github.com/wneessen/apg-go/tree/main/buildfiles/arch-linux) file -in this git repository -### Binary releases -#### Linux/BSD/MacOS -* Download release - ```sh - $ curl -LO https://github.com/wneessen/apg-go/releases/download/v/apg-v--.tar.gz - $ curl -LO https://github.com/wneessen/apg-go/releases/download/v/apg-v--.tar.gz.sha256 - ``` -* Verify the checksum - ```sh - $ sha256 apg-v--.tar.gz - $ cat apg-v--.tar.gz.sha256 - ``` - **Make sure the checksum of the downloaded file and the checksum in the .sha256 match** -* Extract archive - ```sh - $ tar xzf apg-v--.tar.gz - ``` -* Execute - ```sh - $ ./apg - ``` -#### Windows -* Download release - ```PowerShell - PS> Invoke-RestMethod -Uri https://github.com/wneessen/apg-go/releases/download/v/apg-v-windows-.zip -OutFile apg-v-windows-.zip - PS> Invoke-RestMethod -Uri https://github.com/wneessen/apg-go/releases/download/v/apg-v-windows-.zip.sha256 -OutFile apg-v-windows-.zip.sha256 - ``` -* Verify the checksum - ```PowerShell - PS> Get-FileHash apg-v-windows-.zip | Format-List - PS> type apg-v-windows-.zip.sha256 - ``` - **Make sure the checksum of the downloaded file and the checksum in the .sha256 match** -* Extract archive - ```PowerShell - PS> Expand-Archive -LiteralPath apg-v-windows- - ``` -* Execute - ```PowerShell - PS> cd apg-v-windows- - PS> apg.exe - ``` - -### Sources -* Download sources - ```sh - $ curl -LO https://github.com/wneessen/apg-go/archive/refs/tags/v.tar.gz - ``` -* Extract source - ```sh - $ tar xzf v.tar.gz - ``` -* Build binary - ```sh - $ cd apg-go- - $ go build -o apg ./... - ``` -* Execute the brand new binary - ```sh - $ ./apg - ``` - -### Systemwide installation -It is recommed to install apg in a directory of your ```$PATH``` environment. To do so run: -(In this example we use ```/usr/local/bin``` as system-wide binary path. YMMV) -```sh -$ sudo cp apg /usr/local/bin/apg -``` - -## Programmatic interface -Since v0.4.0 the CLI and the main package functionality have been separated from each other, which makes -it easier to use the `apg-go` package in other Go code as well. This way you can make of the password -generation in your own code without having to rely on the actual apg-go binary. - -Code examples on how to use the package can be found in the [example-code](example-code) directory. - -## Usage examples -### Default behaviour -By default apg-go will generate 6 passwords, with a minimum length of 12 characters and a -maxiumum length of 20 characters. The generated password will use a character set constructed -from lower case, upper case and numeric characters. -```shell -$ ./apg-go -R8rCC8bw5NvJmTUK2g -cHB9qogTbfdzFgnH -hoHfpWAHHSNa4Q -QyjscIsZkQGh -904YqsU5SnoqLo2w -utdFKXdeiXFzM -``` -### Modifying the character sets -#### Old style -Let's assume you want to generate a single password, constructed out of upper case, numeric -and special characters. Since lower case is part of the default set, you would need to disable them -by setting the `-L` parameter. In addition you would set the `-S` parameter to enable special -characters. Finally the parameter `-n 1` is needed to keep apg-go from generating more than one -password: -```shell -$ ./apg-go -n 1 -L -S -XY7>}H@5U40&_A1*9I$ -``` - -#### New/modern style -Since the old style switches can be kind of confusing, it is recommended to use the "new style" -parameters instead. The new style is all combined in the `-M` parameter. Using the upper case -version of a parameter argument enables a feature, while the lower case version disabled it. The -previous example could be represented like this in new style: -```shell -$ ./apg-go -n 1 -M lUSN -$B|~sudhtyDBu -``` - -### Password spelling -If you need to read out a password, it can be helpful to know the corresponding word for that character in -the phonetic alphabet. By setting the `-l` parameter, agp-go will provide you with the phonetic spelling -(english language) of your newly created password: -```shell -$ ./apg-go -n 1 -M LUSN -H -E : -l -fUTDKeFsU+zn3r= (foxtrot/Uniform/Tango/Delta/Kilo/echo/Foxtrot/sierra/Uniform/PLUS_SIGN/zulu/november/THREE/romeo/EQUAL_SIGN) -``` - -### Pronouncable passwords -Since v0.4.0 apg-go supports pronouncable passwords, anologous to the original c-apg using the `-a 0` -flag. The original c-apg implemented FIPS-181, which was withdrawn in 2015 for generating pronouncable -passwords. Since the standard is not recommended anymore, `apg-go` instead make use of the -[Koremutake Syllables System](https://shorl.com/koremutake.php). Similar to the original apg, `agp-go` -will automatically randomly add special characters and number (from the human-readable pool) to each -generated pronouncable password. Additionally it will perform a "coinflip" for each Koremutake syllable -and decided if it should switch the case of one of the characters to an upper-case character. - -Using the `-t` parameter, `apg-go` will display a spelled out version of the pronouncable password, where -each syllable or number/special character is seperated with a "-" (dash) and if the syllable is not a -Koremutake syllable the character will be spelled out the same was as with activated `-l` in the -non-pronouncable password mode (`-a 1`). - -**Note on password length**: The `-m` and `-x` parameters will work in prouncable password mode, but -please keep in mind, that due to the nature how syllables work, your generated password might exceed -the desired length by one complete syllable (which can be up to 3 characters long). - -**Security consideration:** Please keep in mind, that pronouncable passwords are less secure then truly -randomly created passwords, due to the nature how syllables work. As a rule of thumb, it is recommended -to multiply the length of your generated pronouncable passwords by at least 1.5 times, compared to truly -randomly generated passwords. It might also be helpful to run the pronoucable password mode with enabled -"[HIBP](#have-i-been-pwned)" flag, so that each generated password is automatically checked against "Have I Been Pwned" -database. -```shell -$ ./apg-go -a 0 -n 1 -KebrutinernMy - -$ ./apg-go -a 0 -n 1 -m 15 -x 15 -t -pEnbocydrageT*En (pEn-bo-cy-dra-geT-ASTERISK-En) -``` - -### Have I Been Pwned -Even though, the passwords that apg-go generated for you, are secure, there is a minimal chance, that -someone on the planet used exactly the same password before and that this person was part of an -internet leak or hack, which exposed the password to the public. Such passwords are not considered -secure anymore as they usually land on public available password lists, that are used by crackers. - -To be on the safe side, you can use the `-p` parameter, to enable a HIBP check. When the feature is -enabled, apg-go will check the HIBP database at https://haveibeenpwned.com if that password has been -leaked before and provide you with a warning if that is the case. - -Please be aware, that this is a live check against the HIBP API, which not only requires internet -connectivity, but also might take between 500ms to 1s to complete. When you generating a bigger list -of password `-n 100`, the process could take much longer than without the `-p` feature enabled. - -## CLI parameters -_apg-go_ replicates most of the parameters of the original c-apg. Some parameters are different though: - -- `-a `: Choose password generation algorithm (Default: 1) - - `0`: Pronouncable password generation (Koremutake syllables) - - `1`: Random password generation according to password modes/flags -- `-m `: The minimum length of the password to be generated (Default: 12) -- `-x `: The maximum length of the password to be generated (Default: 20) -- `-n `: The amount of passwords to be generated (Default: 6) -- `-E `: Do not use the specified characters in generated passwords -- `-M <[LUNSHClunshc]>`: New style password parameters (upper-case enables, lower-case disables) -- `-L`: Use lower-case characters in passwords (Default: on) -- `-U`: Use upper-case characters in passwords (Default: on) -- `-N`: Use numeric characters in passwords (Default: on) -- `-S`: Use special characters in passwords (Default: off) -- `-H`: Avoid ambiguous characters in passwords (i. e.: 1, l, I, o, O, 0) (Default: off) -- `-C`: Generate complex passwords (implies -L -U -N -S and disables -H) (Default: off) -- `-l`: Spell generated passwords in random password mode (Default: off) -- `-t`: Spell generated passwords in pronouncable password mode (Default: off) -- `-p`: Check the HIBP database if the generated passwords was found in a leak before (Default: off) // *this feature requires internet connectivity* -- `-h`: Show a CLI help text -- `-v`: Show the version number - -## Contributors -Thanks to the following people for contributing to the apg-go codebase: -* [Romain Tartière](https://github.com/smortex) -* [Abraham Ingersoll](https://github.com/aberoham) -* [Vinícius Zavam](https://github.com/egypcio) (Maintaining the FreeBSD port) diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index d41fcde..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,6 +0,0 @@ -# Security Policy - -## Reporting a Vulnerability - -Please send a mail to apg-go@pebcak.de when you found a security issue in apg-go, even when you are not 100% certain -that it is actually a security issue. Typically, you will receive an answer within a day or even within a few hours. diff --git a/buildfiles/arch-linux/PKGBUILD b/buildfiles/arch-linux/PKGBUILD deleted file mode 100644 index fcdb040..0000000 --- a/buildfiles/arch-linux/PKGBUILD +++ /dev/null @@ -1,32 +0,0 @@ -# Maintainer: "Winni Neessen (https://pebcak.de) - -pkgname=apg-go -pkgver=0.4.1 -pkgrel=1 -pkgdesc='A "Automated Password Generator"-clone' -arch=('i686' 'x86_64' 'armv6h' 'armv7h' 'aarch64') -url='https://github.com/wneessen/apg-go' -license=('MIT') -makedepends=('go') -source=("https://github.com/wneessen/${pkgname}/archive/refs/tags/v${pkgver}.tar.gz") -sha256sums=('64769495843e2c59fc5513a106e58f8751f1649ff8bf6c38cd141322523deea8') - -prepare() { - cd "${pkgname}-${pkgver}" - mkdir -p build/ -} - -build() { - cd "${pkgname}-${pkgver}" - go build -ldflags="-s -w" -o build/${pkgname} github.com/wneessen/apg-go/cmd/apg -} - -package() { - # binary - install -D -m755 "${srcdir}/${pkgname}-${pkgver}/build/${pkgname}" \ - "${pkgdir}/usr/bin/apg" - - # license - install -Dm644 "${srcdir}/${pkgname}-${pkgver}/LICENSE" \ - "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" -} diff --git a/buildfiles/openbsd/Makefile b/buildfiles/openbsd/Makefile deleted file mode 100644 index 08fe24b..0000000 --- a/buildfiles/openbsd/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# $OpenBSD$ - -COMMENT = "automated password generator" clone written in Go - -GH_ACCOUNT = wneessen -GH_PROJECT = apg-go -GH_TAGNAME = v0.3.2 - -CATEGORIES = security - -MAINTAINER = Winni Neessen - -# MIT -PERMIT_PACKAGE = Yes - -MODULES = lang/go -MODGO_TYPE = bin - -ALL_TARGET = wneessen/apg-go/cmd/apg - -.include \ No newline at end of file diff --git a/buildfiles/openbsd/distinfo b/buildfiles/openbsd/distinfo deleted file mode 100644 index c0bac84..0000000 --- a/buildfiles/openbsd/distinfo +++ /dev/null @@ -1,2 +0,0 @@ -SHA256 (apg-go-0.3.2.tar.gz) = QvCC0vVNHLIOHW1jwdkjJVtxEVHJNwQfZBZBgHWM4OQ= -SIZE (apg-go-0.3.2.tar.gz) = 20114 \ No newline at end of file diff --git a/buildfiles/openbsd/pkg/DESCR b/buildfiles/openbsd/pkg/DESCR deleted file mode 100644 index 0a6857e..0000000 --- a/buildfiles/openbsd/pkg/DESCR +++ /dev/null @@ -1,14 +0,0 @@ -apg-go is a simple APG-like password generator written in Go. - -It tries to replicate the functionality of the "Automated Password Generator", -which hasn't been maintained since 2003. Since more and more Unix distributions -are abondoning the tool, I was looking for an alternative. FreeBSD for example -recommends "security/makepasswd", which is written in Perl but requires a lot -of dependency packages and doesn't offer the feature-set/flexibility of APG. - -Since FIPS-181 (pronouncable passwords) has been withdrawn in 2015, there is -no use in replicating that feature. Therfore apg-go does not support -pronouncable passwords. - -For feature requests or bug reports, please create an issue in the Github -repository at https://github.com/wneessen/apg-go \ No newline at end of file diff --git a/buildfiles/openbsd/pkg/PLIST b/buildfiles/openbsd/pkg/PLIST deleted file mode 100644 index 0b10474..0000000 --- a/buildfiles/openbsd/pkg/PLIST +++ /dev/null @@ -1,2 +0,0 @@ -@comment $OpenBSD: PLIST,v$ -@bin bin/apg-go \ No newline at end of file diff --git a/chars/chars.go b/chars/chars.go deleted file mode 100644 index 90a8011..0000000 --- a/chars/chars.go +++ /dev/null @@ -1,64 +0,0 @@ -package chars - -import ( - "github.com/wneessen/apg-go/config" - "regexp" -) - -// PwLowerCharsHuman is the range of lower-case characters in human-readable mode -const PwLowerCharsHuman string = "abcdefghjkmnpqrstuvwxyz" - -// PwUpperCharsHuman is the range of upper-case characters in human-readable mode -const PwUpperCharsHuman string = "ABCDEFGHJKMNPQRSTUVWXYZ" - -// PwLowerChars is the range of lower-case characters -const PwLowerChars string = "abcdefghijklmnopqrstuvwxyz" - -// PwUpperChars is the range of upper-case characters -const PwUpperChars string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - -// PwSpecialCharsHuman is the range of special characters in human-readable mode -const PwSpecialCharsHuman string = "\"#%*+-/:;=\\_|~" - -// PwSpecialChars is the range of special characters -const PwSpecialChars string = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" - -// PwNumbersHuman is the range of numbers in human-readable mode -const PwNumbersHuman string = "23456789" - -// PwNumbers is the range of numbers -const PwNumbers string = "1234567890" - -// GetRange provides the range of available characters based on configured parameters -func GetRange(config *config.Config) string { - pwUpperChars := PwUpperChars - pwLowerChars := PwLowerChars - pwNumbers := PwNumbers - pwSpecialChars := PwSpecialChars - if config.HumanReadable { - pwUpperChars = PwUpperCharsHuman - pwLowerChars = PwLowerCharsHuman - pwNumbers = PwNumbersHuman - pwSpecialChars = PwSpecialCharsHuman - } - - var charRange string - if config.UseLowerCase { - charRange = charRange + pwLowerChars - } - if config.UseUpperCase { - charRange = charRange + pwUpperChars - } - if config.UseNumber { - charRange = charRange + pwNumbers - } - if config.UseSpecial { - charRange = charRange + pwSpecialChars - } - if config.ExcludeChars != "" { - regExp := regexp.MustCompile("[" + regexp.QuoteMeta(config.ExcludeChars) + "]") - charRange = regExp.ReplaceAllLiteralString(charRange, "") - } - - return charRange -} diff --git a/chars/koremutake.go b/chars/koremutake.go deleted file mode 100644 index 6d98636..0000000 --- a/chars/koremutake.go +++ /dev/null @@ -1,22 +0,0 @@ -package chars - -// KoremutakeSyllables is a slightly modified Koremutake syllables list based on -// the mechanism described on https://shorl.com/koremutake.php -var KoremutakeSyllables = []string{"ba", "be", "bi", "bo", "bu", "by", "da", "de", "di", - "do", "du", "dy", "fe", "fi", "fo", "fu", "fy", "ga", "ge", "gi", "go", "gu", - "gy", "ha", "he", "hi", "ho", "hu", "hy", "ja", "je", "ji", "jo", "ju", "jy", - "ka", "ke", "ko", "ku", "ky", "la", "le", "li", "lo", "lu", "ly", "ma", - "me", "mi", "mo", "mu", "my", "na", "ne", "ni", "no", "nu", "ny", "pa", "pe", - "pi", "po", "pu", "py", "ra", "re", "ri", "ro", "ru", "ry", "sa", "se", - "si", "so", "su", "sy", "ta", "te", "ti", "to", "tu", "ty", "va", "ve", "vi", - "vo", "vu", "vy", "bra", "bre", "bri", "bro", "bru", "bry", "dra", "dre", - "dri", "dro", "dru", "dry", "fra", "fre", "fri", "fro", "fru", "fry", "gra", - "gre", "gri", "gro", "gru", "gry", "pra", "pre", "pri", "pro", "pru", - "pry", "sta", "ste", "sti", "sto", "stu", "sty", "tra", "tre", "er", "ed", - "in", "ex", "al", "en", "an", "ad", "or", "at", "ca", "ap", "el", "ci", "an", - "et", "it", "ob", "of", "af", "au", "cy", "im", "op", "co", "up", "ing", - "con", "ter", "com", "per", "ble", "der", "cal", "man", "est", "for", "mer", - "col", "ful", "get", "low", "son", "tle", "day", "pen", "pre", "ten", - "tor", "ver", "ber", "can", "ple", "fer", "gen", "den", "mag", "sub", "sur", - "men", "min", "out", "tal", "but", "cit", "cle", "cov", "dif", "ern", - "eve", "hap", "ket", "nal", "sup", "ted", "tem", "tin", "tro", "tro"} diff --git a/cmd/apg/apg.go b/cmd/apg/apg.go deleted file mode 100644 index 39b43ec..0000000 --- a/cmd/apg/apg.go +++ /dev/null @@ -1,148 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "github.com/wneessen/apg-go/chars" - "github.com/wneessen/apg-go/config" - "github.com/wneessen/apg-go/random" - "github.com/wneessen/apg-go/spelling" - "github.com/wneessen/go-hibp" - "log" - "os" - "runtime" - "strings" - "time" -) - -// VersionString represents the current version of the apg-go CLI -const VersionString string = "0.4.1" - -// Help text -const usage = `apg-go // A "Automated Password Generator"-clone -Copyright (c) 2021 Winni Neessen - -apg [-a ] [-m ] [-x ] [-L] [-U] [-N] [-S] [-H] [-C] - [-l] [-M mode] [-E char_string] [-n num_of_pass] [-v] [-h] [-t] - -Options: - -a ALGORITH Choose the password generation algorithm (Default: 1) - - 0: pronounceable password generation (koremutake syllables) - - 1: random password generation according to password modes/flags - -m LENGTH Minimum length of the password to be generated (Default: 12) - -x LENGTH Maximum length of the password to be generated (Default: 20) - -n NUMBER Amount of password to be generated (Default: 6) - -E CHARS List of characters to be excluded in the generated password - -M [LUNSHClunshc] New style password parameters (upper case: on, lower case: off) - -L Use lower case characters in passwords (Default: on) - -U Use upper case characters in passwords (Default: on) - -N Use numeric characters in passwords (Default: on) - -S Use special characters in passwords (Default: off) - -H Avoid ambiguous characters in passwords (i. e.: 1, l, I, O, 0) (Default: off) - -C Enable complex password mode (implies -L -U -N -S and disables -H) (Default: off) - -l Spell generated passwords in phonetic alphabet (Default: off) - -p Check the HIBP database if the generated passwords was found in a leak before (Default: off) - - Note: this feature requires internet connectivity - -h Show this help text - -v Show version string` - -// Main function that generated the passwords and returns them -func main() { - // Log configuration - log.SetFlags(log.Ltime | log.Ldate | log.Lshortfile) - - // Read and parse flags - flag.Usage = func() { _, _ = fmt.Fprintf(os.Stderr, "%s\n", usage) } - var cfgObj = config.New() - - // Show version and exit - if cfgObj.ShowVersion { - _, _ = os.Stderr.WriteString(`apg-go // A "Automated Password Generator"-clone v` + VersionString + "\n") - _, _ = os.Stderr.WriteString("OS: " + runtime.GOOS + " // Arch: " + runtime.GOARCH + " \n") - _, _ = os.Stderr.WriteString("(C) 2021 by Winni Neessen\n") - os.Exit(0) - } - - pwList := make([]string, 0) - sylList := map[string][]string{} - - // Choose the type of password generation based on the selected algo - for i := 0; i < cfgObj.NumOfPass; i++ { - pwLength := config.GetPwLengthFromParams(&cfgObj) - - switch cfgObj.PwAlgo { - case 0: - pwString := "" - pwSyls := make([]string, 0) - - charSylSet := chars.KoremutakeSyllables - charSylSet = append(charSylSet, - strings.Split(chars.PwNumbersHuman, "")...) - charSylSet = append(charSylSet, - strings.Split(chars.PwSpecialCharsHuman, "")...) - charSylSetLen := len(charSylSet) - for len(pwString) < pwLength { - randNum, err := random.GetNum(charSylSetLen) - if err != nil { - log.Fatalf("error generating Koremutake syllable: %s", err) - } - nextSyl := charSylSet[randNum] - if random.CoinFlip() { - sylLen := len(nextSyl) - charPos, err := random.GetNum(sylLen) - if err != nil { - log.Fatalf("error generating random number: %s", err) - } - ucChar := string(nextSyl[charPos]) - nextSyl = strings.ReplaceAll(nextSyl, ucChar, strings.ToUpper(ucChar)) - } - - pwString += nextSyl - pwSyls = append(pwSyls, nextSyl) - } - pwList = append(pwList, pwString) - sylList[pwString] = pwSyls - default: - charRange := chars.GetRange(&cfgObj) - pwString, err := random.GetChar(charRange, pwLength) - if err != nil { - log.Fatalf("error generating random character range: %s\n", err) - } - pwList = append(pwList, pwString) - } - } - - for _, p := range pwList { - switch cfgObj.OutputMode { - case 1: - spelledPw, err := spelling.String(p) - if err != nil { - log.Fatalf("error spelling out password: %s\n", err) - } - fmt.Printf("%v (%v)\n", p, spelledPw) - case 2: - fmt.Printf("%s", p) - if cfgObj.SpellPron { - spelledPw, err := spelling.Koremutake(sylList[p]) - if err != nil { - log.Fatalf("error spelling out password: %s", err) - } - fmt.Printf(" (%s)", spelledPw) - } - fmt.Println() - default: - fmt.Println(p) - } - - if cfgObj.CheckHibp { - hc := hibp.New(hibp.WithHTTPTimeout(time.Second*2), hibp.WithPwnedPadding()) - pwnObj, _, err := hc.PwnedPassAPI.CheckPassword(p) - if err != nil { - log.Printf("unable to check HIBP database: %v", err) - } - if pwnObj != nil && pwnObj.Count != 0 { - fmt.Print("^-- !!WARNING: The previously generated password was found in HIBP database. Do not use it!!\n") - } - } - } -} diff --git a/cmd/apg/apg_test.go b/cmd/apg/apg_test.go deleted file mode 100644 index a9febf0..0000000 --- a/cmd/apg/apg_test.go +++ /dev/null @@ -1,288 +0,0 @@ -package main - -import ( - "github.com/wneessen/apg-go/chars" - "github.com/wneessen/apg-go/config" - "github.com/wneessen/apg-go/random" - "github.com/wneessen/apg-go/spelling" - "testing" -) - -var cfgObj config.Config - -// Make sure the flags are initialized -var _ = func() bool { - testing.Init() - cfgObj = config.New() - return true -}() - -// Test getRandNum with max 1000 -func TestGetRandNum(t *testing.T) { - testTable := []struct { - testName string - givenVal int - maxRet int - minRet int - shouldFail bool - }{ - {"randNum up to 1000", 1000, 1000, 0, false}, - {"randNum should be 1", 1, 1, 0, false}, - {"randNum should fail on 0", 0, 0, 0, true}, - {"randNum should fail on negative", -1, 0, 0, true}, - } - - for _, testCase := range testTable { - t.Run(testCase.testName, func(t *testing.T) { - randNum, err := random.GetNum(testCase.givenVal) - if testCase.shouldFail { - if err == nil { - t.Errorf("Random number generation succeeded but was expected to fail. Given: %v, returned: %v", - testCase.givenVal, randNum) - } - } else { - if err != nil { - t.Errorf("Random number generation failed: %v", err.Error()) - } - if randNum > testCase.maxRet { - t.Errorf("Random number generation returned too big value. Given %v, expected max: %v, got: %v", - testCase.givenVal, testCase.maxRet, randNum) - } - if randNum < testCase.minRet { - t.Errorf("Random number generation returned too small value. Given %v, expected max: %v, got: %v", - testCase.givenVal, testCase.minRet, randNum) - } - } - }) - } -} - -// Test Pwlength -func TestGenLength(t *testing.T) { - testTable := []struct { - testName string - minLength int - maxLength int - }{ - {"pwLength defaults", config.DefaultMinLength, config.DefaultMaxLength}, - {"pwLength 0 to 1", 0, 1}, - {"pwLength 1 to 10", 0, 10}, - {"pwLength 10 to 100", 10, 100}, - } - - charRange := chars.GetRange(&cfgObj) - for _, testCase := range testTable { - t.Run(testCase.testName, func(t *testing.T) { - cfgObj.MinPassLen = testCase.minLength - cfgObj.MaxPassLen = testCase.maxLength - pwLength := config.GetPwLengthFromParams(&cfgObj) - for i := 0; i < 1000; i++ { - pwString, err := random.GetChar(charRange, pwLength) - if err != nil { - t.Errorf("getRandChar returned an error: %q", err) - } - retLen := len(pwString) - if retLen > testCase.maxLength { - t.Errorf("Generated password length too long. GivenMin %v, GivenMax: %v, Returned length %v", - testCase.minLength, testCase.maxLength, retLen) - } - if retLen < testCase.minLength { - t.Errorf("Generated password length too short. GivenMin %v, GivenMax: %v, Returned length %v", - testCase.minLength, testCase.maxLength, retLen) - } - } - }) - } -} - -// Test getRandChar -func TestGetRandChar(t *testing.T) { - t.Run("return_value_is_A_B_or_C", func(t *testing.T) { - charRange := "ABC" - randChar, err := random.GetChar(charRange, 1) - if err != nil { - t.Fatalf("Random character generation failed => %v", err.Error()) - } - if randChar != "A" && randChar != "B" && randChar != "C" { - t.Fatalf("Random character generation failed. Expected A, B or C but got: %v", randChar) - } - }) - - t.Run("return_value_has_specific_length", func(t *testing.T) { - charRange := "ABC" - randChar, err := random.GetChar(charRange, 1000) - if err != nil { - t.Fatalf("Random character generation failed => %v", err.Error()) - } - if len(randChar) != 1000 { - t.Fatalf("Generated random characters with 1000 chars returned wrong amount of chars: %v", - len(randChar)) - } - }) - - t.Run("fail", func(t *testing.T) { - charRange := "ABC" - randChar, err := random.GetChar(charRange, -2000) - if err == nil { - t.Fatalf("Generated random characters expected to fail, but returned a value => %v", - randChar) - } - }) -} - -// Test getCharRange() with different cfgObj settings -func TestGetCharRange(t *testing.T) { - lowerCaseBytes := []int{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', - 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} - lowerCaseHumanBytes := []int{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', - 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} - upperCaseBytes := []int{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'} - upperCaseHumanBytes := []int{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', - 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'} - numberBytes := []int{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} - numberHumanBytes := []int{'2', '3', '4', '5', '6', '7', '8', '9'} - specialBytes := []int{'!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', - ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'} - specialHumanBytes := []int{'"', '#', '%', '*', '+', '-', '/', ':', ';', '=', '\\', '_', '|', '~'} - testTable := []struct { - testName string - allowedBytes []int - useLowerCase bool - useUpperCase bool - useNumber bool - useSpecial bool - humanReadable bool - }{ - {"lowercase_only", lowerCaseBytes, true, false, false, false, false}, - {"lowercase_only_human", lowerCaseHumanBytes, true, false, false, false, true}, - {"uppercase_only", upperCaseBytes, false, true, false, false, false}, - {"uppercase_only_human", upperCaseHumanBytes, false, true, false, false, true}, - {"number_only", numberBytes, false, false, true, false, false}, - {"number_only_human", numberHumanBytes, false, false, true, false, true}, - {"special_only", specialBytes, false, false, false, true, false}, - {"special_only_human", specialHumanBytes, false, false, false, true, true}, - } - - for _, testCase := range testTable { - t.Run(testCase.testName, func(t *testing.T) { - cfgObj.UseLowerCase = testCase.useLowerCase - cfgObj.UseUpperCase = testCase.useUpperCase - cfgObj.UseNumber = testCase.useNumber - cfgObj.UseSpecial = testCase.useSpecial - cfgObj.HumanReadable = testCase.humanReadable - charRange := chars.GetRange(&cfgObj) - for _, curChar := range charRange { - searchAllowedBytes := containsByte(testCase.allowedBytes, int(curChar), t) - if !searchAllowedBytes { - t.Errorf("Character range returned invalid value: %v", string(curChar)) - } - } - }) - } -} - -// Test Conversions -func TestConvert(t *testing.T) { - testTable := []struct { - testName string - givenVal byte - expVal string - shouldFail bool - }{ - {"convert_A_to_Alfa", 'A', "Alfa", false}, - {"convert_a_to_alfa", 'a', "alfa", false}, - {"convert_0_to_ZERO", '0', "ZERO", false}, - {"convert_/_to_SLASH", '/', "SLASH", false}, - } - - for _, testCase := range testTable { - t.Run(testCase.testName, func(t *testing.T) { - charToString, err := spelling.ConvertCharToName(testCase.givenVal) - if testCase.shouldFail { - if err == nil { - t.Errorf("Character to string conversion succeeded but was expected to fail. Given: %v, returned: %v", - testCase.givenVal, charToString) - } - } else { - if err != nil { - t.Errorf("Character to string conversion failed: %v", err.Error()) - } - if charToString != testCase.expVal { - t.Errorf("Character to String conversion fail. Given: %q, expected: %q, got: %q", - testCase.givenVal, testCase.expVal, charToString) - } - } - }) - } - - t.Run("all_chars_must_return_a_conversion_string", func(t *testing.T) { - cfgObj.UseUpperCase = true - cfgObj.UseLowerCase = true - cfgObj.UseNumber = true - cfgObj.UseSpecial = true - cfgObj.HumanReadable = false - charRange := chars.GetRange(&cfgObj) - for _, curChar := range charRange { - _, err := spelling.ConvertCharToName(byte(curChar)) - if err != nil { - t.Fatalf("Character to string conversion failed: %v", err.Error()) - } - } - }) - t.Run("spell_Ab!_to_strings", func(t *testing.T) { - pwString := "Ab!" - spelledString, err := spelling.String(pwString) - if err != nil { - t.Fatalf("password spelling failed: %v", err.Error()) - } - if spelledString != "Alfa/bravo/EXCLAMATION_POINT" { - t.Fatalf( - "Spelling pwString 'Ab!' is expected to provide 'Alfa/bravo/EXCLAMATION_POINT', but returned: %q", - spelledString) - } - }) -} - -// Benchmark: Random number generation -func BenchmarkGetRandNum(b *testing.B) { - for i := 0; i < b.N; i++ { - _, _ = random.GetNum(100000) - } -} - -// Benchmark: Random char generation -func BenchmarkGetRandChar(b *testing.B) { - charRange := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\"#/!\\$%&+-*.,?=()[]{}:;~^|" - for i := 0; i < b.N; i++ { - _, _ = random.GetChar(charRange, 20) - } -} - -// Benchmark: Random char generation -func BenchmarkConvertChar(b *testing.B) { - - cfgObj.UseUpperCase = true - cfgObj.UseLowerCase = true - cfgObj.UseNumber = true - cfgObj.UseSpecial = true - cfgObj.HumanReadable = false - charRange := chars.GetRange(&cfgObj) - for i := 0; i < b.N; i++ { - charToConv, _ := random.GetChar(charRange, 1) - charBytes := []byte(charToConv) - _, _ = spelling.ConvertCharToName(charBytes[0]) - } -} - -// Contains function to search a given slice for values -func containsByte(allowedBytes []int, currentChar int, t *testing.T) bool { - t.Helper() - - for _, charInt := range allowedBytes { - if charInt == currentChar { - return true - } - } - return false -} diff --git a/config/config.go b/config/config.go deleted file mode 100644 index eaee823..0000000 --- a/config/config.go +++ /dev/null @@ -1,194 +0,0 @@ -package config - -import ( - "flag" - "github.com/wneessen/apg-go/random" - "log" -) - -// Config is a struct that holds the different config parameters for the apg-go -// application -type Config struct { - MinPassLen int // Minimum password length - MaxPassLen int // Maximum password length - NumOfPass int // Number of passwords to be generated - useComplex bool // Force complex password generation (implies all other Use* Options to be true) - UseLowerCase bool // Allow lower-case chars in passwords - UseUpperCase bool // Allow upper-case chars in password - UseNumber bool // Allow numbers in passwords - UseSpecial bool // Allow special chars in passwords - HumanReadable bool // Generated passwords use the "human readable" character set - CheckHibp bool // Check generated are validated against the HIBP API for possible leaks - ExcludeChars string // List of characters to be excluded from the PW generation charset - NewStyleModes string // Use the "new style" parameters instead of the single params - spellPassword bool // Spell out passwords in the output - ShowHelp bool // Display the help message in the CLI - ShowVersion bool // Display the version string in the CLI - OutputMode int // Interal parameter to control the output mode of the CLI - PwAlgo int // PW generation algorithm to use (0: random PW based on flags, 1: pronouncable) - SpellPron bool // Spell out the pronouncable password -} - -// DefaultMinLength reflects the default minimum length of a generated password -const DefaultMinLength int = 12 - -// DefaultMaxLength reflects the default maximum length of a generated password -const DefaultMaxLength int = 20 - -// DefaultPwAlgo reflects the default password generation algorithm -const DefaultPwAlgo int = 1 - -// New parses the CLI flags and returns a new config object -func New() Config { - var switchConf Config - defaultSwitches := Config{ - UseLowerCase: true, - UseUpperCase: true, - UseNumber: true, - UseSpecial: false, - useComplex: false, - HumanReadable: false, - } - config := Config{ - UseLowerCase: defaultSwitches.UseLowerCase, - UseUpperCase: defaultSwitches.UseUpperCase, - UseNumber: defaultSwitches.UseNumber, - UseSpecial: defaultSwitches.UseSpecial, - useComplex: defaultSwitches.useComplex, - HumanReadable: defaultSwitches.HumanReadable, - } - - // Read and set all flags - flag.BoolVar(&switchConf.UseLowerCase, "L", false, "Use lower case characters in passwords") - flag.BoolVar(&switchConf.UseUpperCase, "U", false, "Use upper case characters in passwords") - flag.BoolVar(&switchConf.UseNumber, "N", false, "Use numerich characters in passwords") - flag.BoolVar(&switchConf.UseSpecial, "S", false, "Use special characters in passwords") - flag.BoolVar(&switchConf.useComplex, "C", false, "Generate complex passwords (implies -L -U -N -S, disables -H)") - flag.BoolVar(&switchConf.HumanReadable, "H", false, "Generate human-readable passwords") - flag.BoolVar(&config.spellPassword, "l", false, "Spell generated password") - flag.BoolVar(&config.CheckHibp, "p", false, "Check the HIBP database if the generated password was leaked before") - flag.BoolVar(&config.ShowVersion, "v", false, "Show version") - flag.IntVar(&config.MinPassLen, "m", DefaultMinLength, "Minimum password length") - flag.IntVar(&config.MaxPassLen, "x", DefaultMaxLength, "Maxiumum password length") - flag.IntVar(&config.NumOfPass, "n", 6, "Number of passwords to generate") - flag.StringVar(&config.ExcludeChars, "E", "", "Exclude list of characters from generated password") - flag.StringVar(&config.NewStyleModes, "M", "", - "New style password parameters (higher priority than single parameters)") - flag.IntVar(&config.PwAlgo, "a", DefaultPwAlgo, "Password generation algorithm") - flag.BoolVar(&config.SpellPron, "t", false, "In pronouncable password mode, spell out the password") - flag.Parse() - - // Invert-switch the defaults - if switchConf.UseLowerCase { - config.UseLowerCase = !defaultSwitches.UseLowerCase - } - if switchConf.UseUpperCase { - config.UseUpperCase = !defaultSwitches.UseUpperCase - } - if switchConf.UseNumber { - config.UseNumber = !defaultSwitches.UseNumber - } - if switchConf.UseSpecial { - config.UseSpecial = !defaultSwitches.UseSpecial - } - if switchConf.useComplex { - config.useComplex = !defaultSwitches.useComplex - } - if switchConf.HumanReadable { - config.HumanReadable = !defaultSwitches.HumanReadable - } - - // Parse additional parameters and new-style switches - parseParams(&config) - - return config -} - -// Parse the parameters and set the according config flags -func parseParams(config *Config) { - parseNewStyleParams(config) - - // Complex overrides everything - if config.useComplex { - config.UseUpperCase = true - config.UseLowerCase = true - config.UseSpecial = true - config.UseNumber = true - config.HumanReadable = false - } - - if !config.UseUpperCase && - !config.UseLowerCase && - !config.UseNumber && - !config.UseSpecial { - log.Fatalf("No password mode set. Cannot generate password from empty character set.") - } - - // Set output mode - switch config.PwAlgo { - case 0: - config.OutputMode = 2 - default: - config.OutputMode = 0 - if config.spellPassword { - config.OutputMode = 1 - } - } -} - -// Parse the new style parameters -func parseNewStyleParams(config *Config) { - if config.NewStyleModes == "" { - return - } - - for _, curParam := range config.NewStyleModes { - switch curParam { - case 'S': - config.UseSpecial = true - case 's': - config.UseSpecial = false - case 'N': - config.UseNumber = true - case 'n': - config.UseNumber = false - case 'L': - config.UseLowerCase = true - case 'l': - config.UseLowerCase = false - case 'U': - config.UseUpperCase = true - case 'u': - config.UseUpperCase = false - case 'H': - config.HumanReadable = true - case 'h': - config.HumanReadable = false - case 'C': - config.useComplex = true - case 'c': - config.useComplex = false - default: - log.Fatalf("Unknown password style parameter: %q\n", string(curParam)) - } - } -} - -// GetPwLengthFromParams extracts the password length from the given cli flags and stores -// in the provided config object -func GetPwLengthFromParams(config *Config) int { - if config.MinPassLen > config.MaxPassLen { - config.MaxPassLen = config.MinPassLen - } - lenDiff := config.MaxPassLen - config.MinPassLen + 1 - randAdd, err := random.GetNum(lenDiff) - if err != nil { - log.Fatalf("Failed to generated password length: %v", err) - } - retVal := config.MinPassLen + randAdd - if retVal <= 0 { - return 1 - } - - return retVal -} diff --git a/docker-files/group b/docker-files/group deleted file mode 100644 index 4cbfc65..0000000 --- a/docker-files/group +++ /dev/null @@ -1 +0,0 @@ -apg-go:*:1000:apg-go diff --git a/docker-files/passwd b/docker-files/passwd deleted file mode 100644 index 8efc7d9..0000000 --- a/docker-files/passwd +++ /dev/null @@ -1 +0,0 @@ -apg-go:*:1000:1000:Automated Password Generator User:/apg-go:/usr/bin/false diff --git a/example-code/simple-password-generator/main.go b/example-code/simple-password-generator/main.go deleted file mode 100644 index 7289abb..0000000 --- a/example-code/simple-password-generator/main.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "fmt" - "github.com/wneessen/apg-go/chars" - "github.com/wneessen/apg-go/config" - "github.com/wneessen/apg-go/random" -) - -func main() { - c := config.Config{ - UseNumber: true, - UseSpecial: true, - UseUpperCase: true, - UseLowerCase: true, - PwAlgo: 1, - MinPassLen: 15, - MaxPassLen: 15, - } - pl := config.GetPwLengthFromParams(&c) - cs := chars.GetRange(&c) - pw, err := random.GetChar(cs, pl) - if err != nil { - panic(err) - } - fmt.Println("Your Password:", pw) -} diff --git a/go.mod b/go.mod deleted file mode 100644 index a215295..0000000 --- a/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/wneessen/apg-go - -go 1.16 - -require github.com/wneessen/go-hibp v1.0.6 diff --git a/random/random.go b/random/random.go deleted file mode 100644 index ec0fdb9..0000000 --- a/random/random.go +++ /dev/null @@ -1,80 +0,0 @@ -package random - -import ( - "crypto/rand" - "encoding/binary" - "fmt" - "math/big" - "strings" -) - -// Bitmask sizes for the string generators (based on 93 chars total) -const ( - letterIdxBits = 7 // 7 bits to represent a letter index - letterIdxMask = 1<= 0; { - if r == 0 { - _, err := rand.Read(rp) - if err != nil { - return rs.String(), err - } - c, r = binary.BigEndian.Uint64(rp), letterIdxMax - } - if idx := int(c & letterIdxMask); idx < crl { - rs.WriteByte(cr[idx]) - i-- - } - c >>= letterIdxBits - r-- - } - return rs.String(), nil -} - -// GetNum generates a random number with given maximum value -func GetNum(maxNum int) (int, error) { - if maxNum <= 0 { - err := fmt.Errorf("provided maxNum is <= 0: %v", maxNum) - return 0, err - } - maxNumBigInt := big.NewInt(int64(maxNum)) - if !maxNumBigInt.IsUint64() { - err := fmt.Errorf("big.NewInt() generation returned negative value: %v", maxNumBigInt) - return 0, err - } - randNum64, err := rand.Int(rand.Reader, maxNumBigInt) - if err != nil { - return 0, err - } - randNum := int(randNum64.Int64()) - if randNum < 0 { - err := fmt.Errorf("generated random number does not fit as int64: %v", randNum64) - return 0, err - } - return randNum, nil -} - -// CoinFlip performs a simple coinflip based on the rand library and returns true or false -func CoinFlip() bool { - num := big.NewInt(2) - cf, _ := rand.Int(rand.Reader, num) - r := int(cf.Int64()) - return r == 1 -} diff --git a/spelling/spelling.go b/spelling/spelling.go deleted file mode 100644 index b4eb7f6..0000000 --- a/spelling/spelling.go +++ /dev/null @@ -1,140 +0,0 @@ -package spelling - -import ( - "fmt" - "github.com/wneessen/apg-go/chars" - "strings" -) - -var ( - symbNumNames = map[byte]string{ - '1': "ONE", - '2': "TWO", - '3': "THREE", - '4': "FOUR", - '5': "FIVE", - '6': "SIX", - '7': "SEVEN", - '8': "EIGHT", - '9': "NINE", - '0': "ZERO", - 33: "EXCLAMATION_POINT", - 34: "QUOTATION_MARK", - 35: "CROSSHATCH", - 36: "DOLLAR_SIGN", - 37: "PERCENT_SIGN", - 38: "AMPERSAND", - 39: "APOSTROPHE", - 40: "LEFT_PARENTHESIS", - 41: "RIGHT_PARENTHESIS", - 42: "ASTERISK", - 43: "PLUS_SIGN", - 44: "COMMA", - 45: "HYPHEN", - 46: "PERIOD", - 47: "SLASH", - 58: "COLON", - 59: "SEMICOLON", - 60: "LESS_THAN", - 61: "EQUAL_SIGN", - 62: "GREATER_THAN", - 63: "QUESTION_MARK", - 64: "AT_SIGN", - 91: "LEFT_BRACKET", - 92: "BACKSLASH", - 93: "RIGHT_BRACKET", - 94: "CIRCUMFLEX", - 95: "UNDERSCORE", - 96: "GRAVE", - 123: "LEFT_BRACE", - 124: "VERTICAL_BAR", - 125: "RIGHT_BRACE", - 126: "TILDE", - } - alphabetNames = map[byte]string{ - 'A': "Alfa", - 'B': "Bravo", - 'C': "Charlie", - 'D': "Delta", - 'E': "Echo", - 'F': "Foxtrot", - 'G': "Golf", - 'H': "Hotel", - 'I': "India", - 'J': "Juliett", - 'K': "Kilo", - 'L': "Lima", - 'M': "Mike", - 'N': "November", - 'O': "Oscar", - 'P': "Papa", - 'Q': "Quebec", - 'R': "Romeo", - 'S': "Sierra", - 'T': "Tango", - 'U': "Uniform", - 'V': "Victor", - 'W': "Whiskey", - 'X': "X_ray", - 'Y': "Yankee", - 'Z': "Zulu", - } -) - -// String returns an english spelled version of the given string -func String(pwString string) (string, error) { - var returnString []string - for _, curChar := range pwString { - curSpellString, err := ConvertCharToName(byte(curChar)) - if err != nil { - return "", err - } - returnString = append(returnString, curSpellString) - } - return strings.Join(returnString, "/"), nil -} - -// Koremutake returns the spelling of the Koremutake password with numbers and special -// chars spelled out in english language -func Koremutake(sylList []string) (string, error) { - var returnString []string - for _, curSyl := range sylList { - isKore := false - for _, x := range chars.KoremutakeSyllables { - if x == strings.ToLower(curSyl) { - isKore = true - } - } - - if isKore { - returnString = append(returnString, curSyl) - continue - } - - curSpellString, err := ConvertCharToName(curSyl[0]) - if err != nil { - return "", err - } - returnString = append(returnString, curSpellString) - } - return strings.Join(returnString, "-"), nil -} - -// ConvertCharToName converts a given ascii byte into the corresponding english spelled -// name -func ConvertCharToName(charByte byte) (string, error) { - var returnString string - if charByte > 64 && charByte < 91 { - returnString = alphabetNames[charByte] - } else if charByte > 96 && charByte < 123 { - returnString = strings.ToLower(alphabetNames[charByte-32]) - } else { - returnString = symbNumNames[charByte] - } - - if returnString == "" { - err := fmt.Errorf("cannot convert to character to name: %q is an unknown character", charByte) - return "", err - } - return returnString, nil -}