//go:build goolm || libolm package infra import ( "context" "fmt" "os" "path/filepath" "maunium.net/go/mautrix" "maunium.net/go/mautrix/crypto/cryptohelper" ) // MatrixCryptoInitConfig parametriza la inicializacion del crypto store Olm/Megolm. type MatrixCryptoInitConfig struct { // Client es el *mautrix.Client ya inicializado via MatrixClientInit. // Debe tener AccessToken, UserID y DeviceID poblados. Client *mautrix.Client // StorePath es la ruta absoluta al archivo SQLite del crypto store. // Debe ser separado del state store. El SDK gestiona el schema internamente. // Si el directorio padre no existe, se crea con permisos 0700. // Ejemplo: "/home/lucas/.config/matrix_client_pc/egutierrez/crypto.db" StorePath string // PickleKey son exactamente 32 bytes usados por cryptohelper para cifrar las // sesiones Olm en disco at-rest. DEBE persistir entre arranques (guardar en keyring). // Si se pierde, el store SQLite se vuelve inutilizable y hay que crear nuevo dispositivo. PickleKey []byte } // MatrixCryptoInitResult contiene el helper listo para usar. type MatrixCryptoInitResult struct { // Helper es el *cryptohelper.CryptoHelper inicializado. // Ya esta asignado a client.Crypto — el Sync loop cifra/descifra automaticamente. Helper *cryptohelper.CryptoHelper // StorePath es la ruta al archivo SQLite del crypto store (igual que cfg.StorePath). StorePath string } // MatrixCryptoInit inicializa el crypto store Olm/Megolm para un cliente mautrix // usando cryptohelper — el wrapper oficial que abstrae SQLite + Olm identity keys + // one-time key upload + decrypt automatico via el Syncer. // // Pasos: // 1. Valida inputs (Client no nil con AccessToken/UserID/DeviceID, StorePath // absoluto, PickleKey exactamente 32 bytes). // 2. Crea el directorio padre de StorePath con permisos 0700 si no existe. // 3. Construye el helper via cryptohelper.NewCryptoHelper(client, pickleKey, storePath). // 4. Llama helper.Init(ctx) — crea tablas SQLite, carga cuenta Olm, sube one-time keys. // 5. Asigna client.Crypto = helper para que SendMessageEvent cifre automaticamente. // 6. Devuelve MatrixCryptoInitResult con el helper listo. func MatrixCryptoInit(ctx context.Context, cfg MatrixCryptoInitConfig) (*MatrixCryptoInitResult, error) { // 1. Validar Client if cfg.Client == nil { return nil, fmt.Errorf("matrix_crypto_init: Client no puede ser nil") } if cfg.Client.AccessToken == "" { return nil, fmt.Errorf("matrix_crypto_init: Client.AccessToken no puede estar vacio") } if cfg.Client.UserID == "" { return nil, fmt.Errorf("matrix_crypto_init: Client.UserID no puede estar vacio") } if cfg.Client.DeviceID == "" { return nil, fmt.Errorf("matrix_crypto_init: Client.DeviceID no puede estar vacio — descubrirlo via MatrixClientInit o Whoami antes de llamar MatrixCryptoInit") } // Validar StorePath if cfg.StorePath == "" { return nil, fmt.Errorf("matrix_crypto_init: StorePath no puede estar vacio") } if !filepath.IsAbs(cfg.StorePath) { return nil, fmt.Errorf("matrix_crypto_init: StorePath debe ser una ruta absoluta (got %q)", cfg.StorePath) } // Validar PickleKey: exactamente 32 bytes if len(cfg.PickleKey) != 32 { return nil, fmt.Errorf("matrix_crypto_init: PickleKey debe tener exactamente 32 bytes (got %d)", len(cfg.PickleKey)) } // 2. Crear directorio padre con permisos 0700 (datos sensibles) storeDir := filepath.Dir(cfg.StorePath) if err := os.MkdirAll(storeDir, 0700); err != nil { return nil, fmt.Errorf("matrix_crypto_init: no se pudo crear directorio del store %q: %w", storeDir, err) } // 3. Construir CryptoHelper — acepta string como path SQLite directamente (v0.28 API) helper, err := cryptohelper.NewCryptoHelper(cfg.Client, cfg.PickleKey, cfg.StorePath) if err != nil { return nil, fmt.Errorf("matrix_crypto_init: NewCryptoHelper failed: %w", err) } // 4. Init: crea tablas SQLite, carga cuenta Olm, sube one-time keys al servidor if err := helper.Init(ctx); err != nil { return nil, fmt.Errorf("matrix_crypto_init: helper.Init failed (comprueba conectividad con Synapse y validez del token): %w", err) } // 5. Asignar client.Crypto para que SendMessageEvent cifre automaticamente cfg.Client.Crypto = helper return &MatrixCryptoInitResult{ Helper: helper, StorePath: cfg.StorePath, }, nil }