matrix: auto-bootstrap cross-signing on first startup
Without this, every Matrix bot started under hermes-agent shows the "Encrypted by a device not verified by its owner" badge in Element indefinitely, because the cross-signing chain (master → SSK → device) was never published. Operators currently have to write their own bootstrap script and remember to run it once per bot — and it's easy to get wrong (the obvious base64.b64encode().decode() produces padded keyids that matrix-rust-sdk silently rejects in /keys/query, so even correctly-signed keys fail to load identity in Element). mautrix already has the right primitive: generate_recovery_key() does the full flow — generate seeds, upload privates to SSSS, publish publics to the homeserver, sign the current device with the new SSK, and return the human-readable recovery key. We invoke it once on startup if the bot has no existing cross-signing identity, and log the recovery key with a clear instruction to save it for future restarts via MATRIX_RECOVERY_KEY (which the existing recovery-key path already consumes). Skipped when MATRIX_RECOVERY_KEY is set (existing path takes over) or when the bot already has cross-signing keys on the homeserver (get_own_cross_signing_public_keys returns non-None). Bootstrap failure is non-fatal — logged with hint about UIA; the bot continues without cross-signing and Element will show the warning that prompted this PR. That matches the existing soft-fail pattern for verify_with_recovery_key. Tested against Continuwuity 0.5.7 (no UIA required). Synapse with UIA enabled will need a follow-up PR to thread MATRIX_PASSWORD through to /keys/device_signing/upload.
This commit is contained in:
@@ -698,6 +698,44 @@ class MatrixAdapter(BasePlatformAdapter):
|
||||
logger.warning(
|
||||
"Matrix: recovery key verification failed: %s", exc
|
||||
)
|
||||
else:
|
||||
# No recovery key — bootstrap cross-signing if the bot
|
||||
# has none yet. Without this, Element shows "Encrypted
|
||||
# by a device not verified by its owner" on every
|
||||
# message from this bot, indefinitely. mautrix's
|
||||
# generate_recovery_key does the full flow: generates
|
||||
# MSK/SSK/USK, uploads private keys to SSSS, publishes
|
||||
# public keys to the homeserver, and signs the current
|
||||
# device with the new SSK. Some homeservers require UIA
|
||||
# for /keys/device_signing/upload — those will need an
|
||||
# alternate path; Continuwuity and Synapse-with-shared-
|
||||
# secret accept the unauthenticated upload.
|
||||
try:
|
||||
own_xsign = await olm.get_own_cross_signing_public_keys()
|
||||
except Exception as exc:
|
||||
own_xsign = None
|
||||
logger.warning(
|
||||
"Matrix: cross-signing key lookup failed: %s", exc
|
||||
)
|
||||
if own_xsign is None:
|
||||
try:
|
||||
new_recovery_key = await olm.generate_recovery_key()
|
||||
logger.warning(
|
||||
"Matrix: bootstrapped cross-signing for %s. "
|
||||
"SAVE THIS RECOVERY KEY — set "
|
||||
"MATRIX_RECOVERY_KEY for future restarts so "
|
||||
"the bot can re-sign its device after key "
|
||||
"rotation: %s",
|
||||
client.mxid,
|
||||
new_recovery_key,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"Matrix: cross-signing bootstrap failed "
|
||||
"(non-fatal — Element will show 'not "
|
||||
"verified by its owner'): %s",
|
||||
exc,
|
||||
)
|
||||
|
||||
client.crypto = olm
|
||||
logger.info(
|
||||
|
||||
Reference in New Issue
Block a user