ensure email is sanitized before any checks; update deps

This commit is contained in:
Aine 2024-10-28 11:24:39 +02:00
parent 797829a627
commit 20980659e2
No known key found for this signature in database
GPG key ID: 34969C908CCA2804
39 changed files with 546 additions and 167 deletions

16
go.mod
View file

@ -7,15 +7,15 @@ toolchain go1.23.1
require (
github.com/archdx/zerolog-sentry v1.8.4
github.com/emersion/go-msgauth v0.6.8
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6
github.com/emersion/go-smtp v0.21.3
github.com/etkecc/go-env v1.2.1
github.com/etkecc/go-fswatcher v1.0.1
github.com/etkecc/go-healthchecks/v2 v2.2.1
github.com/etkecc/go-linkpearl v0.0.0-20240916112808-1ff87355b2b3
github.com/etkecc/go-healthchecks/v2 v2.2.2
github.com/etkecc/go-linkpearl v0.0.0-20241016081935-715b568101ef
github.com/etkecc/go-mxidwc v1.0.1
github.com/etkecc/go-psd v0.0.0-20241014083754-1bc4ec777ba8
github.com/etkecc/go-secgen v1.3.0
github.com/etkecc/go-secgen v1.4.0
github.com/etkecc/go-validator/v2 v2.2.4
github.com/fsnotify/fsnotify v1.7.0
github.com/gabriel-vasile/mimetype v1.4.6
@ -29,7 +29,7 @@ require (
github.com/rs/zerolog v1.33.0
github.com/swaggo/swag v1.16.3
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c
maunium.net/go/mautrix v0.21.0
maunium.net/go/mautrix v0.21.1
modernc.org/sqlite v1.33.1
)
@ -59,7 +59,7 @@ require (
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
@ -68,8 +68,8 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/yuin/goldmark v1.7.6 // indirect
go.mau.fi/util v0.8.0 // indirect
github.com/yuin/goldmark v1.7.8 // indirect
go.mau.fi/util v0.8.1 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.26.0 // indirect

36
go.sum
View file

@ -26,24 +26,24 @@ github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+m
github.com/emersion/go-msgauth v0.6.8 h1:kW/0E9E8Zx5CdKsERC/WnAvnXvX7q9wTHia1OA4944A=
github.com/emersion/go-msgauth v0.6.8/go.mod h1:YDwuyTCUHu9xxmAeVj0eW4INnwB6NNZoPdLerpSxRrc=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43 h1:hH4PQfOndHDlpzYfLAAfl63E8Le6F2+EL/cdhlkyRJY=
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 h1:oP4q0fw+fOSWn3DfFi4EXdT+B+gTtzx8GC9xsc26Znk=
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.21.3 h1:7uVwagE8iPYE48WhNsng3RRpCUpFvNl39JGNSIyGVMY=
github.com/emersion/go-smtp v0.21.3/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/etkecc/go-env v1.2.1 h1:b/mIa8D1d9hc3rI8h5bEtBHsnKkBZ6UbmYPog3QIPTU=
github.com/etkecc/go-env v1.2.1/go.mod h1:yTs1DWEsllAZYA417r4V+OmMuYinGXtBzKkLGNvCv5c=
github.com/etkecc/go-fswatcher v1.0.1 h1:n9hqtjzTS3ETb9hcZe1EqYA1lkkhlzZlztu3hXwFDQc=
github.com/etkecc/go-fswatcher v1.0.1/go.mod h1:O5TODJ9z6Qb7X+snqHbB+F0Pah6G497Wdg0SFE/UYpE=
github.com/etkecc/go-healthchecks/v2 v2.2.1 h1:veGW/EoFuF4mB9ylHhCB4C98MY2kjl3++wZ7g6KRSXg=
github.com/etkecc/go-healthchecks/v2 v2.2.1/go.mod h1:IowWGN4F6By6z0eh63+639OscylgtdvT9ITjfN6hnZA=
github.com/etkecc/go-linkpearl v0.0.0-20240916112808-1ff87355b2b3 h1:Mkf7lWP0lf5Hv8g4x+p1IJ64kfQYIX85z8dKDjsKeuw=
github.com/etkecc/go-linkpearl v0.0.0-20240916112808-1ff87355b2b3/go.mod h1:lmPUKcFUSGuJ2kwqL9Yc5gWsBKVGQr+smuDCX+BqMWY=
github.com/etkecc/go-healthchecks/v2 v2.2.2 h1:YV7e+Ga8JY3aZX4Qf6Q1Ca+DnqbT5Drjli3PufB4J1g=
github.com/etkecc/go-healthchecks/v2 v2.2.2/go.mod h1:IowWGN4F6By6z0eh63+639OscylgtdvT9ITjfN6hnZA=
github.com/etkecc/go-linkpearl v0.0.0-20241016081935-715b568101ef h1:c+7TLGW847a/7nOxNg8ICXBa8DB3WnnH9mAN9d2Ntuw=
github.com/etkecc/go-linkpearl v0.0.0-20241016081935-715b568101ef/go.mod h1:VEzhQeweZez8RKYSEYQhULddGeaNsaVcuWzlb1k8EFM=
github.com/etkecc/go-mxidwc v1.0.1 h1:t4Kq3FxSlQjt1i7RpzE5q3cOWjJ0vrTzzGZRSpgh8mg=
github.com/etkecc/go-mxidwc v1.0.1/go.mod h1:WFlntcH4mdual/gNi6X7a6rSJERNuLjdrwM3K/tucQA=
github.com/etkecc/go-psd v0.0.0-20241014083754-1bc4ec777ba8 h1:ariQTBlHHe71O507IZ97QSHFrk0Eo2vlMm1skJ97Y7Q=
github.com/etkecc/go-psd v0.0.0-20241014083754-1bc4ec777ba8/go.mod h1:x4ORuml+JdRsska0sXHbpSQAqvQyqDLjXydP5Ax5wBg=
github.com/etkecc/go-secgen v1.3.0 h1:DfytmSQL7W0nL7E0kmgDCrorU7V3e2bT5XBgrIisbbs=
github.com/etkecc/go-secgen v1.3.0/go.mod h1:6dkfdOtmtVxkj1hIJM6U6yA7frSNpr1H5brz5t18Y3I=
github.com/etkecc/go-secgen v1.4.0 h1:PapLpen3aIqG2LDu+U6KWDb4SMW2UGuvetpJjd86yUc=
github.com/etkecc/go-secgen v1.4.0/go.mod h1:6dkfdOtmtVxkj1hIJM6U6yA7frSNpr1H5brz5t18Y3I=
github.com/etkecc/go-trysmtp v1.1.5 h1:MQ4l4bE9nWUqRKoJOalGHGLkb/hRmzbcBMlClufEOng=
github.com/etkecc/go-trysmtp v1.1.5/go.mod h1:J4zQu+kgM37xQY148wUz0Dm6y+YhtzMghAv/AaXt0sQ=
github.com/etkecc/go-validator/v2 v2.2.4 h1:E4sE4FpYPVP6VRvnndni+8qUXbeSuHxkniFsi6uCRFQ=
@ -108,8 +108,8 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWtuw0=
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mcnijman/go-emailaddress v1.1.1 h1:AGhgVDG3tCDaL0/Vc6erlPQjDuDN3dAT7rRdgFtetr0=
github.com/mcnijman/go-emailaddress v1.1.1/go.mod h1:5whZrhS8Xp5LxO8zOD35BC+b76kROtsh+dPomeRt/II=
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a h1:eU8j/ClY2Ty3qdHnn0TyW3ivFoPC/0F1gQZz8yTxbbE=
@ -122,8 +122,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274 h1:qli3BGQK0tYDkSEvZ/FzZTi9ZrOX86Q6CIhKLGc489A=
github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -159,10 +159,10 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/yuin/goldmark v1.7.6 h1:cZgJxVh5mL5cu8KOnwxvFJy5TFB0BHUskZZyq7TYbDg=
github.com/yuin/goldmark v1.7.6/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.mau.fi/util v0.8.0 h1:MiSny8jgQq4XtCLAT64gDJhZVhqiDeMVIEBDFVw+M0g=
go.mau.fi/util v0.8.0/go.mod h1:1Ixb8HWoVbl3rT6nAX6nV4iMkzn7KU/KXwE0Rn5RmsQ=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
go.mau.fi/util v0.8.1 h1:Ga43cz6esQBYqcjZ/onRoVnYWoUwjWbsxVeJg2jOTSo=
go.mau.fi/util v0.8.1/go.mod h1:T1u/rD2rzidVrBLyaUdPpZiJdP/rsyi+aTzn0D+Q6wc=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
@ -203,8 +203,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mautrix v0.21.0 h1:Z6nVu+clkJgj6ANwFYQQ1BtYeVXZPZ9lRgwuFN57gOY=
maunium.net/go/mautrix v0.21.0/go.mod h1:qm9oDhcHxF/Xby5RUuONIGpXw1SXXqLZj/GgvMxJxu0=
maunium.net/go/mautrix v0.21.1 h1:Z+e448jtlY977iC1kokNJTH5kg2WmDpcQCqn+v9oZOA=
maunium.net/go/mautrix v0.21.1/go.mod h1:7F/S6XAdyc/6DW+Q7xyFXRSPb6IjfqMb1OMepQ8C8OE=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.21.0 h1:kKPI3dF7RIag8YcToh5ZwDcVMIv6VGa0ED5cvh0LMW4=

View file

@ -3,6 +3,7 @@ package bot
import (
"context"
"strconv"
"strings"
"time"
"maunium.net/go/mautrix/id"
@ -11,10 +12,12 @@ import (
)
func (b *Bot) addRoom(roomID id.RoomID, cfg config.Room) {
b.rooms.Store(cfg.Mailbox(), roomID)
mailbox := strings.ToLower(strings.TrimSpace(cfg.Mailbox()))
b.rooms.Store(mailbox, roomID)
aliases := cfg.Aliases()
if len(aliases) > 0 {
for _, alias := range aliases {
alias = strings.ToLower(strings.TrimSpace(alias))
b.rooms.Store(alias, roomID)
}
}

View file

@ -25,6 +25,7 @@ func MessageID(eventID id.EventID, domain string) string {
// Address gets email address from a valid email address notation (eg: "Jane Doe" <jane@example.com> -> jane@example.com)
func Address(email string) string {
email = strings.ToLower(strings.TrimSpace(email))
addr, _ := mail.ParseAddress(email) //nolint:errcheck // if it fails here, nothing will help
if addr == nil {
list := AddressList(email)
@ -42,6 +43,7 @@ func AddressList(emailList string) []string {
if emailList == "" {
return []string{}
}
emailList = strings.ToLower(strings.TrimSpace(emailList))
list, _ := mail.ParseAddressList(emailList) //nolint:errcheck // if it fails here, nothing will help
if len(list) == 0 {
return []string{}

View file

@ -26,6 +26,7 @@ func Hostname(email string) string {
// EmailParts parses email address into mailbox, subaddress, and hostname
func EmailParts(email string) (mailbox, sub, hostname string) {
email = strings.ToLower(strings.TrimSpace(email))
address, err := emailaddress.Parse(email)
if err == nil {
mailbox = address.LocalPart

View file

@ -1,7 +1,6 @@
# go-sasl
[![godocs.io](https://godocs.io/github.com/emersion/go-sasl?status.svg)](https://godocs.io/github.com/emersion/go-sasl)
[![Build Status](https://travis-ci.org/emersion/go-sasl.svg?branch=master)](https://travis-ci.org/emersion/go-sasl)
[![Go Reference](https://pkg.go.dev/badge/github.com/emersion/go-sasl.svg)](https://pkg.go.dev/github.com/emersion/go-sasl)
A [SASL](https://tools.ietf.org/html/rfc4422) library written in Go.

View file

@ -36,54 +36,3 @@ func (a *loginClient) Next(challenge []byte) (response []byte, err error) {
func NewLoginClient(username, password string) Client {
return &loginClient{username, password}
}
// Authenticates users with an username and a password.
type LoginAuthenticator func(username, password string) error
type loginState int
const (
loginNotStarted loginState = iota
loginWaitingUsername
loginWaitingPassword
)
type loginServer struct {
state loginState
username, password string
authenticate LoginAuthenticator
}
// A server implementation of the LOGIN authentication mechanism, as described
// in https://tools.ietf.org/html/draft-murchison-sasl-login-00.
//
// LOGIN is obsolete and should only be enabled for legacy clients that cannot
// be updated to use PLAIN.
func NewLoginServer(authenticator LoginAuthenticator) Server {
return &loginServer{authenticate: authenticator}
}
func (a *loginServer) Next(response []byte) (challenge []byte, done bool, err error) {
switch a.state {
case loginNotStarted:
// Check for initial response field, as per RFC4422 section 3
if response == nil {
challenge = []byte("Username:")
break
}
a.state++
fallthrough
case loginWaitingUsername:
a.username = string(response)
challenge = []byte("Password:")
case loginWaitingPassword:
a.password = string(response)
err = a.authenticate(a.username, a.password)
done = true
default:
err = ErrUnexpectedClientResponse
}
a.state++
return
}

View file

@ -1 +1 @@
/testdata
/cover.out

View file

@ -0,0 +1,141 @@
run:
concurrency: 4
timeout: 30m
issues-exit-code: 1
tests: true
build-tags: []
skip-dirs-use-default: true
skip-files: []
modules-download-mode: readonly
output:
formats:
- format: colored-line-number
print-issued-lines: true
print-linter-name: true
sort-results: true
linters-settings:
decorder:
dec-order:
- const
- var
- type
- func
dogsled:
max-blank-identifiers: 3
errcheck:
check-type-assertions: true
check-blank: true
errchkjson:
report-no-exported: true
exhaustive:
check:
- switch
- map
default-signifies-exhaustive: true
gocognit:
min-complexity: 15
nestif:
min-complexity: 5
gocritic:
enabled-tags:
- diagnostic
- style
- performance
gofmt:
simplify: true
rewrite-rules:
- pattern: 'interface{}'
replacement: 'any'
- pattern: 'a[b:len(a)]'
replacement: 'a[b:]'
gofumpt:
extra-rules: true
grouper:
const-require-single-const: true
import-require-single-import: true
var-require-single-var: true
misspell:
locale: US
usestdlibvars:
time-month: true
time-layout: true
crypto-hash: true
default-rpc-path: true
sql-isolation-level: true
tls-signature-scheme: true
constant-kind: true
unparam:
check-exported: true
linters:
disable-all: false
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- decorder
- dogsled
- dupl
- dupword
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- exhaustive
- forcetypeassert
- gocognit
- gocritic
- gocyclo
- gofmt
- gofumpt
- goimports
- gosec
- gosimple
- gosmopolitan
- govet
- ineffassign
- makezero
- mirror
- misspell
- nestif
- nolintlint
- prealloc
- predeclared
- revive
- sqlclosecheck
- staticcheck
- unconvert
- unparam
- unused
- usestdlibvars
- wastedassign
fast: false
issues:
exclude-dirs:
- mocks
exclude-rules:
- path: _test\.go
linters:
- gocyclo
- gocognit
- errcheck
- dupl
- gosec
- linters:
- staticcheck
text: "SA9003:"
- linters:
- lll
source: "^//go:generate "
- linters:
- revive
text: "returns unexported type"
max-issues-per-linter: 0
max-same-issues: 0
new: false

View file

@ -1,6 +1,7 @@
package healthchecks
import (
"errors"
"fmt"
"io"
"net/http"
@ -46,20 +47,25 @@ func (c *Client) init(options ...Option) {
}
if c.uuid == "" {
randomUUID, _ := uuid.NewRandom()
randomUUID, _ := uuid.NewRandom() //nolint:errcheck // ignore error
c.uuid = randomUUID.String()
c.create = true
c.log("uuid", fmt.Errorf("check UUID is not provided, using random %q with auto provision", c.uuid))
}
}
// call API
func (c *Client) call(operation, endpoint string, body ...io.Reader) {
// Call API
func (c *Client) Call(operation, endpoint string, body ...io.Reader) {
if !c.enabled {
return
}
c.wg.Add(1)
go c.call(operation, endpoint, body...)
}
// call API, extracted from c.Call to reduce cyclomatic complexity
func (c *Client) call(operation, endpoint string, body ...io.Reader) {
defer c.wg.Done()
targetURL := fmt.Sprintf("%s/%s%s?rid=%s", c.baseURL, c.uuid, endpoint, c.rid)
@ -94,7 +100,7 @@ func (c *Client) call(operation, endpoint string, body ...io.Reader) {
c.log(operation+":response", rerr)
return
}
rerr = fmt.Errorf(string(respb))
rerr = errors.New(string(respb))
c.log(operation+":response", rerr)
return
}
@ -109,27 +115,27 @@ func (c *Client) SetEnabled(enabled bool) {
// Start signal means the job started
func (c *Client) Start(optionalBody ...io.Reader) {
go c.call("start", "/start", optionalBody...)
c.Call("start", "/start", optionalBody...)
}
// Success signal means the job has completed successfully (or, a continuously running process is still running and healthy).
func (c *Client) Success(optionalBody ...io.Reader) {
go c.call("success", "", optionalBody...)
c.Call("success", "", optionalBody...)
}
// Fail signal means the job failed
func (c *Client) Fail(optionalBody ...io.Reader) {
go c.call("fail", "/fail", optionalBody...)
c.Call("fail", "/fail", optionalBody...)
}
// Log signal just adds an event to the job log, without changing job status
func (c *Client) Log(optionalBody ...io.Reader) {
go c.call("log", "/log", optionalBody...)
c.Call("log", "/log", optionalBody...)
}
// ExitStatus signal sends job's exit code (0-255)
func (c *Client) ExitStatus(exitCode int, optionalBody ...io.Reader) {
go c.call("exit status", "/"+strconv.Itoa(exitCode), optionalBody...)
c.Call("exit status", "/"+strconv.Itoa(exitCode), optionalBody...)
}
// Shutdown the client

View file

@ -26,7 +26,7 @@ var DefaultErrLog = func(operation string, err error) {
// New healthchecks client
func New(options ...Option) *Client {
rid, _ := uuid.NewRandom()
rid, _ := uuid.NewRandom() //nolint:errcheck // ignore error
c := &Client{
rid: rid.String(),
}

View file

@ -4,7 +4,7 @@ default:
# update go deps
update *flags:
go get {{flags}} .
go get {{ flags }} .
go mod tidy
# run linter

View file

@ -2,6 +2,7 @@ package secgen
import (
"crypto/rand"
"crypto/sha512"
"encoding/base64"
"encoding/hex"
"math/big"
@ -23,6 +24,12 @@ func Password(length int) string {
return password.String()
}
// Passphrase generates secure passphrase, based on shared secret and salt
func Passphrase(sharedSecret, salt string) string {
hash := sha512.Sum512([]byte(sharedSecret + salt))
return base64.StdEncoding.EncodeToString(hash[:])[:64]
}
// Base64Bytes generates secure bytes with the given length and returns it as a base64 string
func Base64Bytes(length int) string {
randomBytes := make([]byte, length)

View file

@ -123,6 +123,12 @@ type Node interface {
Dump(source []byte, level int)
// Text returns text values of this node.
// This method is valid only for some inline nodes.
// If this node is a block node, Text returns a text value as reasonable as possible.
// Notice that there are no 'correct' text values for the block nodes.
// Result for the block nodes may be different from your expectation.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Pragraph.Lines, Text.Value).
Text(source []byte) []byte
// HasBlankPreviousLines returns true if the row before this node is blank,
@ -375,10 +381,17 @@ func (n *BaseNode) OwnerDocument() *Document {
}
// Text implements Node.Text .
//
// Deprecated: Use other properties of the node to get the text value(i.e. Pragraph.Lines, Text.Value).
func (n *BaseNode) Text(source []byte) []byte {
var buf bytes.Buffer
for c := n.firstChild; c != nil; c = c.NextSibling() {
buf.Write(c.Text(source))
if sb, ok := c.(interface {
SoftLineBreak() bool
}); ok && sb.SoftLineBreak() {
buf.WriteByte('\n')
}
}
return buf.Bytes()
}

View file

@ -1,7 +1,6 @@
package ast
import (
"bytes"
"fmt"
"strings"
@ -48,15 +47,6 @@ func (b *BaseBlock) SetLines(v *textm.Segments) {
b.lines = v
}
// Text implements Node.Text.
func (b *BaseBlock) Text(source []byte) []byte {
var buf bytes.Buffer
for _, line := range b.Lines().Sliced(0, b.Lines().Len()) {
buf.Write(line.Value(source))
}
return buf.Bytes()
}
// A Document struct is a root node of Markdown text.
type Document struct {
BaseBlock
@ -140,6 +130,13 @@ func (n *TextBlock) Kind() NodeKind {
return KindTextBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. TextBlock.Lines).
func (n *TextBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewTextBlock returns a new TextBlock node.
func NewTextBlock() *TextBlock {
return &TextBlock{
@ -165,6 +162,13 @@ func (n *Paragraph) Kind() NodeKind {
return KindParagraph
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Paragraph.Lines).
func (n *Paragraph) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewParagraph returns a new Paragraph node.
func NewParagraph() *Paragraph {
return &Paragraph{
@ -259,6 +263,13 @@ func (n *CodeBlock) Kind() NodeKind {
return KindCodeBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. CodeBlock.Lines).
func (n *CodeBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewCodeBlock returns a new CodeBlock node.
func NewCodeBlock() *CodeBlock {
return &CodeBlock{
@ -314,6 +325,13 @@ func (n *FencedCodeBlock) Kind() NodeKind {
return KindFencedCodeBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. FencedCodeBlock.Lines).
func (n *FencedCodeBlock) Text(source []byte) []byte {
return n.Lines().Value(source)
}
// NewFencedCodeBlock return a new FencedCodeBlock node.
func NewFencedCodeBlock(info *Text) *FencedCodeBlock {
return &FencedCodeBlock{
@ -508,6 +526,17 @@ func (n *HTMLBlock) Kind() NodeKind {
return KindHTMLBlock
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. HTMLBlock.Lines).
func (n *HTMLBlock) Text(source []byte) []byte {
ret := n.Lines().Value(source)
if n.HasClosure() {
ret = append(ret, n.ClosureLine.Value(source)...)
}
return ret
}
// NewHTMLBlock returns a new HTMLBlock node.
func NewHTMLBlock(typ HTMLBlockType) *HTMLBlock {
return &HTMLBlock{

View file

@ -143,17 +143,25 @@ func (n *Text) Merge(node Node, source []byte) bool {
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. Text.Value).
func (n *Text) Text(source []byte) []byte {
return n.Segment.Value(source)
}
// Value returns a value of this node.
// SoftLineBreaks are not included in the returned value.
func (n *Text) Value(source []byte) []byte {
return n.Segment.Value(source)
}
// Dump implements Node.Dump.
func (n *Text) Dump(source []byte, level int) {
fs := textFlagsString(n.flags)
if len(fs) != 0 {
fs = "(" + fs + ")"
}
fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Text(source)), "\n"))
fmt.Printf("%sText%s: \"%s\"\n", strings.Repeat(" ", level), fs, strings.TrimRight(string(n.Value(source)), "\n"))
}
// KindText is a NodeKind of the Text node.
@ -258,6 +266,8 @@ func (n *String) SetCode(v bool) {
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. String.Value).
func (n *String) Text(source []byte) []byte {
return n.Value
}
@ -492,15 +502,22 @@ func (n *AutoLink) URL(source []byte) []byte {
ret := make([]byte, 0, len(n.Protocol)+s.Len()+3)
ret = append(ret, n.Protocol...)
ret = append(ret, ':', '/', '/')
ret = append(ret, n.value.Text(source)...)
ret = append(ret, n.value.Value(source)...)
return ret
}
return n.value.Text(source)
return n.value.Value(source)
}
// Label returns a label of this node.
func (n *AutoLink) Label(source []byte) []byte {
return n.value.Text(source)
return n.value.Value(source)
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. AutoLink.Label).
func (n *AutoLink) Text(source []byte) []byte {
return n.value.Value(source)
}
// NewAutoLink returns a new AutoLink node.
@ -541,6 +558,13 @@ func (n *RawHTML) Kind() NodeKind {
return KindRawHTML
}
// Text implements Node.Text.
//
// Deprecated: Use other properties of the node to get the text value(i.e. RawHTML.Segments).
func (n *RawHTML) Text(source []byte) []byte {
return n.Segments.Value(source)
}
// NewRawHTML returns a new RawHTML node.
func NewRawHTML() *RawHTML {
return &RawHTML{

View file

@ -35,6 +35,7 @@ func (b *codeBlockParser) Open(parent ast.Node, reader text.Reader, pc Context)
if segment.Padding != 0 {
preserveLeadingTabInCodeBlock(&segment, reader, 0)
}
segment.ForceNewline = true
node.Lines().Append(segment)
reader.Advance(segment.Len() - 1)
return node, NoChildren
@ -59,6 +60,7 @@ func (b *codeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context
preserveLeadingTabInCodeBlock(&segment, reader, 0)
}
segment.ForceNewline = true
node.Lines().Append(segment)
reader.Advance(segment.Len() - 1)
return Continue | NoChildren

View file

@ -100,6 +100,7 @@ func (b *fencedCodeBlockParser) Continue(node ast.Node, reader text.Reader, pc C
if padding != 0 {
preserveLeadingTabInCodeBlock(&seg, reader, fdata.indent)
}
seg.ForceNewline = true // EOF as newline
node.Lines().Append(seg)
reader.AdvanceAndSetPadding(segment.Stop-segment.Start-pos-1, padding)
return Continue | NoChildren

View file

@ -878,12 +878,6 @@ func (p *parser) Parse(reader text.Reader, opts ...ParseOption) ast.Node {
blockReader := text.NewBlockReader(reader.Source(), nil)
p.walkBlock(root, func(node ast.Node) {
p.parseBlock(blockReader, node, pc)
lines := node.Lines()
if lines != nil && lines.Len() != 0 {
s := lines.At(lines.Len() - 1)
s.EOB = true
lines.Set(lines.Len()-1, s)
}
})
for _, at := range p.astTransformers {
at.Transform(root, reader, pc)

View file

@ -680,7 +680,7 @@ func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, e
_, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
}
_, _ = w.WriteString(`" alt="`)
r.renderAttribute(w, source, n)
r.renderTexts(w, source, n)
_ = w.WriteByte('"')
if n.Title != nil {
_, _ = w.WriteString(` title="`)
@ -737,7 +737,7 @@ func (r *Renderer) renderText(w util.BufWriter, source []byte, node ast.Node, en
if r.EastAsianLineBreaks != EastAsianLineBreaksNone && len(value) != 0 {
sibling := node.NextSibling()
if sibling != nil && sibling.Kind() == ast.KindText {
if siblingText := sibling.(*ast.Text).Text(source); len(siblingText) != 0 {
if siblingText := sibling.(*ast.Text).Value(source); len(siblingText) != 0 {
thisLastRune := util.ToRune(value, len(value)-1)
siblingFirstRune, _ := utf8.DecodeRune(siblingText)
if r.EastAsianLineBreaks.softLineBreak(thisLastRune, siblingFirstRune) {
@ -770,19 +770,14 @@ func (r *Renderer) renderString(w util.BufWriter, source []byte, node ast.Node,
return ast.WalkContinue, nil
}
func (r *Renderer) renderAttribute(w util.BufWriter, source []byte, n ast.Node) {
func (r *Renderer) renderTexts(w util.BufWriter, source []byte, n ast.Node) {
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
if s, ok := c.(*ast.String); ok {
_, _ = r.renderString(w, source, s, true)
} else if t, ok := c.(*ast.String); ok {
} else if t, ok := c.(*ast.Text); ok {
_, _ = r.renderText(w, source, t, true)
} else if !c.HasChildren() {
r.Writer.Write(w, c.Text(source))
if t, ok := c.(*ast.Text); ok && t.SoftLineBreak() {
_ = w.WriteByte('\n')
}
} else {
r.renderAttribute(w, source, c)
r.renderTexts(w, source, c)
}
}
}

View file

@ -20,8 +20,19 @@ type Segment struct {
// Padding is a padding length of the segment.
Padding int
// EOB is true if the segment is end of the block.
EOB bool
// ForceNewline is true if the segment should be ended with a newline.
// Some elements(i.e. CodeBlock, FencedCodeBlock) does not trim trailing
// newlines. Spec defines that EOF is treated as a newline, so we need to
// add a newline to the end of the segment if it is not empty.
//
// i.e.:
//
// ```go
// const test = "test"
//
// This code does not close the code block and ends with EOF. In this case,
// we need to add a newline to the end of the last line like `const test = "test"\n`.
ForceNewline bool
}
// NewSegment return a new Segment.
@ -52,7 +63,7 @@ func (t *Segment) Value(buffer []byte) []byte {
result = append(result, bytes.Repeat(space, t.Padding)...)
result = append(result, buffer[t.Start:t.Stop]...)
}
if t.EOB && len(result) > 0 && result[len(result)-1] != '\n' {
if t.ForceNewline && len(result) > 0 && result[len(result)-1] != '\n' {
result = append(result, '\n')
}
return result
@ -217,3 +228,12 @@ func (s *Segments) Unshift(v Segment) {
s.values = append(s.values[0:1], s.values[0:]...)
s.values[0] = v
}
// Value returns a string value of the collection.
func (s *Segments) Value(buffer []byte) []byte {
var result []byte
for _, v := range s.values {
result = append(result, v.Value(buffer)...)
}
return result
}

View file

@ -110,14 +110,6 @@ func (db *Database) ColumnExists(ctx context.Context, table, column string) (exi
return
}
func (db *Database) tableExistsNoError(ctx context.Context, table string) bool {
exists, err := db.TableExists(ctx, table)
if err != nil {
panic(fmt.Errorf("failed to check if table exists: %w", err))
}
return exists
}
const createOwnerTable = `
CREATE TABLE IF NOT EXISTS database_owner (
key INTEGER PRIMARY KEY DEFAULT 0,
@ -128,9 +120,13 @@ CREATE TABLE IF NOT EXISTS database_owner (
func (db *Database) checkDatabaseOwner(ctx context.Context) error {
var owner string
if !db.IgnoreForeignTables {
if db.tableExistsNoError(ctx, "state_groups_state") {
if exists, err := db.TableExists(ctx, "state_groups_state"); err != nil {
return fmt.Errorf("failed to check if state_groups_state exists: %w", err)
} else if exists {
return fmt.Errorf("%w (found state_groups_state, likely belonging to Synapse)", ErrForeignTables)
} else if db.tableExistsNoError(ctx, "roomserver_rooms") {
} else if exists, err = db.TableExists(ctx, "roomserver_rooms"); err != nil {
return fmt.Errorf("failed to check if roomserver_rooms exists: %w", err)
} else if exists {
return fmt.Errorf("%w (found roomserver_rooms, likely belonging to Dendrite)", ErrForeignTables)
}
}

View file

@ -78,7 +78,7 @@ var upgradeHeaderRegex = regexp.MustCompile(`^-- (?:v(\d+) -> )?v(\d+)(?: \(comp
// -- v5: Upgrade without transaction
// -- transaction: off
// // do dangerous stuff
var transactionDisableRegex = regexp.MustCompile(`^-- transaction: (\w*)`)
var transactionDisableRegex = regexp.MustCompile(`^-- transaction: ([a-z-]*)`)
func parseFileHeader(file []byte) (from, to, compat int, message string, txn TxnMode, lines [][]byte, err error) {
lines = bytes.Split(file, []byte("\n"))

View file

@ -0,0 +1,24 @@
package exhttp
import "net/http"
// Middleware represents a middleware that can be applied to an [http.Handler].
type Middleware func(http.Handler) http.Handler
// ApplyMiddleware applies the provided [Middleware] functions to the given
// router. The middlewares will be applied in the order they are provided.
func ApplyMiddleware(router http.Handler, middlewares ...Middleware) http.Handler {
// Apply middlewares in reverse order because the first middleware provided
// needs to be the outermost one.
for i := len(middlewares) - 1; i >= 0; i-- {
router = middlewares[i](router)
}
return router
}
// StripPrefix is a wrapper for [http.StripPrefix] is compatible with the middleware pattern.
func StripPrefix(prefix string) Middleware {
return func(next http.Handler) http.Handler {
return http.StripPrefix(prefix, next)
}
}

View file

@ -18,6 +18,8 @@ repos:
- "-w"
- id: go-vet-repo-mod
- id: go-mod-tidy
# TODO enable this
#- id: go-staticcheck-repo-mod
- repo: https://github.com/beeper/pre-commit-go
rev: v0.3.1

View file

@ -1,3 +1,14 @@
## v0.21.1 (2024-10-16)
* *(bridgev2)* Added more features and fixed bugs.
* *(hicli)* Added more features and fixed bugs.
* *(appservice)* Removed TLS support. A reverse proxy should be used if TLS
is needed.
* *(format/mdext)* Added goldmark extension to fix indented paragraphs when
disabling indented code block parser.
* *(event)* Added `Has` method for `Mentions`.
* *(event)* Added basic support for the unstable version of polls.
## v0.21.0 (2024-09-16)
* **Breaking change *(client)*** Dropped support for unauthenticated media.

View file

@ -420,6 +420,10 @@ func (params *FullRequest) compileRequest(ctx context.Context) (*http.Request, e
params.RequestLength = int64(len(params.RequestBytes))
} else if params.RequestLength > 0 && params.RequestBody != nil {
logBody = fmt.Sprintf("<%d bytes>", params.RequestLength)
if rsc, ok := params.RequestBody.(io.ReadSeekCloser); ok {
// Prevent HTTP from closing the request body, it might be needed for retries
reqBody = nopCloseSeeker{rsc}
}
} else if params.Method != http.MethodGet && params.Method != http.MethodHead {
params.RequestJSON = struct{}{}
logBody = params.RequestJSON
@ -1465,6 +1469,18 @@ func (cli *Client) State(ctx context.Context, roomID id.RoomID) (stateMap RoomSt
return
}
// StateAsArray gets all the state in a room as an array. It does not update the state store.
// Use State to get the events as a map and also update the state store.
func (cli *Client) StateAsArray(ctx context.Context, roomID id.RoomID) (state []*event.Event, err error) {
_, err = cli.MakeRequest(ctx, http.MethodGet, cli.BuildClientURL("v3", "rooms", roomID, "state"), nil, &state)
if err == nil {
for _, evt := range state {
evt.Type.Class = event.StateEventType
}
}
return
}
// GetMediaConfig fetches the configuration of the content repository, such as upload limitations.
func (cli *Client) GetMediaConfig(ctx context.Context) (resp *RespMediaConfig, err error) {
_, err = cli.MakeRequest(ctx, http.MethodGet, cli.BuildClientURL("v1", "media", "config"), nil, &resp)
@ -1612,6 +1628,9 @@ func (cli *Client) uploadMediaToURL(ctx context.Context, data ReqUploadMedia) (*
if data.ContentBytes != nil {
data.ContentLength = int64(len(data.ContentBytes))
reader = bytes.NewReader(data.ContentBytes)
} else if rsc, ok := reader.(io.ReadSeekCloser); ok {
// Prevent HTTP from closing the request body, it might be needed for retries
reader = nopCloseSeeker{rsc}
}
readerSeeker, canSeek := reader.(io.ReadSeeker)
if !canSeek {
@ -1656,6 +1675,14 @@ func (cli *Client) uploadMediaToURL(ctx context.Context, data ReqUploadMedia) (*
return m, nil
}
type nopCloseSeeker struct {
io.ReadSeeker
}
func (nopCloseSeeker) Close() error {
return nil
}
// UploadMedia uploads the given data to the content repository and returns an MXC URI.
// See https://spec.matrix.org/v1.7/client-server-api/#post_matrixmediav3upload
func (cli *Client) UploadMedia(ctx context.Context, data ReqUploadMedia) (*RespMediaUpload, error) {
@ -1809,10 +1836,9 @@ func (cli *Client) Hierarchy(ctx context.Context, roomID id.RoomID, req *ReqHier
// Messages returns a list of message and state events for a room. It uses
// pagination query parameters to paginate history in the room.
// See https://spec.matrix.org/v1.2/client-server-api/#get_matrixclientv3roomsroomidmessages
// See https://spec.matrix.org/v1.12/client-server-api/#get_matrixclientv3roomsroomidmessages
func (cli *Client) Messages(ctx context.Context, roomID id.RoomID, from, to string, dir Direction, filter *FilterPart, limit int) (resp *RespMessages, err error) {
query := map[string]string{
"from": from,
"dir": string(dir),
}
if filter != nil {
@ -1822,6 +1848,9 @@ func (cli *Client) Messages(ctx context.Context, roomID id.RoomID, from, to stri
}
query["filter"] = string(filterJSON)
}
if from != "" {
query["from"] = from
}
if to != "" {
query["to"] = to
}

View file

@ -51,7 +51,7 @@ func (mach *OlmMachine) storeCrossSigningKeys(ctx context.Context, crossSigningK
for _, key := range userKeys.Keys {
log := log.With().Str("key", key.String()).Array("usages", exzerolog.ArrayOfStrs(userKeys.Usage)).Logger()
for _, usage := range userKeys.Usage {
log.Debug().Str("usage", string(usage)).Msg("Storing cross-signing key")
log.Trace().Str("usage", string(usage)).Msg("Storing cross-signing key")
if err = mach.CryptoStore.PutCrossSigningKey(ctx, userID, usage, key); err != nil {
log.Error().Err(err).Msg("Error storing cross-signing key")
}
@ -77,16 +77,16 @@ func (mach *OlmMachine) storeCrossSigningKeys(ctx context.Context, crossSigningK
}
}
if len(signingKey) != 43 {
log.Debug().Msg("Cross-signing key has a signature from an unknown key")
log.Trace().Msg("Cross-signing key has a signature from an unknown key")
continue
}
log.Debug().Msg("Verifying cross-signing key signature")
log.Trace().Msg("Verifying cross-signing key signature")
if verified, err := signatures.VerifySignatureJSON(userKeys, signUserID, signKeyName, signingKey); err != nil {
log.Warn().Err(err).Msg("Error verifying cross-signing key signature")
} else {
if verified {
log.Debug().Err(err).Msg("Cross-signing key signature verified")
log.Trace().Err(err).Msg("Cross-signing key signature verified")
err = mach.CryptoStore.PutSignature(ctx, userID, key, signUserID, signingKey, signature)
if err != nil {
log.Error().Err(err).Msg("Error storing cross-signing key signature")

View file

@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/rs/zerolog"
@ -67,7 +68,7 @@ type OlmMachine struct {
otkUploadLock sync.Mutex
lastOTKUpload time.Time
receivedOTKsForSelf bool
receivedOTKsForSelf atomic.Bool
CrossSigningKeys *CrossSigningKeysCache
crossSigningPubkeys *CrossSigningPublicKeysCache
@ -258,16 +259,18 @@ func (mach *OlmMachine) otkCountIsForCrossSigningKey(otkCount *mautrix.OTKCount)
}
func (mach *OlmMachine) HandleOTKCounts(ctx context.Context, otkCount *mautrix.OTKCount) {
receivedOTKsForSelf := mach.receivedOTKsForSelf.Load()
if (len(otkCount.UserID) > 0 && otkCount.UserID != mach.Client.UserID) || (len(otkCount.DeviceID) > 0 && otkCount.DeviceID != mach.Client.DeviceID) {
if otkCount.UserID != mach.Client.UserID || (!mach.receivedOTKsForSelf && !mach.otkCountIsForCrossSigningKey(otkCount)) {
if otkCount.UserID != mach.Client.UserID || (!receivedOTKsForSelf && !mach.otkCountIsForCrossSigningKey(otkCount)) {
mach.Log.Warn().
Str("target_user_id", otkCount.UserID.String()).
Str("target_device_id", otkCount.DeviceID.String()).
Msg("Dropping OTK counts targeted to someone else")
}
return
} else if !receivedOTKsForSelf {
mach.receivedOTKsForSelf.Store(true)
}
mach.receivedOTKsForSelf = true
minCount := mach.account.Internal.MaxNumberOfOneTimeKeys() / 2
if otkCount.SignedCurve25519 < int(minCount) {

View file

@ -162,6 +162,11 @@ func (e RespError) WithMessage(msg string, args ...any) RespError {
return e
}
func (e RespError) WithStatus(status int) RespError {
e.StatusCode = status
return e
}
// Error returns the errcode and error message.
func (e RespError) Error() string {
return e.ErrCode + ": " + e.Err

View file

@ -97,3 +97,10 @@ type BeeperProfileExtra struct {
IsBridgeBot bool `json:"com.beeper.bridge.is_bridge_bot,omitempty"`
IsNetworkBot bool `json:"com.beeper.bridge.is_network_bot,omitempty"`
}
type BeeperPerMessageProfile struct {
ID string `json:"id"`
Displayname string `json:"displayname,omitempty"`
AvatarURL *id.ContentURIString `json:"avatar_url,omitempty"`
AvatarFile *EncryptedFileInfo `json:"avatar_file,omitempty"`
}

View file

@ -55,6 +55,9 @@ var TypeMap = map[Type]reflect.Type{
EventRedaction: reflect.TypeOf(RedactionEventContent{}),
EventReaction: reflect.TypeOf(ReactionEventContent{}),
EventUnstablePollStart: reflect.TypeOf(PollStartEventContent{}),
EventUnstablePollResponse: reflect.TypeOf(PollResponseEventContent{}),
BeeperMessageStatus: reflect.TypeOf(BeeperMessageStatusEventContent{}),
AccountDataRoomTags: reflect.TypeOf(TagEventContent{}),

View file

@ -143,6 +143,27 @@ type MessageEventContent struct {
MSC3245Voice *MSC3245Voice `json:"org.matrix.msc3245.voice,omitempty"`
}
func (content *MessageEventContent) GetFileName() string {
if content.FileName != "" {
return content.FileName
}
return content.Body
}
func (content *MessageEventContent) GetCaption() string {
if content.FileName != "" && content.Body != "" && content.Body != content.FileName {
return content.Body
}
return ""
}
func (content *MessageEventContent) GetFormattedCaption() string {
if content.Format == FormatHTML && content.FormattedBody != "" {
return content.FormattedBody
}
return ""
}
func (content *MessageEventContent) GetRelatesTo() *RelatesTo {
if content.RelatesTo == nil {
content.RelatesTo = &RelatesTo{}
@ -220,6 +241,10 @@ func (m *Mentions) Add(userID id.UserID) {
}
}
func (m *Mentions) Has(userID id.UserID) bool {
return m != nil && slices.Contains(m.UserIDs, userID)
}
type EncryptedFileInfo struct {
attachment.EncryptedFile
URL id.ContentURIString `json:"url"`

67
vendor/maunium.net/go/mautrix/event/poll.go generated vendored Normal file
View file

@ -0,0 +1,67 @@
// Copyright (c) 2024 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
type PollResponseEventContent struct {
RelatesTo RelatesTo `json:"m.relates_to"`
Response struct {
Answers []string `json:"answers"`
} `json:"org.matrix.msc3381.poll.response"`
}
func (content *PollResponseEventContent) GetRelatesTo() *RelatesTo {
return &content.RelatesTo
}
func (content *PollResponseEventContent) OptionalGetRelatesTo() *RelatesTo {
if content.RelatesTo.Type == "" {
return nil
}
return &content.RelatesTo
}
func (content *PollResponseEventContent) SetRelatesTo(rel *RelatesTo) {
content.RelatesTo = *rel
}
type MSC1767Message struct {
Text string `json:"org.matrix.msc1767.text,omitempty"`
HTML string `json:"org.matrix.msc1767.html,omitempty"`
Message []struct {
MimeType string `json:"mimetype"`
Body string `json:"body"`
} `json:"org.matrix.msc1767.message,omitempty"`
}
type PollStartEventContent struct {
RelatesTo *RelatesTo `json:"m.relates_to"`
Mentions *Mentions `json:"m.mentions,omitempty"`
PollStart struct {
Kind string `json:"kind"`
MaxSelections int `json:"max_selections"`
Question MSC1767Message `json:"question"`
Answers []struct {
ID string `json:"id"`
MSC1767Message
} `json:"answers"`
} `json:"org.matrix.msc3381.poll.start"`
}
func (content *PollStartEventContent) GetRelatesTo() *RelatesTo {
if content.RelatesTo == nil {
content.RelatesTo = &RelatesTo{}
}
return content.RelatesTo
}
func (content *PollStartEventContent) OptionalGetRelatesTo() *RelatesTo {
return content.RelatesTo
}
func (content *PollStartEventContent) SetRelatesTo(rel *RelatesTo) {
content.RelatesTo = rel
}

View file

@ -1,10 +0,0 @@
package event
import "maunium.net/go/mautrix/id"
type BeeperPerMessageProfile struct {
ID string `json:"id"`
Displayname string `json:"displayname,omitempty"`
AvatarURL *id.ContentURIString `json:"avatar_url,omitempty"`
AvatarFile *EncryptedFileInfo `json:"avatar_file,omitempty"`
}

View file

@ -126,7 +126,7 @@ func (et *Type) GuessClass() TypeClass {
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, BeeperMessageStatus.Type:
CallNegotiate.Type, CallHangup.Type, BeeperMessageStatus.Type, EventUnstablePollStart.Type, EventUnstablePollResponse.Type:
return MessageEventType
case ToDeviceRoomKey.Type, ToDeviceRoomKeyRequest.Type, ToDeviceForwardedRoomKey.Type, ToDeviceRoomKeyWithheld.Type,
ToDeviceBeeperRoomKeyAck.Type:
@ -232,6 +232,9 @@ var (
CallHangup = Type{"m.call.hangup", MessageEventType}
BeeperMessageStatus = Type{"com.beeper.message_send_status", MessageEventType}
EventUnstablePollStart = Type{Type: "org.matrix.msc3381.poll.start", Class: MessageEventType}
EventUnstablePollResponse = Type{Type: "org.matrix.msc3381.poll.response", Class: MessageEventType}
)
// Ephemeral events

View file

@ -0,0 +1,28 @@
// Copyright (c) 2024 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 mdext
import (
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/util"
)
// indentableParagraphParser is the default paragraph parser with CanAcceptIndentedLine.
// Used when disabling CodeBlockParser (as disabling it without a replacement will make indented blocks disappear).
type indentableParagraphParser struct {
parser.BlockParser
}
var defaultIndentableParagraphParser = &indentableParagraphParser{BlockParser: parser.NewParagraphParser()}
func (b *indentableParagraphParser) CanAcceptIndentedLine() bool {
return true
}
// FixIndentedParagraphs is a goldmark option which fixes indented paragraphs when disabling CodeBlockParser.
var FixIndentedParagraphs = goldmark.WithParserOptions(parser.WithBlockParsers(util.Prioritized(defaultIndentableParagraphParser, 500)))

View file

@ -7,7 +7,7 @@ import (
"strings"
)
const Version = "v0.21.0"
const Version = "v0.21.1"
var GoModVersion = ""
var Commit = ""

16
vendor/modules.txt vendored
View file

@ -30,7 +30,7 @@ github.com/dustin/go-humanize
# github.com/emersion/go-msgauth v0.6.8
## explicit; go 1.18
github.com/emersion/go-msgauth/dkim
# github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
# github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6
## explicit; go 1.12
github.com/emersion/go-sasl
# github.com/emersion/go-smtp v0.21.3
@ -43,10 +43,10 @@ github.com/etkecc/go-env/dotenv
# github.com/etkecc/go-fswatcher v1.0.1
## explicit; go 1.20
github.com/etkecc/go-fswatcher
# github.com/etkecc/go-healthchecks/v2 v2.2.1
# github.com/etkecc/go-healthchecks/v2 v2.2.2
## explicit; go 1.18
github.com/etkecc/go-healthchecks/v2
# github.com/etkecc/go-linkpearl v0.0.0-20240916112808-1ff87355b2b3
# github.com/etkecc/go-linkpearl v0.0.0-20241016081935-715b568101ef
## explicit; go 1.22.0
github.com/etkecc/go-linkpearl
# github.com/etkecc/go-mxidwc v1.0.1
@ -55,7 +55,7 @@ github.com/etkecc/go-mxidwc
# github.com/etkecc/go-psd v0.0.0-20241014083754-1bc4ec777ba8
## explicit; go 1.21.0
github.com/etkecc/go-psd
# github.com/etkecc/go-secgen v1.3.0
# github.com/etkecc/go-secgen v1.4.0
## explicit; go 1.19
github.com/etkecc/go-secgen
# github.com/etkecc/go-trysmtp v1.1.5
@ -155,7 +155,7 @@ github.com/ncruces/go-strftime
# github.com/olekukonko/tablewriter v0.0.5
## explicit; go 1.12
github.com/olekukonko/tablewriter
# github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7
# github.com/petermattis/goid v0.0.0-20241025130422-66cb2e6d7274
## explicit; go 1.17
github.com/petermattis/goid
# github.com/pkg/errors v0.9.1
@ -194,7 +194,7 @@ github.com/tidwall/pretty
# github.com/tidwall/sjson v1.2.5
## explicit; go 1.14
github.com/tidwall/sjson
# github.com/yuin/goldmark v1.7.6
# github.com/yuin/goldmark v1.7.8
## explicit; go 1.19
github.com/yuin/goldmark
github.com/yuin/goldmark/ast
@ -205,7 +205,7 @@ github.com/yuin/goldmark/renderer
github.com/yuin/goldmark/renderer/html
github.com/yuin/goldmark/text
github.com/yuin/goldmark/util
# go.mau.fi/util v0.8.0
# go.mau.fi/util v0.8.1
## explicit; go 1.22.0
go.mau.fi/util/base58
go.mau.fi/util/confusable
@ -288,7 +288,7 @@ golang.org/x/tools/internal/versions
# gopkg.in/yaml.v2 v2.4.0
## explicit; go 1.15
gopkg.in/yaml.v2
# maunium.net/go/mautrix v0.21.0
# maunium.net/go/mautrix v0.21.1
## explicit; go 1.22.0
maunium.net/go/mautrix
maunium.net/go/mautrix/crypto