/** * Feishu app registration via OAuth device-code flow. * * Migrated from feishu-plugin-cli's `feishu-auth.ts` and `install-prompts.ts`. * Replaces axios with native fetch, removes inquirer/ora/chalk in favor of * the openclaw WizardPrompter surface.
*/ import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime"; import { renderQrTerminal } from "./qr-terminal.js"; import type { FeishuDomain } from "./types.js";
async function fetchFeishuJson<T>(params: {
url: string;
init: RequestInit;
auditContext: string;
}): Promise<T> { const { response, release } = await fetchWithSsrFGuard({
url: params.url,
init: params.init,
policy: { allowedHostnames: [new URL(params.url).hostname] },
auditContext: params.auditContext,
}); try { // Registration poll returns 4xx for pending/error states with a JSON body. return (await response.json()) as T;
} finally {
await release();
}
}
// --------------------------------------------------------------------------- // Public API // ---------------------------------------------------------------------------
/** * Step 1: Initialize registration and verify the environment supports * `client_secret` auth. * * @throws If the environment does not support `client_secret`.
*/
export async function initAppRegistration(domain: FeishuDomain = "feishu"): Promise<void> { const baseUrl = accountsBaseUrl(domain); const res = await postRegistration<InitResponse>(baseUrl, { action: "init" });
if (!res.supported_auth_methods?.includes("client_secret")) { thrownew Error("Current environment does not support client_secret auth method");
}
}
/** * Step 2: Begin the device-code flow. Returns a device code and a QR URL * that the user should scan with Feishu/Lark mobile app.
*/
export async function beginAppRegistration(domain: FeishuDomain = "feishu"): Promise<BeginResult> { const baseUrl = accountsBaseUrl(domain); const res = await postRegistration<RawBeginResponse>(baseUrl, {
action: "begin",
archetype: "PersonalAgent",
auth_method: "client_secret",
request_user_info: "open_id",
});
const qrUrl = new URL(res.verification_uri_complete);
qrUrl.searchParams.set("from", "oc_onboard");
qrUrl.searchParams.set("tp", "ob_cli_app");
/** * Print QR code directly to stdout. * * QR codes must be printed without any surrounding box/border decoration, * otherwise the pattern is corrupted and cannot be scanned.
*/
export async function printQrCode(url: string): Promise<void> { const output = await renderQrTerminal(url, { small: true });
process.stdout.write(output.endsWith("\n") ? output : `${output}\n`);
}
/** * Fetch the app owner's open_id using the application.v6.application.get API. * * Used during setup to auto-populate security policy allowlists. * Returns undefined on any failure (fail-open).
*/
export async function getAppOwnerOpenId(params: {
appId: string;
appSecret: string;
domain?: FeishuDomain;
}): Promise<string | undefined> { const baseUrl =
params.domain === "lark" ? "https://open.larksuite.com" : "https://open.feishu.cn";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.