mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(device-pair): resolve QR senders by own key (#101652)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
@@ -601,6 +601,33 @@ describe("device-pair /pair qr", () => {
|
||||
expect(text).not.toContain("```");
|
||||
});
|
||||
|
||||
it.each(["toString", "constructor", "__proto__"])(
|
||||
"requires QR channel sender %s to be an own entry",
|
||||
async (channel) => {
|
||||
const loadAdapter = vi.fn(async () => undefined);
|
||||
const command = registerPairCommand({
|
||||
runtime: {
|
||||
channel: { outbound: { loadAdapter } },
|
||||
} as unknown as OpenClawPluginApi["runtime"],
|
||||
});
|
||||
const result = await command.handler(
|
||||
createCommandContext({
|
||||
channel,
|
||||
senderId: "prototype-channel",
|
||||
gatewayClientScopes: INTERNAL_SETUP_SCOPES,
|
||||
}),
|
||||
);
|
||||
const text = requireText(result);
|
||||
|
||||
expect(pluginApiMocks.writeQrPngTempFile).not.toHaveBeenCalled();
|
||||
expect(loadAdapter).not.toHaveBeenCalled();
|
||||
expect(pluginApiMocks.revokeDeviceBootstrapToken).not.toHaveBeenCalled();
|
||||
expect(pluginApiMocks.issueDeviceBootstrapToken).toHaveBeenCalledTimes(1);
|
||||
expect(text).toContain("QR image delivery is not available on this channel");
|
||||
expect(text).toContain("Setup code:");
|
||||
},
|
||||
);
|
||||
|
||||
it("supports invalidating unused setup codes", async () => {
|
||||
const command = registerPairCommand();
|
||||
const result = await command?.handler(
|
||||
|
||||
@@ -590,8 +590,9 @@ function formatQrInfoMarkdown(params: {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
function canSendQrPngToChannel(channel: string): boolean {
|
||||
return channel in QR_CHANNEL_SENDERS;
|
||||
function resolveQrChannelSender(channel: string): QrChannelSender | undefined {
|
||||
// Prototype names are not supported channel entries and must take the setup-code fallback.
|
||||
return Object.hasOwn(QR_CHANNEL_SENDERS, channel) ? QR_CHANNEL_SENDERS[channel] : undefined;
|
||||
}
|
||||
|
||||
function resolveQrReplyTarget(ctx: QrCommandContext): string {
|
||||
@@ -634,16 +635,13 @@ async function issueSetupPayload(url: string, urls?: string[]): Promise<SetupPay
|
||||
async function sendQrPngToSupportedChannel(params: {
|
||||
api: OpenClawPluginApi;
|
||||
ctx: QrCommandContext;
|
||||
sender: QrChannelSender;
|
||||
target: string;
|
||||
caption: string;
|
||||
qrFilePath: string;
|
||||
}): Promise<boolean> {
|
||||
const mediaLocalRoots = [path.dirname(params.qrFilePath)];
|
||||
const accountId = normalizeOptionalString(params.ctx.accountId) || undefined;
|
||||
const sender = QR_CHANNEL_SENDERS[params.ctx.channel];
|
||||
if (!sender) {
|
||||
return false;
|
||||
}
|
||||
const adapter = await params.api.runtime.channel.outbound.loadAdapter(params.ctx.channel);
|
||||
const send = adapter?.sendMedia;
|
||||
if (!send) {
|
||||
@@ -653,7 +651,7 @@ async function sendQrPngToSupportedChannel(params: {
|
||||
cfg: params.api.config,
|
||||
to: params.target,
|
||||
text: params.caption,
|
||||
...sender.createOpts({
|
||||
...params.sender.createOpts({
|
||||
ctx: params.ctx,
|
||||
qrFilePath: params.qrFilePath,
|
||||
mediaLocalRoots,
|
||||
@@ -783,6 +781,7 @@ export default definePluginEntry({
|
||||
|
||||
if (action === "qr") {
|
||||
const channel = ctx.channel;
|
||||
const qrChannelSender = resolveQrChannelSender(channel);
|
||||
const target = resolveQrReplyTarget(ctx);
|
||||
let autoNotifyArmed = false;
|
||||
|
||||
@@ -807,7 +806,7 @@ export default definePluginEntry({
|
||||
expiresAtMs: payload.expiresAtMs,
|
||||
});
|
||||
|
||||
if (target && canSendQrPngToChannel(channel)) {
|
||||
if (target && qrChannelSender) {
|
||||
let qrFilePath: string | undefined;
|
||||
try {
|
||||
const { resolvePreferredOpenClawTmpDir, writeQrPngTempFile } =
|
||||
@@ -822,6 +821,7 @@ export default definePluginEntry({
|
||||
const sent = await sendQrPngToSupportedChannel({
|
||||
api,
|
||||
ctx,
|
||||
sender: qrChannelSender,
|
||||
target,
|
||||
caption: ["Scan this QR code with the OpenClaw iOS app:", "", ...infoLines].join(
|
||||
"\n",
|
||||
|
||||
Reference in New Issue
Block a user