mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-16 11:33:30 +01:00
feat: implement DAVE end-to-end encryption (#10921)
* feat(voice): implement DAVE E2EE encryption * chore(voice): update dependencies * chore(voice): update debug logs and dependency report * feat(voice): emit and propogate DAVESession errors * chore(voice): export dave session things * chore(voice): move expiry numbers to consts * feat(voice): keep track of and pass connected client IDs * fix(voice): dont set initial transitions as pending * feat(voice): dave encryption * chore(voice): directly reference package name in import * feat(voice): dave decryption * chore(deps): update @snazzah/davey * fix(voice): handle decryption failure tolerance * fix(voice): move and update decryption failure logic to DAVESession * feat(voice): propogate voice privacy code * fix(voice): actually send a transition ready when ready * feat(voice): propogate transitions and verification code function * feat(voice): add dave options * chore: resolve format change requests * chore: emit debug messages on bad transitions * chore: downgrade commit/welcome errors as debug messages * chore: resolve formatting change requests * chore: update davey dependency * chore: add types for underlying dave session * fix: fix rebase * chore: change "ID" to "id" in typedocs --------- Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
This commit is contained in:
@@ -182,6 +182,12 @@ export interface VoiceConnection extends EventEmitter {
|
||||
* @eventProperty
|
||||
*/
|
||||
on(event: 'stateChange', listener: (oldState: VoiceConnectionState, newState: VoiceConnectionState) => void): this;
|
||||
/**
|
||||
* Emitted when the end-to-end encrypted session has transitioned
|
||||
*
|
||||
* @eventProperty
|
||||
*/
|
||||
on(event: 'transitioned', listener: (transitionId: number) => void): this;
|
||||
/**
|
||||
* Emitted when the state of the voice connection changes to a specific status
|
||||
*
|
||||
@@ -235,6 +241,11 @@ export class VoiceConnection extends EventEmitter {
|
||||
*/
|
||||
private readonly debug: ((message: string) => void) | null;
|
||||
|
||||
/**
|
||||
* The options used to create this voice connection.
|
||||
*/
|
||||
private readonly options: CreateVoiceConnectionOptions;
|
||||
|
||||
/**
|
||||
* Creates a new voice connection.
|
||||
*
|
||||
@@ -253,6 +264,7 @@ export class VoiceConnection extends EventEmitter {
|
||||
this.onNetworkingStateChange = this.onNetworkingStateChange.bind(this);
|
||||
this.onNetworkingError = this.onNetworkingError.bind(this);
|
||||
this.onNetworkingDebug = this.onNetworkingDebug.bind(this);
|
||||
this.onNetworkingTransitioned = this.onNetworkingTransitioned.bind(this);
|
||||
|
||||
const adapter = options.adapterCreator({
|
||||
onVoiceServerUpdate: (data) => this.addServerPacket(data),
|
||||
@@ -268,6 +280,7 @@ export class VoiceConnection extends EventEmitter {
|
||||
};
|
||||
|
||||
this.joinConfig = joinConfig;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,6 +308,7 @@ export class VoiceConnection extends EventEmitter {
|
||||
oldNetworking.off('error', this.onNetworkingError);
|
||||
oldNetworking.off('close', this.onNetworkingClose);
|
||||
oldNetworking.off('stateChange', this.onNetworkingStateChange);
|
||||
oldNetworking.off('transitioned', this.onNetworkingTransitioned);
|
||||
oldNetworking.destroy();
|
||||
}
|
||||
|
||||
@@ -412,14 +426,20 @@ export class VoiceConnection extends EventEmitter {
|
||||
token: server.token,
|
||||
sessionId: state.session_id,
|
||||
userId: state.user_id,
|
||||
channelId: state.channel_id!,
|
||||
},
|
||||
{
|
||||
debug: Boolean(this.debug),
|
||||
daveEncryption: this.options.daveEncryption ?? true,
|
||||
decryptionFailureTolerance: this.options.decryptionFailureTolerance,
|
||||
},
|
||||
Boolean(this.debug),
|
||||
);
|
||||
|
||||
networking.once('close', this.onNetworkingClose);
|
||||
networking.on('stateChange', this.onNetworkingStateChange);
|
||||
networking.on('error', this.onNetworkingError);
|
||||
networking.on('debug', this.onNetworkingDebug);
|
||||
networking.on('transitioned', this.onNetworkingTransitioned);
|
||||
|
||||
this.state = {
|
||||
...this.state,
|
||||
@@ -509,6 +529,15 @@ export class VoiceConnection extends EventEmitter {
|
||||
this.debug?.(`[NW] ${message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagates transitions from the underlying network instance.
|
||||
*
|
||||
* @param transitionId - The transition id
|
||||
*/
|
||||
private onNetworkingTransitioned(transitionId: number) {
|
||||
this.emit('transitioned', transitionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an audio packet for dispatch.
|
||||
*
|
||||
@@ -694,6 +723,41 @@ export class VoiceConnection extends EventEmitter {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The current voice privacy code of the encrypted session.
|
||||
*
|
||||
* @remarks
|
||||
* For this data to be available, the VoiceConnection must be in the Ready state,
|
||||
* and the connection would have to be end-to-end encrypted.
|
||||
*/
|
||||
public get voicePrivacyCode() {
|
||||
if (
|
||||
this.state.status === VoiceConnectionStatus.Ready &&
|
||||
this.state.networking.state.code === NetworkingStatusCode.Ready
|
||||
) {
|
||||
return this.state.networking.state.dave?.voicePrivacyCode ?? undefined;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the verification code for a user in the session.
|
||||
*
|
||||
* @throws Will throw if end-to-end encryption is not on or if the user id provided is not in the session.
|
||||
*/
|
||||
public async getVerificationCode(userId: string): Promise<string> {
|
||||
if (
|
||||
this.state.status === VoiceConnectionStatus.Ready &&
|
||||
this.state.networking.state.code === NetworkingStatusCode.Ready &&
|
||||
this.state.networking.state.dave
|
||||
) {
|
||||
return this.state.networking.state.dave.getVerificationCode(userId);
|
||||
}
|
||||
|
||||
throw new Error('Session not available');
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a subscription of this voice connection to an audio player is removed.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user