pub struct AuthorId { /* private fields */ }vcs-git only.Expand description
A canonical author identity, keyed by lowercased email.
Falls back to the lowercased display name when the email is empty (some imported histories carry name-only authors). Compared and hashed by that key so author counts and ownership are stable across display-name variation.
The key is normally the plaintext canonical email; a from_digest
identity instead holds the SHA-256 digest, used when an identity is
reconstructed from the persistent VCS cache (issue #334), which never
stores plaintext author keys on disk. Both forms share the same
equality/hashing contract — distinct-author counts and ownership
ratios are preserved either way because the digest is collision-free
over the author set in practice (SHA-256 of distinct emails yields
distinct hashes) — and within any one walk every identity is of the
same form, so the is_digest flag never makes two
keys-for-the-same-person compare unequal.
Implementations§
Source§impl AuthorId
impl AuthorId
Sourcepub fn new(name: &[u8], email: &[u8]) -> Self
pub fn new(name: &[u8], email: &[u8]) -> Self
Build a canonical identity from raw signature bytes.
Bytes are interpreted lossily as UTF-8: an identity is a map key and a hash pre-image, never re-emitted as a path, so a stray non-UTF-8 byte degrading to U+FFFD is acceptable and keeps the function total.
Sourcepub fn has_identity(&self) -> bool
pub fn has_identity(&self) -> bool
Whether this identity carries a usable key.
An author with neither a name nor an email trims to the empty key,
which would otherwise collapse every keyless author into one
phantom identity (the same Eq/Hash). Callers building a
participant set drop keyless identities so they never anchor
ownership or inflate edit counts (issue #817). A
from_digest identity is never keyless
(a SHA-256 hex is non-empty).
Sourcepub fn from_digest(digest: String) -> Self
pub fn from_digest(digest: String) -> Self
Reconstruct an identity from a previously-emitted SHA-256 hashed
digest. The persistent VCS cache stores authors in this hashed form
(never plaintext — see hashed for what that does and does not
protect), and replaying it must reproduce the same author counts,
ownership, and emitted hashes as a fresh walk — so a from_digest
identity hashes to itself.
Sourcepub fn hashed(&self) -> String
pub fn hashed(&self) -> String
SHA-256 hex digest of the canonical key, for
--emit-author-details. Stable across runs, so the same author
carries the same pseudonym in every report and survives a cache
round-trip.
§Privacy: pseudonym, not anonymization
The digest avoids emitting the plaintext email and deters casual disclosure, but it is not cryptographically irreversible. The pre-image is an email — low-entropy and enumerable — and commit histories are public, so an attacker with a candidate set of emails can recover the mapping by hashing each candidate or with a precomputed email→hash table (the Gravatar weakness). Treat published digests as pseudonymization that keeps plaintext emails out of output and caches, not as robust anonymization against a determined attacker. Hardening (a keyed HMAC / slow KDF) is tracked as a follow-up; it must be reconciled with the issue-#334 cache-replay invariant that replaying reproduces identical digests.
A from_digest identity already is the
digest, so it is returned unchanged (re-hashing would double-hash
and diverge from a fresh walk).
Sourcepub fn emit_hashed(&self, key: Option<&AuthorHashKey>) -> String
pub fn emit_hashed(&self, key: Option<&AuthorHashKey>) -> String
The author digest emitted for --emit-author-details, optionally
hardened with a caller-supplied AuthorHashKey.
Without a key this is exactly hashed — the bare
SHA-256 — so default output is unchanged. With a key it is
HMAC-SHA256(key, hashed_hex): an attacker holding a candidate set
of emails can no longer recover the mapping by hashing each
candidate, nor with a precomputed email→hash table (the Gravatar
weakness hashed documents), because computing the
digest for any candidate now requires the secret key they do not
hold.
Keying the inner digest rather than the raw email is what
preserves the issue-#334 cache-replay invariant: the persistent
cache stores the unkeyed inner SHA-256 (a
from_digest identity is that digest), so
replaying a cached walk under any key reproduces the same emitted
value as a fresh walk, and the same cached walk can be re-finalized
under a different key without re-walking. The trade-off is that the
on-disk cache still holds the unkeyed digest; it is local-only and
never published, matching the cache’s existing threat model.
Trait Implementations§
impl Eq for AuthorId
impl StructuralPartialEq for AuthorId
Auto Trait Implementations§
impl Freeze for AuthorId
impl RefUnwindSafe for AuthorId
impl Send for AuthorId
impl Sync for AuthorId
impl Unpin for AuthorId
impl UnsafeUnpin for AuthorId
impl UnwindSafe for AuthorId
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.