updated deps

This commit is contained in:
Aine
2023-02-13 13:02:13 +02:00
parent dbe4a73174
commit 19e2047a2b
140 changed files with 4106 additions and 12049 deletions

View File

@@ -1,3 +1,31 @@
## v0.13.0 (2023-01-16)
* **Breaking change:** Removed `IsTyping` and `SetTyping` in `appservice.StateStore`
and removed the `TypingStateStore` struct implementing those methods.
* **Breaking change:** Removed legacy fields in Beeper MSS events.
* Added knocked rooms to sync response structs.
* Added wrapper for `/timestamp_to_event` endpoint added in Matrix v1.6.
* Fixed MSC3870 uploads not failing properly after using up the max retry count.
* Fixed parsing non-positive ordered list start positions in HTML parser.
## v0.12.4 (2022-12-16)
* Added `SendReceipt` to support private read receipts and thread receipts in
the same function. `MarkReadWithContent` is now deprecated.
* Changed media download methods to return errors if the server returns a
non-2xx status code.
* Removed legacy `sql_store_upgrade.Upgrade` method. Using `store.DB.Upgrade()`
after `NewSQLCryptoStore(...)` is recommended instead (the bridge module does
this automatically).
* Added missing `suggested` field to `m.space.child` content struct.
* Added `device_unused_fallback_key_types` to `/sync` response and appservice
transaction structs.
* Changed `ReqSetReadMarkers` to omit empty fields.
* Changed bridge configs to force `sqlite3-fk-wal` instead of `sqlite3`.
* Updated bridge helper to close database connection when stopping.
* Fixed read receipt and account data endpoints sending `null` instead of an
empty object as the body when content isn't provided.
## v0.12.3 (2022-11-16)
* **Breaking change:** Added logging for row iteration in the dbutil package.
@@ -123,6 +151,11 @@
[@nightmared]: https://github.com/nightmared
[#83]: https://github.com/mautrix/go/pull/83
## v0.11.1 (2023-01-15)
* Fixed parsing non-positive ordered list start positions in HTML parser
(backport of the same fix in v0.13.0).
## v0.11.0 (2022-05-16)
* Bumped minimum Go version to 1.17.

View File

@@ -44,7 +44,7 @@ func (as *AppService) Start() {
} else {
err = as.server.ListenAndServeTLS(as.Host.TLSCert, as.Host.TLSKey)
}
if err != nil && err.Error() != "http: Server closed" {
if err != nil && !errors.Is(err, http.ErrServerClosed) {
as.Log.Fatalln("Error while listening:", err)
} else {
as.Log.Debugln("Listener stopped.")

View File

@@ -11,7 +11,6 @@ import (
"errors"
"fmt"
"strings"
"time"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
@@ -256,11 +255,12 @@ func (intent *IntentAPI) SendCustomMembershipEvent(roomID id.RoomID, target id.U
ok = memberContent != nil
}
if !ok {
err := intent.StateEvent(roomID, event.StateMember, target.String(), &memberContent)
profile, err := intent.GetProfile(target)
if err != nil {
intent.Logger.Debugfln("Failed to get member info for %s/%s to fill new %s membership event: %v", roomID, target, membership, err)
intent.Logger.Debugfln("Failed to get profile for %s to fill new %s membership event: %v", target, membership, err)
} else {
ok = true
content.Displayname = profile.DisplayName
content.AvatarURL = profile.AvatarURL.CUString()
}
}
}
@@ -402,21 +402,6 @@ func (intent *IntentAPI) SetPowerLevel(roomID id.RoomID, userID id.UserID, level
return nil, nil
}
func (intent *IntentAPI) UserTyping(roomID id.RoomID, typing bool, timeout time.Duration) (resp *mautrix.RespTyping, err error) {
if intent.as.StateStore.IsTyping(roomID, intent.UserID) == typing {
return
}
resp, err = intent.Client.UserTyping(roomID, typing, timeout)
if err != nil {
return
}
if !typing {
timeout = -1
}
intent.as.StateStore.SetTyping(roomID, intent.UserID, timeout)
return
}
func (intent *IntentAPI) SendText(roomID id.RoomID, text string) (*mautrix.RespSendEvent, error) {
if err := intent.EnsureJoined(roomID); err != nil {
return nil, err

View File

@@ -20,6 +20,7 @@ import (
)
type OTKCountMap = map[id.UserID]map[id.DeviceID]mautrix.OTKCount
type FallbackKeyMap = map[id.UserID]map[id.DeviceID][]id.KeyAlgorithm
// Transaction contains a list of events.
type Transaction struct {
@@ -29,11 +30,13 @@ type Transaction struct {
DeviceLists *mautrix.DeviceLists `json:"device_lists,omitempty"`
DeviceOTKCount OTKCountMap `json:"device_one_time_keys_count,omitempty"`
FallbackKeys FallbackKeyMap `json:"device_unused_fallback_key_types,omitempty"`
MSC2409EphemeralEvents []*event.Event `json:"de.sorunome.msc2409.ephemeral,omitempty"`
MSC2409ToDeviceEvents []*event.Event `json:"de.sorunome.msc2409.to_device,omitempty"`
MSC3202DeviceLists *mautrix.DeviceLists `json:"org.matrix.msc3202.device_lists,omitempty"`
MSC3202DeviceOTKCount OTKCountMap `json:"org.matrix.msc3202.device_one_time_keys_count,omitempty"`
MSC3202FallbackKeys FallbackKeyMap `json:"org.matrix.msc3202.device_unused_fallback_key_types,omitempty"`
}
func (txn *Transaction) MarshalZerologObject(ctx *zerolog.Event) {
@@ -46,6 +49,9 @@ func (txn *Transaction) MarshalZerologObject(ctx *zerolog.Event) {
if txn.DeviceLists != nil {
ctx.Int("device_changes", len(txn.DeviceLists.Changed))
}
if txn.FallbackKeys != nil {
ctx.Int("fallback_key_users", len(txn.FallbackKeys))
}
}
func (txn *Transaction) ContentString() string {
@@ -73,6 +79,11 @@ func (txn *Transaction) ContentString() string {
} else if txn.MSC3202DeviceLists != nil {
parts = append(parts, fmt.Sprintf("%d device list changes (unstable)", len(txn.MSC3202DeviceLists.Changed)))
}
if txn.FallbackKeys != nil {
parts = append(parts, fmt.Sprintf("unused fallback key counts for %d users", len(txn.FallbackKeys)))
} else if txn.MSC3202FallbackKeys != nil {
parts = append(parts, fmt.Sprintf("unused fallback key counts for %d users (unstable)", len(txn.MSC3202FallbackKeys)))
}
return strings.Join(parts, ", ")
}

View File

@@ -8,7 +8,6 @@ package appservice
import (
"sync"
"time"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
@@ -18,9 +17,6 @@ type StateStore interface {
IsRegistered(userID id.UserID) bool
MarkRegistered(userID id.UserID)
IsTyping(roomID id.RoomID, userID id.UserID) bool
SetTyping(roomID id.RoomID, userID id.UserID, timeout time.Duration)
IsInRoom(roomID id.RoomID, userID id.UserID) bool
IsInvited(roomID id.RoomID, userID id.UserID) bool
IsMembership(roomID id.RoomID, userID id.UserID, allowedMemberships ...event.Membership) bool
@@ -45,67 +41,21 @@ func (as *AppService) UpdateState(evt *event.Event) {
}
}
type TypingStateStore struct {
typing map[id.RoomID]map[id.UserID]time.Time
typingLock sync.RWMutex
}
func NewTypingStateStore() *TypingStateStore {
return &TypingStateStore{
typing: make(map[id.RoomID]map[id.UserID]time.Time),
}
}
func (store *TypingStateStore) IsTyping(roomID id.RoomID, userID id.UserID) bool {
store.typingLock.RLock()
defer store.typingLock.RUnlock()
roomTyping, ok := store.typing[roomID]
if !ok {
return false
}
typingEndsAt := roomTyping[userID]
return typingEndsAt.After(time.Now())
}
func (store *TypingStateStore) SetTyping(roomID id.RoomID, userID id.UserID, timeout time.Duration) {
store.typingLock.Lock()
defer store.typingLock.Unlock()
roomTyping, ok := store.typing[roomID]
if !ok {
if timeout >= 0 {
roomTyping = map[id.UserID]time.Time{
userID: time.Now().Add(timeout),
}
} else {
return
}
} else {
if timeout >= 0 {
roomTyping[userID] = time.Now().Add(timeout)
} else {
delete(roomTyping, userID)
}
}
store.typing[roomID] = roomTyping
}
type BasicStateStore struct {
registrationsLock sync.RWMutex `json:"-"`
Registrations map[id.UserID]bool `json:"registrations"`
membersLock sync.RWMutex `json:"-"`
Members map[id.RoomID]map[id.UserID]*event.MemberEventContent `json:"memberships"`
powerLevelsLock sync.RWMutex `json:"-"`
PowerLevels map[id.RoomID]*event.PowerLevelsEventContent `json:"power_levels"`
Registrations map[id.UserID]bool `json:"registrations"`
Members map[id.RoomID]map[id.UserID]*event.MemberEventContent `json:"memberships"`
PowerLevels map[id.RoomID]*event.PowerLevelsEventContent `json:"power_levels"`
*TypingStateStore
registrationsLock sync.RWMutex
membersLock sync.RWMutex
powerLevelsLock sync.RWMutex
}
func NewBasicStateStore() StateStore {
return &BasicStateStore{
Registrations: make(map[id.UserID]bool),
Members: make(map[id.RoomID]map[id.UserID]*event.MemberEventContent),
PowerLevels: make(map[id.RoomID]*event.PowerLevelsEventContent),
TypingStateStore: NewTypingStateStore(),
Registrations: make(map[id.UserID]bool),
Members: make(map[id.RoomID]map[id.UserID]*event.MemberEventContent),
PowerLevels: make(map[id.RoomID]*event.PowerLevelsEventContent),
}
}

View File

@@ -220,7 +220,11 @@ func doUpgrade(helper *up.Helper) {
helper.Copy(up.Str, "appservice", "address")
helper.Copy(up.Str, "appservice", "hostname")
helper.Copy(up.Int, "appservice", "port")
helper.Copy(up.Str, "appservice", "database", "type")
if dbType, ok := helper.Get(up.Str, "appservice", "database", "type"); ok && dbType == "sqlite3" {
helper.Set(up.Str, "sqlite3-fk-wal", "appservice", "database", "type")
} else {
helper.Copy(up.Str, "appservice", "database", "type")
}
helper.Copy(up.Str, "appservice", "database", "uri")
helper.Copy(up.Int, "appservice", "database", "max_open_conns")
helper.Copy(up.Int, "appservice", "database", "max_idle_conns")

View File

@@ -830,6 +830,12 @@ func (cli *Client) JoinRoomByID(roomID id.RoomID) (resp *RespJoinRoom, err error
return
}
func (cli *Client) GetProfile(mxid id.UserID) (resp *RespUserProfile, err error) {
urlPath := cli.BuildClientURL("v3", "profile", mxid)
_, err = cli.MakeRequest("GET", urlPath, nil, &resp)
return
}
// GetDisplayName returns the display name of the user with the specified MXID. See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3profileuseriddisplayname
func (cli *Client) GetDisplayName(mxid id.UserID) (resp *RespUserDisplayName, err error) {
urlPath := cli.BuildClientURL("v3", "profile", mxid, "displayname")
@@ -896,7 +902,7 @@ func (cli *Client) GetAccountData(name string, output interface{}) (err error) {
// SetAccountData sets the user's account data of this type. See https://spec.matrix.org/v1.2/client-server-api/#put_matrixclientv3useruseridaccount_datatype
func (cli *Client) SetAccountData(name string, data interface{}) (err error) {
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "account_data", name)
_, err = cli.MakeRequest("PUT", urlPath, &data, nil)
_, err = cli.MakeRequest("PUT", urlPath, data, nil)
if err != nil {
return err
}
@@ -914,7 +920,7 @@ func (cli *Client) GetRoomAccountData(roomID id.RoomID, name string, output inte
// SetRoomAccountData sets the user's account data of this type in a specific room. See https://spec.matrix.org/v1.2/client-server-api/#put_matrixclientv3useruseridroomsroomidaccount_datatype
func (cli *Client) SetRoomAccountData(roomID id.RoomID, name string, data interface{}) (err error) {
urlPath := cli.BuildClientURL("v3", "user", cli.UserID, "rooms", roomID, "account_data", name)
_, err = cli.MakeRequest("PUT", urlPath, &data, nil)
_, err = cli.MakeRequest("PUT", urlPath, data, nil)
if err != nil {
return err
}
@@ -1234,14 +1240,21 @@ func (cli *Client) Download(mxcURL id.ContentURI) (io.ReadCloser, error) {
}
func (cli *Client) DownloadContext(ctx context.Context, mxcURL id.ContentURI) (io.ReadCloser, error) {
if req, err := http.NewRequestWithContext(ctx, http.MethodGet, cli.GetDownloadURL(mxcURL), nil); err != nil {
return nil, err
} else if req.Header.Set("User-Agent", cli.UserAgent+" (media downloader)"); false {
panic("false is true")
} else if resp, err := cli.Client.Do(req); err != nil {
return nil, err
_, resp, err := cli.downloadContext(ctx, mxcURL)
return resp.Body, err
}
func (cli *Client) downloadContext(ctx context.Context, mxcURL id.ContentURI) (*http.Request, *http.Response, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, cli.GetDownloadURL(mxcURL), nil)
if err != nil {
return req, nil, err
}
req.Header.Set("User-Agent", cli.UserAgent+" (media downloader)")
cli.LogRequest(req)
if resp, err := cli.Client.Do(req); err != nil {
return req, nil, err
} else {
return resp.Body, nil
return req, resp, nil
}
}
@@ -1250,12 +1263,19 @@ func (cli *Client) DownloadBytes(mxcURL id.ContentURI) ([]byte, error) {
}
func (cli *Client) DownloadBytesContext(ctx context.Context, mxcURL id.ContentURI) ([]byte, error) {
resp, err := cli.DownloadContext(ctx, mxcURL)
req, resp, err := cli.downloadContext(ctx, mxcURL)
if err != nil {
return nil, err
}
defer resp.Close()
return io.ReadAll(resp)
defer resp.Body.Close()
if resp.StatusCode >= 300 || resp.StatusCode < 200 {
respErr := &RespError{}
if _ = json.NewDecoder(resp.Body).Decode(respErr); respErr.ErrCode == "" {
respErr = nil
}
return nil, HTTPError{Request: req, Response: resp, RespError: respErr}
}
return io.ReadAll(resp.Body)
}
// UnstableCreateMXC creates a blank Matrix content URI to allow uploading the content asynchronously later.
@@ -1328,6 +1348,18 @@ type ReqUploadMedia struct {
UploadURL string
}
func (cli *Client) tryUploadMediaToURL(url, contentType string, content io.Reader) (*http.Response, error) {
cli.Logger.Debugfln("Uploading media to external URL %s", url)
req, err := http.NewRequest(http.MethodPut, url, content)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
req.Header.Set("User-Agent", cli.UserAgent+" (external media uploader)")
return http.DefaultClient.Do(req)
}
func (cli *Client) uploadMediaToURL(data ReqUploadMedia) (*RespMediaUpload, error) {
retries := cli.DefaultHTTPRetries
if data.ContentBytes == nil {
@@ -1335,29 +1367,26 @@ func (cli *Client) uploadMediaToURL(data ReqUploadMedia) (*RespMediaUpload, erro
retries = 0
}
for {
if data.Content == nil {
data.Content = bytes.NewReader(data.ContentBytes)
reader := data.Content
if reader == nil {
reader = bytes.NewReader(data.ContentBytes)
} else {
data.Content = nil
}
cli.Logger.Debugfln("Uploading media to external URL %s", data.UploadURL)
req, err := http.NewRequest(http.MethodPut, data.UploadURL, data.Content)
if err != nil {
resp, err := cli.tryUploadMediaToURL(data.UploadURL, data.ContentType, reader)
if err == nil {
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
// Everything is fine
break
}
err = fmt.Errorf("HTTP %d", resp.StatusCode)
}
if retries <= 0 {
cli.logWarning("Error uploading media to %s: %v, not retrying", data.UploadURL, err)
return nil, err
}
// Tell the next retry to create a new reader from ContentBytes
data.Content = nil
req.Header.Set("Content-Type", data.ContentType)
req.Header.Set("User-Agent", cli.UserAgent+" (external media uploader)")
resp, err := http.DefaultClient.Do(req)
if err != nil {
cli.Logger.Debugfln("Error uploading media to %s: %v, retrying", data.UploadURL, err)
retries--
} else if resp.StatusCode >= 400 || resp.StatusCode < 200 {
cli.Logger.Debugfln("Error uploading media to %s: HTTP %d, retrying", data.UploadURL, resp.StatusCode)
retries--
} else {
break
}
cli.Logger.Debugfln("Error uploading media to %s: %v, retrying", data.UploadURL, err)
retries--
}
query := map[string]string{}
@@ -1483,7 +1512,7 @@ func (cli *Client) Hierarchy(roomID id.RoomID, req *ReqHierarchy) (resp *RespHie
// Messages returns a list of message and state events for a room. It uses
// pagination query parameters to paginate history in the room.
// See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3roomsroomidmessages
func (cli *Client) Messages(roomID id.RoomID, from, to string, dir rune, filter *FilterPart, limit int) (resp *RespMessages, err error) {
func (cli *Client) Messages(roomID id.RoomID, from, to string, dir Direction, filter *FilterPart, limit int) (resp *RespMessages, err error) {
query := map[string]string{
"from": from,
"dir": string(dir),
@@ -1507,6 +1536,19 @@ func (cli *Client) Messages(roomID id.RoomID, from, to string, dir rune, filter
return
}
// TimestampToEvent finds the ID of the event closest to the given timestamp.
//
// See https://spec.matrix.org/v1.6/client-server-api/#get_matrixclientv1roomsroomidtimestamp_to_event
func (cli *Client) TimestampToEvent(roomID id.RoomID, timestamp time.Time, dir Direction) (resp *RespTimestampToEvent, err error) {
query := map[string]string{
"ts": strconv.FormatInt(timestamp.UnixMilli(), 10),
"dir": string(dir),
}
urlPath := cli.BuildURLWithQuery(ClientURLPath{"v1", "rooms", roomID, "timestamp_to_event"}, query)
_, err = cli.MakeRequest(http.MethodGet, urlPath, nil, &resp)
return
}
// Context returns a number of events that happened just before and after the
// specified event. It use pagination query parameters to paginate history in
// the room.
@@ -1536,20 +1578,29 @@ func (cli *Client) GetEvent(roomID id.RoomID, eventID id.EventID) (resp *event.E
}
func (cli *Client) MarkRead(roomID id.RoomID, eventID id.EventID) (err error) {
return cli.MarkReadWithContent(roomID, eventID, struct{}{})
return cli.SendReceipt(roomID, eventID, event.ReceiptTypeRead, nil)
}
// MarkReadWithContent sends a read receipt including custom data.
// N.B. This is not (yet) a part of the spec, normal servers will drop any extra content.
//
// Deprecated: Use SendReceipt instead.
func (cli *Client) MarkReadWithContent(roomID id.RoomID, eventID id.EventID, content interface{}) (err error) {
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "receipt", "m.read", eventID)
_, err = cli.MakeRequest("POST", urlPath, &content, nil)
return cli.SendReceipt(roomID, eventID, event.ReceiptTypeRead, content)
}
// SendReceipt sends a receipt, usually specifically a read receipt.
//
// Passing nil as the content is safe, the library will automatically replace it with an empty JSON object.
// To mark a message in a specific thread as read, use pass a ReqSendReceipt as the content.
func (cli *Client) SendReceipt(roomID id.RoomID, eventID id.EventID, receiptType event.ReceiptType, content interface{}) (err error) {
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "receipt", receiptType, eventID)
_, err = cli.MakeRequest("POST", urlPath, content, nil)
return
}
func (cli *Client) SetReadMarkers(roomID id.RoomID, content interface{}) (err error) {
urlPath := cli.BuildClientURL("v3", "rooms", roomID, "read_markers")
_, err = cli.MakeRequest("POST", urlPath, &content, nil)
_, err = cli.MakeRequest("POST", urlPath, content, nil)
return
}
@@ -1782,6 +1833,24 @@ func (cli *Client) BatchSend(roomID id.RoomID, req *ReqBatchSend) (resp *RespBat
return
}
func (cli *Client) BeeperMergeRooms(req *ReqBeeperMergeRoom) (resp *RespBeeperMergeRoom, err error) {
urlPath := cli.BuildClientURL("unstable", "com.beeper.chatmerging", "merge")
_, err = cli.MakeRequest(http.MethodPost, urlPath, req, &resp)
return
}
func (cli *Client) BeeperSplitRoom(req *ReqBeeperSplitRoom) (resp *RespBeeperSplitRoom, err error) {
urlPath := cli.BuildClientURL("unstable", "com.beeper.chatmerging", "rooms", req.RoomID, "split")
_, err = cli.MakeRequest(http.MethodPost, urlPath, req, &resp)
return
}
func (cli *Client) BeeperDeleteRoom(roomID id.RoomID) (err error) {
urlPath := cli.BuildClientURL("unstable", "com.beeper.yeet", "rooms", roomID, "delete")
_, err = cli.MakeRequest(http.MethodPost, urlPath, nil, nil)
return
}
// TxnID returns the next transaction ID.
func (cli *Client) TxnID() string {
txnID := atomic.AddInt32(&cli.txnID, 1)

View File

@@ -10,6 +10,7 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/id"
@@ -38,7 +39,14 @@ func (mach *OlmMachine) DecryptMegolmEvent(evt *event.Event) (*event.Event, erro
} else if content.Algorithm != id.AlgorithmMegolmV1 {
return nil, UnsupportedAlgorithm
}
sess, err := mach.CryptoStore.GetGroupSession(evt.RoomID, content.SenderKey, content.SessionID)
encryptionRoomID := evt.RoomID
// Allow the server to move encrypted events between rooms if both the real room and target room are on a non-federatable .local domain.
// The message index checks to prevent replay attacks still apply and aren't based on the room ID,
// so the event ID and timestamp must remain the same when the event is moved to a different room.
if origRoomID, ok := evt.Content.Raw["com.beeper.original_room_id"].(string); ok && strings.HasSuffix(origRoomID, ".local") && strings.HasSuffix(evt.RoomID.String(), ".local") {
encryptionRoomID = id.RoomID(origRoomID)
}
sess, err := mach.CryptoStore.GetGroupSession(encryptionRoomID, content.SenderKey, content.SessionID)
if err != nil {
return nil, fmt.Errorf("failed to get group session: %w", err)
} else if sess == nil {
@@ -93,13 +101,13 @@ func (mach *OlmMachine) DecryptMegolmEvent(evt *event.Event) (*event.Event, erro
err = json.Unmarshal(plaintext, &megolmEvt)
if err != nil {
return nil, fmt.Errorf("failed to parse megolm payload: %w", err)
} else if megolmEvt.RoomID != evt.RoomID {
} else if megolmEvt.RoomID != encryptionRoomID {
return nil, WrongRoom
}
megolmEvt.Type.Class = evt.Type.Class
err = megolmEvt.Content.ParseRaw(megolmEvt.Type)
if err != nil {
if event.IsUnsupportedContentType(err) {
if errors.Is(err, event.ErrUnsupportedContentType) {
mach.Log.Warn("Unsupported event type %s in encrypted event %s", megolmEvt.Type.Repr(), evt.ID)
} else {
return nil, fmt.Errorf("failed to parse content of megolm payload event: %w", err)
@@ -113,8 +121,9 @@ func (mach *OlmMachine) DecryptMegolmEvent(evt *event.Event) (*event.Event, erro
} else {
mach.Log.Trace("Not overriding relation data in %s, as encrypted payload already has it", evt.ID)
}
} else {
mach.Log.Warn("Encrypted event %s has relation data, but content type %T (%s) doesn't support it", evt.ID, megolmEvt.Content.Parsed, megolmEvt.Type.String())
}
if _, hasRelation := megolmEvt.Content.Raw["m.relates_to"]; !hasRelation {
megolmEvt.Content.Raw["m.relates_to"] = evt.Content.Raw["m.relates_to"]
}
}
megolmEvt.Type.Class = evt.Type.Class

View File

@@ -94,7 +94,7 @@ func (mach *OlmMachine) decryptAndParseOlmCiphertext(sender id.UserID, senderKey
}
err = olmEvt.Content.ParseRaw(olmEvt.Type)
if err != nil && !event.IsUnsupportedContentType(err) {
if err != nil && !errors.Is(err, event.ErrUnsupportedContentType) {
return nil, fmt.Errorf("failed to parse content of olm payload event: %w", err)
}

View File

@@ -55,10 +55,6 @@ func NewSQLCryptoStore(db *dbutil.Database, log dbutil.DatabaseLogger, accountID
}
}
func (store *SQLCryptoStore) Upgrade() error {
return store.DB.Upgrade()
}
// Flush does nothing for this implementation as data is already persisted in the database.
func (store *SQLCryptoStore) Flush() error {
return nil

View File

@@ -7,7 +7,6 @@
package sql_store_upgrade
import (
"database/sql"
"embed"
"fmt"
@@ -27,14 +26,3 @@ func init() {
})
Table.RegisterFS(fs)
}
// Upgrade upgrades the database from the current to the latest version available.
func Upgrade(sqlDB *sql.DB, dialect string) error {
db, err := dbutil.NewWithDB(sqlDB, dialect)
if err != nil {
return err
}
db.VersionTable = VersionTableName
db.UpgradeTable = Table
return db.Upgrade()
}

View File

@@ -13,12 +13,13 @@ import (
type MessageStatusReason string
const (
MessageStatusGenericError MessageStatusReason = "m.event_not_handled"
MessageStatusUnsupported MessageStatusReason = "com.beeper.unsupported_event"
MessageStatusUndecryptable MessageStatusReason = "com.beeper.undecryptable_event"
MessageStatusTooOld MessageStatusReason = "m.event_too_old"
MessageStatusNetworkError MessageStatusReason = "m.foreign_network_error"
MessageStatusNoPermission MessageStatusReason = "m.no_permission"
MessageStatusGenericError MessageStatusReason = "m.event_not_handled"
MessageStatusUnsupported MessageStatusReason = "com.beeper.unsupported_event"
MessageStatusUndecryptable MessageStatusReason = "com.beeper.undecryptable_event"
MessageStatusTooOld MessageStatusReason = "m.event_too_old"
MessageStatusNetworkError MessageStatusReason = "m.foreign_network_error"
MessageStatusNoPermission MessageStatusReason = "m.no_permission"
MessageStatusBridgeUnavailable MessageStatusReason = "m.bridge_unavailable"
)
type MessageStatus string
@@ -38,27 +39,9 @@ type BeeperMessageStatusEventContent struct {
Error string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
Success bool `json:"success"`
CanRetry *bool `json:"can_retry,omitempty"`
StillWorking bool `json:"still_working,omitempty"`
LastRetry id.EventID `json:"last_retry,omitempty"`
}
func (status *BeeperMessageStatusEventContent) FillLegacyBooleans() {
trueVal := true
falseVal := true
switch status.Status {
case MessageStatusSuccess:
status.Success = true
case MessageStatusPending:
status.CanRetry = &trueVal
status.StillWorking = true
case MessageStatusRetriable:
status.CanRetry = &trueVal
case MessageStatusFail:
status.CanRetry = &falseVal
}
MutateEventKey string `json:"mutate_event_key,omitempty"`
}
type BeeperRetryMetadata struct {

View File

@@ -157,6 +157,7 @@ func (content *Content) MarshalJSON() ([]byte, error) {
return json.Marshal(content.Raw)
}
// Deprecated: use errors.Is directly
func IsUnsupportedContentType(err error) bool {
return errors.Is(err, ErrUnsupportedContentType)
}

View File

@@ -140,7 +140,7 @@ type Unsigned struct {
RedactedBecause *Event `json:"redacted_because,omitempty"`
InviteRoomState []StrippedState `json:"invite_room_state,omitempty"`
HungryRowID int64 `json:"com.beeper.hungry_row_id,omitempty"`
BeeperHSOrder int64 `json:"com.beeper.hs.order,omitempty"`
}
func (us *Unsigned) IsEmpty() bool {

View File

@@ -152,8 +152,9 @@ type BridgeEventContent struct {
}
type SpaceChildEventContent struct {
Via []string `json:"via,omitempty"`
Order string `json:"order,omitempty"`
Via []string `json:"via,omitempty"`
Order string `json:"order,omitempty"`
Suggested bool `json:"suggested,omitempty"`
}
type SpaceParentEventContent struct {

View File

@@ -83,8 +83,13 @@ func (parser *HTMLParser) getAttribute(node *html.Node, attribute string) string
return val
}
// Digits counts the number of digits in a non-negative integer.
// Digits counts the number of digits (and the sign, if negative) in an integer.
func Digits(num int) int {
if num == 0 {
return 1
} else if num < 0 {
return Digits(-num) + 1
}
return int(math.Floor(math.Log10(float64(num))) + 1)
}
@@ -112,6 +117,10 @@ func (parser *HTMLParser) listToString(node *html.Node, stripLinebreak bool, ctx
// TODO make bullets and numbering configurable
if ordered {
indexPadding := indentLength - Digits(counter)
if indexPadding < 0 {
// This will happen on negative start indexes where longestIndex is usually wrong, otherwise shouldn't happen
indexPadding = 0
}
prefix = fmt.Sprintf("%d. %s", counter, strings.Repeat(" ", indexPadding))
} else {
prefix = "* "

View File

@@ -31,6 +31,13 @@ const (
IdentifierTypePhone = "m.id.phone"
)
type Direction rune
const (
DirectionForward Direction = 'f'
DirectionBackward Direction = 'b'
)
// ReqRegister is the JSON request for https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3register
type ReqRegister struct {
Username string `json:"username,omitempty"`
@@ -334,13 +341,17 @@ type ReqBatchSend struct {
}
type ReqSetReadMarkers struct {
Read id.EventID `json:"m.read"`
ReadPrivate id.EventID `json:"m.read.private"`
FullyRead id.EventID `json:"m.fully_read"`
Read id.EventID `json:"m.read,omitempty"`
ReadPrivate id.EventID `json:"m.read.private,omitempty"`
FullyRead id.EventID `json:"m.fully_read,omitempty"`
BeeperReadExtra interface{} `json:"com.beeper.read.extra"`
BeeperReadPrivateExtra interface{} `json:"com.beeper.read.private.extra"`
BeeperFullyReadExtra interface{} `json:"com.beeper.fully_read.extra"`
BeeperReadExtra interface{} `json:"com.beeper.read.extra,omitempty"`
BeeperReadPrivateExtra interface{} `json:"com.beeper.read.private.extra,omitempty"`
BeeperFullyReadExtra interface{} `json:"com.beeper.fully_read.extra,omitempty"`
}
type ReqSendReceipt struct {
ThreadID string `json:"thread_id,omitempty"`
}
// ReqHierarchy contains the parameters for https://spec.matrix.org/v1.4/client-server-api/#get_matrixclientv1roomsroomidhierarchy
@@ -380,3 +391,23 @@ func (req *ReqHierarchy) Query() map[string]string {
}
return query
}
type ReqBeeperMergeRoom struct {
NewRoom ReqCreateRoom `json:"create"`
Key string `json:"key"`
Rooms []id.RoomID `json:"rooms"`
User id.UserID `json:"user_id"`
}
type BeeperSplitRoomPart struct {
UserID id.UserID `json:"user_id"`
Values []string `json:"values"`
NewRoom ReqCreateRoom `json:"create"`
}
type ReqBeeperSplitRoom struct {
RoomID id.RoomID `json:"-"`
Key string `json:"key"`
Parts []BeeperSplitRoomPart `json:"parts"`
}

View File

@@ -160,6 +160,11 @@ type RespUserDisplayName struct {
DisplayName string `json:"displayname"`
}
type RespUserProfile struct {
DisplayName string `json:"displayname"`
AvatarURL id.ContentURI `json:"avatar_url"`
}
// RespRegisterAvailable is the JSON response for https://spec.matrix.org/v1.4/client-server-api/#get_matrixclientv3registeravailable
type RespRegisterAvailable struct {
Available bool `json:"available"`
@@ -246,8 +251,9 @@ type RespSync struct {
Presence SyncEventsList `json:"presence"`
ToDevice SyncEventsList `json:"to_device"`
DeviceLists DeviceLists `json:"device_lists"`
DeviceOTKCount OTKCount `json:"device_one_time_keys_count"`
DeviceLists DeviceLists `json:"device_lists"`
DeviceOTKCount OTKCount `json:"device_one_time_keys_count"`
FallbackKeys []id.KeyAlgorithm `json:"device_unused_fallback_key_types"`
Rooms RespSyncRooms `json:"rooms"`
}
@@ -256,6 +262,7 @@ type RespSyncRooms struct {
Leave map[id.RoomID]*SyncLeftRoom `json:"leave,omitempty"`
Join map[id.RoomID]*SyncJoinedRoom `json:"join,omitempty"`
Invite map[id.RoomID]*SyncInvitedRoom `json:"invite,omitempty"`
Knock map[id.RoomID]*SyncKnockedRoom `json:"knock,omitempty"`
}
type marshalableRespSync RespSync
@@ -332,6 +339,10 @@ func (sir SyncInvitedRoom) MarshalJSON() ([]byte, error) {
return util.MarshalAndDeleteEmpty((marshalableSyncInvitedRoom)(sir), syncInvitedRoomPathsToDelete)
}
type SyncKnockedRoom struct {
State SyncEventsList `json:"knock_state"`
}
type RespTurnServer struct {
Username string `json:"username"`
Password string `json:"password"`
@@ -540,3 +551,14 @@ type StrippedStateWithTime struct {
event.StrippedState
Timestamp jsontime.UnixMilli `json:"origin_server_ts"`
}
type RespBeeperMergeRoom RespCreateRoom
type RespBeeperSplitRoom struct {
RoomIDs map[string]id.RoomID `json:"room_ids"`
}
type RespTimestampToEvent struct {
EventID id.EventID `json:"event_id"`
Timestamp jsontime.UnixMilli `json:"origin_server_ts"`
}

View File

@@ -1,5 +1,5 @@
package mautrix
const Version = "v0.12.3"
const Version = "v0.13.0"
var DefaultUserAgent = "mautrix-go/" + Version

View File

@@ -57,6 +57,8 @@ const (
)
var (
SpecR000 = MustParseSpecVersion("r0.0.0")
SpecR001 = MustParseSpecVersion("r0.0.1")
SpecR010 = MustParseSpecVersion("r0.1.0")
SpecR020 = MustParseSpecVersion("r0.2.0")
SpecR030 = MustParseSpecVersion("r0.3.0")
@@ -68,6 +70,7 @@ var (
SpecV12 = MustParseSpecVersion("v1.2")
SpecV13 = MustParseSpecVersion("v1.3")
SpecV14 = MustParseSpecVersion("v1.4")
SpecV15 = MustParseSpecVersion("v1.5")
)
func (svf SpecVersionFormat) String() string {