4bce095964
Mueve duckdb_open, clickhouse_open, postgres_open, matrix_* y keyring_token_store
del paquete monolitico functions/infra a subpaquetes propios
(functions/infra/{duckdb,clickhouse,postgres,matrix,keyring}). El paquete infra ya
no importa los drivers (go-duckdb, clickhouse-go, pgx, mautrix, go-keyring), por lo
que las apps que solo usan funciones ligeras (process, cron, http, sqlite) dejan de
arrastrarlos. Reduccion de binarios: dag_engine 72->10MB, registry_api 70->8.7MB,
services_api 70->9MB, call_monitor 68->6.6MB, sqlite_api 70->8.9MB.
Los IDs del registry se mantienen estables (domain: infra en frontmatter). Se
preservan los build tags goolm/libolm de matrix_crypto_init.
Tambien corrige TestSSEHandler: el test leia el body con un unico Read() que con
HTTP chunked solo capturaba el primer evento; ahora usa io.ReadAll hasta EOF.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
108 lines
4.2 KiB
Go
108 lines
4.2 KiB
Go
//go:build goolm || libolm
|
|
|
|
package matrix
|
|
|
|
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
|
|
}
|