mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-06 14:33:10 -06:00
Update gomatrixserverlib
This commit is contained in:
parent
94c97ed677
commit
07a1084e5a
6
vendor/manifest
vendored
6
vendor/manifest
vendored
|
|
@ -92,13 +92,13 @@
|
||||||
{
|
{
|
||||||
"importpath": "github.com/matrix-org/gomatrixserverlib",
|
"importpath": "github.com/matrix-org/gomatrixserverlib",
|
||||||
"repository": "https://github.com/matrix-org/gomatrixserverlib",
|
"repository": "https://github.com/matrix-org/gomatrixserverlib",
|
||||||
"revision": "48ee56a33d195dc412dd919a0e81af70c9aaf4a3",
|
"revision": "ce2ae9c5812346444b0ca75d57834794cde03fb7",
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"importpath": "github.com/matrix-org/util",
|
"importpath": "github.com/matrix-org/util",
|
||||||
"repository": "https://github.com/matrix-org/util",
|
"repository": "https://github.com/matrix-org/util",
|
||||||
"revision": "28bd7491c8aafbf346ca23821664f0f9911ef52b",
|
"revision": "ec8896cd7d9ba6de6143c5f123d1e45413657e7d",
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -206,4 +206,4 @@
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -326,6 +326,21 @@ func (e Event) Depth() int64 {
|
||||||
return e.fields.Depth
|
return e.fields.Depth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements json.Unmarshaller assuming the Event is from an untrusted source.
|
||||||
|
// This will cause more checks than might be necessary but is probably better to be safe than sorry.
|
||||||
|
func (e *Event) UnmarshalJSON(data []byte) (err error) {
|
||||||
|
*e, err = NewEventFromUntrustedJSON(data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON implements json.Marshaller
|
||||||
|
func (e Event) MarshalJSON() ([]byte, error) {
|
||||||
|
if e.eventJSON == nil {
|
||||||
|
return nil, fmt.Errorf("gomatrixserverlib: cannot serialise uninitialised Event")
|
||||||
|
}
|
||||||
|
return e.eventJSON, nil
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements json.Unmarshaller
|
// UnmarshalJSON implements json.Unmarshaller
|
||||||
func (er *EventReference) UnmarshalJSON(data []byte) error {
|
func (er *EventReference) UnmarshalJSON(data []byte) error {
|
||||||
var tuple []rawJSON
|
var tuple []rawJSON
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,8 @@ package gomatrixserverlib
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
|
"github.com/matrix-org/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -43,105 +44,108 @@ type StateNeeded struct {
|
||||||
ThirdPartyInvite []string
|
ThirdPartyInvite []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateNeededForAuth returns the event types and state_keys needed to authenticate an event.
|
// StateNeededForEventBuilder returns the event types and state_keys needed to authenticate the
|
||||||
// This takes a list of events to facilitate bulk processing when doing auth checks as part of state conflict resolution.
|
// event being built. These events should be put under 'auth_events' for the event being built.
|
||||||
func StateNeededForAuth(events []Event) (result StateNeeded) {
|
// Returns an error if the state needed could not be calculated with the given builder, e.g
|
||||||
var members []string
|
// if there is a m.room.member without a membership key.
|
||||||
var thirdpartyinvites []string
|
func StateNeededForEventBuilder(builder *EventBuilder) (result StateNeeded, err error) {
|
||||||
|
// Extract the 'content' object from the event if it is m.room.member as we need to know 'membership'
|
||||||
for _, event := range events {
|
var content *memberContent
|
||||||
switch event.Type() {
|
if builder.Type == "m.room.member" {
|
||||||
case "m.room.create":
|
if err = json.Unmarshal(builder.content, &content); err != nil {
|
||||||
// The create event doesn't require any state to authenticate.
|
err = errorf("unparsable member event content: %s", err.Error())
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L123
|
return
|
||||||
case "m.room.aliases":
|
|
||||||
// Alias events need:
|
|
||||||
// * The create event.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L128
|
|
||||||
// Alias events need no further authentication.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L160
|
|
||||||
result.Create = true
|
|
||||||
case "m.room.member":
|
|
||||||
// Member events need:
|
|
||||||
// * The previous membership of the target.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L355
|
|
||||||
// * The current membership state of the sender.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L348
|
|
||||||
// * The join rules for the room if the event is a join event.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L361
|
|
||||||
// * The power levels for the room.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L370
|
|
||||||
// * And optionally may require a m.third_party_invite event
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L393
|
|
||||||
content, err := newMemberContentFromEvent(event)
|
|
||||||
if err != nil {
|
|
||||||
// If we hit an error decoding the content we ignore it here.
|
|
||||||
// The event will be rejected when the actual checks encounter the same error.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result.Create = true
|
|
||||||
result.PowerLevels = true
|
|
||||||
stateKey := event.StateKey()
|
|
||||||
if stateKey != nil {
|
|
||||||
members = append(members, event.Sender(), *stateKey)
|
|
||||||
}
|
|
||||||
if content.Membership == join {
|
|
||||||
result.JoinRules = true
|
|
||||||
}
|
|
||||||
if content.ThirdPartyInvite != nil {
|
|
||||||
token, err := thirdPartyInviteToken(content.ThirdPartyInvite)
|
|
||||||
if err != nil {
|
|
||||||
// If we hit an error decoding the content we ignore it here.
|
|
||||||
// The event will be rejected when the actual checks encounter the same error.
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
thirdpartyinvites = append(thirdpartyinvites, token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
// All other events need:
|
|
||||||
// * The membership of the sender.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L177
|
|
||||||
// * The power levels for the room.
|
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L196
|
|
||||||
result.Create = true
|
|
||||||
result.PowerLevels = true
|
|
||||||
members = append(members, event.Sender())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
err = accumulateStateNeeded(&result, builder.Type, builder.Sender, builder.StateKey, content)
|
||||||
// Deduplicate the state keys.
|
result.Member = util.UniqueStrings(result.Member)
|
||||||
sort.Strings(members)
|
result.ThirdPartyInvite = util.UniqueStrings(result.ThirdPartyInvite)
|
||||||
result.Member = members[:unique(sort.StringSlice(members))]
|
|
||||||
sort.Strings(thirdpartyinvites)
|
|
||||||
result.ThirdPartyInvite = thirdpartyinvites[:unique(sort.StringSlice(thirdpartyinvites))]
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove duplicate items from a sorted list.
|
// StateNeededForAuth returns the event types and state_keys needed to authenticate an event.
|
||||||
// Takes the same interface as sort.Sort
|
// This takes a list of events to facilitate bulk processing when doing auth checks as part of state conflict resolution.
|
||||||
// Returns the length of the data without duplicates
|
func StateNeededForAuth(events []Event) (result StateNeeded) {
|
||||||
// Uses the last occurrence of a duplicate.
|
for _, event := range events {
|
||||||
// O(n).
|
// Extract the 'content' object from the event if it is m.room.member as we need to know 'membership'
|
||||||
func unique(data sort.Interface) int {
|
var content *memberContent
|
||||||
length := data.Len()
|
if event.Type() == "m.room.member" {
|
||||||
if length == 0 {
|
c, err := newMemberContentFromEvent(event)
|
||||||
return 0
|
if err == nil {
|
||||||
}
|
content = &c
|
||||||
j := 0
|
}
|
||||||
for i := 1; i < length; i++ {
|
|
||||||
if data.Less(i-1, i) {
|
|
||||||
data.Swap(i-1, j)
|
|
||||||
j++
|
|
||||||
}
|
}
|
||||||
|
// Ignore errors when accumulating state needed.
|
||||||
|
// The event will be rejected when the actual checks encounter the same error.
|
||||||
|
_ = accumulateStateNeeded(&result, event.Type(), event.Sender(), event.StateKey(), content)
|
||||||
}
|
}
|
||||||
data.Swap(length-1, j)
|
|
||||||
return j + 1
|
// Deduplicate the state keys.
|
||||||
|
result.Member = util.UniqueStrings(result.Member)
|
||||||
|
result.ThirdPartyInvite = util.UniqueStrings(result.ThirdPartyInvite)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func accumulateStateNeeded(result *StateNeeded, eventType, sender string, stateKey *string, content *memberContent) (err error) {
|
||||||
|
switch eventType {
|
||||||
|
case "m.room.create":
|
||||||
|
// The create event doesn't require any state to authenticate.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L123
|
||||||
|
case "m.room.aliases":
|
||||||
|
// Alias events need:
|
||||||
|
// * The create event.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L128
|
||||||
|
// Alias events need no further authentication.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L160
|
||||||
|
result.Create = true
|
||||||
|
case "m.room.member":
|
||||||
|
// Member events need:
|
||||||
|
// * The previous membership of the target.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L355
|
||||||
|
// * The current membership state of the sender.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L348
|
||||||
|
// * The join rules for the room if the event is a join event.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L361
|
||||||
|
// * The power levels for the room.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L370
|
||||||
|
// * And optionally may require a m.third_party_invite event
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L393
|
||||||
|
if content == nil {
|
||||||
|
err = errorf("missing memberContent for m.room.member event")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.Create = true
|
||||||
|
result.PowerLevels = true
|
||||||
|
if stateKey != nil {
|
||||||
|
result.Member = append(result.Member, sender, *stateKey)
|
||||||
|
}
|
||||||
|
if content.Membership == join {
|
||||||
|
result.JoinRules = true
|
||||||
|
}
|
||||||
|
if content.ThirdPartyInvite != nil {
|
||||||
|
token, tokErr := thirdPartyInviteToken(content.ThirdPartyInvite)
|
||||||
|
if tokErr != nil {
|
||||||
|
err = errorf("could not get third-party token: %s", tokErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
result.ThirdPartyInvite = append(result.ThirdPartyInvite, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// All other events need:
|
||||||
|
// * The membership of the sender.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L177
|
||||||
|
// * The power levels for the room.
|
||||||
|
// https://github.com/matrix-org/synapse/blob/v0.18.5/synapse/api/auth.py#L196
|
||||||
|
result.Create = true
|
||||||
|
result.PowerLevels = true
|
||||||
|
result.Member = append(result.Member, sender)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// thirdPartyInviteToken extracts the token from the third_party_invite.
|
// thirdPartyInviteToken extracts the token from the third_party_invite.
|
||||||
func thirdPartyInviteToken(thirdPartyInviteData json.RawMessage) (string, error) {
|
func thirdPartyInviteToken(thirdPartyInviteData rawJSON) (string, error) {
|
||||||
var thirdPartyInvite struct {
|
var thirdPartyInvite struct {
|
||||||
Signed struct {
|
Signed struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ func (tel *testEventList) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testStateNeededForAuth(t *testing.T, eventdata string, want StateNeeded) {
|
func testStateNeededForAuth(t *testing.T, eventdata string, builder *EventBuilder, want StateNeeded) {
|
||||||
var events testEventList
|
var events testEventList
|
||||||
if err := json.Unmarshal([]byte(eventdata), &events); err != nil {
|
if err := json.Unmarshal([]byte(eventdata), &events); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
@ -77,11 +77,24 @@ func testStateNeededForAuth(t *testing.T, eventdata string, want StateNeeded) {
|
||||||
if !stateNeededEquals(got, want) {
|
if !stateNeededEquals(got, want) {
|
||||||
t.Errorf("Testing StateNeededForAuth(%#v), wanted %#v got %#v", events, want, got)
|
t.Errorf("Testing StateNeededForAuth(%#v), wanted %#v got %#v", events, want, got)
|
||||||
}
|
}
|
||||||
|
if builder != nil {
|
||||||
|
got, err := StateNeededForEventBuilder(builder)
|
||||||
|
if !stateNeededEquals(got, want) {
|
||||||
|
t.Errorf("Testing StateNeededForEventBuilder(%#v), wanted %#v got %#v", events, want, got)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateNeededForCreate(t *testing.T) {
|
func TestStateNeededForCreate(t *testing.T) {
|
||||||
// Create events don't need anything.
|
// Create events don't need anything.
|
||||||
testStateNeededForAuth(t, `[{"type": "m.room.create"}]`, StateNeeded{})
|
skey := ""
|
||||||
|
testStateNeededForAuth(t, `[{"type": "m.room.create"}]`, &EventBuilder{
|
||||||
|
Type: "m.room.create",
|
||||||
|
StateKey: &skey,
|
||||||
|
}, StateNeeded{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateNeededForMessage(t *testing.T) {
|
func TestStateNeededForMessage(t *testing.T) {
|
||||||
|
|
@ -89,7 +102,10 @@ func TestStateNeededForMessage(t *testing.T) {
|
||||||
testStateNeededForAuth(t, `[{
|
testStateNeededForAuth(t, `[{
|
||||||
"type": "m.room.message",
|
"type": "m.room.message",
|
||||||
"sender": "@u1:a"
|
"sender": "@u1:a"
|
||||||
}]`, StateNeeded{
|
}]`, &EventBuilder{
|
||||||
|
Type: "m.room.message",
|
||||||
|
Sender: "@u1:a",
|
||||||
|
}, StateNeeded{
|
||||||
Create: true,
|
Create: true,
|
||||||
PowerLevels: true,
|
PowerLevels: true,
|
||||||
Member: []string{"@u1:a"},
|
Member: []string{"@u1:a"},
|
||||||
|
|
@ -98,18 +114,27 @@ func TestStateNeededForMessage(t *testing.T) {
|
||||||
|
|
||||||
func TestStateNeededForAlias(t *testing.T) {
|
func TestStateNeededForAlias(t *testing.T) {
|
||||||
// Alias events need only the create event.
|
// Alias events need only the create event.
|
||||||
testStateNeededForAuth(t, `[{"type": "m.room.aliases"}]`, StateNeeded{
|
testStateNeededForAuth(t, `[{"type": "m.room.aliases"}]`, &EventBuilder{
|
||||||
|
Type: "m.room.aliases",
|
||||||
|
}, StateNeeded{
|
||||||
Create: true,
|
Create: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateNeededForJoin(t *testing.T) {
|
func TestStateNeededForJoin(t *testing.T) {
|
||||||
|
skey := "@u1:a"
|
||||||
|
b := EventBuilder{
|
||||||
|
Type: "m.room.member",
|
||||||
|
StateKey: &skey,
|
||||||
|
Sender: "@u1:a",
|
||||||
|
}
|
||||||
|
b.SetContent(memberContent{"join", nil})
|
||||||
testStateNeededForAuth(t, `[{
|
testStateNeededForAuth(t, `[{
|
||||||
"type": "m.room.member",
|
"type": "m.room.member",
|
||||||
"state_key": "@u1:a",
|
"state_key": "@u1:a",
|
||||||
"sender": "@u1:a",
|
"sender": "@u1:a",
|
||||||
"content": {"membership": "join"}
|
"content": {"membership": "join"}
|
||||||
}]`, StateNeeded{
|
}]`, &b, StateNeeded{
|
||||||
Create: true,
|
Create: true,
|
||||||
JoinRules: true,
|
JoinRules: true,
|
||||||
PowerLevels: true,
|
PowerLevels: true,
|
||||||
|
|
@ -118,12 +143,19 @@ func TestStateNeededForJoin(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateNeededForInvite(t *testing.T) {
|
func TestStateNeededForInvite(t *testing.T) {
|
||||||
|
skey := "@u2:b"
|
||||||
|
b := EventBuilder{
|
||||||
|
Type: "m.room.member",
|
||||||
|
StateKey: &skey,
|
||||||
|
Sender: "@u1:a",
|
||||||
|
}
|
||||||
|
b.SetContent(memberContent{"invite", nil})
|
||||||
testStateNeededForAuth(t, `[{
|
testStateNeededForAuth(t, `[{
|
||||||
"type": "m.room.member",
|
"type": "m.room.member",
|
||||||
"state_key": "@u2:b",
|
"state_key": "@u2:b",
|
||||||
"sender": "@u1:a",
|
"sender": "@u1:a",
|
||||||
"content": {"membership": "invite"}
|
"content": {"membership": "invite"}
|
||||||
}]`, StateNeeded{
|
}]`, &b, StateNeeded{
|
||||||
Create: true,
|
Create: true,
|
||||||
PowerLevels: true,
|
PowerLevels: true,
|
||||||
Member: []string{"@u1:a", "@u2:b"},
|
Member: []string{"@u1:a", "@u2:b"},
|
||||||
|
|
@ -131,6 +163,13 @@ func TestStateNeededForInvite(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateNeededForInvite3PID(t *testing.T) {
|
func TestStateNeededForInvite3PID(t *testing.T) {
|
||||||
|
skey := "@u2:b"
|
||||||
|
b := EventBuilder{
|
||||||
|
Type: "m.room.member",
|
||||||
|
StateKey: &skey,
|
||||||
|
Sender: "@u1:a",
|
||||||
|
}
|
||||||
|
b.SetContent(memberContent{"invite", rawJSON(`{"signed":{"token":"my_token"}}`)})
|
||||||
testStateNeededForAuth(t, `[{
|
testStateNeededForAuth(t, `[{
|
||||||
"type": "m.room.member",
|
"type": "m.room.member",
|
||||||
"state_key": "@u2:b",
|
"state_key": "@u2:b",
|
||||||
|
|
@ -143,7 +182,7 @@ func TestStateNeededForInvite3PID(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}]`, StateNeeded{
|
}]`, &b, StateNeeded{
|
||||||
Create: true,
|
Create: true,
|
||||||
PowerLevels: true,
|
PowerLevels: true,
|
||||||
Member: []string{"@u1:a", "@u2:b"},
|
Member: []string{"@u1:a", "@u2:b"},
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ type memberContent struct {
|
||||||
// We use the membership key in order to check if the user is in the room.
|
// We use the membership key in order to check if the user is in the room.
|
||||||
Membership string `json:"membership"`
|
Membership string `json:"membership"`
|
||||||
// We use the third_party_invite key to special case thirdparty invites.
|
// We use the third_party_invite key to special case thirdparty invites.
|
||||||
ThirdPartyInvite json.RawMessage `json:"third_party_invite"`
|
ThirdPartyInvite rawJSON `json:"third_party_invite,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// newMemberContentFromAuthEvents loads the member content from the member event for the user ID in the auth events.
|
// newMemberContentFromAuthEvents loads the member content from the member event for the user ID in the auth events.
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ func Protect(handler http.HandlerFunc) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
logger := req.Context().Value(ctxValueLogger).(*log.Entry)
|
logger := GetLogger(req.Context())
|
||||||
logger.WithFields(log.Fields{
|
logger.WithFields(log.Fields{
|
||||||
"panic": r,
|
"panic": r,
|
||||||
}).Errorf(
|
}).Errorf(
|
||||||
|
|
@ -108,7 +108,7 @@ func MakeJSONAPI(handler JSONRequestHandler) http.HandlerFunc {
|
||||||
ctx = context.WithValue(ctx, ctxValueRequestID, reqID)
|
ctx = context.WithValue(ctx, ctxValueRequestID, reqID)
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
|
|
||||||
logger := req.Context().Value(ctxValueLogger).(*log.Entry)
|
logger := GetLogger(req.Context())
|
||||||
logger.Print("Incoming request")
|
logger.Print("Incoming request")
|
||||||
|
|
||||||
res := handler.OnIncomingRequest(req)
|
res := handler.OnIncomingRequest(req)
|
||||||
|
|
@ -122,7 +122,7 @@ func MakeJSONAPI(handler JSONRequestHandler) http.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
func respond(w http.ResponseWriter, req *http.Request, res JSONResponse) {
|
func respond(w http.ResponseWriter, req *http.Request, res JSONResponse) {
|
||||||
logger := req.Context().Value(ctxValueLogger).(*log.Entry)
|
logger := GetLogger(req.Context())
|
||||||
|
|
||||||
// Set custom headers
|
// Set custom headers
|
||||||
if res.Headers != nil {
|
if res.Headers != nil {
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,28 @@ func TestProtect(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProtectWithoutLogger(t *testing.T) {
|
||||||
|
log.SetLevel(log.PanicLevel) // suppress logs in test output
|
||||||
|
mockWriter := httptest.NewRecorder()
|
||||||
|
mockReq, _ := http.NewRequest("GET", "http://example.com/foo", nil)
|
||||||
|
h := Protect(func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
panic("oh noes!")
|
||||||
|
})
|
||||||
|
|
||||||
|
h(mockWriter, mockReq)
|
||||||
|
|
||||||
|
expectCode := 500
|
||||||
|
if mockWriter.Code != expectCode {
|
||||||
|
t.Errorf("TestProtect wanted HTTP status %d, got %d", expectCode, mockWriter.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectBody := `{"message":"Internal Server Error"}`
|
||||||
|
actualBody := mockWriter.Body.String()
|
||||||
|
if actualBody != expectBody {
|
||||||
|
t.Errorf("TestProtect wanted body %s, got %s", expectBody, actualBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestWithCORSOptions(t *testing.T) {
|
func TestWithCORSOptions(t *testing.T) {
|
||||||
log.SetLevel(log.PanicLevel) // suppress logs in test output
|
log.SetLevel(log.PanicLevel) // suppress logs in test output
|
||||||
mockWriter := httptest.NewRecorder()
|
mockWriter := httptest.NewRecorder()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue