Skip to content

Commit

Permalink
Posthog improvements + js-sdk bump to not share historical sender keys
Browse files Browse the repository at this point in the history
Adds cryptoVersion to platform details.
Adds encryption to CallStarted and CallEnded.
Adds CallEnded.roomEventEncryptionKeysSent.
Adds CallEnded.roomEventEncryptionKeysReceived.
Adds CallEnded.roomEventEncryptionKeysReceivedAverageAge.
  • Loading branch information
hughns committed Sep 13, 2024
1 parent eb6719d commit 76a2ef8
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
"livekit-client": "^2.0.2",
"lodash": "^4.17.21",
"loglevel": "^1.9.1",
"matrix-js-sdk": "matrix-org/matrix-js-sdk#169e8f86139111574a3738f8557c6fa4b2a199db",
"matrix-js-sdk": "matrix-org/matrix-js-sdk#94fb839140964a967b0f37c1205b037732e0f3d0",
"matrix-widget-api": "^1.8.2",
"normalize.css": "^8.0.1",
"observable-hooks": "^4.2.3",
Expand Down
4 changes: 4 additions & 0 deletions src/analytics/PosthogAnalytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ interface PlatformProperties {
appVersion: string;
matrixBackend: "embedded" | "jssdk";
callBackend: "livekit" | "full-mesh";
cryptoVersion?: string;
}

interface PosthogSettings {
Expand Down Expand Up @@ -184,6 +185,9 @@ export class PosthogAnalytics {
appVersion,
matrixBackend: widget ? "embedded" : "jssdk",
callBackend: "livekit",
cryptoVersion: widget
? undefined
: window.matrixclient?.getCrypto()?.getVersion(),

Check warning on line 190 in src/analytics/PosthogAnalytics.ts

View check run for this annotation

Codecov / codecov/patch

src/analytics/PosthogAnalytics.ts#L188-L190

Added lines #L188 - L190 were not covered by tests
};
}

Expand Down
37 changes: 36 additions & 1 deletion src/analytics/PosthogEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,39 @@ Please see LICENSE in the repository root for full details.

import { DisconnectReason } from "livekit-client";
import { logger } from "matrix-js-sdk/src/logger";
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";

import {
IPosthogEvent,
PosthogAnalytics,
RegistrationType,
} from "./PosthogAnalytics";
import { E2eeType } from "../e2ee/e2eeType";

type EncryptionScheme = "none" | "shared" | "per_sender";

function mapE2eeType(type: E2eeType): EncryptionScheme {
switch (type) {
case E2eeType.NONE:
return "none";

Check warning on line 24 in src/analytics/PosthogEvents.ts

View check run for this annotation

Codecov / codecov/patch

src/analytics/PosthogEvents.ts#L24

Added line #L24 was not covered by tests
case E2eeType.SHARED_KEY:
return "shared";

case E2eeType.PER_PARTICIPANT:
return "per_sender";

Check warning on line 29 in src/analytics/PosthogEvents.ts

View check run for this annotation

Codecov / codecov/patch

src/analytics/PosthogEvents.ts#L29

Added line #L29 was not covered by tests
}
}

interface CallEnded extends IPosthogEvent {
eventName: "CallEnded";
callId: string;
callParticipantsOnLeave: number;
callParticipantsMax: number;
callDuration: number;
encryption: EncryptionScheme;
roomEventEncryptionKeysSent: number;
roomEventEncryptionKeysReceived: number;
roomEventEncryptionKeysReceivedAverageAge: number;
}

export class CallEndedTracker {
Expand All @@ -43,6 +63,8 @@ export class CallEndedTracker {
callId: string,
callParticipantsNow: number,
sendInstantly: boolean,
e2eeType: E2eeType,
rtcSession: MatrixRTCSession,

Check warning on line 67 in src/analytics/PosthogEvents.ts

View check run for this annotation

Codecov / codecov/patch

src/analytics/PosthogEvents.ts#L66-L67

Added lines #L66 - L67 were not covered by tests
): void {
PosthogAnalytics.instance.trackEvent<CallEnded>(
{
Expand All @@ -51,6 +73,17 @@ export class CallEndedTracker {
callParticipantsMax: this.cache.maxParticipantsCount,
callParticipantsOnLeave: callParticipantsNow,
callDuration: (Date.now() - this.cache.startTime.getTime()) / 1000,
encryption: mapE2eeType(e2eeType),
roomEventEncryptionKeysSent:
rtcSession.statistics.counters.roomEventEncryptionKeysSent,
roomEventEncryptionKeysReceived:
rtcSession.statistics.counters.roomEventEncryptionKeysReceived,
roomEventEncryptionKeysReceivedAverageAge:
rtcSession.statistics.counters.roomEventEncryptionKeysReceived > 0
? rtcSession.statistics.totals
.roomEventEncryptionKeysReceivedTotalAge /
rtcSession.statistics.counters.roomEventEncryptionKeysReceived
: 0,

Check warning on line 86 in src/analytics/PosthogEvents.ts

View check run for this annotation

Codecov / codecov/patch

src/analytics/PosthogEvents.ts#L76-L86

Added lines #L76 - L86 were not covered by tests
},
{ send_instantly: sendInstantly },
);
Expand All @@ -60,13 +93,15 @@ export class CallEndedTracker {
interface CallStarted extends IPosthogEvent {
eventName: "CallStarted";
callId: string;
encryption: EncryptionScheme;
}

export class CallStartedTracker {
public track(callId: string): void {
public track(callId: string, e2eeType: E2eeType): void {
PosthogAnalytics.instance.trackEvent<CallStarted>({
eventName: "CallStarted",
callId: callId,
encryption: mapE2eeType(e2eeType),
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/home/RegisteredView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,13 @@ export const RegisteredView: FC<Props> = ({ client }) => {
roomName,
E2eeType.SHARED_KEY,
);
if (!createRoomResult.password)
if (createRoomResult.encryptionSystem.kind !== E2eeType.SHARED_KEY)

Check warning on line 71 in src/home/RegisteredView.tsx

View check run for this annotation

Codecov / codecov/patch

src/home/RegisteredView.tsx#L71

Added line #L71 was not covered by tests
throw new Error("Failed to create room with shared secret");

history.push(
getRelativeRoomUrl(
createRoomResult.roomId,
{ kind: E2eeType.SHARED_KEY, secret: createRoomResult.password },
createRoomResult.encryptionSystem,

Check warning on line 77 in src/home/RegisteredView.tsx

View check run for this annotation

Codecov / codecov/patch

src/home/RegisteredView.tsx#L77

Added line #L77 was not covered by tests
roomName,
),
);
Expand Down
4 changes: 2 additions & 2 deletions src/home/UnauthenticatedView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ export const UnauthenticatedView: FC = () => {
if (!setClient) {
throw new Error("setClient is undefined");
}
if (!createRoomResult.password)
if (createRoomResult.encryptionSystem.kind !== E2eeType.SHARED_KEY)

Check warning on line 109 in src/home/UnauthenticatedView.tsx

View check run for this annotation

Codecov / codecov/patch

src/home/UnauthenticatedView.tsx#L109

Added line #L109 was not covered by tests
throw new Error("Failed to create room with shared secret");

setClient({ client, session });
history.push(
getRelativeRoomUrl(
createRoomResult.roomId,
{ kind: E2eeType.SHARED_KEY, secret: createRoomResult.password },
createRoomResult.encryptionSystem,

Check warning on line 116 in src/home/UnauthenticatedView.tsx

View check run for this annotation

Codecov / codecov/patch

src/home/UnauthenticatedView.tsx#L116

Added line #L116 was not covered by tests
roomName,
),
);
Expand Down
18 changes: 10 additions & 8 deletions src/room/GroupCallView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const GroupCallView: FC<Props> = ({
const { displayName, avatarUrl } = useProfile(client);
const roomName = useRoomName(rtcSession.room);
const roomAvatar = useRoomAvatar(rtcSession.room);
const { perParticipantE2EE, returnToLobby } = useUrlParams();
const { returnToLobby } = useUrlParams();

Check warning on line 100 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L100

Added line #L100 was not covered by tests
const e2eeSystem = useRoomEncryptionSystem(rtcSession.room.roomId);

const matrixInfo = useMemo((): MatrixInfo => {
Expand Down Expand Up @@ -182,7 +182,7 @@ export const GroupCallView: FC<Props> = ({
const onJoin = (ev: CustomEvent<IWidgetApiRequest>): void => {
(async (): Promise<void> => {
await defaultDeviceSetup(ev.detail.data as unknown as JoinCallData);
await enterRTCSession(rtcSession, perParticipantE2EE);
await enterRTCSession(rtcSession, e2eeSystem.kind);

Check warning on line 185 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L185

Added line #L185 was not covered by tests
widget!.api.transport.reply(ev.detail, {});
})().catch((e) => {
logger.error("Error joining RTC session", e);
Expand All @@ -196,12 +196,12 @@ export const GroupCallView: FC<Props> = ({
// No lobby and no preload: we enter the rtc session right away
(async (): Promise<void> => {
await defaultDeviceSetup({ audioInput: null, videoInput: null });
await enterRTCSession(rtcSession, perParticipantE2EE);
await enterRTCSession(rtcSession, e2eeSystem.kind);

Check warning on line 199 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L199

Added line #L199 was not covered by tests
})().catch((e) => {
logger.error("Error joining RTC session", e);
});
}
}, [rtcSession, preload, skipLobby, perParticipantE2EE]);
}, [rtcSession, preload, skipLobby, e2eeSystem]);

Check warning on line 204 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L204

Added line #L204 was not covered by tests

const [left, setLeft] = useState(false);
const [leaveError, setLeaveError] = useState<Error | undefined>(undefined);
Expand All @@ -219,6 +219,8 @@ export const GroupCallView: FC<Props> = ({
rtcSession.room.roomId,
rtcSession.memberships.length,
sendInstantly,
e2eeSystem.kind,
rtcSession,

Check warning on line 223 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L222-L223

Added lines #L222 - L223 were not covered by tests
);

// Only sends matrix leave event. The Livekit session will disconnect once the ActiveCall-view unmounts.
Expand All @@ -236,7 +238,7 @@ export const GroupCallView: FC<Props> = ({
logger.error("Error leaving RTC session", e);
});
},
[rtcSession, isPasswordlessUser, confineToRoom, history],
[rtcSession, isPasswordlessUser, confineToRoom, history, e2eeSystem],

Check warning on line 241 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L241

Added line #L241 was not covered by tests
);

useEffect(() => {
Expand All @@ -263,10 +265,10 @@ export const GroupCallView: FC<Props> = ({
const onReconnect = useCallback(() => {
setLeft(false);
setLeaveError(undefined);
enterRTCSession(rtcSession, perParticipantE2EE).catch((e) => {
enterRTCSession(rtcSession, e2eeSystem.kind).catch((e) => {

Check warning on line 268 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L268

Added line #L268 was not covered by tests
logger.error("Error re-entering RTC session on reconnect", e);
});
}, [rtcSession, perParticipantE2EE]);
}, [rtcSession, e2eeSystem]);

Check warning on line 271 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L271

Added line #L271 was not covered by tests

const joinRule = useJoinRule(rtcSession.room);

Expand Down Expand Up @@ -309,7 +311,7 @@ export const GroupCallView: FC<Props> = ({
client={client}
matrixInfo={matrixInfo}
muteStates={muteStates}
onEnter={() => void enterRTCSession(rtcSession, perParticipantE2EE)}
onEnter={() => void enterRTCSession(rtcSession, e2eeSystem.kind)}

Check warning on line 314 in src/room/GroupCallView.tsx

View check run for this annotation

Codecov / codecov/patch

src/room/GroupCallView.tsx#L314

Added line #L314 was not covered by tests
confineToRoom={confineToRoom}
hideHeader={hideHeader}
participantCount={participantCount}
Expand Down
3 changes: 2 additions & 1 deletion src/rtcSessionHelper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { expect, test, vi } from "vitest";

import { enterRTCSession } from "../src/rtcSessionHelpers";
import { Config } from "../src/config/Config";
import { E2eeType } from "./e2ee/e2eeType";

test("It joins the correct Session", async () => {
const focusFromOlderMembership = {
Expand Down Expand Up @@ -51,7 +52,7 @@ test("It joins the correct Session", async () => {
}),
joinRoomSession: vi.fn(),
}) as unknown as MatrixRTCSession;
await enterRTCSession(mockedSession, false);
await enterRTCSession(mockedSession, E2eeType.SHARED_KEY);

expect(mockedSession.joinRoomSession).toHaveBeenLastCalledWith(
[
Expand Down
10 changes: 7 additions & 3 deletions src/rtcSessionHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import { PosthogAnalytics } from "./analytics/PosthogAnalytics";
import { Config } from "./config/Config";
import { ElementWidgetActions, WidgetHelpers, widget } from "./widget";
import { E2eeType } from "./e2ee/e2eeType";

const FOCI_WK_KEY = "org.matrix.msc4143.rtc_foci";

Expand Down Expand Up @@ -87,10 +88,13 @@ async function makePreferredLivekitFoci(

export async function enterRTCSession(
rtcSession: MatrixRTCSession,
encryptMedia: boolean,
e2eeType: E2eeType,
): Promise<void> {
PosthogAnalytics.instance.eventCallEnded.cacheStartCall(new Date());
PosthogAnalytics.instance.eventCallStarted.track(rtcSession.room.roomId);
PosthogAnalytics.instance.eventCallStarted.track(
rtcSession.room.roomId,
e2eeType,
);

// This must be called before we start trying to join the call, as we need to
// have started tracking by the time calls start getting created.
Expand All @@ -104,7 +108,7 @@ export async function enterRTCSession(
await makePreferredLivekitFoci(rtcSession, livekitAlias),
makeActiveFocus(),
{
manageMediaKeys: encryptMedia,
manageMediaKeys: e2eeType === E2eeType.PER_PARTICIPANT,
...(useDeviceSessionMemberEvents !== undefined && {
useLegacyMemberEvents: !useDeviceSessionMemberEvents,
}),
Expand Down
17 changes: 13 additions & 4 deletions src/utils/matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export function sanitiseRoomNameInput(input: string): string {
interface CreateRoomResult {
roomId: string;
alias?: string;
password?: string;
encryptionSystem: EncryptionSystem;
}

/**
Expand Down Expand Up @@ -286,16 +286,25 @@ export async function createRoom(
client.on(ClientEvent.Room, onRoom);
});

let password: string | undefined;
let encryptionSystem: EncryptionSystem;

Check warning on line 289 in src/utils/matrix.ts

View check run for this annotation

Codecov / codecov/patch

src/utils/matrix.ts#L289

Added line #L289 was not covered by tests

if (e2ee == E2eeType.SHARED_KEY) {
password = secureRandomBase64Url(16);
const password = secureRandomBase64Url(16);

Check warning on line 292 in src/utils/matrix.ts

View check run for this annotation

Codecov / codecov/patch

src/utils/matrix.ts#L292

Added line #L292 was not covered by tests
saveKeyForRoom(roomId, password);
encryptionSystem = {
kind: E2eeType.SHARED_KEY,
secret: password,
};
} else {
encryptionSystem = {
kind: e2ee,
};

Check warning on line 301 in src/utils/matrix.ts

View check run for this annotation

Codecov / codecov/patch

src/utils/matrix.ts#L294-L301

Added lines #L294 - L301 were not covered by tests
}

return {
roomId,
alias: e2ee ? undefined : fullAliasFromRoomName(name, client),
password,
encryptionSystem,

Check warning on line 307 in src/utils/matrix.ts

View check run for this annotation

Codecov / codecov/patch

src/utils/matrix.ts#L307

Added line #L307 was not covered by tests
};
}

Expand Down
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5949,9 +5949,9 @@ [email protected]:
resolved "https://registry.yarnpkg.com/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz#c8c38911e2cb29023b0bbac8d6f32e0de2c957dd"
integrity sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==

matrix-js-sdk@matrix-org/matrix-js-sdk#169e8f86139111574a3738f8557c6fa4b2a199db:
matrix-js-sdk@matrix-org/matrix-js-sdk#94fb839140964a967b0f37c1205b037732e0f3d0:
version "34.4.0"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/169e8f86139111574a3738f8557c6fa4b2a199db"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/94fb839140964a967b0f37c1205b037732e0f3d0"
dependencies:
"@babel/runtime" "^7.12.5"
"@matrix-org/matrix-sdk-crypto-wasm" "^7.0.0"
Expand Down

0 comments on commit 76a2ef8

Please sign in to comment.