parent
63dc2141ba
commit
241b1b5ace
|
@ -52,15 +52,15 @@ func (d Database) FetcherName() string {
|
|||
// FetchKeys implements gomatrixserverlib.KeyDatabase
|
||||
func (d *Database) FetchKeys(
|
||||
ctx context.Context,
|
||||
requests map[gomatrixserverlib.PublicKeyRequest]gomatrixserverlib.Timestamp,
|
||||
) (map[gomatrixserverlib.PublicKeyRequest]gomatrixserverlib.PublicKeyLookupResult, error) {
|
||||
requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp,
|
||||
) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) {
|
||||
return d.statements.bulkSelectServerKeys(ctx, requests)
|
||||
}
|
||||
|
||||
// StoreKeys implements gomatrixserverlib.KeyDatabase
|
||||
func (d *Database) StoreKeys(
|
||||
ctx context.Context,
|
||||
keyMap map[gomatrixserverlib.PublicKeyRequest]gomatrixserverlib.PublicKeyLookupResult,
|
||||
keyMap map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult,
|
||||
) error {
|
||||
// TODO: Inserting all the keys within a single transaction may
|
||||
// be more efficient since the transaction overhead can be quite
|
||||
|
|
|
@ -79,8 +79,8 @@ func (s *serverKeyStatements) prepare(db *sql.DB) (err error) {
|
|||
|
||||
func (s *serverKeyStatements) bulkSelectServerKeys(
|
||||
ctx context.Context,
|
||||
requests map[gomatrixserverlib.PublicKeyRequest]gomatrixserverlib.Timestamp,
|
||||
) (map[gomatrixserverlib.PublicKeyRequest]gomatrixserverlib.PublicKeyLookupResult, error) {
|
||||
requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp,
|
||||
) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) {
|
||||
var nameAndKeyIDs []string
|
||||
for request := range requests {
|
||||
nameAndKeyIDs = append(nameAndKeyIDs, nameAndKeyID(request))
|
||||
|
@ -91,7 +91,7 @@ func (s *serverKeyStatements) bulkSelectServerKeys(
|
|||
return nil, err
|
||||
}
|
||||
defer rows.Close() // nolint: errcheck
|
||||
results := map[gomatrixserverlib.PublicKeyRequest]gomatrixserverlib.PublicKeyLookupResult{}
|
||||
results := map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult{}
|
||||
for rows.Next() {
|
||||
var serverName string
|
||||
var keyID string
|
||||
|
@ -101,7 +101,7 @@ func (s *serverKeyStatements) bulkSelectServerKeys(
|
|||
if err = rows.Scan(&serverName, &keyID, &validUntilTS, &expiredTS, &key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := gomatrixserverlib.PublicKeyRequest{
|
||||
r := gomatrixserverlib.PublicKeyLookupRequest{
|
||||
ServerName: gomatrixserverlib.ServerName(serverName),
|
||||
KeyID: gomatrixserverlib.KeyID(keyID),
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ func (s *serverKeyStatements) bulkSelectServerKeys(
|
|||
|
||||
func (s *serverKeyStatements) upsertServerKeys(
|
||||
ctx context.Context,
|
||||
request gomatrixserverlib.PublicKeyRequest,
|
||||
request gomatrixserverlib.PublicKeyLookupRequest,
|
||||
key gomatrixserverlib.PublicKeyLookupResult,
|
||||
) error {
|
||||
_, err := s.upsertServerKeysStmt.ExecContext(
|
||||
|
@ -136,6 +136,6 @@ func (s *serverKeyStatements) upsertServerKeys(
|
|||
return err
|
||||
}
|
||||
|
||||
func nameAndKeyID(request gomatrixserverlib.PublicKeyRequest) string {
|
||||
func nameAndKeyID(request gomatrixserverlib.PublicKeyLookupRequest) string {
|
||||
return string(request.ServerName) + "\x1F" + string(request.KeyID)
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
{
|
||||
"importpath": "github.com/matrix-org/gomatrixserverlib",
|
||||
"repository": "https://github.com/matrix-org/gomatrixserverlib",
|
||||
"revision": "afa71391f946312c40639a419045e06b8ff2309a",
|
||||
"revision": "38a4f0f648bf357adc4bdb601cdc0535cee14e21",
|
||||
"branch": "master"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/* Copyright 2018 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package gomatrixserverlib
|
||||
|
||||
// ApplicationServiceEvent is an event format that is sent off to an
|
||||
// application service as part of a transaction.
|
||||
type ApplicationServiceEvent struct {
|
||||
Age int64 `json:"age,omitempty"`
|
||||
Content RawJSON `json:"content,omitempty"`
|
||||
EventID string `json:"event_id,omitempty"`
|
||||
OriginServerTimestamp int64 `json:"origin_server_ts,omitempty"`
|
||||
RoomID string `json:"room_id,omitempty"`
|
||||
Sender string `json:"sender,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationServiceTransaction is the transaction that is sent off to an
|
||||
// application service.
|
||||
type ApplicationServiceTransaction struct {
|
||||
Events []ApplicationServiceEvent `json:"events"`
|
||||
}
|
|
@ -30,6 +30,7 @@ import (
|
|||
|
||||
"github.com/matrix-org/gomatrix"
|
||||
"github.com/matrix-org/util"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Default HTTPS request timeout
|
||||
|
@ -207,7 +208,7 @@ func (fc *Client) GetServerKeys(
|
|||
// copy of the keys.
|
||||
// Returns the keys returned by the server, or an error if there was a problem talking to the server.
|
||||
func (fc *Client) LookupServerKeys(
|
||||
ctx context.Context, matrixServer ServerName, keyRequests map[PublicKeyRequest]Timestamp,
|
||||
ctx context.Context, matrixServer ServerName, keyRequests map[PublicKeyLookupRequest]Timestamp,
|
||||
) ([]ServerKeys, error) {
|
||||
url := url.URL{
|
||||
Scheme: "matrix",
|
||||
|
@ -332,18 +333,26 @@ func (fc *Client) DoRequestAndParseResponse(
|
|||
//
|
||||
func (fc *Client) DoHTTPRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
|
||||
reqID := util.RandomString(12)
|
||||
logger := util.GetLogger(ctx).WithField("server", req.URL.Host).WithField("out.req.ID", reqID)
|
||||
logger := util.GetLogger(ctx).WithFields(logrus.Fields{
|
||||
"out.req.ID": reqID,
|
||||
"out.req.method": req.Method,
|
||||
"out.req.uri": req.URL,
|
||||
})
|
||||
logger.Info("Outgoing request")
|
||||
newCtx := util.ContextWithLogger(ctx, logger)
|
||||
|
||||
logger.Infof("Outgoing request %s %s", req.Method, req.URL)
|
||||
start := time.Now()
|
||||
resp, err := fc.client.Do(req.WithContext(newCtx))
|
||||
if err != nil {
|
||||
logger.Infof("Outgoing request %s %s failed with %v", req.Method, req.URL, err)
|
||||
logger.WithField("error", err).Warn("Outgoing request failed")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we haven't yet read the body, so this is slightly premature, but it's the easiest place.
|
||||
logger.Infof("Response %d from %s %s", resp.StatusCode, req.Method, req.URL)
|
||||
logger.WithFields(logrus.Fields{
|
||||
"out.req.code": resp.StatusCode,
|
||||
"out.req.duration_ms": int(time.Since(start) / time.Millisecond),
|
||||
}).Info("Outgoing request returned")
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ const (
|
|||
|
||||
// ClientEvent is an event which is fit for consumption by clients, in accordance with the specification.
|
||||
type ClientEvent struct {
|
||||
Content rawJSON `json:"content"`
|
||||
Content RawJSON `json:"content"`
|
||||
EventID string `json:"event_id"`
|
||||
OriginServerTS Timestamp `json:"origin_server_ts"`
|
||||
// RoomID is omitted on /sync responses
|
||||
|
@ -36,7 +36,7 @@ type ClientEvent struct {
|
|||
Sender string `json:"sender"`
|
||||
StateKey *string `json:"state_key,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Unsigned rawJSON `json:"unsigned,omitempty"`
|
||||
Unsigned RawJSON `json:"unsigned,omitempty"`
|
||||
}
|
||||
|
||||
// ToClientEvents converts server events to client events.
|
||||
|
@ -51,11 +51,11 @@ func ToClientEvents(serverEvs []Event, format EventFormat) []ClientEvent {
|
|||
// ToClientEvent converts a single server event to a client event.
|
||||
func ToClientEvent(se Event, format EventFormat) ClientEvent {
|
||||
ce := ClientEvent{
|
||||
Content: rawJSON(se.Content()),
|
||||
Content: RawJSON(se.Content()),
|
||||
Sender: se.Sender(),
|
||||
Type: se.Type(),
|
||||
StateKey: se.StateKey(),
|
||||
Unsigned: rawJSON(se.Unsigned()),
|
||||
Unsigned: RawJSON(se.Unsigned()),
|
||||
OriginServerTS: se.OriginServerTS(),
|
||||
EventID: se.EventID(),
|
||||
}
|
||||
|
|
|
@ -69,9 +69,9 @@ type EventBuilder struct {
|
|||
// The create event has a depth of 1.
|
||||
Depth int64 `json:"depth"`
|
||||
// The JSON object for "content" key of the event.
|
||||
Content rawJSON `json:"content"`
|
||||
Content RawJSON `json:"content"`
|
||||
// The JSON object for the "unsigned" key
|
||||
Unsigned rawJSON `json:"unsigned,omitempty"`
|
||||
Unsigned RawJSON `json:"unsigned,omitempty"`
|
||||
}
|
||||
|
||||
// SetContent sets the JSON content key of the event.
|
||||
|
@ -102,12 +102,12 @@ type eventFields struct {
|
|||
Sender string `json:"sender"`
|
||||
Type string `json:"type"`
|
||||
StateKey *string `json:"state_key"`
|
||||
Content rawJSON `json:"content"`
|
||||
Content RawJSON `json:"content"`
|
||||
PrevEvents []EventReference `json:"prev_events"`
|
||||
AuthEvents []EventReference `json:"auth_events"`
|
||||
Redacts string `json:"redacts"`
|
||||
Depth int64 `json:"depth"`
|
||||
Unsigned rawJSON `json:"unsigned"`
|
||||
Unsigned RawJSON `json:"unsigned"`
|
||||
OriginServerTS Timestamp `json:"origin_server_ts"`
|
||||
Origin ServerName `json:"origin"`
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ func (e Event) Redact() Event {
|
|||
// SetUnsigned sets the unsigned key of the event.
|
||||
// Returns a copy of the event with the "unsigned" key set.
|
||||
func (e Event) SetUnsigned(unsigned interface{}) (Event, error) {
|
||||
var eventAsMap map[string]rawJSON
|
||||
var eventAsMap map[string]RawJSON
|
||||
var err error
|
||||
if err = json.Unmarshal(e.eventJSON, &eventAsMap); err != nil {
|
||||
return Event{}, err
|
||||
|
@ -326,7 +326,7 @@ func (e *Event) SetUnsignedField(path string, value interface{}) error {
|
|||
eventJSON = CanonicalJSONAssumeValid(eventJSON)
|
||||
|
||||
res := gjson.GetBytes(eventJSON, "unsigned")
|
||||
unsigned := rawJSONFromResult(res, eventJSON)
|
||||
unsigned := RawJSONFromResult(res, eventJSON)
|
||||
|
||||
e.eventJSON = eventJSON
|
||||
e.fields.Unsigned = unsigned
|
||||
|
@ -617,7 +617,7 @@ func (e Event) MarshalJSON() ([]byte, error) {
|
|||
|
||||
// UnmarshalJSON implements json.Unmarshaller
|
||||
func (er *EventReference) UnmarshalJSON(data []byte) error {
|
||||
var tuple []rawJSON
|
||||
var tuple []RawJSON
|
||||
if err := json.Unmarshal(data, &tuple); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ func stateNeededEquals(a, b StateNeeded) bool {
|
|||
type testEventList []Event
|
||||
|
||||
func (tel *testEventList) UnmarshalJSON(data []byte) error {
|
||||
var eventJSONs []rawJSON
|
||||
var eventJSONs []RawJSON
|
||||
var events []Event
|
||||
if err := json.Unmarshal([]byte(data), &eventJSONs); err != nil {
|
||||
return err
|
||||
|
@ -997,7 +997,7 @@ func TestRedactAllowed(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAuthEvents(t *testing.T) {
|
||||
power, err := NewEventFromTrustedJSON(rawJSON(`{
|
||||
power, err := NewEventFromTrustedJSON(RawJSON(`{
|
||||
"type": "m.room.power_levels",
|
||||
"state_key": "",
|
||||
"sender": "@u1:a",
|
||||
|
@ -1018,7 +1018,7 @@ func TestAuthEvents(t *testing.T) {
|
|||
if e, err = a.PowerLevels(); err != nil || e != &power {
|
||||
t.Errorf("TestAuthEvents: failed to get same power_levels event")
|
||||
}
|
||||
create, err := NewEventFromTrustedJSON(rawJSON(`{
|
||||
create, err := NewEventFromTrustedJSON(RawJSON(`{
|
||||
"type": "m.room.create",
|
||||
"state_key": "",
|
||||
"sender": "@u1:a",
|
||||
|
|
|
@ -31,7 +31,7 @@ import (
|
|||
// This hash is used to detect whether the unredacted content of the event is valid.
|
||||
// Returns the event JSON with a "hashes" key added to it.
|
||||
func addContentHashesToEvent(eventJSON []byte) ([]byte, error) {
|
||||
var event map[string]rawJSON
|
||||
var event map[string]RawJSON
|
||||
|
||||
if err := json.Unmarshal(eventJSON, &event); err != nil {
|
||||
return nil, err
|
||||
|
@ -64,7 +64,7 @@ func addContentHashesToEvent(eventJSON []byte) ([]byte, error) {
|
|||
if len(unsignedJSON) > 0 {
|
||||
event["unsigned"] = unsignedJSON
|
||||
}
|
||||
event["hashes"] = rawJSON(hashesJSON)
|
||||
event["hashes"] = RawJSON(hashesJSON)
|
||||
|
||||
return json.Marshal(event)
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ func referenceOfEvent(eventJSON []byte) (EventReference, error) {
|
|||
return EventReference{}, err
|
||||
}
|
||||
|
||||
var event map[string]rawJSON
|
||||
var event map[string]RawJSON
|
||||
if err = json.Unmarshal(redactedJSON, &event); err != nil {
|
||||
return EventReference{}, err
|
||||
}
|
||||
|
@ -150,14 +150,14 @@ func signEvent(signingName string, keyID KeyID, privateKey ed25519.PrivateKey, e
|
|||
}
|
||||
|
||||
var signedEvent struct {
|
||||
Signatures rawJSON `json:"signatures"`
|
||||
Signatures RawJSON `json:"signatures"`
|
||||
}
|
||||
if err := json.Unmarshal(signedJSON, &signedEvent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the event JSON so that we can replace the signatures key.
|
||||
var event map[string]rawJSON
|
||||
var event map[string]RawJSON
|
||||
if err := json.Unmarshal(eventJSON, &event); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ func (r RespSendJoin) MarshalJSON() ([]byte, error) {
|
|||
|
||||
// UnmarshalJSON implements json.Unmarshaller
|
||||
func (r *RespSendJoin) UnmarshalJSON(data []byte) error {
|
||||
var tuple []rawJSON
|
||||
var tuple []RawJSON
|
||||
if err := json.Unmarshal(data, &tuple); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ func (r RespInvite) MarshalJSON() ([]byte, error) {
|
|||
|
||||
// UnmarshalJSON implements json.Unmarshaller
|
||||
func (r *RespInvite) UnmarshalJSON(data []byte) error {
|
||||
var tuple []rawJSON
|
||||
var tuple []RawJSON
|
||||
if err := json.Unmarshal(data, &tuple); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2017 Jan Christian Grünhage
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package gomatrixserverlib
|
||||
|
||||
import "errors"
|
||||
|
||||
// Filter is used by clients to specify how the server should filter responses to e.g. sync requests
|
||||
// Specified by: https://matrix.org/docs/spec/client_server/r0.2.0.html#filtering
|
||||
type Filter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
EventFields []string `json:"event_fields,omitempty"`
|
||||
EventFormat string `json:"event_format,omitempty"`
|
||||
Presence FilterPart `json:"presence,omitempty"`
|
||||
Room RoomFilter `json:"room,omitempty"`
|
||||
}
|
||||
|
||||
// RoomFilter is used to define filtering rules for room events
|
||||
type RoomFilter struct {
|
||||
AccountData FilterPart `json:"account_data,omitempty"`
|
||||
Ephemeral FilterPart `json:"ephemeral,omitempty"`
|
||||
IncludeLeave bool `json:"include_leave,omitempty"`
|
||||
NotRooms []string `json:"not_rooms,omitempty"`
|
||||
Rooms []string `json:"rooms,omitempty"`
|
||||
State FilterPart `json:"state,omitempty"`
|
||||
Timeline FilterPart `json:"timeline,omitempty"`
|
||||
}
|
||||
|
||||
// FilterPart is used to define filtering rules for specific categories of events
|
||||
type FilterPart struct {
|
||||
NotRooms []string `json:"not_rooms,omitempty"`
|
||||
Rooms []string `json:"rooms,omitempty"`
|
||||
Limit int `json:"limit,omitempty"`
|
||||
NotSenders []string `json:"not_senders,omitempty"`
|
||||
NotTypes []string `json:"not_types,omitempty"`
|
||||
Senders []string `json:"senders,omitempty"`
|
||||
Types []string `json:"types,omitempty"`
|
||||
ContainsURL *bool `json:"contains_url,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the filter contains valid property values
|
||||
func (filter *Filter) Validate() error {
|
||||
if filter.EventFormat != "client" && filter.EventFormat != "federation" {
|
||||
return errors.New("Bad event_format value. Must be one of [\"client\", \"federation\"]")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DefaultFilter returns the default filter used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilter() Filter {
|
||||
return Filter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
EventFields: nil,
|
||||
EventFormat: "client",
|
||||
Presence: DefaultFilterPart(),
|
||||
Room: RoomFilter{
|
||||
AccountData: DefaultFilterPart(),
|
||||
Ephemeral: DefaultFilterPart(),
|
||||
IncludeLeave: false,
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
State: DefaultFilterPart(),
|
||||
Timeline: DefaultFilterPart(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultFilterPart returns the default filter part used by the Matrix server if no filter is provided in the request
|
||||
func DefaultFilterPart() FilterPart {
|
||||
return FilterPart{
|
||||
NotRooms: nil,
|
||||
Rooms: nil,
|
||||
Limit: 20,
|
||||
NotSenders: nil,
|
||||
NotTypes: nil,
|
||||
Senders: nil,
|
||||
Types: nil,
|
||||
}
|
||||
}
|
0
vendor/src/github.com/matrix-org/gomatrixserverlib/hooks/install.sh
vendored
Normal file → Executable file
0
vendor/src/github.com/matrix-org/gomatrixserverlib/hooks/install.sh
vendored
Normal file → Executable file
2
vendor/src/github.com/matrix-org/gomatrixserverlib/hooks/pre-commit
vendored
Normal file → Executable file
2
vendor/src/github.com/matrix-org/gomatrixserverlib/hooks/pre-commit
vendored
Normal file → Executable file
|
@ -23,7 +23,7 @@ git checkout-index -a
|
|||
|
||||
echo "Installing lint search engine..."
|
||||
go get github.com/alecthomas/gometalinter/
|
||||
gometalinter --config=linter.json --install --update
|
||||
gometalinter --config=linter.json --install --update --debug
|
||||
|
||||
echo "Testing..."
|
||||
go test
|
||||
|
|
|
@ -17,10 +17,10 @@ package gomatrixserverlib
|
|||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sort"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
|
@ -29,7 +29,7 @@ import (
|
|||
// https://matrix.org/docs/spec/server_server/unstable.html#canonical-json
|
||||
func CanonicalJSON(input []byte) ([]byte, error) {
|
||||
if !gjson.Valid(string(input)) {
|
||||
return nil, errors.Errorf("invalid json")
|
||||
return nil, fmt.Errorf("invalid json")
|
||||
}
|
||||
|
||||
return CanonicalJSONAssumeValid(input), nil
|
||||
|
@ -47,8 +47,8 @@ func CanonicalJSONAssumeValid(input []byte) []byte {
|
|||
func SortJSON(input, output []byte) []byte {
|
||||
result := gjson.ParseBytes(input)
|
||||
|
||||
rawJSON := rawJSONFromResult(result, input)
|
||||
return sortJSONValue(result, rawJSON, output)
|
||||
RawJSON := RawJSONFromResult(result, input)
|
||||
return sortJSONValue(result, RawJSON, output)
|
||||
}
|
||||
|
||||
// sortJSONValue takes a gjson.Result and sorts it. inputJSON must be the
|
||||
|
@ -77,8 +77,8 @@ func sortJSONArray(input gjson.Result, inputJSON, output []byte) []byte {
|
|||
output = append(output, sep)
|
||||
sep = ','
|
||||
|
||||
rawJSON := rawJSONFromResult(value, inputJSON)
|
||||
output = sortJSONValue(value, rawJSON, output)
|
||||
RawJSON := RawJSONFromResult(value, inputJSON)
|
||||
output = sortJSONValue(value, RawJSON, output)
|
||||
|
||||
return true // keep iterating
|
||||
})
|
||||
|
@ -110,7 +110,7 @@ func sortJSONObject(input gjson.Result, inputJSON, output []byte) []byte {
|
|||
input.ForEach(func(key, value gjson.Result) bool {
|
||||
entries = append(entries, entry{
|
||||
key: key.String(),
|
||||
rawKey: rawJSONFromResult(key, inputJSON),
|
||||
rawKey: RawJSONFromResult(key, inputJSON),
|
||||
value: value,
|
||||
})
|
||||
return true // keep iterating
|
||||
|
@ -131,9 +131,9 @@ func sortJSONObject(input gjson.Result, inputJSON, output []byte) []byte {
|
|||
output = append(output, entry.rawKey...)
|
||||
output = append(output, ':')
|
||||
|
||||
rawJSON := rawJSONFromResult(entry.value, inputJSON)
|
||||
RawJSON := RawJSONFromResult(entry.value, inputJSON)
|
||||
|
||||
output = sortJSONValue(entry.value, rawJSON, output)
|
||||
output = sortJSONValue(entry.value, RawJSON, output)
|
||||
}
|
||||
if sep == '{' {
|
||||
// If sep is still '{' then the object was empty and we never wrote the
|
||||
|
@ -263,17 +263,17 @@ func readHexDigits(input []byte) uint32 {
|
|||
return hex & 0xFFFF
|
||||
}
|
||||
|
||||
// rawJSONFromResult extracts the raw JSON bytes pointed to by result.
|
||||
// RawJSONFromResult extracts the raw JSON bytes pointed to by result.
|
||||
// input must be the json bytes that were used to generate result
|
||||
func rawJSONFromResult(result gjson.Result, input []byte) (rawJSON []byte) {
|
||||
func RawJSONFromResult(result gjson.Result, input []byte) (RawJSON []byte) {
|
||||
// This is lifted from gjson README. Basically, result.Raw is a copy of
|
||||
// the bytes we want, but its more efficient to take a slice.
|
||||
// If Index is 0 then for some reason we can't extract it from the original
|
||||
// JSON bytes.
|
||||
if result.Index > 0 {
|
||||
rawJSON = input[result.Index : result.Index+len(result.Raw)]
|
||||
RawJSON = input[result.Index : result.Index+len(result.Raw)]
|
||||
} else {
|
||||
rawJSON = []byte(result.Raw)
|
||||
RawJSON = []byte(result.Raw)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
@ -10,8 +10,8 @@ import (
|
|||
"golang.org/x/crypto/ed25519"
|
||||
)
|
||||
|
||||
// A PublicKeyRequest is a request for a public key with a particular key ID.
|
||||
type PublicKeyRequest struct {
|
||||
// A PublicKeyLookupRequest is a request for a public key with a particular key ID.
|
||||
type PublicKeyLookupRequest struct {
|
||||
// The server to fetch a key for.
|
||||
ServerName ServerName
|
||||
// The ID of the key to fetch.
|
||||
|
@ -60,7 +60,7 @@ type KeyFetcher interface {
|
|||
// The result may have fewer (server name, key ID) pairs than were in the request.
|
||||
// The result may have more (server name, key ID) pairs than were in the request.
|
||||
// Returns an error if there was a problem fetching the keys.
|
||||
FetchKeys(ctx context.Context, requests map[PublicKeyRequest]Timestamp) (map[PublicKeyRequest]PublicKeyLookupResult, error)
|
||||
FetchKeys(ctx context.Context, requests map[PublicKeyLookupRequest]Timestamp) (map[PublicKeyLookupRequest]PublicKeyLookupResult, error)
|
||||
|
||||
// FetcherName returns the name of this fetcher, which can then be used for
|
||||
// logging errors etc.
|
||||
|
@ -77,7 +77,7 @@ type KeyDatabase interface {
|
|||
// to a concurrent FetchKeys(). This is acceptable since the database is
|
||||
// only used as a cache for the keys, so if a FetchKeys() races with a
|
||||
// StoreKeys() and some of the keys are missing they will be just be refetched.
|
||||
StoreKeys(ctx context.Context, results map[PublicKeyRequest]PublicKeyLookupResult) error
|
||||
StoreKeys(ctx context.Context, results map[PublicKeyLookupRequest]PublicKeyLookupResult) error
|
||||
}
|
||||
|
||||
// A KeyRing stores keys for matrix servers and provides methods for verifying JSON messages.
|
||||
|
@ -202,15 +202,15 @@ func (k *KeyRing) isAlgorithmSupported(keyID KeyID) bool {
|
|||
|
||||
func (k *KeyRing) publicKeyRequests(
|
||||
requests []VerifyJSONRequest, results []VerifyJSONResult, keyIDs [][]KeyID,
|
||||
) map[PublicKeyRequest]Timestamp {
|
||||
keyRequests := map[PublicKeyRequest]Timestamp{}
|
||||
) map[PublicKeyLookupRequest]Timestamp {
|
||||
keyRequests := map[PublicKeyLookupRequest]Timestamp{}
|
||||
for i := range requests {
|
||||
if results[i].Error == nil {
|
||||
// We've already verified this message, we don't need to refetch the keys for it.
|
||||
continue
|
||||
}
|
||||
for _, keyID := range keyIDs[i] {
|
||||
k := PublicKeyRequest{requests[i].ServerName, keyID}
|
||||
k := PublicKeyLookupRequest{requests[i].ServerName, keyID}
|
||||
// Grab the maximum neeeded TS for this server and key ID.
|
||||
// This will default to 0 if the server and keyID weren't in the map.
|
||||
maxTS := keyRequests[k]
|
||||
|
@ -228,7 +228,7 @@ func (k *KeyRing) publicKeyRequests(
|
|||
|
||||
func (k *KeyRing) checkUsingKeys(
|
||||
requests []VerifyJSONRequest, results []VerifyJSONResult, keyIDs [][]KeyID,
|
||||
keys map[PublicKeyRequest]PublicKeyLookupResult,
|
||||
keys map[PublicKeyLookupRequest]PublicKeyLookupResult,
|
||||
) {
|
||||
for i := range requests {
|
||||
if results[i].Error == nil {
|
||||
|
@ -237,7 +237,7 @@ func (k *KeyRing) checkUsingKeys(
|
|||
continue
|
||||
}
|
||||
for _, keyID := range keyIDs[i] {
|
||||
serverKey, ok := keys[PublicKeyRequest{requests[i].ServerName, keyID}]
|
||||
serverKey, ok := keys[PublicKeyLookupRequest{requests[i].ServerName, keyID}]
|
||||
if !ok {
|
||||
// No key for this key ID so we continue onto the next key ID.
|
||||
continue
|
||||
|
@ -282,14 +282,14 @@ func (p PerspectiveKeyFetcher) FetcherName() string {
|
|||
|
||||
// FetchKeys implements KeyFetcher
|
||||
func (p *PerspectiveKeyFetcher) FetchKeys(
|
||||
ctx context.Context, requests map[PublicKeyRequest]Timestamp,
|
||||
) (map[PublicKeyRequest]PublicKeyLookupResult, error) {
|
||||
ctx context.Context, requests map[PublicKeyLookupRequest]Timestamp,
|
||||
) (map[PublicKeyLookupRequest]PublicKeyLookupResult, error) {
|
||||
serverKeys, err := p.Client.LookupServerKeys(ctx, p.PerspectiveServerName, requests)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
results := map[PublicKeyRequest]PublicKeyLookupResult{}
|
||||
results := map[PublicKeyLookupRequest]PublicKeyLookupResult{}
|
||||
|
||||
for _, keys := range serverKeys {
|
||||
var valid bool
|
||||
|
@ -347,19 +347,19 @@ func (d DirectKeyFetcher) FetcherName() string {
|
|||
|
||||
// FetchKeys implements KeyFetcher
|
||||
func (d *DirectKeyFetcher) FetchKeys(
|
||||
ctx context.Context, requests map[PublicKeyRequest]Timestamp,
|
||||
) (map[PublicKeyRequest]PublicKeyLookupResult, error) {
|
||||
byServer := map[ServerName]map[PublicKeyRequest]Timestamp{}
|
||||
ctx context.Context, requests map[PublicKeyLookupRequest]Timestamp,
|
||||
) (map[PublicKeyLookupRequest]PublicKeyLookupResult, error) {
|
||||
byServer := map[ServerName]map[PublicKeyLookupRequest]Timestamp{}
|
||||
for req, ts := range requests {
|
||||
server := byServer[req.ServerName]
|
||||
if server == nil {
|
||||
server = map[PublicKeyRequest]Timestamp{}
|
||||
server = map[PublicKeyLookupRequest]Timestamp{}
|
||||
byServer[req.ServerName] = server
|
||||
}
|
||||
server[req] = ts
|
||||
}
|
||||
|
||||
results := map[PublicKeyRequest]PublicKeyLookupResult{}
|
||||
results := map[PublicKeyLookupRequest]PublicKeyLookupResult{}
|
||||
for server := range byServer {
|
||||
// TODO: make these requests in parallel
|
||||
serverResults, err := d.fetchKeysForServer(ctx, server)
|
||||
|
@ -376,7 +376,7 @@ func (d *DirectKeyFetcher) FetchKeys(
|
|||
|
||||
func (d *DirectKeyFetcher) fetchKeysForServer(
|
||||
ctx context.Context, serverName ServerName,
|
||||
) (map[PublicKeyRequest]PublicKeyLookupResult, error) {
|
||||
) (map[PublicKeyLookupRequest]PublicKeyLookupResult, error) {
|
||||
keys, err := d.Client.GetServerKeys(ctx, serverName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -387,7 +387,7 @@ func (d *DirectKeyFetcher) fetchKeysForServer(
|
|||
return nil, fmt.Errorf("gomatrixserverlib: key response direct from %q failed checks", serverName)
|
||||
}
|
||||
|
||||
results := map[PublicKeyRequest]PublicKeyLookupResult{}
|
||||
results := map[PublicKeyLookupRequest]PublicKeyLookupResult{}
|
||||
|
||||
// TODO (matrix-org/dendrite#345): What happens if the same key ID
|
||||
// appears in multiple responses? We should probably reject the response.
|
||||
|
@ -397,11 +397,11 @@ func (d *DirectKeyFetcher) fetchKeysForServer(
|
|||
}
|
||||
|
||||
// mapServerKeysToPublicKeyLookupResult takes the (verified) result from a
|
||||
// /key/v2/query call and inserts it into a PublicKeyRequest->PublicKeyLookupResult
|
||||
// /key/v2/query call and inserts it into a PublicKeyLookupRequest->PublicKeyLookupResult
|
||||
// map.
|
||||
func mapServerKeysToPublicKeyLookupResult(serverKeys ServerKeys, results map[PublicKeyRequest]PublicKeyLookupResult) {
|
||||
func mapServerKeysToPublicKeyLookupResult(serverKeys ServerKeys, results map[PublicKeyLookupRequest]PublicKeyLookupResult) {
|
||||
for keyID, key := range serverKeys.VerifyKeys {
|
||||
results[PublicKeyRequest{
|
||||
results[PublicKeyLookupRequest{
|
||||
ServerName: serverKeys.ServerName,
|
||||
KeyID: keyID,
|
||||
}] = PublicKeyLookupResult{
|
||||
|
@ -411,7 +411,7 @@ func mapServerKeysToPublicKeyLookupResult(serverKeys ServerKeys, results map[Pub
|
|||
}
|
||||
}
|
||||
for keyID, key := range serverKeys.OldVerifyKeys {
|
||||
results[PublicKeyRequest{
|
||||
results[PublicKeyLookupRequest{
|
||||
ServerName: serverKeys.ServerName,
|
||||
KeyID: keyID,
|
||||
}] = PublicKeyLookupResult{
|
||||
|
|
|
@ -41,12 +41,12 @@ func (db testKeyDatabase) FetcherName() string {
|
|||
}
|
||||
|
||||
func (db *testKeyDatabase) FetchKeys(
|
||||
ctx context.Context, requests map[PublicKeyRequest]Timestamp,
|
||||
) (map[PublicKeyRequest]PublicKeyLookupResult, error) {
|
||||
results := map[PublicKeyRequest]PublicKeyLookupResult{}
|
||||
ctx context.Context, requests map[PublicKeyLookupRequest]Timestamp,
|
||||
) (map[PublicKeyLookupRequest]PublicKeyLookupResult, error) {
|
||||
results := map[PublicKeyLookupRequest]PublicKeyLookupResult{}
|
||||
|
||||
req1 := PublicKeyRequest{"localhost:8800", "ed25519:old"}
|
||||
req2 := PublicKeyRequest{"localhost:8800", "ed25519:a_Obwu"}
|
||||
req1 := PublicKeyLookupRequest{"localhost:8800", "ed25519:old"}
|
||||
req2 := PublicKeyLookupRequest{"localhost:8800", "ed25519:a_Obwu"}
|
||||
|
||||
for req := range requests {
|
||||
if req == req1 {
|
||||
|
@ -79,7 +79,7 @@ func (db *testKeyDatabase) FetchKeys(
|
|||
}
|
||||
|
||||
func (db *testKeyDatabase) StoreKeys(
|
||||
ctx context.Context, requests map[PublicKeyRequest]PublicKeyLookupResult,
|
||||
ctx context.Context, requests map[PublicKeyLookupRequest]PublicKeyLookupResult,
|
||||
) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -161,13 +161,13 @@ func (e erroringKeyDatabase) FetcherName() string {
|
|||
}
|
||||
|
||||
func (e *erroringKeyDatabase) FetchKeys(
|
||||
ctx context.Context, requests map[PublicKeyRequest]Timestamp,
|
||||
) (map[PublicKeyRequest]PublicKeyLookupResult, error) {
|
||||
ctx context.Context, requests map[PublicKeyLookupRequest]Timestamp,
|
||||
) (map[PublicKeyLookupRequest]PublicKeyLookupResult, error) {
|
||||
return nil, &testErrorFetch
|
||||
}
|
||||
|
||||
func (e *erroringKeyDatabase) StoreKeys(
|
||||
ctx context.Context, keys map[PublicKeyRequest]PublicKeyLookupResult,
|
||||
ctx context.Context, keys map[PublicKeyLookupRequest]PublicKeyLookupResult,
|
||||
) error {
|
||||
return &testErrorStore
|
||||
}
|
||||
|
|
|
@ -19,16 +19,16 @@ import (
|
|||
"encoding/json"
|
||||
)
|
||||
|
||||
// rawJSON is a reimplementation of json.RawMessage that supports being used as a value type
|
||||
// RawJSON is a reimplementation of json.RawMessage that supports being used as a value type
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// jsonBytes, _ := json.Marshal(struct{
|
||||
// RawMessage json.RawMessage
|
||||
// RawJSON rawJSON
|
||||
// RawJSON RawJSON
|
||||
// }{
|
||||
// json.RawMessage(`"Hello"`),
|
||||
// rawJSON(`"World"`),
|
||||
// RawJSON(`"World"`),
|
||||
// })
|
||||
//
|
||||
// Results in:
|
||||
|
@ -36,17 +36,17 @@ import (
|
|||
// {"RawMessage":"IkhlbGxvIg==","RawJSON":"World"}
|
||||
//
|
||||
// See https://play.golang.org/p/FzhKIJP8-I for a full example.
|
||||
type rawJSON []byte
|
||||
type RawJSON []byte
|
||||
|
||||
// MarshalJSON implements the json.Marshaller interface using a value receiver.
|
||||
// This means that rawJSON used as an embedded value will still encode correctly.
|
||||
func (r rawJSON) MarshalJSON() ([]byte, error) {
|
||||
// This means that RawJSON used as an embedded value will still encode correctly.
|
||||
func (r RawJSON) MarshalJSON() ([]byte, error) {
|
||||
return []byte(r), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaller interface using a pointer receiver.
|
||||
func (r *rawJSON) UnmarshalJSON(data []byte) error {
|
||||
*r = rawJSON(data)
|
||||
func (r *RawJSON) UnmarshalJSON(data []byte) error {
|
||||
*r = RawJSON(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -58,45 +58,45 @@ func redactEvent(eventJSON []byte) ([]byte, error) {
|
|||
// Create events need to keep the creator.
|
||||
// (In an ideal world they would keep the m.federate flag see matrix-org/synapse#1831)
|
||||
type createContent struct {
|
||||
Creator rawJSON `json:"creator,omitempty"`
|
||||
Creator RawJSON `json:"creator,omitempty"`
|
||||
}
|
||||
|
||||
// joinRulesContent keeps the fields needed in a m.room.join_rules event.
|
||||
// Join rules events need to keep the join_rule key.
|
||||
type joinRulesContent struct {
|
||||
JoinRule rawJSON `json:"join_rule,omitempty"`
|
||||
JoinRule RawJSON `json:"join_rule,omitempty"`
|
||||
}
|
||||
|
||||
// powerLevelContent keeps the fields needed in a m.room.power_levels event.
|
||||
// Power level events need to keep all the levels.
|
||||
type powerLevelContent struct {
|
||||
Users rawJSON `json:"users,omitempty"`
|
||||
UsersDefault rawJSON `json:"users_default,omitempty"`
|
||||
Events rawJSON `json:"events,omitempty"`
|
||||
EventsDefault rawJSON `json:"events_default,omitempty"`
|
||||
StateDefault rawJSON `json:"state_default,omitempty"`
|
||||
Ban rawJSON `json:"ban,omitempty"`
|
||||
Kick rawJSON `json:"kick,omitempty"`
|
||||
Redact rawJSON `json:"redact,omitempty"`
|
||||
Users RawJSON `json:"users,omitempty"`
|
||||
UsersDefault RawJSON `json:"users_default,omitempty"`
|
||||
Events RawJSON `json:"events,omitempty"`
|
||||
EventsDefault RawJSON `json:"events_default,omitempty"`
|
||||
StateDefault RawJSON `json:"state_default,omitempty"`
|
||||
Ban RawJSON `json:"ban,omitempty"`
|
||||
Kick RawJSON `json:"kick,omitempty"`
|
||||
Redact RawJSON `json:"redact,omitempty"`
|
||||
}
|
||||
|
||||
// memberContent keeps the fields needed in a m.room.member event.
|
||||
// Member events keep the membership.
|
||||
// (In an ideal world they would keep the third_party_invite see matrix-org/synapse#1831)
|
||||
type memberContent struct {
|
||||
Membership rawJSON `json:"membership,omitempty"`
|
||||
Membership RawJSON `json:"membership,omitempty"`
|
||||
}
|
||||
|
||||
// aliasesContent keeps the fields needed in a m.room.aliases event.
|
||||
// TODO: Alias events probably don't need to keep the aliases key, but we need to match synapse here.
|
||||
type aliasesContent struct {
|
||||
Aliases rawJSON `json:"aliases,omitempty"`
|
||||
Aliases RawJSON `json:"aliases,omitempty"`
|
||||
}
|
||||
|
||||
// historyVisibilityContent keeps the fields needed in a m.room.history_visibility event
|
||||
// History visibility events need to keep the history_visibility key.
|
||||
type historyVisibilityContent struct {
|
||||
HistoryVisibility rawJSON `json:"history_visibility,omitempty"`
|
||||
HistoryVisibility RawJSON `json:"history_visibility,omitempty"`
|
||||
}
|
||||
|
||||
// allContent keeps the union of all the content fields needed across all the event types.
|
||||
|
@ -114,21 +114,21 @@ func redactEvent(eventJSON []byte) ([]byte, error) {
|
|||
// (In an ideal world they would include the "redacts" key for m.room.redaction events, see matrix-org/synapse#1831)
|
||||
// See https://github.com/matrix-org/synapse/blob/v0.18.7/synapse/events/utils.py#L42-L56 for the list of fields
|
||||
type eventFields struct {
|
||||
EventID rawJSON `json:"event_id,omitempty"`
|
||||
Sender rawJSON `json:"sender,omitempty"`
|
||||
RoomID rawJSON `json:"room_id,omitempty"`
|
||||
Hashes rawJSON `json:"hashes,omitempty"`
|
||||
Signatures rawJSON `json:"signatures,omitempty"`
|
||||
EventID RawJSON `json:"event_id,omitempty"`
|
||||
Sender RawJSON `json:"sender,omitempty"`
|
||||
RoomID RawJSON `json:"room_id,omitempty"`
|
||||
Hashes RawJSON `json:"hashes,omitempty"`
|
||||
Signatures RawJSON `json:"signatures,omitempty"`
|
||||
Content allContent `json:"content"`
|
||||
Type string `json:"type"`
|
||||
StateKey rawJSON `json:"state_key,omitempty"`
|
||||
Depth rawJSON `json:"depth,omitempty"`
|
||||
PrevEvents rawJSON `json:"prev_events,omitempty"`
|
||||
PrevState rawJSON `json:"prev_state,omitempty"`
|
||||
AuthEvents rawJSON `json:"auth_events,omitempty"`
|
||||
Origin rawJSON `json:"origin,omitempty"`
|
||||
OriginServerTS rawJSON `json:"origin_server_ts,omitempty"`
|
||||
Membership rawJSON `json:"membership,omitempty"`
|
||||
StateKey RawJSON `json:"state_key,omitempty"`
|
||||
Depth RawJSON `json:"depth,omitempty"`
|
||||
PrevEvents RawJSON `json:"prev_events,omitempty"`
|
||||
PrevState RawJSON `json:"prev_state,omitempty"`
|
||||
AuthEvents RawJSON `json:"auth_events,omitempty"`
|
||||
Origin RawJSON `json:"origin,omitempty"`
|
||||
OriginServerTS RawJSON `json:"origin_server_ts,omitempty"`
|
||||
Membership RawJSON `json:"membership,omitempty"`
|
||||
}
|
||||
|
||||
var event eventFields
|
||||
|
|
|
@ -21,7 +21,7 @@ type FederationRequest struct {
|
|||
// fields implement the JSON format needed for signing
|
||||
// specified in https://matrix.org/docs/spec/server_server/unstable.html#request-authentication
|
||||
fields struct {
|
||||
Content rawJSON `json:"content,omitempty"`
|
||||
Content RawJSON `json:"content,omitempty"`
|
||||
Destination ServerName `json:"destination"`
|
||||
Method string `json:"method"`
|
||||
Origin ServerName `json:"origin"`
|
||||
|
@ -56,7 +56,7 @@ func (r *FederationRequest) SetContent(content interface{}) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.fields.Content = rawJSON(data)
|
||||
r.fields.Content = RawJSON(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ func readHTTPRequest(req *http.Request) (*FederationRequest, error) { // nolint:
|
|||
req.Header.Get("Content-Type"),
|
||||
)
|
||||
}
|
||||
result.fields.Content = rawJSON(content)
|
||||
result.fields.Content = RawJSON(content)
|
||||
}
|
||||
|
||||
for _, authorization := range req.Header["Authorization"] {
|
||||
|
|
|
@ -104,7 +104,7 @@ func TestSignPutRequest(t *testing.T) {
|
|||
request := NewFederationRequest(
|
||||
"PUT", "localhost:44033", "/_matrix/federation/v1/send/1493385816575/",
|
||||
)
|
||||
if err := request.SetContent(rawJSON([]byte(examplePutContent))); err != nil {
|
||||
if err := request.SetContent(RawJSON([]byte(examplePutContent))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := request.Sign("localhost:8800", "ed25519:a_Obwu", privateKey1); err != nil {
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tokens
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
macaroon "gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
||||
const (
|
||||
macaroonVersion = macaroon.V2
|
||||
defaultDuration = 2 * 60
|
||||
// UserPrefix is a common prefix for every user_id caveat
|
||||
UserPrefix = "user_id = "
|
||||
// TimePrefix is a common prefix for every expiry caveat
|
||||
TimePrefix = "time < "
|
||||
// Gen is a common caveat for every token
|
||||
Gen = "gen = 1"
|
||||
)
|
||||
|
||||
// TokenOptions represent parameters of Token
|
||||
type TokenOptions struct {
|
||||
ServerPrivateKey []byte `yaml:"private_key"`
|
||||
ServerName string `yaml:"server_name"`
|
||||
UserID string `json:"user_id"`
|
||||
Duration int // optional
|
||||
}
|
||||
|
||||
// GenerateLoginToken generates a short term login token to be used as
|
||||
// token authentication ("m.login.token")
|
||||
func GenerateLoginToken(op TokenOptions) (string, error) {
|
||||
if !isValidTokenOptions(op) {
|
||||
return "", errors.New("The given TokenOptions is invalid")
|
||||
}
|
||||
|
||||
mac, err := generateBaseMacaroon(op.ServerPrivateKey, op.ServerName, op.UserID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if op.Duration == 0 {
|
||||
op.Duration = defaultDuration
|
||||
}
|
||||
now := time.Now().Second()
|
||||
expiryCaveat := TimePrefix + strconv.Itoa(now+op.Duration)
|
||||
err = mac.AddFirstPartyCaveat([]byte(expiryCaveat))
|
||||
if err != nil {
|
||||
return "", macaroonError(err)
|
||||
}
|
||||
|
||||
urlSafeEncode, err := serializeMacaroon(*mac)
|
||||
if err != nil {
|
||||
return "", macaroonError(err)
|
||||
}
|
||||
return urlSafeEncode, nil
|
||||
}
|
||||
|
||||
// isValidTokenOptions checks for required fields in a TokenOptions
|
||||
func isValidTokenOptions(op TokenOptions) bool {
|
||||
if op.ServerPrivateKey == nil || op.ServerName == "" || op.UserID == "" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// generateBaseMacaroon generates a base macaroon common for accessToken & loginToken.
|
||||
// Returns a macaroon tied with userID,
|
||||
// returns an error if something goes wrong.
|
||||
func generateBaseMacaroon(
|
||||
secret []byte, ServerName string, userID string,
|
||||
) (*macaroon.Macaroon, error) {
|
||||
mac, err := macaroon.New(secret, []byte(userID), ServerName, macaroonVersion)
|
||||
if err != nil {
|
||||
return nil, macaroonError(err)
|
||||
}
|
||||
|
||||
err = mac.AddFirstPartyCaveat([]byte(Gen))
|
||||
if err != nil {
|
||||
return nil, macaroonError(err)
|
||||
}
|
||||
|
||||
err = mac.AddFirstPartyCaveat([]byte(UserPrefix + userID))
|
||||
if err != nil {
|
||||
return nil, macaroonError(err)
|
||||
}
|
||||
|
||||
return mac, nil
|
||||
}
|
||||
|
||||
func macaroonError(err error) error {
|
||||
return fmt.Errorf("Macaroon creation failed: %s", err.Error())
|
||||
}
|
||||
|
||||
// serializeMacaroon takes a macaroon to be serialized.
|
||||
// returns its base64 encoded string, URL safe, which can be sent via web, email, etc.
|
||||
func serializeMacaroon(m macaroon.Macaroon) (string, error) {
|
||||
bin, err := m.MarshalBinary()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
urlSafeEncode := base64.RawURLEncoding.EncodeToString(bin)
|
||||
return urlSafeEncode, nil
|
||||
}
|
||||
|
||||
// deSerializeMacaroon takes a base64 encoded string of a macaroon to be de-serialized.
|
||||
// Returns a macaroon. On failure returns error with description.
|
||||
func deSerializeMacaroon(urlSafeEncode string) (macaroon.Macaroon, error) {
|
||||
var mac macaroon.Macaroon
|
||||
bin, err := base64.RawURLEncoding.DecodeString(urlSafeEncode)
|
||||
if err != nil {
|
||||
return mac, err
|
||||
}
|
||||
|
||||
err = mac.UnmarshalBinary(bin)
|
||||
return mac, err
|
||||
}
|
102
vendor/src/github.com/matrix-org/gomatrixserverlib/tokens/tokens_handlers.go
vendored
Normal file
102
vendor/src/github.com/matrix-org/gomatrixserverlib/tokens/tokens_handlers.go
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tokens
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetUserFromToken returns the user associated with the token
|
||||
// Returns the error if something goes wrong.
|
||||
// Warning: Does not validate the token. Use ValidateToken for that.
|
||||
func GetUserFromToken(token string) (user string, err error) {
|
||||
mac, err := deSerializeMacaroon(token)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
user = string(mac.Id()[:])
|
||||
return
|
||||
}
|
||||
|
||||
// ValidateToken validates that the Token is understood and was signed by this server.
|
||||
// Returns nil if token is valid, otherwise returns a error.
|
||||
func ValidateToken(op TokenOptions, token string) error {
|
||||
mac, err := deSerializeMacaroon(token)
|
||||
if err != nil {
|
||||
return errors.New("Token does not represent a valid macaroon")
|
||||
}
|
||||
|
||||
caveats, err := mac.VerifySignature(op.ServerPrivateKey, nil)
|
||||
if err != nil {
|
||||
return errors.New("Provided token was not issued by this server")
|
||||
}
|
||||
|
||||
err = verifyCaveats(caveats, op.UserID)
|
||||
if err != nil {
|
||||
return errors.New("Provided token not authorized")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyCaveats verifies caveats associated with a login token macaroon.
|
||||
// which are "gen = 1", "user_id = ...", "time < ..."
|
||||
// Returns nil on successful verification, else returns an error.
|
||||
func verifyCaveats(caveats []string, userID string) error {
|
||||
// variable verified represents a bitmap
|
||||
// last 4 bits are Uvvv where,
|
||||
// U: unknownCaveat
|
||||
// v: caveat to be verified
|
||||
var verified uint8
|
||||
now := time.Now().Second()
|
||||
|
||||
LoopCaveat:
|
||||
for _, caveat := range caveats {
|
||||
switch {
|
||||
case caveat == Gen:
|
||||
verified |= 1
|
||||
case strings.HasPrefix(caveat, UserPrefix):
|
||||
if caveat[len(UserPrefix):] == userID {
|
||||
verified |= 2
|
||||
}
|
||||
case strings.HasPrefix(caveat, TimePrefix):
|
||||
if verifyExpiry(caveat[len(TimePrefix):], now) {
|
||||
verified |= 4
|
||||
}
|
||||
default:
|
||||
verified |= 8
|
||||
break LoopCaveat
|
||||
}
|
||||
}
|
||||
// Check that all three caveats are verified and no extra caveats
|
||||
// i.e. Uvvv == 0111
|
||||
if verified == 7 {
|
||||
return nil
|
||||
} else if verified >= 8 {
|
||||
return errors.New("Unknown caveat present")
|
||||
}
|
||||
|
||||
return errors.New("Required caveats not present")
|
||||
}
|
||||
|
||||
func verifyExpiry(t string, now int) bool {
|
||||
expiry, err := strconv.Atoi(t)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return now < expiry
|
||||
}
|
92
vendor/src/github.com/matrix-org/gomatrixserverlib/tokens/tokens_handlers_test.go
vendored
Normal file
92
vendor/src/github.com/matrix-org/gomatrixserverlib/tokens/tokens_handlers_test.go
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tokens
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// If any of these options are missing, validation should fail
|
||||
invalidMissings = []string{"ServerPrivateKey", "UserID"}
|
||||
invalidKeyTokenOp = TokenOptions{
|
||||
ServerPrivateKey: []byte("notASecretKey"),
|
||||
UserID: "aRandomUserID",
|
||||
}
|
||||
invalidUserTokenOp = TokenOptions{
|
||||
ServerPrivateKey: []byte("aSecretKey"),
|
||||
UserID: "notTheSameUserID",
|
||||
}
|
||||
)
|
||||
|
||||
func expireZeroValidTokenOp() TokenOptions {
|
||||
op := validTokenOp
|
||||
op.Duration = 0
|
||||
return op
|
||||
}
|
||||
|
||||
func TestExpiredLoginToken(t *testing.T) {
|
||||
fakeToken, err := GenerateLoginToken(expireZeroValidTokenOp())
|
||||
// token uses 1 second precision
|
||||
time.Sleep(time.Second)
|
||||
res := ValidateToken(validTokenOp, fakeToken)
|
||||
if res == nil {
|
||||
t.Error("Token validation should fail for expired token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateToken(t *testing.T) {
|
||||
fakeToken, err := GenerateLoginToken(validTokenOp)
|
||||
if err != nil {
|
||||
t.Errorf("Token generation failed for valid TokenOptions with err: %s", err.Error())
|
||||
}
|
||||
|
||||
// Test validation
|
||||
res := ValidateToken(validTokenOp, fakeToken)
|
||||
if res != nil {
|
||||
t.Error("Token validation failed with response: ", res)
|
||||
}
|
||||
|
||||
// Test validation fails for invalid TokenOp
|
||||
for _, invalidMissing := range invalidMissings {
|
||||
res = ValidateToken(invalidTokenOps[invalidMissing], fakeToken)
|
||||
if res == nil {
|
||||
t.Errorf("Token validation should fail for TokenOptions with missing %s", invalidMissing)
|
||||
}
|
||||
}
|
||||
|
||||
for _, invalid := range []TokenOptions{invalidKeyTokenOp, invalidUserTokenOp} {
|
||||
res = ValidateToken(invalid, fakeToken)
|
||||
if res == nil {
|
||||
t.Errorf("Token validation should fail for invalid TokenOptions: ", invalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUserFromToken(t *testing.T) {
|
||||
fakeToken, err := GenerateLoginToken(validTokenOp)
|
||||
if err != nil {
|
||||
t.Errorf("Token generation failed for valid TokenOptions with err: %s", err.Error())
|
||||
}
|
||||
|
||||
// Test validation
|
||||
name, err := GetUserFromToken(fakeToken)
|
||||
if err != nil {
|
||||
t.Error("Failed to get userID from Token: ", err)
|
||||
}
|
||||
|
||||
if name != validTokenOp.UserID {
|
||||
t.Error("UserID from Token doesn't match, got: ", name, " expected: ", validTokenOp.UserID)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tokens
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
validTokenOp = TokenOptions{
|
||||
ServerPrivateKey: []byte("aSecretKey"),
|
||||
ServerName: "aRandomServerName",
|
||||
UserID: "aRandomUserID",
|
||||
}
|
||||
invalidTokenOps = map[string]TokenOptions{
|
||||
"ServerPrivateKey": {
|
||||
ServerName: "aRandomServerName",
|
||||
UserID: "aRandomUserID",
|
||||
},
|
||||
"ServerName": {
|
||||
ServerPrivateKey: []byte("aSecretKey"),
|
||||
UserID: "aRandomUserID",
|
||||
},
|
||||
"UserID": {
|
||||
ServerPrivateKey: []byte("aSecretKey"),
|
||||
ServerName: "aRandomServerName",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func TestGenerateLoginToken(t *testing.T) {
|
||||
// Test valid
|
||||
_, err := GenerateLoginToken(validTokenOp)
|
||||
if err != nil {
|
||||
t.Errorf("Token generation failed for valid TokenOptions with err: %s", err.Error())
|
||||
}
|
||||
|
||||
// Test invalids
|
||||
for missing, invalidTokenOp := range invalidTokenOps {
|
||||
_, err := GenerateLoginToken(invalidTokenOp)
|
||||
if err == nil {
|
||||
t.Errorf("Token generation should fail for TokenOptions with missing %s", missing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func serializationTestError(err error) string {
|
||||
return "Token Serialization test failed with err: " + err.Error()
|
||||
}
|
||||
|
||||
func TestSerialization(t *testing.T) {
|
||||
fakeToken, err := GenerateLoginToken(validTokenOp)
|
||||
if err != nil {
|
||||
t.Errorf(serializationTestError(err))
|
||||
}
|
||||
|
||||
fakeMacaroon, err := deSerializeMacaroon(fakeToken)
|
||||
if err != nil {
|
||||
t.Errorf(serializationTestError(err))
|
||||
}
|
||||
|
||||
sameFakeToken, err := serializeMacaroon(fakeMacaroon)
|
||||
if err != nil {
|
||||
t.Errorf(serializationTestError(err))
|
||||
}
|
||||
|
||||
if sameFakeToken != fakeToken {
|
||||
t.Errorf("Token Serialization mismatch")
|
||||
}
|
||||
}
|
1
vendor/src/github.com/matrix-org/gomatrixserverlib/travis.sh
vendored
Normal file → Executable file
1
vendor/src/github.com/matrix-org/gomatrixserverlib/travis.sh
vendored
Normal file → Executable file
|
@ -16,5 +16,6 @@ go get -u \
|
|||
github.com/tidwall/sjson \
|
||||
github.com/pkg/errors \
|
||||
gopkg.in/yaml.v2 \
|
||||
gopkg.in/macaroon.v2 \
|
||||
|
||||
./hooks/pre-commit
|
||||
|
|
Loading…
Reference in New Issue