Skip to content

Commit 9a602f7

Browse files
committed
fix(discord): PluralKit DM pairing identity + direct peer regex (#86332)
Bug 1: resolveDiscordDmPreflightAccess passed the raw gateway author to handleDiscordDmCommandDecision while the access check used the resolved (PK-aware) sender identity. The two diverge for PluralKit users — the pairing record was keyed by the Discord user id while the ingress resolver looked it up by PK member UUID. Result: every inbound DM from a PK user triggered a fresh pairing challenge. Bug 2: extractDiscordSessionKind regex matched 'dm' but not 'direct', which is the canonical peer kind used for normalized DM session keys. No visible breakage today because all callers compare against 'dm', but a latent fragility for any future caller that distinguishes 'direct' from null. - Pass params.sender (resolved identity, includes PK UUID) to the pairing decision so the record key matches the lookup key. - Extend the kind regex to accept 'direct' and map it to 'dm'. Closes #86332
1 parent 35dcd42 commit 9a602f7

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

extensions/discord/src/approval-native.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,18 @@ function extractDiscordSessionKind(sessionKey?: string | null): "channel" | "gro
3636
if (!sessionKey) {
3737
return null;
3838
}
39-
const match = sessionKey.match(/discord:(channel|group|dm):/);
39+
// DM session keys use the `direct` peer kind in the normalized form
40+
// (`agent:<id>:discord:direct:<userId>`); legacy keys may still use `dm`.
41+
// Treat both as the same logical kind for downstream comparisons.
42+
const match = sessionKey.match(/discord:(channel|group|dm|direct):/);
4043
if (!match) {
4144
return null;
4245
}
43-
return match[1] as "channel" | "group" | "dm";
46+
const raw = match[1];
47+
if (raw === "direct") {
48+
return "dm";
49+
}
50+
return raw as "channel" | "group" | "dm";
4451
}
4552

4653
function normalizeDiscordOriginChannelId(value?: string | null): string | null {

extensions/discord/src/monitor/message-handler.dm-preflight.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,15 @@ export async function resolveDiscordDmPreflightAccess(params: {
7979
await handleDiscordDmCommandDecision({
8080
senderAccess: dmAccess.senderAccess,
8181
accountId: params.resolvedAccountId,
82+
// Use the resolved sender identity (e.g. PluralKit member UUID) here so
83+
// the pairing record is keyed under the same stableId that
84+
// resolveDiscordDmCommandAccess / createDiscordDmIngressSubject use on
85+
// subsequent inbound messages. Previously this used the raw gateway
86+
// author id, which only matched non-PK users.
8287
sender: {
83-
id: params.author.id,
84-
tag: formatDiscordUserTag(params.author),
85-
name: params.author.username ?? undefined,
88+
id: params.sender.id,
89+
tag: params.sender.tag ?? formatDiscordUserTag(params.author),
90+
name: params.sender.name ?? params.author.username ?? undefined,
8691
},
8792
onPairingCreated: async (code) => {
8893
logVerbose(

0 commit comments

Comments
 (0)