summaryrefslogtreecommitdiffstats
path: root/vendor/maunium.net/go/mautrix/appservice/protocol.go
blob: 7a9891ef3d672772e1d18db60f3d3c0a579b4ae3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) 2023 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 appservice

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"github.com/rs/zerolog"

	"maunium.net/go/mautrix"
	"maunium.net/go/mautrix/event"
	"maunium.net/go/mautrix/id"
)

type OTKCountMap = map[id.UserID]map[id.DeviceID]mautrix.OTKCount
type FallbackKeyMap = map[id.UserID]map[id.DeviceID][]id.KeyAlgorithm

// Transaction contains a list of events.
type Transaction struct {
	Events          []*event.Event `json:"events"`
	EphemeralEvents []*event.Event `json:"ephemeral,omitempty"`
	ToDeviceEvents  []*event.Event `json:"to_device,omitempty"`

	DeviceLists    *mautrix.DeviceLists `json:"device_lists,omitempty"`
	DeviceOTKCount OTKCountMap          `json:"device_one_time_keys_count,omitempty"`
	FallbackKeys   FallbackKeyMap       `json:"device_unused_fallback_key_types,omitempty"`

	MSC2409EphemeralEvents []*event.Event       `json:"de.sorunome.msc2409.ephemeral,omitempty"`
	MSC2409ToDeviceEvents  []*event.Event       `json:"de.sorunome.msc2409.to_device,omitempty"`
	MSC3202DeviceLists     *mautrix.DeviceLists `json:"org.matrix.msc3202.device_lists,omitempty"`
	MSC3202DeviceOTKCount  OTKCountMap          `json:"org.matrix.msc3202.device_one_time_keys_count,omitempty"`
	MSC3202FallbackKeys    FallbackKeyMap       `json:"org.matrix.msc3202.device_unused_fallback_key_types,omitempty"`
}

func (txn *Transaction) MarshalZerologObject(ctx *zerolog.Event) {
	ctx.Int("pdu", len(txn.Events))
	if txn.EphemeralEvents != nil {
		ctx.Int("edu", len(txn.EphemeralEvents))
	} else if txn.MSC2409EphemeralEvents != nil {
		ctx.Int("unstable_edu", len(txn.MSC2409EphemeralEvents))
	}
	if txn.ToDeviceEvents != nil {
		ctx.Int("to_device", len(txn.ToDeviceEvents))
	} else if txn.MSC2409ToDeviceEvents != nil {
		ctx.Int("unstable_to_device", len(txn.MSC2409ToDeviceEvents))
	}
	if len(txn.DeviceOTKCount) > 0 {
		ctx.Int("otk_count_users", len(txn.DeviceOTKCount))
	} else if len(txn.MSC3202DeviceOTKCount) > 0 {
		ctx.Int("unstable_otk_count_users", len(txn.MSC3202DeviceOTKCount))
	}
	if txn.DeviceLists != nil {
		ctx.Int("device_changes", len(txn.DeviceLists.Changed))
	} else if txn.MSC3202DeviceLists != nil {
		ctx.Int("unstable_device_changes", len(txn.MSC3202DeviceLists.Changed))
	}
	if txn.FallbackKeys != nil {
		ctx.Int("fallback_key_users", len(txn.FallbackKeys))
	} else if txn.MSC3202FallbackKeys != nil {
		ctx.Int("unstable_fallback_key_users", len(txn.MSC3202FallbackKeys))
	}
}

func (txn *Transaction) ContentString() string {
	var parts []string
	if len(txn.Events) > 0 {
		parts = append(parts, fmt.Sprintf("%d PDUs", len(txn.Events)))
	}
	if len(txn.EphemeralEvents) > 0 {
		parts = append(parts, fmt.Sprintf("%d EDUs", len(txn.EphemeralEvents)))
	} else if len(txn.MSC2409EphemeralEvents) > 0 {
		parts = append(parts, fmt.Sprintf("%d EDUs (unstable)", len(txn.MSC2409EphemeralEvents)))
	}
	if len(txn.ToDeviceEvents) > 0 {
		parts = append(parts, fmt.Sprintf("%d to-device events", len(txn.ToDeviceEvents)))
	} else if len(txn.MSC2409ToDeviceEvents) > 0 {
		parts = append(parts, fmt.Sprintf("%d to-device events (unstable)", len(txn.MSC2409ToDeviceEvents)))
	}
	if len(txn.DeviceOTKCount) > 0 {
		parts = append(parts, fmt.Sprintf("OTK counts for %d users", len(txn.DeviceOTKCount)))
	} else if len(txn.MSC3202DeviceOTKCount) > 0 {
		parts = append(parts, fmt.Sprintf("OTK counts for %d users (unstable)", len(txn.MSC3202DeviceOTKCount)))
	}
	if txn.DeviceLists != nil {
		parts = append(parts, fmt.Sprintf("%d device list changes", len(txn.DeviceLists.Changed)))
	} else if txn.MSC3202DeviceLists != nil {
		parts = append(parts, fmt.Sprintf("%d device list changes (unstable)", len(txn.MSC3202DeviceLists.Changed)))
	}
	if txn.FallbackKeys != nil {
		parts = append(parts, fmt.Sprintf("unused fallback key counts for %d users", len(txn.FallbackKeys)))
	} else if txn.MSC3202FallbackKeys != nil {
		parts = append(parts, fmt.Sprintf("unused fallback key counts for %d users (unstable)", len(txn.MSC3202FallbackKeys)))
	}
	return strings.Join(parts, ", ")
}

// EventListener is a function that receives events.
type EventListener func(evt *event.Event)

// WriteBlankOK writes a blank OK message as a reply to a HTTP request.
func WriteBlankOK(w http.ResponseWriter) {
	w.Header().Add("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write([]byte("{}"))
}

// Respond responds to a HTTP request with a JSON object.
func Respond(w http.ResponseWriter, data interface{}) error {
	w.Header().Add("Content-Type", "application/json")
	dataStr, err := json.Marshal(data)
	if err != nil {
		return err
	}
	_, err = w.Write(dataStr)
	return err
}

// Error represents a Matrix protocol error.
type Error struct {
	HTTPStatus int       `json:"-"`
	ErrorCode  ErrorCode `json:"errcode"`
	Message    string    `json:"error"`
}

func (err Error) Write(w http.ResponseWriter) {
	w.Header().Add("Content-Type", "application/json")
	w.WriteHeader(err.HTTPStatus)
	_ = Respond(w, &err)
}

// ErrorCode is the machine-readable code in an Error.
type ErrorCode string

// Native ErrorCodes
const (
	ErrUnknownToken ErrorCode = "M_UNKNOWN_TOKEN"
	ErrBadJSON      ErrorCode = "M_BAD_JSON"
	ErrNotJSON      ErrorCode = "M_NOT_JSON"
	ErrUnknown      ErrorCode = "M_UNKNOWN"
)

// Custom ErrorCodes
const (
	ErrNoTransactionID ErrorCode = "NET.MAUNIUM.NO_TRANSACTION_ID"
)