@coffeerunhobby/mcp-ha-connect 2.4.8 → 2.5.0

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.
Files changed (45) hide show
  1. package/.env.example +16 -1
  2. package/README.md +24 -2
  3. package/dist/config.d.ts +5 -0
  4. package/dist/config.js +18 -0
  5. package/dist/config.js.map +1 -1
  6. package/dist/index.js +3 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/net/adapters/omada.d.ts +7 -0
  9. package/dist/net/adapters/omada.js +22 -2
  10. package/dist/net/adapters/omada.js.map +1 -1
  11. package/dist/net/adapters/ruijie.d.ts +59 -0
  12. package/dist/net/adapters/ruijie.js +363 -0
  13. package/dist/net/adapters/ruijie.js.map +1 -0
  14. package/dist/net/model.d.ts +1 -1
  15. package/dist/ruijieClient/crypto.d.ts +20 -0
  16. package/dist/ruijieClient/crypto.js +57 -0
  17. package/dist/ruijieClient/crypto.js.map +1 -0
  18. package/dist/ruijieClient/index.d.ts +62 -0
  19. package/dist/ruijieClient/index.js +197 -0
  20. package/dist/ruijieClient/index.js.map +1 -0
  21. package/dist/server/common.d.ts +2 -0
  22. package/dist/server/common.js +2 -1
  23. package/dist/server/common.js.map +1 -1
  24. package/dist/server/http.d.ts +2 -0
  25. package/dist/server/http.js +2 -2
  26. package/dist/server/http.js.map +1 -1
  27. package/dist/server/stdio.d.ts +2 -0
  28. package/dist/server/stdio.js.map +1 -1
  29. package/dist/server/stream.d.ts +2 -0
  30. package/dist/server/stream.js +2 -1
  31. package/dist/server/stream.js.map +1 -1
  32. package/dist/tools/index.d.ts +3 -0
  33. package/dist/tools/index.js +9 -3
  34. package/dist/tools/index.js.map +1 -1
  35. package/dist/tools/net/index.d.ts +8 -2
  36. package/dist/tools/net/index.js +58 -2
  37. package/dist/tools/net/index.js.map +1 -1
  38. package/dist/upstreams.d.ts +7 -2
  39. package/dist/upstreams.js +54 -2
  40. package/dist/upstreams.js.map +1 -1
  41. package/dist/utils/redact.js +1 -1
  42. package/dist/utils/redact.js.map +1 -1
  43. package/dist/version.d.ts +1 -1
  44. package/dist/version.js +1 -1
  45. package/package.json +3 -3
@@ -0,0 +1,363 @@
1
+ /**
2
+ * Ruijie / Reyee adapter for the vendor-neutral network model (src/net/model.ts), through the
3
+ * router's local eWeb API (src/ruijieClient). Mapped on a RG-EG105G-V3, ReyeeOS 2.324
4
+ * (2026-10-24). 2.5.0 READS ONLY: every change is refused (UNSUPPORTED) until the write
5
+ * phases (reservations and rules, then networks) are built and live-tested.
6
+ *
7
+ * What is read, and how it maps:
8
+ * - networks: devConfig.get network, `lan[]` (one entry per LAN interface: address, netmask,
9
+ * VLAN id, DHCP). The default LAN carries Ruijie's internal VLAN 233, untagged on the LAN
10
+ * ports; the id of a network is its interface name, "vlan<id>", which rules refer to.
11
+ * - clients: the devices the router sees on its LAN right now, from its ARP table (devSta.get
12
+ * arp, interfaces "br-lan*", resolved MACs only), named by their address lease (devSta.get
13
+ * dhcp_lease) when they have one. A lease alone is no online device (a switched-off laptop
14
+ * keeps it until it expires); WAN-side ARP entries are the upstream network.
15
+ * - reservations: devConfig.get dhcp_static.
16
+ * - ports: devSta.get port_status. The router doesn't say which device is on which port, so
17
+ * `seen` stays empty; the WAN port is the uplink and protected.
18
+ * - rules: devConfig.get access_ctrl (evaluated in list order). Anything the model can't say
19
+ * faithfully (a source "anywhere", source ports, IPv6, user groups, schedules, a rule that
20
+ * matches only some connection states) is listed as `foreign` with the reason.
21
+ * No Wi-Fi radio on this model, no switch port profiles, no mDNS repeater; groups (Ruijie's
22
+ * user groups are address ranges and users, not the model's address groups) come later.
23
+ */
24
+ import { formatMac, normalizeMac } from '../../omadaClient/client.js';
25
+ import { inSubnet, ipToNumber, parseCidr, subnetsOverlap } from '../../utils/ipv4.js';
26
+ import { NetError, } from '../model.js';
27
+ /** Ruijie's name for "all the time" in a rule's time setting (the default time group). */
28
+ const ALL_TIME = new Set(['所有时段', 'everytime', 'All Time', '']);
29
+ const READ_ONLY = 'The Ruijie adapter reads only in this version; changes through it (reservations and rules first, then networks) come in a later version.';
30
+ const text = (value) => (typeof value === 'string' ? value : value === undefined || value === null ? '' : String(value));
31
+ const list = (value) => (Array.isArray(value) ? value.filter((v) => v && typeof v === 'object') : []);
32
+ /** "255.255.255.0" -> 24; undefined for a mask that isn't contiguous ones. */
33
+ export function maskToPrefix(mask) {
34
+ let n;
35
+ try {
36
+ n = ipToNumber(mask);
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ let prefix = 0;
42
+ for (let bit = 31; bit >= 0; bit--) {
43
+ if (Math.floor(n / 2 ** bit) % 2 === 1)
44
+ prefix++;
45
+ else
46
+ break;
47
+ }
48
+ return n === (prefix === 0 ? 0 : (2 ** 32 - 2 ** (32 - prefix))) ? prefix : undefined;
49
+ }
50
+ const numberToIp = (n) => [24, 16, 8, 0].map((s) => Math.floor(n / 2 ** s) % 256).join('.');
51
+ /** One `lan[]` entry as a model network (undefined when its address or mask can't be read). */
52
+ export function toNetwork(raw, index, routerHost) {
53
+ const ip = text(raw.ipaddr);
54
+ const prefix = maskToPrefix(text(raw.netmask));
55
+ try {
56
+ ipToNumber(ip);
57
+ }
58
+ catch {
59
+ return undefined;
60
+ }
61
+ if (prefix === undefined)
62
+ return undefined;
63
+ const vlan = Number(text(raw.vlanid));
64
+ const gateway = `${ip}/${prefix}`;
65
+ const start = text(raw.ipstart);
66
+ const limit = Number(text(raw.limit));
67
+ let range;
68
+ try {
69
+ if (start && Number.isInteger(limit) && limit > 0)
70
+ range = { from: start, to: numberToIp(ipToNumber(start) + limit - 1) };
71
+ }
72
+ catch {
73
+ range = undefined;
74
+ }
75
+ const lease = Number(text(raw.leasetime));
76
+ let routerAddress;
77
+ try {
78
+ routerAddress = ipToNumber(routerHost);
79
+ }
80
+ catch {
81
+ routerAddress = undefined;
82
+ }
83
+ return {
84
+ id: `vlan${text(raw.vlanid)}`,
85
+ name: text(raw.desc) || text(raw.name) || (index === 0 ? 'LAN' : `VLAN ${text(raw.vlanid)}`),
86
+ purpose: 'normal',
87
+ vlan: Number.isInteger(vlan) ? vlan : 0,
88
+ gateway,
89
+ dhcp: {
90
+ enabled: text(raw.ignore) !== '1',
91
+ ...(range ? { range } : {}),
92
+ ...(Number.isInteger(lease) && lease > 0 ? { leaseMinutes: lease } : {}),
93
+ },
94
+ ipv6: false,
95
+ isolated: false,
96
+ // The first LAN is the router's own (its management address), and so is any LAN the
97
+ // router is reached through; neither may be cut off.
98
+ protected: index === 0 || (routerAddress !== undefined && inSubnet(routerAddress, gateway)),
99
+ };
100
+ }
101
+ const networkOf = (ip, networks) => {
102
+ let n;
103
+ try {
104
+ n = ipToNumber(ip);
105
+ }
106
+ catch {
107
+ return undefined;
108
+ }
109
+ return networks.find((net) => net.gateway && inSubnet(n, net.gateway));
110
+ };
111
+ const macOrUndefined = (value) => {
112
+ try {
113
+ return formatMac(text(value));
114
+ }
115
+ catch {
116
+ return undefined;
117
+ }
118
+ };
119
+ /** The devices the router sees on its LAN (ARP), once each, named by their lease (same MAC and address) when they have one. */
120
+ export function toClients(leases, arp, networks) {
121
+ const names = new Map();
122
+ for (const l of leases) {
123
+ const mac = macOrUndefined(l.mac);
124
+ const name = text(l.hostname);
125
+ const key = `${mac}|${text(l.ip)}`;
126
+ if (mac && name && name !== '*' && !names.has(key))
127
+ names.set(key, name);
128
+ }
129
+ const clients = [];
130
+ const seen = new Set();
131
+ for (const a of arp) {
132
+ if (!text(a.intf).startsWith('br-lan'))
133
+ continue;
134
+ const mac = macOrUndefined(a.hardware);
135
+ // 00:00:00:00:00:00 = an address nobody answered for.
136
+ if (!mac || mac === '00-00-00-00-00-00' || seen.has(mac))
137
+ continue;
138
+ seen.add(mac);
139
+ const ip = text(a.address);
140
+ const network = networkOf(ip, networks);
141
+ const name = names.get(`${mac}|${ip}`);
142
+ clients.push({ mac, ...(name ? { name } : {}), ...(ip ? { ip } : {}), ...(network ? { network: { id: network.id } } : {}), online: true });
143
+ }
144
+ return clients;
145
+ }
146
+ export function toReservations(entries, networks) {
147
+ const out = [];
148
+ for (const e of entries) {
149
+ const mac = macOrUndefined(e.macaddr);
150
+ const ip = text(e.ipaddr);
151
+ if (!mac || !ip)
152
+ continue;
153
+ const network = networkOf(ip, networks);
154
+ out.push({ mac, ip, network: network ? { id: network.id } : { name: 'outside the router\'s networks' } });
155
+ }
156
+ return out;
157
+ }
158
+ export function toPorts(entries, routerMac) {
159
+ return entries.map((p) => {
160
+ const wan = text(p.name).toUpperCase() === 'WAN';
161
+ return {
162
+ device: { mac: routerMac },
163
+ port: Number(text(p.portId)),
164
+ ...(text(p.panel_name) ? { name: text(p.panel_name) } : {}),
165
+ seen: [],
166
+ uplink: wan,
167
+ ...(wan ? { protected: "it is the router's internet (WAN) port" } : {}),
168
+ };
169
+ });
170
+ }
171
+ /**
172
+ * A rule side (src or dest, with its addresses) as model selectors, or the reason it can't be one.
173
+ * The model's address selector carries no interface, so addresses are kept only where they imply
174
+ * the interface the rule names: inside the LANs (lan) or that VLAN (vlanX), outside every LAN
175
+ * (wan), or any interface (all). Anything else would overstate or misplace what the rule matches.
176
+ */
177
+ function side(where, addresses, networks, isSource) {
178
+ if (addresses) {
179
+ const parts = addresses.split(',').map((a) => a.trim()).filter(Boolean);
180
+ if (parts.some((a) => a.includes('-')))
181
+ return `an address range (${addresses})`;
182
+ let ranges;
183
+ try {
184
+ ranges = parts.map((a) => parseCidr(a));
185
+ }
186
+ catch {
187
+ return `an address it can't read (${addresses})`;
188
+ }
189
+ const inside = (nets) => ranges.every((r) => nets.some((n) => n.gateway && r.network >= parseCidr(n.gateway).network && r.broadcast <= parseCidr(n.gateway).broadcast));
190
+ const lans = networks.filter((n) => n.gateway);
191
+ const implied = where === 'all' ||
192
+ (where === 'lan' && inside(lans)) ||
193
+ (where === 'wan' && parts.every((a) => !lans.some((n) => subnetsOverlap(a, n.gateway)))) ||
194
+ (where.startsWith('vlan') && inside(networks.filter((n) => n.id === where)));
195
+ if (!implied)
196
+ return `addresses (${addresses}) limited to the interface '${where}'`;
197
+ return [{ addresses: parts }];
198
+ }
199
+ if (where === 'wan')
200
+ return [{ internet: true }];
201
+ if (where === 'lan')
202
+ return networks.map((n) => ({ network: { id: n.id } }));
203
+ if (where === 'all')
204
+ return isSource ? 'traffic from anywhere, the internet included' : 'traffic to anywhere';
205
+ const network = networks.find((n) => n.id === where);
206
+ if (network)
207
+ return [{ network: { id: network.id } }];
208
+ return `the interface '${where}'`;
209
+ }
210
+ export function toRule(raw, index, networks) {
211
+ const reasons = [];
212
+ const target = text(raw.target).toUpperCase();
213
+ const action = target === 'ACCEPT' ? 'allow' : 'block';
214
+ if (!['ACCEPT', 'DROP', 'REJECT'].includes(target))
215
+ reasons.push(`an unknown action '${text(raw.target)}'`);
216
+ let from = [];
217
+ if (text(raw.by) === 'mac') {
218
+ const mac = macOrUndefined(raw.mac);
219
+ if (mac)
220
+ from = [{ device: mac }];
221
+ else
222
+ reasons.push('a device match without a readable MAC');
223
+ // The model's device match has no interface: only "any LAN" or "anywhere" say the same.
224
+ const where = text(raw.src);
225
+ if (where && where !== 'lan' && where !== 'all')
226
+ reasons.push(`a device match limited to the interface '${where}'`);
227
+ }
228
+ else {
229
+ const s = side(text(raw.src), text(raw.srcIP), networks, true);
230
+ if (typeof s === 'string')
231
+ reasons.push(s);
232
+ else
233
+ from = s;
234
+ }
235
+ let to = [];
236
+ const d = side(text(raw.dest), text(raw.destIP), networks, false);
237
+ if (typeof d === 'string')
238
+ reasons.push(d);
239
+ else
240
+ to = d;
241
+ const proto = text(raw.proto).toLowerCase();
242
+ let protocol = 'any';
243
+ if (proto === 'tcp' || proto === 'udp' || proto === 'icmp')
244
+ protocol = proto;
245
+ else if (proto === 'tcpudp' && !text(raw.destPort))
246
+ reasons.push('TCP and UDP together without ports');
247
+ else if (proto !== 'all' && proto !== '' && proto !== 'tcpudp')
248
+ reasons.push(`the protocol '${text(raw.proto)}'`);
249
+ if (text(raw.destPort)) {
250
+ // The model's ports mean TCP and UDP together; a rule for one of them only would be overstated.
251
+ if (proto === 'tcpudp')
252
+ protocol = { tcpUdpPorts: text(raw.destPort) };
253
+ else if (proto === 'tcp' || proto === 'udp')
254
+ reasons.push(`destination ports for ${proto} only (the model's ports mean TCP and UDP)`);
255
+ else
256
+ reasons.push('destination ports without TCP or UDP');
257
+ }
258
+ if (text(raw.srcPort))
259
+ reasons.push('source ports');
260
+ if (text(raw.netProto) && text(raw.netProto) !== 'ipv4')
261
+ reasons.push(`an ${text(raw.netProto)} rule`);
262
+ if (list(raw.user).length || list(raw.user_group_list).length || (Array.isArray(raw.userGroupList) && raw.userGroupList.length))
263
+ reasons.push('user groups');
264
+ if (!ALL_TIME.has(text(raw.tmngtName)))
265
+ reasons.push(`a schedule ('${text(raw.tmngtName)}')`);
266
+ // "0" = every connection state, replies included (the rule is not stateful).
267
+ const state = text(raw.state) || '0';
268
+ if (state !== '0')
269
+ reasons.push(`only some connection states (${state})`);
270
+ return {
271
+ id: text(raw.uuid) || text(raw.ruleid) || `rule-${index + 1}`,
272
+ name: text(raw.ruleName) || `rule ${index + 1}`,
273
+ action,
274
+ from,
275
+ to,
276
+ protocol,
277
+ replies: 'match',
278
+ schedule: { kind: 'always' },
279
+ enabled: text(raw.enable) === '1',
280
+ position: index + 1,
281
+ ...(reasons.length ? { foreign: { reason: `Read-only here: it uses ${reasons.join(', ')}.` } } : {}),
282
+ };
283
+ }
284
+ export class RuijieNetworkController {
285
+ client;
286
+ vendor = 'ruijie';
287
+ id;
288
+ constructor(client, options = {}) {
289
+ this.client = client;
290
+ this.id = options.id ?? `ruijie:${client.host}`;
291
+ }
292
+ async capabilities() {
293
+ return {
294
+ vendor: 'ruijie',
295
+ networks: { create: 'unsupported', isolation: 'unsupported', ipv6: 'unsupported', guestPurpose: 'unsupported' },
296
+ wifi: { create: 'unsupported', bands: [], security: [], pmf: 'unsupported', fastRoaming: 'unsupported', bandSteering: 'unsupported' },
297
+ ports: { profiles: 'unsupported', assign: 'unsupported' },
298
+ rules: { between: 'unsupported', toInternet: 'unsupported', deviceMatch: 'unsupported', wifiMatch: 'unsupported', stateful: 'unsupported', schedule: 'unsupported' },
299
+ groups: { address: 'unsupported', mac: 'unsupported' },
300
+ reservations: 'unsupported',
301
+ mdnsRepeater: 'unsupported',
302
+ };
303
+ }
304
+ async protectedResources() {
305
+ const networks = (await this.listNetworks()).filter((n) => n.protected);
306
+ const ports = (await this.listPorts()).filter((p) => p.protected);
307
+ return { networks: networks.map((n) => ({ id: n.id })), ports: ports.map((p) => ({ device: p.device, port: p.port })), devices: [] };
308
+ }
309
+ async listNetworks() {
310
+ const config = await this.client.config('network');
311
+ return list(config.lan)
312
+ .map((raw, i) => toNetwork(raw, i, this.client.host))
313
+ .filter((n) => n !== undefined);
314
+ }
315
+ async listWifi() {
316
+ return [];
317
+ }
318
+ async listPortProfiles() {
319
+ return [];
320
+ }
321
+ async listPorts(device) {
322
+ const info = await this.client.status('sysinfo');
323
+ const routerMac = macOrUndefined(info.sys_mac) ?? 'unknown';
324
+ if (device) {
325
+ const wanted = 'mac' in device ? device.mac : 'id' in device ? device.id : device.name;
326
+ const names = [routerMac, text(info.model), text(info.product_class), 'router'].map((v) => v.toLowerCase());
327
+ if (normalizeMac(wanted) !== normalizeMac(routerMac) && !names.includes(wanted.trim().toLowerCase())) {
328
+ throw new NetError('NOT_FOUND', `This Ruijie router (${text(info.model) || 'router'}, ${routerMac}) is the only device here; '${wanted}' is not it`);
329
+ }
330
+ }
331
+ const status = await this.client.status('port_status');
332
+ return toPorts(list(status.List), routerMac);
333
+ }
334
+ async listRules() {
335
+ const networks = await this.listNetworks();
336
+ const acl = await this.client.config('access_ctrl');
337
+ return list(acl.list).map((raw, i) => toRule(raw, i, networks));
338
+ }
339
+ async listGroups() {
340
+ return [];
341
+ }
342
+ async listReservations() {
343
+ const networks = await this.listNetworks();
344
+ const config = await this.client.config('dhcp_static');
345
+ return toReservations(list(config.dhcp_static), networks);
346
+ }
347
+ async listClients() {
348
+ const networks = await this.listNetworks();
349
+ const leases = await this.client.status('dhcp_lease');
350
+ const arp = await this.client.status('arp');
351
+ return toClients(list(leases.List), list(arp.arpList), networks);
352
+ }
353
+ async getMdnsRepeater() {
354
+ return { enabled: false, networks: [], foreign: { reason: 'This Ruijie router has no mDNS repeater the tools manage.' } };
355
+ }
356
+ async plan(change) {
357
+ throw new NetError('UNSUPPORTED', READ_ONLY, { capability: change.kind });
358
+ }
359
+ async apply() {
360
+ throw new NetError('UNSUPPORTED', READ_ONLY);
361
+ }
362
+ }
363
+ //# sourceMappingURL=ruijie.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ruijie.js","sourceRoot":"","sources":["../../../src/net/adapters/ruijie.ts"],"names":[],"mappings":"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"}
@@ -26,7 +26,7 @@ export type Ipv4 = string;
26
26
  export type Clock = string;
27
27
  export declare const DAYS: readonly ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
28
28
  export type Day = (typeof DAYS)[number];
29
- export type Vendor = 'omada' | 'unifi' | 'mikrotik';
29
+ export type Vendor = 'omada' | 'unifi' | 'mikrotik' | 'ruijie';
30
30
  export interface TimeWindow {
31
31
  days: Day[];
32
32
  from: Clock;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The small amount of crypto Ruijie's eWeb login and API calls need, done the way the
3
+ * router's own web page does it (verified against a RG-EG105G-V3, ReyeeOS 2.324, 2026-10-24):
4
+ *
5
+ * - The page encrypts the login password with GibberishAES: OpenSSL's "Salted__" format,
6
+ * AES-256-CBC with key and IV from EVP_BytesToKey (MD5). Its key is itself shipped in the
7
+ * page, encrypted with the passphrase "eweb". This hides the password from a casual look at
8
+ * the traffic; it is not a secret, so the transport should still be HTTPS.
9
+ * - Every API request carries two checksum headers, MD5 of a fixed string plus the body's
10
+ * byte length (Content-Accept) and plus the body itself (Contents-Accept).
11
+ */
12
+ /** GibberishAES / `openssl enc -aes-256-cbc -md md5` encryption, base64 with the "Salted__" header. */
13
+ export declare function gibberishEncrypt(text: string, passphrase: string, salt?: Buffer): string;
14
+ export declare function gibberishDecrypt(blob: string, passphrase: string): string;
15
+ /** The key the login page encrypts the password with. */
16
+ export declare function pageKey(): string;
17
+ /** The password as the login page sends it. */
18
+ export declare function encryptPassword(password: string): string;
19
+ /** The two checksum headers the web page sends with every API request. */
20
+ export declare function checksumHeaders(body: string): Record<string, string>;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The small amount of crypto Ruijie's eWeb login and API calls need, done the way the
3
+ * router's own web page does it (verified against a RG-EG105G-V3, ReyeeOS 2.324, 2026-10-24):
4
+ *
5
+ * - The page encrypts the login password with GibberishAES: OpenSSL's "Salted__" format,
6
+ * AES-256-CBC with key and IV from EVP_BytesToKey (MD5). Its key is itself shipped in the
7
+ * page, encrypted with the passphrase "eweb". This hides the password from a casual look at
8
+ * the traffic; it is not a secret, so the transport should still be HTTPS.
9
+ * - Every API request carries two checksum headers, MD5 of a fixed string plus the body's
10
+ * byte length (Content-Accept) and plus the body itself (Contents-Accept).
11
+ */
12
+ import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'node:crypto';
13
+ /** The login-page key blob (GibberishAES of the key, passphrase "eweb"), as the page ships it. */
14
+ const PAGE_KEY_BLOB = 'U2FsdGVkX19ecPYL/ZAlcSG29wb6ivqD9YjEM30k1h8=';
15
+ const PAGE_KEY_PASSPHRASE = 'eweb';
16
+ const CHECKSUM_PREFIX = 'Web@Rj$2020!';
17
+ const SALTED = Buffer.from('Salted__');
18
+ function evpBytesToKey(passphrase, salt) {
19
+ let previous = Buffer.alloc(0);
20
+ let derived = Buffer.alloc(0);
21
+ while (derived.length < 48) {
22
+ previous = createHash('md5').update(Buffer.concat([previous, passphrase, salt])).digest();
23
+ derived = Buffer.concat([derived, previous]);
24
+ }
25
+ return { key: derived.subarray(0, 32), iv: derived.subarray(32, 48) };
26
+ }
27
+ /** GibberishAES / `openssl enc -aes-256-cbc -md md5` encryption, base64 with the "Salted__" header. */
28
+ export function gibberishEncrypt(text, passphrase, salt = randomBytes(8)) {
29
+ const { key, iv } = evpBytesToKey(Buffer.from(passphrase), salt);
30
+ const cipher = createCipheriv('aes-256-cbc', key, iv);
31
+ return Buffer.concat([SALTED, salt, cipher.update(text, 'utf8'), cipher.final()]).toString('base64');
32
+ }
33
+ export function gibberishDecrypt(blob, passphrase) {
34
+ const raw = Buffer.from(blob, 'base64');
35
+ if (raw.length < 32 || !raw.subarray(0, 8).equals(SALTED))
36
+ throw new Error('Not an OpenSSL salted AES blob');
37
+ const { key, iv } = evpBytesToKey(Buffer.from(passphrase), raw.subarray(8, 16));
38
+ const decipher = createDecipheriv('aes-256-cbc', key, iv);
39
+ return Buffer.concat([decipher.update(raw.subarray(16)), decipher.final()]).toString('utf8');
40
+ }
41
+ /** The key the login page encrypts the password with. */
42
+ export function pageKey() {
43
+ return gibberishDecrypt(PAGE_KEY_BLOB, PAGE_KEY_PASSPHRASE);
44
+ }
45
+ /** The password as the login page sends it. */
46
+ export function encryptPassword(password) {
47
+ return gibberishEncrypt(password, pageKey());
48
+ }
49
+ /** The two checksum headers the web page sends with every API request. */
50
+ export function checksumHeaders(body) {
51
+ const md5 = (value) => createHash('md5').update(value).digest('hex');
52
+ return {
53
+ 'Content-Accept': md5(CHECKSUM_PREFIX + Buffer.byteLength(body, 'utf8')),
54
+ 'Contents-Accept': md5(CHECKSUM_PREFIX + body),
55
+ };
56
+ }
57
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../src/ruijieClient/crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Client for a Ruijie / Reyee router's local eWeb API (the JSON API its own web page uses),
3
+ * mapped on a RG-EG105G-V3 with ReyeeOS 2.324 (2026-10-24):
4
+ *
5
+ * - Login: POST /cgi-bin/luci/api/auth {method: "login", params: {username: "admin",
6
+ * password: <GibberishAES>, time, encry: true}} answers {data: {sid, token, sn}} and sets a
7
+ * session cookie. The username is always "admin". The session lasts about an hour.
8
+ * - Calls: POST /cgi-bin/luci/api/cmd?auth=<sid> {method, params: {module, data}} with the
9
+ * cookie and the page's checksum headers. Methods: devConfig.get (settings), devSta.get
10
+ * (live state), and devConfig.add / update / del / set for changes.
11
+ * - An expired or unknown session answers {code: 2, msg: "403 Forbidden, auth is not passed"}:
12
+ * the client logs in again once and repeats the call once.
13
+ *
14
+ * Wrong passwords lock the router's login (five in a row lock it for a minute), so a refused
15
+ * login is never retried: the client switches itself off with a clear message until the
16
+ * setting is fixed and the server restarted. Only a network failure lets the next call try
17
+ * again. The session id is never logged or put in an error message.
18
+ */
19
+ export interface RuijieClientConfig {
20
+ /** e.g. https://192.168.110.1 (the router's management address). */
21
+ baseUrl: string;
22
+ /** The router's admin password (RUIJIE_PASSWORD). */
23
+ password: string;
24
+ /** false: accept the router's self-signed certificate (this client only). */
25
+ strictSsl?: boolean;
26
+ /** Milliseconds per request (default 15000). */
27
+ timeout?: number;
28
+ }
29
+ /** A Ruijie call that failed: `refused` = the login was refused, `unknownModule` = the router has no such module. */
30
+ export declare class RuijieError extends Error {
31
+ readonly kind: 'refused' | 'unreachable' | 'router' | 'unknownModule' | 'disabled';
32
+ constructor(message: string, kind?: 'refused' | 'unreachable' | 'router' | 'unknownModule' | 'disabled');
33
+ }
34
+ export declare class RuijieClient {
35
+ /** Host of the router's base URL (the router's own address, kept out of harm's way). */
36
+ readonly host: string;
37
+ private readonly baseUrl;
38
+ private readonly password;
39
+ private readonly timeout;
40
+ private readonly dispatcher?;
41
+ private session?;
42
+ private loggingIn?;
43
+ private disabledMessage?;
44
+ constructor(config: RuijieClientConfig);
45
+ /** Settings: devConfig.get. */
46
+ config<T = Record<string, unknown>>(module: string, data?: unknown): Promise<T>;
47
+ /** Live state: devSta.get. */
48
+ status<T = Record<string, unknown>>(module: string, data?: unknown): Promise<T>;
49
+ /** The router's identity (model and firmware); logs in when needed. Used as the reachability check. */
50
+ check(): Promise<{
51
+ model: string;
52
+ version: string;
53
+ }>;
54
+ /** Turns every call into a refusal with this message (e.g. after a refused login). */
55
+ disable(message: string): void;
56
+ get disabled(): string | undefined;
57
+ call<T>(method: string, module: string, data?: unknown): Promise<T>;
58
+ private ensureSession;
59
+ private login;
60
+ private post;
61
+ private postWithCookies;
62
+ }