httk.core.identity

Per-user operator identity: signing keys, named identities, and signatures.

An operator identity is the attribution recorded on a document a user publishes — a name, an email, and an Ed25519 signing key. It says who published something and never what they may do: a signature is attribution, never authorization.

Identity keys live under config_home()/"keys" and the named-identity configuration lives in config_home()/"identity.json". Both honour HTTK_CONFIG_HOME through httk.core.userdirs.config_home(), so a test or an isolated run redirects the whole per-user identity store with one environment variable.

Signing is optional by construction: a caller with no identity key returns the document unchanged, and a verifier accepts an unsigned document. That is what keeps a mixed deployment — some installations with keys, some without — working.

Attributes

Classes

OperatorIdentity

One configured operator attribution identity.

DocumentSignature

Report what checking one document's optional identity signature established.

Functions

keys_home()

Return where this user's identity keys live.

identity_config_path()

Return the path of this user's identity configuration file.

read_identity_config()

Read the identity configuration, returning an empty mapping if absent.

write_identity_config(values)

Write a versioned identity configuration atomically and durably.

identity_key_paths(short)

Return the paths of the local identity seed and public key.

ensure_identity_key(short)

Create the user's standard Ed25519 identity key if it is absent.

configured_operator_identity()

Resolve the configured default operator identity, if one exists.

resolve_operator_identity(selector)

Resolve a configured identity or a literal Name <email> label.

initialize_identity(name, email)

Establish the per-user operator identity when it is not configured.

import_v1_identity([source])

Import name, email, and public identity from a legacy ~/.httk tree.

add_identity(short, name, email, *[, make_default])

Create and configure one named operator identity and its signing key.

set_default_identity(short)

Select the default named operator identity.

remove_identity(short)

Remove one named identity, leaving its key files untouched.

identity_seed([seed_path])

Return the local identity seed, or None when no key was created.

identity_public_key([seed_path])

Return the recorded local identity public key, or None.

local_public_keys()

Return the keys configured identities can actually sign with.

signature_digest(document)

Return the domain-separated digest one identity signature covers.

sign_document(document, *[, seed_path])

Return document with a detached identity signature, when one is possible.

verify_document(document)

Check the optional identity signature of document.

Module Contents

httk.core.identity.IDENTITY_CONFIG_FORMAT = 'httk-identity'
httk.core.identity.IDENTITY_CONFIG_FORMAT_VERSION = 1
httk.core.identity.IDENTITY_SIGNATURE_DOMAIN = b'httk-identity-v2\x00'
httk.core.identity.IDENTITY_KEY_MEMBER = 'operator_key'
httk.core.identity.IDENTITY_SIGNATURE_MEMBER = 'signature'
httk.core.identity.keys_home()

Return where this user’s identity keys live.

Returns:

Per-user identity key directory.

Return type:

pathlib.Path

httk.core.identity.identity_config_path()

Return the path of this user’s identity configuration file.

Returns:

Per-user identity configuration path.

Return type:

pathlib.Path

httk.core.identity.read_identity_config()

Read the identity configuration, returning an empty mapping if absent.

A document of an unrecognized format or version is refused by name rather than read as if its members meant what this implementation means by them.

Returns:

Identity configuration members, or an empty mapping when no file exists.

Raises:

ValueError – If the file is not a supported identity configuration document.

Return type:

dict[str, object]

httk.core.identity.write_identity_config(values)

Write a versioned identity configuration atomically and durably.

Parameters:

values (collections.abc.Mapping[str, object]) – Identity configuration members to write.

Returns:

Path of the written configuration file.

Return type:

pathlib.Path

httk.core.identity.identity_key_paths(short)

Return the paths of the local identity seed and public key.

Parameters:

short (str) – Named identity short name.

Returns:

Seed path followed by public-key path.

Raises:

ValueError – If short is not a valid identity short name.

Return type:

tuple[pathlib.Path, pathlib.Path]

httk.core.identity.ensure_identity_key(short)

Create the user’s standard Ed25519 identity key if it is absent.

Parameters:

short (str) – Named identity short name.

Returns:

Seed path followed by public-key path.

Raises:

ValueError – If an existing seed is not a standard Ed25519 seed.

Return type:

tuple[pathlib.Path, pathlib.Path]

class httk.core.identity.OperatorIdentity

One configured operator attribution identity.

Parameters:
  • short – Named identity short name, or None for the default identity.

  • name – Operator name.

  • email – Operator email address.

  • seed_path – Path of the signing seed, or None when none exists yet.

short: str | None
name: str
email: str
seed_path: pathlib.Path | None
property label: str

Return the Name <email> attribution label.

Returns:

The operator’s attribution label.

Return type:

str

httk.core.identity.configured_operator_identity()

Resolve the configured default operator identity, if one exists.

Returns:

The resolved default identity, or None when no identity is configured.

Raises:

ValueError – If the configured identities are malformed or ambiguous.

Return type:

OperatorIdentity | None

httk.core.identity.resolve_operator_identity(selector)

Resolve a configured identity or a literal Name <email> label.

Parameters:

selector (str | None) – A configured short name, a literal Name <email> label, or None for the default.

Returns:

The resolved operator identity.

Raises:

ValueError – If the selector is malformed, unknown, or the default is unresolvable.

Return type:

OperatorIdentity

httk.core.identity.initialize_identity(name, email)

Establish the per-user operator identity when it is not configured.

If a default identity already resolves, this function leaves the identity store untouched and reports that identity. If identities exist but no default can resolve, it refuses because choosing one is an operator action. Otherwise it derives a short name from email and creates the first named identity, which becomes the default.

Parameters:
  • name (str) – Operator name to record.

  • email (str) – Operator email address to record.

Returns:

Whether an identity was created, and the configured identity.

Raises:

ValueError – If identities are ambiguous or the name/email are invalid.

Return type:

tuple[bool, OperatorIdentity]

httk.core.identity.import_v1_identity(source=None)

Import name, email, and public identity from a legacy ~/.httk tree.

When no named identity is configured, a legacy name and email create the first named identity. If an identity already exists, legacy name and email are skipped rather than recorded. Legacy 64-byte private key material is deliberately left untouched.

Parameters:

source (str | os.PathLike[str] | None) – Legacy configuration root, or the default legacy home.

Returns:

The created identity’s short, name, and email when one was created, plus legacy_public_key when a legacy public key was found.

Raises:

FileNotFoundError – If the legacy configuration file is absent.

Return type:

dict[str, object]

httk.core.identity.add_identity(short, name, email, *, make_default=False)

Create and configure one named operator identity and its signing key.

The first identity added becomes the default; a later identity becomes the default only when make_default is set. When a default is already configured it is left in place unless overridden.

Parameters:
  • short (str) – Short identity name matching [a-z0-9][a-z0-9_-]*.

  • name (str) – Operator name.

  • email (str) – Operator email address.

  • make_default (bool) – Whether to make this identity the default.

Returns:

The resulting identity configuration members.

Raises:

ValueError – If the short name is taken or the name/email are unforwardable.

Return type:

dict[str, object]

httk.core.identity.set_default_identity(short)

Select the default named operator identity.

Parameters:

short (str) – Short name of a configured identity.

Returns:

The resulting identity configuration members.

Raises:

ValueError – If short is not a configured identity.

Return type:

dict[str, object]

httk.core.identity.remove_identity(short)

Remove one named identity, leaving its key files untouched.

The key files are deliberately kept: removing an identity forgets its attribution, but a signature it already produced must stay verifiable.

Parameters:

short (str) – Short name of a configured identity.

Returns:

The resulting identity configuration members.

Raises:

ValueError – If short is not configured, or is the default while others remain.

Return type:

dict[str, object]

httk.core.identity.identity_seed(seed_path=None)

Return the local identity seed, or None when no key was created.

Nothing here creates a key. An installation that never configured an identity simply has none, and every caller treats that as unsigned rather than as an error, which is what keeps a mixed deployment working.

Parameters:

seed_path (pathlib.Path | None) – Explicit seed path, or None to resolve the default.

Returns:

The local seed, or no value when no valid key exists.

Raises:

ValueError – If the default is unresolvable or a present seed is unreadable.

Return type:

bytes | None

httk.core.identity.identity_public_key(seed_path=None)

Return the recorded local identity public key, or None.

Parameters:

seed_path (pathlib.Path | None) – Explicit seed path, or None to resolve the default.

Returns:

Encoded public key, or None when no identity exists.

Return type:

str | None

httk.core.identity.local_public_keys()

Return the keys configured identities can actually sign with.

The seed is authoritative; a configured identity with no seed is omitted, while a seed refusal remains an error rather than silently narrowing trust.

Returns:

Canonical encoded public keys for the local operator identities.

Raises:

ValueError – If a configured identity seed is unreadable or malformed.

Return type:

list[str]

httk.core.identity.signature_digest(document)

Return the domain-separated digest one identity signature covers.

The digest covers the whole document except the signature itself, in the same canonical JSON every other httk document is hashed as, so the signing key and the signed members travel together and neither can be swapped.

Parameters:

document (collections.abc.Mapping[str, object]) – Document whose detached signature is being calculated.

Returns:

Domain-separated digest of the unsigned document.

Return type:

bytes

httk.core.identity.sign_document(document, *, seed_path=None)

Return document with a detached identity signature, when one is possible.

Signing is optional by construction: a caller with no identity key returns the document unchanged, and a verifier accepts an unsigned document. The signature is attribution — it says which identity published this — and never authorization: nothing is permitted because a document is signed.

Parameters:
Returns:

Document with identity members when a local key exists.

Raises:

ValueError – If the default is unresolvable or a present seed is unreadable.

Return type:

dict[str, object]

class httk.core.identity.DocumentSignature

Report what checking one document’s optional identity signature established.

Parameters:
  • present – Whether the document carried a signature block.

  • valid – Whether the carried signature verified.

  • operator_key – Encoded key from the signature, when present.

  • reason – Explanation when the signature is absent or invalid.

present: bool
valid: bool
operator_key: str | None = None
reason: str | None = None
httk.core.identity.verify_document(document)

Check the optional identity signature of document.

An absent signature is reported as absent rather than as a failure, so a document published by an installation without an identity key stays usable. A signature that is present and does not verify is a failure: it is either damaged or forged, and neither is something to act on.

Parameters:

document (collections.abc.Mapping[str, object]) – Document whose optional signature is checked.

Returns:

Signature presence and verification result.

Return type:

DocumentSignature