matrix-js-sdk 37.2.0 → 37.3.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/git-revision.txt +1 -1
- package/lib/client.d.ts +8 -2
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +11 -3
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/CryptoBackend.d.ts +8 -0
- package/lib/common-crypto/CryptoBackend.d.ts.map +1 -1
- package/lib/common-crypto/CryptoBackend.js.map +1 -1
- package/lib/http-api/errors.d.ts +8 -0
- package/lib/http-api/errors.d.ts.map +1 -1
- package/lib/http-api/errors.js +14 -0
- package/lib/http-api/errors.js.map +1 -1
- package/lib/http-api/fetch.d.ts.map +1 -1
- package/lib/http-api/fetch.js +3 -3
- package/lib/http-api/fetch.js.map +1 -1
- package/lib/matrixrtc/LegacyMembershipManager.d.ts +9 -1
- package/lib/matrixrtc/LegacyMembershipManager.d.ts.map +1 -1
- package/lib/matrixrtc/LegacyMembershipManager.js +20 -0
- package/lib/matrixrtc/LegacyMembershipManager.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.d.ts.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/NewMembershipManager.d.ts +7 -58
- package/lib/matrixrtc/NewMembershipManager.d.ts.map +1 -1
- package/lib/matrixrtc/NewMembershipManager.js +130 -137
- package/lib/matrixrtc/NewMembershipManager.js.map +1 -1
- package/lib/matrixrtc/NewMembershipManagerActionScheduler.js +3 -3
- package/lib/matrixrtc/NewMembershipManagerActionScheduler.js.map +1 -1
- package/lib/matrixrtc/index.d.ts +1 -0
- package/lib/matrixrtc/index.d.ts.map +1 -1
- package/lib/matrixrtc/index.js +1 -0
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/types.d.ts +77 -1
- package/lib/matrixrtc/types.d.ts.map +1 -1
- package/lib/matrixrtc/types.js +40 -1
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/models/room-summary.d.ts +30 -0
- package/lib/models/room-summary.d.ts.map +1 -1
- package/lib/models/room-summary.js +11 -0
- package/lib/models/room-summary.js.map +1 -1
- package/lib/models/room.d.ts +37 -1
- package/lib/models/room.d.ts.map +1 -1
- package/lib/models/room.js +133 -28
- package/lib/models/room.js.map +1 -1
- package/lib/oidc/tokenRefresher.d.ts.map +1 -1
- package/lib/oidc/tokenRefresher.js +8 -1
- package/lib/oidc/tokenRefresher.js.map +1 -1
- package/lib/pushprocessor.d.ts +10 -1
- package/lib/pushprocessor.d.ts.map +1 -1
- package/lib/pushprocessor.js +24 -9
- package/lib/pushprocessor.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.d.ts.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js +6 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.d.ts +4 -1
- package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +55 -46
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/lib/sliding-sync-sdk.d.ts.map +1 -1
- package/lib/sliding-sync-sdk.js +86 -75
- package/lib/sliding-sync-sdk.js.map +1 -1
- package/lib/sliding-sync.d.ts +23 -60
- package/lib/sliding-sync.d.ts.map +1 -1
- package/lib/sliding-sync.js +62 -321
- package/lib/sliding-sync.js.map +1 -1
- package/package.json +6 -6
- package/src/client.ts +12 -5
- package/src/common-crypto/CryptoBackend.ts +9 -0
- package/src/http-api/errors.ts +14 -0
- package/src/http-api/fetch.ts +3 -4
- package/src/matrixrtc/LegacyMembershipManager.ts +27 -1
- package/src/matrixrtc/MatrixRTCSession.ts +2 -1
- package/src/matrixrtc/NewMembershipManager.ts +120 -165
- package/src/matrixrtc/NewMembershipManagerActionScheduler.ts +3 -3
- package/src/matrixrtc/index.ts +1 -0
- package/src/matrixrtc/types.ts +84 -1
- package/src/models/room-summary.ts +31 -0
- package/src/models/room.ts +133 -23
- package/src/oidc/tokenRefresher.ts +8 -2
- package/src/pushprocessor.ts +25 -16
- package/src/rust-crypto/OutgoingRequestProcessor.ts +6 -0
- package/src/rust-crypto/rust-crypto.ts +7 -1
- package/src/sliding-sync-sdk.ts +28 -28
- package/src/sliding-sync.ts +38 -329
package/src/models/room.ts
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
} from "./event.ts";
|
|
36
36
|
import { EventStatus } from "./event-status.ts";
|
|
37
37
|
import { RoomMember } from "./room-member.ts";
|
|
38
|
-
import { type IRoomSummary, RoomSummary } from "./room-summary.ts";
|
|
38
|
+
import { type IRoomSummary, type Hero, RoomSummary } from "./room-summary.ts";
|
|
39
39
|
import { logger } from "../logger.ts";
|
|
40
40
|
import { TypedReEmitter } from "../ReEmitter.ts";
|
|
41
41
|
import {
|
|
@@ -77,6 +77,7 @@ import { compareEventOrdering } from "./compare-event-ordering.ts";
|
|
|
77
77
|
import * as utils from "../utils.ts";
|
|
78
78
|
import { KnownMembership, type Membership } from "../@types/membership.ts";
|
|
79
79
|
import { type Capabilities, type IRoomVersionsCapability, RoomVersionStability } from "../serverCapabilities.ts";
|
|
80
|
+
import { type MSC4186Hero } from "../sliding-sync.ts";
|
|
80
81
|
|
|
81
82
|
// These constants are used as sane defaults when the homeserver doesn't support
|
|
82
83
|
// the m.room_versions capability. In practice, KNOWN_SAFE_ROOM_VERSION should be
|
|
@@ -335,6 +336,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
335
336
|
public readonly reEmitter: TypedReEmitter<RoomEmittedEvents, RoomEventHandlerMap>;
|
|
336
337
|
private txnToEvent: Map<string, MatrixEvent> = new Map(); // Pending in-flight requests { string: MatrixEvent }
|
|
337
338
|
private notificationCounts: NotificationCount = {};
|
|
339
|
+
private bumpStamp: number | undefined = undefined;
|
|
338
340
|
private readonly threadNotifications = new Map<string, NotificationCount>();
|
|
339
341
|
public readonly cachedThreadReadReceipts = new Map<string, CachedReceiptStructure[]>();
|
|
340
342
|
// Useful to know at what point the current user has started using threads in this room
|
|
@@ -361,7 +363,16 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
361
363
|
// read by megolm via getter; boolean value - null indicates "use global value"
|
|
362
364
|
private blacklistUnverifiedDevices?: boolean;
|
|
363
365
|
private selfMembership?: Membership;
|
|
364
|
-
|
|
366
|
+
/**
|
|
367
|
+
* A `Hero` is a stripped `m.room.member` event which contains the important renderable fields from the event.
|
|
368
|
+
*
|
|
369
|
+
* It is used in MSC4186 (Simplified Sliding Sync) as a replacement for the old `summary` field.
|
|
370
|
+
*
|
|
371
|
+
* When we are doing old-style (`/v3/sync`) sync, we simulate the SSS behaviour by constructing
|
|
372
|
+
* a `Hero` object based on the user id we get from the summary. Obviously, in that case,
|
|
373
|
+
* the `Hero` will lack a `displayName` or `avatarUrl`.
|
|
374
|
+
*/
|
|
375
|
+
private heroes: Hero[] | null = null;
|
|
365
376
|
// flags to stop logspam about missing m.room.create events
|
|
366
377
|
private getTypeWarning = false;
|
|
367
378
|
private getVersionWarning = false;
|
|
@@ -879,7 +890,7 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
879
890
|
// fall back to summary information
|
|
880
891
|
const memberCount = this.getInvitedAndJoinedMemberCount();
|
|
881
892
|
if (memberCount === 2) {
|
|
882
|
-
return this.
|
|
893
|
+
return this.heroes?.[0]?.userId;
|
|
883
894
|
}
|
|
884
895
|
}
|
|
885
896
|
}
|
|
@@ -897,8 +908,8 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
897
908
|
}
|
|
898
909
|
}
|
|
899
910
|
// Remember, we're assuming this room is a DM, so returning the first member we find should be fine
|
|
900
|
-
if (Array.isArray(this.
|
|
901
|
-
return this.
|
|
911
|
+
if (Array.isArray(this.heroes) && this.heroes.length) {
|
|
912
|
+
return this.heroes[0].userId;
|
|
902
913
|
}
|
|
903
914
|
const members = this.currentState.getMembers();
|
|
904
915
|
const anyMember = members.find((m) => m.userId !== this.myUserId);
|
|
@@ -940,12 +951,45 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
940
951
|
if (nonFunctionalMemberCount > 2) return;
|
|
941
952
|
|
|
942
953
|
// Prefer the list of heroes, if present. It should only include the single other user in the DM.
|
|
943
|
-
const nonFunctionalHeroes = this.
|
|
954
|
+
const nonFunctionalHeroes = this.heroes?.filter((h) => !functionalMembers.includes(h.userId));
|
|
944
955
|
const hasHeroes = Array.isArray(nonFunctionalHeroes) && nonFunctionalHeroes.length;
|
|
945
956
|
if (hasHeroes) {
|
|
957
|
+
// use first hero that has a display name or avatar url, or whose user ID
|
|
958
|
+
// can be looked up as a member of the room
|
|
959
|
+
for (const hero of nonFunctionalHeroes) {
|
|
960
|
+
// If the hero was from a legacy sync (`/v3/sync`), we will need to look the user ID up in the room
|
|
961
|
+
// the display name and avatar URL will not be set.
|
|
962
|
+
if (!hero.fromMSC4186) {
|
|
963
|
+
// attempt to look up renderable fields from the m.room.member event if it exists
|
|
964
|
+
const member = this.getMember(hero.userId);
|
|
965
|
+
if (member) {
|
|
966
|
+
return member;
|
|
967
|
+
}
|
|
968
|
+
} else {
|
|
969
|
+
// use the Hero supplied values for the room member.
|
|
970
|
+
// TODO: It's unfortunate that this function, which clearly only cares about the
|
|
971
|
+
// avatar url, returns the entire RoomMember event. We need to fake an event
|
|
972
|
+
// to meet this API shape.
|
|
973
|
+
const heroMember = new RoomMember(this.roomId, hero.userId);
|
|
974
|
+
// set the display name and avatar url
|
|
975
|
+
heroMember.setMembershipEvent(
|
|
976
|
+
new MatrixEvent({
|
|
977
|
+
// ensure it's unique even if we hit the same millisecond
|
|
978
|
+
event_id: "$" + this.roomId + hero.userId + new Date().getTime(),
|
|
979
|
+
type: EventType.RoomMember,
|
|
980
|
+
state_key: hero.userId,
|
|
981
|
+
content: {
|
|
982
|
+
displayname: hero.displayName,
|
|
983
|
+
avatar_url: hero.avatarUrl,
|
|
984
|
+
},
|
|
985
|
+
}),
|
|
986
|
+
);
|
|
987
|
+
return heroMember;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
946
990
|
const availableMember = nonFunctionalHeroes
|
|
947
|
-
.map((
|
|
948
|
-
return this.getMember(userId);
|
|
991
|
+
.map((hero) => {
|
|
992
|
+
return this.getMember(hero.userId);
|
|
949
993
|
})
|
|
950
994
|
.find((member) => !!member);
|
|
951
995
|
if (availableMember) {
|
|
@@ -970,8 +1014,8 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
970
1014
|
// trust and try falling back to a hero, creating a one-off member for it
|
|
971
1015
|
if (hasHeroes) {
|
|
972
1016
|
const availableUser = nonFunctionalHeroes
|
|
973
|
-
.map((
|
|
974
|
-
return this.client.getUser(userId);
|
|
1017
|
+
.map((hero) => {
|
|
1018
|
+
return this.client.getUser(hero.userId);
|
|
975
1019
|
})
|
|
976
1020
|
.find((user) => !!user);
|
|
977
1021
|
if (availableUser) {
|
|
@@ -1602,6 +1646,24 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
1602
1646
|
this.emit(RoomEvent.UnreadNotifications);
|
|
1603
1647
|
}
|
|
1604
1648
|
|
|
1649
|
+
/**
|
|
1650
|
+
* Set the bump stamp for this room. This can be used for sorting rooms when the timeline
|
|
1651
|
+
* entries are unknown. Used in MSC4186: Simplified Sliding Sync.
|
|
1652
|
+
* @param bumpStamp The bump_stamp value from the server
|
|
1653
|
+
*/
|
|
1654
|
+
public setBumpStamp(bumpStamp: number): void {
|
|
1655
|
+
this.bumpStamp = bumpStamp;
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
/**
|
|
1659
|
+
* Get the bump stamp for this room. This can be used for sorting rooms when the timeline
|
|
1660
|
+
* entries are unknown. Used in MSC4186: Simplified Sliding Sync.
|
|
1661
|
+
* @returns The bump stamp for the room, if it exists.
|
|
1662
|
+
*/
|
|
1663
|
+
public getBumpStamp(): number | undefined {
|
|
1664
|
+
return this.bumpStamp;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1605
1667
|
/**
|
|
1606
1668
|
* Set one of the notification counts for this room
|
|
1607
1669
|
* @param type - The type of notification count to set.
|
|
@@ -1616,8 +1678,13 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
1616
1678
|
return this.setUnreadNotificationCount(type, count);
|
|
1617
1679
|
}
|
|
1618
1680
|
|
|
1681
|
+
/**
|
|
1682
|
+
* Takes a legacy room summary (/v3/sync as opposed to MSC4186) and updates the room with it.
|
|
1683
|
+
*
|
|
1684
|
+
* @param summary - The room summary to update the room with
|
|
1685
|
+
*/
|
|
1619
1686
|
public setSummary(summary: IRoomSummary): void {
|
|
1620
|
-
const heroes = summary["m.heroes"];
|
|
1687
|
+
const heroes = summary["m.heroes"]?.map((h) => ({ userId: h, fromMSC4186: false }));
|
|
1621
1688
|
const joinedCount = summary["m.joined_member_count"];
|
|
1622
1689
|
const invitedCount = summary["m.invited_member_count"];
|
|
1623
1690
|
if (Number.isInteger(joinedCount)) {
|
|
@@ -1627,17 +1694,53 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
1627
1694
|
this.currentState.setInvitedMemberCount(invitedCount!);
|
|
1628
1695
|
}
|
|
1629
1696
|
if (Array.isArray(heroes)) {
|
|
1630
|
-
//
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
this.summaryHeroes = heroes.filter((userId) => {
|
|
1634
|
-
return userId !== this.myUserId;
|
|
1697
|
+
// filter out ourselves just in case
|
|
1698
|
+
this.heroes = heroes.filter((h) => {
|
|
1699
|
+
return h.userId != this.myUserId;
|
|
1635
1700
|
});
|
|
1636
1701
|
}
|
|
1637
1702
|
|
|
1638
1703
|
this.emit(RoomEvent.Summary, summary);
|
|
1639
1704
|
}
|
|
1640
1705
|
|
|
1706
|
+
/**
|
|
1707
|
+
* Takes information from the MSC4186 room summary and updates the room with it.
|
|
1708
|
+
*
|
|
1709
|
+
* @param heroes - The room's hero members
|
|
1710
|
+
* @param joinedCount - The number of joined members
|
|
1711
|
+
* @param invitedCount - The number of invited members
|
|
1712
|
+
*/
|
|
1713
|
+
public setMSC4186SummaryData(
|
|
1714
|
+
heroes: MSC4186Hero[] | undefined,
|
|
1715
|
+
joinedCount: number | undefined,
|
|
1716
|
+
invitedCount: number | undefined,
|
|
1717
|
+
): void {
|
|
1718
|
+
if (heroes) {
|
|
1719
|
+
this.heroes = heroes
|
|
1720
|
+
.filter((h) => h.user_id !== this.myUserId)
|
|
1721
|
+
.map((h) => ({
|
|
1722
|
+
userId: h.user_id,
|
|
1723
|
+
displayName: h.displayname,
|
|
1724
|
+
avatarUrl: h.avatar_url,
|
|
1725
|
+
fromMSC4186: true,
|
|
1726
|
+
}));
|
|
1727
|
+
}
|
|
1728
|
+
if (joinedCount !== undefined && Number.isInteger(joinedCount)) {
|
|
1729
|
+
this.currentState.setJoinedMemberCount(joinedCount);
|
|
1730
|
+
}
|
|
1731
|
+
if (invitedCount !== undefined && Number.isInteger(invitedCount)) {
|
|
1732
|
+
this.currentState.setInvitedMemberCount(invitedCount);
|
|
1733
|
+
}
|
|
1734
|
+
|
|
1735
|
+
// Construct a summary object to emit as the event wants the info in a single object
|
|
1736
|
+
// more like old-style (/v3/sync) summaries.
|
|
1737
|
+
this.emit(RoomEvent.Summary, {
|
|
1738
|
+
"m.heroes": this.heroes ? this.heroes.map((h) => h.userId) : [],
|
|
1739
|
+
"m.joined_member_count": joinedCount,
|
|
1740
|
+
"m.invited_member_count": invitedCount,
|
|
1741
|
+
});
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1641
1744
|
/**
|
|
1642
1745
|
* Whether to send encrypted messages to devices within this room.
|
|
1643
1746
|
* @param value - true to blacklist unverified devices, null
|
|
@@ -3459,18 +3562,25 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
|
|
|
3459
3562
|
// get service members (e.g. helper bots) for exclusion
|
|
3460
3563
|
const excludedUserIds = this.getFunctionalMembers();
|
|
3461
3564
|
|
|
3462
|
-
// get members that are NOT ourselves
|
|
3565
|
+
// get members from heroes that are NOT ourselves
|
|
3463
3566
|
let otherNames: string[] = [];
|
|
3464
|
-
if (this.
|
|
3465
|
-
// if we have
|
|
3466
|
-
this.
|
|
3567
|
+
if (this.heroes) {
|
|
3568
|
+
// if we have heroes, use those as the names
|
|
3569
|
+
this.heroes.forEach((hero) => {
|
|
3467
3570
|
// filter service members
|
|
3468
|
-
if (excludedUserIds.includes(userId)) {
|
|
3571
|
+
if (excludedUserIds.includes(hero.userId)) {
|
|
3469
3572
|
inviteJoinCount--;
|
|
3470
3573
|
return;
|
|
3471
3574
|
}
|
|
3472
|
-
|
|
3473
|
-
|
|
3575
|
+
// If the hero has a display name, use that.
|
|
3576
|
+
// Otherwise, look their user ID up in the membership and use
|
|
3577
|
+
// the name from there, or the user ID as a last resort.
|
|
3578
|
+
if (hero.displayName) {
|
|
3579
|
+
otherNames.push(hero.displayName);
|
|
3580
|
+
} else {
|
|
3581
|
+
const member = this.getMember(hero.userId);
|
|
3582
|
+
otherNames.push(member ? member.name : hero.userId);
|
|
3583
|
+
}
|
|
3474
3584
|
});
|
|
3475
3585
|
} else {
|
|
3476
3586
|
let otherMembers = this.currentState.getMembers().filter((m) => {
|
|
@@ -14,9 +14,9 @@ See the License for the specific language governing permissions and
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { type IdTokenClaims, OidcClient, WebStorageStateStore } from "oidc-client-ts";
|
|
17
|
+
import { type IdTokenClaims, OidcClient, WebStorageStateStore, ErrorResponse } from "oidc-client-ts";
|
|
18
18
|
|
|
19
|
-
import { type AccessTokens } from "../http-api/index.ts";
|
|
19
|
+
import { type AccessTokens, TokenRefreshLogoutError } from "../http-api/index.ts";
|
|
20
20
|
import { generateScope } from "./authorize.ts";
|
|
21
21
|
import { discoverAndValidateOIDCIssuerWellKnown } from "./discovery.ts";
|
|
22
22
|
import { logger } from "../logger.ts";
|
|
@@ -104,6 +104,12 @@ export class OidcTokenRefresher {
|
|
|
104
104
|
try {
|
|
105
105
|
const tokens = await this.inflightRefreshRequest;
|
|
106
106
|
return tokens;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
// If we encounter an OIDC error then signal that it should cause a logout by upgrading it to a TokenRefreshLogoutError
|
|
109
|
+
if (e instanceof ErrorResponse) {
|
|
110
|
+
throw new TokenRefreshLogoutError(e);
|
|
111
|
+
}
|
|
112
|
+
throw e;
|
|
107
113
|
} finally {
|
|
108
114
|
this.inflightRefreshRequest = undefined;
|
|
109
115
|
}
|
package/src/pushprocessor.ts
CHANGED
|
@@ -308,6 +308,28 @@ export class PushProcessor {
|
|
|
308
308
|
return newRules;
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
/**
|
|
312
|
+
* Create a RegExp object for the given glob pattern with a single capture group around the pattern itself, caching the result.
|
|
313
|
+
* No cache invalidation is present currently,
|
|
314
|
+
* as this will be inherently bounded to the size of the user's own push rules.
|
|
315
|
+
* @param pattern - the glob pattern to convert to a RegExp
|
|
316
|
+
* @param alignToWordBoundary - whether to align the pattern to word boundaries,
|
|
317
|
+
* as specified for `content.body` matches, will use lookaround assertions to ensure the match only includes the pattern
|
|
318
|
+
* @param flags - the flags to pass to the RegExp constructor, defaults to case-insensitive
|
|
319
|
+
*/
|
|
320
|
+
public static getPushRuleGlobRegex(pattern: string, alignToWordBoundary = false, flags = "i"): RegExp {
|
|
321
|
+
const [prefix, suffix] = alignToWordBoundary ? ["(?<=^|\\W)", "(?=\\W|$)"] : ["^", "$"];
|
|
322
|
+
const cacheKey = `${alignToWordBoundary}-${flags}-${pattern}`;
|
|
323
|
+
|
|
324
|
+
if (!PushProcessor.cachedGlobToRegex[cacheKey]) {
|
|
325
|
+
PushProcessor.cachedGlobToRegex[cacheKey] = new RegExp(
|
|
326
|
+
prefix + "(" + globToRegexp(pattern) + ")" + suffix,
|
|
327
|
+
flags,
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
return PushProcessor.cachedGlobToRegex[cacheKey];
|
|
331
|
+
}
|
|
332
|
+
|
|
311
333
|
/**
|
|
312
334
|
* Pre-caches the parsed keys for push rules and cleans out any obsolete cache
|
|
313
335
|
* entries. Should be called after push rules are updated.
|
|
@@ -567,11 +589,9 @@ export class PushProcessor {
|
|
|
567
589
|
return false;
|
|
568
590
|
}
|
|
569
591
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
: this.createCachedRegex("^", cond.pattern, "$");
|
|
574
|
-
|
|
592
|
+
// Align to word boundary on `content.body` matches, whole string otherwise
|
|
593
|
+
// https://spec.matrix.org/v1.13/client-server-api/#conditions-1
|
|
594
|
+
const regex = PushProcessor.getPushRuleGlobRegex(cond.pattern, cond.key === "content.body");
|
|
575
595
|
return !!val.match(regex);
|
|
576
596
|
}
|
|
577
597
|
|
|
@@ -621,17 +641,6 @@ export class PushProcessor {
|
|
|
621
641
|
);
|
|
622
642
|
}
|
|
623
643
|
|
|
624
|
-
private createCachedRegex(prefix: string, glob: string, suffix: string): RegExp {
|
|
625
|
-
if (PushProcessor.cachedGlobToRegex[glob]) {
|
|
626
|
-
return PushProcessor.cachedGlobToRegex[glob];
|
|
627
|
-
}
|
|
628
|
-
PushProcessor.cachedGlobToRegex[glob] = new RegExp(
|
|
629
|
-
prefix + globToRegexp(glob) + suffix,
|
|
630
|
-
"i", // Case insensitive
|
|
631
|
-
);
|
|
632
|
-
return PushProcessor.cachedGlobToRegex[glob];
|
|
633
|
-
}
|
|
634
|
-
|
|
635
644
|
/**
|
|
636
645
|
* Parse the key into the separate fields to search by splitting on
|
|
637
646
|
* unescaped ".", and then removing any escape characters.
|
|
@@ -219,6 +219,12 @@ export class OutgoingRequestProcessor {
|
|
|
219
219
|
|
|
220
220
|
// we use the full prefix
|
|
221
221
|
prefix: "",
|
|
222
|
+
|
|
223
|
+
// We set a timeout of 60 seconds to guard against requests getting stuck forever and wedging the
|
|
224
|
+
// request loop (cf https://github.com/element-hq/element-web/issues/29534).
|
|
225
|
+
//
|
|
226
|
+
// (XXX: should we do this in the whole of the js-sdk?)
|
|
227
|
+
localTimeoutMs: 60000,
|
|
222
228
|
};
|
|
223
229
|
|
|
224
230
|
return await this.http.authedRequest<string>(method, path, queryParams, body, opts);
|
|
@@ -1635,7 +1635,6 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
|
|
1635
1635
|
|
|
1636
1636
|
/** called by the sync loop after processing each sync.
|
|
1637
1637
|
*
|
|
1638
|
-
* TODO: figure out something equivalent for sliding sync.
|
|
1639
1638
|
*
|
|
1640
1639
|
* @param syncState - information on the completed sync.
|
|
1641
1640
|
*/
|
|
@@ -1647,6 +1646,13 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
|
|
1647
1646
|
});
|
|
1648
1647
|
}
|
|
1649
1648
|
|
|
1649
|
+
/**
|
|
1650
|
+
* Implementation of {@link CryptoApi#markAllTrackedUsersAsDirty}.
|
|
1651
|
+
*/
|
|
1652
|
+
public async markAllTrackedUsersAsDirty(): Promise<void> {
|
|
1653
|
+
await this.olmMachine.markAllTrackedUsersAsDirty();
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1650
1656
|
/**
|
|
1651
1657
|
* Handle an incoming m.key.verification.request event, received either in-room or in a to-device message.
|
|
1652
1658
|
*
|
package/src/sliding-sync-sdk.ts
CHANGED
|
@@ -82,9 +82,16 @@ class ExtensionE2EE implements Extension<ExtensionE2EERequest, ExtensionE2EEResp
|
|
|
82
82
|
return ExtensionState.PreProcess;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
public onRequest(isInitial: boolean): ExtensionE2EERequest
|
|
86
|
-
if (
|
|
87
|
-
|
|
85
|
+
public async onRequest(isInitial: boolean): Promise<ExtensionE2EERequest> {
|
|
86
|
+
if (isInitial) {
|
|
87
|
+
// In SSS, the `?pos=` contains the stream position for device list updates.
|
|
88
|
+
// If we do not have a `?pos=` (e.g because we forgot it, or because the server
|
|
89
|
+
// invalidated our connection) then we MUST invlaidate all device lists because
|
|
90
|
+
// the server will not tell us the delta. This will then cause UTDs as we will fail
|
|
91
|
+
// to encrypt for new devices. This is an expensive call, so we should
|
|
92
|
+
// really really remember `?pos=` wherever possible.
|
|
93
|
+
logger.log("ExtensionE2EE: invalidating all device lists due to missing 'pos'");
|
|
94
|
+
await this.crypto.markAllTrackedUsersAsDirty();
|
|
88
95
|
}
|
|
89
96
|
return {
|
|
90
97
|
enabled: true, // this is sticky so only send it on the initial request
|
|
@@ -134,15 +141,12 @@ class ExtensionToDevice implements Extension<ExtensionToDeviceRequest, Extension
|
|
|
134
141
|
return ExtensionState.PreProcess;
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
public onRequest(isInitial: boolean): ExtensionToDeviceRequest {
|
|
138
|
-
|
|
144
|
+
public async onRequest(isInitial: boolean): Promise<ExtensionToDeviceRequest> {
|
|
145
|
+
return {
|
|
139
146
|
since: this.nextBatch !== null ? this.nextBatch : undefined,
|
|
147
|
+
limit: 100,
|
|
148
|
+
enabled: true,
|
|
140
149
|
};
|
|
141
|
-
if (isInitial) {
|
|
142
|
-
extReq["limit"] = 100;
|
|
143
|
-
extReq["enabled"] = true;
|
|
144
|
-
}
|
|
145
|
-
return extReq;
|
|
146
150
|
}
|
|
147
151
|
|
|
148
152
|
public async onResponse(data: ExtensionToDeviceResponse): Promise<void> {
|
|
@@ -216,10 +220,7 @@ class ExtensionAccountData implements Extension<ExtensionAccountDataRequest, Ext
|
|
|
216
220
|
return ExtensionState.PostProcess;
|
|
217
221
|
}
|
|
218
222
|
|
|
219
|
-
public onRequest(isInitial: boolean): ExtensionAccountDataRequest
|
|
220
|
-
if (!isInitial) {
|
|
221
|
-
return undefined;
|
|
222
|
-
}
|
|
223
|
+
public async onRequest(isInitial: boolean): Promise<ExtensionAccountDataRequest> {
|
|
223
224
|
return {
|
|
224
225
|
enabled: true,
|
|
225
226
|
};
|
|
@@ -286,10 +287,7 @@ class ExtensionTyping implements Extension<ExtensionTypingRequest, ExtensionTypi
|
|
|
286
287
|
return ExtensionState.PostProcess;
|
|
287
288
|
}
|
|
288
289
|
|
|
289
|
-
public onRequest(isInitial: boolean): ExtensionTypingRequest
|
|
290
|
-
if (!isInitial) {
|
|
291
|
-
return undefined; // don't send a JSON object for subsequent requests, we don't need to.
|
|
292
|
-
}
|
|
290
|
+
public async onRequest(isInitial: boolean): Promise<ExtensionTypingRequest> {
|
|
293
291
|
return {
|
|
294
292
|
enabled: true,
|
|
295
293
|
};
|
|
@@ -325,13 +323,10 @@ class ExtensionReceipts implements Extension<ExtensionReceiptsRequest, Extension
|
|
|
325
323
|
return ExtensionState.PostProcess;
|
|
326
324
|
}
|
|
327
325
|
|
|
328
|
-
public onRequest(isInitial: boolean): ExtensionReceiptsRequest
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
return undefined; // don't send a JSON object for subsequent requests, we don't need to.
|
|
326
|
+
public async onRequest(isInitial: boolean): Promise<ExtensionReceiptsRequest> {
|
|
327
|
+
return {
|
|
328
|
+
enabled: true,
|
|
329
|
+
};
|
|
335
330
|
}
|
|
336
331
|
|
|
337
332
|
public async onResponse(data: ExtensionReceiptsResponse): Promise<void> {
|
|
@@ -442,6 +437,7 @@ export class SlidingSyncSdk {
|
|
|
442
437
|
}
|
|
443
438
|
} else {
|
|
444
439
|
this.failCount = 0;
|
|
440
|
+
logger.log(`SlidingSyncState.RequestFinished with ${Object.keys(resp?.rooms || []).length} rooms`);
|
|
445
441
|
}
|
|
446
442
|
break;
|
|
447
443
|
}
|
|
@@ -580,7 +576,7 @@ export class SlidingSyncSdk {
|
|
|
580
576
|
|
|
581
577
|
// TODO: handle threaded / beacon events
|
|
582
578
|
|
|
583
|
-
if (roomData.initial) {
|
|
579
|
+
if (roomData.limited || roomData.initial) {
|
|
584
580
|
// we should not know about any of these timeline entries if this is a genuinely new room.
|
|
585
581
|
// If we do, then we've effectively done scrollback (e.g requesting timeline_limit: 1 for
|
|
586
582
|
// this room, then timeline_limit: 50).
|
|
@@ -637,6 +633,9 @@ export class SlidingSyncSdk {
|
|
|
637
633
|
room.setUnreadNotificationCount(NotificationCountType.Highlight, roomData.highlight_count);
|
|
638
634
|
}
|
|
639
635
|
}
|
|
636
|
+
if (roomData.bump_stamp) {
|
|
637
|
+
room.setBumpStamp(roomData.bump_stamp);
|
|
638
|
+
}
|
|
640
639
|
|
|
641
640
|
if (Number.isInteger(roomData.invited_count)) {
|
|
642
641
|
room.currentState.setInvitedMemberCount(roomData.invited_count!);
|
|
@@ -656,11 +655,10 @@ export class SlidingSyncSdk {
|
|
|
656
655
|
inviteStateEvents.forEach((e) => {
|
|
657
656
|
this.client.emit(ClientEvent.Event, e);
|
|
658
657
|
});
|
|
659
|
-
room.updateMyMembership(KnownMembership.Invite);
|
|
660
658
|
return;
|
|
661
659
|
}
|
|
662
660
|
|
|
663
|
-
if (roomData.
|
|
661
|
+
if (roomData.limited) {
|
|
664
662
|
// set the back-pagination token. Do this *before* adding any
|
|
665
663
|
// events so that clients can start back-paginating.
|
|
666
664
|
room.getLiveTimeline().setPaginationToken(roomData.prev_batch ?? null, EventTimeline.BACKWARDS);
|
|
@@ -728,6 +726,8 @@ export class SlidingSyncSdk {
|
|
|
728
726
|
// synchronous execution prior to emitting SlidingSyncState.Complete
|
|
729
727
|
room.updateMyMembership(KnownMembership.Join);
|
|
730
728
|
|
|
729
|
+
room.setMSC4186SummaryData(roomData.heroes, roomData.joined_count, roomData.invited_count);
|
|
730
|
+
|
|
731
731
|
room.recalculate();
|
|
732
732
|
if (roomData.initial) {
|
|
733
733
|
client.store.storeRoom(room);
|