UNPKG

64.1 kBJavaScriptView Raw
1/*
2Copyright 2015, 2016 OpenMarket Ltd
3Copyright 2017 Vector Creations Ltd
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16*/
17"use strict";
18
19/**
20 * This is an internal module. MatrixBaseApis is currently only meant to be used
21 * by {@link client~MatrixClient}.
22 *
23 * @module base-apis
24 */
25
26const httpApi = require("./http-api");
27const utils = require("./utils");
28
29/**
30 * Low-level wrappers for the Matrix APIs
31 *
32 * @constructor
33 *
34 * @param {Object} opts Configuration options
35 *
36 * @param {string} opts.baseUrl Required. The base URL to the client-server
37 * HTTP API.
38 *
39 * @param {string} opts.idBaseUrl Optional. The base identity server URL for
40 * identity server requests.
41 *
42 * @param {Function} opts.request Required. The function to invoke for HTTP
43 * requests. The value of this property is typically <code>require("request")
44 * </code> as it returns a function which meets the required interface. See
45 * {@link requestFunction} for more information.
46 *
47 * @param {string} opts.accessToken The access_token for this user.
48 *
49 * @param {Number=} opts.localTimeoutMs Optional. The default maximum amount of
50 * time to wait before timing out HTTP requests. If not specified, there is no
51 * timeout.
52 *
53 * @param {Object} opts.queryParams Optional. Extra query parameters to append
54 * to all requests with this client. Useful for application services which require
55 * <code>?user_id=</code>.
56 *
57 * @param {boolean} [opts.useAuthorizationHeader = false] Set to true to use
58 * Authorization header instead of query param to send the access token to the server.
59 */
60function MatrixBaseApis(opts) {
61 utils.checkObjectHasKeys(opts, ["baseUrl", "request"]);
62
63 this.baseUrl = opts.baseUrl;
64 this.idBaseUrl = opts.idBaseUrl;
65
66 const httpOpts = {
67 baseUrl: opts.baseUrl,
68 idBaseUrl: opts.idBaseUrl,
69 accessToken: opts.accessToken,
70 request: opts.request,
71 prefix: httpApi.PREFIX_R0,
72 onlyData: true,
73 extraParams: opts.queryParams,
74 localTimeoutMs: opts.localTimeoutMs,
75 useAuthorizationHeader: opts.useAuthorizationHeader,
76 };
77 this._http = new httpApi.MatrixHttpApi(this, httpOpts);
78
79 this._txnCtr = 0;
80}
81
82/**
83 * Get the Homeserver URL of this client
84 * @return {string} Homeserver URL of this client
85 */
86MatrixBaseApis.prototype.getHomeserverUrl = function() {
87 return this.baseUrl;
88};
89
90/**
91 * Get the Identity Server URL of this client
92 * @param {boolean} stripProto whether or not to strip the protocol from the URL
93 * @return {string} Identity Server URL of this client
94 */
95MatrixBaseApis.prototype.getIdentityServerUrl = function(stripProto=false) {
96 if (stripProto && (this.idBaseUrl.startsWith("http://") ||
97 this.idBaseUrl.startsWith("https://"))) {
98 return this.idBaseUrl.split("://")[1];
99 }
100 return this.idBaseUrl;
101};
102
103/**
104 * Get the access token associated with this account.
105 * @return {?String} The access_token or null
106 */
107MatrixBaseApis.prototype.getAccessToken = function() {
108 return this._http.opts.accessToken || null;
109};
110
111/**
112 * @return {boolean} true if there is a valid access_token for this client.
113 */
114MatrixBaseApis.prototype.isLoggedIn = function() {
115 return this._http.opts.accessToken !== undefined;
116};
117
118/**
119 * Make up a new transaction id
120 *
121 * @return {string} a new, unique, transaction id
122 */
123MatrixBaseApis.prototype.makeTxnId = function() {
124 return "m" + new Date().getTime() + "." + (this._txnCtr++);
125};
126
127
128// Registration/Login operations
129// =============================
130
131/**
132 * Check whether a username is available prior to registration. An error response
133 * indicates an invalid/unavailable username.
134 * @param {string} username The username to check the availability of.
135 * @return {module:client.Promise} Resolves: to `true`.
136 */
137MatrixBaseApis.prototype.isUsernameAvailable = function(username) {
138 return this._http.authedRequest(
139 undefined, "GET", '/register/available', { username: username },
140 ).then((response) => {
141 return response.available;
142 });
143};
144
145/**
146 * @param {string} username
147 * @param {string} password
148 * @param {string} sessionId
149 * @param {Object} auth
150 * @param {Object} bindThreepids Set key 'email' to true to bind any email
151 * threepid uses during registration in the ID server. Set 'msisdn' to
152 * true to bind msisdn.
153 * @param {string} guestAccessToken
154 * @param {module:client.callback} callback Optional.
155 * @return {module:client.Promise} Resolves: TODO
156 * @return {module:http-api.MatrixError} Rejects: with an error response.
157 */
158MatrixBaseApis.prototype.register = function(
159 username, password,
160 sessionId, auth, bindThreepids, guestAccessToken,
161 callback,
162) {
163 // backwards compat
164 if (bindThreepids === true) {
165 bindThreepids = {email: true};
166 } else if (bindThreepids === null || bindThreepids === undefined) {
167 bindThreepids = {};
168 }
169
170 if (auth === undefined || auth === null) {
171 auth = {};
172 }
173 if (sessionId) {
174 auth.session = sessionId;
175 }
176
177 const params = {
178 auth: auth,
179 };
180 if (username !== undefined && username !== null) {
181 params.username = username;
182 }
183 if (password !== undefined && password !== null) {
184 params.password = password;
185 }
186 if (bindThreepids.email) {
187 params.bind_email = true;
188 }
189 if (bindThreepids.msisdn) {
190 params.bind_msisdn = true;
191 }
192 if (guestAccessToken !== undefined && guestAccessToken !== null) {
193 params.guest_access_token = guestAccessToken;
194 }
195 // Temporary parameter added to make the register endpoint advertise
196 // msisdn flows. This exists because there are clients that break
197 // when given stages they don't recognise. This parameter will cease
198 // to be necessary once these old clients are gone.
199 // Only send it if we send any params at all (the password param is
200 // mandatory, so if we send any params, we'll send the password param)
201 if (password !== undefined && password !== null) {
202 params.x_show_msisdn = true;
203 }
204
205 return this.registerRequest(params, undefined, callback);
206};
207
208/**
209 * Register a guest account.
210 * @param {Object=} opts Registration options
211 * @param {Object} opts.body JSON HTTP body to provide.
212 * @param {module:client.callback} callback Optional.
213 * @return {module:client.Promise} Resolves: TODO
214 * @return {module:http-api.MatrixError} Rejects: with an error response.
215 */
216MatrixBaseApis.prototype.registerGuest = function(opts, callback) {
217 opts = opts || {};
218 opts.body = opts.body || {};
219 return this.registerRequest(opts.body, "guest", callback);
220};
221
222/**
223 * @param {Object} data parameters for registration request
224 * @param {string=} kind type of user to register. may be "guest"
225 * @param {module:client.callback=} callback
226 * @return {module:client.Promise} Resolves: to the /register response
227 * @return {module:http-api.MatrixError} Rejects: with an error response.
228 */
229MatrixBaseApis.prototype.registerRequest = function(data, kind, callback) {
230 const params = {};
231 if (kind) {
232 params.kind = kind;
233 }
234
235 return this._http.request(
236 callback, "POST", "/register", params, data,
237 );
238};
239
240/**
241 * @param {module:client.callback} callback Optional.
242 * @return {module:client.Promise} Resolves: TODO
243 * @return {module:http-api.MatrixError} Rejects: with an error response.
244 */
245MatrixBaseApis.prototype.loginFlows = function(callback) {
246 return this._http.request(callback, "GET", "/login");
247};
248
249/**
250 * @param {string} loginType
251 * @param {Object} data
252 * @param {module:client.callback} callback Optional.
253 * @return {module:client.Promise} Resolves: TODO
254 * @return {module:http-api.MatrixError} Rejects: with an error response.
255 */
256MatrixBaseApis.prototype.login = function(loginType, data, callback) {
257 const login_data = {
258 type: loginType,
259 };
260
261 // merge data into login_data
262 utils.extend(login_data, data);
263
264 return this._http.authedRequest(
265 (error, response) => {
266 if (loginType === "m.login.password" && response &&
267 response.access_token && response.user_id) {
268 this._http.opts.accessToken = response.access_token;
269 this.credentials = {
270 userId: response.user_id,
271 };
272 }
273
274 if (callback) {
275 callback(error, response);
276 }
277 }, "POST", "/login", undefined, login_data,
278 );
279};
280
281/**
282 * @param {string} user
283 * @param {string} password
284 * @param {module:client.callback} callback Optional.
285 * @return {module:client.Promise} Resolves: TODO
286 * @return {module:http-api.MatrixError} Rejects: with an error response.
287 */
288MatrixBaseApis.prototype.loginWithPassword = function(user, password, callback) {
289 return this.login("m.login.password", {
290 user: user,
291 password: password,
292 }, callback);
293};
294
295/**
296 * @param {string} relayState URL Callback after SAML2 Authentication
297 * @param {module:client.callback} callback Optional.
298 * @return {module:client.Promise} Resolves: TODO
299 * @return {module:http-api.MatrixError} Rejects: with an error response.
300 */
301MatrixBaseApis.prototype.loginWithSAML2 = function(relayState, callback) {
302 return this.login("m.login.saml2", {
303 relay_state: relayState,
304 }, callback);
305};
306
307/**
308 * @param {string} redirectUrl The URL to redirect to after the HS
309 * authenticates with CAS.
310 * @return {string} The HS URL to hit to begin the CAS login process.
311 */
312MatrixBaseApis.prototype.getCasLoginUrl = function(redirectUrl) {
313 return this.getSsoLoginUrl(redirectUrl, "cas");
314};
315
316/**
317 * @param {string} redirectUrl The URL to redirect to after the HS
318 * authenticates with the SSO.
319 * @param {string} loginType The type of SSO login we are doing (sso or cas).
320 * Defaults to 'sso'.
321 * @return {string} The HS URL to hit to begin the SSO login process.
322 */
323MatrixBaseApis.prototype.getSsoLoginUrl = function(redirectUrl, loginType) {
324 if (loginType === undefined) {
325 loginType = "sso";
326 }
327 return this._http.getUrl("/login/"+loginType+"/redirect", {
328 "redirectUrl": redirectUrl,
329 }, httpApi.PREFIX_R0);
330};
331
332/**
333 * @param {string} token Login token previously received from homeserver
334 * @param {module:client.callback} callback Optional.
335 * @return {module:client.Promise} Resolves: TODO
336 * @return {module:http-api.MatrixError} Rejects: with an error response.
337 */
338MatrixBaseApis.prototype.loginWithToken = function(token, callback) {
339 return this.login("m.login.token", {
340 token: token,
341 }, callback);
342};
343
344
345/**
346 * Logs out the current session.
347 * Obviously, further calls that require authorisation should fail after this
348 * method is called. The state of the MatrixClient object is not affected:
349 * it is up to the caller to either reset or destroy the MatrixClient after
350 * this method succeeds.
351 * @param {module:client.callback} callback Optional.
352 * @return {module:client.Promise} Resolves: On success, the empty object
353 */
354MatrixBaseApis.prototype.logout = function(callback) {
355 return this._http.authedRequest(
356 callback, "POST", '/logout',
357 );
358};
359
360/**
361 * Deactivates the logged-in account.
362 * Obviously, further calls that require authorisation should fail after this
363 * method is called. The state of the MatrixClient object is not affected:
364 * it is up to the caller to either reset or destroy the MatrixClient after
365 * this method succeeds.
366 * @param {object} auth Optional. Auth data to supply for User-Interactive auth.
367 * @param {boolean} erase Optional. If set, send as `erase` attribute in the
368 * JSON request body, indicating whether the account should be erased. Defaults
369 * to false.
370 * @return {module:client.Promise} Resolves: On success, the empty object
371 */
372MatrixBaseApis.prototype.deactivateAccount = function(auth, erase) {
373 if (typeof(erase) === 'function') {
374 throw new Error(
375 'deactivateAccount no longer accepts a callback parameter',
376 );
377 }
378
379 const body = {};
380 if (auth) {
381 body.auth = auth;
382 }
383 if (erase !== undefined) {
384 body.erase = erase;
385 }
386
387 return this._http.authedRequestWithPrefix(
388 undefined, "POST", '/account/deactivate', undefined, body,
389 httpApi.PREFIX_R0,
390 );
391};
392
393/**
394 * Get the fallback URL to use for unknown interactive-auth stages.
395 *
396 * @param {string} loginType the type of stage being attempted
397 * @param {string} authSessionId the auth session ID provided by the homeserver
398 *
399 * @return {string} HS URL to hit to for the fallback interface
400 */
401MatrixBaseApis.prototype.getFallbackAuthUrl = function(loginType, authSessionId) {
402 const path = utils.encodeUri("/auth/$loginType/fallback/web", {
403 $loginType: loginType,
404 });
405
406 return this._http.getUrl(path, {
407 session: authSessionId,
408 }, httpApi.PREFIX_R0);
409};
410
411// Room operations
412// ===============
413
414/**
415 * Create a new room.
416 * @param {Object} options a list of options to pass to the /createRoom API.
417 * @param {string} options.room_alias_name The alias localpart to assign to
418 * this room.
419 * @param {string} options.visibility Either 'public' or 'private'.
420 * @param {string[]} options.invite A list of user IDs to invite to this room.
421 * @param {string} options.name The name to give this room.
422 * @param {string} options.topic The topic to give this room.
423 * @param {module:client.callback} callback Optional.
424 * @return {module:client.Promise} Resolves: <code>{room_id: {string},
425 * room_alias: {string(opt)}}</code>
426 * @return {module:http-api.MatrixError} Rejects: with an error response.
427 */
428MatrixBaseApis.prototype.createRoom = function(options, callback) {
429 // valid options include: room_alias_name, visibility, invite
430 return this._http.authedRequest(
431 callback, "POST", "/createRoom", undefined, options,
432 );
433};
434
435/**
436 * @param {string} roomId
437 * @param {module:client.callback} callback Optional.
438 * @return {module:client.Promise} Resolves: TODO
439 * @return {module:http-api.MatrixError} Rejects: with an error response.
440 */
441MatrixBaseApis.prototype.roomState = function(roomId, callback) {
442 const path = utils.encodeUri("/rooms/$roomId/state", {$roomId: roomId});
443 return this._http.authedRequest(callback, "GET", path);
444};
445
446/**
447 * Get an event in a room by its event id.
448 * @param {string} roomId
449 * @param {string} eventId
450 * @param {module:client.callback} callback Optional.
451 *
452 * @return {Promise} Resolves to an object containing the event.
453 * @return {module:http-api.MatrixError} Rejects: with an error response.
454 */
455MatrixBaseApis.prototype.fetchRoomEvent = function(roomId, eventId, callback) {
456 const path = utils.encodeUri(
457 "/rooms/$roomId/event/$eventId", {
458 $roomId: roomId,
459 $eventId: eventId,
460 },
461 );
462 return this._http.authedRequest(callback, "GET", path);
463};
464
465/**
466 * @param {string} roomId
467 * @param {string} includeMembership the membership type to include in the response
468 * @param {string} excludeMembership the membership type to exclude from the response
469 * @param {string} atEventId the id of the event for which moment in the timeline the members should be returned for
470 * @param {module:client.callback} callback Optional.
471 * @return {module:client.Promise} Resolves: dictionary of userid to profile information
472 * @return {module:http-api.MatrixError} Rejects: with an error response.
473 */
474MatrixBaseApis.prototype.members =
475function(roomId, includeMembership, excludeMembership, atEventId, callback) {
476 const queryParams = {};
477 if (includeMembership) {
478 queryParams.membership = includeMembership;
479 }
480 if (excludeMembership) {
481 queryParams.not_membership = excludeMembership;
482 }
483 if (atEventId) {
484 queryParams.at = atEventId;
485 }
486
487 const queryString = utils.encodeParams(queryParams);
488
489 const path = utils.encodeUri("/rooms/$roomId/members?" + queryString,
490 {$roomId: roomId});
491 return this._http.authedRequest(callback, "GET", path);
492};
493
494/**
495 * Upgrades a room to a new protocol version
496 * @param {string} roomId
497 * @param {string} newVersion The target version to upgrade to
498 * @return {module:client.Promise} Resolves: Object with key 'replacement_room'
499 * @return {module:http-api.MatrixError} Rejects: with an error response.
500 */
501MatrixBaseApis.prototype.upgradeRoom = function(roomId, newVersion) {
502 const path = utils.encodeUri("/rooms/$roomId/upgrade", {$roomId: roomId});
503 return this._http.authedRequest(
504 undefined, "POST", path, undefined, {new_version: newVersion},
505 );
506};
507
508
509/**
510 * @param {string} groupId
511 * @return {module:client.Promise} Resolves: Group summary object
512 * @return {module:http-api.MatrixError} Rejects: with an error response.
513 */
514MatrixBaseApis.prototype.getGroupSummary = function(groupId) {
515 const path = utils.encodeUri("/groups/$groupId/summary", {$groupId: groupId});
516 return this._http.authedRequest(undefined, "GET", path);
517};
518
519/**
520 * @param {string} groupId
521 * @return {module:client.Promise} Resolves: Group profile object
522 * @return {module:http-api.MatrixError} Rejects: with an error response.
523 */
524MatrixBaseApis.prototype.getGroupProfile = function(groupId) {
525 const path = utils.encodeUri("/groups/$groupId/profile", {$groupId: groupId});
526 return this._http.authedRequest(undefined, "GET", path);
527};
528
529/**
530 * @param {string} groupId
531 * @param {Object} profile The group profile object
532 * @param {string=} profile.name Name of the group
533 * @param {string=} profile.avatar_url MXC avatar URL
534 * @param {string=} profile.short_description A short description of the room
535 * @param {string=} profile.long_description A longer HTML description of the room
536 * @return {module:client.Promise} Resolves: Empty object
537 * @return {module:http-api.MatrixError} Rejects: with an error response.
538 */
539MatrixBaseApis.prototype.setGroupProfile = function(groupId, profile) {
540 const path = utils.encodeUri("/groups/$groupId/profile", {$groupId: groupId});
541 return this._http.authedRequest(
542 undefined, "POST", path, undefined, profile,
543 );
544};
545
546/**
547 * @param {string} groupId
548 * @param {object} policy The join policy for the group. Must include at
549 * least a 'type' field which is 'open' if anyone can join the group
550 * the group without prior approval, or 'invite' if an invite is
551 * required to join.
552 * @return {module:client.Promise} Resolves: Empty object
553 * @return {module:http-api.MatrixError} Rejects: with an error response.
554 */
555MatrixBaseApis.prototype.setGroupJoinPolicy = function(groupId, policy) {
556 const path = utils.encodeUri(
557 "/groups/$groupId/settings/m.join_policy",
558 {$groupId: groupId},
559 );
560 return this._http.authedRequest(
561 undefined, "PUT", path, undefined, {
562 'm.join_policy': policy,
563 },
564 );
565};
566
567/**
568 * @param {string} groupId
569 * @return {module:client.Promise} Resolves: Group users list object
570 * @return {module:http-api.MatrixError} Rejects: with an error response.
571 */
572MatrixBaseApis.prototype.getGroupUsers = function(groupId) {
573 const path = utils.encodeUri("/groups/$groupId/users", {$groupId: groupId});
574 return this._http.authedRequest(undefined, "GET", path);
575};
576
577/**
578 * @param {string} groupId
579 * @return {module:client.Promise} Resolves: Group users list object
580 * @return {module:http-api.MatrixError} Rejects: with an error response.
581 */
582MatrixBaseApis.prototype.getGroupInvitedUsers = function(groupId) {
583 const path = utils.encodeUri("/groups/$groupId/invited_users", {$groupId: groupId});
584 return this._http.authedRequest(undefined, "GET", path);
585};
586
587/**
588 * @param {string} groupId
589 * @return {module:client.Promise} Resolves: Group rooms list object
590 * @return {module:http-api.MatrixError} Rejects: with an error response.
591 */
592MatrixBaseApis.prototype.getGroupRooms = function(groupId) {
593 const path = utils.encodeUri("/groups/$groupId/rooms", {$groupId: groupId});
594 return this._http.authedRequest(undefined, "GET", path);
595};
596
597/**
598 * @param {string} groupId
599 * @param {string} userId
600 * @return {module:client.Promise} Resolves: Empty object
601 * @return {module:http-api.MatrixError} Rejects: with an error response.
602 */
603MatrixBaseApis.prototype.inviteUserToGroup = function(groupId, userId) {
604 const path = utils.encodeUri(
605 "/groups/$groupId/admin/users/invite/$userId",
606 {$groupId: groupId, $userId: userId},
607 );
608 return this._http.authedRequest(undefined, "PUT", path, undefined, {});
609};
610
611/**
612 * @param {string} groupId
613 * @param {string} userId
614 * @return {module:client.Promise} Resolves: Empty object
615 * @return {module:http-api.MatrixError} Rejects: with an error response.
616 */
617MatrixBaseApis.prototype.removeUserFromGroup = function(groupId, userId) {
618 const path = utils.encodeUri(
619 "/groups/$groupId/admin/users/remove/$userId",
620 {$groupId: groupId, $userId: userId},
621 );
622 return this._http.authedRequest(undefined, "PUT", path, undefined, {});
623};
624
625/**
626 * @param {string} groupId
627 * @param {string} userId
628 * @param {string} roleId Optional.
629 * @return {module:client.Promise} Resolves: Empty object
630 * @return {module:http-api.MatrixError} Rejects: with an error response.
631 */
632MatrixBaseApis.prototype.addUserToGroupSummary = function(groupId, userId, roleId) {
633 const path = utils.encodeUri(
634 roleId ?
635 "/groups/$groupId/summary/$roleId/users/$userId" :
636 "/groups/$groupId/summary/users/$userId",
637 {$groupId: groupId, $roleId: roleId, $userId: userId},
638 );
639 return this._http.authedRequest(undefined, "PUT", path, undefined, {});
640};
641
642/**
643 * @param {string} groupId
644 * @param {string} userId
645 * @return {module:client.Promise} Resolves: Empty object
646 * @return {module:http-api.MatrixError} Rejects: with an error response.
647 */
648MatrixBaseApis.prototype.removeUserFromGroupSummary = function(groupId, userId) {
649 const path = utils.encodeUri(
650 "/groups/$groupId/summary/users/$userId",
651 {$groupId: groupId, $userId: userId},
652 );
653 return this._http.authedRequest(undefined, "DELETE", path, undefined, {});
654};
655
656/**
657 * @param {string} groupId
658 * @param {string} roomId
659 * @param {string} categoryId Optional.
660 * @return {module:client.Promise} Resolves: Empty object
661 * @return {module:http-api.MatrixError} Rejects: with an error response.
662 */
663MatrixBaseApis.prototype.addRoomToGroupSummary = function(groupId, roomId, categoryId) {
664 const path = utils.encodeUri(
665 categoryId ?
666 "/groups/$groupId/summary/$categoryId/rooms/$roomId" :
667 "/groups/$groupId/summary/rooms/$roomId",
668 {$groupId: groupId, $categoryId: categoryId, $roomId: roomId},
669 );
670 return this._http.authedRequest(undefined, "PUT", path, undefined, {});
671};
672
673/**
674 * @param {string} groupId
675 * @param {string} roomId
676 * @return {module:client.Promise} Resolves: Empty object
677 * @return {module:http-api.MatrixError} Rejects: with an error response.
678 */
679MatrixBaseApis.prototype.removeRoomFromGroupSummary = function(groupId, roomId) {
680 const path = utils.encodeUri(
681 "/groups/$groupId/summary/rooms/$roomId",
682 {$groupId: groupId, $roomId: roomId},
683 );
684 return this._http.authedRequest(undefined, "DELETE", path, undefined, {});
685};
686
687/**
688 * @param {string} groupId
689 * @param {string} roomId
690 * @param {bool} isPublic Whether the room-group association is visible to non-members
691 * @return {module:client.Promise} Resolves: Empty object
692 * @return {module:http-api.MatrixError} Rejects: with an error response.
693 */
694MatrixBaseApis.prototype.addRoomToGroup = function(groupId, roomId, isPublic) {
695 if (isPublic === undefined) {
696 isPublic = true;
697 }
698 const path = utils.encodeUri(
699 "/groups/$groupId/admin/rooms/$roomId",
700 {$groupId: groupId, $roomId: roomId},
701 );
702 return this._http.authedRequest(undefined, "PUT", path, undefined,
703 { "m.visibility": { type: isPublic ? "public" : "private" } },
704 );
705};
706
707/**
708 * Configure the visibility of a room-group association.
709 * @param {string} groupId
710 * @param {string} roomId
711 * @param {bool} isPublic Whether the room-group association is visible to non-members
712 * @return {module:client.Promise} Resolves: Empty object
713 * @return {module:http-api.MatrixError} Rejects: with an error response.
714 */
715MatrixBaseApis.prototype.updateGroupRoomVisibility = function(groupId, roomId, isPublic) {
716 // NB: The /config API is generic but there's not much point in exposing this yet as synapse
717 // is the only server to implement this. In future we should consider an API that allows
718 // arbitrary configuration, i.e. "config/$configKey".
719
720 const path = utils.encodeUri(
721 "/groups/$groupId/admin/rooms/$roomId/config/m.visibility",
722 {$groupId: groupId, $roomId: roomId},
723 );
724 return this._http.authedRequest(undefined, "PUT", path, undefined,
725 { type: isPublic ? "public" : "private" },
726 );
727};
728
729/**
730 * @param {string} groupId
731 * @param {string} roomId
732 * @return {module:client.Promise} Resolves: Empty object
733 * @return {module:http-api.MatrixError} Rejects: with an error response.
734 */
735MatrixBaseApis.prototype.removeRoomFromGroup = function(groupId, roomId) {
736 const path = utils.encodeUri(
737 "/groups/$groupId/admin/rooms/$roomId",
738 {$groupId: groupId, $roomId: roomId},
739 );
740 return this._http.authedRequest(undefined, "DELETE", path, undefined, {});
741};
742
743/**
744 * @param {string} groupId
745 * @param {Object} opts Additional options to send alongside the acceptance.
746 * @return {module:client.Promise} Resolves: Empty object
747 * @return {module:http-api.MatrixError} Rejects: with an error response.
748 */
749MatrixBaseApis.prototype.acceptGroupInvite = function(groupId, opts = null) {
750 const path = utils.encodeUri(
751 "/groups/$groupId/self/accept_invite",
752 {$groupId: groupId},
753 );
754 return this._http.authedRequest(undefined, "PUT", path, undefined, opts || {});
755};
756
757/**
758 * @param {string} groupId
759 * @return {module:client.Promise} Resolves: Empty object
760 * @return {module:http-api.MatrixError} Rejects: with an error response.
761 */
762MatrixBaseApis.prototype.joinGroup = function(groupId) {
763 const path = utils.encodeUri(
764 "/groups/$groupId/self/join",
765 {$groupId: groupId},
766 );
767 return this._http.authedRequest(undefined, "PUT", path, undefined, {});
768};
769
770/**
771 * @param {string} groupId
772 * @return {module:client.Promise} Resolves: Empty object
773 * @return {module:http-api.MatrixError} Rejects: with an error response.
774 */
775MatrixBaseApis.prototype.leaveGroup = function(groupId) {
776 const path = utils.encodeUri(
777 "/groups/$groupId/self/leave",
778 {$groupId: groupId},
779 );
780 return this._http.authedRequest(undefined, "PUT", path, undefined, {});
781};
782
783/**
784 * @return {module:client.Promise} Resolves: The groups to which the user is joined
785 * @return {module:http-api.MatrixError} Rejects: with an error response.
786 */
787MatrixBaseApis.prototype.getJoinedGroups = function() {
788 const path = utils.encodeUri("/joined_groups");
789 return this._http.authedRequest(undefined, "GET", path);
790};
791
792/**
793 * @param {Object} content Request content
794 * @param {string} content.localpart The local part of the desired group ID
795 * @param {Object} content.profile Group profile object
796 * @return {module:client.Promise} Resolves: Object with key group_id: id of the created group
797 * @return {module:http-api.MatrixError} Rejects: with an error response.
798 */
799MatrixBaseApis.prototype.createGroup = function(content) {
800 const path = utils.encodeUri("/create_group");
801 return this._http.authedRequest(
802 undefined, "POST", path, undefined, content,
803 );
804};
805
806/**
807 * @param {string[]} userIds List of user IDs
808 * @return {module:client.Promise} Resolves: Object as exmaple below
809 *
810 * {
811 * "users": {
812 * "@bob:example.com": {
813 * "+example:example.com"
814 * }
815 * }
816 * }
817 * @return {module:http-api.MatrixError} Rejects: with an error response.
818 */
819MatrixBaseApis.prototype.getPublicisedGroups = function(userIds) {
820 const path = utils.encodeUri("/publicised_groups");
821 return this._http.authedRequest(
822 undefined, "POST", path, undefined, { user_ids: userIds },
823 );
824};
825
826/**
827 * @param {string} groupId
828 * @param {bool} isPublic Whether the user's membership of this group is made public
829 * @return {module:client.Promise} Resolves: Empty object
830 * @return {module:http-api.MatrixError} Rejects: with an error response.
831 */
832MatrixBaseApis.prototype.setGroupPublicity = function(groupId, isPublic) {
833 const path = utils.encodeUri(
834 "/groups/$groupId/self/update_publicity",
835 {$groupId: groupId},
836 );
837 return this._http.authedRequest(undefined, "PUT", path, undefined, {
838 publicise: isPublic,
839 });
840};
841
842/**
843 * Retrieve a state event.
844 * @param {string} roomId
845 * @param {string} eventType
846 * @param {string} stateKey
847 * @param {module:client.callback} callback Optional.
848 * @return {module:client.Promise} Resolves: TODO
849 * @return {module:http-api.MatrixError} Rejects: with an error response.
850 */
851MatrixBaseApis.prototype.getStateEvent = function(roomId, eventType, stateKey, callback) {
852 const pathParams = {
853 $roomId: roomId,
854 $eventType: eventType,
855 $stateKey: stateKey,
856 };
857 let path = utils.encodeUri("/rooms/$roomId/state/$eventType", pathParams);
858 if (stateKey !== undefined) {
859 path = utils.encodeUri(path + "/$stateKey", pathParams);
860 }
861 return this._http.authedRequest(
862 callback, "GET", path,
863 );
864};
865
866/**
867 * @param {string} roomId
868 * @param {string} eventType
869 * @param {Object} content
870 * @param {string} stateKey
871 * @param {module:client.callback} callback Optional.
872 * @return {module:client.Promise} Resolves: TODO
873 * @return {module:http-api.MatrixError} Rejects: with an error response.
874 */
875MatrixBaseApis.prototype.sendStateEvent = function(roomId, eventType, content, stateKey,
876 callback) {
877 const pathParams = {
878 $roomId: roomId,
879 $eventType: eventType,
880 $stateKey: stateKey,
881 };
882 let path = utils.encodeUri("/rooms/$roomId/state/$eventType", pathParams);
883 if (stateKey !== undefined) {
884 path = utils.encodeUri(path + "/$stateKey", pathParams);
885 }
886 return this._http.authedRequest(
887 callback, "PUT", path, undefined, content,
888 );
889};
890
891/**
892 * @param {string} roomId
893 * @param {string} eventId
894 * @param {module:client.callback} callback Optional.
895 * @return {module:client.Promise} Resolves: TODO
896 * @return {module:http-api.MatrixError} Rejects: with an error response.
897 */
898MatrixBaseApis.prototype.redactEvent = function(roomId, eventId, callback) {
899 const path = utils.encodeUri("/rooms/$roomId/redact/$eventId", {
900 $roomId: roomId,
901 $eventId: eventId,
902 });
903 return this._http.authedRequest(callback, "POST", path, undefined, {});
904};
905
906/**
907 * @param {string} roomId
908 * @param {Number} limit
909 * @param {module:client.callback} callback Optional.
910 * @return {module:client.Promise} Resolves: TODO
911 * @return {module:http-api.MatrixError} Rejects: with an error response.
912 */
913MatrixBaseApis.prototype.roomInitialSync = function(roomId, limit, callback) {
914 if (utils.isFunction(limit)) {
915 callback = limit; limit = undefined;
916 }
917 const path = utils.encodeUri("/rooms/$roomId/initialSync",
918 {$roomId: roomId},
919 );
920 if (!limit) {
921 limit = 30;
922 }
923 return this._http.authedRequest(
924 callback, "GET", path, { limit: limit },
925 );
926};
927
928/**
929 * Set a marker to indicate the point in a room before which the user has read every
930 * event. This can be retrieved from room account data (the event type is `m.fully_read`)
931 * and displayed as a horizontal line in the timeline that is visually distinct to the
932 * position of the user's own read receipt.
933 * @param {string} roomId ID of the room that has been read
934 * @param {string} rmEventId ID of the event that has been read
935 * @param {string} rrEventId ID of the event tracked by the read receipt. This is here
936 * for convenience because the RR and the RM are commonly updated at the same time as
937 * each other. Optional.
938 * @return {module:client.Promise} Resolves: the empty object, {}.
939 */
940MatrixBaseApis.prototype.setRoomReadMarkersHttpRequest =
941 function(roomId, rmEventId, rrEventId) {
942 const path = utils.encodeUri("/rooms/$roomId/read_markers", {
943 $roomId: roomId,
944 });
945
946 const content = {
947 "m.fully_read": rmEventId,
948 "m.read": rrEventId,
949 };
950
951 return this._http.authedRequest(
952 undefined, "POST", path, undefined, content,
953 );
954};
955
956/**
957 * @return {module:client.Promise} Resolves: A list of the user's current rooms
958 * @return {module:http-api.MatrixError} Rejects: with an error response.
959 */
960MatrixBaseApis.prototype.getJoinedRooms = function() {
961 const path = utils.encodeUri("/joined_rooms");
962 return this._http.authedRequest(undefined, "GET", path);
963};
964
965/**
966 * Retrieve membership info. for a room.
967 * @param {string} roomId ID of the room to get membership for
968 * @return {module:client.Promise} Resolves: A list of currently joined users
969 * and their profile data.
970 * @return {module:http-api.MatrixError} Rejects: with an error response.
971 */
972MatrixBaseApis.prototype.getJoinedRoomMembers = function(roomId) {
973 const path = utils.encodeUri("/rooms/$roomId/joined_members", {
974 $roomId: roomId,
975 });
976 return this._http.authedRequest(undefined, "GET", path);
977};
978
979// Room Directory operations
980// =========================
981
982/**
983 * @param {Object} options Options for this request
984 * @param {string} options.server The remote server to query for the room list.
985 * Optional. If unspecified, get the local home
986 * server's public room list.
987 * @param {number} options.limit Maximum number of entries to return
988 * @param {string} options.since Token to paginate from
989 * @param {object} options.filter Filter parameters
990 * @param {string} options.filter.generic_search_term String to search for
991 * @param {module:client.callback} callback Optional.
992 * @return {module:client.Promise} Resolves: TODO
993 * @return {module:http-api.MatrixError} Rejects: with an error response.
994 */
995MatrixBaseApis.prototype.publicRooms = function(options, callback) {
996 if (typeof(options) == 'function') {
997 callback = options;
998 options = {};
999 }
1000 if (options === undefined) {
1001 options = {};
1002 }
1003
1004 const query_params = {};
1005 if (options.server) {
1006 query_params.server = options.server;
1007 delete options.server;
1008 }
1009
1010 if (Object.keys(options).length === 0 && Object.keys(query_params).length === 0) {
1011 return this._http.authedRequest(callback, "GET", "/publicRooms");
1012 } else {
1013 return this._http.authedRequest(
1014 callback, "POST", "/publicRooms", query_params, options,
1015 );
1016 }
1017};
1018
1019/**
1020 * Create an alias to room ID mapping.
1021 * @param {string} alias The room alias to create.
1022 * @param {string} roomId The room ID to link the alias to.
1023 * @param {module:client.callback} callback Optional.
1024 * @return {module:client.Promise} Resolves: TODO.
1025 * @return {module:http-api.MatrixError} Rejects: with an error response.
1026 */
1027MatrixBaseApis.prototype.createAlias = function(alias, roomId, callback) {
1028 const path = utils.encodeUri("/directory/room/$alias", {
1029 $alias: alias,
1030 });
1031 const data = {
1032 room_id: roomId,
1033 };
1034 return this._http.authedRequest(
1035 callback, "PUT", path, undefined, data,
1036 );
1037};
1038
1039/**
1040 * Delete an alias to room ID mapping. This alias must be on your local server
1041 * and you must have sufficient access to do this operation.
1042 * @param {string} alias The room alias to delete.
1043 * @param {module:client.callback} callback Optional.
1044 * @return {module:client.Promise} Resolves: TODO.
1045 * @return {module:http-api.MatrixError} Rejects: with an error response.
1046 */
1047MatrixBaseApis.prototype.deleteAlias = function(alias, callback) {
1048 const path = utils.encodeUri("/directory/room/$alias", {
1049 $alias: alias,
1050 });
1051 return this._http.authedRequest(
1052 callback, "DELETE", path, undefined, undefined,
1053 );
1054};
1055
1056/**
1057 * Get room info for the given alias.
1058 * @param {string} alias The room alias to resolve.
1059 * @param {module:client.callback} callback Optional.
1060 * @return {module:client.Promise} Resolves: Object with room_id and servers.
1061 * @return {module:http-api.MatrixError} Rejects: with an error response.
1062 */
1063MatrixBaseApis.prototype.getRoomIdForAlias = function(alias, callback) {
1064 // TODO: deprecate this or resolveRoomAlias
1065 const path = utils.encodeUri("/directory/room/$alias", {
1066 $alias: alias,
1067 });
1068 return this._http.authedRequest(
1069 callback, "GET", path,
1070 );
1071};
1072
1073/**
1074 * @param {string} roomAlias
1075 * @param {module:client.callback} callback Optional.
1076 * @return {module:client.Promise} Resolves: TODO
1077 * @return {module:http-api.MatrixError} Rejects: with an error response.
1078 */
1079MatrixBaseApis.prototype.resolveRoomAlias = function(roomAlias, callback) {
1080 // TODO: deprecate this or getRoomIdForAlias
1081 const path = utils.encodeUri("/directory/room/$alias", {$alias: roomAlias});
1082 return this._http.request(callback, "GET", path);
1083};
1084
1085/**
1086 * Get the visibility of a room in the current HS's room directory
1087 * @param {string} roomId
1088 * @param {module:client.callback} callback Optional.
1089 * @return {module:client.Promise} Resolves: TODO
1090 * @return {module:http-api.MatrixError} Rejects: with an error response.
1091 */
1092MatrixBaseApis.prototype.getRoomDirectoryVisibility =
1093 function(roomId, callback) {
1094 const path = utils.encodeUri("/directory/list/room/$roomId", {
1095 $roomId: roomId,
1096 });
1097 return this._http.authedRequest(callback, "GET", path);
1098};
1099
1100/**
1101 * Set the visbility of a room in the current HS's room directory
1102 * @param {string} roomId
1103 * @param {string} visibility "public" to make the room visible
1104 * in the public directory, or "private" to make
1105 * it invisible.
1106 * @param {module:client.callback} callback Optional.
1107 * @return {module:client.Promise} Resolves: result object
1108 * @return {module:http-api.MatrixError} Rejects: with an error response.
1109 */
1110MatrixBaseApis.prototype.setRoomDirectoryVisibility =
1111 function(roomId, visibility, callback) {
1112 const path = utils.encodeUri("/directory/list/room/$roomId", {
1113 $roomId: roomId,
1114 });
1115 return this._http.authedRequest(
1116 callback, "PUT", path, undefined, { "visibility": visibility },
1117 );
1118};
1119
1120/**
1121 * Set the visbility of a room bridged to a 3rd party network in
1122 * the current HS's room directory.
1123 * @param {string} networkId the network ID of the 3rd party
1124 * instance under which this room is published under.
1125 * @param {string} roomId
1126 * @param {string} visibility "public" to make the room visible
1127 * in the public directory, or "private" to make
1128 * it invisible.
1129 * @param {module:client.callback} callback Optional.
1130 * @return {module:client.Promise} Resolves: result object
1131 * @return {module:http-api.MatrixError} Rejects: with an error response.
1132 */
1133MatrixBaseApis.prototype.setRoomDirectoryVisibilityAppService =
1134 function(networkId, roomId, visibility, callback) {
1135 const path = utils.encodeUri("/directory/list/appservice/$networkId/$roomId", {
1136 $networkId: networkId,
1137 $roomId: roomId,
1138 });
1139 return this._http.authedRequest(
1140 callback, "PUT", path, undefined, { "visibility": visibility },
1141 );
1142};
1143
1144// User Directory Operations
1145// =========================
1146
1147/**
1148 * Query the user directory with a term matching user IDs, display names and domains.
1149 * @param {object} opts options
1150 * @param {string} opts.term the term with which to search.
1151 * @param {number} opts.limit the maximum number of results to return. The server will
1152 * apply a limit if unspecified.
1153 * @return {module:client.Promise} Resolves: an array of results.
1154 */
1155MatrixBaseApis.prototype.searchUserDirectory = function(opts) {
1156 const body = {
1157 search_term: opts.term,
1158 };
1159
1160 if (opts.limit !== undefined) {
1161 body.limit = opts.limit;
1162 }
1163
1164 return this._http.authedRequest(
1165 undefined, "POST", "/user_directory/search", undefined, body,
1166 );
1167};
1168
1169
1170// Media operations
1171// ================
1172
1173/**
1174 * Upload a file to the media repository on the home server.
1175 *
1176 * @param {object} file The object to upload. On a browser, something that
1177 * can be sent to XMLHttpRequest.send (typically a File). Under node.js,
1178 * a a Buffer, String or ReadStream.
1179 *
1180 * @param {object} opts options object
1181 *
1182 * @param {string=} opts.name Name to give the file on the server. Defaults
1183 * to <tt>file.name</tt>.
1184 *
1185 * @param {boolean=} opts.includeFilename if false will not send the filename,
1186 * e.g for encrypted file uploads where filename leaks are undesirable.
1187 * Defaults to true.
1188 *
1189 * @param {string=} opts.type Content-type for the upload. Defaults to
1190 * <tt>file.type</tt>, or <tt>applicaton/octet-stream</tt>.
1191 *
1192 * @param {boolean=} opts.rawResponse Return the raw body, rather than
1193 * parsing the JSON. Defaults to false (except on node.js, where it
1194 * defaults to true for backwards compatibility).
1195 *
1196 * @param {boolean=} opts.onlyContentUri Just return the content URI,
1197 * rather than the whole body. Defaults to false (except on browsers,
1198 * where it defaults to true for backwards compatibility). Ignored if
1199 * opts.rawResponse is true.
1200 *
1201 * @param {Function=} opts.callback Deprecated. Optional. The callback to
1202 * invoke on success/failure. See the promise return values for more
1203 * information.
1204 *
1205 * @param {Function=} opts.progressHandler Optional. Called when a chunk of
1206 * data has been uploaded, with an object containing the fields `loaded`
1207 * (number of bytes transferred) and `total` (total size, if known).
1208 *
1209 * @return {module:client.Promise} Resolves to response object, as
1210 * determined by this.opts.onlyData, opts.rawResponse, and
1211 * opts.onlyContentUri. Rejects with an error (usually a MatrixError).
1212 */
1213MatrixBaseApis.prototype.uploadContent = function(file, opts) {
1214 return this._http.uploadContent(file, opts);
1215};
1216
1217/**
1218 * Cancel a file upload in progress
1219 * @param {module:client.Promise} promise The promise returned from uploadContent
1220 * @return {boolean} true if canceled, otherwise false
1221 */
1222MatrixBaseApis.prototype.cancelUpload = function(promise) {
1223 return this._http.cancelUpload(promise);
1224};
1225
1226/**
1227 * Get a list of all file uploads in progress
1228 * @return {array} Array of objects representing current uploads.
1229 * Currently in progress is element 0. Keys:
1230 * - promise: The promise associated with the upload
1231 * - loaded: Number of bytes uploaded
1232 * - total: Total number of bytes to upload
1233 */
1234MatrixBaseApis.prototype.getCurrentUploads = function() {
1235 return this._http.getCurrentUploads();
1236};
1237
1238
1239// Profile operations
1240// ==================
1241
1242/**
1243 * @param {string} userId
1244 * @param {string} info The kind of info to retrieve (e.g. 'displayname',
1245 * 'avatar_url').
1246 * @param {module:client.callback} callback Optional.
1247 * @return {module:client.Promise} Resolves: TODO
1248 * @return {module:http-api.MatrixError} Rejects: with an error response.
1249 */
1250MatrixBaseApis.prototype.getProfileInfo = function(userId, info, callback) {
1251 if (utils.isFunction(info)) {
1252 callback = info; info = undefined;
1253 }
1254
1255 const path = info ?
1256 utils.encodeUri("/profile/$userId/$info",
1257 { $userId: userId, $info: info }) :
1258 utils.encodeUri("/profile/$userId",
1259 { $userId: userId });
1260 return this._http.authedRequest(callback, "GET", path);
1261};
1262
1263
1264// Account operations
1265// ==================
1266
1267/**
1268 * @param {module:client.callback} callback Optional.
1269 * @return {module:client.Promise} Resolves: TODO
1270 * @return {module:http-api.MatrixError} Rejects: with an error response.
1271 */
1272MatrixBaseApis.prototype.getThreePids = function(callback) {
1273 const path = "/account/3pid";
1274 return this._http.authedRequest(
1275 callback, "GET", path, undefined, undefined,
1276 );
1277};
1278
1279/**
1280 * @param {Object} creds
1281 * @param {boolean} bind
1282 * @param {module:client.callback} callback Optional.
1283 * @return {module:client.Promise} Resolves: TODO
1284 * @return {module:http-api.MatrixError} Rejects: with an error response.
1285 */
1286MatrixBaseApis.prototype.addThreePid = function(creds, bind, callback) {
1287 const path = "/account/3pid";
1288 const data = {
1289 'threePidCreds': creds,
1290 'bind': bind,
1291 };
1292 return this._http.authedRequest(
1293 callback, "POST", path, null, data,
1294 );
1295};
1296
1297/**
1298 * @param {string} medium The threepid medium (eg. 'email')
1299 * @param {string} address The threepid address (eg. 'bob@example.com')
1300 * this must be as returned by getThreePids.
1301 * @return {module:client.Promise} Resolves: The server response on success
1302 * (generally the empty JSON object)
1303 * @return {module:http-api.MatrixError} Rejects: with an error response.
1304 */
1305MatrixBaseApis.prototype.deleteThreePid = function(medium, address) {
1306 const path = "/account/3pid/delete";
1307 const data = {
1308 'medium': medium,
1309 'address': address,
1310 };
1311 return this._http.authedRequestWithPrefix(
1312 undefined, "POST", path, null, data, httpApi.PREFIX_UNSTABLE,
1313 );
1314};
1315
1316/**
1317 * Make a request to change your password.
1318 * @param {Object} authDict
1319 * @param {string} newPassword The new desired password.
1320 * @param {module:client.callback} callback Optional.
1321 * @return {module:client.Promise} Resolves: TODO
1322 * @return {module:http-api.MatrixError} Rejects: with an error response.
1323 */
1324MatrixBaseApis.prototype.setPassword = function(authDict, newPassword, callback) {
1325 const path = "/account/password";
1326 const data = {
1327 'auth': authDict,
1328 'new_password': newPassword,
1329 };
1330
1331 return this._http.authedRequest(
1332 callback, "POST", path, null, data,
1333 );
1334};
1335
1336
1337// Device operations
1338// =================
1339
1340/**
1341 * Gets all devices recorded for the logged-in user
1342 * @return {module:client.Promise} Resolves: result object
1343 * @return {module:http-api.MatrixError} Rejects: with an error response.
1344 */
1345MatrixBaseApis.prototype.getDevices = function() {
1346 const path = "/devices";
1347 return this._http.authedRequestWithPrefix(
1348 undefined, "GET", path, undefined, undefined,
1349 httpApi.PREFIX_UNSTABLE,
1350 );
1351};
1352
1353/**
1354 * Update the given device
1355 *
1356 * @param {string} device_id device to update
1357 * @param {Object} body body of request
1358 * @return {module:client.Promise} Resolves: result object
1359 * @return {module:http-api.MatrixError} Rejects: with an error response.
1360 */
1361MatrixBaseApis.prototype.setDeviceDetails = function(device_id, body) {
1362 const path = utils.encodeUri("/devices/$device_id", {
1363 $device_id: device_id,
1364 });
1365
1366
1367 return this._http.authedRequestWithPrefix(
1368 undefined, "PUT", path, undefined, body,
1369 httpApi.PREFIX_UNSTABLE,
1370 );
1371};
1372
1373/**
1374 * Delete the given device
1375 *
1376 * @param {string} device_id device to delete
1377 * @param {object} auth Optional. Auth data to supply for User-Interactive auth.
1378 * @return {module:client.Promise} Resolves: result object
1379 * @return {module:http-api.MatrixError} Rejects: with an error response.
1380 */
1381MatrixBaseApis.prototype.deleteDevice = function(device_id, auth) {
1382 const path = utils.encodeUri("/devices/$device_id", {
1383 $device_id: device_id,
1384 });
1385
1386 const body = {};
1387
1388 if (auth) {
1389 body.auth = auth;
1390 }
1391
1392 return this._http.authedRequestWithPrefix(
1393 undefined, "DELETE", path, undefined, body,
1394 httpApi.PREFIX_UNSTABLE,
1395 );
1396};
1397
1398/**
1399 * Delete multiple device
1400 *
1401 * @param {string[]} devices IDs of the devices to delete
1402 * @param {object} auth Optional. Auth data to supply for User-Interactive auth.
1403 * @return {module:client.Promise} Resolves: result object
1404 * @return {module:http-api.MatrixError} Rejects: with an error response.
1405 */
1406MatrixBaseApis.prototype.deleteMultipleDevices = function(devices, auth) {
1407 const body = {devices};
1408
1409 if (auth) {
1410 body.auth = auth;
1411 }
1412
1413 return this._http.authedRequestWithPrefix(
1414 undefined, "POST", "/delete_devices", undefined, body,
1415 httpApi.PREFIX_UNSTABLE,
1416 );
1417};
1418
1419
1420// Push operations
1421// ===============
1422
1423/**
1424 * Gets all pushers registered for the logged-in user
1425 *
1426 * @param {module:client.callback} callback Optional.
1427 * @return {module:client.Promise} Resolves: Array of objects representing pushers
1428 * @return {module:http-api.MatrixError} Rejects: with an error response.
1429 */
1430MatrixBaseApis.prototype.getPushers = function(callback) {
1431 const path = "/pushers";
1432 return this._http.authedRequest(
1433 callback, "GET", path, undefined, undefined,
1434 );
1435};
1436
1437/**
1438 * Adds a new pusher or updates an existing pusher
1439 *
1440 * @param {Object} pusher Object representing a pusher
1441 * @param {module:client.callback} callback Optional.
1442 * @return {module:client.Promise} Resolves: Empty json object on success
1443 * @return {module:http-api.MatrixError} Rejects: with an error response.
1444 */
1445MatrixBaseApis.prototype.setPusher = function(pusher, callback) {
1446 const path = "/pushers/set";
1447 return this._http.authedRequest(
1448 callback, "POST", path, null, pusher,
1449 );
1450};
1451
1452/**
1453 * @param {module:client.callback} callback Optional.
1454 * @return {module:client.Promise} Resolves: TODO
1455 * @return {module:http-api.MatrixError} Rejects: with an error response.
1456 */
1457MatrixBaseApis.prototype.getPushRules = function(callback) {
1458 return this._http.authedRequest(callback, "GET", "/pushrules/");
1459};
1460
1461/**
1462 * @param {string} scope
1463 * @param {string} kind
1464 * @param {string} ruleId
1465 * @param {Object} body
1466 * @param {module:client.callback} callback Optional.
1467 * @return {module:client.Promise} Resolves: TODO
1468 * @return {module:http-api.MatrixError} Rejects: with an error response.
1469 */
1470MatrixBaseApis.prototype.addPushRule = function(scope, kind, ruleId, body, callback) {
1471 // NB. Scope not uri encoded because devices need the '/'
1472 const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId", {
1473 $kind: kind,
1474 $ruleId: ruleId,
1475 });
1476 return this._http.authedRequest(
1477 callback, "PUT", path, undefined, body,
1478 );
1479};
1480
1481/**
1482 * @param {string} scope
1483 * @param {string} kind
1484 * @param {string} ruleId
1485 * @param {module:client.callback} callback Optional.
1486 * @return {module:client.Promise} Resolves: TODO
1487 * @return {module:http-api.MatrixError} Rejects: with an error response.
1488 */
1489MatrixBaseApis.prototype.deletePushRule = function(scope, kind, ruleId, callback) {
1490 // NB. Scope not uri encoded because devices need the '/'
1491 const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId", {
1492 $kind: kind,
1493 $ruleId: ruleId,
1494 });
1495 return this._http.authedRequest(callback, "DELETE", path);
1496};
1497
1498/**
1499 * Enable or disable a push notification rule.
1500 * @param {string} scope
1501 * @param {string} kind
1502 * @param {string} ruleId
1503 * @param {boolean} enabled
1504 * @param {module:client.callback} callback Optional.
1505 * @return {module:client.Promise} Resolves: result object
1506 * @return {module:http-api.MatrixError} Rejects: with an error response.
1507 */
1508MatrixBaseApis.prototype.setPushRuleEnabled = function(scope, kind,
1509 ruleId, enabled, callback) {
1510 const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId/enabled", {
1511 $kind: kind,
1512 $ruleId: ruleId,
1513 });
1514 return this._http.authedRequest(
1515 callback, "PUT", path, undefined, {"enabled": enabled},
1516 );
1517};
1518
1519/**
1520 * Set the actions for a push notification rule.
1521 * @param {string} scope
1522 * @param {string} kind
1523 * @param {string} ruleId
1524 * @param {array} actions
1525 * @param {module:client.callback} callback Optional.
1526 * @return {module:client.Promise} Resolves: result object
1527 * @return {module:http-api.MatrixError} Rejects: with an error response.
1528 */
1529MatrixBaseApis.prototype.setPushRuleActions = function(scope, kind,
1530 ruleId, actions, callback) {
1531 const path = utils.encodeUri("/pushrules/" + scope + "/$kind/$ruleId/actions", {
1532 $kind: kind,
1533 $ruleId: ruleId,
1534 });
1535 return this._http.authedRequest(
1536 callback, "PUT", path, undefined, {"actions": actions},
1537 );
1538};
1539
1540
1541// Search
1542// ======
1543
1544/**
1545 * Perform a server-side search.
1546 * @param {Object} opts
1547 * @param {string} opts.next_batch the batch token to pass in the query string
1548 * @param {Object} opts.body the JSON object to pass to the request body.
1549 * @param {module:client.callback} callback Optional.
1550 * @return {module:client.Promise} Resolves: TODO
1551 * @return {module:http-api.MatrixError} Rejects: with an error response.
1552 */
1553MatrixBaseApis.prototype.search = function(opts, callback) {
1554 const queryparams = {};
1555 if (opts.next_batch) {
1556 queryparams.next_batch = opts.next_batch;
1557 }
1558 return this._http.authedRequest(
1559 callback, "POST", "/search", queryparams, opts.body,
1560 );
1561};
1562
1563// Crypto
1564// ======
1565
1566/**
1567 * Upload keys
1568 *
1569 * @param {Object} content body of upload request
1570 *
1571 * @param {Object=} opts
1572 *
1573 * @param {string=} opts.device_id explicit device_id to use for upload
1574 * (default is to use the same as that used during auth).
1575 *
1576 * @param {module:client.callback=} callback
1577 *
1578 * @return {module:client.Promise} Resolves: result object. Rejects: with
1579 * an error response ({@link module:http-api.MatrixError}).
1580 */
1581MatrixBaseApis.prototype.uploadKeysRequest = function(content, opts, callback) {
1582 opts = opts || {};
1583 const deviceId = opts.device_id;
1584 let path;
1585 if (deviceId) {
1586 path = utils.encodeUri("/keys/upload/$deviceId", {
1587 $deviceId: deviceId,
1588 });
1589 } else {
1590 path = "/keys/upload";
1591 }
1592 return this._http.authedRequestWithPrefix(
1593 callback, "POST", path, undefined, content, httpApi.PREFIX_UNSTABLE,
1594 );
1595};
1596
1597/**
1598 * Download device keys
1599 *
1600 * @param {string[]} userIds list of users to get keys for
1601 *
1602 * @param {Object=} opts
1603 *
1604 * @param {string=} opts.token sync token to pass in the query request, to help
1605 * the HS give the most recent results
1606 *
1607 * @return {module:client.Promise} Resolves: result object. Rejects: with
1608 * an error response ({@link module:http-api.MatrixError}).
1609 */
1610MatrixBaseApis.prototype.downloadKeysForUsers = function(userIds, opts) {
1611 if (utils.isFunction(opts)) {
1612 // opts used to be 'callback'.
1613 throw new Error(
1614 'downloadKeysForUsers no longer accepts a callback parameter',
1615 );
1616 }
1617 opts = opts || {};
1618
1619 const content = {
1620 device_keys: {},
1621 };
1622 if ('token' in opts) {
1623 content.token = opts.token;
1624 }
1625 userIds.forEach((u) => {
1626 content.device_keys[u] = {};
1627 });
1628
1629 return this._http.authedRequestWithPrefix(
1630 undefined, "POST", "/keys/query", undefined, content,
1631 httpApi.PREFIX_UNSTABLE,
1632 );
1633};
1634
1635/**
1636 * Claim one-time keys
1637 *
1638 * @param {string[]} devices a list of [userId, deviceId] pairs
1639 *
1640 * @param {string} [key_algorithm = signed_curve25519] desired key type
1641 *
1642 * @return {module:client.Promise} Resolves: result object. Rejects: with
1643 * an error response ({@link module:http-api.MatrixError}).
1644 */
1645MatrixBaseApis.prototype.claimOneTimeKeys = function(devices, key_algorithm) {
1646 const queries = {};
1647
1648 if (key_algorithm === undefined) {
1649 key_algorithm = "signed_curve25519";
1650 }
1651
1652 for (let i = 0; i < devices.length; ++i) {
1653 const userId = devices[i][0];
1654 const deviceId = devices[i][1];
1655 const query = queries[userId] || {};
1656 queries[userId] = query;
1657 query[deviceId] = key_algorithm;
1658 }
1659 const content = {one_time_keys: queries};
1660 return this._http.authedRequestWithPrefix(
1661 undefined, "POST", "/keys/claim", undefined, content,
1662 httpApi.PREFIX_UNSTABLE,
1663 );
1664};
1665
1666/**
1667 * Ask the server for a list of users who have changed their device lists
1668 * between a pair of sync tokens
1669 *
1670 * @param {string} oldToken
1671 * @param {string} newToken
1672 *
1673 * @return {module:client.Promise} Resolves: result object. Rejects: with
1674 * an error response ({@link module:http-api.MatrixError}).
1675 */
1676MatrixBaseApis.prototype.getKeyChanges = function(oldToken, newToken) {
1677 const qps = {
1678 from: oldToken,
1679 to: newToken,
1680 };
1681
1682 return this._http.authedRequestWithPrefix(
1683 undefined, "GET", "/keys/changes", qps, undefined,
1684 httpApi.PREFIX_UNSTABLE,
1685 );
1686};
1687
1688
1689// Identity Server Operations
1690// ==========================
1691
1692/**
1693 * Requests an email verification token directly from an Identity Server.
1694 *
1695 * Note that the Home Server offers APIs to proxy this API for specific
1696 * situations, allowing for better feedback to the user.
1697 *
1698 * @param {string} email The email address to request a token for
1699 * @param {string} clientSecret A secret binary string generated by the client.
1700 * It is recommended this be around 16 ASCII characters.
1701 * @param {number} sendAttempt If an identity server sees a duplicate request
1702 * with the same sendAttempt, it will not send another email.
1703 * To request another email to be sent, use a larger value for
1704 * the sendAttempt param as was used in the previous request.
1705 * @param {string} nextLink Optional If specified, the client will be redirected
1706 * to this link after validation.
1707 * @param {module:client.callback} callback Optional.
1708 * @return {module:client.Promise} Resolves: TODO
1709 * @return {module:http-api.MatrixError} Rejects: with an error response.
1710 * @throws Error if No ID server is set
1711 */
1712MatrixBaseApis.prototype.requestEmailToken = function(email, clientSecret,
1713 sendAttempt, nextLink, callback) {
1714 const params = {
1715 client_secret: clientSecret,
1716 email: email,
1717 send_attempt: sendAttempt,
1718 next_link: nextLink,
1719 };
1720 return this._http.idServerRequest(
1721 callback, "POST", "/validate/email/requestToken",
1722 params, httpApi.PREFIX_IDENTITY_V1,
1723 );
1724};
1725
1726/**
1727 * Submits an MSISDN token to the identity server
1728 *
1729 * This is used when submitting the code sent by SMS to a phone number.
1730 * The ID server has an equivalent API for email but the js-sdk does
1731 * not expose this, since email is normally validated by the user clicking
1732 * a link rather than entering a code.
1733 *
1734 * @param {string} sid The sid given in the response to requestToken
1735 * @param {string} clientSecret A secret binary string generated by the client.
1736 * This must be the same value submitted in the requestToken call.
1737 * @param {string} token The token, as enetered by the user.
1738 *
1739 * @return {module:client.Promise} Resolves: Object, currently with no parameters.
1740 * @return {module:http-api.MatrixError} Rejects: with an error response.
1741 * @throws Error if No ID server is set
1742 */
1743MatrixBaseApis.prototype.submitMsisdnToken = function(sid, clientSecret, token) {
1744 const params = {
1745 sid: sid,
1746 client_secret: clientSecret,
1747 token: token,
1748 };
1749 return this._http.idServerRequest(
1750 undefined, "POST", "/validate/msisdn/submitToken",
1751 params, httpApi.PREFIX_IDENTITY_V1,
1752 );
1753};
1754
1755/**
1756 * Looks up the public Matrix ID mapping for a given 3rd party
1757 * identifier from the Identity Server
1758 * @param {string} medium The medium of the threepid, eg. 'email'
1759 * @param {string} address The textual address of the threepid
1760 * @param {module:client.callback} callback Optional.
1761 * @return {module:client.Promise} Resolves: A threepid mapping
1762 * object or the empty object if no mapping
1763 * exists
1764 * @return {module:http-api.MatrixError} Rejects: with an error response.
1765 */
1766MatrixBaseApis.prototype.lookupThreePid = function(medium, address, callback) {
1767 const params = {
1768 medium: medium,
1769 address: address,
1770 };
1771 return this._http.idServerRequest(
1772 callback, "GET", "/lookup",
1773 params, httpApi.PREFIX_IDENTITY_V1,
1774 );
1775};
1776
1777
1778// Direct-to-device messaging
1779// ==========================
1780
1781/**
1782 * Send an event to a specific list of devices
1783 *
1784 * @param {string} eventType type of event to send
1785 * @param {Object.<string, Object<string, Object>>} contentMap
1786 * content to send. Map from user_id to device_id to content object.
1787 * @param {string=} txnId transaction id. One will be made up if not
1788 * supplied.
1789 * @return {module:client.Promise} Resolves to the result object
1790 */
1791MatrixBaseApis.prototype.sendToDevice = function(
1792 eventType, contentMap, txnId,
1793) {
1794 const path = utils.encodeUri("/sendToDevice/$eventType/$txnId", {
1795 $eventType: eventType,
1796 $txnId: txnId ? txnId : this.makeTxnId(),
1797 });
1798
1799 const body = {
1800 messages: contentMap,
1801 };
1802
1803 return this._http.authedRequestWithPrefix(
1804 undefined, "PUT", path, undefined, body,
1805 httpApi.PREFIX_UNSTABLE,
1806 );
1807};
1808
1809// Third party Lookup API
1810// ======================
1811
1812/**
1813 * Get the third party protocols that can be reached using
1814 * this HS
1815 * @return {module:client.Promise} Resolves to the result object
1816 */
1817MatrixBaseApis.prototype.getThirdpartyProtocols = function() {
1818 return this._http.authedRequestWithPrefix(
1819 undefined, "GET", "/thirdparty/protocols", undefined, undefined,
1820 httpApi.PREFIX_UNSTABLE,
1821 ).then((response) => {
1822 // sanity check
1823 if (!response || typeof(response) !== 'object') {
1824 throw new Error(
1825 `/thirdparty/protocols did not return an object: ${response}`,
1826 );
1827 }
1828 return response;
1829 });
1830};
1831
1832/**
1833 * Get information on how a specific place on a third party protocol
1834 * may be reached.
1835 * @param {string} protocol The protocol given in getThirdpartyProtocols()
1836 * @param {object} params Protocol-specific parameters, as given in the
1837 * response to getThirdpartyProtocols()
1838 * @return {module:client.Promise} Resolves to the result object
1839 */
1840MatrixBaseApis.prototype.getThirdpartyLocation = function(protocol, params) {
1841 const path = utils.encodeUri("/thirdparty/location/$protocol", {
1842 $protocol: protocol,
1843 });
1844
1845 return this._http.authedRequestWithPrefix(
1846 undefined, "GET", path, params, undefined,
1847 httpApi.PREFIX_UNSTABLE,
1848 );
1849};
1850
1851/**
1852 * Get information on how a specific user on a third party protocol
1853 * may be reached.
1854 * @param {string} protocol The protocol given in getThirdpartyProtocols()
1855 * @param {object} params Protocol-specific parameters, as given in the
1856 * response to getThirdpartyProtocols()
1857 * @return {module:client.Promise} Resolves to the result object
1858 */
1859MatrixBaseApis.prototype.getThirdpartyUser = function(protocol, params) {
1860 const path = utils.encodeUri("/thirdparty/user/$protocol", {
1861 $protocol: protocol,
1862 });
1863
1864 return this._http.authedRequestWithPrefix(
1865 undefined, "GET", path, params, undefined,
1866 httpApi.PREFIX_UNSTABLE,
1867 );
1868};
1869
1870/**
1871 * MatrixBaseApis object
1872 */
1873module.exports = MatrixBaseApis;