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)
-
-_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
-}