@lemoncat7/dsh-partner 1.0.0 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ import { createDecipheriv } from 'node:crypto';
2
+ import { PARTNER_MEDIA_MAX_BYTES, safeMediaName } from '../../channel-message.js';
3
+ const CDN_BASE_URL = 'https://novac2c.cdn.weixin.qq.com/c2c';
4
+ export async function receiveWeixinMedia(item, signal) {
5
+ if (item.type === 2 && item.image_item) {
6
+ const image = item.image_item;
7
+ const data = await readMedia(image.media, image.aeskey, signal);
8
+ if (!data)
9
+ return undefined;
10
+ const mediaType = imageType(data);
11
+ const extension = imageExtension(mediaType);
12
+ return { kind: 'image', data, name: safeMediaName(image.filename || '微信图片', `微信图片${extension}`, extension), mediaType };
13
+ }
14
+ if (item.type === 4 && item.file_item) {
15
+ const file = item.file_item;
16
+ const data = await readMedia(file.media, undefined, signal);
17
+ if (!data)
18
+ return undefined;
19
+ return { kind: 'file', data, name: safeMediaName(file.file_name || file.filename || '微信文件.bin'), ...(file.content_type ? { mediaType: file.content_type } : {}) };
20
+ }
21
+ return undefined;
22
+ }
23
+ async function readMedia(media, imageAesKey, signal) {
24
+ if (!media)
25
+ return undefined;
26
+ const url = media.full_url?.trim() || (media.encrypt_query_param ? `${CDN_BASE_URL}/download?encrypted_query_param=${encodeURIComponent(media.encrypt_query_param)}` : '');
27
+ if (!url)
28
+ return undefined;
29
+ const parsed = new URL(url);
30
+ if (parsed.protocol !== 'https:' || !trustedWeixinHost(parsed.hostname))
31
+ throw new Error('微信附件下载地址不可信');
32
+ const response = await fetch(parsed, signal ? { signal } : undefined);
33
+ if (!response.ok)
34
+ throw new Error(`微信附件下载失败: HTTP ${response.status}`);
35
+ const declared = Number(response.headers.get('content-length') || 0);
36
+ if (declared > PARTNER_MEDIA_MAX_BYTES)
37
+ throw new Error('微信附件超过 64 MB 限制');
38
+ const encrypted = Buffer.from(await response.arrayBuffer());
39
+ if (encrypted.length > PARTNER_MEDIA_MAX_BYTES + 16)
40
+ throw new Error('微信附件超过 64 MB 限制');
41
+ const encodedKey = imageAesKey ? Buffer.from(imageAesKey, 'hex').toString('base64') : media.aes_key;
42
+ if (!encodedKey)
43
+ return encrypted;
44
+ const key = decodeAesKey(encodedKey);
45
+ const decipher = createDecipheriv('aes-128-ecb', key, null);
46
+ const plain = Buffer.concat([decipher.update(encrypted), decipher.final()]);
47
+ if (plain.length > PARTNER_MEDIA_MAX_BYTES)
48
+ throw new Error('微信附件超过 64 MB 限制');
49
+ return plain;
50
+ }
51
+ function decodeAesKey(value) {
52
+ const decoded = Buffer.from(value, 'base64');
53
+ if (decoded.length === 16)
54
+ return decoded;
55
+ if (decoded.length === 32 && /^[0-9a-f]{32}$/i.test(decoded.toString('ascii')))
56
+ return Buffer.from(decoded.toString('ascii'), 'hex');
57
+ throw new Error('微信附件 AES 密钥格式无效');
58
+ }
59
+ function trustedWeixinHost(hostname) {
60
+ const host = hostname.toLowerCase();
61
+ return host === 'weixin.qq.com' || host.endsWith('.weixin.qq.com') || host === 'wechat.com' || host.endsWith('.wechat.com');
62
+ }
63
+ function imageType(data) {
64
+ const value = Buffer.from(data);
65
+ if (value.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10])))
66
+ return 'image/png';
67
+ if (value[0] === 0xff && value[1] === 0xd8 && value[2] === 0xff)
68
+ return 'image/jpeg';
69
+ if (value.subarray(0, 6).toString('ascii') === 'GIF87a' || value.subarray(0, 6).toString('ascii') === 'GIF89a')
70
+ return 'image/gif';
71
+ if (value.subarray(0, 4).toString('ascii') === 'RIFF' && value.subarray(8, 12).toString('ascii') === 'WEBP')
72
+ return 'image/webp';
73
+ throw new Error('微信图片格式不受支持');
74
+ }
75
+ function imageExtension(mediaType) {
76
+ return mediaType === 'image/png' ? '.png' : mediaType === 'image/jpeg' ? '.jpg' : mediaType === 'image/gif' ? '.gif' : '.webp';
77
+ }
78
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/channels/weixin/media.ts"],"names":[],"mappings":"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"}
@@ -34,7 +34,24 @@ export interface WeixinRawItem {
34
34
  voice_item?: {
35
35
  text?: string;
36
36
  };
37
- image_item?: unknown;
38
- file_item?: unknown;
37
+ image_item?: {
38
+ filename?: string;
39
+ content_type?: string;
40
+ aeskey?: string;
41
+ media?: WeixinCdnMedia;
42
+ };
43
+ file_item?: {
44
+ filename?: string;
45
+ file_name?: string;
46
+ content_type?: string;
47
+ len?: string;
48
+ media?: WeixinCdnMedia;
49
+ };
50
+ }
51
+ export interface WeixinCdnMedia {
52
+ encrypt_query_param?: string;
53
+ aes_key?: string;
54
+ encrypt_type?: number;
55
+ full_url?: string;
39
56
  }
40
57
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/channels/weixin/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7B,UAAU,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/channels/weixin/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC7B,UAAU,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9B,UAAU,CAAC,EAAE;QACX,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,cAAc,CAAA;KACvB,CAAA;IACD,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,GAAG,CAAC,EAAE,MAAM,CAAA;QACZ,KAAK,CAAC,EAAE,cAAc,CAAA;KACvB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB"}