2024-01-05 13:44:41 +02:00
|
|
|
package store
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2024-03-22 21:24:30 +02:00
|
|
|
"sync"
|
2024-01-05 13:44:41 +02:00
|
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
|
"github.com/rs/zerolog"
|
2025-02-04 11:48:31 +02:00
|
|
|
"go.mau.fi/util/dbutil"
|
2024-01-05 13:44:41 +02:00
|
|
|
|
|
|
|
|
"go.mau.fi/mautrix-signal/pkg/libsignalgo"
|
2024-10-02 20:39:47 +03:00
|
|
|
signalpb "go.mau.fi/mautrix-signal/pkg/signalmeow/protobuf"
|
2024-01-05 13:44:41 +02:00
|
|
|
)
|
|
|
|
|
|
2024-03-19 19:15:30 +02:00
|
|
|
type sqlStore struct {
|
|
|
|
|
*Container
|
|
|
|
|
AccountID uuid.UUID
|
2024-03-22 21:24:30 +02:00
|
|
|
|
|
|
|
|
contactLock sync.Mutex
|
2025-11-20 13:29:38 +02:00
|
|
|
|
|
|
|
|
blockCacheLock sync.RWMutex
|
|
|
|
|
blockCache map[uuid.UUID]bool
|
2024-01-05 13:44:41 +02:00
|
|
|
}
|
|
|
|
|
|
2024-03-19 19:15:30 +02:00
|
|
|
type scopedSQLStore struct {
|
|
|
|
|
*Container
|
|
|
|
|
AccountID uuid.UUID
|
|
|
|
|
ServiceID libsignalgo.ServiceID
|
2024-01-05 13:44:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type DeviceData struct {
|
|
|
|
|
ACIIdentityKeyPair *libsignalgo.IdentityKeyPair
|
|
|
|
|
PNIIdentityKeyPair *libsignalgo.IdentityKeyPair
|
2024-03-25 21:25:00 +02:00
|
|
|
ACIRegistrationID int
|
2024-01-05 13:44:41 +02:00
|
|
|
PNIRegistrationID int
|
|
|
|
|
ACI uuid.UUID
|
|
|
|
|
PNI uuid.UUID
|
|
|
|
|
DeviceID int
|
|
|
|
|
Number string
|
|
|
|
|
Password string
|
2024-03-22 21:50:26 +02:00
|
|
|
MasterKey []byte
|
2024-10-02 20:39:47 +03:00
|
|
|
AccountRecord *signalpb.AccountRecord
|
2025-01-18 02:58:43 +02:00
|
|
|
AccountEntropyPool libsignalgo.AccountEntropyPool
|
|
|
|
|
EphemeralBackupKey *libsignalgo.BackupKey
|
|
|
|
|
MediaRootBackupKey *libsignalgo.BackupKey
|
2024-01-05 13:44:41 +02:00
|
|
|
}
|
|
|
|
|
|
2024-03-15 15:30:44 +02:00
|
|
|
func (d *DeviceData) ACIServiceID() libsignalgo.ServiceID {
|
|
|
|
|
return libsignalgo.NewACIServiceID(d.ACI)
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-19 19:15:30 +02:00
|
|
|
func (d *DeviceData) PNIServiceID() libsignalgo.ServiceID {
|
|
|
|
|
return libsignalgo.NewPNIServiceID(d.PNI)
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-05 13:44:41 +02:00
|
|
|
func (d *DeviceData) BasicAuthCreds() (string, string) {
|
|
|
|
|
username := fmt.Sprintf("%s.%d", d.ACI, d.DeviceID)
|
|
|
|
|
password := d.Password
|
|
|
|
|
return username, password
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Device is a wrapper for a signalmeow session, including device data,
|
|
|
|
|
// and interfaces for operating on the DB within the session.
|
|
|
|
|
type Device struct {
|
|
|
|
|
DeviceData
|
|
|
|
|
|
|
|
|
|
// NOTE: when adding a new store interface, make sure to assing it below
|
|
|
|
|
// (search for "innerStore" further down in this file)
|
|
|
|
|
|
|
|
|
|
// libsignalgo store interfaces
|
2024-03-25 21:25:00 +02:00
|
|
|
ACIPreKeyStore PreKeyStore
|
|
|
|
|
PNIPreKeyStore PreKeyStore
|
|
|
|
|
ACISessionStore SessionStore
|
|
|
|
|
PNISessionStore SessionStore
|
|
|
|
|
ACIIdentityStore libsignalgo.IdentityKeyStore
|
|
|
|
|
PNIIdentityStore libsignalgo.IdentityKeyStore
|
|
|
|
|
IdentityKeyStore IdentityKeyStore
|
2025-11-27 16:53:59 +02:00
|
|
|
SenderKeyStore SenderKeyStore
|
2024-03-19 19:15:30 +02:00
|
|
|
|
2024-03-22 21:24:30 +02:00
|
|
|
GroupStore GroupStore
|
|
|
|
|
RecipientStore RecipientStore
|
|
|
|
|
DeviceStore DeviceStore
|
2025-01-18 16:29:20 +02:00
|
|
|
BackupStore BackupStore
|
2025-05-12 16:39:54 +03:00
|
|
|
EventBuffer EventBuffer
|
2025-01-18 16:29:20 +02:00
|
|
|
|
2025-02-04 11:48:31 +02:00
|
|
|
sqlStore *sqlStore
|
|
|
|
|
db *dbutil.Database
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type contextKey int64
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
contextKeyContactLock contextKey = 1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func (d *Device) DoContactTxn(ctx context.Context, fn func(context.Context) error) error {
|
|
|
|
|
d.sqlStore.contactLock.Lock()
|
|
|
|
|
defer d.sqlStore.contactLock.Unlock()
|
|
|
|
|
ctx = context.WithValue(ctx, dbutil.ContextKeyDoTxnCallerSkip, 1)
|
|
|
|
|
ctx = context.WithValue(ctx, contextKeyContactLock, true)
|
|
|
|
|
return d.db.DoTxn(ctx, nil, fn)
|
2024-01-05 13:44:41 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-12 16:39:54 +03:00
|
|
|
func (d *Device) DoDecryptionTxn(ctx context.Context, fn func(context.Context) error) error {
|
|
|
|
|
ctx = context.WithValue(ctx, dbutil.ContextKeyDoTxnCallerSkip, 2)
|
|
|
|
|
return d.db.DoTxn(ctx, nil, fn)
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-05 13:44:41 +02:00
|
|
|
func (d *Device) ClearDeviceKeys(ctx context.Context) error {
|
|
|
|
|
// We need to clear out keys associated with the Signal device that no longer has valid credentials
|
|
|
|
|
if d == nil {
|
|
|
|
|
zerolog.Ctx(ctx).Warn().Msg("ClearDeviceKeys called with nil device")
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-03-19 19:15:30 +02:00
|
|
|
err := d.ACIPreKeyStore.DeleteAllPreKeys(ctx)
|
2024-01-06 14:53:48 -07:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2024-03-19 19:15:30 +02:00
|
|
|
err = d.ACISessionStore.RemoveAllSessions(ctx)
|
2024-01-05 13:44:41 +02:00
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Device) IsDeviceLoggedIn() bool {
|
|
|
|
|
return d != nil &&
|
|
|
|
|
d.ACI != uuid.Nil &&
|
|
|
|
|
d.DeviceID != 0 &&
|
|
|
|
|
d.Password != ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Device) ClearPassword(ctx context.Context) error {
|
|
|
|
|
d.Password = ""
|
|
|
|
|
return d.DeviceStore.PutDevice(ctx, &d.DeviceData)
|
|
|
|
|
}
|
2024-03-19 19:15:30 +02:00
|
|
|
|
|
|
|
|
func (d *Device) PreKeyStore(serviceID libsignalgo.ServiceID) PreKeyStore {
|
|
|
|
|
if serviceID == d.ACIServiceID() {
|
|
|
|
|
return d.ACIPreKeyStore
|
|
|
|
|
} else if serviceID == d.PNIServiceID() {
|
|
|
|
|
return d.PNIPreKeyStore
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (d *Device) SessionStore(serviceID libsignalgo.ServiceID) SessionStore {
|
|
|
|
|
if serviceID == d.ACIServiceID() {
|
|
|
|
|
return d.ACISessionStore
|
|
|
|
|
} else if serviceID == d.PNIServiceID() {
|
|
|
|
|
return d.PNISessionStore
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2024-03-25 21:25:00 +02:00
|
|
|
|
|
|
|
|
func (d *Device) IdentityStore(serviceID libsignalgo.ServiceID) libsignalgo.IdentityKeyStore {
|
|
|
|
|
if serviceID == d.ACIServiceID() {
|
|
|
|
|
return d.ACIIdentityStore
|
|
|
|
|
} else if serviceID == d.PNIServiceID() {
|
|
|
|
|
return d.PNIIdentityStore
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|