e-2fa
Encrypted 2FA manager for the terminal.


Install
Needs Go 1.23+.
go install github.com/AegisTrail/e-2fa/cmd/e-2fa@latest
Make sure Go's bin dir is on your PATH:
export PATH="$PATH:$(go env GOPATH)/bin"
From source:
git clone https://github.com/AegisTrail/e-2fa.git
cd e-2fa
go build -o e-2fa ./cmd/e-2fa
Use
e-2fa # first run creates the encrypted vault
add # add an entry (asks for type, issuer, account, secret)
add-uri '<otpauth URI from the QR code>'
code 1 # print a code
Run help inside for everything. Useful ones: watch, live 3,
copy 3, window 3, search, edit, group, import, verify.
Switching from another app
import <path> detects the format on its own. Every format below is
covered by tests. Add --dry-run to preview first.
- Aegis, plain and encrypted backups
- Google Authenticator, transfer QR (
otpauth-migration:// URIs)
- Bitwarden, unencrypted JSON and CSV exports
- 2FAS, andOTP, Raivo backups
- Generic CSV and plain otpauth URI lists
Import and export
import backup.json --dry-run # preview; auto-detects Aegis, 2FAS, andOTP,
# Raivo, Bitwarden CSV, CSV, otpauth URIs
backup file.json # encrypted Aegis backup
export file.json # plain backup
Scripting
e-2fa --json list
e-2fa --json code 1
e-2fa --vault /path/to/vault.json stats
Set E2FA_PASSWORD (env or .e-2fa.env, see .e-2fa.env.example) to skip
the password prompt. Do not commit that file.
Vault
Default location ~/.local/share/e-2fa/vault.json (mode 0600),
AES-256-GCM with an scrypt key.
Dev
Run make help to list all targets.
make build # build ./e-2fa
make run ARGS="--json list" # build then run (ARGS passed through)
make install # go install to GOPATH/bin
make dist # cross-compile linux/darwin/windows into dist/
make clean # remove binaries, dist/ and coverage files
make test # all tests, pretty output (needs gotestsum, below)
make test-unit # unit tests only (excludes ./tests)
make test-integration # integration suite only
make test-security # security suite only
make test-dots # compact dots + slow-test list
make test-race # all tests with the race detector
make test-verbose # all tests without gotestsum
make cover # coverage summary; make coverage-html for HTML report
make vet
make fmt # check only, expect no output; make fmt-fix to rewrite
make lint # vet + fmt, plus golangci-lint if installed
make tidy # go mod tidy (fails if go.mod/go.sum were dirty)
make check # fmt + vet + test
make tools # one-time install of gotestsum for the pretty output
[!NOTE]
Project layout
| Package |
Role |
cmd/e-2fa |
Entrypoint: flags and wiring |
cli |
Terminal UI: list, watch, live, copy, ... |
e2fa |
Backup/import codec: Aegis, 2FAS, andOTP, Raivo, Bitwarden, CSV, otpauth URIs, Google-Auth transfer QRs |
model |
Vault types: entries and groups |
otp |
TOTP / HOTP / Steam codes |
store |
Local encrypted vault (AES-256-GCM + scrypt) |
config |
Env-file config (.e-2fa.env) |
tests |
Integration + security suites (public API) |
[!TIP]
Test layers
| Layer |
Location |
Covers |
| Unit |
*_test.go beside the code |
White-box: parsers, merge logic, helpers |
| Integration |
tests/ |
Public API, end to end |
| Security |
tests/security_test.go |
Tamper, perms, nonces, leaks |
Unit tests stay next to the code because Go requires it for
white-box coverage of unexported helpers. Run a single layer with
make test-unit, make test-integration, make test-security
(or raw go test ./tests/ -v -run 'TestIntegration|TestSecurity').
License
