Treat an unreadable backend probe as the older server, not an error

Stalwart before 0.16 does not know urn:stalwart:jmap, and rejects the whole
request rather than the one call when `using` names a capability it cannot
parse. The probe is only sent when the session advertises that capability, so
this should not arise — but if it ever does, throwing turns a server we can
still manage credentials on into a Security page that only shows an error.
Fall through to the endpoint those servers do have.
This commit is contained in:
2026-08-24 08:41:15 -07:00
parent c55b54163f
commit 337c46ebda
+11 -5
View File
@@ -83,11 +83,17 @@ async function probeBackend(ctx: Ctx): Promise<Backend> {
// A server with the registry answers x:AccountPassword/get; one without it
// fails to parse the method name at all and returns unknownMethod.
if (ctx.session.capabilities && STALWART_CAP in ctx.session.capabilities) {
const res = await jmap(ctx, [["x:AccountPassword/get", { accountId: accountId(ctx), ids: [SINGLETON] }, "p"]]);
const [name, args] = res.methodResponses?.[0] ?? [];
if (name && name !== "error") return "registry";
const type = (args as { type?: string } | undefined)?.type;
if (type && type !== "unknownMethod") return "registry"; // present, but refused us
try {
const res = await jmap(ctx, [["x:AccountPassword/get", { accountId: accountId(ctx), ids: [SINGLETON] }, "p"]]);
const [name, args] = res.methodResponses?.[0] ?? [];
if (name && name !== "error") return "registry";
const type = (args as { type?: string } | undefined)?.type;
if (type && type !== "unknownMethod") return "registry"; // present, but refused us
} catch {
// Not an answer we can read - most likely a server too old to know the
// capability we named, which rejects the whole request rather than the
// one call. Fall through and try the endpoint such servers do have.
}
}
return "legacy";
}