WIP: mautrix
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
package bmatrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
matrix "github.com/matrix-org/gomatrix"
|
||||
matrix "maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
func newMatrixUsername(username string) *matrixUsername {
|
||||
@@ -28,7 +27,7 @@ func newMatrixUsername(username string) *matrixUsername {
|
||||
}
|
||||
|
||||
// getRoomID retrieves a matching room ID from the channel name.
|
||||
func (b *Bmatrix) getRoomID(channel string) string {
|
||||
func (b *Bmatrix) getRoomID(channel string) id.RoomID {
|
||||
b.RLock()
|
||||
defer b.RUnlock()
|
||||
for ID, name := range b.RoomMap {
|
||||
@@ -40,21 +39,10 @@ func (b *Bmatrix) getRoomID(channel string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// interface2Struct marshals and immediately unmarshals an interface.
|
||||
// Useful for converting map[string]interface{} to a struct.
|
||||
func interface2Struct(in interface{}, out interface{}) error {
|
||||
jsonObj, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return err //nolint:wrapcheck
|
||||
}
|
||||
|
||||
return json.Unmarshal(jsonObj, out)
|
||||
}
|
||||
|
||||
// getDisplayName retrieves the displayName for mxid, querying the homeserver if the mxid is not in the cache.
|
||||
func (b *Bmatrix) getDisplayName(channelID string, mxid string) string {
|
||||
func (b *Bmatrix) getDisplayName(channelID id.RoomID, mxid id.UserID) string {
|
||||
if b.GetBool("UseUserName") {
|
||||
return mxid[1:]
|
||||
return string(mxid)[1:]
|
||||
}
|
||||
|
||||
b.RLock()
|
||||
@@ -74,7 +62,7 @@ func (b *Bmatrix) getDisplayName(channelID string, mxid string) string {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return b.cacheDisplayName(channelID, mxid, mxid[1:])
|
||||
return b.cacheDisplayName(channelID, mxid, string(mxid)[1:])
|
||||
}
|
||||
|
||||
return b.cacheDisplayName(channelID, mxid, displayName.DisplayName)
|
||||
@@ -82,12 +70,12 @@ func (b *Bmatrix) getDisplayName(channelID string, mxid string) string {
|
||||
|
||||
// cacheDisplayName stores the mapping between a mxid and a display name, to be reused later without performing a query to the homeserver.
|
||||
// Note that old entries are cleaned when this function is called.
|
||||
func (b *Bmatrix) cacheDisplayName(channelID string, mxid string, displayName string) string {
|
||||
func (b *Bmatrix) cacheDisplayName(channelID id.RoomID, mxid id.UserID, displayName string) string {
|
||||
now := time.Now()
|
||||
|
||||
// scan to delete old entries, to stop memory usage from becoming high with obsolete entries.
|
||||
// In addition, we detect if another user have the same username, and if so, we append their mxids to their usernames to differentiate them.
|
||||
toDelete := map[string]string{}
|
||||
toDelete := map[id.RoomID]id.UserID{}
|
||||
conflict := false
|
||||
|
||||
b.Lock()
|
||||
@@ -118,7 +106,7 @@ func (b *Bmatrix) cacheDisplayName(channelID string, mxid string, displayName st
|
||||
}
|
||||
|
||||
if _, channelPresent := b.NicknameMap[channelID]; !channelPresent {
|
||||
b.NicknameMap[channelID] = make(map[string]NicknameCacheEntry)
|
||||
b.NicknameMap[channelID] = make(map[id.UserID]NicknameCacheEntry)
|
||||
}
|
||||
|
||||
b.NicknameMap[channelID][mxid] = NicknameCacheEntry{
|
||||
@@ -130,77 +118,43 @@ func (b *Bmatrix) cacheDisplayName(channelID string, mxid string, displayName st
|
||||
return displayName
|
||||
}
|
||||
|
||||
// handleError converts errors into httpError.
|
||||
//nolint:exhaustivestruct
|
||||
func handleError(err error) *httpError {
|
||||
var mErr matrix.HTTPError
|
||||
if !errors.As(err, &mErr) {
|
||||
return &httpError{
|
||||
Err: "not a HTTPError",
|
||||
}
|
||||
}
|
||||
|
||||
var httpErr httpError
|
||||
|
||||
if err := json.Unmarshal(mErr.Contents, &httpErr); err != nil {
|
||||
return &httpError{
|
||||
Err: "unmarshal failed",
|
||||
}
|
||||
}
|
||||
|
||||
return &httpErr
|
||||
}
|
||||
|
||||
func (b *Bmatrix) containsAttachment(content map[string]interface{}) bool {
|
||||
// Skip empty messages
|
||||
if content["msgtype"] == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Only allow image,video or file msgtypes
|
||||
if !(content["msgtype"].(string) == "m.image" ||
|
||||
content["msgtype"].(string) == "m.video" ||
|
||||
content["msgtype"].(string) == "m.file") {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// getAvatarURL returns the avatar URL of the specified sender.
|
||||
func (b *Bmatrix) getAvatarURL(sender string) string {
|
||||
urlPath := b.mc.BuildURL("profile", sender, "avatar_url")
|
||||
|
||||
s := struct {
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}{}
|
||||
|
||||
err := b.mc.MakeRequest("GET", urlPath, nil, &s)
|
||||
func (b *Bmatrix) getAvatarURL(sender id.UserID) string {
|
||||
url, err := b.mc.GetAvatarURL(sender)
|
||||
if err != nil {
|
||||
b.Log.Errorf("getAvatarURL failed: %s", err)
|
||||
|
||||
b.Log.Errorf("Couldn't retrieve the URL of the avatar for MXID %s", sender)
|
||||
return ""
|
||||
}
|
||||
|
||||
url := strings.ReplaceAll(s.AvatarURL, "mxc://", b.GetString("Server")+"/_matrix/media/r0/thumbnail/")
|
||||
if url != "" {
|
||||
url += "?width=37&height=37&method=crop"
|
||||
}
|
||||
|
||||
return url
|
||||
return url.String()
|
||||
}
|
||||
|
||||
// handleRatelimit handles the ratelimit errors and return if we're ratelimited and the amount of time to sleep
|
||||
func (b *Bmatrix) handleRatelimit(err error) (time.Duration, bool) {
|
||||
httpErr := handleError(err)
|
||||
if httpErr.Errcode != "M_LIMIT_EXCEEDED" {
|
||||
var mErr matrix.HTTPError
|
||||
if !errors.As(err, &mErr) {
|
||||
b.Log.Errorf("Received a non-HTTPError, don't know what to make of it:\n%#v", err)
|
||||
return 0, false
|
||||
}
|
||||
|
||||
b.Log.Debugf("ratelimited: %s", httpErr.Err)
|
||||
b.Log.Infof("getting ratelimited by matrix, sleeping approx %d seconds before retrying", httpErr.RetryAfterMs/1000)
|
||||
if mErr.RespError.ErrCode != "M_LIMIT_EXCEEDED" {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return time.Duration(httpErr.RetryAfterMs) * time.Millisecond, true
|
||||
b.Log.Debugf("ratelimited: %s", mErr.RespError.Err)
|
||||
|
||||
// fallback to a one-second delay
|
||||
retryDelayMs := 1000
|
||||
|
||||
if retryDelayString, present := mErr.RespError.ExtraData["retry_after_ms"]; present {
|
||||
if retryDelayInt, correct := retryDelayString.(int); correct && retryDelayInt > retryDelayMs {
|
||||
retryDelayMs = retryDelayInt
|
||||
}
|
||||
}
|
||||
|
||||
b.Log.Infof("getting ratelimited by matrix, sleeping approx %d seconds before retrying", retryDelayMs/1000)
|
||||
|
||||
return time.Duration(retryDelayMs) * time.Millisecond, true
|
||||
}
|
||||
|
||||
// retry function will check if we're ratelimited and retries again when backoff time expired
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//nolint: exhaustivestruct
|
||||
package bmatrix
|
||||
|
||||
import (
|
||||
@@ -9,10 +10,13 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
matrix "maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"github.com/42wim/matterbridge/bridge"
|
||||
"github.com/42wim/matterbridge/bridge/config"
|
||||
"github.com/42wim/matterbridge/bridge/helper"
|
||||
matrix "github.com/matrix-org/gomatrix"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -26,20 +30,15 @@ type NicknameCacheEntry struct {
|
||||
}
|
||||
|
||||
type Bmatrix struct {
|
||||
mc *matrix.Client
|
||||
UserID string
|
||||
// channelId -> mxid -> NickNameCacheEntry
|
||||
NicknameMap map[string]map[string]NicknameCacheEntry
|
||||
RoomMap map[string]string
|
||||
mc *matrix.Client
|
||||
UserID id.UserID
|
||||
NicknameMap map[id.RoomID]map[id.UserID]NicknameCacheEntry
|
||||
RoomMap map[id.RoomID]string
|
||||
rateMutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
*bridge.Config
|
||||
}
|
||||
|
||||
type httpError struct {
|
||||
Errcode string `json:"errcode"`
|
||||
Err string `json:"error"`
|
||||
RetryAfterMs int `json:"retry_after_ms"`
|
||||
stop chan int
|
||||
stopAck chan int
|
||||
}
|
||||
|
||||
type matrixUsername struct {
|
||||
@@ -47,29 +46,12 @@ type matrixUsername struct {
|
||||
formatted string
|
||||
}
|
||||
|
||||
// SubTextMessage represents the new content of the message in edit messages.
|
||||
type SubTextMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// MessageRelation explains how the current message relates to a previous message.
|
||||
// Notably used for message edits.
|
||||
type MessageRelation struct {
|
||||
EventID string `json:"event_id"`
|
||||
Type string `json:"rel_type"`
|
||||
}
|
||||
|
||||
type EditedMessage struct {
|
||||
NewContent SubTextMessage `json:"m.new_content"`
|
||||
RelatedTo MessageRelation `json:"m.relates_to"`
|
||||
matrix.TextMessage
|
||||
}
|
||||
|
||||
func New(cfg *bridge.Config) bridge.Bridger {
|
||||
b := &Bmatrix{Config: cfg}
|
||||
b.RoomMap = make(map[string]string)
|
||||
b.NicknameMap = make(map[string]map[string]NicknameCacheEntry)
|
||||
b.RoomMap = make(map[id.RoomID]string)
|
||||
b.NicknameMap = make(map[id.RoomID]map[id.UserID]NicknameCacheEntry)
|
||||
b.stop = make(chan int, 1)
|
||||
b.stopAck = make(chan int, 1)
|
||||
return b
|
||||
}
|
||||
|
||||
@@ -77,13 +59,13 @@ func (b *Bmatrix) Connect() error {
|
||||
var err error
|
||||
b.Log.Infof("Connecting %s", b.GetString("Server"))
|
||||
if b.GetString("MxID") != "" && b.GetString("Token") != "" {
|
||||
b.UserID = id.UserID(b.GetString("MxID"))
|
||||
b.mc, err = matrix.NewClient(
|
||||
b.GetString("Server"), b.GetString("MxID"), b.GetString("Token"),
|
||||
b.GetString("Server"), b.UserID, b.GetString("Token"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.UserID = b.GetString("MxID")
|
||||
b.Log.Info("Using existing Matrix credentials")
|
||||
} else {
|
||||
b.mc, err = matrix.NewClient(b.GetString("Server"), "", "")
|
||||
@@ -91,15 +73,14 @@ func (b *Bmatrix) Connect() error {
|
||||
return err
|
||||
}
|
||||
resp, err := b.mc.Login(&matrix.ReqLogin{
|
||||
Type: "m.login.password",
|
||||
User: b.GetString("Login"),
|
||||
Password: b.GetString("Password"),
|
||||
Identifier: matrix.NewUserIdentifier(b.GetString("Login")),
|
||||
Type: matrix.AuthTypePassword,
|
||||
Password: b.GetString("Password"),
|
||||
Identifier: matrix.UserIdentifier{Type: matrix.IdentifierTypeUser, User: b.GetString("Login")},
|
||||
StoreCredentials: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.mc.SetCredentials(resp.UserID, resp.AccessToken)
|
||||
b.UserID = resp.UserID
|
||||
b.Log.Info("Connection succeeded")
|
||||
}
|
||||
@@ -108,6 +89,13 @@ func (b *Bmatrix) Connect() error {
|
||||
}
|
||||
|
||||
func (b *Bmatrix) Disconnect() error {
|
||||
// tell the Sync() loop to exit
|
||||
b.stop <- 0
|
||||
b.mc.StopSync()
|
||||
|
||||
// wait for the syncer to terminate
|
||||
<-b.stopAck
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -136,26 +124,13 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
|
||||
// Make a action /me of the message
|
||||
if msg.Event == config.EventUserAction {
|
||||
m := matrix.TextMessage{
|
||||
MsgType: "m.emote",
|
||||
m := event.MessageEventContent{
|
||||
MsgType: event.MsgEmote,
|
||||
Body: username.plain + msg.Text,
|
||||
FormattedBody: username.formatted + msg.Text,
|
||||
}
|
||||
|
||||
msgID := ""
|
||||
|
||||
err := b.retry(func() error {
|
||||
resp, err := b.mc.SendMessageEvent(channel, "m.room.message", m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgID = resp.EventID
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
return msgID, err
|
||||
return b.sendEventWithRetries(channel, event.EventMessage, m)
|
||||
}
|
||||
|
||||
// Delete message
|
||||
@@ -167,12 +142,12 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
msgID := ""
|
||||
|
||||
err := b.retry(func() error {
|
||||
resp, err := b.mc.RedactEvent(channel, msg.ID, &matrix.ReqRedact{})
|
||||
resp, err := b.mc.RedactEvent(channel, id.EventID(msg.ID), matrix.ReqRedact{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgID = resp.EventID
|
||||
msgID = string(resp.EventID)
|
||||
|
||||
return err
|
||||
})
|
||||
@@ -183,13 +158,12 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
// Upload a file if it exists
|
||||
if msg.Extra != nil {
|
||||
for _, rmsg := range helper.HandleExtra(&msg, b.General) {
|
||||
rmsg := rmsg
|
||||
m := event.MessageEventContent{
|
||||
MsgType: event.MsgText,
|
||||
Body: rmsg.Username + rmsg.Text,
|
||||
}
|
||||
|
||||
err := b.retry(func() error {
|
||||
_, err := b.mc.SendText(channel, rmsg.Username+rmsg.Text)
|
||||
|
||||
return err
|
||||
})
|
||||
_, err := b.sendEventWithRetries(channel, event.EventMessage, m)
|
||||
if err != nil {
|
||||
b.Log.Errorf("sendText failed: %s", err)
|
||||
}
|
||||
@@ -202,89 +176,84 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
|
||||
// Edit message if we have an ID
|
||||
if msg.ID != "" {
|
||||
rmsg := EditedMessage{TextMessage: matrix.TextMessage{
|
||||
rmsg := event.MessageEventContent{
|
||||
Body: username.plain + msg.Text,
|
||||
MsgType: "m.text",
|
||||
}}
|
||||
MsgType: event.MsgText,
|
||||
}
|
||||
if b.GetBool("HTMLDisable") {
|
||||
rmsg.TextMessage.FormattedBody = username.formatted + "* " + msg.Text
|
||||
rmsg.FormattedBody = username.formatted + "* " + msg.Text
|
||||
} else {
|
||||
rmsg.Format = "org.matrix.custom.html"
|
||||
rmsg.TextMessage.FormattedBody = username.formatted + "* " + helper.ParseMarkdown(msg.Text)
|
||||
rmsg.Format = event.FormatHTML
|
||||
rmsg.FormattedBody = username.formatted + "* " + helper.ParseMarkdown(msg.Text)
|
||||
}
|
||||
rmsg.NewContent = SubTextMessage{
|
||||
Body: rmsg.TextMessage.Body,
|
||||
MsgType: "m.text",
|
||||
rmsg.NewContent = &event.MessageEventContent{
|
||||
Body: rmsg.Body,
|
||||
MsgType: event.MsgText,
|
||||
}
|
||||
rmsg.RelatedTo = MessageRelation{
|
||||
EventID: msg.ID,
|
||||
Type: "m.replace",
|
||||
rmsg.RelatesTo = &event.RelatesTo{
|
||||
EventID: id.EventID(msg.ID),
|
||||
Type: event.RelReplace,
|
||||
}
|
||||
|
||||
err := b.retry(func() error {
|
||||
_, err := b.mc.SendMessageEvent(channel, "m.room.message", rmsg)
|
||||
return b.sendEventWithRetries(channel, event.EventMessage, rmsg)
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return msg.ID, nil
|
||||
m := event.MessageEventContent{
|
||||
Body: username.plain + msg.Text,
|
||||
FormattedBody: username.formatted + msg.Text,
|
||||
}
|
||||
|
||||
// Use notices to send join/leave events
|
||||
if msg.Event == config.EventJoinLeave {
|
||||
m := matrix.TextMessage{
|
||||
MsgType: "m.notice",
|
||||
Body: username.plain + msg.Text,
|
||||
FormattedBody: username.formatted + msg.Text,
|
||||
m.MsgType = event.MsgNotice
|
||||
} else {
|
||||
m.MsgType = event.MsgText
|
||||
if b.GetBool("HTMLDisable") {
|
||||
m.FormattedBody = ""
|
||||
} else {
|
||||
m.FormattedBody = username.formatted + helper.ParseMarkdown(msg.Text)
|
||||
}
|
||||
|
||||
var (
|
||||
resp *matrix.RespSendEvent
|
||||
err error
|
||||
)
|
||||
|
||||
err = b.retry(func() error {
|
||||
resp, err = b.mc.SendMessageEvent(channel, "m.room.message", m)
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.EventID, err
|
||||
}
|
||||
|
||||
if b.GetBool("HTMLDisable") {
|
||||
var (
|
||||
resp *matrix.RespSendEvent
|
||||
err error
|
||||
)
|
||||
return b.sendEventWithRetries(channel, event.EventMessage, m)
|
||||
}
|
||||
|
||||
err = b.retry(func() error {
|
||||
resp, err = b.mc.SendText(channel, username.plain+msg.Text)
|
||||
func (b *Bmatrix) handlematrix() {
|
||||
syncer, ok := b.mc.Syncer.(*matrix.DefaultSyncer)
|
||||
if !ok {
|
||||
b.Log.Errorln("couldn't convert the Syncer object to a DefaultSyncer structure, the matrix bridge won't work")
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.EventID, err
|
||||
return
|
||||
}
|
||||
|
||||
// Post normal message with HTML support (eg riot.im)
|
||||
syncer.OnEventType(event.EventRedaction, b.handleEvent)
|
||||
syncer.OnEventType(event.EventMessage, b.handleEvent)
|
||||
syncer.OnEventType(event.StateMember, b.handleMemberChange)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-b.stop:
|
||||
b.stopAck <- 1
|
||||
|
||||
return
|
||||
default:
|
||||
if err := b.mc.Sync(); err != nil {
|
||||
b.Log.Println("Sync() returned ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//nolint: wrapcheck
|
||||
func (b *Bmatrix) sendEventWithRetries(channel id.RoomID, eventType event.Type, eventData interface{}) (string, error) {
|
||||
var (
|
||||
resp *matrix.RespSendEvent
|
||||
err error
|
||||
)
|
||||
|
||||
err = b.retry(func() error {
|
||||
resp, err = b.mc.SendFormattedText(channel, username.plain+msg.Text,
|
||||
username.formatted+helper.ParseMarkdown(msg.Text))
|
||||
resp, err = b.mc.SendMessageEvent(channel, eventType, eventData)
|
||||
|
||||
return err
|
||||
})
|
||||
@@ -292,63 +261,57 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return resp.EventID, err
|
||||
return string(resp.EventID), err
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handlematrix() {
|
||||
syncer := b.mc.Syncer.(*matrix.DefaultSyncer)
|
||||
syncer.OnEventType("m.room.redaction", b.handleEvent)
|
||||
syncer.OnEventType("m.room.message", b.handleEvent)
|
||||
syncer.OnEventType("m.room.member", b.handleMemberChange)
|
||||
go func() {
|
||||
for {
|
||||
if err := b.mc.Sync(); err != nil {
|
||||
b.Log.Println("Sync() returned ", err)
|
||||
}
|
||||
func (b *Bmatrix) handleMemberChange(source matrix.EventSource, ev *event.Event) {
|
||||
member := ev.Content.AsMember()
|
||||
if member == nil {
|
||||
b.Log.Errorf("Couldn't process a member event:\n%#v", ev)
|
||||
|
||||
return
|
||||
}
|
||||
// Update the displayname on join messages, according to https://matrix.org/docs/spec/client_server/r0.6.1#events-on-change-of-profile-information
|
||||
if member.Membership == event.MembershipJoin {
|
||||
b.cacheDisplayName(ev.RoomID, ev.Sender, member.Displayname)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handleMessage(rmsg config.Message, msg event.MessageEventContent, ev *event.Event) {
|
||||
rmsg.Text = msg.Body
|
||||
|
||||
// Do we have a /me action
|
||||
if msg.MsgType == event.MsgEmote {
|
||||
rmsg.Event = config.EventUserAction
|
||||
}
|
||||
|
||||
// Is it an edit?
|
||||
if msg.RelatesTo != nil && msg.NewContent != nil && msg.RelatesTo.Type == event.RelReplace {
|
||||
rmsg.ID = string(msg.RelatesTo.EventID)
|
||||
rmsg.Text = msg.NewContent.Body
|
||||
b.Remote <- rmsg
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Do we have attachments (we only allow image,video or file msgtypes)
|
||||
if msg.MsgType == event.MsgImage || msg.MsgType == event.MsgVideo || msg.MsgType == event.MsgFile {
|
||||
err := b.handleDownloadFile(&rmsg, msg)
|
||||
if err != nil {
|
||||
b.Log.Errorf("download failed: %#v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handleEdit(ev *matrix.Event, rmsg config.Message) bool {
|
||||
relationInterface, present := ev.Content["m.relates_to"]
|
||||
newContentInterface, present2 := ev.Content["m.new_content"]
|
||||
if !(present && present2) {
|
||||
return false
|
||||
}
|
||||
|
||||
var relation MessageRelation
|
||||
if err := interface2Struct(relationInterface, &relation); err != nil {
|
||||
b.Log.Warnf("Couldn't parse 'm.relates_to' object with value %#v", relationInterface)
|
||||
return false
|
||||
}
|
||||
|
||||
var newContent SubTextMessage
|
||||
if err := interface2Struct(newContentInterface, &newContent); err != nil {
|
||||
b.Log.Warnf("Couldn't parse 'm.new_content' object with value %#v", newContentInterface)
|
||||
return false
|
||||
}
|
||||
|
||||
if relation.Type != "m.replace" {
|
||||
return false
|
||||
}
|
||||
|
||||
rmsg.ID = relation.EventID
|
||||
rmsg.Text = newContent.Body
|
||||
b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account)
|
||||
b.Remote <- rmsg
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handleMemberChange(ev *matrix.Event) {
|
||||
// Update the displayname on join messages, according to https://matrix.org/docs/spec/client_server/r0.6.1#events-on-change-of-profile-information
|
||||
if ev.Content["membership"] == "join" {
|
||||
if dn, ok := ev.Content["displayname"].(string); ok {
|
||||
b.cacheDisplayName(ev.RoomID, ev.Sender, dn)
|
||||
}
|
||||
// not crucial, so no ratelimit check here
|
||||
if err := b.mc.MarkRead(ev.RoomID, ev.ID); err != nil {
|
||||
b.Log.Errorf("couldn't mark message as read %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bmatrix) handleEvent(ev *matrix.Event) {
|
||||
func (b *Bmatrix) handleEvent(source matrix.EventSource, ev *event.Event) {
|
||||
b.Log.Debugf("== Receiving event: %#v", ev)
|
||||
if ev.Sender != b.UserID {
|
||||
b.RLock()
|
||||
@@ -364,8 +327,8 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) {
|
||||
Username: b.getDisplayName(ev.RoomID, ev.Sender),
|
||||
Channel: channel,
|
||||
Account: b.Account,
|
||||
UserID: ev.Sender,
|
||||
ID: ev.ID,
|
||||
UserID: string(ev.Sender),
|
||||
ID: string(ev.ID),
|
||||
Avatar: b.getAvatarURL(ev.Sender),
|
||||
}
|
||||
|
||||
@@ -376,95 +339,52 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) {
|
||||
}
|
||||
|
||||
// Delete event
|
||||
if ev.Type == "m.room.redaction" {
|
||||
if ev.Type == event.EventRedaction {
|
||||
rmsg.Event = config.EventMsgDelete
|
||||
rmsg.ID = ev.Redacts
|
||||
rmsg.ID = string(ev.Redacts)
|
||||
rmsg.Text = config.EventMsgDelete
|
||||
b.Remote <- rmsg
|
||||
return
|
||||
}
|
||||
|
||||
// Text must be a string
|
||||
if rmsg.Text, ok = ev.Content["body"].(string); !ok {
|
||||
b.Log.Errorf("Content[body] is not a string: %T\n%#v",
|
||||
ev.Content["body"], ev.Content)
|
||||
msg := ev.Content.AsMessage()
|
||||
if msg == nil {
|
||||
b.Log.Errorf("matterbridge don't support this event type: %s", ev.Type.Type)
|
||||
b.Log.Debugf("Full event: %#v", ev)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Do we have a /me action
|
||||
if ev.Content["msgtype"].(string) == "m.emote" {
|
||||
rmsg.Event = config.EventUserAction
|
||||
}
|
||||
|
||||
// Is it an edit?
|
||||
if b.handleEdit(ev, rmsg) {
|
||||
return
|
||||
}
|
||||
|
||||
// Do we have attachments
|
||||
if b.containsAttachment(ev.Content) {
|
||||
err := b.handleDownloadFile(&rmsg, ev.Content)
|
||||
if err != nil {
|
||||
b.Log.Errorf("download failed: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
b.Log.Debugf("<= Sending message from %s on %s to gateway", ev.Sender, b.Account)
|
||||
b.Remote <- rmsg
|
||||
|
||||
// not crucial, so no ratelimit check here
|
||||
if err := b.mc.MarkRead(ev.RoomID, ev.ID); err != nil {
|
||||
b.Log.Errorf("couldn't mark message as read %s", err.Error())
|
||||
}
|
||||
b.handleMessage(rmsg, *msg, ev)
|
||||
}
|
||||
}
|
||||
|
||||
// handleDownloadFile handles file download
|
||||
func (b *Bmatrix) handleDownloadFile(rmsg *config.Message, content map[string]interface{}) error {
|
||||
var (
|
||||
ok bool
|
||||
url, name, msgtype, mtype string
|
||||
info map[string]interface{}
|
||||
size float64
|
||||
)
|
||||
|
||||
func (b *Bmatrix) handleDownloadFile(rmsg *config.Message, msg event.MessageEventContent) error {
|
||||
rmsg.Extra = make(map[string][]interface{})
|
||||
if url, ok = content["url"].(string); !ok {
|
||||
return fmt.Errorf("url isn't a %T", url)
|
||||
if msg.URL == "" || msg.Info == nil {
|
||||
b.Log.Error("couldn't download a file with no URL or no file informations (invalid event ?)")
|
||||
b.Log.Debugf("Full Message content:\n%#v", msg)
|
||||
}
|
||||
url = strings.Replace(url, "mxc://", b.GetString("Server")+"/_matrix/media/v1/download/", -1)
|
||||
|
||||
if info, ok = content["info"].(map[string]interface{}); !ok {
|
||||
return fmt.Errorf("info isn't a %T", info)
|
||||
}
|
||||
if size, ok = info["size"].(float64); !ok {
|
||||
return fmt.Errorf("size isn't a %T", size)
|
||||
}
|
||||
if name, ok = content["body"].(string); !ok {
|
||||
return fmt.Errorf("name isn't a %T", name)
|
||||
}
|
||||
if msgtype, ok = content["msgtype"].(string); !ok {
|
||||
return fmt.Errorf("msgtype isn't a %T", msgtype)
|
||||
}
|
||||
if mtype, ok = info["mimetype"].(string); !ok {
|
||||
return fmt.Errorf("mtype isn't a %T", mtype)
|
||||
}
|
||||
url := strings.ReplaceAll(string(msg.URL), "mxc://", b.GetString("Server")+"/_matrix/media/v1/download/")
|
||||
filename := msg.Body
|
||||
|
||||
// check if we have an image uploaded without extension
|
||||
if !strings.Contains(name, ".") {
|
||||
if msgtype == "m.image" {
|
||||
mext, _ := mime.ExtensionsByType(mtype)
|
||||
if len(mext) > 0 {
|
||||
name += mext[0]
|
||||
}
|
||||
if !strings.Contains(filename, ".") {
|
||||
mext, _ := mime.ExtensionsByType(msg.Info.MimeType)
|
||||
if len(mext) > 0 {
|
||||
filename += mext[0]
|
||||
} else {
|
||||
// just a default .png extension if we don't have mime info
|
||||
name += ".png"
|
||||
if msg.MsgType == event.MsgImage {
|
||||
// just a default .png extension if we don't have mime info
|
||||
filename += ".png"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the size is ok
|
||||
err := helper.HandleDownloadSize(b.Log, rmsg, name, int64(size), b.General)
|
||||
err := helper.HandleDownloadSize(b.Log, rmsg, filename, int64(msg.Info.Size), b.General)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -474,12 +394,12 @@ func (b *Bmatrix) handleDownloadFile(rmsg *config.Message, content map[string]in
|
||||
return fmt.Errorf("download %s failed %#v", url, err)
|
||||
}
|
||||
// add the downloaded data to the message
|
||||
helper.HandleDownloadData(b.Log, rmsg, name, "", url, data, b.General)
|
||||
helper.HandleDownloadData(b.Log, rmsg, filename, "", url, data, b.General)
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleUploadFiles handles native upload of files.
|
||||
func (b *Bmatrix) handleUploadFiles(msg *config.Message, channel string) (string, error) {
|
||||
func (b *Bmatrix) handleUploadFiles(msg *config.Message, channel id.RoomID) (string, error) {
|
||||
for _, f := range msg.Extra["file"] {
|
||||
if fi, ok := f.(config.FileInfo); ok {
|
||||
b.handleUploadFile(msg, channel, &fi)
|
||||
@@ -489,17 +409,21 @@ func (b *Bmatrix) handleUploadFiles(msg *config.Message, channel string) (string
|
||||
}
|
||||
|
||||
// handleUploadFile handles native upload of a file.
|
||||
func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *config.FileInfo) {
|
||||
//nolint: funlen
|
||||
func (b *Bmatrix) handleUploadFile(msg *config.Message, channel id.RoomID, fi *config.FileInfo) {
|
||||
username := newMatrixUsername(msg.Username)
|
||||
content := bytes.NewReader(*fi.Data)
|
||||
sp := strings.Split(fi.Name, ".")
|
||||
mtype := mime.TypeByExtension("." + sp[len(sp)-1])
|
||||
// image and video uploads send no username, we have to do this ourself here #715
|
||||
err := b.retry(func() error {
|
||||
_, err := b.mc.SendFormattedText(channel, username.plain+fi.Comment, username.formatted+fi.Comment)
|
||||
|
||||
return err
|
||||
})
|
||||
// image and video uploads send no username, we have to do this ourself here #715
|
||||
m := event.MessageEventContent{
|
||||
MsgType: event.MsgText,
|
||||
Body: username.plain + fi.Comment,
|
||||
FormattedBody: username.formatted + fi.Comment,
|
||||
}
|
||||
|
||||
_, err := b.sendEventWithRetries(channel, event.EventMessage, m)
|
||||
if err != nil {
|
||||
b.Log.Errorf("file comment failed: %#v", err)
|
||||
}
|
||||
@@ -507,9 +431,14 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *conf
|
||||
b.Log.Debugf("uploading file: %s %s", fi.Name, mtype)
|
||||
|
||||
var res *matrix.RespMediaUpload
|
||||
req := matrix.ReqUploadMedia{
|
||||
Content: content,
|
||||
ContentType: mtype,
|
||||
ContentLength: fi.Size,
|
||||
}
|
||||
|
||||
err = b.retry(func() error {
|
||||
res, err = b.mc.UploadToContentRepo(content, mtype, int64(len(*fi.Data)))
|
||||
res, err = b.mc.UploadMedia(req)
|
||||
|
||||
return err
|
||||
})
|
||||
@@ -519,63 +448,42 @@ func (b *Bmatrix) handleUploadFile(msg *config.Message, channel string, fi *conf
|
||||
return
|
||||
}
|
||||
|
||||
b.Log.Debugf("result: %#v", res)
|
||||
|
||||
m = event.MessageEventContent{
|
||||
Body: fi.Name,
|
||||
URL: res.ContentURI.CUString(),
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(mtype, "video"):
|
||||
b.Log.Debugf("sendVideo %s", res.ContentURI)
|
||||
err = b.retry(func() error {
|
||||
_, err = b.mc.SendVideo(channel, fi.Name, res.ContentURI)
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("sendVideo failed: %#v", err)
|
||||
}
|
||||
m.MsgType = event.MsgVideo
|
||||
case strings.Contains(mtype, "image"):
|
||||
b.Log.Debugf("sendImage %s", res.ContentURI)
|
||||
err = b.retry(func() error {
|
||||
_, err = b.mc.SendImage(channel, fi.Name, res.ContentURI)
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("sendImage failed: %#v", err)
|
||||
}
|
||||
m.MsgType = event.MsgImage
|
||||
case strings.Contains(mtype, "audio"):
|
||||
b.Log.Debugf("sendAudio %s", res.ContentURI)
|
||||
err = b.retry(func() error {
|
||||
_, err = b.mc.SendMessageEvent(channel, "m.room.message", matrix.AudioMessage{
|
||||
MsgType: "m.audio",
|
||||
Body: fi.Name,
|
||||
URL: res.ContentURI,
|
||||
Info: matrix.AudioInfo{
|
||||
Mimetype: mtype,
|
||||
Size: uint(len(*fi.Data)),
|
||||
},
|
||||
})
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("sendAudio failed: %#v", err)
|
||||
m.MsgType = event.MsgAudio
|
||||
m.Info = &event.FileInfo{
|
||||
MimeType: mtype,
|
||||
Size: len(*fi.Data),
|
||||
}
|
||||
default:
|
||||
b.Log.Debugf("sendFile %s", res.ContentURI)
|
||||
err = b.retry(func() error {
|
||||
_, err = b.mc.SendMessageEvent(channel, "m.room.message", matrix.FileMessage{
|
||||
MsgType: "m.file",
|
||||
Body: fi.Name,
|
||||
URL: res.ContentURI,
|
||||
Info: matrix.FileInfo{
|
||||
Mimetype: mtype,
|
||||
Size: uint(len(*fi.Data)),
|
||||
},
|
||||
})
|
||||
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
b.Log.Errorf("sendFile failed: %#v", err)
|
||||
m.MsgType = event.MsgFile
|
||||
m.Info = &event.FileInfo{
|
||||
MimeType: mtype,
|
||||
Size: len(*fi.Data),
|
||||
}
|
||||
}
|
||||
b.Log.Debugf("result: %#v", res)
|
||||
|
||||
_, err = b.sendEventWithRetries(channel, event.EventMessage, m)
|
||||
if err != nil {
|
||||
b.Log.Errorf("sending the message referencing the uploaded file failed: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
3
go.mod
3
go.mod
@@ -22,7 +22,7 @@ require (
|
||||
github.com/kyokomi/emoji/v2 v2.2.8
|
||||
github.com/labstack/echo/v4 v4.3.0
|
||||
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 // indirect
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20210403163225-761e8622445d
|
||||
github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7
|
||||
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
|
||||
@@ -55,6 +55,7 @@ require (
|
||||
gomod.garykim.dev/nc-talk v0.3.0
|
||||
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
|
||||
layeh.com/gumble v0.0.0-20200818122324-146f9205029b
|
||||
maunium.net/go/mautrix v0.9.14
|
||||
)
|
||||
|
||||
go 1.15
|
||||
|
||||
49
go.sum
49
go.sum
@@ -56,7 +56,6 @@ github.com/Azure/azure-sdk-for-go v26.5.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
|
||||
github.com/Azure/go-autorest v11.5.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f h1:2dk3eOnYllh+wUOuDhOoC2vUVoJF/5z478ryJ+wzEII=
|
||||
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f/go.mod h1:4a58ifQTEe2uwwsaqbh3i2un5/CBPg+At/qHpt18Tmk=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
||||
@@ -94,6 +93,7 @@ github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrU
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/advancedlogic/GoOse v0.0.0-20191112112754-e742535969c1/go.mod h1:f3HCSN1fBWjcpGtXyM119MJgeQl838v6so/PQOqvE1w=
|
||||
github.com/advancedlogic/GoOse v0.0.0-20200830213114-1225d531e0ad/go.mod h1:f3HCSN1fBWjcpGtXyM119MJgeQl838v6so/PQOqvE1w=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -146,6 +146,16 @@ github.com/blevesearch/zap/v14 v14.0.3/go.mod h1:oObAhcDHw7p1ahiTCqhRkdxdl7UA8qp
|
||||
github.com/blevesearch/zap/v15 v15.0.1/go.mod h1:ho0frqAex2ktT9cYFAxQpoQXsxb/KEfdjpx4s49rf/M=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
@@ -192,6 +202,7 @@ github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs
|
||||
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||
github.com/d5/tengo/v2 v2.7.0 h1:oAGQ+gcas0/T0bdqvNxfKzjOJhpQRwceWIF5gldB3aM=
|
||||
github.com/d5/tengo/v2 v2.7.0/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -284,7 +295,6 @@ github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81 h1:FdZThbRF0R+2qgyBl3KCVNWWBmKm68E+stT3rnQ02Ww=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81/go.mod h1:lDm2E64X4OjFdBUA4hlN4mEvbSitvhJdKw7rsA8KHgI=
|
||||
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
|
||||
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
@@ -348,7 +358,6 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
@@ -382,7 +391,6 @@ github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbV
|
||||
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q=
|
||||
@@ -468,6 +476,7 @@ github.com/jamiealquiza/envy v1.1.0/go.mod h1:MP36BriGCLwEHhi1OU8E9569JNZrjWfCvz
|
||||
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
@@ -481,6 +490,7 @@ github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUB
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -489,7 +499,6 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
||||
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||
@@ -507,6 +516,7 @@ github.com/keybase/go-ps v0.0.0-20190827175125-91aafc93ba19/go.mod h1:hY+WOq6m2F
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
@@ -523,12 +533,10 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kyokomi/emoji/v2 v2.2.8 h1:jcofPxjHWEkJtkIbcLHvZhxKgCPl6C7MyjTrD4KDqUE=
|
||||
github.com/kyokomi/emoji/v2 v2.2.8/go.mod h1:JUcn42DTdsXJo1SWanHh4HKDEyPaR5CqkmoirZZP9qE=
|
||||
@@ -544,6 +552,7 @@ github.com/levigross/exp-html v0.0.0-20120902181939-8df60c69a8f5/go.mod h1:QMe2w
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b h1:jrLvME7VuLW6NRysbiZtenTB9QcNlR9RPKK4LFfZn60=
|
||||
@@ -556,7 +565,6 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
|
||||
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20210403163225-761e8622445d h1:Csy27nDj00vRGp2+QvwSanaW0RA60SZUHXCk4BBT0AU=
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20210403163225-761e8622445d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
|
||||
@@ -600,6 +608,7 @@ github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/godown v0.0.1 h1:39uk50ufLVQFs0eapIJVX5fCS74a1Fs2g5f1MVqIHdE=
|
||||
github.com/mattn/godown v0.0.1/go.mod h1:/ivCKurgV/bx6yqtP/Jtc2Xmrv3beCYBvlfAUl4X5g4=
|
||||
@@ -667,7 +676,6 @@ github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9/go.mod h1:A5SRAcpTe
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
@@ -683,13 +691,11 @@ github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
|
||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
|
||||
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/oov/psd v0.0.0-20201002182931-74231384897f/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
@@ -791,6 +797,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR
|
||||
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
@@ -843,10 +850,8 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDq
|
||||
github.com/slack-go/slack v0.9.1 h1:pekQBs0RmrdAgoqzcMCzUCWSyIkhzUU3F83ExAdZrKo=
|
||||
github.com/slack-go/slack v0.9.1/go.mod h1:wWL//kk0ho+FcQXcBTmEafUI5dz4qz5f4mMk8oIkioQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
|
||||
github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
|
||||
@@ -899,6 +904,10 @@ github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/throttled/throttled v2.2.5+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
|
||||
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE=
|
||||
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
|
||||
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||
@@ -944,7 +953,6 @@ github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPy
|
||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw=
|
||||
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
@@ -1010,6 +1018,7 @@ go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1
|
||||
golang.org/dl v0.0.0-20190829154251-82a15e2f2ead/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -1022,10 +1031,12 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1124,6 +1135,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
@@ -1229,6 +1241,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1315,10 +1328,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomod.garykim.dev/nc-talk v0.2.2 h1:+U+daJFPPuwM7yRXYazeMHZgIBSGP6SeQURO0O5a32I=
|
||||
gomod.garykim.dev/nc-talk v0.2.2/go.mod h1:q/Adot/H7iqi+H4lANopV7/xcMf+sX3AZXUXqiITwok=
|
||||
gomod.garykim.dev/nc-talk v0.3.0 h1:MZxLc/gX2/+bdOw4xt6pi+qQFUQld1woGfw1hEJ0fbM=
|
||||
gomod.garykim.dev/nc-talk v0.3.0/go.mod h1:q/Adot/H7iqi+H4lANopV7/xcMf+sX3AZXUXqiITwok=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
@@ -1456,7 +1466,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
@@ -1477,7 +1486,6 @@ gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 h1:sY2a+y0j4iDrajJc
|
||||
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376/go.mod h1:BHKOc1m5wm8WwQkMqYBoo4vNxhmF7xg8+xhG8L+Cy3M=
|
||||
gopkg.in/olivere/elastic.v6 v6.2.35/go.mod h1:2cTT8Z+/LcArSWpCgvZqBgt3VOqXiy7v00w12Lz8bd4=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
@@ -1507,6 +1515,9 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||
layeh.com/gopus v0.0.0-20161224163843-0ebf989153aa/go.mod h1:AOef7vHz0+v4sWwJnr0jSyHiX/1NgsMoaxl+rEPz/I0=
|
||||
layeh.com/gumble v0.0.0-20200818122324-146f9205029b h1:Kne6wkHqbqrygRsqs5XUNhSs84DFG5TYMeCkCbM56sY=
|
||||
layeh.com/gumble v0.0.0-20200818122324-146f9205029b/go.mod h1:tWPVA9ZAfImNwabjcd9uDE+Mtz0Hfs7a7G3vxrnrwyc=
|
||||
maunium.net/go/maulogger/v2 v2.2.4/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||
maunium.net/go/mautrix v0.9.14 h1:2MMJ630VM+xfa4Q5AooMAhPG1+wQnQybSr/z8PlRZ8A=
|
||||
maunium.net/go/mautrix v0.9.14/go.mod h1:7IzKfWvpQtN+W2Lzxc0rLvIxFM3ryKX6Ys3S/ZoWbg8=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
|
||||
16
vendor/github.com/btcsuite/btcutil/LICENSE
generated
vendored
Normal file
16
vendor/github.com/btcsuite/btcutil/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2013-2017 The btcsuite developers
|
||||
Copyright (c) 2016-2017 The Lightning Network Developers
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
34
vendor/github.com/btcsuite/btcutil/base58/README.md
generated
vendored
Normal file
34
vendor/github.com/btcsuite/btcutil/base58/README.md
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
base58
|
||||
==========
|
||||
|
||||
[](https://travis-ci.org/btcsuite/btcutil)
|
||||
[](http://copyfree.org)
|
||||
[](http://godoc.org/github.com/btcsuite/btcutil/base58)
|
||||
|
||||
Package base58 provides an API for encoding and decoding to and from the
|
||||
modified base58 encoding. It also provides an API to do Base58Check encoding,
|
||||
as described [here](https://en.bitcoin.it/wiki/Base58Check_encoding).
|
||||
|
||||
A comprehensive suite of tests is provided to ensure proper functionality.
|
||||
|
||||
## Installation and Updating
|
||||
|
||||
```bash
|
||||
$ go get -u github.com/btcsuite/btcutil/base58
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
* [Decode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-Decode)
|
||||
Demonstrates how to decode modified base58 encoded data.
|
||||
* [Encode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-Encode)
|
||||
Demonstrates how to encode data using the modified base58 encoding scheme.
|
||||
* [CheckDecode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-CheckDecode)
|
||||
Demonstrates how to decode Base58Check encoded data.
|
||||
* [CheckEncode Example](http://godoc.org/github.com/btcsuite/btcutil/base58#example-CheckEncode)
|
||||
Demonstrates how to encode data using the Base58Check encoding scheme.
|
||||
|
||||
## License
|
||||
|
||||
Package base58 is licensed under the [copyfree](http://copyfree.org) ISC
|
||||
License.
|
||||
49
vendor/github.com/btcsuite/btcutil/base58/alphabet.go
generated
vendored
Normal file
49
vendor/github.com/btcsuite/btcutil/base58/alphabet.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// AUTOGENERATED by genalphabet.go; do not edit.
|
||||
|
||||
package base58
|
||||
|
||||
const (
|
||||
// alphabet is the modified base58 alphabet used by Bitcoin.
|
||||
alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
|
||||
alphabetIdx0 = '1'
|
||||
)
|
||||
|
||||
var b58 = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 1, 2, 3, 4, 5, 6,
|
||||
7, 8, 255, 255, 255, 255, 255, 255,
|
||||
255, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 255, 17, 18, 19, 20, 21, 255,
|
||||
22, 23, 24, 25, 26, 27, 28, 29,
|
||||
30, 31, 32, 255, 255, 255, 255, 255,
|
||||
255, 33, 34, 35, 36, 37, 38, 39,
|
||||
40, 41, 42, 43, 255, 44, 45, 46,
|
||||
47, 48, 49, 50, 51, 52, 53, 54,
|
||||
55, 56, 57, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
75
vendor/github.com/btcsuite/btcutil/base58/base58.go
generated
vendored
Normal file
75
vendor/github.com/btcsuite/btcutil/base58/base58.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2013-2015 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
//go:generate go run genalphabet.go
|
||||
|
||||
var bigRadix = big.NewInt(58)
|
||||
var bigZero = big.NewInt(0)
|
||||
|
||||
// Decode decodes a modified base58 string to a byte slice.
|
||||
func Decode(b string) []byte {
|
||||
answer := big.NewInt(0)
|
||||
j := big.NewInt(1)
|
||||
|
||||
scratch := new(big.Int)
|
||||
for i := len(b) - 1; i >= 0; i-- {
|
||||
tmp := b58[b[i]]
|
||||
if tmp == 255 {
|
||||
return []byte("")
|
||||
}
|
||||
scratch.SetInt64(int64(tmp))
|
||||
scratch.Mul(j, scratch)
|
||||
answer.Add(answer, scratch)
|
||||
j.Mul(j, bigRadix)
|
||||
}
|
||||
|
||||
tmpval := answer.Bytes()
|
||||
|
||||
var numZeros int
|
||||
for numZeros = 0; numZeros < len(b); numZeros++ {
|
||||
if b[numZeros] != alphabetIdx0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
flen := numZeros + len(tmpval)
|
||||
val := make([]byte, flen)
|
||||
copy(val[numZeros:], tmpval)
|
||||
|
||||
return val
|
||||
}
|
||||
|
||||
// Encode encodes a byte slice to a modified base58 string.
|
||||
func Encode(b []byte) string {
|
||||
x := new(big.Int)
|
||||
x.SetBytes(b)
|
||||
|
||||
answer := make([]byte, 0, len(b)*136/100)
|
||||
for x.Cmp(bigZero) > 0 {
|
||||
mod := new(big.Int)
|
||||
x.DivMod(x, bigRadix, mod)
|
||||
answer = append(answer, alphabet[mod.Int64()])
|
||||
}
|
||||
|
||||
// leading zero bytes
|
||||
for _, i := range b {
|
||||
if i != 0 {
|
||||
break
|
||||
}
|
||||
answer = append(answer, alphabetIdx0)
|
||||
}
|
||||
|
||||
// reverse
|
||||
alen := len(answer)
|
||||
for i := 0; i < alen/2; i++ {
|
||||
answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
|
||||
}
|
||||
|
||||
return string(answer)
|
||||
}
|
||||
52
vendor/github.com/btcsuite/btcutil/base58/base58check.go
generated
vendored
Normal file
52
vendor/github.com/btcsuite/btcutil/base58/base58check.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2013-2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package base58
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// ErrChecksum indicates that the checksum of a check-encoded string does not verify against
|
||||
// the checksum.
|
||||
var ErrChecksum = errors.New("checksum error")
|
||||
|
||||
// ErrInvalidFormat indicates that the check-encoded string has an invalid format.
|
||||
var ErrInvalidFormat = errors.New("invalid format: version and/or checksum bytes missing")
|
||||
|
||||
// checksum: first four bytes of sha256^2
|
||||
func checksum(input []byte) (cksum [4]byte) {
|
||||
h := sha256.Sum256(input)
|
||||
h2 := sha256.Sum256(h[:])
|
||||
copy(cksum[:], h2[:4])
|
||||
return
|
||||
}
|
||||
|
||||
// CheckEncode prepends a version byte and appends a four byte checksum.
|
||||
func CheckEncode(input []byte, version byte) string {
|
||||
b := make([]byte, 0, 1+len(input)+4)
|
||||
b = append(b, version)
|
||||
b = append(b, input[:]...)
|
||||
cksum := checksum(b)
|
||||
b = append(b, cksum[:]...)
|
||||
return Encode(b)
|
||||
}
|
||||
|
||||
// CheckDecode decodes a string that was encoded with CheckEncode and verifies the checksum.
|
||||
func CheckDecode(input string) (result []byte, version byte, err error) {
|
||||
decoded := Decode(input)
|
||||
if len(decoded) < 5 {
|
||||
return nil, 0, ErrInvalidFormat
|
||||
}
|
||||
version = decoded[0]
|
||||
var cksum [4]byte
|
||||
copy(cksum[:], decoded[len(decoded)-4:])
|
||||
if checksum(decoded[:len(decoded)-4]) != cksum {
|
||||
return nil, 0, ErrChecksum
|
||||
}
|
||||
payload := decoded[1 : len(decoded)-4]
|
||||
result = append(result, payload...)
|
||||
return
|
||||
}
|
||||
17
vendor/github.com/btcsuite/btcutil/base58/cov_report.sh
generated
vendored
Normal file
17
vendor/github.com/btcsuite/btcutil/base58/cov_report.sh
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script uses gocov to generate a test coverage report.
|
||||
# The gocov tool my be obtained with the following command:
|
||||
# go get github.com/axw/gocov/gocov
|
||||
#
|
||||
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
|
||||
|
||||
# Check for gocov.
|
||||
type gocov >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo >&2 "This script requires the gocov tool."
|
||||
echo >&2 "You may obtain it with the following command:"
|
||||
echo >&2 "go get github.com/axw/gocov/gocov"
|
||||
exit 1
|
||||
fi
|
||||
gocov test | gocov report
|
||||
29
vendor/github.com/btcsuite/btcutil/base58/doc.go
generated
vendored
Normal file
29
vendor/github.com/btcsuite/btcutil/base58/doc.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2014 The btcsuite developers
|
||||
// Use of this source code is governed by an ISC
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package base58 provides an API for working with modified base58 and Base58Check
|
||||
encodings.
|
||||
|
||||
Modified Base58 Encoding
|
||||
|
||||
Standard base58 encoding is similar to standard base64 encoding except, as the
|
||||
name implies, it uses a 58 character alphabet which results in an alphanumeric
|
||||
string and allows some characters which are problematic for humans to be
|
||||
excluded. Due to this, there can be various base58 alphabets.
|
||||
|
||||
The modified base58 alphabet used by Bitcoin, and hence this package, omits the
|
||||
0, O, I, and l characters that look the same in many fonts and are therefore
|
||||
hard to humans to distinguish.
|
||||
|
||||
Base58Check Encoding Scheme
|
||||
|
||||
The Base58Check encoding scheme is primarily used for Bitcoin addresses at the
|
||||
time of this writing, however it can be used to generically encode arbitrary
|
||||
byte arrays into human-readable strings along with a version byte that can be
|
||||
used to differentiate the same payload. For Bitcoin addresses, the extra
|
||||
version is used to differentiate the network of otherwise identical public keys
|
||||
which helps prevent using an address intended for one network on another.
|
||||
*/
|
||||
package base58
|
||||
28
vendor/github.com/matrix-org/gomatrix/.gitignore
generated
vendored
28
vendor/github.com/matrix-org/gomatrix/.gitignore
generated
vendored
@@ -1,28 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.out
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
# test editor files
|
||||
*.swp
|
||||
21
vendor/github.com/matrix-org/gomatrix/.golangci.yml
generated
vendored
21
vendor/github.com/matrix-org/gomatrix/.golangci.yml
generated
vendored
@@ -1,21 +0,0 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
linters:
|
||||
enable:
|
||||
- vet
|
||||
- vetshadow
|
||||
- typecheck
|
||||
- deadcode
|
||||
- gocyclo
|
||||
- golint
|
||||
- varcheck
|
||||
- structcheck
|
||||
- maligned
|
||||
- ineffassign
|
||||
- misspell
|
||||
- unparam
|
||||
- goimports
|
||||
- goconst
|
||||
- unconvert
|
||||
- errcheck
|
||||
- interfacer
|
||||
7
vendor/github.com/matrix-org/gomatrix/.travis.yml
generated
vendored
7
vendor/github.com/matrix-org/gomatrix/.travis.yml
generated
vendored
@@ -1,7 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.13.10
|
||||
install:
|
||||
- go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.24.0
|
||||
- go build
|
||||
script: ./hooks/pre-commit
|
||||
1
vendor/github.com/matrix-org/gomatrix/CHANGELOG.md
generated
vendored
1
vendor/github.com/matrix-org/gomatrix/CHANGELOG.md
generated
vendored
@@ -1 +0,0 @@
|
||||
## Release 0.1.0 (UNRELEASED)
|
||||
201
vendor/github.com/matrix-org/gomatrix/LICENSE
generated
vendored
201
vendor/github.com/matrix-org/gomatrix/LICENSE
generated
vendored
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
71
vendor/github.com/matrix-org/gomatrix/README.md
generated
vendored
71
vendor/github.com/matrix-org/gomatrix/README.md
generated
vendored
@@ -1,71 +0,0 @@
|
||||
# gomatrix
|
||||
[](https://godoc.org/github.com/matrix-org/gomatrix)
|
||||
|
||||
A Golang Matrix client.
|
||||
|
||||
**THIS IS UNDER ACTIVE DEVELOPMENT: BREAKING CHANGES ARE FREQUENT.**
|
||||
|
||||
# Contributing
|
||||
|
||||
All contributions are greatly appreciated!
|
||||
|
||||
## How to report issues
|
||||
|
||||
Please check the current open issues for similar reports
|
||||
in order to avoid duplicates.
|
||||
|
||||
Some general guidelines:
|
||||
|
||||
- Include a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) when possible.
|
||||
- Describe the expected behaviour and what actually happened
|
||||
including a full trace-back in case of exceptions.
|
||||
- Make sure to list details about your environment
|
||||
|
||||
## Setting up your environment
|
||||
|
||||
If you intend to contribute to gomatrix you'll first need Go installed on your machine (version 1.12+ is required). Also, make sure to have golangci-lint properly set up since we use it for pre-commit hooks (for instructions on how to install it, check the [official docs](https://golangci-lint.run/usage/install/#local-installation)).
|
||||
|
||||
- Fork gomatrix to your GitHub account by clicking the [Fork](https://github.com/matrix-org/gomatrix/fork) button.
|
||||
- [Clone](https://help.github.com/en/articles/fork-a-repo#step-2-create-a-local-clone-of-your-fork) the main repository (not your fork) to your local machine.
|
||||
|
||||
|
||||
$ git clone https://github.com/matrix-org/gomatrix
|
||||
$ cd gomatrix
|
||||
|
||||
|
||||
- Add your fork as a remote to push your contributions.Replace
|
||||
``{username}`` with your username.
|
||||
|
||||
git remote add fork https://github.com/{username}/gomatrix
|
||||
|
||||
- Create a new branch to identify what feature you are working on.
|
||||
|
||||
$ git fetch origin
|
||||
$ git checkout -b your-branch-name origin/master
|
||||
|
||||
|
||||
- Make your changes, including tests that cover any code changes you make, and run them as described below.
|
||||
|
||||
- Execute pre-commit hooks by running
|
||||
|
||||
<gomatrix dir>/hooks/pre-commit
|
||||
|
||||
- Push your changes to your fork and [create a pull request](https://help.github.com/en/articles/creating-a-pull-request) describing your changes.
|
||||
|
||||
$ git push --set-upstream fork your-branch-name
|
||||
|
||||
- Finally, create a [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
|
||||
|
||||
## How to run tests
|
||||
|
||||
You can run the test suite and example code with `$ go test -v`
|
||||
|
||||
# Running Coverage
|
||||
|
||||
To run coverage, first generate the coverage report using `go test`
|
||||
|
||||
go test -v -cover -coverprofile=coverage.out
|
||||
|
||||
You can now show the generated report as a html page with `go tool`
|
||||
|
||||
go tool cover -html=coverage.out
|
||||
805
vendor/github.com/matrix-org/gomatrix/client.go
generated
vendored
805
vendor/github.com/matrix-org/gomatrix/client.go
generated
vendored
@@ -1,805 +0,0 @@
|
||||
// Package gomatrix implements the Matrix Client-Server API.
|
||||
//
|
||||
// Specification can be found at http://matrix.org/docs/spec/client_server/r0.2.0.html
|
||||
package gomatrix
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client represents a Matrix client.
|
||||
type Client struct {
|
||||
HomeserverURL *url.URL // The base homeserver URL
|
||||
Prefix string // The API prefix eg '/_matrix/client/r0'
|
||||
UserID string // The user ID of the client. Used for forming HTTP paths which use the client's user ID.
|
||||
AccessToken string // The access_token for the client.
|
||||
Client *http.Client // The underlying HTTP client which will be used to make HTTP requests.
|
||||
Syncer Syncer // The thing which can process /sync responses
|
||||
Store Storer // The thing which can store rooms/tokens/ids
|
||||
|
||||
// The ?user_id= query parameter for application services. This must be set *prior* to calling a method. If this is empty,
|
||||
// no user_id parameter will be sent.
|
||||
// See http://matrix.org/docs/spec/application_service/unstable.html#identity-assertion
|
||||
AppServiceUserID string
|
||||
|
||||
syncingMutex sync.Mutex // protects syncingID
|
||||
syncingID uint32 // Identifies the current Sync. Only one Sync can be active at any given time.
|
||||
}
|
||||
|
||||
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
|
||||
type HTTPError struct {
|
||||
Contents []byte
|
||||
WrappedError error
|
||||
Message string
|
||||
Code int
|
||||
}
|
||||
|
||||
func (e HTTPError) Error() string {
|
||||
var wrappedErrMsg string
|
||||
if e.WrappedError != nil {
|
||||
wrappedErrMsg = e.WrappedError.Error()
|
||||
}
|
||||
return fmt.Sprintf("contents=%v msg=%s code=%d wrapped=%s", e.Contents, e.Message, e.Code, wrappedErrMsg)
|
||||
}
|
||||
|
||||
// BuildURL builds a URL with the Client's homeserver/prefix set already.
|
||||
func (cli *Client) BuildURL(urlPath ...string) string {
|
||||
ps := append([]string{cli.Prefix}, urlPath...)
|
||||
return cli.BuildBaseURL(ps...)
|
||||
}
|
||||
|
||||
// BuildBaseURL builds a URL with the Client's homeserver set already. You must
|
||||
// supply the prefix in the path.
|
||||
func (cli *Client) BuildBaseURL(urlPath ...string) string {
|
||||
// copy the URL. Purposefully ignore error as the input is from a valid URL already
|
||||
hsURL, _ := url.Parse(cli.HomeserverURL.String())
|
||||
parts := []string{hsURL.Path}
|
||||
parts = append(parts, urlPath...)
|
||||
hsURL.Path = path.Join(parts...)
|
||||
// Manually add the trailing slash back to the end of the path if it's explicitly needed
|
||||
if strings.HasSuffix(urlPath[len(urlPath)-1], "/") {
|
||||
hsURL.Path = hsURL.Path + "/"
|
||||
}
|
||||
query := hsURL.Query()
|
||||
if cli.AppServiceUserID != "" {
|
||||
query.Set("user_id", cli.AppServiceUserID)
|
||||
}
|
||||
hsURL.RawQuery = query.Encode()
|
||||
return hsURL.String()
|
||||
}
|
||||
|
||||
// BuildURLWithQuery builds a URL with query parameters in addition to the Client's homeserver/prefix set already.
|
||||
func (cli *Client) BuildURLWithQuery(urlPath []string, urlQuery map[string]string) string {
|
||||
u, _ := url.Parse(cli.BuildURL(urlPath...))
|
||||
q := u.Query()
|
||||
for k, v := range urlQuery {
|
||||
q.Set(k, v)
|
||||
}
|
||||
u.RawQuery = q.Encode()
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// SetCredentials sets the user ID and access token on this client instance.
|
||||
func (cli *Client) SetCredentials(userID, accessToken string) {
|
||||
cli.AccessToken = accessToken
|
||||
cli.UserID = userID
|
||||
}
|
||||
|
||||
// ClearCredentials removes the user ID and access token on this client instance.
|
||||
func (cli *Client) ClearCredentials() {
|
||||
cli.AccessToken = ""
|
||||
cli.UserID = ""
|
||||
}
|
||||
|
||||
// Sync starts syncing with the provided Homeserver. If Sync() is called twice then the first sync will be stopped and the
|
||||
// error will be nil.
|
||||
//
|
||||
// This function will block until a fatal /sync error occurs, so it should almost always be started as a new goroutine.
|
||||
// Fatal sync errors can be caused by:
|
||||
// - The failure to create a filter.
|
||||
// - Client.Syncer.OnFailedSync returning an error in response to a failed sync.
|
||||
// - Client.Syncer.ProcessResponse returning an error.
|
||||
// If you wish to continue retrying in spite of these fatal errors, call Sync() again.
|
||||
func (cli *Client) Sync() error {
|
||||
// Mark the client as syncing.
|
||||
// We will keep syncing until the syncing state changes. Either because
|
||||
// Sync is called or StopSync is called.
|
||||
syncingID := cli.incrementSyncingID()
|
||||
nextBatch := cli.Store.LoadNextBatch(cli.UserID)
|
||||
filterID := cli.Store.LoadFilterID(cli.UserID)
|
||||
if filterID == "" {
|
||||
filterJSON := cli.Syncer.GetFilterJSON(cli.UserID)
|
||||
resFilter, err := cli.CreateFilter(filterJSON)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filterID = resFilter.FilterID
|
||||
cli.Store.SaveFilterID(cli.UserID, filterID)
|
||||
}
|
||||
|
||||
for {
|
||||
resSync, err := cli.SyncRequest(30000, nextBatch, filterID, false, "")
|
||||
if err != nil {
|
||||
duration, err2 := cli.Syncer.OnFailedSync(resSync, err)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
time.Sleep(duration)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check that the syncing state hasn't changed
|
||||
// Either because we've stopped syncing or another sync has been started.
|
||||
// We discard the response from our sync.
|
||||
if cli.getSyncingID() != syncingID {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Save the token now *before* processing it. This means it's possible
|
||||
// to not process some events, but it means that we won't get constantly stuck processing
|
||||
// a malformed/buggy event which keeps making us panic.
|
||||
cli.Store.SaveNextBatch(cli.UserID, resSync.NextBatch)
|
||||
if err = cli.Syncer.ProcessResponse(resSync, nextBatch); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nextBatch = resSync.NextBatch
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) incrementSyncingID() uint32 {
|
||||
cli.syncingMutex.Lock()
|
||||
defer cli.syncingMutex.Unlock()
|
||||
cli.syncingID++
|
||||
return cli.syncingID
|
||||
}
|
||||
|
||||
func (cli *Client) getSyncingID() uint32 {
|
||||
cli.syncingMutex.Lock()
|
||||
defer cli.syncingMutex.Unlock()
|
||||
return cli.syncingID
|
||||
}
|
||||
|
||||
// StopSync stops the ongoing sync started by Sync.
|
||||
func (cli *Client) StopSync() {
|
||||
// Advance the syncing state so that any running Syncs will terminate.
|
||||
cli.incrementSyncingID()
|
||||
}
|
||||
|
||||
// MakeRequest makes a JSON HTTP request to the given URL.
|
||||
// The response body will be stream decoded into an interface. This will automatically stop if the response
|
||||
// body is nil.
|
||||
//
|
||||
// Returns an error if the response is not 2xx along with the HTTP body bytes if it got that far. This error is
|
||||
// an HTTPError which includes the returned HTTP status code, byte contents of the response body and possibly a
|
||||
// RespError as the WrappedError, if the HTTP body could be decoded as a RespError.
|
||||
func (cli *Client) MakeRequest(method string, httpURL string, reqBody interface{}, resBody interface{}) error {
|
||||
var req *http.Request
|
||||
var err error
|
||||
if reqBody != nil {
|
||||
buf := new(bytes.Buffer)
|
||||
if err := json.NewEncoder(buf).Encode(reqBody); err != nil {
|
||||
return err
|
||||
}
|
||||
req, err = http.NewRequest(method, httpURL, buf)
|
||||
} else {
|
||||
req, err = http.NewRequest(method, httpURL, nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
if cli.AccessToken != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+cli.AccessToken)
|
||||
}
|
||||
|
||||
res, err := cli.Client.Do(req)
|
||||
if res != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if res.StatusCode/100 != 2 { // not 2xx
|
||||
contents, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var wrap error
|
||||
var respErr RespError
|
||||
if _ = json.Unmarshal(contents, &respErr); respErr.ErrCode != "" {
|
||||
wrap = respErr
|
||||
}
|
||||
|
||||
// If we failed to decode as RespError, don't just drop the HTTP body, include it in the
|
||||
// HTTP error instead (e.g proxy errors which return HTML).
|
||||
msg := "Failed to " + method + " JSON to " + req.URL.Path
|
||||
if wrap == nil {
|
||||
msg = msg + ": " + string(contents)
|
||||
}
|
||||
|
||||
return HTTPError{
|
||||
Contents: contents,
|
||||
Code: res.StatusCode,
|
||||
Message: msg,
|
||||
WrappedError: wrap,
|
||||
}
|
||||
}
|
||||
|
||||
if resBody != nil && res.Body != nil {
|
||||
return json.NewDecoder(res.Body).Decode(&resBody)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateFilter makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
|
||||
func (cli *Client) CreateFilter(filter json.RawMessage) (resp *RespCreateFilter, err error) {
|
||||
urlPath := cli.BuildURL("user", cli.UserID, "filter")
|
||||
err = cli.MakeRequest("POST", urlPath, &filter, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// SyncRequest makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync
|
||||
func (cli *Client) SyncRequest(timeout int, since, filterID string, fullState bool, setPresence string) (resp *RespSync, err error) {
|
||||
query := map[string]string{
|
||||
"timeout": strconv.Itoa(timeout),
|
||||
}
|
||||
if since != "" {
|
||||
query["since"] = since
|
||||
}
|
||||
if filterID != "" {
|
||||
query["filter"] = filterID
|
||||
}
|
||||
if setPresence != "" {
|
||||
query["set_presence"] = setPresence
|
||||
}
|
||||
if fullState {
|
||||
query["full_state"] = "true"
|
||||
}
|
||||
urlPath := cli.BuildURLWithQuery([]string{"sync"}, query)
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *Client) register(u string, req *ReqRegister) (resp *RespRegister, uiaResp *RespUserInteractive, err error) {
|
||||
err = cli.MakeRequest("POST", u, req, &resp)
|
||||
if err != nil {
|
||||
httpErr, ok := err.(HTTPError)
|
||||
if !ok { // network error
|
||||
return
|
||||
}
|
||||
if httpErr.Code == 401 {
|
||||
// body should be RespUserInteractive, if it isn't, fail with the error
|
||||
err = json.Unmarshal(httpErr.Contents, &uiaResp)
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Register makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
||||
//
|
||||
// Registers with kind=user. For kind=guest, see RegisterGuest.
|
||||
func (cli *Client) Register(req *ReqRegister) (*RespRegister, *RespUserInteractive, error) {
|
||||
u := cli.BuildURL("register")
|
||||
return cli.register(u, req)
|
||||
}
|
||||
|
||||
// RegisterGuest makes an HTTP request according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
||||
// with kind=guest.
|
||||
//
|
||||
// For kind=user, see Register.
|
||||
func (cli *Client) RegisterGuest(req *ReqRegister) (*RespRegister, *RespUserInteractive, error) {
|
||||
query := map[string]string{
|
||||
"kind": "guest",
|
||||
}
|
||||
u := cli.BuildURLWithQuery([]string{"register"}, query)
|
||||
return cli.register(u, req)
|
||||
}
|
||||
|
||||
// RegisterDummy performs m.login.dummy registration according to https://matrix.org/docs/spec/client_server/r0.2.0.html#dummy-auth
|
||||
//
|
||||
// Only a username and password need to be provided on the ReqRegister struct. Most local/developer homeservers will allow registration
|
||||
// this way. If the homeserver does not, an error is returned.
|
||||
//
|
||||
// This does not set credentials on the client instance. See SetCredentials() instead.
|
||||
//
|
||||
// res, err := cli.RegisterDummy(&gomatrix.ReqRegister{
|
||||
// Username: "alice",
|
||||
// Password: "wonderland",
|
||||
// })
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
// token := res.AccessToken
|
||||
func (cli *Client) RegisterDummy(req *ReqRegister) (*RespRegister, error) {
|
||||
res, uia, err := cli.Register(req)
|
||||
if err != nil && uia == nil {
|
||||
return nil, err
|
||||
}
|
||||
if uia != nil && uia.HasSingleStageFlow("m.login.dummy") {
|
||||
req.Auth = struct {
|
||||
Type string `json:"type"`
|
||||
Session string `json:"session,omitempty"`
|
||||
}{"m.login.dummy", uia.Session}
|
||||
res, _, err = cli.Register(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if res == nil {
|
||||
return nil, fmt.Errorf("registration failed: does this server support m.login.dummy?")
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Login a user to the homeserver according to http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-login
|
||||
// This does not set credentials on this client instance. See SetCredentials() instead.
|
||||
func (cli *Client) Login(req *ReqLogin) (resp *RespLogin, err error) {
|
||||
urlPath := cli.BuildURL("login")
|
||||
err = cli.MakeRequest("POST", urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// Logout the current user. See http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-logout
|
||||
// This does not clear the credentials from the client instance. See ClearCredentials() instead.
|
||||
func (cli *Client) Logout() (resp *RespLogout, err error) {
|
||||
urlPath := cli.BuildURL("logout")
|
||||
err = cli.MakeRequest("POST", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// LogoutAll logs the current user out on all devices. See https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-logout-all
|
||||
// This does not clear the credentials from the client instance. See ClearCredentails() instead.
|
||||
func (cli *Client) LogoutAll() (resp *RespLogoutAll, err error) {
|
||||
urlPath := cli.BuildURL("logout/all")
|
||||
err = cli.MakeRequest("POST", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// Versions returns the list of supported Matrix versions on this homeserver. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions
|
||||
func (cli *Client) Versions() (resp *RespVersions, err error) {
|
||||
urlPath := cli.BuildBaseURL("_matrix", "client", "versions")
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// PublicRooms returns the list of public rooms on target server. See https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-unstable-publicrooms
|
||||
func (cli *Client) PublicRooms(limit int, since string, server string) (resp *RespPublicRooms, err error) {
|
||||
args := map[string]string{}
|
||||
|
||||
if limit != 0 {
|
||||
args["limit"] = strconv.Itoa(limit)
|
||||
}
|
||||
if since != "" {
|
||||
args["since"] = since
|
||||
}
|
||||
if server != "" {
|
||||
args["server"] = server
|
||||
}
|
||||
|
||||
urlPath := cli.BuildURLWithQuery([]string{"publicRooms"}, args)
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// PublicRoomsFiltered returns a subset of PublicRooms filtered server side.
|
||||
// See https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-unstable-publicrooms
|
||||
func (cli *Client) PublicRoomsFiltered(limit int, since string, server string, filter string) (resp *RespPublicRooms, err error) {
|
||||
content := map[string]string{}
|
||||
|
||||
if limit != 0 {
|
||||
content["limit"] = strconv.Itoa(limit)
|
||||
}
|
||||
if since != "" {
|
||||
content["since"] = since
|
||||
}
|
||||
if filter != "" {
|
||||
content["filter"] = filter
|
||||
}
|
||||
|
||||
var urlPath string
|
||||
if server == "" {
|
||||
urlPath = cli.BuildURL("publicRooms")
|
||||
} else {
|
||||
urlPath = cli.BuildURLWithQuery([]string{"publicRooms"}, map[string]string{
|
||||
"server": server,
|
||||
})
|
||||
}
|
||||
|
||||
err = cli.MakeRequest("POST", urlPath, content, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// JoinRoom joins the client to a room ID or alias. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-join-roomidoralias
|
||||
//
|
||||
// If serverName is specified, this will be added as a query param to instruct the homeserver to join via that server. If content is specified, it will
|
||||
// be JSON encoded and used as the request body.
|
||||
func (cli *Client) JoinRoom(roomIDorAlias, serverName string, content interface{}) (resp *RespJoinRoom, err error) {
|
||||
var urlPath string
|
||||
if serverName != "" {
|
||||
urlPath = cli.BuildURLWithQuery([]string{"join", roomIDorAlias}, map[string]string{
|
||||
"server_name": serverName,
|
||||
})
|
||||
} else {
|
||||
urlPath = cli.BuildURL("join", roomIDorAlias)
|
||||
}
|
||||
err = cli.MakeRequest("POST", urlPath, content, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetDisplayName returns the display name of the user from the specified MXID. See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
|
||||
func (cli *Client) GetDisplayName(mxid string) (resp *RespUserDisplayName, err error) {
|
||||
urlPath := cli.BuildURL("profile", mxid, "displayname")
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOwnDisplayName returns the user's display name. See https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
|
||||
func (cli *Client) GetOwnDisplayName() (resp *RespUserDisplayName, err error) {
|
||||
urlPath := cli.BuildURL("profile", cli.UserID, "displayname")
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// SetDisplayName sets the user's profile display name. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-profile-userid-displayname
|
||||
func (cli *Client) SetDisplayName(displayName string) (err error) {
|
||||
urlPath := cli.BuildURL("profile", cli.UserID, "displayname")
|
||||
s := struct {
|
||||
DisplayName string `json:"displayname"`
|
||||
}{displayName}
|
||||
err = cli.MakeRequest("PUT", urlPath, &s, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// GetAvatarURL gets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-avatar-url
|
||||
func (cli *Client) GetAvatarURL() (string, error) {
|
||||
urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url")
|
||||
s := struct {
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}{}
|
||||
|
||||
err := cli.MakeRequest("GET", urlPath, nil, &s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return s.AvatarURL, nil
|
||||
}
|
||||
|
||||
// SetAvatarURL sets the user's avatar URL. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-profile-userid-avatar-url
|
||||
func (cli *Client) SetAvatarURL(url string) error {
|
||||
urlPath := cli.BuildURL("profile", cli.UserID, "avatar_url")
|
||||
s := struct {
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
}{url}
|
||||
err := cli.MakeRequest("PUT", urlPath, &s, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStatus returns the status of the user from the specified MXID. See https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status
|
||||
func (cli *Client) GetStatus(mxid string) (resp *RespUserStatus, err error) {
|
||||
urlPath := cli.BuildURL("presence", mxid, "status")
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// GetOwnStatus returns the user's status. See https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status
|
||||
func (cli *Client) GetOwnStatus() (resp *RespUserStatus, err error) {
|
||||
return cli.GetStatus(cli.UserID)
|
||||
}
|
||||
|
||||
// SetStatus sets the user's status. See https://matrix.org/docs/spec/client_server/r0.6.0#put-matrix-client-r0-presence-userid-status
|
||||
func (cli *Client) SetStatus(presence, status string) (err error) {
|
||||
urlPath := cli.BuildURL("presence", cli.UserID, "status")
|
||||
s := struct {
|
||||
Presence string `json:"presence"`
|
||||
StatusMsg string `json:"status_msg"`
|
||||
}{presence, status}
|
||||
err = cli.MakeRequest("PUT", urlPath, &s, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
|
||||
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
|
||||
func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) {
|
||||
txnID := txnID()
|
||||
urlPath := cli.BuildURL("rooms", roomID, "send", eventType, txnID)
|
||||
err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// SendStateEvent sends a state event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-state-eventtype-statekey
|
||||
// contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
|
||||
func (cli *Client) SendStateEvent(roomID, eventType, stateKey string, contentJSON interface{}) (resp *RespSendEvent, err error) {
|
||||
urlPath := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
|
||||
err = cli.MakeRequest("PUT", urlPath, contentJSON, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// SendText sends an m.room.message event into the given room with a msgtype of m.text
|
||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-text
|
||||
func (cli *Client) SendText(roomID, text string) (*RespSendEvent, error) {
|
||||
return cli.SendMessageEvent(roomID, "m.room.message",
|
||||
TextMessage{MsgType: "m.text", Body: text})
|
||||
}
|
||||
|
||||
// SendFormattedText sends an m.room.message event into the given room with a msgtype of m.text, supports a subset of HTML for formatting.
|
||||
// See https://matrix.org/docs/spec/client_server/r0.6.0#m-text
|
||||
func (cli *Client) SendFormattedText(roomID, text, formattedText string) (*RespSendEvent, error) {
|
||||
return cli.SendMessageEvent(roomID, "m.room.message",
|
||||
TextMessage{MsgType: "m.text", Body: text, FormattedBody: formattedText, Format: "org.matrix.custom.html"})
|
||||
}
|
||||
|
||||
// SendImage sends an m.room.message event into the given room with a msgtype of m.image
|
||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
|
||||
func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
|
||||
return cli.SendMessageEvent(roomID, "m.room.message",
|
||||
ImageMessage{
|
||||
MsgType: "m.image",
|
||||
Body: body,
|
||||
URL: url,
|
||||
})
|
||||
}
|
||||
|
||||
// SendVideo sends an m.room.message event into the given room with a msgtype of m.video
|
||||
// See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
|
||||
func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
|
||||
return cli.SendMessageEvent(roomID, "m.room.message",
|
||||
VideoMessage{
|
||||
MsgType: "m.video",
|
||||
Body: body,
|
||||
URL: url,
|
||||
})
|
||||
}
|
||||
|
||||
// SendNotice sends an m.room.message event into the given room with a msgtype of m.notice
|
||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-notice
|
||||
func (cli *Client) SendNotice(roomID, text string) (*RespSendEvent, error) {
|
||||
return cli.SendMessageEvent(roomID, "m.room.message",
|
||||
TextMessage{MsgType: "m.notice", Body: text})
|
||||
}
|
||||
|
||||
// RedactEvent redacts the given event. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
||||
func (cli *Client) RedactEvent(roomID, eventID string, req *ReqRedact) (resp *RespSendEvent, err error) {
|
||||
txnID := txnID()
|
||||
urlPath := cli.BuildURL("rooms", roomID, "redact", eventID, txnID)
|
||||
err = cli.MakeRequest("PUT", urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// MarkRead marks eventID in roomID as read, signifying the event, and all before it have been read. See https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-rooms-roomid-receipt-receipttype-eventid
|
||||
func (cli *Client) MarkRead(roomID, eventID string) error {
|
||||
urlPath := cli.BuildURL("rooms", roomID, "receipt", "m.read", eventID)
|
||||
return cli.MakeRequest("POST", urlPath, nil, nil)
|
||||
}
|
||||
|
||||
// CreateRoom creates a new Matrix room. See https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
// resp, err := cli.CreateRoom(&gomatrix.ReqCreateRoom{
|
||||
// Preset: "public_chat",
|
||||
// })
|
||||
// fmt.Println("Room:", resp.RoomID)
|
||||
func (cli *Client) CreateRoom(req *ReqCreateRoom) (resp *RespCreateRoom, err error) {
|
||||
urlPath := cli.BuildURL("createRoom")
|
||||
err = cli.MakeRequest("POST", urlPath, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// LeaveRoom leaves the given room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
|
||||
func (cli *Client) LeaveRoom(roomID string) (resp *RespLeaveRoom, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "leave")
|
||||
err = cli.MakeRequest("POST", u, struct{}{}, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// ForgetRoom forgets a room entirely. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
|
||||
func (cli *Client) ForgetRoom(roomID string) (resp *RespForgetRoom, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "forget")
|
||||
err = cli.MakeRequest("POST", u, struct{}{}, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// InviteUser invites a user to a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
func (cli *Client) InviteUser(roomID string, req *ReqInviteUser) (resp *RespInviteUser, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "invite")
|
||||
err = cli.MakeRequest("POST", u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// InviteUserByThirdParty invites a third-party identifier to a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#invite-by-third-party-id-endpoint
|
||||
func (cli *Client) InviteUserByThirdParty(roomID string, req *ReqInvite3PID) (resp *RespInviteUser, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "invite")
|
||||
err = cli.MakeRequest("POST", u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// KickUser kicks a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
func (cli *Client) KickUser(roomID string, req *ReqKickUser) (resp *RespKickUser, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "kick")
|
||||
err = cli.MakeRequest("POST", u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// BanUser bans a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
func (cli *Client) BanUser(roomID string, req *ReqBanUser) (resp *RespBanUser, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "ban")
|
||||
err = cli.MakeRequest("POST", u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// UnbanUser unbans a user from a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
func (cli *Client) UnbanUser(roomID string, req *ReqUnbanUser) (resp *RespUnbanUser, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "unban")
|
||||
err = cli.MakeRequest("POST", u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// UserTyping sets the typing status of the user. See https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
func (cli *Client) UserTyping(roomID string, typing bool, timeout int64) (resp *RespTyping, err error) {
|
||||
req := ReqTyping{Typing: typing, Timeout: timeout}
|
||||
u := cli.BuildURL("rooms", roomID, "typing", cli.UserID)
|
||||
err = cli.MakeRequest("PUT", u, req, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// StateEvent gets a single state event in a room. It will attempt to JSON unmarshal into the given "outContent" struct with
|
||||
// the HTTP response body, or return an error.
|
||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
|
||||
func (cli *Client) StateEvent(roomID, eventType, stateKey string, outContent interface{}) (err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
|
||||
err = cli.MakeRequest("GET", u, nil, outContent)
|
||||
return
|
||||
}
|
||||
|
||||
// UploadLink uploads an HTTP URL and then returns an MXC URI.
|
||||
func (cli *Client) UploadLink(link string) (*RespMediaUpload, error) {
|
||||
res, err := cli.Client.Get(link)
|
||||
if res != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cli.UploadToContentRepo(res.Body, res.Header.Get("Content-Type"), res.ContentLength)
|
||||
}
|
||||
|
||||
// UploadToContentRepo uploads the given bytes to the content repository and returns an MXC URI.
|
||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
|
||||
func (cli *Client) UploadToContentRepo(content io.Reader, contentType string, contentLength int64) (*RespMediaUpload, error) {
|
||||
req, err := http.NewRequest("POST", cli.BuildBaseURL("_matrix/media/r0/upload"), content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
req.Header.Set("Authorization", "Bearer "+cli.AccessToken)
|
||||
|
||||
req.ContentLength = contentLength
|
||||
|
||||
res, err := cli.Client.Do(req)
|
||||
if res != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
contents, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, HTTPError{
|
||||
Message: "Upload request failed - Failed to read response body: " + err.Error(),
|
||||
Code: res.StatusCode,
|
||||
}
|
||||
}
|
||||
return nil, HTTPError{
|
||||
Contents: contents,
|
||||
Message: "Upload request failed: " + string(contents),
|
||||
Code: res.StatusCode,
|
||||
}
|
||||
}
|
||||
|
||||
var m RespMediaUpload
|
||||
if err := json.NewDecoder(res.Body).Decode(&m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
// JoinedMembers returns a map of joined room members. See TODO-SPEC. https://github.com/matrix-org/synapse/pull/1680
|
||||
//
|
||||
// In general, usage of this API is discouraged in favour of /sync, as calling this API can race with incoming membership changes.
|
||||
// This API is primarily designed for application services which may want to efficiently look up joined members in a room.
|
||||
func (cli *Client) JoinedMembers(roomID string) (resp *RespJoinedMembers, err error) {
|
||||
u := cli.BuildURL("rooms", roomID, "joined_members")
|
||||
err = cli.MakeRequest("GET", u, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// JoinedRooms returns a list of rooms which the client is joined to. See TODO-SPEC. https://github.com/matrix-org/synapse/pull/1680
|
||||
//
|
||||
// In general, usage of this API is discouraged in favour of /sync, as calling this API can race with incoming membership changes.
|
||||
// This API is primarily designed for application services which may want to efficiently look up joined rooms.
|
||||
func (cli *Client) JoinedRooms() (resp *RespJoinedRooms, err error) {
|
||||
u := cli.BuildURL("joined_rooms")
|
||||
err = cli.MakeRequest("GET", u, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// 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://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
|
||||
func (cli *Client) Messages(roomID, from, to string, dir rune, limit int) (resp *RespMessages, err error) {
|
||||
query := map[string]string{
|
||||
"from": from,
|
||||
"dir": string(dir),
|
||||
}
|
||||
if to != "" {
|
||||
query["to"] = to
|
||||
}
|
||||
if limit != 0 {
|
||||
query["limit"] = strconv.Itoa(limit)
|
||||
}
|
||||
|
||||
urlPath := cli.BuildURLWithQuery([]string{"rooms", roomID, "messages"}, query)
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
// TurnServer returns turn server details and credentials for the client to use when initiating calls.
|
||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-voip-turnserver
|
||||
func (cli *Client) TurnServer() (resp *RespTurnServer, err error) {
|
||||
urlPath := cli.BuildURL("voip", "turnServer")
|
||||
err = cli.MakeRequest("GET", urlPath, nil, &resp)
|
||||
return
|
||||
}
|
||||
|
||||
func txnID() string {
|
||||
return "go" + strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
}
|
||||
|
||||
// NewClient creates a new Matrix Client ready for syncing
|
||||
func NewClient(homeserverURL, userID, accessToken string) (*Client, error) {
|
||||
hsURL, err := url.Parse(homeserverURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// By default, use an in-memory store which will never save filter ids / next batch tokens to disk.
|
||||
// The client will work with this storer: it just won't remember across restarts.
|
||||
// In practice, a database backend should be used.
|
||||
store := NewInMemoryStore()
|
||||
cli := Client{
|
||||
AccessToken: accessToken,
|
||||
HomeserverURL: hsURL,
|
||||
UserID: userID,
|
||||
Prefix: "/_matrix/client/r0",
|
||||
Syncer: NewDefaultSyncer(userID, store),
|
||||
Store: store,
|
||||
}
|
||||
// By default, use the default HTTP client.
|
||||
cli.Client = http.DefaultClient
|
||||
|
||||
return &cli, nil
|
||||
}
|
||||
157
vendor/github.com/matrix-org/gomatrix/events.go
generated
vendored
157
vendor/github.com/matrix-org/gomatrix/events.go
generated
vendored
@@ -1,157 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
import (
|
||||
"html"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Event represents a single Matrix event.
|
||||
type Event struct {
|
||||
StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
|
||||
Sender string `json:"sender"` // The user ID of the sender of the event
|
||||
Type string `json:"type"` // The event type
|
||||
Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
|
||||
ID string `json:"event_id"` // The unique ID of this event
|
||||
RoomID string `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
|
||||
Redacts string `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
|
||||
Unsigned map[string]interface{} `json:"unsigned"` // The unsigned portions of the event, such as age and prev_content
|
||||
Content map[string]interface{} `json:"content"` // The JSON content of the event.
|
||||
PrevContent map[string]interface{} `json:"prev_content,omitempty"` // The JSON prev_content of the event.
|
||||
}
|
||||
|
||||
// Body returns the value of the "body" key in the event content if it is
|
||||
// present and is a string.
|
||||
func (event *Event) Body() (body string, ok bool) {
|
||||
value, exists := event.Content["body"]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
body, ok = value.(string)
|
||||
return
|
||||
}
|
||||
|
||||
// MessageType returns the value of the "msgtype" key in the event content if
|
||||
// it is present and is a string.
|
||||
func (event *Event) MessageType() (msgtype string, ok bool) {
|
||||
value, exists := event.Content["msgtype"]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
msgtype, ok = value.(string)
|
||||
return
|
||||
}
|
||||
|
||||
// TextMessage is the contents of a Matrix formated message event.
|
||||
type TextMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
FormattedBody string `json:"formatted_body"`
|
||||
Format string `json:"format"`
|
||||
}
|
||||
|
||||
// ThumbnailInfo contains info about an thumbnail image - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
|
||||
type ThumbnailInfo struct {
|
||||
Height uint `json:"h,omitempty"`
|
||||
Width uint `json:"w,omitempty"`
|
||||
Mimetype string `json:"mimetype,omitempty"`
|
||||
Size uint `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
// ImageInfo contains info about an image - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
|
||||
type ImageInfo struct {
|
||||
Height uint `json:"h,omitempty"`
|
||||
Width uint `json:"w,omitempty"`
|
||||
Mimetype string `json:"mimetype,omitempty"`
|
||||
Size uint `json:"size,omitempty"`
|
||||
ThumbnailInfo ThumbnailInfo `json:"thumbnail_info,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
||||
}
|
||||
|
||||
// VideoInfo contains info about a video - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
|
||||
type VideoInfo struct {
|
||||
Mimetype string `json:"mimetype,omitempty"`
|
||||
ThumbnailInfo ThumbnailInfo `json:"thumbnail_info"`
|
||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
||||
Height uint `json:"h,omitempty"`
|
||||
Width uint `json:"w,omitempty"`
|
||||
Duration uint `json:"duration,omitempty"`
|
||||
Size uint `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
// VideoMessage is an m.video - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
|
||||
type VideoMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
URL string `json:"url"`
|
||||
Info VideoInfo `json:"info"`
|
||||
}
|
||||
|
||||
// ImageMessage is an m.image event
|
||||
type ImageMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
URL string `json:"url"`
|
||||
Info ImageInfo `json:"info"`
|
||||
}
|
||||
|
||||
// An HTMLMessage is the contents of a Matrix HTML formated message event.
|
||||
type HTMLMessage struct {
|
||||
Body string `json:"body"`
|
||||
MsgType string `json:"msgtype"`
|
||||
Format string `json:"format"`
|
||||
FormattedBody string `json:"formatted_body"`
|
||||
}
|
||||
|
||||
// FileInfo contains info about an file - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-file
|
||||
type FileInfo struct {
|
||||
Mimetype string `json:"mimetype,omitempty"`
|
||||
Size uint `json:"size,omitempty"` //filesize in bytes
|
||||
}
|
||||
|
||||
// FileMessage is an m.file event - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-file
|
||||
type FileMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
URL string `json:"url"`
|
||||
Filename string `json:"filename"`
|
||||
Info FileInfo `json:"info,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
||||
ThumbnailInfo ImageInfo `json:"thumbnail_info,omitempty"`
|
||||
}
|
||||
|
||||
// LocationMessage is an m.location event - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-location
|
||||
type LocationMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
GeoURI string `json:"geo_uri"`
|
||||
ThumbnailURL string `json:"thumbnail_url,omitempty"`
|
||||
ThumbnailInfo ImageInfo `json:"thumbnail_info,omitempty"`
|
||||
}
|
||||
|
||||
// AudioInfo contains info about an file - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio
|
||||
type AudioInfo struct {
|
||||
Mimetype string `json:"mimetype,omitempty"`
|
||||
Size uint `json:"size,omitempty"` //filesize in bytes
|
||||
Duration uint `json:"duration,omitempty"` //audio duration in ms
|
||||
}
|
||||
|
||||
// AudioMessage is an m.audio event - http://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio
|
||||
type AudioMessage struct {
|
||||
MsgType string `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
URL string `json:"url"`
|
||||
Info AudioInfo `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
var htmlRegex = regexp.MustCompile("<[^<]+?>")
|
||||
|
||||
// GetHTMLMessage returns an HTMLMessage with the body set to a stripped version of the provided HTML, in addition
|
||||
// to the provided HTML.
|
||||
func GetHTMLMessage(msgtype, htmlText string) HTMLMessage {
|
||||
return HTMLMessage{
|
||||
Body: html.UnescapeString(htmlRegex.ReplaceAllLiteralString(htmlText, "")),
|
||||
MsgType: msgtype,
|
||||
Format: "org.matrix.custom.html",
|
||||
FormattedBody: htmlText,
|
||||
}
|
||||
}
|
||||
90
vendor/github.com/matrix-org/gomatrix/filter.go
generated
vendored
90
vendor/github.com/matrix-org/gomatrix/filter.go
generated
vendored
@@ -1,90 +0,0 @@
|
||||
// Copyright 2017 Jan Christian Grünhage
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gomatrix
|
||||
|
||||
import "errors"
|
||||
|
||||
//Filter is used by clients to specify how the server should filter responses to e.g. sync requests
|
||||
//Specified by: https://matrix.org/docs/spec/client_server/r0.2.0.html#filtering
|
||||
type Filter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
EventFields []string `json:"event_fields,omitempty"`
|
||||
EventFormat string `json:"event_format,omitempty"`
|
||||
Presence FilterPart `json:"presence,omitempty"`
|
||||
Room RoomFilter `json:"room,omitempty"`
|
||||
}
|
||||
|
||||
// RoomFilter is used to define filtering rules for room events
|
||||
type RoomFilter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
Ephemeral FilterPart `json:"ephemeral,omitempty"`
|
||||
IncludeLeave bool `json:"include_leave,omitempty"`
|
||||
NotRooms []string `json:"not_rooms,omitempty"`
|
||||
Rooms []string `json:"rooms,omitempty"`
|
||||
State FilterPart `json:"state,omitempty"`
|
||||
Timeline FilterPart `json:"timeline,omitempty"`
|
||||
}
|
||||
|
||||
// FilterPart is used to define filtering rules for specific categories of events
|
||||
type FilterPart struct {
|
||||
NotRooms []string `json:"not_rooms,omitempty"`
|
||||
Rooms []string `json:"rooms,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
NotSenders []string `json:"not_senders,omitempty"`
|
||||
NotTypes []string `json:"not_types,omitempty"`
|
||||
Senders []string `json:"senders,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the filter contains valid property values
|
||||
func (filter *Filter) Validate() error {
|
||||
if filter.EventFormat != "client" && filter.EventFormat != "federation" {
|
||||
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultFilter returns the default filter used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilter() Filter {
|
||||
return Filter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
EventFields: nil,
|
||||
EventFormat: "client",
|
||||
Presence: DefaultFilterPart(),
|
||||
Room: RoomFilter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
Ephemeral: DefaultFilterPart(),
|
||||
IncludeLeave: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
State: DefaultFilterPart(),
|
||||
Timeline: DefaultFilterPart(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultFilterPart returns the default filter part used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilterPart() FilterPart {
|
||||
return FilterPart{
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
Limit: 20,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
}
|
||||
}
|
||||
3
vendor/github.com/matrix-org/gomatrix/go.mod
generated
vendored
3
vendor/github.com/matrix-org/gomatrix/go.mod
generated
vendored
@@ -1,3 +0,0 @@
|
||||
module github.com/matrix-org/gomatrix
|
||||
|
||||
go 1.12
|
||||
69
vendor/github.com/matrix-org/gomatrix/identifier.go
generated
vendored
69
vendor/github.com/matrix-org/gomatrix/identifier.go
generated
vendored
@@ -1,69 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
// Identifier is the interface for https://matrix.org/docs/spec/client_server/r0.6.0#identifier-types
|
||||
type Identifier interface {
|
||||
// Returns the identifier type
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#identifier-types
|
||||
Type() string
|
||||
}
|
||||
|
||||
// UserIdentifier is the Identifier for https://matrix.org/docs/spec/client_server/r0.6.0#matrix-user-id
|
||||
type UserIdentifier struct {
|
||||
IDType string `json:"type"` // Set by NewUserIdentifer
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
// Type implements the Identifier interface
|
||||
func (i UserIdentifier) Type() string {
|
||||
return "m.id.user"
|
||||
}
|
||||
|
||||
// NewUserIdentifier creates a new UserIdentifier with IDType set to "m.id.user"
|
||||
func NewUserIdentifier(user string) UserIdentifier {
|
||||
return UserIdentifier{
|
||||
IDType: "m.id.user",
|
||||
User: user,
|
||||
}
|
||||
}
|
||||
|
||||
// ThirdpartyIdentifier is the Identifier for https://matrix.org/docs/spec/client_server/r0.6.0#third-party-id
|
||||
type ThirdpartyIdentifier struct {
|
||||
IDType string `json:"type"` // Set by NewThirdpartyIdentifier
|
||||
Medium string `json:"medium"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// Type implements the Identifier interface
|
||||
func (i ThirdpartyIdentifier) Type() string {
|
||||
return "m.id.thirdparty"
|
||||
}
|
||||
|
||||
// NewThirdpartyIdentifier creates a new UserIdentifier with IDType set to "m.id.user"
|
||||
func NewThirdpartyIdentifier(medium, address string) ThirdpartyIdentifier {
|
||||
return ThirdpartyIdentifier{
|
||||
IDType: "m.id.thirdparty",
|
||||
Medium: medium,
|
||||
Address: address,
|
||||
}
|
||||
}
|
||||
|
||||
// PhoneIdentifier is the Identifier for https://matrix.org/docs/spec/client_server/r0.6.0#phone-number
|
||||
type PhoneIdentifier struct {
|
||||
IDType string `json:"type"` // Set by NewPhoneIdentifier
|
||||
Country string `json:"country"`
|
||||
Phone string `json:"phone"`
|
||||
}
|
||||
|
||||
// Type implements the Identifier interface
|
||||
func (i PhoneIdentifier) Type() string {
|
||||
return "m.id.phone"
|
||||
}
|
||||
|
||||
// NewPhoneIdentifier creates a new UserIdentifier with IDType set to "m.id.user"
|
||||
func NewPhoneIdentifier(country, phone string) PhoneIdentifier {
|
||||
return PhoneIdentifier{
|
||||
IDType: "m.id.phone",
|
||||
Country: country,
|
||||
Phone: phone,
|
||||
}
|
||||
}
|
||||
79
vendor/github.com/matrix-org/gomatrix/requests.go
generated
vendored
79
vendor/github.com/matrix-org/gomatrix/requests.go
generated
vendored
@@ -1,79 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
// ReqRegister is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
||||
type ReqRegister struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
BindEmail bool `json:"bind_email,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
InitialDeviceDisplayName string `json:"initial_device_display_name"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
// ReqLogin is the JSON request for http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-login
|
||||
type ReqLogin struct {
|
||||
Type string `json:"type"`
|
||||
Identifier Identifier `json:"identifier,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Medium string `json:"medium,omitempty"`
|
||||
User string `json:"user,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
DeviceID string `json:"device_id,omitempty"`
|
||||
InitialDeviceDisplayName string `json:"initial_device_display_name,omitempty"`
|
||||
}
|
||||
|
||||
// ReqCreateRoom is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type ReqCreateRoom struct {
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
RoomAliasName string `json:"room_alias_name,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Topic string `json:"topic,omitempty"`
|
||||
Invite []string `json:"invite,omitempty"`
|
||||
Invite3PID []ReqInvite3PID `json:"invite_3pid,omitempty"`
|
||||
CreationContent map[string]interface{} `json:"creation_content,omitempty"`
|
||||
InitialState []Event `json:"initial_state,omitempty"`
|
||||
Preset string `json:"preset,omitempty"`
|
||||
IsDirect bool `json:"is_direct,omitempty"`
|
||||
}
|
||||
|
||||
// ReqRedact is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
||||
type ReqRedact struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// ReqInvite3PID is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#id57
|
||||
// It is also a JSON object used in https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type ReqInvite3PID struct {
|
||||
IDServer string `json:"id_server"`
|
||||
Medium string `json:"medium"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// ReqInviteUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
type ReqInviteUser struct {
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqKickUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
type ReqKickUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqBanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
type ReqBanUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqUnbanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
type ReqUnbanUser struct {
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqTyping is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
type ReqTyping struct {
|
||||
Typing bool `json:"typing"`
|
||||
Timeout int64 `json:"timeout"`
|
||||
}
|
||||
210
vendor/github.com/matrix-org/gomatrix/responses.go
generated
vendored
210
vendor/github.com/matrix-org/gomatrix/responses.go
generated
vendored
@@ -1,210 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
// RespError is the standard JSON error response from Homeservers. It also implements the Golang "error" interface.
|
||||
// See http://matrix.org/docs/spec/client_server/r0.2.0.html#api-standards
|
||||
type RespError struct {
|
||||
ErrCode string `json:"errcode"`
|
||||
Err string `json:"error"`
|
||||
}
|
||||
|
||||
// Error returns the errcode and error message.
|
||||
func (e RespError) Error() string {
|
||||
return e.ErrCode + ": " + e.Err
|
||||
}
|
||||
|
||||
// RespCreateFilter is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
|
||||
type RespCreateFilter struct {
|
||||
FilterID string `json:"filter_id"`
|
||||
}
|
||||
|
||||
// RespVersions is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions
|
||||
type RespVersions struct {
|
||||
Versions []string `json:"versions"`
|
||||
}
|
||||
|
||||
// RespPublicRooms is the JSON response for http://matrix.org/speculator/spec/HEAD/client_server/unstable.html#get-matrix-client-unstable-publicrooms
|
||||
type RespPublicRooms struct {
|
||||
TotalRoomCountEstimate int `json:"total_room_count_estimate"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
NextBatch string `json:"next_batch"`
|
||||
Chunk []PublicRoom `json:"chunk"`
|
||||
}
|
||||
|
||||
// RespJoinRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-join
|
||||
type RespJoinRoom struct {
|
||||
RoomID string `json:"room_id"`
|
||||
}
|
||||
|
||||
// RespLeaveRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
|
||||
type RespLeaveRoom struct{}
|
||||
|
||||
// RespForgetRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
|
||||
type RespForgetRoom struct{}
|
||||
|
||||
// RespInviteUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
type RespInviteUser struct{}
|
||||
|
||||
// RespKickUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
type RespKickUser struct{}
|
||||
|
||||
// RespBanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
type RespBanUser struct{}
|
||||
|
||||
// RespUnbanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
type RespUnbanUser struct{}
|
||||
|
||||
// RespTyping is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
type RespTyping struct{}
|
||||
|
||||
// RespJoinedRooms is the JSON response for TODO-SPEC https://github.com/matrix-org/synapse/pull/1680
|
||||
type RespJoinedRooms struct {
|
||||
JoinedRooms []string `json:"joined_rooms"`
|
||||
}
|
||||
|
||||
// RespJoinedMembers is the JSON response for TODO-SPEC https://github.com/matrix-org/synapse/pull/1680
|
||||
type RespJoinedMembers struct {
|
||||
Joined map[string]struct {
|
||||
DisplayName *string `json:"display_name"`
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
} `json:"joined"`
|
||||
}
|
||||
|
||||
// RespMessages is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
|
||||
type RespMessages struct {
|
||||
Start string `json:"start"`
|
||||
Chunk []Event `json:"chunk"`
|
||||
End string `json:"end"`
|
||||
}
|
||||
|
||||
// RespSendEvent is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
|
||||
type RespSendEvent struct {
|
||||
EventID string `json:"event_id"`
|
||||
}
|
||||
|
||||
// RespMediaUpload is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
|
||||
type RespMediaUpload struct {
|
||||
ContentURI string `json:"content_uri"`
|
||||
}
|
||||
|
||||
// RespUserInteractive is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#user-interactive-authentication-api
|
||||
type RespUserInteractive struct {
|
||||
Flows []struct {
|
||||
Stages []string `json:"stages"`
|
||||
} `json:"flows"`
|
||||
Params map[string]interface{} `json:"params"`
|
||||
Session string `json:"session"`
|
||||
Completed []string `json:"completed"`
|
||||
ErrCode string `json:"errcode"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// HasSingleStageFlow returns true if there exists at least 1 Flow with a single stage of stageName.
|
||||
func (r RespUserInteractive) HasSingleStageFlow(stageName string) bool {
|
||||
for _, f := range r.Flows {
|
||||
if len(f.Stages) == 1 && f.Stages[0] == stageName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RespUserDisplayName is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
|
||||
type RespUserDisplayName struct {
|
||||
DisplayName string `json:"displayname"`
|
||||
}
|
||||
|
||||
// RespUserStatus is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-presence-userid-status
|
||||
type RespUserStatus struct {
|
||||
Presence string `json:"presence"`
|
||||
StatusMsg string `json:"status_msg"`
|
||||
LastActiveAgo int `json:"last_active_ago"`
|
||||
CurrentlyActive bool `json:"currently_active"`
|
||||
}
|
||||
|
||||
// RespRegister is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
||||
type RespRegister struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DeviceID string `json:"device_id"`
|
||||
HomeServer string `json:"home_server"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
|
||||
// RespLogin is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-login
|
||||
type RespLogin struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DeviceID string `json:"device_id"`
|
||||
HomeServer string `json:"home_server"`
|
||||
UserID string `json:"user_id"`
|
||||
WellKnown DiscoveryInformation `json:"well_known"`
|
||||
}
|
||||
|
||||
// DiscoveryInformation is the JSON Response for https://matrix.org/docs/spec/client_server/r0.6.0#get-well-known-matrix-client and a part of the JSON Response for https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-login
|
||||
type DiscoveryInformation struct {
|
||||
Homeserver struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
} `json:"m.homeserver"`
|
||||
IdentityServer struct {
|
||||
BaseURL string `json:"base_url"`
|
||||
} `json:"m.identitiy_server"`
|
||||
}
|
||||
|
||||
// RespLogout is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-logout
|
||||
type RespLogout struct{}
|
||||
|
||||
// RespLogoutAll is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.0#post-matrix-client-r0-logout-all
|
||||
type RespLogoutAll struct{}
|
||||
|
||||
// RespCreateRoom is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type RespCreateRoom struct {
|
||||
RoomID string `json:"room_id"`
|
||||
}
|
||||
|
||||
// RespSync is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-sync
|
||||
type RespSync struct {
|
||||
NextBatch string `json:"next_batch"`
|
||||
AccountData struct {
|
||||
Events []Event `json:"events"`
|
||||
} `json:"account_data"`
|
||||
Presence struct {
|
||||
Events []Event `json:"events"`
|
||||
} `json:"presence"`
|
||||
Rooms struct {
|
||||
Leave map[string]struct {
|
||||
State struct {
|
||||
Events []Event `json:"events"`
|
||||
} `json:"state"`
|
||||
Timeline struct {
|
||||
Events []Event `json:"events"`
|
||||
Limited bool `json:"limited"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
} `json:"timeline"`
|
||||
} `json:"leave"`
|
||||
Join map[string]struct {
|
||||
State struct {
|
||||
Events []Event `json:"events"`
|
||||
} `json:"state"`
|
||||
Timeline struct {
|
||||
Events []Event `json:"events"`
|
||||
Limited bool `json:"limited"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
} `json:"timeline"`
|
||||
Ephemeral struct {
|
||||
Events []Event `json:"events"`
|
||||
} `json:"ephemeral"`
|
||||
} `json:"join"`
|
||||
Invite map[string]struct {
|
||||
State struct {
|
||||
Events []Event
|
||||
} `json:"invite_state"`
|
||||
} `json:"invite"`
|
||||
} `json:"rooms"`
|
||||
}
|
||||
|
||||
// RespTurnServer is the JSON response from a Turn Server
|
||||
type RespTurnServer struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
TTL int `json:"ttl"`
|
||||
URIs []string `json:"uris"`
|
||||
}
|
||||
63
vendor/github.com/matrix-org/gomatrix/room.go
generated
vendored
63
vendor/github.com/matrix-org/gomatrix/room.go
generated
vendored
@@ -1,63 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
// Room represents a single Matrix room.
|
||||
type Room struct {
|
||||
ID string
|
||||
State map[string]map[string]*Event
|
||||
}
|
||||
|
||||
// PublicRoom represents the information about a public room obtainable from the room directory
|
||||
type PublicRoom struct {
|
||||
CanonicalAlias string `json:"canonical_alias"`
|
||||
Name string `json:"name"`
|
||||
WorldReadable bool `json:"world_readable"`
|
||||
Topic string `json:"topic"`
|
||||
NumJoinedMembers int `json:"num_joined_members"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
RoomID string `json:"room_id"`
|
||||
GuestCanJoin bool `json:"guest_can_join"`
|
||||
Aliases []string `json:"aliases"`
|
||||
}
|
||||
|
||||
// UpdateState updates the room's current state with the given Event. This will clobber events based
|
||||
// on the type/state_key combination.
|
||||
func (room Room) UpdateState(event *Event) {
|
||||
_, exists := room.State[event.Type]
|
||||
if !exists {
|
||||
room.State[event.Type] = make(map[string]*Event)
|
||||
}
|
||||
room.State[event.Type][*event.StateKey] = event
|
||||
}
|
||||
|
||||
// GetStateEvent returns the state event for the given type/state_key combo, or nil.
|
||||
func (room Room) GetStateEvent(eventType string, stateKey string) *Event {
|
||||
stateEventMap := room.State[eventType]
|
||||
event := stateEventMap[stateKey]
|
||||
return event
|
||||
}
|
||||
|
||||
// GetMembershipState returns the membership state of the given user ID in this room. If there is
|
||||
// no entry for this member, 'leave' is returned for consistency with left users.
|
||||
func (room Room) GetMembershipState(userID string) string {
|
||||
state := "leave"
|
||||
event := room.GetStateEvent("m.room.member", userID)
|
||||
if event != nil {
|
||||
membershipState, found := event.Content["membership"]
|
||||
if found {
|
||||
mState, isString := membershipState.(string)
|
||||
if isString {
|
||||
state = mState
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// NewRoom creates a new Room with the given ID
|
||||
func NewRoom(roomID string) *Room {
|
||||
// Init the State map and return a pointer to the Room
|
||||
return &Room{
|
||||
ID: roomID,
|
||||
State: make(map[string]map[string]*Event),
|
||||
}
|
||||
}
|
||||
65
vendor/github.com/matrix-org/gomatrix/store.go
generated
vendored
65
vendor/github.com/matrix-org/gomatrix/store.go
generated
vendored
@@ -1,65 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
// Storer is an interface which must be satisfied to store client data.
|
||||
//
|
||||
// You can either write a struct which persists this data to disk, or you can use the
|
||||
// provided "InMemoryStore" which just keeps data around in-memory which is lost on
|
||||
// restarts.
|
||||
type Storer interface {
|
||||
SaveFilterID(userID, filterID string)
|
||||
LoadFilterID(userID string) string
|
||||
SaveNextBatch(userID, nextBatchToken string)
|
||||
LoadNextBatch(userID string) string
|
||||
SaveRoom(room *Room)
|
||||
LoadRoom(roomID string) *Room
|
||||
}
|
||||
|
||||
// InMemoryStore implements the Storer interface.
|
||||
//
|
||||
// Everything is persisted in-memory as maps. It is not safe to load/save filter IDs
|
||||
// or next batch tokens on any goroutine other than the syncing goroutine: the one
|
||||
// which called Client.Sync().
|
||||
type InMemoryStore struct {
|
||||
Filters map[string]string
|
||||
NextBatch map[string]string
|
||||
Rooms map[string]*Room
|
||||
}
|
||||
|
||||
// SaveFilterID to memory.
|
||||
func (s *InMemoryStore) SaveFilterID(userID, filterID string) {
|
||||
s.Filters[userID] = filterID
|
||||
}
|
||||
|
||||
// LoadFilterID from memory.
|
||||
func (s *InMemoryStore) LoadFilterID(userID string) string {
|
||||
return s.Filters[userID]
|
||||
}
|
||||
|
||||
// SaveNextBatch to memory.
|
||||
func (s *InMemoryStore) SaveNextBatch(userID, nextBatchToken string) {
|
||||
s.NextBatch[userID] = nextBatchToken
|
||||
}
|
||||
|
||||
// LoadNextBatch from memory.
|
||||
func (s *InMemoryStore) LoadNextBatch(userID string) string {
|
||||
return s.NextBatch[userID]
|
||||
}
|
||||
|
||||
// SaveRoom to memory.
|
||||
func (s *InMemoryStore) SaveRoom(room *Room) {
|
||||
s.Rooms[room.ID] = room
|
||||
}
|
||||
|
||||
// LoadRoom from memory.
|
||||
func (s *InMemoryStore) LoadRoom(roomID string) *Room {
|
||||
return s.Rooms[roomID]
|
||||
}
|
||||
|
||||
// NewInMemoryStore constructs a new InMemoryStore.
|
||||
func NewInMemoryStore() *InMemoryStore {
|
||||
return &InMemoryStore{
|
||||
Filters: make(map[string]string),
|
||||
NextBatch: make(map[string]string),
|
||||
Rooms: make(map[string]*Room),
|
||||
}
|
||||
}
|
||||
168
vendor/github.com/matrix-org/gomatrix/sync.go
generated
vendored
168
vendor/github.com/matrix-org/gomatrix/sync.go
generated
vendored
@@ -1,168 +0,0 @@
|
||||
package gomatrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Syncer represents an interface that must be satisfied in order to do /sync requests on a client.
|
||||
type Syncer interface {
|
||||
// Process the /sync response. The since parameter is the since= value that was used to produce the response.
|
||||
// This is useful for detecting the very first sync (since=""). If an error is return, Syncing will be stopped
|
||||
// permanently.
|
||||
ProcessResponse(resp *RespSync, since string) error
|
||||
// OnFailedSync returns either the time to wait before retrying or an error to stop syncing permanently.
|
||||
OnFailedSync(res *RespSync, err error) (time.Duration, error)
|
||||
// GetFilterJSON for the given user ID. NOT the filter ID.
|
||||
GetFilterJSON(userID string) json.RawMessage
|
||||
}
|
||||
|
||||
// DefaultSyncer is the default syncing implementation. You can either write your own syncer, or selectively
|
||||
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
|
||||
// pattern to notify callers about incoming events. See DefaultSyncer.OnEventType for more information.
|
||||
type DefaultSyncer struct {
|
||||
UserID string
|
||||
Store Storer
|
||||
listeners map[string][]OnEventListener // event type to listeners array
|
||||
}
|
||||
|
||||
// OnEventListener can be used with DefaultSyncer.OnEventType to be informed of incoming events.
|
||||
type OnEventListener func(*Event)
|
||||
|
||||
// NewDefaultSyncer returns an instantiated DefaultSyncer
|
||||
func NewDefaultSyncer(userID string, store Storer) *DefaultSyncer {
|
||||
return &DefaultSyncer{
|
||||
UserID: userID,
|
||||
Store: store,
|
||||
listeners: make(map[string][]OnEventListener),
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessResponse processes the /sync response in a way suitable for bots. "Suitable for bots" means a stream of
|
||||
// unrepeating events. Returns a fatal error if a listener panics.
|
||||
func (s *DefaultSyncer) ProcessResponse(res *RespSync, since string) (err error) {
|
||||
if !s.shouldProcessResponse(res, since) {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("ProcessResponse panicked! userID=%s since=%s panic=%s\n%s", s.UserID, since, r, debug.Stack())
|
||||
}
|
||||
}()
|
||||
|
||||
for roomID, roomData := range res.Rooms.Join {
|
||||
room := s.getOrCreateRoom(roomID)
|
||||
for _, event := range roomData.State.Events {
|
||||
event.RoomID = roomID
|
||||
room.UpdateState(&event)
|
||||
s.notifyListeners(&event)
|
||||
}
|
||||
for _, event := range roomData.Timeline.Events {
|
||||
event.RoomID = roomID
|
||||
s.notifyListeners(&event)
|
||||
}
|
||||
for _, event := range roomData.Ephemeral.Events {
|
||||
event.RoomID = roomID
|
||||
s.notifyListeners(&event)
|
||||
}
|
||||
}
|
||||
for roomID, roomData := range res.Rooms.Invite {
|
||||
room := s.getOrCreateRoom(roomID)
|
||||
for _, event := range roomData.State.Events {
|
||||
event.RoomID = roomID
|
||||
room.UpdateState(&event)
|
||||
s.notifyListeners(&event)
|
||||
}
|
||||
}
|
||||
for roomID, roomData := range res.Rooms.Leave {
|
||||
room := s.getOrCreateRoom(roomID)
|
||||
for _, event := range roomData.Timeline.Events {
|
||||
if event.StateKey != nil {
|
||||
event.RoomID = roomID
|
||||
room.UpdateState(&event)
|
||||
s.notifyListeners(&event)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OnEventType allows callers to be notified when there are new events for the given event type.
|
||||
// There are no duplicate checks.
|
||||
func (s *DefaultSyncer) OnEventType(eventType string, callback OnEventListener) {
|
||||
_, exists := s.listeners[eventType]
|
||||
if !exists {
|
||||
s.listeners[eventType] = []OnEventListener{}
|
||||
}
|
||||
s.listeners[eventType] = append(s.listeners[eventType], callback)
|
||||
}
|
||||
|
||||
// shouldProcessResponse returns true if the response should be processed. May modify the response to remove
|
||||
// stuff that shouldn't be processed.
|
||||
func (s *DefaultSyncer) shouldProcessResponse(resp *RespSync, since string) bool {
|
||||
if since == "" {
|
||||
return false
|
||||
}
|
||||
// This is a horrible hack because /sync will return the most recent messages for a room
|
||||
// as soon as you /join it. We do NOT want to process those events in that particular room
|
||||
// because they may have already been processed (if you toggle the bot in/out of the room).
|
||||
//
|
||||
// Work around this by inspecting each room's timeline and seeing if an m.room.member event for us
|
||||
// exists and is "join" and then discard processing that room entirely if so.
|
||||
// TODO: We probably want to process messages from after the last join event in the timeline.
|
||||
for roomID, roomData := range resp.Rooms.Join {
|
||||
for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
|
||||
e := roomData.Timeline.Events[i]
|
||||
if e.Type == "m.room.member" && e.StateKey != nil && *e.StateKey == s.UserID {
|
||||
m := e.Content["membership"]
|
||||
mship, ok := m.(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if mship == "join" {
|
||||
_, ok := resp.Rooms.Join[roomID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
delete(resp.Rooms.Join, roomID) // don't re-process messages
|
||||
delete(resp.Rooms.Invite, roomID) // don't re-process invites
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// getOrCreateRoom must only be called by the Sync() goroutine which calls ProcessResponse()
|
||||
func (s *DefaultSyncer) getOrCreateRoom(roomID string) *Room {
|
||||
room := s.Store.LoadRoom(roomID)
|
||||
if room == nil { // create a new Room
|
||||
room = NewRoom(roomID)
|
||||
s.Store.SaveRoom(room)
|
||||
}
|
||||
return room
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) notifyListeners(event *Event) {
|
||||
listeners, exists := s.listeners[event.Type]
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
for _, fn := range listeners {
|
||||
fn(event)
|
||||
}
|
||||
}
|
||||
|
||||
// OnFailedSync always returns a 10 second wait period between failed /syncs, never a fatal error.
|
||||
func (s *DefaultSyncer) OnFailedSync(res *RespSync, err error) (time.Duration, error) {
|
||||
return 10 * time.Second, nil
|
||||
}
|
||||
|
||||
// GetFilterJSON returns a filter with a timeline limit of 50.
|
||||
func (s *DefaultSyncer) GetFilterJSON(userID string) json.RawMessage {
|
||||
return json.RawMessage(`{"room":{"timeline":{"limit":50}}}`)
|
||||
}
|
||||
26
vendor/github.com/matrix-org/gomatrix/tags.go
generated
vendored
26
vendor/github.com/matrix-org/gomatrix/tags.go
generated
vendored
@@ -1,26 +0,0 @@
|
||||
// Copyright 2019 Sumukha PK
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gomatrix
|
||||
|
||||
// TagContent contains the data for an m.tag message type
|
||||
// https://matrix.org/docs/spec/client_server/r0.4.0.html#m-tag
|
||||
type TagContent struct {
|
||||
Tags map[string]TagProperties `json:"tags"`
|
||||
}
|
||||
|
||||
// TagProperties contains the properties of a Tag
|
||||
type TagProperties struct {
|
||||
Order float32 `json:"order,omitempty"` // Empty values must be neglected
|
||||
}
|
||||
77
vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
Normal file
77
vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
|
||||
2898 / PKCS #5 v2.0.
|
||||
|
||||
A key derivation function is useful when encrypting data based on a password
|
||||
or any other not-fully-random data. It uses a pseudorandom function to derive
|
||||
a secure encryption key based on the password.
|
||||
|
||||
While v2.0 of the standard defines only one pseudorandom function to use,
|
||||
HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
|
||||
Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
|
||||
choose, you can pass the `New` functions from the different SHA packages to
|
||||
pbkdf2.Key.
|
||||
*/
|
||||
package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Key derives a key from the password, salt and iteration count, returning a
|
||||
// []byte of length keylen that can be used as cryptographic key. The key is
|
||||
// derived based on the method described as PBKDF2 with the HMAC variant using
|
||||
// the supplied hash function.
|
||||
//
|
||||
// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
|
||||
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||
// doing:
|
||||
//
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
//
|
||||
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||
// RFC.
|
||||
//
|
||||
// Using a higher iteration count will increase the cost of an exhaustive
|
||||
// search but will also make derivation proportionally slower.
|
||||
func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||
prf := hmac.New(h, password)
|
||||
hashLen := prf.Size()
|
||||
numBlocks := (keyLen + hashLen - 1) / hashLen
|
||||
|
||||
var buf [4]byte
|
||||
dk := make([]byte, 0, numBlocks*hashLen)
|
||||
U := make([]byte, hashLen)
|
||||
for block := 1; block <= numBlocks; block++ {
|
||||
// N.B.: || means concatenation, ^ means XOR
|
||||
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||
// U_1 = PRF(password, salt || uint(i))
|
||||
prf.Reset()
|
||||
prf.Write(salt)
|
||||
buf[0] = byte(block >> 24)
|
||||
buf[1] = byte(block >> 16)
|
||||
buf[2] = byte(block >> 8)
|
||||
buf[3] = byte(block)
|
||||
prf.Write(buf[:4])
|
||||
dk = prf.Sum(dk)
|
||||
T := dk[len(dk)-hashLen:]
|
||||
copy(U, T)
|
||||
|
||||
// U_n = PRF(password, U_(n-1))
|
||||
for n := 2; n <= iter; n++ {
|
||||
prf.Reset()
|
||||
prf.Write(U)
|
||||
U = U[:0]
|
||||
U = prf.Sum(U)
|
||||
for x := range U {
|
||||
T[x] ^= U[x]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dk[:keyLen]
|
||||
}
|
||||
2
vendor/maunium.net/go/mautrix/.gitignore
generated
vendored
Normal file
2
vendor/maunium.net/go/mautrix/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
374
vendor/maunium.net/go/mautrix/LICENSE
generated
vendored
Normal file
374
vendor/maunium.net/go/mautrix/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
24
vendor/maunium.net/go/mautrix/README.md
generated
vendored
Normal file
24
vendor/maunium.net/go/mautrix/README.md
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# mautrix-go
|
||||
[](https://godoc.org/maunium.net/go/mautrix)
|
||||
|
||||
A Golang Matrix framework. Used by [gomuks](https://matrix.org/docs/projects/client/gomuks),
|
||||
[go-neb](https://github.com/matrix-org/go-neb), [mautrix-whatsapp](https://github.com/tulir/mautrix-whatsapp)
|
||||
and others.
|
||||
|
||||
Matrix room: [`#maunium:maunium.net`](https://matrix.to/#/#maunium:maunium.net)
|
||||
|
||||
This project is based on [matrix-org/gomatrix](https://github.com/matrix-org/gomatrix).
|
||||
The original project is licensed under [Apache 2.0](https://github.com/matrix-org/gomatrix/blob/master/LICENSE).
|
||||
|
||||
In addition to the basic client API features the original project has, this framework also has:
|
||||
|
||||
* Appservice support (Intent API like mautrix-python, room state storage, etc)
|
||||
* End-to-end encryption support (incl. interactive SAS verification)
|
||||
* Structs for parsing event content
|
||||
* Helpers for parsing and generating Matrix HTML
|
||||
* Helpers for handling push rules
|
||||
|
||||
This project contains modules that are licensed under Apache 2.0:
|
||||
|
||||
* [maunium.net/go/mautrix/crypto/canonicaljson](crypto/canonicaljson)
|
||||
* [maunium.net/go/mautrix/crypto/olm](crypto/olm)
|
||||
1344
vendor/maunium.net/go/mautrix/client.go
generated
vendored
Normal file
1344
vendor/maunium.net/go/mautrix/client.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
171
vendor/maunium.net/go/mautrix/crypto/attachment/attachments.go
generated
vendored
Normal file
171
vendor/maunium.net/go/mautrix/crypto/attachment/attachments.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package attachment
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"hash"
|
||||
"io"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
HashMismatch = errors.New("mismatching SHA-256 digest")
|
||||
UnsupportedVersion = errors.New("unsupported Matrix file encryption version")
|
||||
UnsupportedAlgorithm = errors.New("unsupported JWK encryption algorithm")
|
||||
InvalidKey = errors.New("failed to decode key")
|
||||
InvalidInitVector = errors.New("failed to decode initialization vector")
|
||||
ReaderClosed = errors.New("encrypting reader was already closed")
|
||||
)
|
||||
|
||||
var (
|
||||
keyBase64Length = base64.RawURLEncoding.EncodedLen(utils.AESCTRKeyLength)
|
||||
ivBase64Length = base64.RawStdEncoding.EncodedLen(utils.AESCTRIVLength)
|
||||
hashBase64Length = base64.RawStdEncoding.EncodedLen(utils.SHAHashLength)
|
||||
)
|
||||
|
||||
type JSONWebKey struct {
|
||||
Key string `json:"k"`
|
||||
Algorithm string `json:"alg"`
|
||||
Extractable bool `json:"ext"`
|
||||
KeyType string `json:"kty"`
|
||||
KeyOps []string `json:"key_ops"`
|
||||
}
|
||||
|
||||
type EncryptedFileHashes struct {
|
||||
SHA256 string `json:"sha256"`
|
||||
}
|
||||
|
||||
type decodedKeys struct {
|
||||
key [utils.AESCTRKeyLength]byte
|
||||
iv [utils.AESCTRIVLength]byte
|
||||
}
|
||||
|
||||
type EncryptedFile struct {
|
||||
Key JSONWebKey `json:"key"`
|
||||
InitVector string `json:"iv"`
|
||||
Hashes EncryptedFileHashes `json:"hashes"`
|
||||
Version string `json:"v"`
|
||||
|
||||
decoded *decodedKeys `json:"-"`
|
||||
}
|
||||
|
||||
func NewEncryptedFile() *EncryptedFile {
|
||||
key, iv := utils.GenAttachmentA256CTR()
|
||||
return &EncryptedFile{
|
||||
Key: JSONWebKey{
|
||||
Key: base64.RawURLEncoding.EncodeToString(key[:]),
|
||||
Algorithm: "A256CTR",
|
||||
Extractable: true,
|
||||
KeyType: "oct",
|
||||
KeyOps: []string{"encrypt", "decrypt"},
|
||||
},
|
||||
InitVector: base64.RawStdEncoding.EncodeToString(iv[:]),
|
||||
Version: "v2",
|
||||
|
||||
decoded: &decodedKeys{key, iv},
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) decodeKeys() error {
|
||||
if ef.decoded != nil {
|
||||
return nil
|
||||
} else if len(ef.Key.Key) != keyBase64Length {
|
||||
return InvalidKey
|
||||
} else if len(ef.InitVector) != ivBase64Length {
|
||||
return InvalidInitVector
|
||||
}
|
||||
ef.decoded = &decodedKeys{}
|
||||
_, err := base64.RawURLEncoding.Decode(ef.decoded.key[:], []byte(ef.Key.Key))
|
||||
if err != nil {
|
||||
return InvalidKey
|
||||
}
|
||||
_, err = base64.RawStdEncoding.Decode(ef.decoded.iv[:], []byte(ef.InitVector))
|
||||
if err != nil {
|
||||
return InvalidInitVector
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) Encrypt(plaintext []byte) []byte {
|
||||
ef.decodeKeys()
|
||||
ciphertext := utils.XorA256CTR(plaintext, ef.decoded.key, ef.decoded.iv)
|
||||
checksum := sha256.Sum256(ciphertext)
|
||||
ef.Hashes.SHA256 = base64.RawStdEncoding.EncodeToString(checksum[:])
|
||||
return ciphertext
|
||||
}
|
||||
|
||||
// encryptingReader is a variation of cipher.StreamReader that also hashes the content.
|
||||
type encryptingReader struct {
|
||||
stream cipher.Stream
|
||||
hash hash.Hash
|
||||
source io.Reader
|
||||
file *EncryptedFile
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (r *encryptingReader) Read(dst []byte) (n int, err error) {
|
||||
if r.closed {
|
||||
return 0, ReaderClosed
|
||||
}
|
||||
n, err = r.source.Read(dst)
|
||||
r.stream.XORKeyStream(dst[:n], dst[:n])
|
||||
r.hash.Write(dst[:n])
|
||||
return
|
||||
}
|
||||
|
||||
func (r *encryptingReader) Close() (err error) {
|
||||
closer, ok := r.source.(io.ReadCloser)
|
||||
if ok {
|
||||
err = closer.Close()
|
||||
}
|
||||
r.file.Hashes.SHA256 = base64.RawStdEncoding.EncodeToString(r.hash.Sum(nil))
|
||||
r.closed = true
|
||||
return
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) EncryptStream(reader io.Reader) io.ReadCloser {
|
||||
ef.decodeKeys()
|
||||
block, _ := aes.NewCipher(ef.decoded.key[:])
|
||||
return &encryptingReader{
|
||||
stream: cipher.NewCTR(block, ef.decoded.iv[:]),
|
||||
hash: sha256.New(),
|
||||
source: reader,
|
||||
file: ef,
|
||||
}
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) checkHash(ciphertext []byte) bool {
|
||||
if len(ef.Hashes.SHA256) != hashBase64Length {
|
||||
return false
|
||||
}
|
||||
var checksum [utils.SHAHashLength]byte
|
||||
_, err := base64.RawStdEncoding.Decode(checksum[:], []byte(ef.Hashes.SHA256))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return checksum == sha256.Sum256(ciphertext)
|
||||
}
|
||||
|
||||
func (ef *EncryptedFile) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
if ef.Version != "v2" {
|
||||
return nil, UnsupportedVersion
|
||||
} else if ef.Key.Algorithm != "A256CTR" {
|
||||
return nil, UnsupportedAlgorithm
|
||||
} else if !ef.checkHash(ciphertext) {
|
||||
return nil, HashMismatch
|
||||
} else if err := ef.decodeKeys(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return utils.XorA256CTR(ciphertext, ef.decoded.key, ef.decoded.iv), nil
|
||||
}
|
||||
}
|
||||
133
vendor/maunium.net/go/mautrix/crypto/utils/utils.go
generated
vendored
Normal file
133
vendor/maunium.net/go/mautrix/crypto/utils/utils.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2020 Nikos Filippakis
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/btcsuite/btcutil/base58"
|
||||
"golang.org/x/crypto/hkdf"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
// AESCTRKeyLength is the length of the AES256-CTR key used.
|
||||
AESCTRKeyLength = 32
|
||||
// AESCTRIVLength is the length of the AES256-CTR IV used.
|
||||
AESCTRIVLength = 16
|
||||
// HMACKeyLength is the length of the HMAC key used.
|
||||
HMACKeyLength = 32
|
||||
// SHAHashLength is the length of the SHA hash used.
|
||||
SHAHashLength = 32
|
||||
)
|
||||
|
||||
// XorA256CTR encrypts the input with the keystream generated by the AES256-CTR algorithm with the given arguments.
|
||||
func XorA256CTR(source []byte, key [AESCTRKeyLength]byte, iv [AESCTRIVLength]byte) []byte {
|
||||
block, _ := aes.NewCipher(key[:])
|
||||
result := make([]byte, len(source))
|
||||
cipher.NewCTR(block, iv[:]).XORKeyStream(result, source)
|
||||
return result
|
||||
}
|
||||
|
||||
// GenAttachmentA256CTR generates a new random AES256-CTR key and IV suitable for encrypting attachments.
|
||||
func GenAttachmentA256CTR() (key [AESCTRKeyLength]byte, iv [AESCTRIVLength]byte) {
|
||||
_, err := rand.Read(key[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The last 8 bytes of the IV act as the counter in AES-CTR, which means they're left empty here
|
||||
_, err = rand.Read(iv[:8])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GenA256CTRIV generates a random IV for AES256-CTR with the last bit set to zero.
|
||||
func GenA256CTRIV() (iv [AESCTRIVLength]byte) {
|
||||
_, err := rand.Read(iv[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
iv[8] &= 0x7F
|
||||
return
|
||||
}
|
||||
|
||||
// DeriveKeysSHA256 derives an AES and a HMAC key from the given recovery key.
|
||||
func DeriveKeysSHA256(key []byte, name string) ([AESCTRKeyLength]byte, [HMACKeyLength]byte) {
|
||||
var zeroBytes [32]byte
|
||||
|
||||
derivedHkdf := hkdf.New(sha256.New, key[:], zeroBytes[:], []byte(name))
|
||||
|
||||
var aesKey [AESCTRKeyLength]byte
|
||||
var hmacKey [HMACKeyLength]byte
|
||||
derivedHkdf.Read(aesKey[:])
|
||||
derivedHkdf.Read(hmacKey[:])
|
||||
|
||||
return aesKey, hmacKey
|
||||
}
|
||||
|
||||
// PBKDF2SHA512 generates a key of the given bit-length using the given passphrase, salt and iteration count.
|
||||
func PBKDF2SHA512(password []byte, salt []byte, iters int, keyLenBits int) []byte {
|
||||
return pbkdf2.Key(password, salt, iters, keyLenBits/8, sha512.New)
|
||||
}
|
||||
|
||||
// DecodeBase58RecoveryKey recovers the secret storage from a recovery key.
|
||||
func DecodeBase58RecoveryKey(recoveryKey string) []byte {
|
||||
noSpaces := strings.ReplaceAll(recoveryKey, " ", "")
|
||||
decoded := base58.Decode(noSpaces)
|
||||
if len(decoded) != AESCTRKeyLength+3 { // AESCTRKeyLength bytes key and 3 bytes prefix / parity
|
||||
return nil
|
||||
}
|
||||
var parity byte
|
||||
for _, b := range decoded[:34] {
|
||||
parity ^= b
|
||||
}
|
||||
if parity != decoded[34] || decoded[0] != 0x8B || decoded[1] != 1 {
|
||||
return nil
|
||||
}
|
||||
return decoded[2:34]
|
||||
}
|
||||
|
||||
// EncodeBase58RecoveryKey recovers the secret storage from a recovery key.
|
||||
func EncodeBase58RecoveryKey(key []byte) string {
|
||||
var inputBytes [35]byte
|
||||
copy(inputBytes[2:34], key[:])
|
||||
inputBytes[0] = 0x8B
|
||||
inputBytes[1] = 1
|
||||
|
||||
var parity byte
|
||||
for _, b := range inputBytes[:34] {
|
||||
parity ^= b
|
||||
}
|
||||
inputBytes[34] = parity
|
||||
recoveryKey := base58.Encode(inputBytes[:])
|
||||
|
||||
var spacedKey string
|
||||
for i, c := range recoveryKey {
|
||||
if i > 0 && i%4 == 0 {
|
||||
spacedKey += " "
|
||||
}
|
||||
spacedKey += string(c)
|
||||
}
|
||||
return spacedKey
|
||||
}
|
||||
|
||||
// HMACSHA256B64 calculates the base64 of the SHA256 hmac of the input with the given key.
|
||||
func HMACSHA256B64(input []byte, hmacKey [HMACKeyLength]byte) string {
|
||||
h := hmac.New(sha256.New, hmacKey[:])
|
||||
h.Write(input)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
144
vendor/maunium.net/go/mautrix/error.go
generated
vendored
Normal file
144
vendor/maunium.net/go/mautrix/error.go
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Common error codes from https://matrix.org/docs/spec/client_server/latest#api-standards
|
||||
//
|
||||
// Can be used with errors.Is() to check the response code without casting the error:
|
||||
// err := client.Sync()
|
||||
// if errors.Is(err, MUnknownToken) {
|
||||
// // logout
|
||||
// }
|
||||
var (
|
||||
// Forbidden access, e.g. joining a room without permission, failed login.
|
||||
MForbidden = RespError{ErrCode: "M_FORBIDDEN"}
|
||||
// The access token specified was not recognised.
|
||||
MUnknownToken = RespError{ErrCode: "M_UNKNOWN_TOKEN"}
|
||||
// No access token was specified for the request.
|
||||
MMissingToken = RespError{ErrCode: "M_MISSING_TOKEN"}
|
||||
// Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys.
|
||||
MBadJSON = RespError{ErrCode: "M_BAD_JSON"}
|
||||
// Request did not contain valid JSON.
|
||||
MNotJSON = RespError{ErrCode: "M_NOT_JSON"}
|
||||
// No resource was found for this request.
|
||||
MNotFound = RespError{ErrCode: "M_NOT_FOUND"}
|
||||
// Too many requests have been sent in a short period of time. Wait a while then try again.
|
||||
MLimitExceeded = RespError{ErrCode: "M_LIMIT_EXCEEDED"}
|
||||
// The user ID associated with the request has been deactivated.
|
||||
// Typically for endpoints that prove authentication, such as /login.
|
||||
MUserDeactivated = RespError{ErrCode: "M_USER_DEACTIVATED"}
|
||||
// Encountered when trying to register a user ID which has been taken.
|
||||
MUserInUse = RespError{ErrCode: "M_USER_IN_USE"}
|
||||
// Encountered when trying to register a user ID which is not valid.
|
||||
MInvalidUsername = RespError{ErrCode: "M_INVALID_USERNAME"}
|
||||
// Sent when the room alias given to the createRoom API is already in use.
|
||||
MRoomInUse = RespError{ErrCode: "M_ROOM_IN_USE"}
|
||||
// The state change requested cannot be performed, such as attempting to unban a user who is not banned.
|
||||
MBadState = RespError{ErrCode: "M_BAD_STATE"}
|
||||
// The request or entity was too large.
|
||||
MTooLarge = RespError{ErrCode: "M_TOO_LARGE"}
|
||||
// The resource being requested is reserved by an application service, or the application service making the request has not created the resource.
|
||||
MExclusive = RespError{ErrCode: "M_EXCLUSIVE"}
|
||||
// The client's request to create a room used a room version that the server does not support.
|
||||
MUnsupportedRoomVersion = RespError{ErrCode: "M_UNSUPPORTED_ROOM_VERSION"}
|
||||
// The client attempted to join a room that has a version the server does not support.
|
||||
// Inspect the room_version property of the error response for the room's version.
|
||||
MIncompatibleRoomVersion = RespError{ErrCode: "M_INCOMPATIBLE_ROOM_VERSION"}
|
||||
)
|
||||
|
||||
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
|
||||
type HTTPError struct {
|
||||
Request *http.Request
|
||||
Response *http.Response
|
||||
ResponseBody string
|
||||
|
||||
WrappedError error
|
||||
RespError *RespError
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e HTTPError) Is(err error) bool {
|
||||
return (e.RespError != nil && errors.Is(e.RespError, err)) || (e.WrappedError != nil && errors.Is(e.WrappedError, err))
|
||||
}
|
||||
|
||||
func (e HTTPError) IsStatus(code int) bool {
|
||||
return e.Response != nil && e.Response.StatusCode == code
|
||||
}
|
||||
|
||||
func (e HTTPError) Error() string {
|
||||
if e.WrappedError != nil {
|
||||
return fmt.Sprintf("%s: %v", e.Message, e.WrappedError)
|
||||
} else if e.RespError != nil {
|
||||
return fmt.Sprintf("failed to %s %s: %s (HTTP %d): %s", e.Request.Method, e.Request.URL.Path,
|
||||
e.RespError.ErrCode, e.Response.StatusCode, e.RespError.Err)
|
||||
} else {
|
||||
msg := fmt.Sprintf("failed to %s %s: %s", e.Request.Method, e.Request.URL.Path, e.Response.Status)
|
||||
if len(e.ResponseBody) > 0 {
|
||||
msg = fmt.Sprintf("%s\n%s", msg, e.ResponseBody)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
func (e HTTPError) Unwrap() error {
|
||||
if e.WrappedError != nil {
|
||||
return e.WrappedError
|
||||
} else if e.RespError != nil {
|
||||
return *e.RespError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RespError is the standard JSON error response from Homeservers. It also implements the Golang "error" interface.
|
||||
// See http://matrix.org/docs/spec/client_server/r0.6.1.html#api-standards
|
||||
type RespError struct {
|
||||
ErrCode string
|
||||
Err string
|
||||
ExtraData map[string]interface{}
|
||||
}
|
||||
|
||||
func (e *RespError) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, &e.ExtraData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.ErrCode, _ = e.ExtraData["errcode"].(string)
|
||||
e.Err, _ = e.ExtraData["error"].(string)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *RespError) MarshalJSON() ([]byte, error) {
|
||||
if e.ExtraData == nil {
|
||||
e.ExtraData = make(map[string]interface{})
|
||||
}
|
||||
e.ExtraData["errcode"] = e.ErrCode
|
||||
e.ExtraData["error"] = e.Err
|
||||
return json.Marshal(&e.ExtraData)
|
||||
}
|
||||
|
||||
// Error returns the errcode and error message.
|
||||
func (e RespError) Error() string {
|
||||
return e.ErrCode + ": " + e.Err
|
||||
}
|
||||
|
||||
func (e RespError) Is(err error) bool {
|
||||
e2, ok := err.(RespError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if e.ErrCode == "M_UNKNOWN" && e2.ErrCode == "M_UNKNOWN" {
|
||||
return e.Err == e2.Err
|
||||
}
|
||||
return e2.ErrCode == e.ErrCode
|
||||
}
|
||||
45
vendor/maunium.net/go/mautrix/event/accountdata.go
generated
vendored
Normal file
45
vendor/maunium.net/go/mautrix/event/accountdata.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// TagEventContent represents the content of a m.tag room account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-tag
|
||||
type TagEventContent struct {
|
||||
Tags Tags `json:"tags"`
|
||||
}
|
||||
|
||||
type Tags map[string]Tag
|
||||
|
||||
type Tag struct {
|
||||
Order json.Number `json:"order,omitempty"`
|
||||
}
|
||||
|
||||
// DirectChatsEventContent represents the content of a m.direct account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-direct
|
||||
type DirectChatsEventContent map[id.UserID][]id.RoomID
|
||||
|
||||
// FullyReadEventContent represents the content of a m.fully_read account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-fully-read
|
||||
type FullyReadEventContent struct {
|
||||
EventID id.EventID `json:"event_id"`
|
||||
}
|
||||
|
||||
// IgnoredUserListEventContent represents the content of a m.ignored_user_list account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-ignored-user-list
|
||||
type IgnoredUserListEventContent struct {
|
||||
IgnoredUsers map[id.UserID]IgnoredUser `json:"ignored_users"`
|
||||
}
|
||||
|
||||
type IgnoredUser struct {
|
||||
// This is an empty object
|
||||
}
|
||||
457
vendor/maunium.net/go/mautrix/event/content.go
generated
vendored
Normal file
457
vendor/maunium.net/go/mautrix/event/content.go
generated
vendored
Normal file
@@ -0,0 +1,457 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// TypeMap is a mapping from event type to the content struct type.
|
||||
// This is used by Content.ParseRaw() for creating the correct type of struct.
|
||||
var TypeMap = map[Type]reflect.Type{
|
||||
StateMember: reflect.TypeOf(MemberEventContent{}),
|
||||
StatePowerLevels: reflect.TypeOf(PowerLevelsEventContent{}),
|
||||
StateCanonicalAlias: reflect.TypeOf(CanonicalAliasEventContent{}),
|
||||
StateRoomName: reflect.TypeOf(RoomNameEventContent{}),
|
||||
StateRoomAvatar: reflect.TypeOf(RoomAvatarEventContent{}),
|
||||
StateTopic: reflect.TypeOf(TopicEventContent{}),
|
||||
StateTombstone: reflect.TypeOf(TombstoneEventContent{}),
|
||||
StateCreate: reflect.TypeOf(CreateEventContent{}),
|
||||
StateJoinRules: reflect.TypeOf(JoinRulesEventContent{}),
|
||||
StateHistoryVisibility: reflect.TypeOf(HistoryVisibilityEventContent{}),
|
||||
StateGuestAccess: reflect.TypeOf(GuestAccessEventContent{}),
|
||||
StatePinnedEvents: reflect.TypeOf(PinnedEventsEventContent{}),
|
||||
StateEncryption: reflect.TypeOf(EncryptionEventContent{}),
|
||||
|
||||
EventMessage: reflect.TypeOf(MessageEventContent{}),
|
||||
EventSticker: reflect.TypeOf(MessageEventContent{}),
|
||||
EventEncrypted: reflect.TypeOf(EncryptedEventContent{}),
|
||||
EventRedaction: reflect.TypeOf(RedactionEventContent{}),
|
||||
EventReaction: reflect.TypeOf(ReactionEventContent{}),
|
||||
|
||||
AccountDataRoomTags: reflect.TypeOf(TagEventContent{}),
|
||||
AccountDataDirectChats: reflect.TypeOf(DirectChatsEventContent{}),
|
||||
AccountDataFullyRead: reflect.TypeOf(FullyReadEventContent{}),
|
||||
AccountDataIgnoredUserList: reflect.TypeOf(IgnoredUserListEventContent{}),
|
||||
|
||||
EphemeralEventTyping: reflect.TypeOf(TypingEventContent{}),
|
||||
EphemeralEventReceipt: reflect.TypeOf(ReceiptEventContent{}),
|
||||
EphemeralEventPresence: reflect.TypeOf(PresenceEventContent{}),
|
||||
|
||||
InRoomVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
InRoomVerificationReady: reflect.TypeOf(VerificationReadyEventContent{}),
|
||||
InRoomVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
|
||||
InRoomVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
|
||||
InRoomVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
|
||||
InRoomVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
|
||||
ToDeviceRoomKey: reflect.TypeOf(RoomKeyEventContent{}),
|
||||
ToDeviceForwardedRoomKey: reflect.TypeOf(ForwardedRoomKeyEventContent{}),
|
||||
ToDeviceRoomKeyRequest: reflect.TypeOf(RoomKeyRequestEventContent{}),
|
||||
ToDeviceEncrypted: reflect.TypeOf(EncryptedEventContent{}),
|
||||
ToDeviceRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
|
||||
|
||||
ToDeviceVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
|
||||
ToDeviceVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
|
||||
ToDeviceVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
|
||||
ToDeviceVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
|
||||
ToDeviceVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
|
||||
ToDeviceVerificationRequest: reflect.TypeOf(VerificationRequestEventContent{}),
|
||||
|
||||
ToDeviceOrgMatrixRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
|
||||
|
||||
CallInvite: reflect.TypeOf(CallInviteEventContent{}),
|
||||
CallCandidates: reflect.TypeOf(CallCandidatesEventContent{}),
|
||||
CallAnswer: reflect.TypeOf(CallAnswerEventContent{}),
|
||||
CallReject: reflect.TypeOf(CallRejectEventContent{}),
|
||||
CallSelectAnswer: reflect.TypeOf(CallSelectAnswerEventContent{}),
|
||||
CallNegotiate: reflect.TypeOf(CallNegotiateEventContent{}),
|
||||
CallHangup: reflect.TypeOf(CallHangupEventContent{}),
|
||||
}
|
||||
|
||||
// Content stores the content of a Matrix event.
|
||||
//
|
||||
// By default, the content is only parsed into a map[string]interface{}. However, you can call ParseRaw with the
|
||||
// correct event type to parse the content into a nicer struct, which you can then access from Parsed or via the
|
||||
// helper functions.
|
||||
type Content struct {
|
||||
VeryRaw json.RawMessage
|
||||
Raw map[string]interface{}
|
||||
Parsed interface{}
|
||||
}
|
||||
|
||||
type Relatable interface {
|
||||
GetRelatesTo() *RelatesTo
|
||||
OptionalGetRelatesTo() *RelatesTo
|
||||
SetRelatesTo(rel *RelatesTo)
|
||||
}
|
||||
|
||||
func (content *Content) UnmarshalJSON(data []byte) error {
|
||||
content.VeryRaw = data
|
||||
err := json.Unmarshal(data, &content.Raw)
|
||||
return err
|
||||
}
|
||||
|
||||
func (content *Content) MarshalJSON() ([]byte, error) {
|
||||
if content.Raw == nil {
|
||||
if content.Parsed == nil {
|
||||
if content.VeryRaw == nil {
|
||||
return []byte("{}"), nil
|
||||
}
|
||||
return content.VeryRaw, nil
|
||||
}
|
||||
return json.Marshal(content.Parsed)
|
||||
} else if content.Parsed != nil {
|
||||
// TODO this whole thing is incredibly hacky
|
||||
// It needs to produce JSON, where:
|
||||
// * content.Parsed is applied after content.Raw
|
||||
// * MarshalJSON() is respected inside content.Parsed
|
||||
// * Custom field inside nested objects of content.Raw are preserved,
|
||||
// even if content.Parsed contains the higher-level objects.
|
||||
// * content.Raw is not modified
|
||||
|
||||
unparsed, err := json.Marshal(content.Parsed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var rawParsed map[string]interface{}
|
||||
err = json.Unmarshal(unparsed, &rawParsed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
output := make(map[string]interface{})
|
||||
for key, value := range content.Raw {
|
||||
output[key] = value
|
||||
}
|
||||
|
||||
mergeMaps(output, rawParsed)
|
||||
return json.Marshal(output)
|
||||
}
|
||||
return json.Marshal(content.Raw)
|
||||
}
|
||||
|
||||
func IsUnsupportedContentType(err error) bool {
|
||||
return errors.Is(err, UnsupportedContentType)
|
||||
}
|
||||
|
||||
var ContentAlreadyParsed = errors.New("content is already parsed")
|
||||
var UnsupportedContentType = errors.New("unsupported event type")
|
||||
|
||||
func (content *Content) ParseRaw(evtType Type) error {
|
||||
if content.Parsed != nil {
|
||||
return ContentAlreadyParsed
|
||||
}
|
||||
structType, ok := TypeMap[evtType]
|
||||
if !ok {
|
||||
return fmt.Errorf("%w %s", UnsupportedContentType, evtType.Repr())
|
||||
}
|
||||
content.Parsed = reflect.New(structType).Interface()
|
||||
return json.Unmarshal(content.VeryRaw, &content.Parsed)
|
||||
}
|
||||
|
||||
func mergeMaps(into, from map[string]interface{}) {
|
||||
for key, newValue := range from {
|
||||
existingValue, ok := into[key]
|
||||
if !ok {
|
||||
into[key] = newValue
|
||||
continue
|
||||
}
|
||||
existingValueMap, okEx := existingValue.(map[string]interface{})
|
||||
newValueMap, okNew := newValue.(map[string]interface{})
|
||||
if okEx && okNew {
|
||||
mergeMaps(existingValueMap, newValueMap)
|
||||
} else {
|
||||
into[key] = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
gob.Register(&MemberEventContent{})
|
||||
gob.Register(&PowerLevelsEventContent{})
|
||||
gob.Register(&CanonicalAliasEventContent{})
|
||||
gob.Register(&EncryptionEventContent{})
|
||||
gob.Register(&RoomNameEventContent{})
|
||||
gob.Register(&RoomAvatarEventContent{})
|
||||
gob.Register(&TopicEventContent{})
|
||||
gob.Register(&TombstoneEventContent{})
|
||||
gob.Register(&CreateEventContent{})
|
||||
gob.Register(&JoinRulesEventContent{})
|
||||
gob.Register(&HistoryVisibilityEventContent{})
|
||||
gob.Register(&GuestAccessEventContent{})
|
||||
gob.Register(&PinnedEventsEventContent{})
|
||||
gob.Register(&MessageEventContent{})
|
||||
gob.Register(&MessageEventContent{})
|
||||
gob.Register(&EncryptedEventContent{})
|
||||
gob.Register(&RedactionEventContent{})
|
||||
gob.Register(&ReactionEventContent{})
|
||||
gob.Register(&TagEventContent{})
|
||||
gob.Register(&DirectChatsEventContent{})
|
||||
gob.Register(&FullyReadEventContent{})
|
||||
gob.Register(&IgnoredUserListEventContent{})
|
||||
gob.Register(&TypingEventContent{})
|
||||
gob.Register(&ReceiptEventContent{})
|
||||
gob.Register(&PresenceEventContent{})
|
||||
gob.Register(&RoomKeyEventContent{})
|
||||
gob.Register(&ForwardedRoomKeyEventContent{})
|
||||
gob.Register(&RoomKeyRequestEventContent{})
|
||||
gob.Register(&RoomKeyWithheldEventContent{})
|
||||
}
|
||||
|
||||
// Helper cast functions below
|
||||
|
||||
func (content *Content) AsMember() *MemberEventContent {
|
||||
casted, ok := content.Parsed.(*MemberEventContent)
|
||||
if !ok {
|
||||
return &MemberEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsPowerLevels() *PowerLevelsEventContent {
|
||||
casted, ok := content.Parsed.(*PowerLevelsEventContent)
|
||||
if !ok {
|
||||
return &PowerLevelsEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCanonicalAlias() *CanonicalAliasEventContent {
|
||||
casted, ok := content.Parsed.(*CanonicalAliasEventContent)
|
||||
if !ok {
|
||||
return &CanonicalAliasEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomName() *RoomNameEventContent {
|
||||
casted, ok := content.Parsed.(*RoomNameEventContent)
|
||||
if !ok {
|
||||
return &RoomNameEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomAvatar() *RoomAvatarEventContent {
|
||||
casted, ok := content.Parsed.(*RoomAvatarEventContent)
|
||||
if !ok {
|
||||
return &RoomAvatarEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTopic() *TopicEventContent {
|
||||
casted, ok := content.Parsed.(*TopicEventContent)
|
||||
if !ok {
|
||||
return &TopicEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTombstone() *TombstoneEventContent {
|
||||
casted, ok := content.Parsed.(*TombstoneEventContent)
|
||||
if !ok {
|
||||
return &TombstoneEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCreate() *CreateEventContent {
|
||||
casted, ok := content.Parsed.(*CreateEventContent)
|
||||
if !ok {
|
||||
return &CreateEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsJoinRules() *JoinRulesEventContent {
|
||||
casted, ok := content.Parsed.(*JoinRulesEventContent)
|
||||
if !ok {
|
||||
return &JoinRulesEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsHistoryVisibility() *HistoryVisibilityEventContent {
|
||||
casted, ok := content.Parsed.(*HistoryVisibilityEventContent)
|
||||
if !ok {
|
||||
return &HistoryVisibilityEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsGuestAccess() *GuestAccessEventContent {
|
||||
casted, ok := content.Parsed.(*GuestAccessEventContent)
|
||||
if !ok {
|
||||
return &GuestAccessEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsPinnedEvents() *PinnedEventsEventContent {
|
||||
casted, ok := content.Parsed.(*PinnedEventsEventContent)
|
||||
if !ok {
|
||||
return &PinnedEventsEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsEncryption() *EncryptionEventContent {
|
||||
casted, ok := content.Parsed.(*EncryptionEventContent)
|
||||
if !ok {
|
||||
return &EncryptionEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsMessage() *MessageEventContent {
|
||||
casted, ok := content.Parsed.(*MessageEventContent)
|
||||
if !ok {
|
||||
return &MessageEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsEncrypted() *EncryptedEventContent {
|
||||
casted, ok := content.Parsed.(*EncryptedEventContent)
|
||||
if !ok {
|
||||
return &EncryptedEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRedaction() *RedactionEventContent {
|
||||
casted, ok := content.Parsed.(*RedactionEventContent)
|
||||
if !ok {
|
||||
return &RedactionEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsReaction() *ReactionEventContent {
|
||||
casted, ok := content.Parsed.(*ReactionEventContent)
|
||||
if !ok {
|
||||
return &ReactionEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTag() *TagEventContent {
|
||||
casted, ok := content.Parsed.(*TagEventContent)
|
||||
if !ok {
|
||||
return &TagEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsDirectChats() *DirectChatsEventContent {
|
||||
casted, ok := content.Parsed.(*DirectChatsEventContent)
|
||||
if !ok {
|
||||
return &DirectChatsEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsFullyRead() *FullyReadEventContent {
|
||||
casted, ok := content.Parsed.(*FullyReadEventContent)
|
||||
if !ok {
|
||||
return &FullyReadEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsIgnoredUserList() *IgnoredUserListEventContent {
|
||||
casted, ok := content.Parsed.(*IgnoredUserListEventContent)
|
||||
if !ok {
|
||||
return &IgnoredUserListEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsTyping() *TypingEventContent {
|
||||
casted, ok := content.Parsed.(*TypingEventContent)
|
||||
if !ok {
|
||||
return &TypingEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsReceipt() *ReceiptEventContent {
|
||||
casted, ok := content.Parsed.(*ReceiptEventContent)
|
||||
if !ok {
|
||||
return &ReceiptEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsPresence() *PresenceEventContent {
|
||||
casted, ok := content.Parsed.(*PresenceEventContent)
|
||||
if !ok {
|
||||
return &PresenceEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomKey() *RoomKeyEventContent {
|
||||
casted, ok := content.Parsed.(*RoomKeyEventContent)
|
||||
if !ok {
|
||||
return &RoomKeyEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsForwardedRoomKey() *ForwardedRoomKeyEventContent {
|
||||
casted, ok := content.Parsed.(*ForwardedRoomKeyEventContent)
|
||||
if !ok {
|
||||
return &ForwardedRoomKeyEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomKeyRequest() *RoomKeyRequestEventContent {
|
||||
casted, ok := content.Parsed.(*RoomKeyRequestEventContent)
|
||||
if !ok {
|
||||
return &RoomKeyRequestEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsRoomKeyWithheld() *RoomKeyWithheldEventContent {
|
||||
casted, ok := content.Parsed.(*RoomKeyWithheldEventContent)
|
||||
if !ok {
|
||||
return &RoomKeyWithheldEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallInvite() *CallInviteEventContent {
|
||||
casted, ok := content.Parsed.(*CallInviteEventContent)
|
||||
if !ok {
|
||||
return &CallInviteEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallCandidates() *CallCandidatesEventContent {
|
||||
casted, ok := content.Parsed.(*CallCandidatesEventContent)
|
||||
if !ok {
|
||||
return &CallCandidatesEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallAnswer() *CallAnswerEventContent {
|
||||
casted, ok := content.Parsed.(*CallAnswerEventContent)
|
||||
if !ok {
|
||||
return &CallAnswerEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallReject() *CallRejectEventContent {
|
||||
casted, ok := content.Parsed.(*CallRejectEventContent)
|
||||
if !ok {
|
||||
return &CallRejectEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallSelectAnswer() *CallSelectAnswerEventContent {
|
||||
casted, ok := content.Parsed.(*CallSelectAnswerEventContent)
|
||||
if !ok {
|
||||
return &CallSelectAnswerEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallNegotiate() *CallNegotiateEventContent {
|
||||
casted, ok := content.Parsed.(*CallNegotiateEventContent)
|
||||
if !ok {
|
||||
return &CallNegotiateEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
func (content *Content) AsCallHangup() *CallHangupEventContent {
|
||||
casted, ok := content.Parsed.(*CallHangupEventContent)
|
||||
if !ok {
|
||||
return &CallHangupEventContent{}
|
||||
}
|
||||
return casted
|
||||
}
|
||||
141
vendor/maunium.net/go/mautrix/event/encryption.go
generated
vendored
Normal file
141
vendor/maunium.net/go/mautrix/event/encryption.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// EncryptionEventContent represents the content of a m.room.encryption state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-encryption
|
||||
type EncryptionEventContent struct {
|
||||
// The encryption algorithm to be used to encrypt messages sent in this room. Must be 'm.megolm.v1.aes-sha2'.
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
// How long the session should be used before changing it. 604800000 (a week) is the recommended default.
|
||||
RotationPeriodMillis int64 `json:"rotation_period_ms,omitempty"`
|
||||
// How many messages should be sent before changing the session. 100 is the recommended default.
|
||||
RotationPeriodMessages int `json:"rotation_period_msgs,omitempty"`
|
||||
}
|
||||
|
||||
// EncryptedEventContent represents the content of a m.room.encrypted message event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-encrypted
|
||||
type EncryptedEventContent struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
SessionID id.SessionID `json:"session_id,omitempty"`
|
||||
Ciphertext json.RawMessage `json:"ciphertext"`
|
||||
|
||||
MegolmCiphertext []byte `json:"-"`
|
||||
OlmCiphertext OlmCiphertexts `json:"-"`
|
||||
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
type OlmCiphertexts map[id.Curve25519]struct {
|
||||
Body string `json:"body"`
|
||||
Type id.OlmMsgType `json:"type"`
|
||||
}
|
||||
|
||||
type serializableEncryptedEventContent EncryptedEventContent
|
||||
|
||||
func (content *EncryptedEventContent) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, (*serializableEncryptedEventContent)(content))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch content.Algorithm {
|
||||
case id.AlgorithmOlmV1:
|
||||
content.OlmCiphertext = make(OlmCiphertexts)
|
||||
return json.Unmarshal(content.Ciphertext, &content.OlmCiphertext)
|
||||
case id.AlgorithmMegolmV1:
|
||||
if len(content.Ciphertext) == 0 || content.Ciphertext[0] != '"' || content.Ciphertext[len(content.Ciphertext)-1] != '"' {
|
||||
return id.InputNotJSONString
|
||||
}
|
||||
content.MegolmCiphertext = content.Ciphertext[1 : len(content.Ciphertext)-1]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (content *EncryptedEventContent) MarshalJSON() ([]byte, error) {
|
||||
var err error
|
||||
switch content.Algorithm {
|
||||
case id.AlgorithmOlmV1:
|
||||
content.Ciphertext, err = json.Marshal(content.OlmCiphertext)
|
||||
case id.AlgorithmMegolmV1:
|
||||
content.Ciphertext = make([]byte, len(content.MegolmCiphertext)+2)
|
||||
content.Ciphertext[0] = '"'
|
||||
content.Ciphertext[len(content.Ciphertext)-1] = '"'
|
||||
copy(content.Ciphertext[1:len(content.Ciphertext)-1], content.MegolmCiphertext)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal((*serializableEncryptedEventContent)(content))
|
||||
}
|
||||
|
||||
// RoomKeyEventContent represents the content of a m.room_key to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-key
|
||||
type RoomKeyEventContent struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
SessionID id.SessionID `json:"session_id"`
|
||||
SessionKey string `json:"session_key"`
|
||||
}
|
||||
|
||||
// ForwardedRoomKeyEventContent represents the content of a m.forwarded_room_key to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-forwarded-room-key
|
||||
type ForwardedRoomKeyEventContent struct {
|
||||
RoomKeyEventContent
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
SenderClaimedKey id.Ed25519 `json:"sender_claimed_ed25519_key"`
|
||||
ForwardingKeyChain []string `json:"forwarding_curve25519_key_chain"`
|
||||
}
|
||||
|
||||
type KeyRequestAction string
|
||||
|
||||
const (
|
||||
KeyRequestActionRequest = "request"
|
||||
KeyRequestActionCancel = "request_cancellation"
|
||||
)
|
||||
|
||||
// RoomKeyRequestEventContent represents the content of a m.room_key_request to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-key-request
|
||||
type RoomKeyRequestEventContent struct {
|
||||
Body RequestedKeyInfo `json:"body"`
|
||||
Action KeyRequestAction `json:"action"`
|
||||
RequestingDeviceID id.DeviceID `json:"requesting_device_id"`
|
||||
RequestID string `json:"request_id"`
|
||||
}
|
||||
|
||||
type RequestedKeyInfo struct {
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
SessionID id.SessionID `json:"session_id"`
|
||||
}
|
||||
|
||||
type RoomKeyWithheldCode string
|
||||
|
||||
const (
|
||||
RoomKeyWithheldBlacklisted RoomKeyWithheldCode = "m.blacklisted"
|
||||
RoomKeyWithheldUnverified RoomKeyWithheldCode = "m.unverified"
|
||||
RoomKeyWithheldUnauthorized RoomKeyWithheldCode = "m.unauthorized"
|
||||
RoomKeyWithheldUnavailable RoomKeyWithheldCode = "m.unavailable"
|
||||
RoomKeyWithheldNoOlmSession RoomKeyWithheldCode = "m.no_olm"
|
||||
)
|
||||
|
||||
type RoomKeyWithheldEventContent struct {
|
||||
RoomID id.RoomID `json:"room_id,omitempty"`
|
||||
Algorithm id.Algorithm `json:"algorithm"`
|
||||
SessionID id.SessionID `json:"session_id,omitempty"`
|
||||
SenderKey id.SenderKey `json:"sender_key"`
|
||||
Code RoomKeyWithheldCode `json:"code"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
80
vendor/maunium.net/go/mautrix/event/ephemeral.go
generated
vendored
Normal file
80
vendor/maunium.net/go/mautrix/event/ephemeral.go
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// TagEventContent represents the content of a m.typing ephemeral event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-typing
|
||||
type TypingEventContent struct {
|
||||
UserIDs []id.UserID `json:"user_ids"`
|
||||
}
|
||||
|
||||
// ReceiptEventContent represents the content of a m.receipt ephemeral event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-receipt
|
||||
type ReceiptEventContent map[id.EventID]Receipts
|
||||
|
||||
type Receipts struct {
|
||||
Read map[id.UserID]ReadReceipt `json:"m.read"`
|
||||
}
|
||||
|
||||
type ReadReceipt struct {
|
||||
Timestamp int64 `json:"ts"`
|
||||
|
||||
// Extra contains any unknown fields in the read receipt event.
|
||||
// Most servers don't allow clients to set them, so this will be empty in most cases.
|
||||
Extra map[string]interface{} `json:"-"`
|
||||
}
|
||||
|
||||
func (rr *ReadReceipt) UnmarshalJSON(data []byte) error {
|
||||
// Hacky compatibility hack against crappy clients that send double-encoded read receipts.
|
||||
// TODO is this actually needed? clients can't currently set custom content in receipts 🤔
|
||||
if data[0] == '"' && data[len(data)-1] == '"' {
|
||||
var strData string
|
||||
err := json.Unmarshal(data, &strData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = []byte(strData)
|
||||
}
|
||||
|
||||
var parsed map[string]interface{}
|
||||
err := json.Unmarshal(data, &parsed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ts, _ := parsed["ts"].(float64)
|
||||
delete(parsed, "ts")
|
||||
*rr = ReadReceipt{
|
||||
Timestamp: int64(ts),
|
||||
Extra: parsed,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Presence string
|
||||
|
||||
const (
|
||||
PresenceOnline Presence = "online"
|
||||
PresenceOffline Presence = "offline"
|
||||
PresenceUnavailable Presence = "unavailable"
|
||||
)
|
||||
|
||||
// PresenceEventContent represents the content of a m.presence ephemeral event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-presence
|
||||
type PresenceEventContent struct {
|
||||
Presence Presence `json:"presence"`
|
||||
Displayname string `json:"displayname,omitempty"`
|
||||
AvatarURL id.ContentURIString `json:"avatar_url,omitempty"`
|
||||
LastActiveAgo int64 `json:"last_active_ago,omitempty"`
|
||||
CurrentlyActive bool `json:"currently_active,omitempty"`
|
||||
StatusMessage string `json:"status_msg,omitempty"`
|
||||
}
|
||||
54
vendor/maunium.net/go/mautrix/event/events.go
generated
vendored
Normal file
54
vendor/maunium.net/go/mautrix/event/events.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Event represents a single Matrix event.
|
||||
type Event struct {
|
||||
StateKey *string `json:"state_key,omitempty"` // The state key for the event. Only present on State Events.
|
||||
Sender id.UserID `json:"sender"` // The user ID of the sender of the event
|
||||
Type Type `json:"type"` // The event type
|
||||
Timestamp int64 `json:"origin_server_ts"` // The unix timestamp when this message was sent by the origin server
|
||||
ID id.EventID `json:"event_id"` // The unique ID of this event
|
||||
RoomID id.RoomID `json:"room_id"` // The room the event was sent to. May be nil (e.g. for presence)
|
||||
Content Content `json:"content"` // The JSON content of the event.
|
||||
Redacts id.EventID `json:"redacts,omitempty"` // The event ID that was redacted if a m.room.redaction event
|
||||
Unsigned Unsigned `json:"unsigned,omitempty"` // Unsigned content set by own homeserver.
|
||||
|
||||
Mautrix MautrixInfo `json:"-"`
|
||||
}
|
||||
|
||||
type MautrixInfo struct {
|
||||
Verified bool
|
||||
}
|
||||
|
||||
func (evt *Event) GetStateKey() string {
|
||||
if evt.StateKey != nil {
|
||||
return *evt.StateKey
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StrippedState struct {
|
||||
Content Content `json:"content"`
|
||||
Type Type `json:"type"`
|
||||
StateKey string `json:"state_key"`
|
||||
}
|
||||
|
||||
type Unsigned struct {
|
||||
PrevContent *Content `json:"prev_content,omitempty"`
|
||||
PrevSender id.UserID `json:"prev_sender,omitempty"`
|
||||
ReplacesState id.EventID `json:"replaces_state,omitempty"`
|
||||
Age int64 `json:"age,omitempty"`
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
Relations Relations `json:"m.relations,omitempty"`
|
||||
RedactedBecause *Event `json:"redacted_because,omitempty"`
|
||||
InviteRoomState []StrippedState `json:"invite_room_state"`
|
||||
}
|
||||
53
vendor/maunium.net/go/mautrix/event/member.go
generated
vendored
Normal file
53
vendor/maunium.net/go/mautrix/event/member.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Membership is an enum specifying the membership state of a room member.
|
||||
type Membership string
|
||||
|
||||
func (ms Membership) IsInviteOrJoin() bool {
|
||||
return ms == MembershipJoin || ms == MembershipInvite
|
||||
}
|
||||
|
||||
func (ms Membership) IsLeaveOrBan() bool {
|
||||
return ms == MembershipLeave || ms == MembershipBan
|
||||
}
|
||||
|
||||
// The allowed membership states as specified in spec section 10.5.5.
|
||||
const (
|
||||
MembershipJoin Membership = "join"
|
||||
MembershipLeave Membership = "leave"
|
||||
MembershipInvite Membership = "invite"
|
||||
MembershipBan Membership = "ban"
|
||||
MembershipKnock Membership = "knock"
|
||||
)
|
||||
|
||||
// MemberEventContent represents the content of a m.room.member state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-member
|
||||
type MemberEventContent struct {
|
||||
Membership Membership `json:"membership"`
|
||||
AvatarURL id.ContentURIString `json:"avatar_url,omitempty"`
|
||||
Displayname string `json:"displayname,omitempty"`
|
||||
IsDirect bool `json:"is_direct,omitempty"`
|
||||
ThirdPartyInvite *ThirdPartyInvite `json:"third_party_invite,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type ThirdPartyInvite struct {
|
||||
DisplayName string `json:"display_name"`
|
||||
Signed struct {
|
||||
Token string `json:"token"`
|
||||
Signatures json.RawMessage `json:"signatures"`
|
||||
MXID string `json:"mxid"`
|
||||
}
|
||||
}
|
||||
231
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
Normal file
231
vendor/maunium.net/go/mautrix/event/message.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/attachment"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// MessageType is the sub-type of a m.room.message event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-message-msgtypes
|
||||
type MessageType string
|
||||
|
||||
// Msgtypes
|
||||
const (
|
||||
MsgText MessageType = "m.text"
|
||||
MsgEmote MessageType = "m.emote"
|
||||
MsgNotice MessageType = "m.notice"
|
||||
MsgImage MessageType = "m.image"
|
||||
MsgLocation MessageType = "m.location"
|
||||
MsgVideo MessageType = "m.video"
|
||||
MsgAudio MessageType = "m.audio"
|
||||
MsgFile MessageType = "m.file"
|
||||
|
||||
MsgVerificationRequest MessageType = "m.key.verification.request"
|
||||
)
|
||||
|
||||
// Format specifies the format of the formatted_body in m.room.message events.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-message-msgtypes
|
||||
type Format string
|
||||
|
||||
// Message formats
|
||||
const (
|
||||
FormatHTML Format = "org.matrix.custom.html"
|
||||
)
|
||||
|
||||
// RedactionEventContent represents the content of a m.room.redaction message event.
|
||||
//
|
||||
// The redacted event ID is still at the top level, but will move in a future room version.
|
||||
// See https://github.com/matrix-org/matrix-doc/pull/2244 and https://github.com/matrix-org/matrix-doc/pull/2174
|
||||
//
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-redaction
|
||||
type RedactionEventContent struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// ReactionEventContent represents the content of a m.reaction message event.
|
||||
// This is not yet in a spec release, see https://github.com/matrix-org/matrix-doc/pull/1849
|
||||
type ReactionEventContent struct {
|
||||
RelatesTo RelatesTo `json:"m.relates_to"`
|
||||
}
|
||||
|
||||
func (content *ReactionEventContent) GetRelatesTo() *RelatesTo {
|
||||
return &content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *ReactionEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return &content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *ReactionEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
content.RelatesTo = *rel
|
||||
}
|
||||
|
||||
// MssageEventContent represents the content of a m.room.message event.
|
||||
//
|
||||
// It is also used to represent m.sticker events, as they are equivalent to m.room.message
|
||||
// with the exception of the msgtype field.
|
||||
//
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-message
|
||||
type MessageEventContent struct {
|
||||
// Base m.room.message fields
|
||||
MsgType MessageType `json:"msgtype"`
|
||||
Body string `json:"body"`
|
||||
|
||||
// Extra fields for text types
|
||||
Format Format `json:"format,omitempty"`
|
||||
FormattedBody string `json:"formatted_body,omitempty"`
|
||||
|
||||
// Extra field for m.location
|
||||
GeoURI string `json:"geo_uri,omitempty"`
|
||||
|
||||
// Extra fields for media types
|
||||
URL id.ContentURIString `json:"url,omitempty"`
|
||||
Info *FileInfo `json:"info,omitempty"`
|
||||
File *EncryptedFileInfo `json:"file,omitempty"`
|
||||
|
||||
// Edits and relations
|
||||
NewContent *MessageEventContent `json:"m.new_content,omitempty"`
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
|
||||
// In-room verification
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
FromDevice id.DeviceID `json:"from_device,omitempty"`
|
||||
Methods []VerificationMethod `json:"methods,omitempty"`
|
||||
|
||||
replyFallbackRemoved bool
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetRelatesTo() *RelatesTo {
|
||||
if content.RelatesTo == nil {
|
||||
content.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return content.RelatesTo
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
content.RelatesTo = rel
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetFile() *EncryptedFileInfo {
|
||||
if content.File == nil {
|
||||
content.File = &EncryptedFileInfo{}
|
||||
}
|
||||
return content.File
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetInfo() *FileInfo {
|
||||
if content.Info == nil {
|
||||
content.Info = &FileInfo{}
|
||||
}
|
||||
return content.Info
|
||||
}
|
||||
|
||||
type EncryptedFileInfo struct {
|
||||
attachment.EncryptedFile
|
||||
URL id.ContentURIString `json:"url"`
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
MimeType string `json:"mimetype,omitempty"`
|
||||
ThumbnailInfo *FileInfo `json:"thumbnail_info,omitempty"`
|
||||
ThumbnailURL id.ContentURIString `json:"thumbnail_url,omitempty"`
|
||||
ThumbnailFile *EncryptedFileInfo `json:"thumbnail_file,omitempty"`
|
||||
Width int `json:"-"`
|
||||
Height int `json:"-"`
|
||||
Duration int `json:"-"`
|
||||
Size int `json:"-"`
|
||||
}
|
||||
|
||||
type serializableFileInfo struct {
|
||||
MimeType string `json:"mimetype,omitempty"`
|
||||
ThumbnailInfo *serializableFileInfo `json:"thumbnail_info,omitempty"`
|
||||
ThumbnailURL id.ContentURIString `json:"thumbnail_url,omitempty"`
|
||||
ThumbnailFile *EncryptedFileInfo `json:"thumbnail_file,omitempty"`
|
||||
|
||||
Width json.Number `json:"w,omitempty"`
|
||||
Height json.Number `json:"h,omitempty"`
|
||||
Duration json.Number `json:"duration,omitempty"`
|
||||
Size json.Number `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
func (sfi *serializableFileInfo) CopyFrom(fileInfo *FileInfo) *serializableFileInfo {
|
||||
if fileInfo == nil {
|
||||
return nil
|
||||
}
|
||||
*sfi = serializableFileInfo{
|
||||
MimeType: fileInfo.MimeType,
|
||||
ThumbnailURL: fileInfo.ThumbnailURL,
|
||||
ThumbnailInfo: (&serializableFileInfo{}).CopyFrom(fileInfo.ThumbnailInfo),
|
||||
ThumbnailFile: fileInfo.ThumbnailFile,
|
||||
}
|
||||
if fileInfo.Width > 0 {
|
||||
sfi.Width = json.Number(strconv.Itoa(fileInfo.Width))
|
||||
}
|
||||
if fileInfo.Height > 0 {
|
||||
sfi.Height = json.Number(strconv.Itoa(fileInfo.Height))
|
||||
}
|
||||
if fileInfo.Size > 0 {
|
||||
sfi.Size = json.Number(strconv.Itoa(fileInfo.Size))
|
||||
|
||||
}
|
||||
if fileInfo.Duration > 0 {
|
||||
sfi.Duration = json.Number(strconv.Itoa(int(fileInfo.Duration)))
|
||||
}
|
||||
return sfi
|
||||
}
|
||||
|
||||
func (sfi *serializableFileInfo) CopyTo(fileInfo *FileInfo) {
|
||||
*fileInfo = FileInfo{
|
||||
Width: numberToInt(sfi.Width),
|
||||
Height: numberToInt(sfi.Height),
|
||||
Size: numberToInt(sfi.Size),
|
||||
Duration: numberToInt(sfi.Duration),
|
||||
MimeType: sfi.MimeType,
|
||||
ThumbnailURL: sfi.ThumbnailURL,
|
||||
}
|
||||
if sfi.ThumbnailInfo != nil {
|
||||
fileInfo.ThumbnailInfo = &FileInfo{}
|
||||
sfi.ThumbnailInfo.CopyTo(fileInfo.ThumbnailInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func (fileInfo *FileInfo) UnmarshalJSON(data []byte) error {
|
||||
sfi := &serializableFileInfo{}
|
||||
if err := json.Unmarshal(data, sfi); err != nil {
|
||||
return err
|
||||
}
|
||||
sfi.CopyTo(fileInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fileInfo *FileInfo) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal((&serializableFileInfo{}).CopyFrom(fileInfo))
|
||||
}
|
||||
|
||||
func numberToInt(val json.Number) int {
|
||||
f64, _ := val.Float64()
|
||||
if f64 > 0 {
|
||||
return int(f64)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (fileInfo *FileInfo) GetThumbnailInfo() *FileInfo {
|
||||
if fileInfo.ThumbnailInfo == nil {
|
||||
fileInfo.ThumbnailInfo = &FileInfo{}
|
||||
}
|
||||
return fileInfo.ThumbnailInfo
|
||||
}
|
||||
128
vendor/maunium.net/go/mautrix/event/powerlevels.go
generated
vendored
Normal file
128
vendor/maunium.net/go/mautrix/event/powerlevels.go
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// PowerLevelsEventContent represents the content of a m.room.power_levels state event content.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-power-levels
|
||||
type PowerLevelsEventContent struct {
|
||||
usersLock sync.RWMutex `json:"-"`
|
||||
Users map[id.UserID]int `json:"users"`
|
||||
UsersDefault int `json:"users_default"`
|
||||
|
||||
eventsLock sync.RWMutex `json:"-"`
|
||||
Events map[string]int `json:"events"`
|
||||
EventsDefault int `json:"events_default"`
|
||||
|
||||
StateDefaultPtr *int `json:"state_default,omitempty"`
|
||||
|
||||
InvitePtr *int `json:"invite,omitempty"`
|
||||
KickPtr *int `json:"kick,omitempty"`
|
||||
BanPtr *int `json:"ban,omitempty"`
|
||||
RedactPtr *int `json:"redact,omitempty"`
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Invite() int {
|
||||
if pl.InvitePtr != nil {
|
||||
return *pl.InvitePtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Kick() int {
|
||||
if pl.KickPtr != nil {
|
||||
return *pl.KickPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Ban() int {
|
||||
if pl.BanPtr != nil {
|
||||
return *pl.BanPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) Redact() int {
|
||||
if pl.RedactPtr != nil {
|
||||
return *pl.RedactPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) StateDefault() int {
|
||||
if pl.StateDefaultPtr != nil {
|
||||
return *pl.StateDefaultPtr
|
||||
}
|
||||
return 50
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) GetUserLevel(userID id.UserID) int {
|
||||
pl.usersLock.RLock()
|
||||
defer pl.usersLock.RUnlock()
|
||||
level, ok := pl.Users[userID]
|
||||
if !ok {
|
||||
return pl.UsersDefault
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) SetUserLevel(userID id.UserID, level int) {
|
||||
pl.usersLock.Lock()
|
||||
defer pl.usersLock.Unlock()
|
||||
if level == pl.UsersDefault {
|
||||
delete(pl.Users, userID)
|
||||
} else {
|
||||
pl.Users[userID] = level
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) EnsureUserLevel(userID id.UserID, level int) bool {
|
||||
existingLevel := pl.GetUserLevel(userID)
|
||||
if existingLevel != level {
|
||||
pl.SetUserLevel(userID, level)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) GetEventLevel(eventType Type) int {
|
||||
pl.eventsLock.RLock()
|
||||
defer pl.eventsLock.RUnlock()
|
||||
level, ok := pl.Events[eventType.String()]
|
||||
if !ok {
|
||||
if eventType.IsState() {
|
||||
return pl.StateDefault()
|
||||
}
|
||||
return pl.EventsDefault
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) SetEventLevel(eventType Type, level int) {
|
||||
pl.eventsLock.Lock()
|
||||
defer pl.eventsLock.Unlock()
|
||||
if (eventType.IsState() && level == pl.StateDefault()) || (!eventType.IsState() && level == pl.EventsDefault) {
|
||||
delete(pl.Events, eventType.String())
|
||||
} else {
|
||||
pl.Events[eventType.String()] = level
|
||||
}
|
||||
}
|
||||
|
||||
func (pl *PowerLevelsEventContent) EnsureEventLevel(eventType Type, level int) bool {
|
||||
existingLevel := pl.GetEventLevel(eventType)
|
||||
if existingLevel != level {
|
||||
pl.SetEventLevel(eventType, level)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
200
vendor/maunium.net/go/mautrix/event/relations.go
generated
vendored
Normal file
200
vendor/maunium.net/go/mautrix/event/relations.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type RelationType string
|
||||
|
||||
const (
|
||||
RelReplace RelationType = "m.replace"
|
||||
RelReference RelationType = "m.reference"
|
||||
RelAnnotation RelationType = "m.annotation"
|
||||
RelReply RelationType = "net.maunium.reply"
|
||||
)
|
||||
|
||||
type RelatesTo struct {
|
||||
Type RelationType
|
||||
EventID id.EventID
|
||||
Key string
|
||||
}
|
||||
|
||||
type serializableInReplyTo struct {
|
||||
EventID id.EventID `json:"event_id,omitempty"`
|
||||
}
|
||||
|
||||
type serializableRelatesTo struct {
|
||||
InReplyTo *serializableInReplyTo `json:"m.in_reply_to,omitempty"`
|
||||
|
||||
Type RelationType `json:"rel_type,omitempty"`
|
||||
EventID id.EventID `json:"event_id,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetReplaceID() id.EventID {
|
||||
if rel.Type == RelReplace {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetReferenceID() id.EventID {
|
||||
if rel.Type == RelReference {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetReplyID() id.EventID {
|
||||
if rel.Type == RelReply {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetAnnotationID() id.EventID {
|
||||
if rel.Type == RelAnnotation {
|
||||
return rel.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) GetAnnotationKey() string {
|
||||
if rel.Type == RelAnnotation {
|
||||
return rel.Key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) UnmarshalJSON(data []byte) error {
|
||||
var srel serializableRelatesTo
|
||||
if err := json.Unmarshal(data, &srel); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(srel.Type) > 0 {
|
||||
rel.Type = srel.Type
|
||||
rel.EventID = srel.EventID
|
||||
rel.Key = srel.Key
|
||||
} else if srel.InReplyTo != nil && len(srel.InReplyTo.EventID) > 0 {
|
||||
rel.Type = RelReply
|
||||
rel.EventID = srel.InReplyTo.EventID
|
||||
rel.Key = ""
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rel *RelatesTo) MarshalJSON() ([]byte, error) {
|
||||
srel := serializableRelatesTo{Type: rel.Type, EventID: rel.EventID, Key: rel.Key}
|
||||
if rel.Type == RelReply {
|
||||
srel.InReplyTo = &serializableInReplyTo{rel.EventID}
|
||||
}
|
||||
return json.Marshal(&srel)
|
||||
}
|
||||
|
||||
type RelationChunkItem struct {
|
||||
Type RelationType `json:"type"`
|
||||
EventID string `json:"event_id,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
}
|
||||
|
||||
type RelationChunk struct {
|
||||
Chunk []RelationChunkItem `json:"chunk"`
|
||||
|
||||
Limited bool `json:"limited"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type AnnotationChunk struct {
|
||||
RelationChunk
|
||||
Map map[string]int `json:"-"`
|
||||
}
|
||||
|
||||
type serializableAnnotationChunk AnnotationChunk
|
||||
|
||||
func (ac *AnnotationChunk) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, (*serializableAnnotationChunk)(ac)); err != nil {
|
||||
return err
|
||||
}
|
||||
ac.Map = make(map[string]int)
|
||||
for _, item := range ac.Chunk {
|
||||
ac.Map[item.Key] += item.Count
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ac *AnnotationChunk) Serialize() RelationChunk {
|
||||
ac.Chunk = make([]RelationChunkItem, len(ac.Map))
|
||||
i := 0
|
||||
for key, count := range ac.Map {
|
||||
ac.Chunk[i] = RelationChunkItem{
|
||||
Type: RelAnnotation,
|
||||
Key: key,
|
||||
Count: count,
|
||||
}
|
||||
}
|
||||
return ac.RelationChunk
|
||||
}
|
||||
|
||||
type EventIDChunk struct {
|
||||
RelationChunk
|
||||
List []string `json:"-"`
|
||||
}
|
||||
|
||||
type serializableEventIDChunk EventIDChunk
|
||||
|
||||
func (ec *EventIDChunk) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, (*serializableEventIDChunk)(ec)); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range ec.Chunk {
|
||||
ec.List = append(ec.List, item.EventID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ec *EventIDChunk) Serialize(typ RelationType) RelationChunk {
|
||||
ec.Chunk = make([]RelationChunkItem, len(ec.List))
|
||||
for i, eventID := range ec.List {
|
||||
ec.Chunk[i] = RelationChunkItem{
|
||||
Type: typ,
|
||||
EventID: eventID,
|
||||
}
|
||||
}
|
||||
return ec.RelationChunk
|
||||
}
|
||||
|
||||
type Relations struct {
|
||||
Raw map[RelationType]RelationChunk `json:"-"`
|
||||
|
||||
Annotations AnnotationChunk `json:"m.annotation,omitempty"`
|
||||
References EventIDChunk `json:"m.reference,omitempty"`
|
||||
Replaces EventIDChunk `json:"m.replace,omitempty"`
|
||||
}
|
||||
|
||||
type serializableRelations Relations
|
||||
|
||||
func (relations *Relations) UnmarshalJSON(data []byte) error {
|
||||
if err := json.Unmarshal(data, &relations.Raw); err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, (*serializableRelations)(relations))
|
||||
}
|
||||
|
||||
func (relations *Relations) MarshalJSON() ([]byte, error) {
|
||||
if relations.Raw == nil {
|
||||
relations.Raw = make(map[RelationType]RelationChunk)
|
||||
}
|
||||
relations.Raw[RelAnnotation] = relations.Annotations.Serialize()
|
||||
relations.Raw[RelReference] = relations.References.Serialize(RelReference)
|
||||
relations.Raw[RelReplace] = relations.Replaces.Serialize(RelReplace)
|
||||
return json.Marshal(relations.Raw)
|
||||
}
|
||||
108
vendor/maunium.net/go/mautrix/event/reply.go
generated
vendored
Normal file
108
vendor/maunium.net/go/mautrix/event/reply.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var HTMLReplyFallbackRegex = regexp.MustCompile(`^<mx-reply>[\s\S]+?</mx-reply>`)
|
||||
|
||||
func TrimReplyFallbackHTML(html string) string {
|
||||
return HTMLReplyFallbackRegex.ReplaceAllString(html, "")
|
||||
}
|
||||
|
||||
func TrimReplyFallbackText(text string) string {
|
||||
if !strings.HasPrefix(text, "> ") || !strings.Contains(text, "\n") {
|
||||
return text
|
||||
}
|
||||
|
||||
lines := strings.Split(text, "\n")
|
||||
for len(lines) > 0 && strings.HasPrefix(lines[0], "> ") {
|
||||
lines = lines[1:]
|
||||
}
|
||||
return strings.TrimSpace(strings.Join(lines, "\n"))
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) RemoveReplyFallback() {
|
||||
if len(content.GetReplyTo()) > 0 && !content.replyFallbackRemoved {
|
||||
if content.Format == FormatHTML {
|
||||
content.FormattedBody = TrimReplyFallbackHTML(content.FormattedBody)
|
||||
}
|
||||
content.Body = TrimReplyFallbackText(content.Body)
|
||||
content.replyFallbackRemoved = true
|
||||
}
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) GetReplyTo() id.EventID {
|
||||
if content.RelatesTo != nil && content.RelatesTo.Type == RelReply {
|
||||
return content.RelatesTo.EventID
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
const ReplyFormat = `<mx-reply><blockquote><a href="https://matrix.to/#/%s/%s">In reply to</a> <a href="https://matrix.to/#/%s">%s</a><br>%s</blockquote></mx-reply>`
|
||||
|
||||
func (evt *Event) GenerateReplyFallbackHTML() string {
|
||||
parsedContent, ok := evt.Content.Parsed.(*MessageEventContent)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
parsedContent.RemoveReplyFallback()
|
||||
body := parsedContent.FormattedBody
|
||||
if len(body) == 0 {
|
||||
body = html.EscapeString(parsedContent.Body)
|
||||
}
|
||||
|
||||
senderDisplayName := evt.Sender
|
||||
|
||||
return fmt.Sprintf(ReplyFormat, evt.RoomID, evt.ID, evt.Sender, senderDisplayName, body)
|
||||
}
|
||||
|
||||
func (evt *Event) GenerateReplyFallbackText() string {
|
||||
parsedContent, ok := evt.Content.Parsed.(*MessageEventContent)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
parsedContent.RemoveReplyFallback()
|
||||
body := parsedContent.Body
|
||||
lines := strings.Split(strings.TrimSpace(body), "\n")
|
||||
firstLine, lines := lines[0], lines[1:]
|
||||
|
||||
senderDisplayName := evt.Sender
|
||||
|
||||
var fallbackText strings.Builder
|
||||
_, _ = fmt.Fprintf(&fallbackText, "> <%s> %s", senderDisplayName, firstLine)
|
||||
for _, line := range lines {
|
||||
_, _ = fmt.Fprintf(&fallbackText, "\n> %s", line)
|
||||
}
|
||||
fallbackText.WriteString("\n\n")
|
||||
return fallbackText.String()
|
||||
}
|
||||
|
||||
func (content *MessageEventContent) SetReply(inReplyTo *Event) {
|
||||
content.RelatesTo = &RelatesTo{
|
||||
EventID: inReplyTo.ID,
|
||||
Type: RelReply,
|
||||
}
|
||||
|
||||
if content.MsgType == MsgText || content.MsgType == MsgNotice {
|
||||
if len(content.FormattedBody) == 0 || content.Format != FormatHTML {
|
||||
content.FormattedBody = html.EscapeString(content.Body)
|
||||
content.Format = FormatHTML
|
||||
}
|
||||
content.FormattedBody = inReplyTo.GenerateReplyFallbackHTML() + content.FormattedBody
|
||||
content.Body = inReplyTo.GenerateReplyFallbackText() + content.Body
|
||||
content.replyFallbackRemoved = false
|
||||
}
|
||||
}
|
||||
110
vendor/maunium.net/go/mautrix/event/state.go
generated
vendored
Normal file
110
vendor/maunium.net/go/mautrix/event/state.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// CanonicalAliasEventContent represents the content of a m.room.canonical_alias state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.1#m-room-canonical-alias
|
||||
type CanonicalAliasEventContent struct {
|
||||
Alias id.RoomAlias `json:"alias"`
|
||||
AltAliases []id.RoomAlias `json:"alt_aliases,omitempty"`
|
||||
}
|
||||
|
||||
// RoomNameEventContent represents the content of a m.room.name state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-name
|
||||
type RoomNameEventContent struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// RoomAvatarEventContent represents the content of a m.room.avatar state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-avatar
|
||||
type RoomAvatarEventContent struct {
|
||||
URL id.ContentURI `json:"url"`
|
||||
}
|
||||
|
||||
// TopicEventContent represents the content of a m.room.topic state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-topic
|
||||
type TopicEventContent struct {
|
||||
Topic string `json:"topic"`
|
||||
}
|
||||
|
||||
// TombstoneEventContent represents the content of a m.room.tombstone state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-tombstone
|
||||
type TombstoneEventContent struct {
|
||||
Body string `json:"body"`
|
||||
ReplacementRoom id.RoomID `json:"replacement_room"`
|
||||
}
|
||||
|
||||
// CreateEventContent represents the content of a m.room.create state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-create
|
||||
type CreateEventContent struct {
|
||||
Creator id.UserID `json:"creator"`
|
||||
Federate bool `json:"m.federate,omitempty"`
|
||||
RoomVersion string `json:"version,omitempty"`
|
||||
Predecessor struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
EventID id.EventID `json:"event_id"`
|
||||
} `json:"predecessor"`
|
||||
}
|
||||
|
||||
// JoinRule specifies how open a room is to new members.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-join-rules
|
||||
type JoinRule string
|
||||
|
||||
const (
|
||||
JoinRulePublic JoinRule = "public"
|
||||
JoinRuleKnock JoinRule = "knock"
|
||||
JoinRuleInvite JoinRule = "invite"
|
||||
JoinRulePrivate JoinRule = "private"
|
||||
)
|
||||
|
||||
// JoinRulesEventContent represents the content of a m.room.join_rules state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-join-rules
|
||||
type JoinRulesEventContent struct {
|
||||
JoinRule JoinRule `json:"join_rule"`
|
||||
}
|
||||
|
||||
// PinnedEventsEventContent represents the content of a m.room.pinned_events state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-pinned-events
|
||||
type PinnedEventsEventContent struct {
|
||||
Pinned []id.EventID `json:"pinned"`
|
||||
}
|
||||
|
||||
// HistoryVisibility specifies who can see new messages.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-history-visibility
|
||||
type HistoryVisibility string
|
||||
|
||||
const (
|
||||
HistoryVisibilityInvited HistoryVisibility = "invited"
|
||||
HistoryVisibilityJoined HistoryVisibility = "joined"
|
||||
HistoryVisibilityShared HistoryVisibility = "shared"
|
||||
HistoryVisibilityWorldReadable HistoryVisibility = "world_readable"
|
||||
)
|
||||
|
||||
// HistoryVisibilityEventContent represents the content of a m.room.history_visibility state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-history-visibility
|
||||
type HistoryVisibilityEventContent struct {
|
||||
HistoryVisibility HistoryVisibility `json:"history_visibility"`
|
||||
}
|
||||
|
||||
// GuestAccess specifies whether or not guest accounts can join.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-guest-access
|
||||
type GuestAccess string
|
||||
|
||||
const (
|
||||
GuestAccessCanJoin GuestAccess = "can_join"
|
||||
GuestAccessForbidden GuestAccess = "forbidden"
|
||||
)
|
||||
|
||||
// GuestAccessEventContent represents the content of a m.room.guest_access state event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-guest-access
|
||||
type GuestAccessEventContent struct {
|
||||
GuestAccess GuestAccess `json:"guest_access"`
|
||||
}
|
||||
235
vendor/maunium.net/go/mautrix/event/type.go
generated
vendored
Normal file
235
vendor/maunium.net/go/mautrix/event/type.go
generated
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type TypeClass int
|
||||
|
||||
func (tc TypeClass) Name() string {
|
||||
switch tc {
|
||||
case MessageEventType:
|
||||
return "message"
|
||||
case StateEventType:
|
||||
return "state"
|
||||
case EphemeralEventType:
|
||||
return "ephemeral"
|
||||
case AccountDataEventType:
|
||||
return "account data"
|
||||
case ToDeviceEventType:
|
||||
return "to-device"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// Unknown events
|
||||
UnknownEventType TypeClass = iota
|
||||
// Normal message events
|
||||
MessageEventType
|
||||
// State events
|
||||
StateEventType
|
||||
// Ephemeral events
|
||||
EphemeralEventType
|
||||
// Account data events
|
||||
AccountDataEventType
|
||||
// Device-to-device events
|
||||
ToDeviceEventType
|
||||
)
|
||||
|
||||
type Type struct {
|
||||
Type string
|
||||
Class TypeClass
|
||||
}
|
||||
|
||||
func NewEventType(name string) Type {
|
||||
evtType := Type{Type: name}
|
||||
evtType.Class = evtType.GuessClass()
|
||||
return evtType
|
||||
}
|
||||
|
||||
func (et *Type) IsState() bool {
|
||||
return et.Class == StateEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsEphemeral() bool {
|
||||
return et.Class == EphemeralEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsAccountData() bool {
|
||||
return et.Class == AccountDataEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsToDevice() bool {
|
||||
return et.Class == ToDeviceEventType
|
||||
}
|
||||
|
||||
func (et *Type) IsInRoomVerification() bool {
|
||||
switch et.Type {
|
||||
case InRoomVerificationStart.Type, InRoomVerificationReady.Type, InRoomVerificationAccept.Type,
|
||||
InRoomVerificationKey.Type, InRoomVerificationMAC.Type, InRoomVerificationCancel.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (et *Type) IsCall() bool {
|
||||
switch et.Type {
|
||||
case CallInvite.Type, CallCandidates.Type, CallAnswer.Type, CallReject.Type, CallSelectAnswer.Type,
|
||||
CallNegotiate.Type, CallHangup.Type:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (et *Type) IsCustom() bool {
|
||||
return !strings.HasPrefix(et.Type, "m.")
|
||||
}
|
||||
|
||||
func (et *Type) GuessClass() TypeClass {
|
||||
switch et.Type {
|
||||
case StateAliases.Type, StateCanonicalAlias.Type, StateCreate.Type, StateJoinRules.Type, StateMember.Type,
|
||||
StatePowerLevels.Type, StateRoomName.Type, StateRoomAvatar.Type, StateTopic.Type, StatePinnedEvents.Type,
|
||||
StateTombstone.Type, StateEncryption.Type:
|
||||
return StateEventType
|
||||
case EphemeralEventReceipt.Type, EphemeralEventTyping.Type, EphemeralEventPresence.Type:
|
||||
return EphemeralEventType
|
||||
case AccountDataDirectChats.Type, AccountDataPushRules.Type, AccountDataRoomTags.Type,
|
||||
AccountDataSecretStorageKey.Type, AccountDataSecretStorageDefaultKey.Type,
|
||||
AccountDataCrossSigningMaster.Type, AccountDataCrossSigningSelf.Type, AccountDataCrossSigningUser.Type:
|
||||
return AccountDataEventType
|
||||
case EventRedaction.Type, EventMessage.Type, EventEncrypted.Type, EventReaction.Type, EventSticker.Type,
|
||||
InRoomVerificationStart.Type, InRoomVerificationReady.Type, InRoomVerificationAccept.Type,
|
||||
InRoomVerificationKey.Type, InRoomVerificationMAC.Type, InRoomVerificationCancel.Type,
|
||||
CallInvite.Type, CallCandidates.Type, CallAnswer.Type, CallReject.Type, CallSelectAnswer.Type,
|
||||
CallNegotiate.Type, CallHangup.Type:
|
||||
return MessageEventType
|
||||
case ToDeviceRoomKey.Type, ToDeviceRoomKeyRequest.Type, ToDeviceForwardedRoomKey.Type, ToDeviceRoomKeyWithheld.Type:
|
||||
return ToDeviceEventType
|
||||
default:
|
||||
return UnknownEventType
|
||||
}
|
||||
}
|
||||
|
||||
func (et *Type) UnmarshalJSON(data []byte) error {
|
||||
err := json.Unmarshal(data, &et.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
et.Class = et.GuessClass()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (et *Type) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(&et.Type)
|
||||
}
|
||||
|
||||
func (et Type) UnmarshalText(data []byte) error {
|
||||
et.Type = string(data)
|
||||
et.Class = et.GuessClass()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (et Type) MarshalText() ([]byte, error) {
|
||||
return []byte(et.Type), nil
|
||||
}
|
||||
|
||||
func (et *Type) String() string {
|
||||
return et.Type
|
||||
}
|
||||
|
||||
func (et *Type) Repr() string {
|
||||
return fmt.Sprintf("%s (%s)", et.Type, et.Class.Name())
|
||||
}
|
||||
|
||||
// State events
|
||||
var (
|
||||
StateAliases = Type{"m.room.aliases", StateEventType}
|
||||
StateCanonicalAlias = Type{"m.room.canonical_alias", StateEventType}
|
||||
StateCreate = Type{"m.room.create", StateEventType}
|
||||
StateJoinRules = Type{"m.room.join_rules", StateEventType}
|
||||
StateHistoryVisibility = Type{"m.room.history_visibility", StateEventType}
|
||||
StateGuestAccess = Type{"m.room.guest_access", StateEventType}
|
||||
StateMember = Type{"m.room.member", StateEventType}
|
||||
StatePowerLevels = Type{"m.room.power_levels", StateEventType}
|
||||
StateRoomName = Type{"m.room.name", StateEventType}
|
||||
StateTopic = Type{"m.room.topic", StateEventType}
|
||||
StateRoomAvatar = Type{"m.room.avatar", StateEventType}
|
||||
StatePinnedEvents = Type{"m.room.pinned_events", StateEventType}
|
||||
StateTombstone = Type{"m.room.tombstone", StateEventType}
|
||||
StateEncryption = Type{"m.room.encryption", StateEventType}
|
||||
)
|
||||
|
||||
// Message events
|
||||
var (
|
||||
EventRedaction = Type{"m.room.redaction", MessageEventType}
|
||||
EventMessage = Type{"m.room.message", MessageEventType}
|
||||
EventEncrypted = Type{"m.room.encrypted", MessageEventType}
|
||||
EventReaction = Type{"m.reaction", MessageEventType}
|
||||
EventSticker = Type{"m.sticker", MessageEventType}
|
||||
|
||||
InRoomVerificationStart = Type{"m.key.verification.start", MessageEventType}
|
||||
InRoomVerificationReady = Type{"m.key.verification.ready", MessageEventType}
|
||||
InRoomVerificationAccept = Type{"m.key.verification.accept", MessageEventType}
|
||||
InRoomVerificationKey = Type{"m.key.verification.key", MessageEventType}
|
||||
InRoomVerificationMAC = Type{"m.key.verification.mac", MessageEventType}
|
||||
InRoomVerificationCancel = Type{"m.key.verification.cancel", MessageEventType}
|
||||
|
||||
CallInvite = Type{"m.call.invite", MessageEventType}
|
||||
CallCandidates = Type{"m.call.candidates", MessageEventType}
|
||||
CallAnswer = Type{"m.call.answer", MessageEventType}
|
||||
CallReject = Type{"m.call.reject", MessageEventType}
|
||||
CallSelectAnswer = Type{"m.call.select_answer", MessageEventType}
|
||||
CallNegotiate = Type{"m.call.negotiate", MessageEventType}
|
||||
CallHangup = Type{"m.call.hangup", MessageEventType}
|
||||
)
|
||||
|
||||
// Ephemeral events
|
||||
var (
|
||||
EphemeralEventReceipt = Type{"m.receipt", EphemeralEventType}
|
||||
EphemeralEventTyping = Type{"m.typing", EphemeralEventType}
|
||||
EphemeralEventPresence = Type{"m.presence", EphemeralEventType}
|
||||
)
|
||||
|
||||
// Account data events
|
||||
var (
|
||||
AccountDataDirectChats = Type{"m.direct", AccountDataEventType}
|
||||
AccountDataPushRules = Type{"m.push_rules", AccountDataEventType}
|
||||
AccountDataRoomTags = Type{"m.tag", AccountDataEventType}
|
||||
AccountDataFullyRead = Type{"m.fully_read", AccountDataEventType}
|
||||
AccountDataIgnoredUserList = Type{"m.ignored_user_list", AccountDataEventType}
|
||||
|
||||
AccountDataSecretStorageDefaultKey = Type{"m.secret_storage.default_key", AccountDataEventType}
|
||||
AccountDataSecretStorageKey = Type{"m.secret_storage.key", AccountDataEventType}
|
||||
AccountDataCrossSigningMaster = Type{"m.cross_signing.master", AccountDataEventType}
|
||||
AccountDataCrossSigningUser = Type{"m.cross_signing.user_signing", AccountDataEventType}
|
||||
AccountDataCrossSigningSelf = Type{"m.cross_signing.self_signing", AccountDataEventType}
|
||||
)
|
||||
|
||||
// Device-to-device events
|
||||
var (
|
||||
ToDeviceRoomKey = Type{"m.room_key", ToDeviceEventType}
|
||||
ToDeviceRoomKeyRequest = Type{"m.room_key_request", ToDeviceEventType}
|
||||
ToDeviceForwardedRoomKey = Type{"m.forwarded_room_key", ToDeviceEventType}
|
||||
ToDeviceEncrypted = Type{"m.room.encrypted", ToDeviceEventType}
|
||||
ToDeviceRoomKeyWithheld = Type{"m.room_key.withheld", ToDeviceEventType}
|
||||
ToDeviceVerificationRequest = Type{"m.key.verification.request", ToDeviceEventType}
|
||||
ToDeviceVerificationStart = Type{"m.key.verification.start", ToDeviceEventType}
|
||||
ToDeviceVerificationAccept = Type{"m.key.verification.accept", ToDeviceEventType}
|
||||
ToDeviceVerificationKey = Type{"m.key.verification.key", ToDeviceEventType}
|
||||
ToDeviceVerificationMAC = Type{"m.key.verification.mac", ToDeviceEventType}
|
||||
ToDeviceVerificationCancel = Type{"m.key.verification.cancel", ToDeviceEventType}
|
||||
|
||||
ToDeviceOrgMatrixRoomKeyWithheld = Type{"org.matrix.room_key.withheld", ToDeviceEventType}
|
||||
)
|
||||
306
vendor/maunium.net/go/mautrix/event/verification.go
generated
vendored
Normal file
306
vendor/maunium.net/go/mautrix/event/verification.go
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
// Copyright (c) 2020 Nikos Filippakis
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type VerificationMethod string
|
||||
|
||||
const VerificationMethodSAS VerificationMethod = "m.sas.v1"
|
||||
|
||||
// VerificationRequestEventContent represents the content of a m.key.verification.request to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-request
|
||||
type VerificationRequestEventContent struct {
|
||||
// The device ID which is initiating the request.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// An opaque identifier for the verification request. Must be unique with respect to the devices involved.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The verification methods supported by the sender.
|
||||
Methods []VerificationMethod `json:"methods"`
|
||||
// The POSIX timestamp in milliseconds for when the request was made.
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vrec *VerificationRequestEventContent) SupportsVerificationMethod(meth VerificationMethod) bool {
|
||||
for _, supportedMeth := range vrec.Methods {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type KeyAgreementProtocol string
|
||||
|
||||
const (
|
||||
KeyAgreementCurve25519 KeyAgreementProtocol = "curve25519"
|
||||
KeyAgreementCurve25519HKDFSHA256 KeyAgreementProtocol = "curve25519-hkdf-sha256"
|
||||
)
|
||||
|
||||
type VerificationHashMethod string
|
||||
|
||||
const VerificationHashSHA256 VerificationHashMethod = "sha256"
|
||||
|
||||
type MACMethod string
|
||||
|
||||
const HKDFHMACSHA256 MACMethod = "hkdf-hmac-sha256"
|
||||
|
||||
type SASMethod string
|
||||
|
||||
const (
|
||||
SASDecimal SASMethod = "decimal"
|
||||
SASEmoji SASMethod = "emoji"
|
||||
)
|
||||
|
||||
// VerificationStartEventContent represents the content of a m.key.verification.start to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-start
|
||||
type VerificationStartEventContent struct {
|
||||
// The device ID which is initiating the process.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// An opaque identifier for the verification process. Must be unique with respect to the devices involved.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The verification method to use.
|
||||
Method VerificationMethod `json:"method"`
|
||||
// The key agreement protocols the sending device understands.
|
||||
KeyAgreementProtocols []KeyAgreementProtocol `json:"key_agreement_protocols"`
|
||||
// The hash methods the sending device understands.
|
||||
Hashes []VerificationHashMethod `json:"hashes"`
|
||||
// The message authentication codes that the sending device understands.
|
||||
MessageAuthenticationCodes []MACMethod `json:"message_authentication_codes"`
|
||||
// The SAS methods the sending device (and the sending device's user) understands.
|
||||
ShortAuthenticationString []SASMethod `json:"short_authentication_string"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsKeyAgreementProtocol(proto KeyAgreementProtocol) bool {
|
||||
for _, supportedProto := range vsec.KeyAgreementProtocols {
|
||||
if supportedProto == proto {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsHashMethod(alg VerificationHashMethod) bool {
|
||||
for _, supportedAlg := range vsec.Hashes {
|
||||
if supportedAlg == alg {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsMACMethod(meth MACMethod) bool {
|
||||
for _, supportedMeth := range vsec.MessageAuthenticationCodes {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SupportsSASMethod(meth SASMethod) bool {
|
||||
for _, supportedMeth := range vsec.ShortAuthenticationString {
|
||||
if supportedMeth == meth {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vsec.RelatesTo == nil {
|
||||
vsec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vsec.RelatesTo
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vsec.RelatesTo
|
||||
}
|
||||
|
||||
func (vsec *VerificationStartEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vsec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationReadyEventContent represents the content of a m.key.verification.ready event.
|
||||
type VerificationReadyEventContent struct {
|
||||
// The device ID which accepted the process.
|
||||
FromDevice id.DeviceID `json:"from_device"`
|
||||
// The verification methods supported by the sender.
|
||||
Methods []VerificationMethod `json:"methods"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
var _ Relatable = (*VerificationReadyEventContent)(nil)
|
||||
|
||||
func (vrec *VerificationReadyEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vrec.RelatesTo == nil {
|
||||
vrec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vrec.RelatesTo
|
||||
}
|
||||
|
||||
func (vrec *VerificationReadyEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vrec.RelatesTo
|
||||
}
|
||||
|
||||
func (vrec *VerificationReadyEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vrec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationAcceptEventContent represents the content of a m.key.verification.accept to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-accept
|
||||
type VerificationAcceptEventContent struct {
|
||||
// An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The verification method to use.
|
||||
Method VerificationMethod `json:"method"`
|
||||
// The key agreement protocol the device is choosing to use, out of the options in the m.key.verification.start message.
|
||||
KeyAgreementProtocol KeyAgreementProtocol `json:"key_agreement_protocol"`
|
||||
// The hash method the device is choosing to use, out of the options in the m.key.verification.start message.
|
||||
Hash VerificationHashMethod `json:"hash"`
|
||||
// The message authentication code the device is choosing to use, out of the options in the m.key.verification.start message.
|
||||
MessageAuthenticationCode MACMethod `json:"message_authentication_code"`
|
||||
// The SAS methods both devices involved in the verification process understand. Must be a subset of the options in the m.key.verification.start message.
|
||||
ShortAuthenticationString []SASMethod `json:"short_authentication_string"`
|
||||
// The hash (encoded as unpadded base64) of the concatenation of the device's ephemeral public key (encoded as unpadded base64) and the canonical JSON representation of the m.key.verification.start message.
|
||||
Commitment string `json:"commitment"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vaec *VerificationAcceptEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vaec.RelatesTo == nil {
|
||||
vaec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vaec.RelatesTo
|
||||
}
|
||||
|
||||
func (vaec *VerificationAcceptEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vaec.RelatesTo
|
||||
}
|
||||
|
||||
func (vaec *VerificationAcceptEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vaec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationKeyEventContent represents the content of a m.key.verification.key to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-key
|
||||
type VerificationKeyEventContent struct {
|
||||
// An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// The device's ephemeral public key, encoded as unpadded base64.
|
||||
Key string `json:"key"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vkec *VerificationKeyEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vkec.RelatesTo == nil {
|
||||
vkec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vkec.RelatesTo
|
||||
}
|
||||
|
||||
func (vkec *VerificationKeyEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vkec.RelatesTo
|
||||
}
|
||||
|
||||
func (vkec *VerificationKeyEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vkec.RelatesTo = rel
|
||||
}
|
||||
|
||||
// VerificationMacEventContent represents the content of a m.key.verification.mac to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-mac
|
||||
type VerificationMacEventContent struct {
|
||||
// An opaque identifier for the verification process. Must be the same as the one used for the m.key.verification.start message.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// A map of the key ID to the MAC of the key, using the algorithm in the verification process. The MAC is encoded as unpadded base64.
|
||||
Mac map[id.KeyID]string `json:"mac"`
|
||||
// The MAC of the comma-separated, sorted, list of key IDs given in the mac property, encoded as unpadded base64.
|
||||
Keys string `json:"keys"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vmec *VerificationMacEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vmec.RelatesTo == nil {
|
||||
vmec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vmec.RelatesTo
|
||||
}
|
||||
|
||||
func (vmec *VerificationMacEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vmec.RelatesTo
|
||||
}
|
||||
|
||||
func (vmec *VerificationMacEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vmec.RelatesTo = rel
|
||||
}
|
||||
|
||||
type VerificationCancelCode string
|
||||
|
||||
const (
|
||||
VerificationCancelByUser VerificationCancelCode = "m.user"
|
||||
VerificationCancelByTimeout VerificationCancelCode = "m.timeout"
|
||||
VerificationCancelUnknownTransaction VerificationCancelCode = "m.unknown_transaction"
|
||||
VerificationCancelUnknownMethod VerificationCancelCode = "m.unknown_method"
|
||||
VerificationCancelUnexpectedMessage VerificationCancelCode = "m.unexpected_message"
|
||||
VerificationCancelKeyMismatch VerificationCancelCode = "m.key_mismatch"
|
||||
VerificationCancelUserMismatch VerificationCancelCode = "m.user_mismatch"
|
||||
VerificationCancelInvalidMessage VerificationCancelCode = "m.invalid_message"
|
||||
VerificationCancelAccepted VerificationCancelCode = "m.accepted"
|
||||
VerificationCancelSASMismatch VerificationCancelCode = "m.mismatched_sas"
|
||||
VerificationCancelCommitmentMismatch VerificationCancelCode = "m.mismatched_commitment"
|
||||
)
|
||||
|
||||
// VerificationCancelEventContent represents the content of a m.key.verification.cancel to_device event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-key-verification-cancel
|
||||
type VerificationCancelEventContent struct {
|
||||
// The opaque identifier for the verification process/request.
|
||||
TransactionID string `json:"transaction_id,omitempty"`
|
||||
// A human readable description of the code. The client should only rely on this string if it does not understand the code.
|
||||
Reason string `json:"reason"`
|
||||
// The error code for why the process/request was cancelled by the user.
|
||||
Code VerificationCancelCode `json:"code"`
|
||||
// The user that the event is sent to for in-room verification.
|
||||
To id.UserID `json:"to,omitempty"`
|
||||
// Original event ID for in-room verification.
|
||||
RelatesTo *RelatesTo `json:"m.relates_to,omitempty"`
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) GetRelatesTo() *RelatesTo {
|
||||
if vcec.RelatesTo == nil {
|
||||
vcec.RelatesTo = &RelatesTo{}
|
||||
}
|
||||
return vcec.RelatesTo
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) OptionalGetRelatesTo() *RelatesTo {
|
||||
return vcec.RelatesTo
|
||||
}
|
||||
|
||||
func (vcec *VerificationCancelEventContent) SetRelatesTo(rel *RelatesTo) {
|
||||
vcec.RelatesTo = rel
|
||||
}
|
||||
116
vendor/maunium.net/go/mautrix/event/voip.go
generated
vendored
Normal file
116
vendor/maunium.net/go/mautrix/event/voip.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package event
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CallHangupReason string
|
||||
|
||||
const (
|
||||
CallHangupICEFailed CallHangupReason = "ice_failed"
|
||||
CallHangupInviteTimeout CallHangupReason = "invite_timeout"
|
||||
CallHangupUserHangup CallHangupReason = "user_hangup"
|
||||
CallHangupUserMediaFailed CallHangupReason = "user_media_failed"
|
||||
CallHangupUnknownError CallHangupReason = "unknown_error"
|
||||
)
|
||||
|
||||
type CallDataType string
|
||||
|
||||
const (
|
||||
CallDataTypeOffer CallDataType = "offer"
|
||||
CallDataTypeAnswer CallDataType = "answer"
|
||||
)
|
||||
|
||||
type CallData struct {
|
||||
SDP string `json:"sdp"`
|
||||
Type CallDataType `json:"type"`
|
||||
}
|
||||
|
||||
type CallCandidate struct {
|
||||
Candidate string `json:"candidate"`
|
||||
SDPMLineIndex int `json:"sdpMLineIndex"`
|
||||
SDPMID string `json:"sdpMid"`
|
||||
}
|
||||
|
||||
type CallVersion string
|
||||
|
||||
func (cv *CallVersion) UnmarshalJSON(raw []byte) error {
|
||||
var numberVersion int
|
||||
err := json.Unmarshal(raw, &numberVersion)
|
||||
if err != nil {
|
||||
var stringVersion string
|
||||
err = json.Unmarshal(raw, &stringVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse CallVersion: %w", err)
|
||||
}
|
||||
*cv = CallVersion(stringVersion)
|
||||
} else {
|
||||
*cv = CallVersion(strconv.Itoa(numberVersion))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cv *CallVersion) MarshalJSON() ([]byte, error) {
|
||||
for _, char := range *cv {
|
||||
if char < '0' || char > '9' {
|
||||
// The version contains weird characters, return as string.
|
||||
return json.Marshal(string(*cv))
|
||||
}
|
||||
}
|
||||
// The version consists of only ASCII digits, return as an integer.
|
||||
return []byte(*cv), nil
|
||||
}
|
||||
|
||||
func (cv *CallVersion) Int() (int, error) {
|
||||
return strconv.Atoi(string(*cv))
|
||||
}
|
||||
|
||||
type BaseCallEventContent struct {
|
||||
CallID string `json:"call_id"`
|
||||
PartyID string `json:"party_id"`
|
||||
Version CallVersion `json:"version"`
|
||||
}
|
||||
|
||||
type CallInviteEventContent struct {
|
||||
BaseCallEventContent
|
||||
Lifetime int `json:"lifetime"`
|
||||
Offer CallData `json:"offer"`
|
||||
}
|
||||
|
||||
type CallCandidatesEventContent struct {
|
||||
BaseCallEventContent
|
||||
Candidates []CallCandidate `json:"candidates"`
|
||||
}
|
||||
|
||||
type CallRejectEventContent struct {
|
||||
BaseCallEventContent
|
||||
}
|
||||
|
||||
type CallAnswerEventContent struct {
|
||||
BaseCallEventContent
|
||||
Answer CallData `json:"answer"`
|
||||
}
|
||||
|
||||
type CallSelectAnswerEventContent struct {
|
||||
BaseCallEventContent
|
||||
SelectedPartyID string `json:"selected_party_id"`
|
||||
}
|
||||
|
||||
type CallNegotiateEventContent struct {
|
||||
BaseCallEventContent
|
||||
Lifetime int `json:"lifetime"`
|
||||
Description CallData `json:"description"`
|
||||
}
|
||||
|
||||
type CallHangupEventContent struct {
|
||||
BaseCallEventContent
|
||||
Reason CallHangupReason `json:"reason"`
|
||||
}
|
||||
93
vendor/maunium.net/go/mautrix/filter.go
generated
vendored
Normal file
93
vendor/maunium.net/go/mautrix/filter.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2017 Jan Christian Grünhage
|
||||
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type EventFormat string
|
||||
|
||||
const (
|
||||
EventFormatClient EventFormat = "client"
|
||||
EventFormatFederation EventFormat = "federation"
|
||||
)
|
||||
|
||||
//Filter is used by clients to specify how the server should filter responses to e.g. sync requests
|
||||
//Specified by: https://matrix.org/docs/spec/client_server/r0.6.0.html#filtering
|
||||
type Filter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
EventFields []string `json:"event_fields,omitempty"`
|
||||
EventFormat EventFormat `json:"event_format,omitempty"`
|
||||
Presence FilterPart `json:"presence,omitempty"`
|
||||
Room RoomFilter `json:"room,omitempty"`
|
||||
}
|
||||
|
||||
// RoomFilter is used to define filtering rules for room events
|
||||
type RoomFilter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
Ephemeral FilterPart `json:"ephemeral,omitempty"`
|
||||
IncludeLeave bool `json:"include_leave,omitempty"`
|
||||
NotRooms []id.RoomID `json:"not_rooms,omitempty"`
|
||||
Rooms []id.RoomID `json:"rooms,omitempty"`
|
||||
State FilterPart `json:"state,omitempty"`
|
||||
Timeline FilterPart `json:"timeline,omitempty"`
|
||||
}
|
||||
|
||||
// FilterPart is used to define filtering rules for specific categories of events
|
||||
type FilterPart struct {
|
||||
NotRooms []id.RoomID `json:"not_rooms,omitempty"`
|
||||
Rooms []id.RoomID `json:"rooms,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
NotSenders []id.UserID `json:"not_senders,omitempty"`
|
||||
NotTypes []event.Type `json:"not_types,omitempty"`
|
||||
Senders []id.UserID `json:"senders,omitempty"`
|
||||
Types []event.Type `json:"types,omitempty"`
|
||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
||||
|
||||
LazyLoadMembers bool `json:"lazy_load_members,omitempty"`
|
||||
IncludeRedundantMembers bool `json:"include_redundant_members,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the filter contains valid property values
|
||||
func (filter *Filter) Validate() error {
|
||||
if filter.EventFormat != EventFormatClient && filter.EventFormat != EventFormatFederation {
|
||||
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultFilter returns the default filter used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilter() Filter {
|
||||
return Filter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
EventFields: nil,
|
||||
EventFormat: "client",
|
||||
Presence: DefaultFilterPart(),
|
||||
Room: RoomFilter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
Ephemeral: DefaultFilterPart(),
|
||||
IncludeLeave: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
State: DefaultFilterPart(),
|
||||
Timeline: DefaultFilterPart(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultFilterPart returns the default filter part used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilterPart() FilterPart {
|
||||
return FilterPart{
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
Limit: 20,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
}
|
||||
}
|
||||
19
vendor/maunium.net/go/mautrix/go.mod
generated
vendored
Normal file
19
vendor/maunium.net/go/mautrix/go.mod
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
module maunium.net/go/mautrix
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcutil v1.0.2
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/lib/pq v1.9.0
|
||||
github.com/mattn/go-sqlite3 v1.14.6
|
||||
github.com/russross/blackfriday/v2 v2.1.0
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/tidwall/gjson v1.6.8
|
||||
github.com/tidwall/sjson v1.1.5
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
maunium.net/go/maulogger/v2 v2.2.4
|
||||
)
|
||||
77
vendor/maunium.net/go/mautrix/go.sum
generated
vendored
Normal file
77
vendor/maunium.net/go/mautrix/go.sum
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
|
||||
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
|
||||
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/tidwall/gjson v1.6.8 h1:CTmXMClGYPAmln7652e69B7OLXfTi5ABcPPwjIWUv7w=
|
||||
github.com/tidwall/gjson v1.6.8/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||
github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE=
|
||||
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/sjson v1.1.5 h1:wsUceI/XDyZk3J1FUvuuYlK62zJv2HO2Pzb8A5EWdUE=
|
||||
github.com/tidwall/sjson v1.1.5/go.mod h1:VuJzsZnTowhSxWdOgsAnb886i4AjEyTkk7tNtsL7EYE=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
|
||||
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
maunium.net/go/maulogger/v2 v2.2.4 h1:oV2GDeM4fx1uRysdpDC0FcrPg+thFicSd9XzPcYMbVY=
|
||||
maunium.net/go/maulogger/v2 v2.2.4/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||
133
vendor/maunium.net/go/mautrix/id/contenturi.go
generated
vendored
Normal file
133
vendor/maunium.net/go/mautrix/id/contenturi.go
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package id
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
InvalidContentURI = errors.New("invalid Matrix content URI")
|
||||
InputNotJSONString = errors.New("input doesn't look like a JSON string")
|
||||
)
|
||||
|
||||
// ContentURIString is a string that's expected to be a Matrix content URI.
|
||||
// It's useful for delaying the parsing of the content URI to move errors from the event content
|
||||
// JSON parsing step to a later step where more appropriate errors can be produced.
|
||||
type ContentURIString string
|
||||
|
||||
func (uriString ContentURIString) Parse() (ContentURI, error) {
|
||||
return ParseContentURI(string(uriString))
|
||||
}
|
||||
|
||||
func (uriString ContentURIString) ParseOrIgnore() ContentURI {
|
||||
parsed, _ := ParseContentURI(string(uriString))
|
||||
return parsed
|
||||
}
|
||||
|
||||
// ContentURI represents a Matrix content URI.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#matrix-content-mxc-uris
|
||||
type ContentURI struct {
|
||||
Homeserver string
|
||||
FileID string
|
||||
}
|
||||
|
||||
func MustParseContentURI(uri string) ContentURI {
|
||||
parsed, err := ParseContentURI(uri)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
// ParseContentURI parses a Matrix content URI.
|
||||
func ParseContentURI(uri string) (parsed ContentURI, err error) {
|
||||
if len(uri) == 0 {
|
||||
return
|
||||
} else if !strings.HasPrefix(uri, "mxc://") {
|
||||
err = InvalidContentURI
|
||||
} else if index := strings.IndexRune(uri[6:], '/'); index == -1 || index == len(uri)-7 {
|
||||
err = InvalidContentURI
|
||||
} else {
|
||||
parsed.Homeserver = uri[6 : 6+index]
|
||||
parsed.FileID = uri[6+index+1:]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var mxcBytes = []byte("mxc://")
|
||||
|
||||
func ParseContentURIBytes(uri []byte) (parsed ContentURI, err error) {
|
||||
if len(uri) == 0 {
|
||||
return
|
||||
} else if !bytes.HasPrefix(uri, mxcBytes) {
|
||||
err = InvalidContentURI
|
||||
} else if index := bytes.IndexRune(uri[6:], '/'); index == -1 || index == len(uri)-7 {
|
||||
err = InvalidContentURI
|
||||
} else {
|
||||
parsed.Homeserver = string(uri[6 : 6+index])
|
||||
parsed.FileID = string(uri[6+index+1:])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (uri *ContentURI) UnmarshalJSON(raw []byte) (err error) {
|
||||
if string(raw) == "null" {
|
||||
*uri = ContentURI{}
|
||||
return nil
|
||||
} else if len(raw) < 2 || raw[0] != '"' || raw[len(raw)-1] != '"' {
|
||||
return InputNotJSONString
|
||||
}
|
||||
parsed, err := ParseContentURIBytes(raw[1:len(raw)-1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*uri = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uri *ContentURI) MarshalJSON() ([]byte, error) {
|
||||
if uri.IsEmpty() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(uri.String())
|
||||
}
|
||||
|
||||
func (uri *ContentURI) UnmarshalText(raw []byte) (err error) {
|
||||
parsed, err := ParseContentURIBytes(raw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*uri = parsed
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uri ContentURI) MarshalText() ([]byte, error) {
|
||||
if uri.IsEmpty() {
|
||||
return []byte(""), nil
|
||||
}
|
||||
return []byte(uri.String()), nil
|
||||
}
|
||||
|
||||
func (uri *ContentURI) String() string {
|
||||
if uri.IsEmpty() {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("mxc://%s/%s", uri.Homeserver, uri.FileID)
|
||||
}
|
||||
|
||||
func (uri *ContentURI) CUString() ContentURIString {
|
||||
return ContentURIString(uri.String())
|
||||
}
|
||||
|
||||
func (uri *ContentURI) IsEmpty() bool {
|
||||
return len(uri.Homeserver) == 0 || len(uri.FileID) == 0
|
||||
}
|
||||
114
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
Normal file
114
vendor/maunium.net/go/mautrix/id/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package id
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// OlmMsgType is an Olm message type
|
||||
type OlmMsgType int
|
||||
|
||||
const (
|
||||
OlmMsgTypePreKey OlmMsgType = 0
|
||||
OlmMsgTypeMsg OlmMsgType = 1
|
||||
)
|
||||
|
||||
// Algorithm is a Matrix message encryption algorithm.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#messaging-algorithm-names
|
||||
type Algorithm string
|
||||
|
||||
const (
|
||||
AlgorithmOlmV1 Algorithm = "m.olm.v1.curve25519-aes-sha2"
|
||||
AlgorithmMegolmV1 Algorithm = "m.megolm.v1.aes-sha2"
|
||||
)
|
||||
|
||||
type KeyAlgorithm string
|
||||
|
||||
const (
|
||||
KeyAlgorithmCurve25519 KeyAlgorithm = "curve25519"
|
||||
KeyAlgorithmEd25519 KeyAlgorithm = "ed25519"
|
||||
KeyAlgorithmSignedCurve25519 KeyAlgorithm = "signed_curve25519"
|
||||
)
|
||||
|
||||
type CrossSigningUsage string
|
||||
|
||||
const (
|
||||
XSUsageMaster CrossSigningUsage = "master"
|
||||
XSUsageSelfSigning CrossSigningUsage = "self_signing"
|
||||
XSUsageUserSigning CrossSigningUsage = "user_signing"
|
||||
)
|
||||
|
||||
// A SessionID is an arbitrary string that identifies an Olm or Megolm session.
|
||||
type SessionID string
|
||||
|
||||
func (sessionID SessionID) String() string {
|
||||
return string(sessionID)
|
||||
}
|
||||
|
||||
// Ed25519 is the base64 representation of an Ed25519 public key
|
||||
type Ed25519 string
|
||||
type SigningKey = Ed25519
|
||||
|
||||
func (ed25519 Ed25519) String() string {
|
||||
return string(ed25519)
|
||||
}
|
||||
|
||||
// Curve25519 is the base64 representation of an Curve25519 public key
|
||||
type Curve25519 string
|
||||
type SenderKey = Curve25519
|
||||
type IdentityKey = Curve25519
|
||||
|
||||
func (curve25519 Curve25519) String() string {
|
||||
return string(curve25519)
|
||||
}
|
||||
|
||||
// A DeviceID is an arbitrary string that references a specific device.
|
||||
type DeviceID string
|
||||
|
||||
func (deviceID DeviceID) String() string {
|
||||
return string(deviceID)
|
||||
}
|
||||
|
||||
// A DeviceKeyID is a string formatted as <algorithm>:<device_id> that is used as the key in deviceid-key mappings.
|
||||
type DeviceKeyID string
|
||||
|
||||
func NewDeviceKeyID(algorithm KeyAlgorithm, deviceID DeviceID) DeviceKeyID {
|
||||
return DeviceKeyID(fmt.Sprintf("%s:%s", algorithm, deviceID))
|
||||
}
|
||||
|
||||
func (deviceKeyID DeviceKeyID) String() string {
|
||||
return string(deviceKeyID)
|
||||
}
|
||||
|
||||
func (deviceKeyID DeviceKeyID) Parse() (Algorithm, DeviceID) {
|
||||
index := strings.IndexRune(string(deviceKeyID), ':')
|
||||
if index < 0 || len(deviceKeyID) <= index+1 {
|
||||
return "", ""
|
||||
}
|
||||
return Algorithm(deviceKeyID[:index]), DeviceID(deviceKeyID[index+1:])
|
||||
}
|
||||
|
||||
// A KeyID a string formatted as <keyalgorithm>:<key_id> that is used as the key in one-time-key mappings.
|
||||
type KeyID string
|
||||
|
||||
func NewKeyID(algorithm KeyAlgorithm, keyID string) KeyID {
|
||||
return KeyID(fmt.Sprintf("%s:%s", algorithm, keyID))
|
||||
}
|
||||
|
||||
func (keyID KeyID) String() string {
|
||||
return string(keyID)
|
||||
}
|
||||
|
||||
func (keyID KeyID) Parse() (KeyAlgorithm, string) {
|
||||
index := strings.IndexRune(string(keyID), ':')
|
||||
if index < 0 || len(keyID) <= index+1 {
|
||||
return "", ""
|
||||
}
|
||||
return KeyAlgorithm(keyID[:index]), string(keyID[index+1:])
|
||||
}
|
||||
293
vendor/maunium.net/go/mautrix/id/matrixuri.go
generated
vendored
Normal file
293
vendor/maunium.net/go/mautrix/id/matrixuri.go
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package id
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Errors that can happen when parsing matrix: URIs
|
||||
var (
|
||||
ErrInvalidScheme = errors.New("matrix URI scheme must be exactly 'matrix'")
|
||||
ErrInvalidPartCount = errors.New("matrix URIs must have exactly 2 or 4 segments")
|
||||
ErrInvalidFirstSegment = errors.New("invalid identifier in first segment of matrix URI")
|
||||
ErrEmptySecondSegment = errors.New("the second segment of the matrix URI must not be empty")
|
||||
ErrInvalidThirdSegment = errors.New("invalid identifier in third segment of matrix URI")
|
||||
ErrEmptyFourthSegment = errors.New("the fourth segment of the matrix URI must not be empty when the third segment is present")
|
||||
)
|
||||
|
||||
// Errors that can happen when parsing matrix.to URLs
|
||||
var (
|
||||
ErrNotMatrixTo = errors.New("that URL is not a matrix.to URL")
|
||||
ErrInvalidMatrixToPartCount = errors.New("matrix.to URLs must have exactly 1 or 2 segments")
|
||||
ErrEmptyMatrixToPrimaryIdentifier = errors.New("the primary identifier in the matrix.to URL is empty")
|
||||
ErrInvalidMatrixToPrimaryIdentifier = errors.New("the primary identifier in the matrix.to URL has an invalid sigil")
|
||||
ErrInvalidMatrixToSecondaryIdentifier = errors.New("the secondary identifier in the matrix.to URL has an invalid sigil")
|
||||
)
|
||||
|
||||
var ErrNotMatrixToOrMatrixURI = errors.New("that URL is not a matrix.to URL nor matrix: URI")
|
||||
|
||||
// MatrixURI contains the result of parsing a matrix: URI using ParseMatrixURI
|
||||
type MatrixURI struct {
|
||||
Sigil1 rune
|
||||
Sigil2 rune
|
||||
MXID1 string
|
||||
MXID2 string
|
||||
Via []string
|
||||
Action string
|
||||
}
|
||||
|
||||
// SigilToPathSegment contains a mapping from Matrix identifier sigils to matrix: URI path segments.
|
||||
var SigilToPathSegment = map[rune]string{
|
||||
'$': "e",
|
||||
'#': "r",
|
||||
'!': "roomid",
|
||||
'@': "u",
|
||||
}
|
||||
|
||||
func (uri *MatrixURI) getQuery() url.Values {
|
||||
q := make(url.Values)
|
||||
if uri.Via != nil && len(uri.Via) > 0 {
|
||||
q["via"] = uri.Via
|
||||
}
|
||||
if len(uri.Action) > 0 {
|
||||
q.Set("action", uri.Action)
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
// String converts the parsed matrix: URI back into the string representation.
|
||||
func (uri *MatrixURI) String() string {
|
||||
parts := []string{
|
||||
SigilToPathSegment[uri.Sigil1],
|
||||
uri.MXID1,
|
||||
}
|
||||
if uri.Sigil2 != 0 {
|
||||
parts = append(parts, SigilToPathSegment[uri.Sigil2], uri.MXID2)
|
||||
}
|
||||
return (&url.URL{
|
||||
Scheme: "matrix",
|
||||
Opaque: strings.Join(parts, "/"),
|
||||
RawQuery: uri.getQuery().Encode(),
|
||||
}).String()
|
||||
}
|
||||
|
||||
// MatrixToURL converts to parsed matrix: URI into a matrix.to URL
|
||||
func (uri *MatrixURI) MatrixToURL() string {
|
||||
fragment := fmt.Sprintf("#/%s", url.QueryEscape(uri.PrimaryIdentifier()))
|
||||
if uri.Sigil2 != 0 {
|
||||
fragment = fmt.Sprintf("%s/%s", fragment, url.QueryEscape(uri.SecondaryIdentifier()))
|
||||
}
|
||||
query := uri.getQuery().Encode()
|
||||
if len(query) > 0 {
|
||||
fragment = fmt.Sprintf("%s?%s", fragment, query)
|
||||
}
|
||||
// It would be nice to use URL{...}.String() here, but figuring out the Fragment vs RawFragment stuff is a pain
|
||||
return fmt.Sprintf("https://matrix.to/%s", fragment)
|
||||
}
|
||||
|
||||
// PrimaryIdentifier returns the first Matrix identifier in the URI.
|
||||
// Currently room IDs, room aliases and user IDs can be in the primary identifier slot.
|
||||
func (uri *MatrixURI) PrimaryIdentifier() string {
|
||||
return fmt.Sprintf("%c%s", uri.Sigil1, uri.MXID1)
|
||||
}
|
||||
|
||||
// SecondaryIdentifier returns the second Matrix identifier in the URI.
|
||||
// Currently only event IDs can be in the secondary identifier slot.
|
||||
func (uri *MatrixURI) SecondaryIdentifier() string {
|
||||
if uri.Sigil2 == 0 {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%c%s", uri.Sigil2, uri.MXID2)
|
||||
}
|
||||
|
||||
// UserID returns the user ID from the URI if the primary identifier is a user ID.
|
||||
func (uri *MatrixURI) UserID() UserID {
|
||||
if uri.Sigil1 == '@' {
|
||||
return UserID(uri.PrimaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RoomID returns the room ID from the URI if the primary identifier is a room ID.
|
||||
func (uri *MatrixURI) RoomID() RoomID {
|
||||
if uri.Sigil1 == '!' {
|
||||
return RoomID(uri.PrimaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RoomAlias returns the room alias from the URI if the primary identifier is a room alias.
|
||||
func (uri *MatrixURI) RoomAlias() RoomAlias {
|
||||
if uri.Sigil1 == '#' {
|
||||
return RoomAlias(uri.PrimaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// EventID returns the event ID from the URI if the primary identifier is a room ID or alias and the secondary identifier is an event ID.
|
||||
func (uri *MatrixURI) EventID() EventID {
|
||||
if (uri.Sigil1 == '!' || uri.Sigil1 == '#') && uri.Sigil2 == '$' {
|
||||
return EventID(uri.SecondaryIdentifier())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ParseMatrixURIOrMatrixToURL parses the given matrix.to URL or matrix: URI into a unified representation.
|
||||
func ParseMatrixURIOrMatrixToURL(uri string) (*MatrixURI, error) {
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URI: %w", err)
|
||||
}
|
||||
if parsed.Scheme == "matrix" {
|
||||
return ProcessMatrixURI(parsed)
|
||||
} else if strings.HasSuffix(parsed.Hostname(), "matrix.to") {
|
||||
return ProcessMatrixToURL(parsed)
|
||||
} else {
|
||||
return nil, ErrNotMatrixToOrMatrixURI
|
||||
}
|
||||
}
|
||||
|
||||
// ParseMatrixURI implements the matrix: URI parsing algorithm.
|
||||
//
|
||||
// Currently specified in https://github.com/matrix-org/matrix-doc/blob/master/proposals/2312-matrix-uri.md#uri-parsing-algorithm
|
||||
func ParseMatrixURI(uri string) (*MatrixURI, error) {
|
||||
// Step 1: parse the URI according to RFC 3986
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URI: %w", err)
|
||||
}
|
||||
return ProcessMatrixURI(parsed)
|
||||
}
|
||||
|
||||
// ProcessMatrixURI implements steps 2-7 of the matrix: URI parsing algorithm
|
||||
// (i.e. everything except parsing the URI itself, which is done with url.Parse or ParseMatrixURI)
|
||||
func ProcessMatrixURI(uri *url.URL) (*MatrixURI, error) {
|
||||
// Step 2: check that scheme is exactly `matrix`
|
||||
if uri.Scheme != "matrix" {
|
||||
return nil, ErrInvalidScheme
|
||||
}
|
||||
|
||||
// Step 3: split the path into segments separated by /
|
||||
parts := strings.Split(uri.Opaque, "/")
|
||||
|
||||
// Step 4: Check that the URI contains either 2 or 4 segments
|
||||
if len(parts) != 2 && len(parts) != 4 {
|
||||
return nil, ErrInvalidPartCount
|
||||
}
|
||||
|
||||
var parsed MatrixURI
|
||||
|
||||
// Step 5: Construct the top-level Matrix identifier
|
||||
// a: find the sigil from the first segment
|
||||
switch parts[0] {
|
||||
case "u", "user":
|
||||
parsed.Sigil1 = '@'
|
||||
case "r", "room":
|
||||
parsed.Sigil1 = '#'
|
||||
case "roomid":
|
||||
parsed.Sigil1 = '!'
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: '%s'", ErrInvalidFirstSegment, parts[0])
|
||||
}
|
||||
// b: find the identifier from the second segment
|
||||
if len(parts[1]) == 0 {
|
||||
return nil, ErrEmptySecondSegment
|
||||
}
|
||||
parsed.MXID1 = parts[1]
|
||||
|
||||
// Step 6: if the first part is a room and the URI has 4 segments, construct a second level identifier
|
||||
if (parsed.Sigil1 == '!' || parsed.Sigil1 == '#') && len(parts) == 4 {
|
||||
// a: find the sigil from the third segment
|
||||
switch parts[2] {
|
||||
case "e", "event":
|
||||
parsed.Sigil2 = '$'
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: '%s'", ErrInvalidThirdSegment, parts[0])
|
||||
}
|
||||
|
||||
// b: find the identifier from the fourth segment
|
||||
if len(parts[3]) == 0 {
|
||||
return nil, ErrEmptyFourthSegment
|
||||
}
|
||||
parsed.MXID2 = parts[3]
|
||||
}
|
||||
|
||||
// Step 7: parse the query and extract via and action items
|
||||
via, ok := uri.Query()["via"]
|
||||
if ok && len(via) > 0 {
|
||||
parsed.Via = via
|
||||
}
|
||||
action, ok := uri.Query()["action"]
|
||||
if ok && len(action) > 0 {
|
||||
parsed.Action = action[len(action)-1]
|
||||
}
|
||||
|
||||
return &parsed, nil
|
||||
}
|
||||
|
||||
// ParseMatrixToURL parses a matrix.to URL into the same container as ParseMatrixURI parses matrix: URIs.
|
||||
func ParseMatrixToURL(uri string) (*MatrixURI, error) {
|
||||
parsed, err := url.Parse(uri)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse URL: %w", err)
|
||||
}
|
||||
return ProcessMatrixToURL(parsed)
|
||||
}
|
||||
|
||||
// ProcessMatrixToURL is the equivalent of ProcessMatrixURI for matrix.to URLs.
|
||||
func ProcessMatrixToURL(uri *url.URL) (*MatrixURI, error) {
|
||||
if !strings.HasSuffix(uri.Hostname(), "matrix.to") {
|
||||
return nil, ErrNotMatrixTo
|
||||
}
|
||||
|
||||
initialSplit := strings.SplitN(uri.Fragment, "?", 2)
|
||||
parts := strings.Split(initialSplit[0], "/")
|
||||
if len(initialSplit) > 1 {
|
||||
uri.RawQuery = initialSplit[1]
|
||||
}
|
||||
|
||||
if len(parts) < 2 || len(parts) > 3 {
|
||||
return nil, ErrInvalidMatrixToPartCount
|
||||
}
|
||||
|
||||
if len(parts[1]) == 0 {
|
||||
return nil, ErrEmptyMatrixToPrimaryIdentifier
|
||||
}
|
||||
|
||||
var parsed MatrixURI
|
||||
|
||||
parsed.Sigil1 = rune(parts[1][0])
|
||||
parsed.MXID1 = parts[1][1:]
|
||||
_, isKnown := SigilToPathSegment[parsed.Sigil1]
|
||||
if !isKnown {
|
||||
return nil, ErrInvalidMatrixToPrimaryIdentifier
|
||||
}
|
||||
|
||||
if len(parts) == 3 && len(parts[2]) > 0 {
|
||||
parsed.Sigil2 = rune(parts[2][0])
|
||||
parsed.MXID2 = parts[2][1:]
|
||||
_, isKnown = SigilToPathSegment[parsed.Sigil2]
|
||||
if !isKnown {
|
||||
return nil, ErrInvalidMatrixToSecondaryIdentifier
|
||||
}
|
||||
}
|
||||
|
||||
via, ok := uri.Query()["via"]
|
||||
if ok && len(via) > 0 {
|
||||
parsed.Via = via
|
||||
}
|
||||
action, ok := uri.Query()["action"]
|
||||
if ok && len(action) > 0 {
|
||||
parsed.Action = action[len(action)-1]
|
||||
}
|
||||
|
||||
return &parsed, nil
|
||||
}
|
||||
41
vendor/maunium.net/go/mautrix/id/opaque.go
generated
vendored
Normal file
41
vendor/maunium.net/go/mautrix/id/opaque.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package id
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A RoomID is a string starting with ! that references a specific room.
|
||||
// https://matrix.org/docs/spec/appendices#room-ids-and-event-ids
|
||||
type RoomID string
|
||||
|
||||
// A RoomAlias is a string starting with # that can be resolved into.
|
||||
// https://matrix.org/docs/spec/appendices#room-aliases
|
||||
type RoomAlias string
|
||||
|
||||
func NewRoomAlias(localpart, server string) RoomAlias {
|
||||
return RoomAlias(fmt.Sprintf("#%s:%s", localpart, server))
|
||||
}
|
||||
|
||||
// An EventID is a string starting with $ that references a specific event.
|
||||
//
|
||||
// https://matrix.org/docs/spec/appendices#room-ids-and-event-ids
|
||||
// https://matrix.org/docs/spec/rooms/v4#event-ids
|
||||
type EventID string
|
||||
|
||||
func (roomID RoomID) String() string {
|
||||
return string(roomID)
|
||||
}
|
||||
|
||||
func (roomAlias RoomAlias) String() string {
|
||||
return string(roomAlias)
|
||||
}
|
||||
|
||||
func (eventID EventID) String() string {
|
||||
return string(eventID)
|
||||
}
|
||||
@@ -1,12 +1,95 @@
|
||||
package gomatrix
|
||||
// Copyright (c) 2021 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package id
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UserID represents a Matrix user ID.
|
||||
// https://matrix.org/docs/spec/appendices#user-identifiers
|
||||
type UserID string
|
||||
|
||||
const UserIDMaxLength = 255
|
||||
|
||||
func NewUserID(localpart, homeserver string) UserID {
|
||||
return UserID(fmt.Sprintf("@%s:%s", localpart, homeserver))
|
||||
}
|
||||
|
||||
func NewEncodedUserID(localpart, homeserver string) UserID {
|
||||
return NewUserID(EncodeUserLocalpart(localpart), homeserver)
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidUserID = errors.New("is not a valid user ID")
|
||||
ErrNoncompliantLocalpart = errors.New("contains characters that are not allowed")
|
||||
ErrUserIDTooLong = errors.New("the given user ID is longer than 255 characters")
|
||||
ErrEmptyLocalpart = errors.New("empty localparts are not allowed")
|
||||
)
|
||||
|
||||
// Parse parses the user ID into the localpart and server name.
|
||||
//
|
||||
// Note that this only enforces very basic user ID formatting requirements: user IDs start with
|
||||
// a @, and contain a : after the @. If you want to enforce localpart validity, see the
|
||||
// ParseAndValidate and ValidateUserLocalpart functions.
|
||||
func (userID UserID) Parse() (localpart, homeserver string, err error) {
|
||||
if len(userID) == 0 || userID[0] != '@' || !strings.ContainsRune(string(userID), ':') {
|
||||
// This error wrapping lets you use errors.Is() nicely even though the message contains the user ID
|
||||
err = fmt.Errorf("'%s' %w", userID, ErrInvalidUserID)
|
||||
return
|
||||
}
|
||||
parts := strings.SplitN(string(userID), ":", 2)
|
||||
localpart, homeserver = strings.TrimPrefix(parts[0], "@"), parts[1]
|
||||
return
|
||||
}
|
||||
|
||||
var ValidLocalpartRegex = regexp.MustCompile("^[0-9a-z-.=_/]+$")
|
||||
|
||||
// ValidateUserLocalpart validates a Matrix user ID localpart using the grammar
|
||||
// in https://matrix.org/docs/spec/appendices#user-identifier
|
||||
func ValidateUserLocalpart(localpart string) error {
|
||||
if len(localpart) == 0 {
|
||||
return ErrEmptyLocalpart
|
||||
} else if !ValidLocalpartRegex.MatchString(localpart) {
|
||||
return fmt.Errorf("'%s' %w", localpart, ErrNoncompliantLocalpart)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseAndValidate parses the user ID into the localpart and server name like Parse,
|
||||
// and also validates that the localpart is allowed according to the user identifiers spec.
|
||||
func (userID UserID) ParseAndValidate() (localpart, homeserver string, err error) {
|
||||
localpart, homeserver, err = userID.Parse()
|
||||
if err == nil {
|
||||
err = ValidateUserLocalpart(localpart)
|
||||
}
|
||||
if err == nil && len(userID) > UserIDMaxLength {
|
||||
err = ErrUserIDTooLong
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (userID UserID) ParseAndDecode() (localpart, homeserver string, err error) {
|
||||
localpart, homeserver, err = userID.ParseAndValidate()
|
||||
if err == nil {
|
||||
localpart, err = DecodeUserLocalpart(localpart)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (userID UserID) String() string {
|
||||
return string(userID)
|
||||
}
|
||||
|
||||
const lowerhex = "0123456789abcdef"
|
||||
|
||||
// encode the given byte using quoted-printable encoding (e.g "=2f")
|
||||
@@ -116,15 +199,3 @@ func DecodeUserLocalpart(str string) (string, error) {
|
||||
}
|
||||
return outputBuffer.String(), nil
|
||||
}
|
||||
|
||||
// ExtractUserLocalpart extracts the localpart portion of a user ID.
|
||||
// See http://matrix.org/docs/spec/intro.html#user-identifiers
|
||||
func ExtractUserLocalpart(userID string) (string, error) {
|
||||
if len(userID) == 0 || userID[0] != '@' {
|
||||
return "", fmt.Errorf("%s is not a valid user id", userID)
|
||||
}
|
||||
return strings.TrimPrefix(
|
||||
strings.SplitN(userID, ":", 2)[0], // @foo:bar:8448 => [ "@foo", "bar:8448" ]
|
||||
"@", // remove "@" prefix
|
||||
), nil
|
||||
}
|
||||
124
vendor/maunium.net/go/mautrix/pushrules/action.go
generated
vendored
Normal file
124
vendor/maunium.net/go/mautrix/pushrules/action.go
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pushrules
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// PushActionType is the type of a PushAction
|
||||
type PushActionType string
|
||||
|
||||
// The allowed push action types as specified in spec section 11.12.1.4.1.
|
||||
const (
|
||||
ActionNotify PushActionType = "notify"
|
||||
ActionDontNotify PushActionType = "dont_notify"
|
||||
ActionCoalesce PushActionType = "coalesce"
|
||||
ActionSetTweak PushActionType = "set_tweak"
|
||||
)
|
||||
|
||||
// PushActionTweak is the type of the tweak in SetTweak push actions.
|
||||
type PushActionTweak string
|
||||
|
||||
// The allowed tweak types as specified in spec section 11.12.1.4.1.1.
|
||||
const (
|
||||
TweakSound PushActionTweak = "sound"
|
||||
TweakHighlight PushActionTweak = "highlight"
|
||||
)
|
||||
|
||||
// PushActionArray is an array of PushActions.
|
||||
type PushActionArray []*PushAction
|
||||
|
||||
// PushActionArrayShould contains the important information parsed from a PushActionArray.
|
||||
type PushActionArrayShould struct {
|
||||
// Whether or not the array contained a Notify, DontNotify or Coalesce action type.
|
||||
NotifySpecified bool
|
||||
// Whether or not the event in question should trigger a notification.
|
||||
Notify bool
|
||||
// Whether or not the event in question should be highlighted.
|
||||
Highlight bool
|
||||
|
||||
// Whether or not the event in question should trigger a sound alert.
|
||||
PlaySound bool
|
||||
// The name of the sound to play if PlaySound is true.
|
||||
SoundName string
|
||||
}
|
||||
|
||||
// Should parses this push action array and returns the relevant details wrapped in a PushActionArrayShould struct.
|
||||
func (actions PushActionArray) Should() (should PushActionArrayShould) {
|
||||
for _, action := range actions {
|
||||
switch action.Action {
|
||||
case ActionNotify, ActionCoalesce:
|
||||
should.Notify = true
|
||||
should.NotifySpecified = true
|
||||
case ActionDontNotify:
|
||||
should.Notify = false
|
||||
should.NotifySpecified = true
|
||||
case ActionSetTweak:
|
||||
switch action.Tweak {
|
||||
case TweakHighlight:
|
||||
var ok bool
|
||||
should.Highlight, ok = action.Value.(bool)
|
||||
if !ok {
|
||||
// Highlight value not specified, so assume true since the tweak is set.
|
||||
should.Highlight = true
|
||||
}
|
||||
case TweakSound:
|
||||
should.SoundName = action.Value.(string)
|
||||
should.PlaySound = len(should.SoundName) > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PushAction is a single action that should be triggered when receiving a message.
|
||||
type PushAction struct {
|
||||
Action PushActionType
|
||||
Tweak PushActionTweak
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses JSON into this PushAction.
|
||||
//
|
||||
// * If the JSON is a single string, the value is stored in the Action field.
|
||||
// * If the JSON is an object with the set_tweak field, Action will be set to
|
||||
// "set_tweak", Tweak will be set to the value of the set_tweak field and
|
||||
// and Value will be set to the value of the value field.
|
||||
// * In any other case, the function does nothing.
|
||||
func (action *PushAction) UnmarshalJSON(raw []byte) error {
|
||||
var data interface{}
|
||||
|
||||
err := json.Unmarshal(raw, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch val := data.(type) {
|
||||
case string:
|
||||
action.Action = PushActionType(val)
|
||||
case map[string]interface{}:
|
||||
tweak, ok := val["set_tweak"].(string)
|
||||
if ok {
|
||||
action.Action = ActionSetTweak
|
||||
action.Tweak = PushActionTweak(tweak)
|
||||
action.Value, _ = val["value"]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON is the reverse of UnmarshalJSON()
|
||||
func (action *PushAction) MarshalJSON() (raw []byte, err error) {
|
||||
if action.Action == ActionSetTweak {
|
||||
data := map[string]interface{}{
|
||||
"set_tweak": action.Tweak,
|
||||
"value": action.Value,
|
||||
}
|
||||
return json.Marshal(&data)
|
||||
}
|
||||
data := string(action.Action)
|
||||
return json.Marshal(&data)
|
||||
}
|
||||
149
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
Normal file
149
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/pushrules/glob"
|
||||
)
|
||||
|
||||
// Room is an interface with the functions that are needed for processing room-specific push conditions
|
||||
type Room interface {
|
||||
GetOwnDisplayname() string
|
||||
GetMemberCount() int
|
||||
}
|
||||
|
||||
// PushCondKind is the type of a push condition.
|
||||
type PushCondKind string
|
||||
|
||||
// The allowed push condition kinds as specified in section 11.12.1.4.3 of r0.3.0 of the Client-Server API.
|
||||
const (
|
||||
KindEventMatch PushCondKind = "event_match"
|
||||
KindContainsDisplayName PushCondKind = "contains_display_name"
|
||||
KindRoomMemberCount PushCondKind = "room_member_count"
|
||||
)
|
||||
|
||||
// PushCondition wraps a condition that is required for a specific PushRule to be used.
|
||||
type PushCondition struct {
|
||||
// The type of the condition.
|
||||
Kind PushCondKind `json:"kind"`
|
||||
// The dot-separated field of the event to match. Only applicable if kind is EventMatch.
|
||||
Key string `json:"key,omitempty"`
|
||||
// The glob-style pattern to match the field against. Only applicable if kind is EventMatch.
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
// The condition that needs to be fulfilled for RoomMemberCount-type conditions.
|
||||
// A decimal integer optionally prefixed by ==, <, >, >= or <=. Prefix "==" is assumed if no prefix found.
|
||||
MemberCountCondition string `json:"is,omitempty"`
|
||||
}
|
||||
|
||||
// MemberCountFilterRegex is the regular expression to parse the MemberCountCondition of PushConditions.
|
||||
var MemberCountFilterRegex = regexp.MustCompile("^(==|[<>]=?)?([0-9]+)$")
|
||||
|
||||
// Match checks if this condition is fulfilled for the given event in the given room.
|
||||
func (cond *PushCondition) Match(room Room, evt *event.Event) bool {
|
||||
switch cond.Kind {
|
||||
case KindEventMatch:
|
||||
return cond.matchValue(room, evt)
|
||||
case KindContainsDisplayName:
|
||||
return cond.matchDisplayName(room, evt)
|
||||
case KindRoomMemberCount:
|
||||
return cond.matchMemberCount(room)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(room Room, evt *event.Event) bool {
|
||||
index := strings.IndexRune(cond.Key, '.')
|
||||
key := cond.Key
|
||||
subkey := ""
|
||||
if index > 0 {
|
||||
subkey = key[index+1:]
|
||||
key = key[0:index]
|
||||
}
|
||||
|
||||
pattern, err := glob.Compile(cond.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "type":
|
||||
return pattern.MatchString(evt.Type.String())
|
||||
case "sender":
|
||||
return pattern.MatchString(string(evt.Sender))
|
||||
case "room_id":
|
||||
return pattern.MatchString(string(evt.RoomID))
|
||||
case "state_key":
|
||||
if evt.StateKey == nil {
|
||||
return cond.Pattern == ""
|
||||
}
|
||||
return pattern.MatchString(*evt.StateKey)
|
||||
case "content":
|
||||
val, _ := evt.Content.Raw[subkey].(string)
|
||||
return pattern.MatchString(val)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchDisplayName(room Room, evt *event.Event) bool {
|
||||
displayname := room.GetOwnDisplayname()
|
||||
if len(displayname) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
msg, ok := evt.Content.Raw["body"].(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
isAcceptable := func(r uint8) bool {
|
||||
return unicode.IsSpace(rune(r)) || unicode.IsPunct(rune(r))
|
||||
}
|
||||
length := len(displayname)
|
||||
for index := strings.Index(msg, displayname); index != -1; index = strings.Index(msg, displayname) {
|
||||
if (index <= 0 || isAcceptable(msg[index-1])) && (index+length >= len(msg) || isAcceptable(msg[index+length])) {
|
||||
return true
|
||||
}
|
||||
msg = msg[index+len(displayname):]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchMemberCount(room Room) bool {
|
||||
group := MemberCountFilterRegex.FindStringSubmatch(cond.MemberCountCondition)
|
||||
if len(group) != 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
operator := group[1]
|
||||
wantedMemberCount, _ := strconv.Atoi(group[2])
|
||||
|
||||
memberCount := room.GetMemberCount()
|
||||
|
||||
switch operator {
|
||||
case "==", "":
|
||||
return memberCount == wantedMemberCount
|
||||
case ">":
|
||||
return memberCount > wantedMemberCount
|
||||
case ">=":
|
||||
return memberCount >= wantedMemberCount
|
||||
case "<":
|
||||
return memberCount < wantedMemberCount
|
||||
case "<=":
|
||||
return memberCount <= wantedMemberCount
|
||||
default:
|
||||
// Should be impossible due to regex.
|
||||
return false
|
||||
}
|
||||
}
|
||||
2
vendor/maunium.net/go/mautrix/pushrules/doc.go
generated
vendored
Normal file
2
vendor/maunium.net/go/mautrix/pushrules/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package pushrules contains utilities to parse push notification rules.
|
||||
package pushrules
|
||||
22
vendor/maunium.net/go/mautrix/pushrules/glob/LICENSE
generated
vendored
Normal file
22
vendor/maunium.net/go/mautrix/pushrules/glob/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Glob is licensed under the MIT "Expat" License:
|
||||
|
||||
Copyright (c) 2016: Zachary Yedidia.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
28
vendor/maunium.net/go/mautrix/pushrules/glob/README.md
generated
vendored
Normal file
28
vendor/maunium.net/go/mautrix/pushrules/glob/README.md
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# String globbing in Go
|
||||
|
||||
[](http://godoc.org/github.com/zyedidia/glob)
|
||||
|
||||
This package adds support for globs in Go.
|
||||
|
||||
It simply converts glob expressions to regexps. I try to follow the standard defined [here](http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13).
|
||||
|
||||
# Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/zyedidia/glob"
|
||||
|
||||
func main() {
|
||||
glob, err := glob.Compile("{*.go,*.c}")
|
||||
if err != nil {
|
||||
// Error
|
||||
}
|
||||
|
||||
glob.Match([]byte("test.c")) // true
|
||||
glob.Match([]byte("hello.go")) // true
|
||||
glob.Match([]byte("test.d")) // false
|
||||
}
|
||||
```
|
||||
|
||||
You can call all the same functions on a glob that you can call on a regexp.
|
||||
108
vendor/maunium.net/go/mautrix/pushrules/glob/glob.go
generated
vendored
Normal file
108
vendor/maunium.net/go/mautrix/pushrules/glob/glob.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Package glob provides objects for matching strings with globs
|
||||
package glob
|
||||
|
||||
import "regexp"
|
||||
|
||||
// Glob is a wrapper of *regexp.Regexp.
|
||||
// It should contain a glob expression compiled into a regular expression.
|
||||
type Glob struct {
|
||||
*regexp.Regexp
|
||||
}
|
||||
|
||||
// Compile a takes a glob expression as a string and transforms it
|
||||
// into a *Glob object (which is really just a regular expression)
|
||||
// Compile also returns a possible error.
|
||||
func Compile(pattern string) (*Glob, error) {
|
||||
r, err := globToRegex(pattern)
|
||||
return &Glob{r}, err
|
||||
}
|
||||
|
||||
func globToRegex(glob string) (*regexp.Regexp, error) {
|
||||
regex := ""
|
||||
inGroup := 0
|
||||
inClass := 0
|
||||
firstIndexInClass := -1
|
||||
arr := []byte(glob)
|
||||
|
||||
hasGlobCharacters := false
|
||||
|
||||
for i := 0; i < len(arr); i++ {
|
||||
ch := arr[i]
|
||||
|
||||
switch ch {
|
||||
case '\\':
|
||||
i++
|
||||
if i >= len(arr) {
|
||||
regex += "\\"
|
||||
} else {
|
||||
next := arr[i]
|
||||
switch next {
|
||||
case ',':
|
||||
// Nothing
|
||||
case 'Q', 'E':
|
||||
regex += "\\\\"
|
||||
default:
|
||||
regex += "\\"
|
||||
}
|
||||
regex += string(next)
|
||||
}
|
||||
case '*':
|
||||
if inClass == 0 {
|
||||
regex += ".*"
|
||||
} else {
|
||||
regex += "*"
|
||||
}
|
||||
hasGlobCharacters = true
|
||||
case '?':
|
||||
if inClass == 0 {
|
||||
regex += "."
|
||||
} else {
|
||||
regex += "?"
|
||||
}
|
||||
hasGlobCharacters = true
|
||||
case '[':
|
||||
inClass++
|
||||
firstIndexInClass = i + 1
|
||||
regex += "["
|
||||
hasGlobCharacters = true
|
||||
case ']':
|
||||
inClass--
|
||||
regex += "]"
|
||||
case '.', '(', ')', '+', '|', '^', '$', '@', '%':
|
||||
if inClass == 0 || (firstIndexInClass == i && ch == '^') {
|
||||
regex += "\\"
|
||||
}
|
||||
regex += string(ch)
|
||||
hasGlobCharacters = true
|
||||
case '!':
|
||||
if firstIndexInClass == i {
|
||||
regex += "^"
|
||||
} else {
|
||||
regex += "!"
|
||||
}
|
||||
hasGlobCharacters = true
|
||||
case '{':
|
||||
inGroup++
|
||||
regex += "("
|
||||
hasGlobCharacters = true
|
||||
case '}':
|
||||
inGroup--
|
||||
regex += ")"
|
||||
case ',':
|
||||
if inGroup > 0 {
|
||||
regex += "|"
|
||||
hasGlobCharacters = true
|
||||
} else {
|
||||
regex += ","
|
||||
}
|
||||
default:
|
||||
regex += string(ch)
|
||||
}
|
||||
}
|
||||
|
||||
if hasGlobCharacters {
|
||||
return regexp.Compile("^" + regex + "$")
|
||||
} else {
|
||||
return regexp.Compile(regex)
|
||||
}
|
||||
}
|
||||
37
vendor/maunium.net/go/mautrix/pushrules/pushrules.go
generated
vendored
Normal file
37
vendor/maunium.net/go/mautrix/pushrules/pushrules.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
)
|
||||
|
||||
// EventContent represents the content of a m.push_rules account data event.
|
||||
// https://matrix.org/docs/spec/client_server/r0.6.0#m-push-rules
|
||||
type EventContent struct {
|
||||
Ruleset *PushRuleset `json:"global"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
event.TypeMap[event.AccountDataPushRules] = reflect.TypeOf(EventContent{})
|
||||
gob.Register(&EventContent{})
|
||||
}
|
||||
|
||||
// EventToPushRules converts a m.push_rules event to a PushRuleset by passing the data through JSON.
|
||||
func EventToPushRules(evt *event.Event) (*PushRuleset, error) {
|
||||
content := &EventContent{}
|
||||
err := json.Unmarshal(evt.Content.VeryRaw, content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content.Ruleset, nil
|
||||
}
|
||||
154
vendor/maunium.net/go/mautrix/pushrules/rule.go
generated
vendored
Normal file
154
vendor/maunium.net/go/mautrix/pushrules/rule.go
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules/glob"
|
||||
)
|
||||
|
||||
func init() {
|
||||
gob.Register(PushRuleArray{})
|
||||
gob.Register(PushRuleMap{})
|
||||
}
|
||||
|
||||
type PushRuleCollection interface {
|
||||
GetActions(room Room, evt *event.Event) PushActionArray
|
||||
}
|
||||
|
||||
type PushRuleArray []*PushRule
|
||||
|
||||
func (rules PushRuleArray) SetType(typ PushRuleType) PushRuleArray {
|
||||
for _, rule := range rules {
|
||||
rule.Type = typ
|
||||
}
|
||||
return rules
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) GetActions(room Room, evt *event.Event) PushActionArray {
|
||||
for _, rule := range rules {
|
||||
if !rule.Match(room, evt) {
|
||||
continue
|
||||
}
|
||||
return rule.Actions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PushRuleMap struct {
|
||||
Map map[string]*PushRule
|
||||
Type PushRuleType
|
||||
}
|
||||
|
||||
func (rules PushRuleArray) SetTypeAndMap(typ PushRuleType) PushRuleMap {
|
||||
data := PushRuleMap{
|
||||
Map: make(map[string]*PushRule),
|
||||
Type: typ,
|
||||
}
|
||||
for _, rule := range rules {
|
||||
rule.Type = typ
|
||||
data.Map[rule.RuleID] = rule
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) GetActions(room Room, evt *event.Event) PushActionArray {
|
||||
var rule *PushRule
|
||||
var found bool
|
||||
switch ruleMap.Type {
|
||||
case RoomRule:
|
||||
rule, found = ruleMap.Map[string(evt.RoomID)]
|
||||
case SenderRule:
|
||||
rule, found = ruleMap.Map[string(evt.Sender)]
|
||||
}
|
||||
if found && rule.Match(room, evt) {
|
||||
return rule.Actions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ruleMap PushRuleMap) Unmap() PushRuleArray {
|
||||
array := make(PushRuleArray, len(ruleMap.Map))
|
||||
index := 0
|
||||
for _, rule := range ruleMap.Map {
|
||||
array[index] = rule
|
||||
index++
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
type PushRuleType string
|
||||
|
||||
const (
|
||||
OverrideRule PushRuleType = "override"
|
||||
ContentRule PushRuleType = "content"
|
||||
RoomRule PushRuleType = "room"
|
||||
SenderRule PushRuleType = "sender"
|
||||
UnderrideRule PushRuleType = "underride"
|
||||
)
|
||||
|
||||
type PushRule struct {
|
||||
// The type of this rule.
|
||||
Type PushRuleType `json:"-"`
|
||||
// The ID of this rule.
|
||||
// For room-specific rules and user-specific rules, this is the room or user ID (respectively)
|
||||
// For other types of rules, this doesn't affect anything.
|
||||
RuleID string `json:"rule_id"`
|
||||
// The actions this rule should trigger when matched.
|
||||
Actions PushActionArray `json:"actions"`
|
||||
// Whether this is a default rule, or has been set explicitly.
|
||||
Default bool `json:"default"`
|
||||
// Whether or not this push rule is enabled.
|
||||
Enabled bool `json:"enabled"`
|
||||
// The conditions to match in order to trigger this rule.
|
||||
// Only applicable to generic underride/override rules.
|
||||
Conditions []*PushCondition `json:"conditions,omitempty"`
|
||||
// Pattern for content-specific push rules
|
||||
Pattern string `json:"pattern,omitempty"`
|
||||
}
|
||||
|
||||
func (rule *PushRule) Match(room Room, evt *event.Event) bool {
|
||||
if !rule.Enabled {
|
||||
return false
|
||||
}
|
||||
switch rule.Type {
|
||||
case OverrideRule, UnderrideRule:
|
||||
return rule.matchConditions(room, evt)
|
||||
case ContentRule:
|
||||
return rule.matchPattern(room, evt)
|
||||
case RoomRule:
|
||||
return id.RoomID(rule.RuleID) == evt.RoomID
|
||||
case SenderRule:
|
||||
return id.UserID(rule.RuleID) == evt.Sender
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchConditions(room Room, evt *event.Event) bool {
|
||||
for _, cond := range rule.Conditions {
|
||||
if !cond.Match(room, evt) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (rule *PushRule) matchPattern(room Room, evt *event.Event) bool {
|
||||
pattern, err := glob.Compile(rule.Pattern)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
msg, ok := evt.Content.Raw["body"].(string)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return pattern.MatchString(msg)
|
||||
}
|
||||
88
vendor/maunium.net/go/mautrix/pushrules/ruleset.go
generated
vendored
Normal file
88
vendor/maunium.net/go/mautrix/pushrules/ruleset.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package pushrules
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
)
|
||||
|
||||
type PushRuleset struct {
|
||||
Override PushRuleArray
|
||||
Content PushRuleArray
|
||||
Room PushRuleMap
|
||||
Sender PushRuleMap
|
||||
Underride PushRuleArray
|
||||
}
|
||||
|
||||
type rawPushRuleset struct {
|
||||
Override PushRuleArray `json:"override"`
|
||||
Content PushRuleArray `json:"content"`
|
||||
Room PushRuleArray `json:"room"`
|
||||
Sender PushRuleArray `json:"sender"`
|
||||
Underride PushRuleArray `json:"underride"`
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses JSON into this PushRuleset.
|
||||
//
|
||||
// For override, sender and underride push rule arrays, the type is added
|
||||
// to each PushRule and the array is used as-is.
|
||||
//
|
||||
// For room and sender push rule arrays, the type is added to each PushRule
|
||||
// and the array is converted to a map with the rule ID as the key and the
|
||||
// PushRule as the value.
|
||||
func (rs *PushRuleset) UnmarshalJSON(raw []byte) (err error) {
|
||||
data := rawPushRuleset{}
|
||||
err = json.Unmarshal(raw, &data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
rs.Override = data.Override.SetType(OverrideRule)
|
||||
rs.Content = data.Content.SetType(ContentRule)
|
||||
rs.Room = data.Room.SetTypeAndMap(RoomRule)
|
||||
rs.Sender = data.Sender.SetTypeAndMap(SenderRule)
|
||||
rs.Underride = data.Underride.SetType(UnderrideRule)
|
||||
return
|
||||
}
|
||||
|
||||
// MarshalJSON is the reverse of UnmarshalJSON()
|
||||
func (rs *PushRuleset) MarshalJSON() ([]byte, error) {
|
||||
data := rawPushRuleset{
|
||||
Override: rs.Override,
|
||||
Content: rs.Content,
|
||||
Room: rs.Room.Unmap(),
|
||||
Sender: rs.Sender.Unmap(),
|
||||
Underride: rs.Underride,
|
||||
}
|
||||
return json.Marshal(&data)
|
||||
}
|
||||
|
||||
// DefaultPushActions is the value returned if none of the rule
|
||||
// collections in a Ruleset match the event given to GetActions()
|
||||
var DefaultPushActions = PushActionArray{&PushAction{Action: ActionDontNotify}}
|
||||
|
||||
// GetActions matches the given event against all of the push rule
|
||||
// collections in this push ruleset in the order of priority as
|
||||
// specified in spec section 11.12.1.4.
|
||||
func (rs *PushRuleset) GetActions(room Room, evt *event.Event) (match PushActionArray) {
|
||||
// Add push rule collections to array in priority order
|
||||
arrays := []PushRuleCollection{rs.Override, rs.Content, rs.Room, rs.Sender, rs.Underride}
|
||||
// Loop until one of the push rule collections matches the room/event combo.
|
||||
for _, pra := range arrays {
|
||||
if pra == nil {
|
||||
continue
|
||||
}
|
||||
if match = pra.GetActions(room, evt); match != nil {
|
||||
// Match found, return it.
|
||||
return
|
||||
}
|
||||
}
|
||||
// No match found, return default actions.
|
||||
return DefaultPushActions
|
||||
}
|
||||
302
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
Normal file
302
vendor/maunium.net/go/mautrix/requests.go
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"maunium.net/go/mautrix/pushrules"
|
||||
)
|
||||
|
||||
type AuthType string
|
||||
|
||||
const (
|
||||
AuthTypePassword = "m.login.password"
|
||||
AuthTypeReCAPTCHA = "m.login.recaptcha"
|
||||
AuthTypeOAuth2 = "m.login.oauth2"
|
||||
AuthTypeSSO = "m.login.sso"
|
||||
AuthTypeEmail = "m.login.email.identity"
|
||||
AuthTypeMSISDN = "m.login.msisdn"
|
||||
AuthTypeToken = "m.login.token"
|
||||
AuthTypeDummy = "m.login.dummy"
|
||||
|
||||
AuthTypeAppservice = "m.login.application_service"
|
||||
AuthTypeHalfyAppservice = "uk.half-shot.msc2778.login.application_service"
|
||||
)
|
||||
|
||||
type IdentifierType string
|
||||
|
||||
const (
|
||||
IdentifierTypeUser = "m.id.user"
|
||||
IdentifierTypeThirdParty = "m.id.thirdparty"
|
||||
IdentifierTypePhone = "m.id.phone"
|
||||
)
|
||||
|
||||
// ReqRegister is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-register
|
||||
type ReqRegister struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
InitialDeviceDisplayName string `json:"initial_device_display_name,omitempty"`
|
||||
InhibitLogin bool `json:"inhibit_login,omitempty"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
|
||||
// Type for registration, only used for appservice user registrations
|
||||
// https://matrix.org/docs/spec/application_service/r0.1.2#server-admin-style-permissions
|
||||
Type AuthType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type BaseAuthData struct {
|
||||
Type AuthType `json:"type"`
|
||||
Session string `json:"session,omitempty"`
|
||||
}
|
||||
|
||||
type UserIdentifier struct {
|
||||
Type IdentifierType `json:"type"`
|
||||
|
||||
User string `json:"user,omitempty"`
|
||||
|
||||
Medium string `json:"medium,omitempty"`
|
||||
Address string `json:"address,omitempty"`
|
||||
|
||||
Country string `json:"country,omitempty"`
|
||||
Phone string `json:"phone,omitempty"`
|
||||
}
|
||||
|
||||
// ReqLogin is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-login
|
||||
type ReqLogin struct {
|
||||
Type AuthType `json:"type"`
|
||||
Identifier UserIdentifier `json:"identifier"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
InitialDeviceDisplayName string `json:"initial_device_display_name,omitempty"`
|
||||
|
||||
// Whether or not the returned credentials should be stored in the Client
|
||||
StoreCredentials bool `json:"-"`
|
||||
}
|
||||
|
||||
type ReqUIAuthFallback struct {
|
||||
Session string `json:"session"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
type ReqUIAuthLogin struct {
|
||||
BaseAuthData
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// ReqCreateRoom is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type ReqCreateRoom struct {
|
||||
Visibility string `json:"visibility,omitempty"`
|
||||
RoomAliasName string `json:"room_alias_name,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Topic string `json:"topic,omitempty"`
|
||||
Invite []id.UserID `json:"invite,omitempty"`
|
||||
Invite3PID []ReqInvite3PID `json:"invite_3pid,omitempty"`
|
||||
CreationContent map[string]interface{} `json:"creation_content,omitempty"`
|
||||
InitialState []*event.Event `json:"initial_state,omitempty"`
|
||||
Preset string `json:"preset,omitempty"`
|
||||
IsDirect bool `json:"is_direct,omitempty"`
|
||||
}
|
||||
|
||||
// ReqRedact is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-redact-eventid-txnid
|
||||
type ReqRedact struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
TxnID string `json:"-"`
|
||||
}
|
||||
|
||||
type ReqMembers struct {
|
||||
At string `json:"at"`
|
||||
Membership event.Membership `json:"membership,omitempty"`
|
||||
NotMembership event.Membership `json:"not_membership,omitempty"`
|
||||
}
|
||||
|
||||
// ReqInvite3PID is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#id57
|
||||
// It is also a JSON object used in https://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-createroom
|
||||
type ReqInvite3PID struct {
|
||||
IDServer string `json:"id_server"`
|
||||
Medium string `json:"medium"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// ReqInviteUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
type ReqInviteUser struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqKickUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
type ReqKickUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqBanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
type ReqBanUser struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqUnbanUser is the JSON request for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
type ReqUnbanUser struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
// ReqTyping is the JSON request for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
type ReqTyping struct {
|
||||
Typing bool `json:"typing"`
|
||||
Timeout int64 `json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
type ReqPresence struct {
|
||||
Presence event.Presence `json:"presence"`
|
||||
}
|
||||
|
||||
type ReqAliasCreate struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
}
|
||||
|
||||
type OneTimeKey struct {
|
||||
Key id.Curve25519 `json:"key"`
|
||||
IsSigned bool `json:"-"`
|
||||
Signatures Signatures `json:"signatures,omitempty"`
|
||||
Unsigned map[string]interface{} `json:"unsigned,omitempty"`
|
||||
}
|
||||
|
||||
type serializableOTK OneTimeKey
|
||||
|
||||
func (otk *OneTimeKey) UnmarshalJSON(data []byte) (err error) {
|
||||
if len(data) > 0 && data[0] == '"' && data[len(data)-1] == '"' {
|
||||
err = json.Unmarshal(data, &otk.Key)
|
||||
otk.Signatures = nil
|
||||
otk.Unsigned = nil
|
||||
otk.IsSigned = false
|
||||
} else {
|
||||
err = json.Unmarshal(data, (*serializableOTK)(otk))
|
||||
otk.IsSigned = true
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (otk *OneTimeKey) MarshalJSON() ([]byte, error) {
|
||||
if !otk.IsSigned {
|
||||
return json.Marshal(otk.Key)
|
||||
} else {
|
||||
return json.Marshal((*serializableOTK)(otk))
|
||||
}
|
||||
}
|
||||
|
||||
type ReqUploadKeys struct {
|
||||
DeviceKeys *DeviceKeys `json:"device_keys,omitempty"`
|
||||
OneTimeKeys map[id.KeyID]OneTimeKey `json:"one_time_keys"`
|
||||
}
|
||||
|
||||
type ReqKeysSignatures struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
DeviceID id.DeviceID `json:"device_id,omitempty"`
|
||||
Algorithms []id.Algorithm `json:"algorithms,omitempty"`
|
||||
Usage []id.CrossSigningUsage `json:"usage,omitempty"`
|
||||
Keys map[id.KeyID]string `json:"keys"`
|
||||
Signatures Signatures `json:"signatures"`
|
||||
}
|
||||
|
||||
type ReqUploadSignatures map[id.UserID]map[string]ReqKeysSignatures
|
||||
|
||||
type DeviceKeys struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
Algorithms []id.Algorithm `json:"algorithms"`
|
||||
Keys KeyMap `json:"keys"`
|
||||
Signatures Signatures `json:"signatures"`
|
||||
Unsigned map[string]interface{} `json:"unsigned,omitempty"`
|
||||
}
|
||||
|
||||
type CrossSigningKeys struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
Usage []id.CrossSigningUsage `json:"usage"`
|
||||
Keys map[id.KeyID]id.Ed25519 `json:"keys"`
|
||||
Signatures map[id.UserID]map[id.KeyID]string `json:"signatures,omitempty"`
|
||||
}
|
||||
|
||||
func (csk *CrossSigningKeys) FirstKey() id.Ed25519 {
|
||||
for _, key := range csk.Keys {
|
||||
return key
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type UploadCrossSigningKeysReq struct {
|
||||
Master CrossSigningKeys `json:"master_key"`
|
||||
SelfSigning CrossSigningKeys `json:"self_signing_key"`
|
||||
UserSigning CrossSigningKeys `json:"user_signing_key"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type KeyMap map[id.DeviceKeyID]string
|
||||
|
||||
func (km KeyMap) GetEd25519(deviceID id.DeviceID) id.Ed25519 {
|
||||
val, ok := km[id.NewDeviceKeyID(id.KeyAlgorithmEd25519, deviceID)]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return id.Ed25519(val)
|
||||
}
|
||||
|
||||
func (km KeyMap) GetCurve25519(deviceID id.DeviceID) id.Curve25519 {
|
||||
val, ok := km[id.NewDeviceKeyID(id.KeyAlgorithmCurve25519, deviceID)]
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return id.Curve25519(val)
|
||||
}
|
||||
|
||||
type Signatures map[id.UserID]map[id.KeyID]string
|
||||
|
||||
type ReqQueryKeys struct {
|
||||
DeviceKeys DeviceKeysRequest `json:"device_keys"`
|
||||
|
||||
Timeout int64 `json:"timeout,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
type DeviceKeysRequest map[id.UserID]DeviceIDList
|
||||
|
||||
type DeviceIDList []id.DeviceID
|
||||
|
||||
type ReqClaimKeys struct {
|
||||
OneTimeKeys OneTimeKeysRequest `json:"one_time_keys"`
|
||||
|
||||
Timeout int64 `json:"timeout,omitempty"`
|
||||
}
|
||||
|
||||
type OneTimeKeysRequest map[id.UserID]map[id.DeviceID]id.KeyAlgorithm
|
||||
|
||||
type ReqSendToDevice struct {
|
||||
Messages map[id.UserID]map[id.DeviceID]*event.Content `json:"messages"`
|
||||
}
|
||||
|
||||
// ReqDeviceInfo is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#put-matrix-client-r0-devices-deviceid
|
||||
type ReqDeviceInfo struct {
|
||||
DisplayName string `json:"display_name,omitempty"`
|
||||
}
|
||||
|
||||
// ReqDeleteDevice is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#delete-matrix-client-r0-devices-deviceid
|
||||
type ReqDeleteDevice struct {
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
// ReqDeleteDevices is the JSON request for https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-delete-devices
|
||||
type ReqDeleteDevices struct {
|
||||
Devices []id.DeviceID `json:"devices"`
|
||||
Auth interface{} `json:"auth,omitempty"`
|
||||
}
|
||||
|
||||
type ReqPutPushRule struct {
|
||||
Before string `json:"-"`
|
||||
After string `json:"-"`
|
||||
|
||||
Actions []pushrules.PushActionType `json:"actions"`
|
||||
Conditions []pushrules.PushCondition `json:"conditions"`
|
||||
Pattern string `json:"pattern"`
|
||||
}
|
||||
291
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
Normal file
291
vendor/maunium.net/go/mautrix/responses.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// RespWhoami is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-account-whoami
|
||||
type RespWhoami struct {
|
||||
UserID id.UserID `json:"user_id"`
|
||||
// N.B. This field is not in the spec yet, it's expected to land in r0.6.2 or r0.7.0
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
}
|
||||
|
||||
// RespCreateFilter is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-user-userid-filter
|
||||
type RespCreateFilter struct {
|
||||
FilterID string `json:"filter_id"`
|
||||
}
|
||||
|
||||
// RespVersions is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.1.html#get-matrix-client-versions
|
||||
type RespVersions struct {
|
||||
Versions []string `json:"versions"`
|
||||
UnstableFeatures map[string]bool `json:"unstable_features"`
|
||||
}
|
||||
|
||||
// RespJoinRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-join
|
||||
type RespJoinRoom struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
}
|
||||
|
||||
// RespLeaveRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-leave
|
||||
type RespLeaveRoom struct{}
|
||||
|
||||
// RespForgetRoom is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-forget
|
||||
type RespForgetRoom struct{}
|
||||
|
||||
// RespInviteUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-invite
|
||||
type RespInviteUser struct{}
|
||||
|
||||
// RespKickUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-kick
|
||||
type RespKickUser struct{}
|
||||
|
||||
// RespBanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-ban
|
||||
type RespBanUser struct{}
|
||||
|
||||
// RespUnbanUser is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-rooms-roomid-unban
|
||||
type RespUnbanUser struct{}
|
||||
|
||||
// RespTyping is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-typing-userid
|
||||
type RespTyping struct{}
|
||||
|
||||
// RespPresence is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-presence-userid-status
|
||||
type RespPresence struct {
|
||||
Presence event.Presence `json:"presence"`
|
||||
LastActiveAgo int `json:"last_active_ago"`
|
||||
StatusMsg string `json:"status_msg"`
|
||||
CurrentlyActive bool `json:"currently_active"`
|
||||
}
|
||||
|
||||
// RespJoinedRooms is the JSON response for https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-joined-rooms
|
||||
type RespJoinedRooms struct {
|
||||
JoinedRooms []id.RoomID `json:"joined_rooms"`
|
||||
}
|
||||
|
||||
// RespJoinedMembers is the JSON response for https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-joined-rooms
|
||||
type RespJoinedMembers struct {
|
||||
Joined map[id.UserID]struct {
|
||||
DisplayName *string `json:"display_name"`
|
||||
AvatarURL *string `json:"avatar_url"`
|
||||
} `json:"joined"`
|
||||
}
|
||||
|
||||
// RespMessages is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-messages
|
||||
type RespMessages struct {
|
||||
Start string `json:"start"`
|
||||
Chunk []*event.Event `json:"chunk"`
|
||||
State []*event.Event `json:"state"`
|
||||
End string `json:"end"`
|
||||
}
|
||||
|
||||
// RespSendEvent is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
|
||||
type RespSendEvent struct {
|
||||
EventID id.EventID `json:"event_id"`
|
||||
}
|
||||
|
||||
// RespMediaUpload is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-media-r0-upload
|
||||
type RespMediaUpload struct {
|
||||
ContentURI id.ContentURI `json:"content_uri"`
|
||||
}
|
||||
|
||||
// RespUserInteractive is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#user-interactive-authentication-api
|
||||
type RespUserInteractive struct {
|
||||
Flows []struct {
|
||||
Stages []AuthType `json:"stages"`
|
||||
} `json:"flows"`
|
||||
Params map[AuthType]interface{} `json:"params"`
|
||||
Session string `json:"session"`
|
||||
Completed []string `json:"completed"`
|
||||
|
||||
ErrCode string `json:"errcode"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
// HasSingleStageFlow returns true if there exists at least 1 Flow with a single stage of stageName.
|
||||
func (r RespUserInteractive) HasSingleStageFlow(stageName AuthType) bool {
|
||||
for _, f := range r.Flows {
|
||||
if len(f.Stages) == 1 && f.Stages[0] == stageName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RespUserDisplayName is the JSON response for https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-profile-userid-displayname
|
||||
type RespUserDisplayName struct {
|
||||
DisplayName string `json:"displayname"`
|
||||
}
|
||||
|
||||
// RespRegister is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-register
|
||||
type RespRegister struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
HomeServer string `json:"home_server"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
}
|
||||
|
||||
type RespLoginFlows struct {
|
||||
Flows []struct {
|
||||
Type AuthType `json:"type"`
|
||||
} `json:"flows"`
|
||||
}
|
||||
|
||||
func (rlf *RespLoginFlows) HasFlow(flowType AuthType) bool {
|
||||
for _, flow := range rlf.Flows {
|
||||
if flow.Type == flowType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RespLogin is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-login
|
||||
type RespLogin struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
UserID id.UserID `json:"user_id"`
|
||||
// TODO add .well-known field here
|
||||
}
|
||||
|
||||
// RespLogout is the JSON response for http://matrix.org/docs/spec/client_server/r0.2.0.html#post-matrix-client-r0-logout
|
||||
type RespLogout struct{}
|
||||
|
||||
// RespCreateRoom is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.0.html#post-matrix-client-r0-createroom
|
||||
type RespCreateRoom struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
}
|
||||
|
||||
type RespMembers struct {
|
||||
Chunk []*event.Event `json:"chunk"`
|
||||
}
|
||||
|
||||
type LazyLoadSummary struct {
|
||||
Heroes []id.UserID `json:"m.heroes,omitempty"`
|
||||
JoinedMemberCount *int `json:"m.joined_member_count,omitempty"`
|
||||
InvitedMemberCount *int `json:"m.invited_member_count,omitempty"`
|
||||
}
|
||||
|
||||
// RespSync is the JSON response for http://matrix.org/docs/spec/client_server/r0.6.0.html#get-matrix-client-r0-sync
|
||||
type RespSync struct {
|
||||
NextBatch string `json:"next_batch"`
|
||||
|
||||
AccountData struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"account_data"`
|
||||
Presence struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"presence"`
|
||||
ToDevice struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"to_device"`
|
||||
|
||||
DeviceLists struct {
|
||||
Changed []id.UserID `json:"changed"`
|
||||
Left []id.UserID `json:"left"`
|
||||
} `json:"device_lists"`
|
||||
DeviceOneTimeKeysCount OneTimeKeysCount `json:"device_one_time_keys_count"`
|
||||
|
||||
Rooms struct {
|
||||
Leave map[id.RoomID]SyncLeftRoom `json:"leave"`
|
||||
Join map[id.RoomID]SyncJoinedRoom `json:"join"`
|
||||
Invite map[id.RoomID]SyncInvitedRoom `json:"invite"`
|
||||
} `json:"rooms"`
|
||||
}
|
||||
|
||||
type OneTimeKeysCount struct {
|
||||
Curve25519 int `json:"curve25519"`
|
||||
SignedCurve25519 int `json:"signed_curve25519"`
|
||||
}
|
||||
|
||||
type SyncLeftRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"state"`
|
||||
Timeline struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
Limited bool `json:"limited"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
} `json:"timeline"`
|
||||
}
|
||||
|
||||
type SyncJoinedRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"state"`
|
||||
Timeline struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
Limited bool `json:"limited"`
|
||||
PrevBatch string `json:"prev_batch"`
|
||||
} `json:"timeline"`
|
||||
Ephemeral struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"ephemeral"`
|
||||
AccountData struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"account_data"`
|
||||
}
|
||||
|
||||
type SyncInvitedRoom struct {
|
||||
Summary LazyLoadSummary `json:"summary"`
|
||||
State struct {
|
||||
Events []*event.Event `json:"events"`
|
||||
} `json:"invite_state"`
|
||||
}
|
||||
|
||||
type RespTurnServer struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
TTL int `json:"ttl"`
|
||||
URIs []string `json:"uris"`
|
||||
}
|
||||
|
||||
type RespAliasCreate struct{}
|
||||
type RespAliasDelete struct{}
|
||||
type RespAliasResolve struct {
|
||||
RoomID id.RoomID `json:"room_id"`
|
||||
Servers []string `json:"servers"`
|
||||
}
|
||||
|
||||
type RespUploadKeys struct {
|
||||
OneTimeKeyCounts OneTimeKeysCount `json:"one_time_key_counts"`
|
||||
}
|
||||
|
||||
type RespQueryKeys struct {
|
||||
Failures map[string]interface{} `json:"failures"`
|
||||
DeviceKeys map[id.UserID]map[id.DeviceID]DeviceKeys `json:"device_keys"`
|
||||
MasterKeys map[id.UserID]CrossSigningKeys `json:"master_keys"`
|
||||
SelfSigningKeys map[id.UserID]CrossSigningKeys `json:"self_signing_keys"`
|
||||
UserSigningKeys map[id.UserID]CrossSigningKeys `json:"user_signing_keys"`
|
||||
}
|
||||
|
||||
type RespClaimKeys struct {
|
||||
Failures map[string]interface{} `json:"failures"`
|
||||
OneTimeKeys map[id.UserID]map[id.DeviceID]map[id.KeyID]OneTimeKey `json:"one_time_keys"`
|
||||
}
|
||||
|
||||
type RespUploadSignatures struct {
|
||||
Failures map[string]interface{} `json:"failures"`
|
||||
}
|
||||
|
||||
type RespKeyChanges struct {
|
||||
Changed []id.UserID `json:"changed"`
|
||||
Left []id.UserID `json:"left"`
|
||||
}
|
||||
|
||||
type RespSendToDevice struct{}
|
||||
|
||||
// RespDevicesInfo is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-devices
|
||||
type RespDevicesInfo struct {
|
||||
Devices []RespDeviceInfo `json:"devices"`
|
||||
}
|
||||
|
||||
// RespDeviceInfo is the JSON response for https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-devices-deviceid
|
||||
type RespDeviceInfo struct {
|
||||
DeviceID id.DeviceID `json:"device_id"`
|
||||
DisplayName string `json:"display_name"`
|
||||
LastSeenIP string `json:"last_seen_ip"`
|
||||
LastSeenTS int64 `json:"last_seen_ts"`
|
||||
}
|
||||
52
vendor/maunium.net/go/mautrix/room.go
generated
vendored
Normal file
52
vendor/maunium.net/go/mautrix/room.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Room represents a single Matrix room.
|
||||
type Room struct {
|
||||
ID id.RoomID
|
||||
State map[event.Type]map[string]*event.Event
|
||||
}
|
||||
|
||||
// UpdateState updates the room's current state with the given Event. This will clobber events based
|
||||
// on the type/state_key combination.
|
||||
func (room Room) UpdateState(evt *event.Event) {
|
||||
_, exists := room.State[evt.Type]
|
||||
if !exists {
|
||||
room.State[evt.Type] = make(map[string]*event.Event)
|
||||
}
|
||||
room.State[evt.Type][*evt.StateKey] = evt
|
||||
}
|
||||
|
||||
// GetStateEvent returns the state event for the given type/state_key combo, or nil.
|
||||
func (room Room) GetStateEvent(eventType event.Type, stateKey string) *event.Event {
|
||||
stateEventMap, _ := room.State[eventType]
|
||||
evt, _ := stateEventMap[stateKey]
|
||||
return evt
|
||||
}
|
||||
|
||||
// GetMembershipState returns the membership state of the given user ID in this room. If there is
|
||||
// no entry for this member, 'leave' is returned for consistency with left users.
|
||||
func (room Room) GetMembershipState(userID id.UserID) event.Membership {
|
||||
state := event.MembershipLeave
|
||||
evt := room.GetStateEvent(event.StateMember, string(userID))
|
||||
if evt != nil {
|
||||
membership, ok := evt.Content.Raw["membership"].(string)
|
||||
if ok {
|
||||
state = event.Membership(membership)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// NewRoom creates a new Room with the given ID
|
||||
func NewRoom(roomID id.RoomID) *Room {
|
||||
// Init the State map and return a pointer to the Room
|
||||
return &Room{
|
||||
ID: roomID,
|
||||
State: make(map[event.Type]map[string]*event.Event),
|
||||
}
|
||||
}
|
||||
162
vendor/maunium.net/go/mautrix/store.go
generated
vendored
Normal file
162
vendor/maunium.net/go/mautrix/store.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Storer is an interface which must be satisfied to store client data.
|
||||
//
|
||||
// You can either write a struct which persists this data to disk, or you can use the
|
||||
// provided "InMemoryStore" which just keeps data around in-memory which is lost on
|
||||
// restarts.
|
||||
type Storer interface {
|
||||
SaveFilterID(userID id.UserID, filterID string)
|
||||
LoadFilterID(userID id.UserID) string
|
||||
SaveNextBatch(userID id.UserID, nextBatchToken string)
|
||||
LoadNextBatch(userID id.UserID) string
|
||||
SaveRoom(room *Room)
|
||||
LoadRoom(roomID id.RoomID) *Room
|
||||
}
|
||||
|
||||
// InMemoryStore implements the Storer interface.
|
||||
//
|
||||
// Everything is persisted in-memory as maps. It is not safe to load/save filter IDs
|
||||
// or next batch tokens on any goroutine other than the syncing goroutine: the one
|
||||
// which called Client.Sync().
|
||||
type InMemoryStore struct {
|
||||
Filters map[id.UserID]string
|
||||
NextBatch map[id.UserID]string
|
||||
Rooms map[id.RoomID]*Room
|
||||
}
|
||||
|
||||
// SaveFilterID to memory.
|
||||
func (s *InMemoryStore) SaveFilterID(userID id.UserID, filterID string) {
|
||||
s.Filters[userID] = filterID
|
||||
}
|
||||
|
||||
// LoadFilterID from memory.
|
||||
func (s *InMemoryStore) LoadFilterID(userID id.UserID) string {
|
||||
return s.Filters[userID]
|
||||
}
|
||||
|
||||
// SaveNextBatch to memory.
|
||||
func (s *InMemoryStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
|
||||
s.NextBatch[userID] = nextBatchToken
|
||||
}
|
||||
|
||||
// LoadNextBatch from memory.
|
||||
func (s *InMemoryStore) LoadNextBatch(userID id.UserID) string {
|
||||
return s.NextBatch[userID]
|
||||
}
|
||||
|
||||
// SaveRoom to memory.
|
||||
func (s *InMemoryStore) SaveRoom(room *Room) {
|
||||
s.Rooms[room.ID] = room
|
||||
}
|
||||
|
||||
// LoadRoom from memory.
|
||||
func (s *InMemoryStore) LoadRoom(roomID id.RoomID) *Room {
|
||||
return s.Rooms[roomID]
|
||||
}
|
||||
|
||||
// UpdateState stores a state event. This can be passed to DefaultSyncer.OnEvent to keep all room state cached.
|
||||
func (s *InMemoryStore) UpdateState(_ EventSource, evt *event.Event) {
|
||||
if !evt.Type.IsState() {
|
||||
return
|
||||
}
|
||||
room := s.LoadRoom(evt.RoomID)
|
||||
if room == nil {
|
||||
room = NewRoom(evt.RoomID)
|
||||
s.SaveRoom(room)
|
||||
}
|
||||
room.UpdateState(evt)
|
||||
}
|
||||
|
||||
// NewInMemoryStore constructs a new InMemoryStore.
|
||||
func NewInMemoryStore() *InMemoryStore {
|
||||
return &InMemoryStore{
|
||||
Filters: make(map[id.UserID]string),
|
||||
NextBatch: make(map[id.UserID]string),
|
||||
Rooms: make(map[id.RoomID]*Room),
|
||||
}
|
||||
}
|
||||
|
||||
// AccountDataStore uses account data to store the next batch token, and
|
||||
// reuses the InMemoryStore for all other operations.
|
||||
type AccountDataStore struct {
|
||||
*InMemoryStore
|
||||
eventType string
|
||||
client *Client
|
||||
}
|
||||
|
||||
type accountData struct {
|
||||
NextBatch string `json:"next_batch"`
|
||||
}
|
||||
|
||||
// SaveNextBatch to account data.
|
||||
func (s *AccountDataStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
|
||||
if userID.String() != s.client.UserID.String() {
|
||||
panic("AccountDataStore must only be used with bots")
|
||||
}
|
||||
|
||||
data := accountData{
|
||||
NextBatch: nextBatchToken,
|
||||
}
|
||||
|
||||
err := s.client.SetAccountData(s.eventType, data)
|
||||
if err != nil {
|
||||
if s.client.Logger != nil {
|
||||
s.client.Logger.Debugfln("failed to save next batch token to account data: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LoadNextBatch from account data.
|
||||
func (s *AccountDataStore) LoadNextBatch(userID id.UserID) string {
|
||||
if userID.String() != s.client.UserID.String() {
|
||||
panic("AccountDataStore must only be used with bots")
|
||||
}
|
||||
|
||||
data := &accountData{}
|
||||
|
||||
err := s.client.GetAccountData(s.eventType, data)
|
||||
if err != nil {
|
||||
if s.client.Logger != nil {
|
||||
s.client.Logger.Debugfln("failed to load next batch token to account data: %s", err.Error())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
return data.NextBatch
|
||||
}
|
||||
|
||||
// NewAccountDataStore returns a new AccountDataStore, which stores
|
||||
// the next_batch token as a custom event in account data in the
|
||||
// homeserver.
|
||||
//
|
||||
// AccountDataStore is only appropriate for bots, not appservices.
|
||||
//
|
||||
// eventType should be a reversed DNS name like tld.domain.sub.internal and
|
||||
// must be unique for a client. The data stored in it is considered internal
|
||||
// and must not be modified through outside means. You should also add a filter
|
||||
// for account data changes of this event type, to avoid ending up in a sync
|
||||
// loop:
|
||||
//
|
||||
// mautrix.Filter{
|
||||
// AccountData: mautrix.FilterPart{
|
||||
// Limit: 20,
|
||||
// NotTypes: []event.Type{
|
||||
// event.NewEventType(eventType),
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
// mautrix.Client.CreateFilter(...)
|
||||
//
|
||||
func NewAccountDataStore(eventType string, client *Client) *AccountDataStore {
|
||||
return &AccountDataStore{
|
||||
InMemoryStore: NewInMemoryStore(),
|
||||
eventType: eventType,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
283
vendor/maunium.net/go/mautrix/sync.go
generated
vendored
Normal file
283
vendor/maunium.net/go/mautrix/sync.go
generated
vendored
Normal file
@@ -0,0 +1,283 @@
|
||||
// Copyright (c) 2020 Tulir Asokan
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package mautrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// EventSource represents the part of the sync response that an event came from.
|
||||
type EventSource int
|
||||
|
||||
const (
|
||||
EventSourcePresence EventSource = 1 << iota
|
||||
EventSourceJoin
|
||||
EventSourceInvite
|
||||
EventSourceLeave
|
||||
EventSourceAccountData
|
||||
EventSourceTimeline
|
||||
EventSourceState
|
||||
EventSourceEphemeral
|
||||
EventSourceToDevice
|
||||
)
|
||||
|
||||
func (es EventSource) String() string {
|
||||
switch {
|
||||
case es == EventSourcePresence:
|
||||
return "presence"
|
||||
case es == EventSourceAccountData:
|
||||
return "user account data"
|
||||
case es == EventSourceToDevice:
|
||||
return "to-device"
|
||||
case es&EventSourceJoin != 0:
|
||||
es -= EventSourceJoin
|
||||
switch es {
|
||||
case EventSourceState:
|
||||
return "joined state"
|
||||
case EventSourceTimeline:
|
||||
return "joined timeline"
|
||||
case EventSourceEphemeral:
|
||||
return "room ephemeral (joined)"
|
||||
case EventSourceAccountData:
|
||||
return "room account data (joined)"
|
||||
}
|
||||
case es&EventSourceInvite != 0:
|
||||
es -= EventSourceInvite
|
||||
switch es {
|
||||
case EventSourceState:
|
||||
return "invited state"
|
||||
}
|
||||
case es&EventSourceLeave != 0:
|
||||
es -= EventSourceLeave
|
||||
switch es {
|
||||
case EventSourceState:
|
||||
return "left state"
|
||||
case EventSourceTimeline:
|
||||
return "left timeline"
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("unknown (%d)", es)
|
||||
}
|
||||
|
||||
// EventHandler handles a single event from a sync response.
|
||||
type EventHandler func(source EventSource, evt *event.Event)
|
||||
|
||||
// SyncHandler handles a whole sync response. If the return value is false, handling will be stopped completely.
|
||||
type SyncHandler func(resp *RespSync, since string) bool
|
||||
|
||||
// Syncer is an interface that must be satisfied in order to do /sync requests on a client.
|
||||
type Syncer interface {
|
||||
// Process the /sync response. The since parameter is the since= value that was used to produce the response.
|
||||
// This is useful for detecting the very first sync (since=""). If an error is return, Syncing will be stopped
|
||||
// permanently.
|
||||
ProcessResponse(resp *RespSync, since string) error
|
||||
// OnFailedSync returns either the time to wait before retrying or an error to stop syncing permanently.
|
||||
OnFailedSync(res *RespSync, err error) (time.Duration, error)
|
||||
// GetFilterJSON for the given user ID. NOT the filter ID.
|
||||
GetFilterJSON(userID id.UserID) *Filter
|
||||
}
|
||||
|
||||
type ExtensibleSyncer interface {
|
||||
OnSync(callback SyncHandler)
|
||||
OnEvent(callback EventHandler)
|
||||
OnEventType(eventType event.Type, callback EventHandler)
|
||||
}
|
||||
|
||||
// DefaultSyncer is the default syncing implementation. You can either write your own syncer, or selectively
|
||||
// replace parts of this default syncer (e.g. the ProcessResponse method). The default syncer uses the observer
|
||||
// pattern to notify callers about incoming events. See DefaultSyncer.OnEventType for more information.
|
||||
type DefaultSyncer struct {
|
||||
// syncListeners want the whole sync response, e.g. the crypto machine
|
||||
syncListeners []SyncHandler
|
||||
// globalListeners want all events
|
||||
globalListeners []EventHandler
|
||||
// listeners want a specific event type
|
||||
listeners map[event.Type][]EventHandler
|
||||
// ParseEventContent determines whether or not event content should be parsed before passing to handlers.
|
||||
ParseEventContent bool
|
||||
// ParseErrorHandler is called when event.Content.ParseRaw returns an error.
|
||||
// If it returns false, the event will not be forwarded to listeners.
|
||||
ParseErrorHandler func(evt *event.Event, err error) bool
|
||||
}
|
||||
|
||||
var _ Syncer = (*DefaultSyncer)(nil)
|
||||
var _ ExtensibleSyncer = (*DefaultSyncer)(nil)
|
||||
|
||||
// NewDefaultSyncer returns an instantiated DefaultSyncer
|
||||
func NewDefaultSyncer() *DefaultSyncer {
|
||||
return &DefaultSyncer{
|
||||
listeners: make(map[event.Type][]EventHandler),
|
||||
syncListeners: []SyncHandler{},
|
||||
globalListeners: []EventHandler{},
|
||||
ParseEventContent: true,
|
||||
ParseErrorHandler: func(evt *event.Event, err error) bool {
|
||||
return false
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessResponse processes the /sync response in a way suitable for bots. "Suitable for bots" means a stream of
|
||||
// unrepeating events. Returns a fatal error if a listener panics.
|
||||
func (s *DefaultSyncer) ProcessResponse(res *RespSync, since string) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("ProcessResponse panicked! since=%s panic=%s\n%s", since, r, debug.Stack())
|
||||
}
|
||||
}()
|
||||
|
||||
for _, listener := range s.syncListeners {
|
||||
if !listener(res, since) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.processSyncEvents("", res.Presence.Events, EventSourcePresence)
|
||||
s.processSyncEvents("", res.AccountData.Events, EventSourceAccountData)
|
||||
|
||||
for roomID, roomData := range res.Rooms.Join {
|
||||
s.processSyncEvents(roomID, roomData.State.Events, EventSourceJoin|EventSourceState)
|
||||
s.processSyncEvents(roomID, roomData.Timeline.Events, EventSourceJoin|EventSourceTimeline)
|
||||
s.processSyncEvents(roomID, roomData.Ephemeral.Events, EventSourceJoin|EventSourceEphemeral)
|
||||
s.processSyncEvents(roomID, roomData.AccountData.Events, EventSourceJoin|EventSourceAccountData)
|
||||
}
|
||||
for roomID, roomData := range res.Rooms.Invite {
|
||||
s.processSyncEvents(roomID, roomData.State.Events, EventSourceInvite|EventSourceState)
|
||||
}
|
||||
for roomID, roomData := range res.Rooms.Leave {
|
||||
s.processSyncEvents(roomID, roomData.State.Events, EventSourceLeave|EventSourceState)
|
||||
s.processSyncEvents(roomID, roomData.Timeline.Events, EventSourceLeave|EventSourceTimeline)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) processSyncEvents(roomID id.RoomID, events []*event.Event, source EventSource) {
|
||||
for _, evt := range events {
|
||||
s.processSyncEvent(roomID, evt, source)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) processSyncEvent(roomID id.RoomID, evt *event.Event, source EventSource) {
|
||||
evt.RoomID = roomID
|
||||
|
||||
// Ensure the type class is correct. It's safe to mutate the class since the event type is not a pointer.
|
||||
// Listeners are keyed by type structs, which means only the correct class will pass.
|
||||
switch {
|
||||
case evt.StateKey != nil:
|
||||
evt.Type.Class = event.StateEventType
|
||||
case source == EventSourcePresence, source&EventSourceEphemeral != 0:
|
||||
evt.Type.Class = event.EphemeralEventType
|
||||
case source&EventSourceAccountData != 0:
|
||||
evt.Type.Class = event.AccountDataEventType
|
||||
case source == EventSourceToDevice:
|
||||
evt.Type.Class = event.ToDeviceEventType
|
||||
default:
|
||||
evt.Type.Class = event.MessageEventType
|
||||
}
|
||||
|
||||
if s.ParseEventContent {
|
||||
err := evt.Content.ParseRaw(evt.Type)
|
||||
if err != nil && !s.ParseErrorHandler(evt, err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s.notifyListeners(source, evt)
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) notifyListeners(source EventSource, evt *event.Event) {
|
||||
for _, fn := range s.globalListeners {
|
||||
fn(source, evt)
|
||||
}
|
||||
listeners, exists := s.listeners[evt.Type]
|
||||
if exists {
|
||||
for _, fn := range listeners {
|
||||
fn(source, evt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnEventType allows callers to be notified when there are new events for the given event type.
|
||||
// There are no duplicate checks.
|
||||
func (s *DefaultSyncer) OnEventType(eventType event.Type, callback EventHandler) {
|
||||
_, exists := s.listeners[eventType]
|
||||
if !exists {
|
||||
s.listeners[eventType] = []EventHandler{}
|
||||
}
|
||||
s.listeners[eventType] = append(s.listeners[eventType], callback)
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) OnSync(callback SyncHandler) {
|
||||
s.syncListeners = append(s.syncListeners, callback)
|
||||
}
|
||||
|
||||
func (s *DefaultSyncer) OnEvent(callback EventHandler) {
|
||||
s.globalListeners = append(s.globalListeners, callback)
|
||||
}
|
||||
|
||||
// OnFailedSync always returns a 10 second wait period between failed /syncs, never a fatal error.
|
||||
func (s *DefaultSyncer) OnFailedSync(res *RespSync, err error) (time.Duration, error) {
|
||||
return 10 * time.Second, nil
|
||||
}
|
||||
|
||||
// GetFilterJSON returns a filter with a timeline limit of 50.
|
||||
func (s *DefaultSyncer) GetFilterJSON(userID id.UserID) *Filter {
|
||||
return &Filter{
|
||||
Room: RoomFilter{
|
||||
Timeline: FilterPart{
|
||||
Limit: 50,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OldEventIgnorer is an utility struct for bots to ignore events from before the bot joined the room.
|
||||
// Create a struct and call Register with your DefaultSyncer to register the sync handler.
|
||||
type OldEventIgnorer struct {
|
||||
UserID id.UserID
|
||||
}
|
||||
|
||||
func (oei *OldEventIgnorer) Register(syncer ExtensibleSyncer) {
|
||||
syncer.OnSync(oei.DontProcessOldEvents)
|
||||
}
|
||||
|
||||
// DontProcessOldEvents returns true if a sync response should be processed. May modify the response to remove
|
||||
// stuff that shouldn't be processed.
|
||||
func (oei *OldEventIgnorer) DontProcessOldEvents(resp *RespSync, since string) bool {
|
||||
if since == "" {
|
||||
return false
|
||||
}
|
||||
// This is a horrible hack because /sync will return the most recent messages for a room
|
||||
// as soon as you /join it. We do NOT want to process those events in that particular room
|
||||
// because they may have already been processed (if you toggle the bot in/out of the room).
|
||||
//
|
||||
// Work around this by inspecting each room's timeline and seeing if an m.room.member event for us
|
||||
// exists and is "join" and then discard processing that room entirely if so.
|
||||
// TODO: We probably want to process messages from after the last join event in the timeline.
|
||||
for roomID, roomData := range resp.Rooms.Join {
|
||||
for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
|
||||
evt := roomData.Timeline.Events[i]
|
||||
if evt.Type == event.StateMember && evt.GetStateKey() == string(oei.UserID) {
|
||||
membership, _ := evt.Content.Raw["membership"].(string)
|
||||
if membership == "join" {
|
||||
_, ok := resp.Rooms.Join[roomID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
delete(resp.Rooms.Join, roomID) // don't re-process messages
|
||||
delete(resp.Rooms.Invite, roomID) // don't re-process invites
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
5
vendor/maunium.net/go/mautrix/version.go
generated
vendored
Normal file
5
vendor/maunium.net/go/mautrix/version.go
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
package mautrix
|
||||
|
||||
const Version = "v0.9.14"
|
||||
|
||||
var DefaultUserAgent = "mautrix-go/" + Version
|
||||
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
@@ -38,6 +38,8 @@ github.com/SevereCloud/vksdk/v2/longpoll-bot
|
||||
github.com/SevereCloud/vksdk/v2/object
|
||||
# github.com/blang/semver v3.5.1+incompatible
|
||||
github.com/blang/semver
|
||||
# github.com/btcsuite/btcutil v1.0.2
|
||||
github.com/btcsuite/btcutil/base58
|
||||
# github.com/d5/tengo/v2 v2.7.0
|
||||
## explicit
|
||||
github.com/d5/tengo/v2
|
||||
@@ -137,7 +139,6 @@ github.com/lrstanley/girc
|
||||
github.com/magiconair/properties
|
||||
# github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
|
||||
## explicit
|
||||
github.com/matrix-org/gomatrix
|
||||
# github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20210403163225-761e8622445d
|
||||
## explicit
|
||||
github.com/matterbridge/Rocket.Chat.Go.SDK/models
|
||||
@@ -325,6 +326,7 @@ golang.org/x/crypto/ed25519/internal/edwards25519
|
||||
golang.org/x/crypto/hkdf
|
||||
golang.org/x/crypto/internal/subtle
|
||||
golang.org/x/crypto/nacl/secretbox
|
||||
golang.org/x/crypto/pbkdf2
|
||||
golang.org/x/crypto/poly1305
|
||||
golang.org/x/crypto/salsa20/salsa
|
||||
golang.org/x/crypto/ssh
|
||||
@@ -445,3 +447,12 @@ layeh.com/gumble/gumble
|
||||
layeh.com/gumble/gumble/MumbleProto
|
||||
layeh.com/gumble/gumble/varint
|
||||
layeh.com/gumble/gumbleutil
|
||||
# maunium.net/go/mautrix v0.9.14
|
||||
## explicit
|
||||
maunium.net/go/mautrix
|
||||
maunium.net/go/mautrix/crypto/attachment
|
||||
maunium.net/go/mautrix/crypto/utils
|
||||
maunium.net/go/mautrix/event
|
||||
maunium.net/go/mautrix/id
|
||||
maunium.net/go/mautrix/pushrules
|
||||
maunium.net/go/mautrix/pushrules/glob
|
||||
|
||||
Reference in New Issue
Block a user