receive verification request
This commit is contained in:
parent
c4b36b9064
commit
5cbc88fbdb
5 changed files with 121 additions and 164 deletions
|
|
@ -1,11 +1,4 @@
|
|||
import {
|
||||
ShowSasCallbacks,
|
||||
VerificationPhase,
|
||||
VerificationRequest,
|
||||
Verifier,
|
||||
} from 'matrix-js-sdk/lib/crypto-api';
|
||||
import React, { CSSProperties, useCallback, useEffect, useState } from 'react';
|
||||
import { VerificationMethod } from 'matrix-js-sdk/lib/types';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
|
|
@ -23,13 +16,24 @@ import {
|
|||
} from 'folds';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import {
|
||||
useVerificationRequestPhase,
|
||||
useVerificationRequestReceived,
|
||||
useVerifierCancel,
|
||||
useVerifierShowSas,
|
||||
} from '../hooks/useVerificationRequest';
|
||||
CancelableVerificationStage,
|
||||
CancelVerificationStage,
|
||||
DoneVerificationStage,
|
||||
InboundRequestStage,
|
||||
InboundVerification,
|
||||
OutboundRequestStage,
|
||||
OutboundVerification,
|
||||
ReadyVerificationStage,
|
||||
SasAcceptStage,
|
||||
SasCancelState,
|
||||
SasMethod,
|
||||
SasStartStage,
|
||||
StartVerificationStage,
|
||||
} from 'neurone/lib/crypto/machine/verification';
|
||||
import { useVerificationRequestReceived } from '../hooks/useVerificationRequest';
|
||||
import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback';
|
||||
import { ContainerColor } from '../styles/ContainerColor.css';
|
||||
import { useObservableValue } from '../hooks/useObservableValue';
|
||||
|
||||
const DialogHeaderStyles: CSSProperties = {
|
||||
padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
|
||||
|
|
@ -70,10 +74,12 @@ function VerificationWaitAccept() {
|
|||
}
|
||||
|
||||
type VerificationAcceptProps = {
|
||||
onAccept: () => Promise<void>;
|
||||
stage: InboundRequestStage;
|
||||
};
|
||||
function VerificationAccept({ onAccept }: VerificationAcceptProps) {
|
||||
const [acceptState, accept] = useAsyncCallback(onAccept);
|
||||
function VerificationAccept({ stage }: VerificationAcceptProps) {
|
||||
const [acceptState, accept] = useAsyncCallback(
|
||||
useCallback(() => stage.ready(['m.sas.v1']), [stage])
|
||||
);
|
||||
|
||||
const accepting = acceptState.status === AsyncStatus.Loading;
|
||||
return (
|
||||
|
|
@ -102,12 +108,12 @@ function VerificationWaitStart() {
|
|||
}
|
||||
|
||||
type VerificationStartProps = {
|
||||
onStart: () => Promise<void>;
|
||||
stage: ReadyVerificationStage;
|
||||
};
|
||||
function AutoVerificationStart({ onStart }: VerificationStartProps) {
|
||||
function AutoVerificationStart({ stage }: VerificationStartProps) {
|
||||
useEffect(() => {
|
||||
onStart();
|
||||
}, [onStart]);
|
||||
stage.startSas();
|
||||
}, [stage]);
|
||||
|
||||
return (
|
||||
<Box direction="Column" gap="400">
|
||||
|
|
@ -116,8 +122,8 @@ function AutoVerificationStart({ onStart }: VerificationStartProps) {
|
|||
);
|
||||
}
|
||||
|
||||
function CompareEmoji({ sasData }: { sasData: ShowSasCallbacks }) {
|
||||
const [confirmState, confirm] = useAsyncCallback(useCallback(() => sasData.confirm(), [sasData]));
|
||||
function CompareEmoji({ stage }: { stage: SasAcceptStage }) {
|
||||
const [confirmState, confirm] = useAsyncCallback(useCallback(() => stage.match(), [stage]));
|
||||
|
||||
const confirming =
|
||||
confirmState.status === AsyncStatus.Loading || confirmState.status === AsyncStatus.Success;
|
||||
|
|
@ -135,17 +141,17 @@ function CompareEmoji({ sasData }: { sasData: ShowSasCallbacks }) {
|
|||
wrap="Wrap"
|
||||
justifyContent="Center"
|
||||
>
|
||||
{sasData.sas.emoji?.map(([emoji, name], index) => (
|
||||
{stage.emoji?.map((emoji, index) => (
|
||||
<Box
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
key={`${emoji}${name}${index}`}
|
||||
key={`${emoji.description}${index}`}
|
||||
direction="Column"
|
||||
gap="100"
|
||||
justifyContent="Center"
|
||||
alignItems="Center"
|
||||
>
|
||||
<Text size="H1">{emoji}</Text>
|
||||
<Text size="T200">{name}</Text>
|
||||
<Text size="H1">{emoji.emoji}</Text>
|
||||
<Text size="T200">{emoji.description}</Text>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
|
|
@ -162,7 +168,7 @@ function CompareEmoji({ sasData }: { sasData: ShowSasCallbacks }) {
|
|||
<Button
|
||||
variant="Primary"
|
||||
fill="Soft"
|
||||
onClick={() => sasData.mismatch()}
|
||||
onClick={() => stage.mismatch()}
|
||||
disabled={confirming}
|
||||
>
|
||||
<Text size="B400">Do not Match</Text>
|
||||
|
|
@ -173,21 +179,23 @@ function CompareEmoji({ sasData }: { sasData: ShowSasCallbacks }) {
|
|||
}
|
||||
|
||||
type SasVerificationProps = {
|
||||
verifier: Verifier;
|
||||
sas: SasMethod;
|
||||
onCancel: () => void;
|
||||
};
|
||||
function SasVerification({ verifier, onCancel }: SasVerificationProps) {
|
||||
const [sasData, setSasData] = useState<ShowSasCallbacks>();
|
||||
|
||||
useVerifierShowSas(verifier, setSasData);
|
||||
useVerifierCancel(verifier, onCancel);
|
||||
function SasVerification({ sas, onCancel }: SasVerificationProps) {
|
||||
const stage = useObservableValue(sas.stage);
|
||||
|
||||
useEffect(() => {
|
||||
verifier.verify();
|
||||
}, [verifier]);
|
||||
if (stage instanceof SasStartStage) {
|
||||
stage.accept();
|
||||
}
|
||||
if (stage instanceof SasCancelState) {
|
||||
onCancel();
|
||||
}
|
||||
}, [stage, onCancel]);
|
||||
|
||||
if (sasData) {
|
||||
return <CompareEmoji sasData={sasData} />;
|
||||
if (stage instanceof SasAcceptStage && stage.emoji) {
|
||||
return <CompareEmoji stage={stage} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -214,12 +222,13 @@ function VerificationDone({ onExit }: VerificationDoneProps) {
|
|||
}
|
||||
|
||||
type VerificationCanceledProps = {
|
||||
stage: CancelVerificationStage;
|
||||
onClose: () => void;
|
||||
};
|
||||
function VerificationCanceled({ onClose }: VerificationCanceledProps) {
|
||||
function VerificationCanceled({ stage, onClose }: VerificationCanceledProps) {
|
||||
return (
|
||||
<Box direction="Column" gap="400">
|
||||
<Text>Verification has been canceled.</Text>
|
||||
<Text>Verification has been canceled. {stage.reason}</Text>
|
||||
<Button variant="Secondary" fill="Soft" onClick={onClose}>
|
||||
<Text size="B400">Close</Text>
|
||||
</Button>
|
||||
|
|
@ -228,23 +237,18 @@ function VerificationCanceled({ onClose }: VerificationCanceledProps) {
|
|||
}
|
||||
|
||||
type DeviceVerificationProps = {
|
||||
request: VerificationRequest;
|
||||
request: InboundVerification | OutboundVerification;
|
||||
onExit: () => void;
|
||||
};
|
||||
export function DeviceVerification({ request, onExit }: DeviceVerificationProps) {
|
||||
const phase = useVerificationRequestPhase(request);
|
||||
const stage = useObservableValue(request.stage);
|
||||
|
||||
const handleCancel = useCallback(() => {
|
||||
if (request.phase !== VerificationPhase.Done && request.phase !== VerificationPhase.Cancelled) {
|
||||
request.cancel();
|
||||
if (stage instanceof CancelableVerificationStage) {
|
||||
stage.cancel();
|
||||
}
|
||||
onExit();
|
||||
}, [request, onExit]);
|
||||
|
||||
const handleAccept = useCallback(() => request.accept(), [request]);
|
||||
const handleStart = useCallback(async () => {
|
||||
await request.startVerification(VerificationMethod.Sas);
|
||||
}, [request]);
|
||||
}, [stage, onExit]);
|
||||
|
||||
return (
|
||||
<Overlay open backdrop={<OverlayBackdrop />}>
|
||||
|
|
@ -266,30 +270,27 @@ export function DeviceVerification({ request, onExit }: DeviceVerificationProps)
|
|||
</IconButton>
|
||||
</Header>
|
||||
<Box style={{ padding: config.space.S400 }} direction="Column" gap="400">
|
||||
{phase === VerificationPhase.Requested &&
|
||||
(request.initiatedByMe ? (
|
||||
<VerificationWaitAccept />
|
||||
) : (
|
||||
<VerificationAccept onAccept={handleAccept} />
|
||||
))}
|
||||
{phase === VerificationPhase.Ready &&
|
||||
(request.initiatedByMe ? (
|
||||
<AutoVerificationStart onStart={handleStart} />
|
||||
{stage instanceof InboundRequestStage && <VerificationAccept stage={stage} />}
|
||||
{stage instanceof OutboundRequestStage && <VerificationWaitAccept />}
|
||||
{stage instanceof ReadyVerificationStage &&
|
||||
(request instanceof OutboundRequestStage ? (
|
||||
<AutoVerificationStart stage={stage} />
|
||||
) : (
|
||||
<VerificationWaitStart />
|
||||
))}
|
||||
{phase === VerificationPhase.Started &&
|
||||
(request.verifier ? (
|
||||
<SasVerification verifier={request.verifier} onCancel={handleCancel} />
|
||||
{stage instanceof StartVerificationStage &&
|
||||
(stage.method ? (
|
||||
<SasVerification sas={stage.method} onCancel={handleCancel} />
|
||||
) : (
|
||||
<VerificationUnexpected
|
||||
message="Unexpected Error! Verification is started but verifier is missing."
|
||||
onClose={handleCancel}
|
||||
/>
|
||||
))}
|
||||
{phase === VerificationPhase.Done && <VerificationDone onExit={onExit} />}
|
||||
{phase === VerificationPhase.Cancelled && (
|
||||
<VerificationCanceled onClose={handleCancel} />
|
||||
|
||||
{stage instanceof DoneVerificationStage && <VerificationDone onExit={onExit} />}
|
||||
{stage instanceof CancelVerificationStage && (
|
||||
<VerificationCanceled stage={stage} onClose={handleCancel} />
|
||||
)}
|
||||
</Box>
|
||||
</Dialog>
|
||||
|
|
@ -300,7 +301,7 @@ export function DeviceVerification({ request, onExit }: DeviceVerificationProps)
|
|||
}
|
||||
|
||||
export function ReceiveSelfDeviceVerification() {
|
||||
const [request, setRequest] = useState<VerificationRequest>();
|
||||
const [request, setRequest] = useState<InboundVerification | OutboundVerification>();
|
||||
|
||||
useVerificationRequestReceived(setRequest);
|
||||
|
||||
|
|
@ -310,7 +311,7 @@ export function ReceiveSelfDeviceVerification() {
|
|||
|
||||
if (!request) return null;
|
||||
|
||||
if (!request.isSelfVerification) {
|
||||
if (!request.selfVerification) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,87 +1,11 @@
|
|||
import { useCallback, useEffect, useState } from 'react';
|
||||
import {
|
||||
CryptoEvent,
|
||||
CryptoEventHandlerMap,
|
||||
VerificationPhase,
|
||||
VerificationRequest,
|
||||
VerificationRequestEvent,
|
||||
VerificationRequestEventHandlerMap,
|
||||
Verifier,
|
||||
VerifierEvent,
|
||||
VerifierEventHandlerMap,
|
||||
} from 'matrix-js-sdk/lib/crypto-api';
|
||||
import { useMatrixClient } from './useMatrixClient';
|
||||
import { useEffect } from 'react';
|
||||
import { InboundVerification, OutboundVerification } from 'neurone/lib/crypto/machine/verification';
|
||||
import { useClient } from './useClient';
|
||||
|
||||
export const useVerificationRequestReceived = (
|
||||
onRequest: CryptoEventHandlerMap[CryptoEvent.VerificationRequestReceived]
|
||||
onRequest: (request: OutboundVerification | InboundVerification) => void
|
||||
) => {
|
||||
const mx = useMatrixClient();
|
||||
const ct = useClient();
|
||||
|
||||
useEffect(() => {
|
||||
mx.on(CryptoEvent.VerificationRequestReceived, onRequest);
|
||||
return () => {
|
||||
mx.removeListener(CryptoEvent.VerificationRequestReceived, onRequest);
|
||||
};
|
||||
}, [mx, onRequest]);
|
||||
};
|
||||
|
||||
export const useVerificationRequestChange = (
|
||||
request: VerificationRequest,
|
||||
onChange: VerificationRequestEventHandlerMap[VerificationRequestEvent.Change]
|
||||
) => {
|
||||
useEffect(() => {
|
||||
request.on(VerificationRequestEvent.Change, onChange);
|
||||
return () => {
|
||||
request.removeListener(VerificationRequestEvent.Change, onChange);
|
||||
};
|
||||
}, [request, onChange]);
|
||||
};
|
||||
|
||||
export const useVerificationRequestPhase = (request: VerificationRequest): VerificationPhase => {
|
||||
const [phase, setPhase] = useState(() => request.phase);
|
||||
|
||||
useVerificationRequestChange(
|
||||
request,
|
||||
useCallback(() => {
|
||||
setPhase(request.phase);
|
||||
}, [request])
|
||||
);
|
||||
|
||||
return phase;
|
||||
};
|
||||
|
||||
export const useVerifierCancel = (
|
||||
verifier: Verifier,
|
||||
onCallback: VerifierEventHandlerMap[VerifierEvent.Cancel]
|
||||
) => {
|
||||
useEffect(() => {
|
||||
verifier.on(VerifierEvent.Cancel, onCallback);
|
||||
return () => {
|
||||
verifier.removeListener(VerifierEvent.Cancel, onCallback);
|
||||
};
|
||||
}, [verifier, onCallback]);
|
||||
};
|
||||
|
||||
export const useVerifierShowSas = (
|
||||
verifier: Verifier,
|
||||
onCallback: VerifierEventHandlerMap[VerifierEvent.ShowSas]
|
||||
) => {
|
||||
useEffect(() => {
|
||||
verifier.on(VerifierEvent.ShowSas, onCallback);
|
||||
return () => {
|
||||
verifier.removeListener(VerifierEvent.ShowSas, onCallback);
|
||||
};
|
||||
}, [verifier, onCallback]);
|
||||
};
|
||||
|
||||
export const useVerifierShowReciprocateQr = (
|
||||
verifier: Verifier,
|
||||
onCallback: VerifierEventHandlerMap[VerifierEvent.ShowReciprocateQr]
|
||||
) => {
|
||||
useEffect(() => {
|
||||
verifier.on(VerifierEvent.ShowReciprocateQr, onCallback);
|
||||
return () => {
|
||||
verifier.removeListener(VerifierEvent.ShowReciprocateQr, onCallback);
|
||||
};
|
||||
}, [verifier, onCallback]);
|
||||
useEffect(() => ct.verificationRequest.subscribe(onRequest), [ct, onRequest]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ import { GetSyncOK, JoinRoom } from 'neurone/lib/api/matrix/client/v3/sync';
|
|||
import { ObservableValue } from 'neurone/lib/utils/observable';
|
||||
import { EncryptionSyncChanges } from 'neurone/lib/crypto/machine';
|
||||
import { Disposable, Disposer } from 'neurone/lib/utils/disposable';
|
||||
import { ToDeviceDecrypted, ToDevicePlainText } from 'neurone/lib/crypto/machine/events';
|
||||
import { roomState } from 'neurone/lib/utils/sync/v3/join';
|
||||
import { ObjectReader } from 'neurone/lib/utils';
|
||||
import { InboundVerification, OutboundVerification } from 'neurone/lib/crypto/machine/verification';
|
||||
import to from 'await-to-js';
|
||||
import { ClientContext } from './context';
|
||||
import { writeSync } from './syncWriter';
|
||||
|
|
@ -11,6 +13,12 @@ import { sessionValue } from './storage/collections';
|
|||
import { syncLatestEvent } from './syncLatestEvent';
|
||||
import { SyncValue } from './sync';
|
||||
|
||||
export type SyncResponseManagerCallbacks = {
|
||||
onWriteComplete: () => void;
|
||||
onSyncToken: (token: string) => void;
|
||||
onVerificationRequest: (verificationFlow: OutboundVerification | InboundVerification) => void;
|
||||
};
|
||||
|
||||
export class SyncResponseManager implements Disposable {
|
||||
private firstSync = true;
|
||||
|
||||
|
|
@ -18,22 +26,18 @@ export class SyncResponseManager implements Disposable {
|
|||
|
||||
private readonly syncTokenObservable: ObservableValue<string | undefined>;
|
||||
|
||||
private readonly onWriteComplete: () => void;
|
||||
|
||||
private readonly onSyncToken: (token: string) => void;
|
||||
private readonly callbacks: SyncResponseManagerCallbacks;
|
||||
|
||||
private readonly disposer = new Disposer();
|
||||
|
||||
constructor(
|
||||
ct: ClientContext,
|
||||
syncTokenObservable: ObservableValue<string | undefined>,
|
||||
onWriteComplete: () => void,
|
||||
onSyncToken: (token: string) => void
|
||||
callbacks: SyncResponseManagerCallbacks
|
||||
) {
|
||||
this.ct = ct;
|
||||
this.syncTokenObservable = syncTokenObservable;
|
||||
this.onWriteComplete = onWriteComplete;
|
||||
this.onSyncToken = onSyncToken;
|
||||
this.callbacks = callbacks;
|
||||
|
||||
this.disposer.collect(
|
||||
this.syncTokenObservable.subscribe(this.handleSyncToken.bind(this)),
|
||||
|
|
@ -48,7 +52,7 @@ export class SyncResponseManager implements Disposable {
|
|||
// after syncLatestEvent completes to prevent race
|
||||
return;
|
||||
}
|
||||
this.onSyncToken(sinceToken);
|
||||
this.callbacks.onSyncToken(sinceToken);
|
||||
};
|
||||
|
||||
private async handleSync(syncValue: SyncValue) {
|
||||
|
|
@ -70,7 +74,14 @@ export class SyncResponseManager implements Disposable {
|
|||
unusedFallbackKeys: data.device_unused_fallback_key_types,
|
||||
};
|
||||
|
||||
await this.ct.machine.syncChanges.receive(encryptionChanges);
|
||||
const proccessedToDeviceEvents = await this.ct.machine.syncChanges.receive(encryptionChanges);
|
||||
proccessedToDeviceEvents
|
||||
.filter((e) => e instanceof ToDeviceDecrypted || e instanceof ToDevicePlainText)
|
||||
.forEach((proccessedEvent) => {
|
||||
this.ct.machine.verificationManager.receiveToDeviceEvent(proccessedEvent.event, (v) =>
|
||||
this.callbacks.onVerificationRequest(v)
|
||||
);
|
||||
});
|
||||
// TODO: room key bundle detection from to device events;
|
||||
|
||||
const encryptedRooms = this.filterEncryptedRoomResponse(data.rooms?.join ?? {});
|
||||
|
|
@ -81,7 +92,7 @@ export class SyncResponseManager implements Disposable {
|
|||
}
|
||||
|
||||
private async afterWrite(nextBatch: string) {
|
||||
this.onWriteComplete();
|
||||
this.callbacks.onWriteComplete();
|
||||
|
||||
await this.ct.machine.outgoingRequests.processAll();
|
||||
|
||||
|
|
@ -95,7 +106,7 @@ export class SyncResponseManager implements Disposable {
|
|||
const [err] = await to(syncLatestEvent(this.ct, currentSyncToken));
|
||||
if (err) console.error(err);
|
||||
this.firstSync = false;
|
||||
this.onSyncToken(nextBatch);
|
||||
this.callbacks.onSyncToken(nextBatch);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { ComputedObservableValue, ObservableValue } from 'neurone/lib/utils/observable';
|
||||
import { ComputedObservableValue, Observable, ObservableValue } from 'neurone/lib/utils/observable';
|
||||
import { MatrixRequest } from 'neurone/lib/matrix-request';
|
||||
import { HistoryVisibility, Machine } from 'neurone/lib/crypto/machine';
|
||||
import { ObjectReader } from 'neurone/lib/utils';
|
||||
import { Disposer } from 'neurone/lib/utils/disposable';
|
||||
import { InboundVerification, OutboundVerification } from 'neurone/lib/crypto/machine/verification';
|
||||
import {
|
||||
MessageEventWithoutRoomId,
|
||||
RoomSummary,
|
||||
|
|
@ -103,6 +104,7 @@ export type ClientContext = {
|
|||
roomToTimeline: ObservableValue<Map<string, Timeline>>;
|
||||
|
||||
pendingMemberRooms: ObservableValue<string[]>;
|
||||
verificationRequest: Observable<InboundVerification | OutboundVerification>;
|
||||
sync: SyncContext;
|
||||
requestAuthJSON: MatrixRequest;
|
||||
getTxnId: GetTxnId;
|
||||
|
|
@ -878,3 +880,18 @@ export const createPendingMemberRoomObservable = async (
|
|||
disposer.collect(pendingMemberRoomsObj, pendingMemberRoomsObservable);
|
||||
return pendingMemberRoomsObservable;
|
||||
};
|
||||
|
||||
export const createVerificationRequestObservable = () => {
|
||||
const publishKey = crypto.randomUUID();
|
||||
const verificationRequest = new Observable<InboundVerification | OutboundVerification>(
|
||||
publishKey
|
||||
);
|
||||
const onVerificationRequest = (v: InboundVerification | OutboundVerification) => {
|
||||
verificationRequest.publish(publishKey, v);
|
||||
};
|
||||
|
||||
return {
|
||||
verificationRequest,
|
||||
onVerificationRequest,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
createSpaceMapping,
|
||||
createStateContext,
|
||||
createSyncTokenObservable,
|
||||
createVerificationRequestObservable,
|
||||
} from './context';
|
||||
import { createStorage } from './storage';
|
||||
import { getAuthJSONRequest } from './request';
|
||||
|
|
@ -69,6 +70,8 @@ export const initializeClient = async (session: Session): Promise<ClientContext>
|
|||
const syncTokenObservable = await createSyncTokenObservable(storage, disposer);
|
||||
const pendingMemberRooms = await createPendingMemberRoomObservable(storage, disposer);
|
||||
|
||||
const { verificationRequest, onVerificationRequest } = createVerificationRequestObservable();
|
||||
|
||||
const getTxnId: GetTxnId = getTxnIdFunc();
|
||||
|
||||
const [syncObservable, sync] = createSync(requestAuthJSON);
|
||||
|
|
@ -125,6 +128,7 @@ export const initializeClient = async (session: Session): Promise<ClientContext>
|
|||
roomToTimeline,
|
||||
|
||||
pendingMemberRooms,
|
||||
verificationRequest,
|
||||
sync: {
|
||||
observable: syncObservable,
|
||||
controller: syncController,
|
||||
|
|
@ -137,12 +141,11 @@ export const initializeClient = async (session: Session): Promise<ClientContext>
|
|||
|
||||
const machineManager = new MachineManager(ct);
|
||||
|
||||
const syncResponseManager = new SyncResponseManager(
|
||||
ct,
|
||||
syncTokenObservable,
|
||||
const syncResponseManager = new SyncResponseManager(ct, syncTokenObservable, {
|
||||
onWriteComplete,
|
||||
onSyncToken
|
||||
);
|
||||
onSyncToken,
|
||||
onVerificationRequest,
|
||||
});
|
||||
|
||||
disposer.collect(
|
||||
decryption,
|
||||
|
|
@ -152,6 +155,7 @@ export const initializeClient = async (session: Session): Promise<ClientContext>
|
|||
logoutObservable,
|
||||
logoutManager,
|
||||
machineManager,
|
||||
verificationRequest,
|
||||
syncResponseManager
|
||||
);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue