mirror of
https://github.com/wneessen/apg-go.git
synced 2024-11-22 22:00:49 +01:00
Compare commits
No commits in common. "5ba220f1b9524044c4f41ea163f8bfc93ab10b89" and "641af1f88cfd04190dec19c91547c502483bf924" have entirely different histories.
5ba220f1b9
...
641af1f88c
18 changed files with 7 additions and 420 deletions
1
.github/workflows/codecov.yml
vendored
1
.github/workflows/codecov.yml
vendored
|
@ -3,7 +3,6 @@
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
name: Codecov workflow
|
name: Codecov workflow
|
||||||
permissions: read-all
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
|
91
.github/workflows/codeql.yml
vendored
91
.github/workflows/codeql.yml
vendored
|
@ -1,91 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
# For most projects, this workflow file will not need changing; you simply need
|
|
||||||
# to commit it to your repository.
|
|
||||||
#
|
|
||||||
# You may wish to alter this file to override the set of languages analyzed,
|
|
||||||
# or to provide custom queries or build logic.
|
|
||||||
#
|
|
||||||
# ******** NOTE ********
|
|
||||||
# We have attempted to detect the languages in your repository. Please check
|
|
||||||
# the `language` matrix defined below to confirm you have the correct set of
|
|
||||||
# supported CodeQL languages.
|
|
||||||
#
|
|
||||||
name: "CodeQL"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
schedule:
|
|
||||||
- cron: '31 14 * * 1'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analyze:
|
|
||||||
name: Analyze
|
|
||||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
|
||||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
|
||||||
# - https://gh.io/supported-runners-and-hardware-resources
|
|
||||||
# - https://gh.io/using-larger-runners
|
|
||||||
# Consider using larger runners for possible analysis time improvements.
|
|
||||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
|
||||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
|
||||||
permissions:
|
|
||||||
# required for all workflows
|
|
||||||
security-events: write
|
|
||||||
|
|
||||||
# only required for workflows in private repositories
|
|
||||||
actions: read
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
language: [ 'go' ]
|
|
||||||
# CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
|
|
||||||
# Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
|
|
||||||
# Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
|
||||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v3
|
|
||||||
with:
|
|
||||||
languages: ${{ matrix.language }}
|
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
||||||
# By default, queries listed here will override any specified in a config file.
|
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
||||||
|
|
||||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
||||||
# queries: security-extended,security-and-quality
|
|
||||||
|
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
|
||||||
# - name: Autobuild
|
|
||||||
# uses: github/codeql-action/autobuild@v3
|
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
||||||
|
|
||||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
|
||||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
|
||||||
|
|
||||||
- run: |
|
|
||||||
echo "Build Application using Go"
|
|
||||||
/usr/bin/env GOTOOLCHAIN=go1.22.1+auto go build -a -installsuffix cgo -ldflags '-w -s -extldflags "-static"' -o apg github.com/wneessen/apg-go/cmd/apg
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v3
|
|
||||||
with:
|
|
||||||
category: "/language:${{matrix.language}}"
|
|
3
.github/workflows/docker-publish.yml
vendored
3
.github/workflows/docker-publish.yml
vendored
|
@ -19,9 +19,6 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
# Use docker.io for Docker Hub if empty
|
# Use docker.io for Docker Hub if empty
|
||||||
REGISTRY: ghcr.io
|
REGISTRY: ghcr.io
|
||||||
|
|
2
.github/workflows/reuse.yml
vendored
2
.github/workflows/reuse.yml
vendored
|
@ -3,8 +3,6 @@
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
name: REUSE Compliance Check
|
name: REUSE Compliance Check
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
|
76
.github/workflows/scorecard.yml
vendored
76
.github/workflows/scorecard.yml
vendored
|
@ -1,76 +0,0 @@
|
||||||
# SPDX-FileCopyrightText: 2022 Winni Neessen <winni@neessen.dev>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
|
||||||
|
|
||||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
|
||||||
# by a third-party and are governed by separate terms of service, privacy
|
|
||||||
# policy, and support documentation.
|
|
||||||
|
|
||||||
name: Scorecard supply-chain security
|
|
||||||
on:
|
|
||||||
# For Branch-Protection check. Only the default branch is supported. See
|
|
||||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
|
||||||
branch_protection_rule:
|
|
||||||
# To guarantee Maintained check is occasionally updated. See
|
|
||||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
|
||||||
schedule:
|
|
||||||
- cron: '34 15 * * 4'
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
# Declare default permissions as read only.
|
|
||||||
permissions: read-all
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
analysis:
|
|
||||||
name: Scorecard analysis
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
# Needed to upload the results to code-scanning dashboard.
|
|
||||||
security-events: write
|
|
||||||
# Needed to publish results and get a badge (see publish_results below).
|
|
||||||
id-token: write
|
|
||||||
# Uncomment the permissions below if installing in a private repository.
|
|
||||||
# contents: read
|
|
||||||
# actions: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout code"
|
|
||||||
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: "Run analysis"
|
|
||||||
uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2
|
|
||||||
with:
|
|
||||||
results_file: results.sarif
|
|
||||||
results_format: sarif
|
|
||||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
|
||||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
|
||||||
# - you are installing Scorecard on a *private* repository
|
|
||||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
|
||||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
|
||||||
|
|
||||||
# Public repositories:
|
|
||||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
|
||||||
# - Allows the repository to include the Scorecard badge.
|
|
||||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
|
||||||
# For private repositories:
|
|
||||||
# - `publish_results` will always be set to `false`, regardless
|
|
||||||
# of the value entered here.
|
|
||||||
publish_results: true
|
|
||||||
|
|
||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
|
||||||
# format to the repository Actions tab.
|
|
||||||
- name: "Upload artifact"
|
|
||||||
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
|
|
||||||
with:
|
|
||||||
name: SARIF file
|
|
||||||
path: results.sarif
|
|
||||||
retention-days: 5
|
|
||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
|
||||||
- name: "Upload to code-scanning"
|
|
||||||
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
|
|
||||||
with:
|
|
||||||
sarif_file: results.sarif
|
|
1
.github/workflows/sonarqube.yml
vendored
1
.github/workflows/sonarqube.yml
vendored
|
@ -3,7 +3,6 @@
|
||||||
# SPDX-License-Identifier: CC0-1.0
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
name: SonarQube
|
name: SonarQube
|
||||||
permissions: read-all
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
|
|
29
README.md
29
README.md
|
@ -49,14 +49,6 @@ vEbErlaFryaNgyex (vE-bEr-la-Fry-aN-gy-ex)
|
||||||
We generated a 15-character long pronounceable phrase with syllables output, for easy
|
We generated a 15-character long pronounceable phrase with syllables output, for easy
|
||||||
use in e. g. a phone verification process.
|
use in e. g. a phone verification process.
|
||||||
|
|
||||||
### Cryptographic key for encryption
|
|
||||||
```shell
|
|
||||||
$ apg -a 3 -f 32 -bh
|
|
||||||
```
|
|
||||||
We generated a 32 bytes/256 bits long fully binary secret that can be used i. e. as
|
|
||||||
encryption key for a AES-256 symmetric encryption. The output is represented in
|
|
||||||
hexadecimal format.
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
@ -335,24 +327,6 @@ Heads
|
||||||
Heads
|
Heads
|
||||||
```
|
```
|
||||||
|
|
||||||
### Binary mode
|
|
||||||
Since v1.1.0 apg-go has a new algorithm for binary secrets. This is a very basic mode that will ignore
|
|
||||||
most of the available options, as it will only generate binary secrets with full 256 bits of randomness.
|
|
||||||
The only available options for this mode are: `-f` to set the length of the returned secret in bytes,
|
|
||||||
`-bh` to tell apg-go to output the generated secret in hexadecial representation and `-bn` to instruct
|
|
||||||
apg-go to return a newline after the generated secret. Any other option available in the other modes
|
|
||||||
will be ignored.
|
|
||||||
|
|
||||||
This mode can be useful for example if you need to generate a AES-256 encryption key. Since 32 bytes is
|
|
||||||
the default length for the secret generation in this mode, you can simply generate a secret key with
|
|
||||||
the following command:
|
|
||||||
```shell
|
|
||||||
$ apg -a 3 -bh
|
|
||||||
a1cdab8db365af3d70828b1fe43b7896190c157ad3f1ae2a0a1d52ec1628c6b5
|
|
||||||
```
|
|
||||||
*For ease for readability we used the `-bh` flag, to instruct apg-go to output the secret in its
|
|
||||||
hexadecimal representation*
|
|
||||||
|
|
||||||
### Minimum required characters
|
### Minimum required characters
|
||||||
Even though in apg-go you can select what kind of characters are used for the password generation, it is
|
Even though in apg-go you can select what kind of characters are used for the password generation, it is
|
||||||
not guaranteed, that if you request a password with a numeric value, that the generated password will
|
not guaranteed, that if you request a password with a numeric value, that the generated password will
|
||||||
|
@ -402,9 +376,6 @@ _apg-go_ replicates most of the parameters of the original c-apg. Some parameter
|
||||||
- `0`: Pronouncable password generation (Koremutake syllables)
|
- `0`: Pronouncable password generation (Koremutake syllables)
|
||||||
- `1`: Random password generation according to password modes/flags
|
- `1`: Random password generation according to password modes/flags
|
||||||
- `2`: Coinflip (returns heads or tails)
|
- `2`: Coinflip (returns heads or tails)
|
||||||
- `3`: Binary mode (returns a secret with 256 bits of randomness)
|
|
||||||
- `-bh`: When set, will print the generated secret in its hex representation (Default: off)
|
|
||||||
- `-bn`: When set, will return a new line character after the generated secret (Default: off)
|
|
||||||
- `-m <length>`: The minimum length of the password to be generated (Default: 12)
|
- `-m <length>`: The minimum length of the password to be generated (Default: 12)
|
||||||
- `-x <length>`: The maximum length of the password to be generated (Default: 20)
|
- `-x <length>`: The maximum length of the password to be generated (Default: 20)
|
||||||
- `-f <length>`: Fixed length of the password to be generated (Ignores -m and -x)
|
- `-f <length>`: Fixed length of the password to be generated (Ignores -m and -x)
|
||||||
|
|
38
SECURITY.md
38
SECURITY.md
|
@ -1,38 +0,0 @@
|
||||||
<!--
|
|
||||||
SPDX-FileCopyrightText: 2021-2024 Winni Neessen <wn@neessen.dev>
|
|
||||||
|
|
||||||
SPDX-License-Identifier: CC0-1.0
|
|
||||||
-->
|
|
||||||
|
|
||||||
# Security Policy
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
To report (possible) security issues in apg-go, please either send a mail to
|
|
||||||
[security@neessen.dev](mailto:security@neessen.dev) or use Github's
|
|
||||||
[private reporting feature](https://github.com/wneessen/apg-go/security/advisories/new).
|
|
||||||
Reports are always welcome. Even if you are not 100% certain that a specific issue you found
|
|
||||||
counts as a security issue, we'd love to hear the details, so we can figure out together if
|
|
||||||
the issue in question needds to be addressed.
|
|
||||||
|
|
||||||
Typically, you will receive an answer within a day or even within a few hours.
|
|
||||||
|
|
||||||
## Encryption
|
|
||||||
You can send OpenPGP/GPG encrpyted mails to the [security@neessen.dev](mailto:security@neessen.dev) address.
|
|
||||||
|
|
||||||
OpenPGP/GPG public key:
|
|
||||||
```
|
|
||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
||||||
xjMEZfdSjxYJKwYBBAHaRw8BAQdA8YoxV0iaLJxVUkBlpC+FQyOiCvWPcnnk
|
|
||||||
O8rsfRHT22bNK3NlY3VyaXR5QG5lZXNzZW4uZGV2IDxzZWN1cml0eUBuZWVz
|
|
||||||
c2VuLmRldj7CjAQQFgoAPgWCZfdSjwQLCQcICZAajWCli0ncDgMVCAoEFgAC
|
|
||||||
AQIZAQKbAwIeARYhBB6X6h8oUi9vvjcMFxqNYKWLSdwOAACHrQEAmfT2HNXF
|
|
||||||
x1W0z6E6PiuoHDU6DzZ1MC6TZkFfFoC3jJ0BAJZdZnf6xFkVtEAbxNIVpIkI
|
|
||||||
zjVxgI7gefYDXbqzQx4PzjgEZfdSjxIKKwYBBAGXVQEFAQEHQBdOGYxMLrCy
|
|
||||||
+kypzTe9jgaEOjob2VVsZ2UV2K9MGKYYAwEIB8J4BBgWCgAqBYJl91KPCZAa
|
|
||||||
jWCli0ncDgKbDBYhBB6X6h8oUi9vvjcMFxqNYKWLSdwOAABIFAEA3YglATpF
|
|
||||||
YrJxatxHb+yI6WdhhJTA2TaF2bxBl10d/xEA/R5CKbMe3kj647gjiQ1YXQUh
|
|
||||||
dM5AKh9kcJn6FPLEoKEM
|
|
||||||
=nm5C
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
||||||
```
|
|
5
algo.go
5
algo.go
|
@ -18,9 +18,6 @@ const (
|
||||||
// AlgoCoinFlip represents a very simple coinflip algorithm returning "heads"
|
// AlgoCoinFlip represents a very simple coinflip algorithm returning "heads"
|
||||||
// or "tails"
|
// or "tails"
|
||||||
AlgoCoinFlip
|
AlgoCoinFlip
|
||||||
// AlgoBinary represents a full binary randomness mode with up to 256 bits
|
|
||||||
// of randomness
|
|
||||||
AlgoBinary
|
|
||||||
// AlgoUnsupported represents an unsupported algorithm
|
// AlgoUnsupported represents an unsupported algorithm
|
||||||
AlgoUnsupported
|
AlgoUnsupported
|
||||||
)
|
)
|
||||||
|
@ -35,8 +32,6 @@ func IntToAlgo(a int) Algorithm {
|
||||||
return AlgoRandom
|
return AlgoRandom
|
||||||
case 2:
|
case 2:
|
||||||
return AlgoCoinFlip
|
return AlgoCoinFlip
|
||||||
case 3:
|
|
||||||
return AlgoBinary
|
|
||||||
default:
|
default:
|
||||||
return AlgoUnsupported
|
return AlgoUnsupported
|
||||||
}
|
}
|
||||||
|
|
38
algo_test.go
38
algo_test.go
|
@ -4,9 +4,7 @@
|
||||||
|
|
||||||
package apg
|
package apg
|
||||||
|
|
||||||
import (
|
import "testing"
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIntToAlgo(t *testing.T) {
|
func TestIntToAlgo(t *testing.T) {
|
||||||
tt := []struct {
|
tt := []struct {
|
||||||
|
@ -17,8 +15,7 @@ func TestIntToAlgo(t *testing.T) {
|
||||||
{"AlgoPronounceable", 0, AlgoPronounceable},
|
{"AlgoPronounceable", 0, AlgoPronounceable},
|
||||||
{"AlgoRandom", 1, AlgoRandom},
|
{"AlgoRandom", 1, AlgoRandom},
|
||||||
{"AlgoCoinflip", 2, AlgoCoinFlip},
|
{"AlgoCoinflip", 2, AlgoCoinFlip},
|
||||||
{"AlgoBinary", 3, AlgoBinary},
|
{"AlgoUnsupported", 3, AlgoUnsupported},
|
||||||
{"AlgoUnsupported", 4, AlgoUnsupported},
|
|
||||||
}
|
}
|
||||||
for _, tc := range tt {
|
for _, tc := range tt {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
@ -29,34 +26,3 @@ func TestIntToAlgo(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FuzzIntToAlgo(f *testing.F) {
|
|
||||||
f.Add(-1) // Test negative input
|
|
||||||
f.Add(4) // Test out-of-range positive input
|
|
||||||
f.Add(100) // Test very large input
|
|
||||||
f.Fuzz(func(t *testing.T, a int) {
|
|
||||||
algo := IntToAlgo(a)
|
|
||||||
switch a {
|
|
||||||
case 0:
|
|
||||||
if algo != AlgoPronounceable {
|
|
||||||
t.Errorf("IntToAlgo(%d) expected AlgoPronounceable, got %v", a, algo)
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
if algo != AlgoRandom {
|
|
||||||
t.Errorf("IntToAlgo(%d) expected AlgoRandom, got %v", a, algo)
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
if algo != AlgoCoinFlip {
|
|
||||||
t.Errorf("IntToAlgo(%d) expected AlgoCoinFlip, got %v", a, algo)
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
if algo != AlgoBinary {
|
|
||||||
t.Errorf("IntToAlgo(%d) expected AlgoBinary, got %v", a, algo)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if algo != AlgoUnsupported {
|
|
||||||
t.Errorf("IntToAlgo(%d) expected AlgoUnsupported, got %v", a, algo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
2
apg.go
2
apg.go
|
@ -5,7 +5,7 @@
|
||||||
package apg
|
package apg
|
||||||
|
|
||||||
// VERSION represents the version string
|
// VERSION represents the version string
|
||||||
const VERSION = "1.1.0"
|
const VERSION = "1.0.0"
|
||||||
|
|
||||||
// Generator is the password generator type of the APG package
|
// Generator is the password generator type of the APG package
|
||||||
type Generator struct {
|
type Generator struct {
|
||||||
|
|
|
@ -31,8 +31,6 @@ func main() {
|
||||||
var modeString string
|
var modeString string
|
||||||
var complexPass, humanReadable, lowerCase, numeric, special, showVer, upperCase bool
|
var complexPass, humanReadable, lowerCase, numeric, special, showVer, upperCase bool
|
||||||
flag.IntVar(&algorithm, "a", 1, "")
|
flag.IntVar(&algorithm, "a", 1, "")
|
||||||
flag.BoolVar(&config.BinaryHexMode, "bh", false, "")
|
|
||||||
flag.BoolVar(&config.BinaryNewline, "bn", false, "")
|
|
||||||
flag.BoolVar(&complexPass, "C", false, "")
|
flag.BoolVar(&complexPass, "C", false, "")
|
||||||
flag.StringVar(&config.ExcludeChars, "E", "", "")
|
flag.StringVar(&config.ExcludeChars, "E", "", "")
|
||||||
flag.Int64Var(&config.FixedLength, "f", 0, "")
|
flag.Int64Var(&config.FixedLength, "f", 0, "")
|
||||||
|
@ -146,23 +144,6 @@ func configOldStyle(config *apg.Config, humanReadable, lowerCase, upperCase,
|
||||||
|
|
||||||
func generate(config *apg.Config) {
|
func generate(config *apg.Config) {
|
||||||
generator := apg.New(config)
|
generator := apg.New(config)
|
||||||
|
|
||||||
// In binary mode we only generate a single secret
|
|
||||||
if config.Algorithm == apg.AlgoBinary {
|
|
||||||
password, err := generator.Generate()
|
|
||||||
if err != nil {
|
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "failed to generate password: %s\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if config.BinaryNewline {
|
|
||||||
fmt.Println(password)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Print(password)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// For any other mode we cycle through the amount of passwords to be generated
|
|
||||||
for i := int64(0); i < config.NumberPass; i++ {
|
for i := int64(0); i < config.NumberPass; i++ {
|
||||||
password, err := generator.Generate()
|
password, err := generator.Generate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -216,17 +197,12 @@ Flags:
|
||||||
- 0: pronounceable password generation (koremutake syllables)
|
- 0: pronounceable password generation (koremutake syllables)
|
||||||
- 1: random password generation according to password modes/flags
|
- 1: random password generation according to password modes/flags
|
||||||
- 2: coinflip (returns heads or tails)
|
- 2: coinflip (returns heads or tails)
|
||||||
- 3: full binary mode (generates simple 256 bit randomness)
|
|
||||||
-bh When set, will print the generated secret in its hex representation (Default: off)
|
|
||||||
-bn When set, will return a new line character after the generated secret (Default: off)
|
|
||||||
- Note: The -bX options only apply to binary mode (Algo: 3)
|
|
||||||
-m LENGTH Minimum length of the password to be generated (Default: 12)
|
-m LENGTH Minimum length of the password to be generated (Default: 12)
|
||||||
-x LENGTH Maximum length of the password to be generated (Default: 20)
|
-x LENGTH Maximum length of the password to be generated (Default: 20)
|
||||||
-f LENGTH Fixed length of the password to be generated (Ignores -m and -x)
|
-f LENGTH Fixed length of the password to be generated (Ignores -m and -x)
|
||||||
- Note: Due to the way the pronounceable password algorithm works,
|
- Note: Due to the way the pronounceable password algorithm works,
|
||||||
this setting might not always apply
|
this setting might not always apply
|
||||||
-n NUMBER Amount of password to be generated (Default: 6)
|
-n NUMBER Amount of password to be generated (Default: 6)
|
||||||
- Note: Does not apply to binary mode (Algo: 3)
|
|
||||||
-E CHARS List of characters to be excluded in the generated password
|
-E CHARS List of characters to be excluded in the generated password
|
||||||
-M [LUNSHClunshc] New style password flags
|
-M [LUNSHClunshc] New style password flags
|
||||||
- Note: new-style flags have higher priority than any of the old-style flags
|
- Note: new-style flags have higher priority than any of the old-style flags
|
||||||
|
|
14
config.go
14
config.go
|
@ -10,8 +10,6 @@ const (
|
||||||
DefaultMinLength int64 = 12
|
DefaultMinLength int64 = 12
|
||||||
// DefaultMaxLength reflects the default maximum length of a generated password
|
// DefaultMaxLength reflects the default maximum length of a generated password
|
||||||
DefaultMaxLength int64 = 20
|
DefaultMaxLength int64 = 20
|
||||||
// DefaultBinarySize is the default byte size for generating binary random bytes
|
|
||||||
DefaultBinarySize int64 = 32
|
|
||||||
// DefaultMode sets the default character set mode bitmask to a combination of
|
// DefaultMode sets the default character set mode bitmask to a combination of
|
||||||
// lower- and upper-case characters as well as numbers
|
// lower- and upper-case characters as well as numbers
|
||||||
DefaultMode ModeMask = ModeLowerCase | ModeNumeric | ModeUpperCase
|
DefaultMode ModeMask = ModeLowerCase | ModeNumeric | ModeUpperCase
|
||||||
|
@ -23,11 +21,6 @@ const (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Algorithm sets the Algorithm used for the password generation
|
// Algorithm sets the Algorithm used for the password generation
|
||||||
Algorithm Algorithm
|
Algorithm Algorithm
|
||||||
// BinaryHexMode if set will output the hex representation of the generated
|
|
||||||
// binary random string
|
|
||||||
BinaryHexMode bool
|
|
||||||
// BinaryNewline if set will print out a new line in AlgoBinary mode
|
|
||||||
BinaryNewline bool
|
|
||||||
// CheckHIBP sets a flag if the generated password has to be checked
|
// CheckHIBP sets a flag if the generated password has to be checked
|
||||||
// against the HIBP pwned password database
|
// against the HIBP pwned password database
|
||||||
CheckHIBP bool
|
CheckHIBP bool
|
||||||
|
@ -95,13 +88,6 @@ func WithAlgorithm(algo Algorithm) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithBinaryHexMode sets the hex mode for the AlgoBinary
|
|
||||||
func WithBinaryHexMode() Option {
|
|
||||||
return func(config *Config) {
|
|
||||||
config.BinaryHexMode = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithExcludeChars sets a list of characters to be excluded in the generated
|
// WithExcludeChars sets a list of characters to be excluded in the generated
|
||||||
// passwords
|
// passwords
|
||||||
func WithExcludeChars(chars string) Option {
|
func WithExcludeChars(chars string) Option {
|
||||||
|
|
|
@ -46,8 +46,7 @@ func TestWithAlgorithm(t *testing.T) {
|
||||||
{"Pronounceable passwords", AlgoPronounceable, 0},
|
{"Pronounceable passwords", AlgoPronounceable, 0},
|
||||||
{"Random passwords", AlgoRandom, 1},
|
{"Random passwords", AlgoRandom, 1},
|
||||||
{"Coinflip", AlgoCoinFlip, 2},
|
{"Coinflip", AlgoCoinFlip, 2},
|
||||||
{"Binary", AlgoBinary, 3},
|
{"Unsupported", AlgoUnsupported, 3},
|
||||||
{"Unsupported", AlgoUnsupported, 4},
|
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -68,18 +67,6 @@ func TestWithAlgorithm(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWithBinaryHexMode(t *testing.T) {
|
|
||||||
c := NewConfig(WithBinaryHexMode())
|
|
||||||
if c == nil {
|
|
||||||
t.Errorf("NewConfig(WithBinaryHexMode()) failed, expected config pointer but got nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !c.BinaryHexMode {
|
|
||||||
t.Errorf("NewConfig(WithBinaryHexMode()) failed, expected chars: %t, got: %t",
|
|
||||||
true, c.BinaryHexMode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithExcludeChars(t *testing.T) {
|
func TestWithExcludeChars(t *testing.T) {
|
||||||
e := "abcdefg"
|
e := "abcdefg"
|
||||||
c := NewConfig(WithExcludeChars(e))
|
c := NewConfig(WithExcludeChars(e))
|
||||||
|
@ -196,18 +183,3 @@ func TestWithModeMask(t *testing.T) {
|
||||||
e, c.Mode)
|
e, c.Mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func FuzzWithAlgorithm(f *testing.F) {
|
|
||||||
f.Add(0)
|
|
||||||
f.Add(1)
|
|
||||||
f.Add(2)
|
|
||||||
f.Add(3)
|
|
||||||
f.Add(-1)
|
|
||||||
f.Add(100)
|
|
||||||
f.Fuzz(func(t *testing.T, algo int) {
|
|
||||||
config := NewConfig(WithAlgorithm(Algorithm(algo)))
|
|
||||||
if config.MaxLength < config.MinLength {
|
|
||||||
t.Errorf("Invalid algorithm: %d", algo)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,8 +21,7 @@ func TestHasBeenPwned(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
got, err := HasBeenPwned(tt.password)
|
got, err := HasBeenPwned(tt.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("HasBeenPwned() failed: %s", err)
|
t.Errorf("HasBeenPwned() failed: %s", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if tt.want != got {
|
if tt.want != got {
|
||||||
t.Errorf("HasBeenPwned() failed, wanted: %t, got: %t", tt.want, got)
|
t.Errorf("HasBeenPwned() failed, wanted: %t, got: %t", tt.want, got)
|
||||||
|
|
25
random.go
25
random.go
|
@ -57,13 +57,10 @@ func (g *Generator) Generate() (string, error) {
|
||||||
return g.generateCoinFlip()
|
return g.generateCoinFlip()
|
||||||
case AlgoRandom:
|
case AlgoRandom:
|
||||||
return g.generateRandom()
|
return g.generateRandom()
|
||||||
case AlgoBinary:
|
|
||||||
return g.generateBinary()
|
|
||||||
case AlgoUnsupported:
|
case AlgoUnsupported:
|
||||||
return "", fmt.Errorf("unsupported algorithm")
|
return "", fmt.Errorf("unsupported algorithm")
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("unsupported algorithm")
|
|
||||||
}
|
}
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCharRangeFromConfig checks the Mode from the Config and returns a
|
// GetCharRangeFromConfig checks the Mode from the Config and returns a
|
||||||
|
@ -318,26 +315,8 @@ func (g *Generator) generatePronounceable() (string, error) {
|
||||||
return password, nil
|
return password, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateBinary is executed when Generate() is called with Algorithm set
|
|
||||||
// to AlgoBinary
|
|
||||||
func (g *Generator) generateBinary() (string, error) {
|
|
||||||
length := DefaultBinarySize
|
|
||||||
if g.config.FixedLength > 0 {
|
|
||||||
length = g.config.FixedLength
|
|
||||||
}
|
|
||||||
randBytes := make([]byte, length)
|
|
||||||
_, err := rand.Read(randBytes)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to generate random bytes: %w", err)
|
|
||||||
}
|
|
||||||
if g.config.BinaryHexMode {
|
|
||||||
return fmt.Sprintf("%x", randBytes), nil
|
|
||||||
}
|
|
||||||
return string(randBytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateRandom is executed when Generate() is called with Algorithm set
|
// generateRandom is executed when Generate() is called with Algorithm set
|
||||||
// to AlgoRandom
|
// to AlgoRandmom
|
||||||
func (g *Generator) generateRandom() (string, error) {
|
func (g *Generator) generateRandom() (string, error) {
|
||||||
length, err := g.GetPasswordLength()
|
length, err := g.GetPasswordLength()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -471,10 +471,6 @@ func TestGenerate(t *testing.T) {
|
||||||
name: "Random",
|
name: "Random",
|
||||||
algorithm: AlgoRandom,
|
algorithm: AlgoRandom,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Binary",
|
|
||||||
algorithm: AlgoBinary,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Unsupported",
|
name: "Unsupported",
|
||||||
algorithm: AlgoUnsupported,
|
algorithm: AlgoUnsupported,
|
||||||
|
@ -534,38 +530,3 @@ func BenchmarkGenerator_RandomString(b *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGenerator_generateBinary(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
config *Config
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Positive Case - Binary in Hex",
|
|
||||||
config: &Config{FixedLength: 10, BinaryHexMode: true},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Negative Case - Insufficient length",
|
|
||||||
config: &Config{FixedLength: -1, BinaryHexMode: false},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Positive Case - Binary without Hex",
|
|
||||||
config: &Config{FixedLength: 10, BinaryHexMode: false},
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
g := &Generator{config: tt.config}
|
|
||||||
_, err := g.generateBinary()
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("Generator.generateBinary() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -140,12 +140,6 @@ func TestPronounce(t *testing.T) {
|
||||||
want: "mu-sa",
|
want: "mu-sa",
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Pronounce_Mixed",
|
|
||||||
syllables: []string{"mu", "1"},
|
|
||||||
want: "mu-ONE",
|
|
||||||
wantErr: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Pronounce_NonKoremutakeSyllable",
|
name: "Pronounce_NonKoremutakeSyllable",
|
||||||
syllables: []string{"ä"},
|
syllables: []string{"ä"},
|
||||||
|
|
Loading…
Reference in a new issue