mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Both session paths called GenerateAndUploadCrossSigningKeys unconditionally on every start. That published a fresh cross-signing identity each time the bot restarted, so every user's client saw the bot's verification break and had to re-verify it. The freshly-minted recovery key was only ever logged, never kept, so the identity couldn't be recovered either. bootstrapCrossSigning now mints once, persists the recovery key to DATA_DIR/cross_signing.json (0600), and on later starts reuses the stored identity untouched. Two escape hatches, both normally unset: CROSS_SIGNING_REGENERATE=1 forces exactly one remint (every user must then re-verify), and CROSS_SIGNING_RECOVERY_KEY imports an identity created before the bot persisted its own key. Shared by the appservice and masdevice paths, which had drifted into two copies of the same block.
57 lines
1.6 KiB
Go
57 lines
1.6 KiB
Go
package bot
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestRecoveryKeyRoundTrip(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if got := loadRecoveryKey(dir); got != "" {
|
|
t.Fatalf("fresh install returned %q, want empty", got)
|
|
}
|
|
|
|
const key = "EsTd o49d mMLt 3Uf9 Gjn9 x5fv YE9H wF6n aadC q2D8 Fv7j rQ4c"
|
|
saveRecoveryKey(dir, key)
|
|
if got := loadRecoveryKey(dir); got != key {
|
|
t.Fatalf("loadRecoveryKey() = %q, want %q", got, key)
|
|
}
|
|
}
|
|
|
|
// The key is crypto material sitting next to crypto.db; it must not be readable
|
|
// by other users on the host.
|
|
func TestRecoveryKeyFileIsPrivate(t *testing.T) {
|
|
dir := t.TempDir()
|
|
saveRecoveryKey(dir, "some-key")
|
|
info, err := os.Stat(filepath.Join(dir, crossSigningFile))
|
|
if err != nil {
|
|
t.Fatalf("stat: %v", err)
|
|
}
|
|
if perm := info.Mode().Perm(); perm != 0o600 {
|
|
t.Fatalf("recovery key file mode = %o, want 600", perm)
|
|
}
|
|
}
|
|
|
|
// A corrupt store must degrade to "no key" rather than panicking or returning
|
|
// garbage that would be fed to VerifyWithRecoveryKey.
|
|
func TestRecoveryKeyCorruptStore(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(dir, crossSigningFile), []byte("{not json"), 0o600); err != nil {
|
|
t.Fatalf("write: %v", err)
|
|
}
|
|
if got := loadRecoveryKey(dir); got != "" {
|
|
t.Fatalf("corrupt store returned %q, want empty", got)
|
|
}
|
|
}
|
|
|
|
// Overwriting an adopted key must not leave trailing bytes from the longer value.
|
|
func TestRecoveryKeyOverwrite(t *testing.T) {
|
|
dir := t.TempDir()
|
|
saveRecoveryKey(dir, "a-much-longer-original-recovery-key-value")
|
|
saveRecoveryKey(dir, "short")
|
|
if got := loadRecoveryKey(dir); got != "short" {
|
|
t.Fatalf("loadRecoveryKey() = %q, want %q", got, "short")
|
|
}
|
|
}
|