Skip to content

Commit b594f62

Browse files
authored
Merge branch 'main' into s7evink/eventsize
2 parents 8cbbea4 + db5b96f commit b594f62

File tree

127 files changed

+4050
-3827
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+4050
-3827
lines changed
File renamed without changes.

internal/b/blueprints.go renamed to b/blueprints.go

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,28 +93,10 @@ type ApplicationService struct {
9393
}
9494

9595
type Event struct {
96-
Type string
97-
Sender string
98-
StateKey *string
99-
Content map[string]interface{}
100-
101-
/* The following fields are ignored in blueprints as clients are unable to set them.
102-
* They are used with federation.Server.
103-
*/
104-
105-
Unsigned map[string]interface{}
106-
107-
// The events needed to authenticate this event.
108-
// This can be either []EventReference for room v1/v2, or []string for room v3 onwards.
109-
// If it is left at nil, MustCreateEvent will populate it automatically based on the room state.
110-
AuthEvents interface{}
111-
112-
// The prev events of the event if we want to override or falsify them.
113-
// If it is left at nil, MustCreateEvent will populate it automatically based on the forward extremities.
114-
PrevEvents interface{}
115-
116-
// If this is a redaction, the event that it redacts
117-
Redacts string
96+
Type string `json:"type"`
97+
Sender string `json:"sender,omitempty"`
98+
StateKey *string `json:"state_key,omitempty"`
99+
Content map[string]interface{} `json:"content"`
118100
}
119101

120102
func MustValidate(bp Blueprint) Blueprint {
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

client/auth.go

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package client
2+
3+
import (
4+
"crypto/hmac"
5+
"crypto/sha1"
6+
"encoding/hex"
7+
"io"
8+
9+
"github.com/tidwall/gjson"
10+
)
11+
12+
const (
13+
SharedSecret = "complement"
14+
)
15+
16+
type LoginOpt func(map[string]interface{})
17+
18+
func WithDeviceID(deviceID string) LoginOpt {
19+
return func(loginBody map[string]interface{}) {
20+
loginBody["device_id"] = deviceID
21+
}
22+
}
23+
24+
// LoginUser will log in to a homeserver and create a new device on an existing user.
25+
func (c *CSAPI) LoginUser(t TestLike, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string) {
26+
t.Helper()
27+
reqBody := map[string]interface{}{
28+
"identifier": map[string]interface{}{
29+
"type": "m.id.user",
30+
"user": localpart,
31+
},
32+
"password": password,
33+
"type": "m.login.password",
34+
}
35+
36+
for _, opt := range opts {
37+
opt(reqBody)
38+
}
39+
40+
res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, WithJSONBody(t, reqBody))
41+
42+
body, err := io.ReadAll(res.Body)
43+
if err != nil {
44+
t.Fatalf("unable to read response body: %v", err)
45+
}
46+
47+
userID = GetJSONFieldStr(t, body, "user_id")
48+
accessToken = GetJSONFieldStr(t, body, "access_token")
49+
deviceID = GetJSONFieldStr(t, body, "device_id")
50+
return userID, accessToken, deviceID
51+
}
52+
53+
// LoginUserWithRefreshToken will log in to a homeserver, with refresh token enabled,
54+
// and create a new device on an existing user.
55+
func (c *CSAPI) LoginUserWithRefreshToken(t TestLike, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64) {
56+
t.Helper()
57+
reqBody := map[string]interface{}{
58+
"identifier": map[string]interface{}{
59+
"type": "m.id.user",
60+
"user": localpart,
61+
},
62+
"password": password,
63+
"type": "m.login.password",
64+
"refresh_token": true,
65+
}
66+
res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "login"}, WithJSONBody(t, reqBody))
67+
68+
body, err := io.ReadAll(res.Body)
69+
if err != nil {
70+
t.Fatalf("unable to read response body: %v", err)
71+
}
72+
73+
userID = GetJSONFieldStr(t, body, "user_id")
74+
accessToken = GetJSONFieldStr(t, body, "access_token")
75+
deviceID = GetJSONFieldStr(t, body, "device_id")
76+
refreshToken = GetJSONFieldStr(t, body, "refresh_token")
77+
expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int()
78+
return userID, accessToken, refreshToken, deviceID, expiresInMs
79+
}
80+
81+
// RefreshToken will consume a refresh token and return a new access token and refresh token.
82+
func (c *CSAPI) ConsumeRefreshToken(t TestLike, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64) {
83+
t.Helper()
84+
reqBody := map[string]interface{}{
85+
"refresh_token": refreshToken,
86+
}
87+
res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "refresh"}, WithJSONBody(t, reqBody))
88+
89+
body, err := io.ReadAll(res.Body)
90+
if err != nil {
91+
t.Fatalf("unable to read response body: %v", err)
92+
}
93+
94+
newAccessToken = GetJSONFieldStr(t, body, "access_token")
95+
newRefreshToken = GetJSONFieldStr(t, body, "refresh_token")
96+
expiresInMs = gjson.GetBytes(body, "expires_in_ms").Int()
97+
return newAccessToken, newRefreshToken, expiresInMs
98+
}
99+
100+
// RegisterUser will register the user with given parameters and
101+
// return user ID, access token and device ID. It fails the test on network error.
102+
func (c *CSAPI) RegisterUser(t TestLike, localpart, password string) (userID, accessToken, deviceID string) {
103+
t.Helper()
104+
reqBody := map[string]interface{}{
105+
"auth": map[string]string{
106+
"type": "m.login.dummy",
107+
},
108+
"username": localpart,
109+
"password": password,
110+
}
111+
res := c.MustDo(t, "POST", []string{"_matrix", "client", "v3", "register"}, WithJSONBody(t, reqBody))
112+
113+
body, err := io.ReadAll(res.Body)
114+
if err != nil {
115+
t.Fatalf("unable to read response body: %v", err)
116+
}
117+
118+
userID = GetJSONFieldStr(t, body, "user_id")
119+
accessToken = GetJSONFieldStr(t, body, "access_token")
120+
deviceID = GetJSONFieldStr(t, body, "device_id")
121+
return userID, accessToken, deviceID
122+
}
123+
124+
// RegisterSharedSecret registers a new account with a shared secret via HMAC
125+
// See https://github.com/matrix-org/synapse/blob/e550ab17adc8dd3c48daf7fedcd09418a73f524b/synapse/_scripts/register_new_matrix_user.py#L40
126+
func (c *CSAPI) RegisterSharedSecret(t TestLike, user, pass string, isAdmin bool) (userID, accessToken, deviceID string) {
127+
resp := c.Do(t, "GET", []string{"_synapse", "admin", "v1", "register"})
128+
if resp.StatusCode != 200 {
129+
t.Skipf("Homeserver image does not support shared secret registration, /_synapse/admin/v1/register returned HTTP %d", resp.StatusCode)
130+
return
131+
}
132+
body := ParseJSON(t, resp)
133+
nonce := gjson.GetBytes(body, "nonce")
134+
if !nonce.Exists() {
135+
t.Fatalf("Malformed shared secret GET response: %s", string(body))
136+
}
137+
mac := hmac.New(sha1.New, []byte(SharedSecret))
138+
mac.Write([]byte(nonce.Str))
139+
mac.Write([]byte("\x00"))
140+
mac.Write([]byte(user))
141+
mac.Write([]byte("\x00"))
142+
mac.Write([]byte(pass))
143+
mac.Write([]byte("\x00"))
144+
if isAdmin {
145+
mac.Write([]byte("admin"))
146+
} else {
147+
mac.Write([]byte("notadmin"))
148+
}
149+
sig := mac.Sum(nil)
150+
reqBody := map[string]interface{}{
151+
"nonce": nonce.Str,
152+
"username": user,
153+
"password": pass,
154+
"mac": hex.EncodeToString(sig),
155+
"admin": isAdmin,
156+
}
157+
resp = c.MustDo(t, "POST", []string{"_synapse", "admin", "v1", "register"}, WithJSONBody(t, reqBody))
158+
body = ParseJSON(t, resp)
159+
userID = GetJSONFieldStr(t, body, "user_id")
160+
accessToken = GetJSONFieldStr(t, body, "access_token")
161+
deviceID = GetJSONFieldStr(t, body, "device_id")
162+
return userID, accessToken, deviceID
163+
}

0 commit comments

Comments
 (0)