mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 04:13:17 +08:00
68 lines
2.9 KiB
JavaScript
68 lines
2.9 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { mkdtemp, readFile, rm, stat } from 'node:fs/promises';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import test from 'node:test';
|
|
|
|
import {
|
|
deriveWecomBotIdentity,
|
|
WecomConfigStore,
|
|
} from '../../../src/channels/wecom/config-store.mjs';
|
|
import { WecomQrAuth } from '../../../src/channels/wecom/qr-auth.mjs';
|
|
|
|
test('Enterprise WeChat config stores only non-secret bot identity with mode 0600', async (t) => {
|
|
const root = await mkdtemp(join(tmpdir(), 'dsh-im-wecom-config-'));
|
|
t.after(() => rm(root, { recursive: true, force: true }));
|
|
const path = join(root, 'config.json');
|
|
const identity = deriveWecomBotIdentity('bot-enterprise-1');
|
|
const store = await new WecomConfigStore(path).load();
|
|
await store.save({
|
|
...identity,
|
|
remoteBotId: 'bot-enterprise-1',
|
|
createdAt: '2026-08-15T00:00:00.000Z',
|
|
});
|
|
const document = await readFile(path, 'utf8');
|
|
assert.match(document, /bot-enterprise-1/);
|
|
assert.doesNotMatch(document, /private-secret|"secret"/);
|
|
assert.equal((await stat(path)).mode & 0o777, 0o600);
|
|
assert.equal(store.get(identity.botId).remoteBotId, 'bot-enterprise-1');
|
|
});
|
|
|
|
test('Enterprise WeChat QR auth uses fixed official endpoints and returns credentials only after success', async () => {
|
|
const requests = [];
|
|
const replies = [
|
|
{ data: { scode: 'opaque-scode', auth_url: 'https://work.weixin.qq.com/ai/qc/auth?ticket=opaque' } },
|
|
{ data: { status: 'init' } },
|
|
{ data: { status: 'success', bot_info: { botid: 'bot-enterprise-1', secret: 'private-secret' } } },
|
|
];
|
|
const auth = new WecomQrAuth({
|
|
clock: () => 1_000,
|
|
fetch: async (url, options) => {
|
|
requests.push({ url: String(url), options });
|
|
return { ok: true, status: 200, json: async () => replies.shift() };
|
|
},
|
|
});
|
|
const started = await auth.start();
|
|
assert.equal(started.verificationUrl, 'https://work.weixin.qq.com/ai/qc/auth?ticket=opaque');
|
|
assert.equal(started.expiresAt, 301_000);
|
|
assert.equal(await auth.poll({ scode: started.scode }).then((value) => value.status), 'waiting');
|
|
const completed = await auth.poll({ scode: started.scode });
|
|
assert.deepEqual(completed, {
|
|
status: 'success', remoteBotId: 'bot-enterprise-1', secret: 'private-secret',
|
|
});
|
|
assert.match(requests[0].url, /^https:\/\/work\.weixin\.qq\.com\/ai\/qc\/generate\?/);
|
|
assert.match(requests[0].url, /source=deepseek-harness/);
|
|
assert.match(requests[1].url, /^https:\/\/work\.weixin\.qq\.com\/ai\/qc\/query_result\?/);
|
|
assert.equal(requests.every(({ options }) => options.redirect === 'error'), true);
|
|
});
|
|
|
|
test('Enterprise WeChat QR auth rejects an authorization URL outside the official host', async () => {
|
|
const auth = new WecomQrAuth({
|
|
fetch: async () => ({
|
|
ok: true,
|
|
status: 200,
|
|
json: async () => ({ data: { scode: 'opaque', auth_url: 'https://example.com/steal' } }),
|
|
}),
|
|
});
|
|
await assert.rejects(() => auth.start(), /invalid data/);
|
|
});
|