Skip to content

identity

identity

This device's cryptographic identity in the mesh.

Every installation holds one Ed25519 key pair, created on first use. The public half is what other devices are told about; the private half never leaves this machine and never appears in a log, a payload or an error.

Why a key pair rather than the opaque mac-<hex> Succès already had: an identifier a device simply asserts can be asserted by anyone. Section 5 of the mesh specification rules out IP, hostname, user agent, MAC address and non-revocable tokens for exactly that reason. A key is different in kind — the device proves it holds the private half, and revocation is meaningful because the public half is what was recorded.

Storage follows the local API key's hardened pattern (0700 directory, 0600 file, atomic O_EXCL creation, O_NOFOLLOW read): the same threat — a swapped symlink or a world-readable secret — applies identically here.

Classes

DeviceIdentity dataclass

DeviceIdentity(
    device_id: str,
    public_key: bytes,
    name: str,
    platform: str,
    created_at_ms: int,
)

This device, as the rest of the mesh may know it.

Methods:
to_public_dict
to_public_dict() -> dict[str, Any]

Everything shareable — and nothing else. No private key, ever.

Source code in src/diapason/mesh/identity.py
def to_public_dict(self) -> dict[str, Any]:
    """Everything shareable — and nothing else. No private key, ever."""
    return {
        "deviceId": self.device_id,
        "publicKey": self.public_key_b64,
        "name": self.name,
        "platform": self.platform,
        "createdAtMs": self.created_at_ms,
        "ownerId": owner_id(),
    }

Functions:

owner_id

owner_id() -> str

The identity every device of this fleet shares.

Chosen shape (user decision): a locally minted identity propagated by pairing, not an account on a server. No password, no e-mail, nothing to breach remotely — and it still gives commands the "same owner" check spec §9 requires, because a device only ever learns it by being paired.

Created once, then read; never regenerated silently, since a changed owner id would orphan every device already paired.

Source code in src/diapason/mesh/identity.py
def owner_id() -> str:
    """The identity every device of this fleet shares.

    Chosen shape (user decision): a locally minted identity propagated by
    pairing, not an account on a server. No password, no e-mail, nothing to
    breach remotely — and it still gives commands the "same owner" check
    spec §9 requires, because a device only ever learns it by being paired.

    Created once, then read; never regenerated silently, since a changed
    owner id would orphan every device already paired.
    """
    directory = identity_dir()
    directory.mkdir(mode=0o700, parents=True, exist_ok=True)
    path = directory / _OWNER_FILENAME
    if path.exists():
        existing = path.read_text(encoding="utf-8").strip()
        if existing:
            return existing
    import secrets

    minted = f"owner_{secrets.token_hex(16)}"
    path.write_text(minted, encoding="utf-8")
    try:
        path.chmod(0o600)
    except OSError:  # noqa: BLE001
        pass
    return minted

adopt_owner_id

adopt_owner_id(
    value: str, *, remplacer_si_solitaire: bool = False
) -> str

Join an existing fleet: take the owner id our host handed us.

Refuses to overwrite a different established identity — a device cannot silently change fleets, which is how paired devices would lose each other.

remplacer_si_solitaire — constaté le 25 août 2026 en branchant enfin cette fonction : elle était écrite pour un appareil VIERGE, et il n'en existe aucun. owner_id() frappe un identifiant dès le premier appel, et le serveur l'appelle à chaque démarrage pour publier son identité : tout Diapason ayant tourné une fois portait donc déjà une flotte à lui, et refusait d'en rejoindre une. La fonction était juste, mais inatteignable.

La distinction qui manquait n'est pas « a-t-il un identifiant » mais « cet identifiant est-il partagé avec quelqu'un ». Un identifiant frappé tout seul et connu de personne est un nom de naissance, pas une appartenance : le remplacer ne coûte rien. Un identifiant qu'au moins un pair de confiance connaît est une vraie flotte, et l'écraser les perdrait tous d'un coup — c'est le danger que ce docstring nommait depuis le début. L'appelant tranche, et il ne le fait qu'après avoir CONSTATÉ la solitude, jamais par confort.

Source code in src/diapason/mesh/identity.py
def adopt_owner_id(value: str, *, remplacer_si_solitaire: bool = False) -> str:
    """Join an existing fleet: take the owner id our host handed us.

    Refuses to overwrite a different established identity — a device cannot
    silently change fleets, which is how paired devices would lose each other.

    ``remplacer_si_solitaire`` — constaté le 25 août 2026 en branchant enfin
    cette fonction : elle était écrite pour un appareil VIERGE, et il n'en
    existe aucun. ``owner_id()`` frappe un identifiant dès le premier appel,
    et le serveur l'appelle à chaque démarrage pour publier son identité :
    tout Diapason ayant tourné une fois portait donc déjà une flotte à lui,
    et refusait d'en rejoindre une. La fonction était juste, mais
    inatteignable.

    La distinction qui manquait n'est pas « a-t-il un identifiant » mais
    « cet identifiant est-il partagé avec quelqu'un ». Un identifiant frappé
    tout seul et connu de personne est un nom de naissance, pas une
    appartenance : le remplacer ne coûte rien. Un identifiant qu'au moins un
    pair de confiance connaît est une vraie flotte, et l'écraser les
    perdrait tous d'un coup — c'est le danger que ce docstring nommait
    depuis le début. L'appelant tranche, et il ne le fait qu'après avoir
    CONSTATÉ la solitude, jamais par confort.
    """
    candidate = str(value or "").strip()
    if not candidate.startswith("owner_") or len(candidate) > 80:
        raise ValueError("Identifiant de propriétaire invalide.")
    directory = identity_dir()
    directory.mkdir(mode=0o700, parents=True, exist_ok=True)
    path = directory / _OWNER_FILENAME
    if path.exists():
        current = path.read_text(encoding="utf-8").strip()
        if current and current != candidate and not remplacer_si_solitaire:
            raise ValueError(
                "Cet appareil appartient déjà à un autre ensemble d'appareils."
            )
        if current and current != candidate:
            logger.info(
                "adoption d'une flotte : l'identifiant local %s, connu de "
                "personne, cède la place à %s",
                current[:14],
                candidate[:14],
            )
    path.write_text(candidate, encoding="utf-8")
    try:
        path.chmod(0o600)
    except OSError:  # noqa: BLE001
        pass
    return candidate

device_identity

device_identity(*, name: str = '') -> DeviceIdentity

This device's identity, creating the key pair on first call.

Idempotent: subsequent calls read what the first one wrote. The private key is generated once and never regenerated silently — a device whose key changed would be, to every peer, a different device.

Source code in src/diapason/mesh/identity.py
def device_identity(*, name: str = "") -> DeviceIdentity:
    """This device's identity, creating the key pair on first call.

    Idempotent: subsequent calls read what the first one wrote. The private
    key is generated once and never regenerated silently — a device whose key
    changed would be, to every peer, a different device.
    """
    from diapason.security.signing import generate_keypair

    directory = identity_dir()
    directory.mkdir(mode=0o700, parents=True, exist_ok=True)
    try:
        directory.chmod(0o700)
    except OSError:  # noqa: BLE001 - a stricter umask is fine
        pass

    key_path = directory / _KEY_FILENAME
    manifest_path = directory / _MANIFEST_FILENAME

    if key_path.exists() and manifest_path.exists():
        # Read the private key for its side effects only: it re-asserts 0600
        # and refuses a swapped symlink, so a tampered key fails HERE rather
        # than at the first signature, when a command is already in flight.
        _read_private_key(key_path)
        manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
        return DeviceIdentity(
            device_id=str(manifest["deviceId"]),
            public_key=base64.b64decode(manifest["publicKey"]),
            name=str(manifest.get("name") or _default_name()),
            platform=str(manifest.get("platform") or _default_platform()),
            created_at_ms=int(manifest.get("createdAtMs") or _now_ms()),
        )

    keypair = generate_keypair()
    device_id = _legacy_succes_device_id() or _fingerprint(keypair.public_key)
    identity = DeviceIdentity(
        device_id=device_id,
        public_key=keypair.public_key,
        name=name or _default_name(),
        platform=_default_platform(),
        created_at_ms=_now_ms(),
    )
    # Key first, manifest second: a crash between the two is recoverable
    # (the half-written pair is detected by the exists() check above and
    # regenerated), whereas a manifest without its key is not.
    if not key_path.exists():
        _write_private_key(key_path, keypair.private_key)
    manifest_path.write_text(
        json.dumps(identity.to_public_dict(), ensure_ascii=False, indent=2),
        encoding="utf-8",
    )
    try:
        manifest_path.chmod(0o600)
    except OSError:  # noqa: BLE001
        pass
    return identity

public_identity

public_identity() -> dict[str, Any]

What this device may publish about itself.

Source code in src/diapason/mesh/identity.py
def public_identity() -> dict[str, Any]:
    """What this device may publish about itself."""
    return device_identity().to_public_dict()

canonical_bytes

canonical_bytes(payload: dict[str, Any]) -> bytes

The exact bytes both sides sign.

Signing a dict means agreeing on its serialisation first: sorted keys, no incidental whitespace, UTF-8 preserved. Succès already canonicalises its operation payloads this way — same rule, one place.

Source code in src/diapason/mesh/identity.py
def canonical_bytes(payload: dict[str, Any]) -> bytes:
    """The exact bytes both sides sign.

    Signing a dict means agreeing on its serialisation first: sorted keys, no
    incidental whitespace, UTF-8 preserved. Succès already canonicalises its
    operation payloads this way — same rule, one place.
    """
    return json.dumps(
        payload,
        ensure_ascii=False,
        sort_keys=True,
        separators=(",", ":"),
        default=str,
    ).encode("utf-8")

sign_envelope

sign_envelope(payload: dict[str, Any]) -> str

Sign payload with this device's private key. Returns base64.

Source code in src/diapason/mesh/identity.py
def sign_envelope(payload: dict[str, Any]) -> str:
    """Sign *payload* with this device's private key. Returns base64."""
    from diapason.security.signing import sign_b64

    directory = identity_dir()
    device_identity()  # ensure the pair exists before reading it
    private_key = _read_private_key(directory / _KEY_FILENAME)
    return sign_b64(canonical_bytes(payload), private_key)

verify_envelope

verify_envelope(
    payload: dict[str, Any],
    signature_b64: str,
    public_key: bytes,
) -> bool

True when signature_b64 is this payload, signed by public_key.

Source code in src/diapason/mesh/identity.py
def verify_envelope(
    payload: dict[str, Any], signature_b64: str, public_key: bytes
) -> bool:
    """True when *signature_b64* is this payload, signed by *public_key*."""
    from diapason.security.signing import verify_b64

    if not signature_b64:
        return False
    return verify_b64(canonical_bytes(payload), signature_b64, public_key)