Help us shape the future of Go! Take the 2026 Go Developer Survey

credential

package
v0.19.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 25, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package credential generates and checks the shared secrets a player proves themselves with: the recovery code from docs/adr/0006 and the PIN from docs/adr/0007.

Like the rest of the business logic it knows neither the database nor HTTP (CLAUDE.md, "Konventionen"). It hands out strings and verifies them; who stores them is somebody else's problem.

Index

Constants

View Source
const (
	MinPINLength = 6
	MaxPINLength = 32
)

The bounds on a PIN. docs/adr/0007 sets the floor at six digits, which only holds up because of the brake in front of it; the ceiling is here so the field cannot become an essay, and nothing needs it.

They live in this package rather than beside the handler because the form that collects a PIN needs them too, and two copies of a rule drift.

Variables

View Source
var ErrMalformedHash = errors.New("stored credential hash is malformed")

ErrMalformedHash reports a stored hash this package cannot read. It means the row is broken, not that the secret was wrong, and callers have to keep the two apart: answering "wrong code" to a corrupted row would send somebody looking for a code that was right all along.

Functions

func Hash

func Hash(secret string) string

Hash derives the digest that gets stored for secret.

The result carries its own parameters and salt, in the format Argon2 implementations agree on:

$argon2id$v=19$m=65536,t=2,p=4$<salt>$<digest>

Self-describing on purpose. Raising the cost later has to leave the rows written before it verifiable, or the change locks out everybody who has not signed in since.

func NewCode

func NewCode() string

NewCode returns a fresh recovery code, formatted for reading aloud.

Generated, never chosen. docs/adr/0006 is explicit about why: a field somebody may type their own secret into becomes a field somebody types their company password into.

func NewRecoveryCode

func NewRecoveryCode() (code, hash string)

NewRecoveryCode returns a fresh code to show and the hash to store.

The two come from one call because they must not be derived apart. The hash covers the *normalized* code, which is what a sign-in compares against after running what somebody typed through NormalizeCode. Hashing the formatted string instead would reject every code the moment it was typed back without its hyphens — which is how most people would type it.

func NormalizeCode

func NormalizeCode(raw string) string

NormalizeCode turns what somebody typed into what was generated.

It folds case, drops the hyphens and anything else that is not part of the alphabet, and maps the characters the alphabet leaves out onto the ones it kept: O to zero, I and L to one. Somebody reading a code off a screen and typing "O" where a "0" stands is the expected case, not an attack, and a sign-in that refuses it for that is refusing the right person.

The result is not checked for length or plausibility. That belongs to whoever compares it against a hash, where a wrong code and a mistyped one have to look the same anyway.

func Verify

func Verify(encoded, secret string) (bool, error)

Verify reports whether secret is the one encoded stands for.

A wrong secret is (false, nil) — an ordinary answer, not a failure. Only an unreadable encoded hash returns an error.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL