add vendoring
This commit is contained in:
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)
|
||||
}
|
||||
266
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
Normal file
266
vendor/maunium.net/go/mautrix/pushrules/condition.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
// Copyright (c) 2022 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"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
"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
|
||||
}
|
||||
|
||||
// EventfulRoom is an extension of Room to support MSC3664.
|
||||
type EventfulRoom interface {
|
||||
Room
|
||||
GetEvent(id.EventID) *event.Event
|
||||
}
|
||||
|
||||
// PushCondKind is the type of a push condition.
|
||||
type PushCondKind string
|
||||
|
||||
// The allowed push condition kinds as specified in https://spec.matrix.org/v1.2/client-server-api/#conditions-1
|
||||
const (
|
||||
KindEventMatch PushCondKind = "event_match"
|
||||
KindContainsDisplayName PushCondKind = "contains_display_name"
|
||||
KindRoomMemberCount PushCondKind = "room_member_count"
|
||||
|
||||
// MSC3664: https://github.com/matrix-org/matrix-spec-proposals/pull/3664
|
||||
|
||||
KindRelatedEventMatch PushCondKind = "related_event_match"
|
||||
KindUnstableRelatedEventMatch PushCondKind = "im.nheko.msc3664.related_event_match"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
|
||||
// The relation type for related_event_match from MSC3664
|
||||
RelType event.RelationType `json:"rel_type,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 KindRelatedEventMatch, KindUnstableRelatedEventMatch:
|
||||
return cond.matchRelatedEvent(room, evt)
|
||||
case KindContainsDisplayName:
|
||||
return cond.matchDisplayName(room, evt)
|
||||
case KindRoomMemberCount:
|
||||
return cond.matchMemberCount(room)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func splitWithEscaping(s string, separator, escape byte) []string {
|
||||
var token []byte
|
||||
var tokens []string
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == separator {
|
||||
tokens = append(tokens, string(token))
|
||||
token = token[:0]
|
||||
} else if s[i] == escape && i+1 < len(s) {
|
||||
i++
|
||||
token = append(token, s[i])
|
||||
} else {
|
||||
token = append(token, s[i])
|
||||
}
|
||||
}
|
||||
tokens = append(tokens, string(token))
|
||||
return tokens
|
||||
}
|
||||
|
||||
func hackyNestedGet(data map[string]interface{}, path []string) (interface{}, bool) {
|
||||
val, ok := data[path[0]]
|
||||
if len(path) == 1 {
|
||||
// We don't have any more path parts, return the value regardless of whether it exists or not.
|
||||
return val, ok
|
||||
} else if ok {
|
||||
if mapVal, ok := val.(map[string]interface{}); ok {
|
||||
val, ok = hackyNestedGet(mapVal, path[1:])
|
||||
if ok {
|
||||
return val, true
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we don't find the key, try to combine the first two parts.
|
||||
// e.g. if the key is content.m.relates_to.rel_type, we'll first try data["m"], which will fail,
|
||||
// then combine m and relates_to to get data["m.relates_to"], which should succeed.
|
||||
path[1] = path[0] + "." + path[1]
|
||||
return hackyNestedGet(data, path[1:])
|
||||
}
|
||||
|
||||
func stringifyForPushCondition(val interface{}) string {
|
||||
// Implement MSC3862 to allow matching any type of field
|
||||
// https://github.com/matrix-org/matrix-spec-proposals/pull/3862
|
||||
switch typedVal := val.(type) {
|
||||
case string:
|
||||
return typedVal
|
||||
case nil:
|
||||
return "null"
|
||||
case float64:
|
||||
// Floats aren't allowed in Matrix events, but the JSON parser always stores numbers as floats,
|
||||
// so just handle that and convert to int
|
||||
return strconv.FormatInt(int64(typedVal), 10)
|
||||
default:
|
||||
return fmt.Sprint(val)
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchValue(room Room, evt *event.Event) bool {
|
||||
key, subkey, _ := strings.Cut(cond.Key, ".")
|
||||
|
||||
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 false
|
||||
}
|
||||
return pattern.MatchString(*evt.StateKey)
|
||||
case "content":
|
||||
// Split the match key with escaping to implement https://github.com/matrix-org/matrix-spec-proposals/pull/3873
|
||||
splitKey := splitWithEscaping(subkey, '.', '\\')
|
||||
// Then do a hacky nested get that supports combining parts for the backwards-compat part of MSC3873
|
||||
val, ok := hackyNestedGet(evt.Content.Raw, splitKey)
|
||||
if !ok {
|
||||
return cond.Pattern == ""
|
||||
}
|
||||
return pattern.MatchString(stringifyForPushCondition(val))
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) getRelationEventID(relatesTo *event.RelatesTo) id.EventID {
|
||||
if relatesTo == nil {
|
||||
return ""
|
||||
}
|
||||
switch cond.RelType {
|
||||
case "":
|
||||
return relatesTo.EventID
|
||||
case "m.in_reply_to":
|
||||
if relatesTo.IsFallingBack || relatesTo.InReplyTo == nil {
|
||||
return ""
|
||||
}
|
||||
return relatesTo.InReplyTo.EventID
|
||||
default:
|
||||
if relatesTo.Type != cond.RelType {
|
||||
return ""
|
||||
}
|
||||
return relatesTo.EventID
|
||||
}
|
||||
}
|
||||
|
||||
func (cond *PushCondition) matchRelatedEvent(room Room, evt *event.Event) bool {
|
||||
var relatesTo *event.RelatesTo
|
||||
if relatable, ok := evt.Content.Parsed.(event.Relatable); ok {
|
||||
relatesTo = relatable.OptionalGetRelatesTo()
|
||||
} else {
|
||||
res := gjson.GetBytes(evt.Content.VeryRaw, `m\.relates_to`)
|
||||
if res.Exists() && res.IsObject() {
|
||||
_ = json.Unmarshal([]byte(res.Raw), &relatesTo)
|
||||
}
|
||||
}
|
||||
if evtID := cond.getRelationEventID(relatesTo); evtID == "" {
|
||||
return false
|
||||
} else if eventfulRoom, ok := room.(EventfulRoom); !ok {
|
||||
return false
|
||||
} else if evt = eventfulRoom.GetEvent(relatesTo.EventID); evt == nil {
|
||||
return false
|
||||
} else {
|
||||
return cond.matchValue(room, evt)
|
||||
}
|
||||
}
|
||||
|
||||
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://spec.matrix.org/v1.2/client-server-api/#mpush_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
|
||||
}
|
||||
Reference in New Issue
Block a user