matrix-pretix/internal/matrix/client.go

253 lines
5.2 KiB
Go
Raw Permalink Normal View History

2022-07-22 19:52:41 +02:00
package matrix
import (
2022-07-24 02:40:44 +02:00
"context"
"database/sql"
"log"
"sync"
"git.luj0ga.de/franconian/matrix-pretix/internal/config"
2022-07-24 02:40:44 +02:00
"git.luj0ga.de/franconian/matrix-pretix/internal/database"
2022-07-22 19:52:41 +02:00
"maunium.net/go/mautrix"
2022-07-24 02:40:44 +02:00
"maunium.net/go/mautrix/crypto"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
2022-07-22 19:52:41 +02:00
)
2022-07-24 02:40:44 +02:00
type Client struct {
client *mautrix.Client
config *config.MatrixConfig
db *sql.DB
2022-07-25 01:07:28 +02:00
greetedRooms []id.RoomID
2022-07-24 02:40:44 +02:00
olmMachine *crypto.OlmMachine
store *sqlStore
2022-07-27 18:07:06 +02:00
syncer *mautrix.DefaultSyncer
2022-07-24 02:40:44 +02:00
}
func NewClient(config *config.MatrixConfig, db *sql.DB) (*Client, error) {
client, err := mautrix.NewClient(config.HomeserverURL, "", "")
if err != nil {
return nil, err
}
2022-07-24 02:40:44 +02:00
syncer := mautrix.NewDefaultSyncer()
client.Syncer = syncer
store := &sqlStore{db}
client.Store = store
err = store.CreateTables()
if err != nil {
return nil, err
}
c := &Client{
client: client,
config: config,
db: db,
store: store,
syncer: syncer,
2022-07-24 02:40:44 +02:00
}
syncer.OnEventType(event.StateMember, c.handleMemberEvent)
2022-07-24 02:40:44 +02:00
return c, nil
2022-07-24 02:40:44 +02:00
}
func (c *Client) Login() error {
userID, err := makeUserID(c.config.UserIdentifier, c.config.HomeserverURL)
if err != nil {
return err
}
deviceID := c.loadDeviceID(userID)
2022-07-24 02:40:44 +02:00
2022-07-27 18:07:06 +02:00
_, err = c.client.Login(&mautrix.ReqLogin{
2022-07-24 02:40:44 +02:00
Type: mautrix.AuthTypePassword,
Identifier: mautrix.UserIdentifier{
Type: mautrix.IdentifierTypeUser,
2022-07-24 02:40:44 +02:00
User: c.config.UserIdentifier,
},
2022-07-24 02:40:44 +02:00
Password: c.config.Password,
DeviceID: deviceID,
InitialDeviceDisplayName: c.config.DeviceName,
2022-07-24 02:40:44 +02:00
StoreCredentials: true,
})
if err != nil {
2022-07-24 02:40:44 +02:00
return err
}
log.Print("device ID: ", c.client.DeviceID)
2022-07-24 23:44:04 +02:00
2022-07-24 02:40:44 +02:00
return nil
}
func (c *Client) Encrypt() error {
sqlCryptoStore := crypto.NewSQLCryptoStore(
c.db,
database.DBDriverName,
c.client.UserID.String(),
c.client.DeviceID,
2022-07-24 02:40:44 +02:00
[]byte(c.config.PickleKey),
logger{},
)
err := sqlCryptoStore.CreateTables()
if err != nil {
return err
}
c.olmMachine = crypto.NewOlmMachine(c.client, &logger{}, sqlCryptoStore, c.store)
err = c.olmMachine.Load()
if err != nil {
return err
}
c.syncer.OnSync(c.olmMachine.ProcessSyncResponse)
c.syncer.OnEventType(event.StateEncryption, c.handleEncryptionEvent)
return nil
}
func (c *Client) Sync(ctx context.Context, cancel context.CancelFunc, wg *sync.WaitGroup) {
2022-07-24 02:40:44 +02:00
wg.Add(1)
defer wg.Done()
for {
select {
case <-ctx.Done():
return
default:
err := c.client.SyncWithContext(ctx)
if err != nil && err != ctx.Err() {
log.Print(err)
cancel()
2022-07-24 02:40:44 +02:00
}
}
}
}
func (c *Client) Send(roomID id.RoomID, message *event.MessageEventContent) error {
2022-07-24 23:19:52 +02:00
content := event.Content{Parsed: message}
2022-07-25 01:07:28 +02:00
if c.store.IsEncrypted(roomID) {
encrypted, err := c.olmMachine.EncryptMegolmEvent(roomID, event.EventMessage, &content)
if err == crypto.NoGroupSession || err == crypto.SessionExpired || err == crypto.SessionNotShared {
err = c.olmMachine.ShareGroupSession(roomID, c.store.GetRoomMembers(roomID))
if err != nil {
return err
2022-07-25 01:07:28 +02:00
}
encrypted, err = c.olmMachine.EncryptMegolmEvent(roomID, event.EventMessage, &content)
}
if err != nil {
return err
2022-07-25 01:07:28 +02:00
}
_, err = c.client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
if err != nil {
return err
2022-07-25 01:07:28 +02:00
}
} else {
_, err := c.client.SendMessageEvent(roomID, event.EventMessage, &content)
if err != nil {
return err
2022-07-25 01:07:28 +02:00
}
}
return nil
2022-07-25 01:07:28 +02:00
}
func (c *Client) Broadcast(message *event.MessageEventContent) (success bool) {
for _, roomID := range c.store.FindAllSharedRooms(c.client.UserID) {
2022-07-24 23:19:52 +02:00
allowed := false
for _, room := range c.config.AllowedRooms {
if room == roomID.String() {
allowed = true
break
}
}
if !allowed {
continue
}
err := c.Send(roomID, message)
if err != nil {
log.Print(err)
} else {
success = true
}
2022-07-24 23:19:52 +02:00
}
2022-07-27 18:07:06 +02:00
return success
2022-07-24 23:19:52 +02:00
}
2022-07-24 02:40:44 +02:00
func (c *Client) handleMemberEvent(source mautrix.EventSource, evt *event.Event) {
if c.olmMachine != nil {
c.olmMachine.HandleMemberEvent(evt)
}
c.store.SetMembership(evt.RoomID, evt.GetStateKey(), evt.Content.AsMember().Membership)
if evt.GetStateKey() == c.client.UserID.String() && evt.Content.AsMember().Membership == event.MembershipInvite {
2022-07-24 02:40:44 +02:00
allowed := false
for _, room := range c.config.AllowedRooms {
if room == evt.RoomID.String() {
allowed = true
break
}
}
if allowed {
_, err := c.client.JoinRoomByID(evt.RoomID)
if err != nil {
log.Print(err)
}
2022-07-25 01:07:28 +02:00
for _, room := range c.greetedRooms {
if room == evt.RoomID {
return
}
}
message := event.MessageEventContent{
MsgType: event.MsgText,
Body: c.config.Greeting,
}
err = c.Send(evt.RoomID, &message)
if err != nil {
log.Print(err)
return
2022-07-25 01:07:28 +02:00
}
c.greetedRooms = append(c.greetedRooms, evt.RoomID)
2022-07-24 02:40:44 +02:00
} else {
_, err := c.client.LeaveRoom(evt.RoomID)
if err != nil {
log.Print(err)
}
}
}
}
func (c *Client) handleEncryptionEvent(source mautrix.EventSource, evt *event.Event) {
c.store.SetEncryptionEvent(evt.RoomID, evt.Content.AsEncryption())
}
func (c *Client) loadDeviceID(accountID id.UserID) (deviceID id.DeviceID) {
row := c.db.QueryRow("SELECT device_id FROM crypto_account WHERE account_id = ?;", accountID)
2022-07-24 02:40:44 +02:00
err := row.Scan(&deviceID)
if err != nil {
return ""
}
2022-07-24 02:40:44 +02:00
return deviceID
2022-07-22 19:52:41 +02:00
}