mslxdff 0.1.160 → 0.1.161
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.
- package/bin/mslxdff.js +4 -4
- package/docs/cli_help_mini.md +135 -0
- package/package.json +1 -1
- package/src/auto.js +254 -254
- package/src/autostart.js +3 -0
- package/src/bench/cline-bench.js +42 -42
- package/src/bench/probe.js +70 -70
- package/src/bench/report.js +162 -162
- package/src/bench/runner.js +77 -77
- package/src/bench/via-probe.js +124 -124
- package/src/bench/via-routes.js +87 -87
- package/src/bench/workbuddy-bench.js +54 -54
- package/src/chat/engine.js +160 -160
- package/src/chat/gateway.js +163 -163
- package/src/chat/orchestrator.js +234 -234
- package/src/chat/prompt.js +70 -70
- package/src/chat/repl.js +88 -88
- package/src/chat/terminal.js +135 -135
- package/src/chat/tools.js +306 -306
- package/src/chat-pipeline/empty-turn.js +119 -0
- package/src/chat-pipeline/index.js +126 -123
- package/src/chat-pipeline/policy.js +76 -76
- package/src/chat-pipeline/serial-trial.js +53 -19
- package/src/cli/commands/daemon.js +4 -4
- package/src/cli/commands/group.js +249 -249
- package/src/cli/commands/model/list-providers.js +1 -1
- package/src/cli/commands/model/picks.js +50 -50
- package/src/cli/commands/provider/bench-via.js +247 -247
- package/src/cli/commands/provider/bench.js +141 -141
- package/src/cli/commands/provider/globalqwenwork-login.js +126 -0
- package/src/cli/commands/provider/index.js +126 -124
- package/src/cli/commands/provider/models.js +142 -139
- package/src/cli/commands/provider/qwenwork-login.js +119 -119
- package/src/cli/commands/sync.js +232 -232
- package/src/cli/commands/system.js +2 -2
- package/src/cli/format.js +6 -0
- package/src/cli/policy.js +2 -2
- package/src/cli/provider-row.js +2 -2
- package/src/cli/status.js +279 -279
- package/src/daemon.js +101 -96
- package/src/logs.js +14 -1
- package/src/model-capabilities/enrich.js +86 -86
- package/src/model-capabilities/index.js +183 -183
- package/src/model-capabilities/parse.js +70 -70
- package/src/model-trace.js +5 -2
- package/src/models.js +225 -225
- package/src/providers/AGENTS.md +46 -0
- package/src/providers/classify.js +1 -1
- package/src/providers/cline/auth.js +228 -228
- package/src/providers/cline/chat.js +307 -307
- package/src/providers/cline.js +2 -2
- package/src/providers/globalqwenwork/account-store.js +141 -0
- package/src/providers/globalqwenwork/constants.js +73 -0
- package/src/providers/globalqwenwork/cosy.js +123 -0
- package/src/providers/globalqwenwork/crypto.js +220 -0
- package/src/providers/globalqwenwork/http.js +22 -0
- package/src/providers/globalqwenwork/index.js +331 -0
- package/src/providers/globalqwenwork/payload.js +145 -0
- package/src/providers/globalqwenwork/rsa.js +56 -0
- package/src/providers/globalqwenwork/sse.js +270 -0
- package/src/providers/globalqwenwork/stream.js +132 -0
- package/src/providers/globalqwenwork/upstream.js +122 -0
- package/src/providers/globalqwenwork.js +1 -0
- package/src/providers/keyring.js +60 -60
- package/src/providers/qoder/chat.js +183 -183
- package/src/providers/qoder/index.js +230 -230
- package/src/providers/qoder/sse.js +103 -103
- package/src/providers/qwenwork/account-store.js +133 -133
- package/src/providers/qwenwork/constants.js +67 -67
- package/src/providers/qwenwork/cosy.js +120 -120
- package/src/providers/qwenwork/crypto.js +218 -218
- package/src/providers/qwenwork/http.js +20 -20
- package/src/providers/qwenwork/index.js +327 -327
- package/src/providers/qwenwork/payload.js +142 -142
- package/src/providers/qwenwork/rsa.js +54 -54
- package/src/providers/qwenwork/sse.js +268 -268
- package/src/providers/qwenwork/stream.js +130 -130
- package/src/providers/qwenwork/upstream.js +120 -120
- package/src/providers/qwenwork.js +1 -1
- package/src/providers/registry.js +74 -66
- package/src/providers/workbuddy/chat.js +248 -248
- package/src/providers/workbuddy/reshape.js +152 -152
- package/src/providers/workbuddy.js +2 -2
- package/src/providers/zcode/sse.js +19 -2
- package/src/reasoning.js +32 -32
- package/src/routes/AGENTS.md +37 -0
- package/src/routes/chat/exhausted-handler.js +23 -8
- package/src/routes/chat/gateway.js +46 -46
- package/src/routes/chat/local-handler.js +3 -1
- package/src/routes/chat/relay-pipeline.js +276 -264
- package/src/routes/chat/via-route-handler.js +146 -146
- package/src/routes/hedge.js +255 -255
- package/src/routes/helpers.js +20 -4
- package/src/routes/models-route.js +167 -167
- package/src/routes/peers.js +273 -273
- package/src/routes/stream-hold.js +138 -0
- package/src/routes/stream-scan.js +192 -0
- package/src/routes/stream.js +386 -393
- package/src/runtime/bootstrap.js +45 -45
- package/src/runtime/lifecycle-forensics.js +116 -0
- package/src/runtime/lifecycle-log.js +23 -0
- package/src/runtime/provider-gate.js +34 -33
- package/src/runtime/providers-setup.js +165 -165
- package/src/server.js +64 -64
- package/src/state/schemas/allowlist.js +92 -92
- package/src/sync-opencode.js +280 -280
- package/src/talk-log.js +226 -0
- package/src/timeline.js +5 -2
- package/src/transport/index.js +244 -244
- package/src/transport/pool.js +56 -56
- package/src/transport/retry.js +24 -24
- package/src/transport/sse.js +93 -93
- package/src/upstream-probe/display.js +52 -52
- package/src/upstream-probe/probe.js +49 -49
- package/src/upstream-probe/rotate.js +110 -110
- package/src/upstream-probe/start.js +45 -45
- package/src/upstream.js +289 -289
|
@@ -1,142 +1,142 @@
|
|
|
1
|
-
// vendor 自 _shared/body.js(OpenAI body → agent_chat 请求体),逐字搬;去掉 desensitize 分支。
|
|
2
|
-
// 实测通过的字段形状(2026-09-29 真号 200):request_id==request_set_id==chat_record_id、
|
|
3
|
-
// stream 恒 true、system 抽到顶层且不出现在 messages、parameters.max_tokens 默认 32000。
|
|
4
|
-
import { uuid } from "./crypto.js";
|
|
5
|
-
import { DEFAULT_MODEL, BUSINESS_PRODUCT, BUSINESS_TYPE, CONTEXT_LENGTH } from "./constants.js";
|
|
6
|
-
|
|
7
|
-
export function mapModel(name) {
|
|
8
|
-
const m = String(name || "").trim();
|
|
9
|
-
switch (m) {
|
|
10
|
-
case "":
|
|
11
|
-
case "auto":
|
|
12
|
-
case "lite":
|
|
13
|
-
case "flash":
|
|
14
|
-
return "flash";
|
|
15
|
-
case "advanced":
|
|
16
|
-
case "pro":
|
|
17
|
-
return "pro";
|
|
18
|
-
case "max":
|
|
19
|
-
case "qwen3.8-max":
|
|
20
|
-
case "qwen3.8-max-preview":
|
|
21
|
-
return "qwen3.8-max-preview";
|
|
22
|
-
default:
|
|
23
|
-
return m;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function contentText(value) {
|
|
28
|
-
if (typeof value === "string") return value;
|
|
29
|
-
if (Array.isArray(value)) {
|
|
30
|
-
let out = "";
|
|
31
|
-
for (const part of value) {
|
|
32
|
-
if (part && typeof part === "object" && typeof part.text === "string") out += part.text;
|
|
33
|
-
}
|
|
34
|
-
return out;
|
|
35
|
-
}
|
|
36
|
-
if (value === null || value === undefined) return "";
|
|
37
|
-
return JSON.stringify(value);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function splitMessages(payload) {
|
|
41
|
-
const raw = Array.isArray(payload.messages) ? payload.messages : [];
|
|
42
|
-
const sysParts = [];
|
|
43
|
-
const messages = [];
|
|
44
|
-
let lastUser = "";
|
|
45
|
-
for (const item of raw) {
|
|
46
|
-
if (!item || typeof item !== "object") continue;
|
|
47
|
-
if (item.role === "system") {
|
|
48
|
-
const text = contentText(item.content);
|
|
49
|
-
if (text) sysParts.push(text);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
messages.push(item);
|
|
53
|
-
}
|
|
54
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
55
|
-
const m = messages[i];
|
|
56
|
-
if (m && m.role === "user") {
|
|
57
|
-
lastUser = contentText(m.content);
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return { system: sysParts.join("\n\n"), messages, lastUser };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function buildBody(payload, modelKey) {
|
|
65
|
-
const key = modelKey || DEFAULT_MODEL;
|
|
66
|
-
const requestID = uuid();
|
|
67
|
-
const { system, messages, lastUser: first } = splitMessages(payload);
|
|
68
|
-
let lastUser = first;
|
|
69
|
-
if (!lastUser) {
|
|
70
|
-
for (const m of messages) {
|
|
71
|
-
if (m && m.role === "user") {
|
|
72
|
-
lastUser = contentText(m.content);
|
|
73
|
-
if (lastUser) break;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (!lastUser) lastUser = "ping";
|
|
78
|
-
|
|
79
|
-
const tokenCap = payload.max_completion_tokens !== undefined ? payload.max_completion_tokens : payload.max_tokens;
|
|
80
|
-
const parameters = {};
|
|
81
|
-
for (const k of ["temperature", "top_p", "presence_penalty", "frequency_penalty"]) {
|
|
82
|
-
if (payload[k] !== undefined && payload[k] !== null) parameters[k] = payload[k];
|
|
83
|
-
}
|
|
84
|
-
if (tokenCap !== undefined && tokenCap !== null) {
|
|
85
|
-
const n = Number(tokenCap);
|
|
86
|
-
if (Number.isFinite(n) && n > 0) parameters.max_tokens = Math.floor(n);
|
|
87
|
-
}
|
|
88
|
-
if (parameters.max_tokens === undefined) parameters.max_tokens = 32000;
|
|
89
|
-
|
|
90
|
-
const tools = !(payload.tool_choice === "none") && Array.isArray(payload.tools) ? payload.tools : [];
|
|
91
|
-
const isReasoning = false;
|
|
92
|
-
|
|
93
|
-
return JSON.stringify({
|
|
94
|
-
request_id: requestID,
|
|
95
|
-
request_set_id: requestID,
|
|
96
|
-
chat_record_id: requestID,
|
|
97
|
-
session_id: uuid(),
|
|
98
|
-
stream: true,
|
|
99
|
-
chat_task: "FREE_INPUT",
|
|
100
|
-
chat_context: {
|
|
101
|
-
text: lastUser,
|
|
102
|
-
features: [],
|
|
103
|
-
extra: {
|
|
104
|
-
context: [],
|
|
105
|
-
modelConfig: { key, is_reasoning: isReasoning },
|
|
106
|
-
originalContent: lastUser,
|
|
107
|
-
},
|
|
108
|
-
chatPrompt: "",
|
|
109
|
-
imageUrls: null,
|
|
110
|
-
},
|
|
111
|
-
is_reply: true,
|
|
112
|
-
is_retry: false,
|
|
113
|
-
source: 1,
|
|
114
|
-
version: "3",
|
|
115
|
-
agent_id: "agent_common",
|
|
116
|
-
task_id: "common",
|
|
117
|
-
session_type: "qoder_work",
|
|
118
|
-
aliyun_user_type: "",
|
|
119
|
-
model_config: {
|
|
120
|
-
key,
|
|
121
|
-
display_name: key,
|
|
122
|
-
model: "",
|
|
123
|
-
format: "openai",
|
|
124
|
-
is_vl: true,
|
|
125
|
-
is_reasoning: isReasoning,
|
|
126
|
-
api_key: "",
|
|
127
|
-
url: "",
|
|
128
|
-
source: "system",
|
|
129
|
-
max_input_tokens: CONTEXT_LENGTH,
|
|
130
|
-
},
|
|
131
|
-
system,
|
|
132
|
-
messages,
|
|
133
|
-
tools,
|
|
134
|
-
parameters,
|
|
135
|
-
business: {
|
|
136
|
-
product: BUSINESS_PRODUCT,
|
|
137
|
-
type: BUSINESS_TYPE,
|
|
138
|
-
version: "1",
|
|
139
|
-
feature_switches: {},
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
}
|
|
1
|
+
// vendor 自 _shared/body.js(OpenAI body → agent_chat 请求体),逐字搬;去掉 desensitize 分支。
|
|
2
|
+
// 实测通过的字段形状(2026-09-29 真号 200):request_id==request_set_id==chat_record_id、
|
|
3
|
+
// stream 恒 true、system 抽到顶层且不出现在 messages、parameters.max_tokens 默认 32000。
|
|
4
|
+
import { uuid } from "./crypto.js";
|
|
5
|
+
import { DEFAULT_MODEL, BUSINESS_PRODUCT, BUSINESS_TYPE, CONTEXT_LENGTH } from "./constants.js";
|
|
6
|
+
|
|
7
|
+
export function mapModel(name) {
|
|
8
|
+
const m = String(name || "").trim();
|
|
9
|
+
switch (m) {
|
|
10
|
+
case "":
|
|
11
|
+
case "auto":
|
|
12
|
+
case "lite":
|
|
13
|
+
case "flash":
|
|
14
|
+
return "flash";
|
|
15
|
+
case "advanced":
|
|
16
|
+
case "pro":
|
|
17
|
+
return "pro";
|
|
18
|
+
case "max":
|
|
19
|
+
case "qwen3.8-max":
|
|
20
|
+
case "qwen3.8-max-preview":
|
|
21
|
+
return "qwen3.8-max-preview";
|
|
22
|
+
default:
|
|
23
|
+
return m;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function contentText(value) {
|
|
28
|
+
if (typeof value === "string") return value;
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
let out = "";
|
|
31
|
+
for (const part of value) {
|
|
32
|
+
if (part && typeof part === "object" && typeof part.text === "string") out += part.text;
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
if (value === null || value === undefined) return "";
|
|
37
|
+
return JSON.stringify(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function splitMessages(payload) {
|
|
41
|
+
const raw = Array.isArray(payload.messages) ? payload.messages : [];
|
|
42
|
+
const sysParts = [];
|
|
43
|
+
const messages = [];
|
|
44
|
+
let lastUser = "";
|
|
45
|
+
for (const item of raw) {
|
|
46
|
+
if (!item || typeof item !== "object") continue;
|
|
47
|
+
if (item.role === "system") {
|
|
48
|
+
const text = contentText(item.content);
|
|
49
|
+
if (text) sysParts.push(text);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
messages.push(item);
|
|
53
|
+
}
|
|
54
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
55
|
+
const m = messages[i];
|
|
56
|
+
if (m && m.role === "user") {
|
|
57
|
+
lastUser = contentText(m.content);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { system: sysParts.join("\n\n"), messages, lastUser };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function buildBody(payload, modelKey) {
|
|
65
|
+
const key = modelKey || DEFAULT_MODEL;
|
|
66
|
+
const requestID = uuid();
|
|
67
|
+
const { system, messages, lastUser: first } = splitMessages(payload);
|
|
68
|
+
let lastUser = first;
|
|
69
|
+
if (!lastUser) {
|
|
70
|
+
for (const m of messages) {
|
|
71
|
+
if (m && m.role === "user") {
|
|
72
|
+
lastUser = contentText(m.content);
|
|
73
|
+
if (lastUser) break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!lastUser) lastUser = "ping";
|
|
78
|
+
|
|
79
|
+
const tokenCap = payload.max_completion_tokens !== undefined ? payload.max_completion_tokens : payload.max_tokens;
|
|
80
|
+
const parameters = {};
|
|
81
|
+
for (const k of ["temperature", "top_p", "presence_penalty", "frequency_penalty"]) {
|
|
82
|
+
if (payload[k] !== undefined && payload[k] !== null) parameters[k] = payload[k];
|
|
83
|
+
}
|
|
84
|
+
if (tokenCap !== undefined && tokenCap !== null) {
|
|
85
|
+
const n = Number(tokenCap);
|
|
86
|
+
if (Number.isFinite(n) && n > 0) parameters.max_tokens = Math.floor(n);
|
|
87
|
+
}
|
|
88
|
+
if (parameters.max_tokens === undefined) parameters.max_tokens = 32000;
|
|
89
|
+
|
|
90
|
+
const tools = !(payload.tool_choice === "none") && Array.isArray(payload.tools) ? payload.tools : [];
|
|
91
|
+
const isReasoning = false;
|
|
92
|
+
|
|
93
|
+
return JSON.stringify({
|
|
94
|
+
request_id: requestID,
|
|
95
|
+
request_set_id: requestID,
|
|
96
|
+
chat_record_id: requestID,
|
|
97
|
+
session_id: uuid(),
|
|
98
|
+
stream: true,
|
|
99
|
+
chat_task: "FREE_INPUT",
|
|
100
|
+
chat_context: {
|
|
101
|
+
text: lastUser,
|
|
102
|
+
features: [],
|
|
103
|
+
extra: {
|
|
104
|
+
context: [],
|
|
105
|
+
modelConfig: { key, is_reasoning: isReasoning },
|
|
106
|
+
originalContent: lastUser,
|
|
107
|
+
},
|
|
108
|
+
chatPrompt: "",
|
|
109
|
+
imageUrls: null,
|
|
110
|
+
},
|
|
111
|
+
is_reply: true,
|
|
112
|
+
is_retry: false,
|
|
113
|
+
source: 1,
|
|
114
|
+
version: "3",
|
|
115
|
+
agent_id: "agent_common",
|
|
116
|
+
task_id: "common",
|
|
117
|
+
session_type: "qoder_work",
|
|
118
|
+
aliyun_user_type: "",
|
|
119
|
+
model_config: {
|
|
120
|
+
key,
|
|
121
|
+
display_name: key,
|
|
122
|
+
model: "",
|
|
123
|
+
format: "openai",
|
|
124
|
+
is_vl: true,
|
|
125
|
+
is_reasoning: isReasoning,
|
|
126
|
+
api_key: "",
|
|
127
|
+
url: "",
|
|
128
|
+
source: "system",
|
|
129
|
+
max_input_tokens: CONTEXT_LENGTH,
|
|
130
|
+
},
|
|
131
|
+
system,
|
|
132
|
+
messages,
|
|
133
|
+
tools,
|
|
134
|
+
parameters,
|
|
135
|
+
business: {
|
|
136
|
+
product: BUSINESS_PRODUCT,
|
|
137
|
+
type: BUSINESS_TYPE,
|
|
138
|
+
version: "1",
|
|
139
|
+
feature_switches: {},
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
// vendor 自 _shared/crypto.js 的 RSA 段(BigInt modPow + PKCS#1 v1.5 type-2),逐字搬。
|
|
2
|
-
// 模数取 constants.js 的 RSA_MODULUS_HEX(与上游一致,勿改)。
|
|
3
|
-
import { b64, utf8 } from "./crypto.js";
|
|
4
|
-
import { RSA_MODULUS_HEX, RSA_EXPONENT } from "./constants.js";
|
|
5
|
-
|
|
6
|
-
export const RSA_N = BigInt("0x" + RSA_MODULUS_HEX);
|
|
7
|
-
export const RSA_E = BigInt(RSA_EXPONENT);
|
|
8
|
-
|
|
9
|
-
function modPow(base, exp, mod) {
|
|
10
|
-
let result = 1n;
|
|
11
|
-
let b = base % mod;
|
|
12
|
-
let e = exp;
|
|
13
|
-
while (e > 0n) {
|
|
14
|
-
if (e & 1n) result = (result * b) % mod;
|
|
15
|
-
b = (b * b) % mod;
|
|
16
|
-
e >>= 1n;
|
|
17
|
-
}
|
|
18
|
-
return result;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function rsaPkcs1Encrypt(data, n = RSA_N, e = RSA_E, k = 128) {
|
|
22
|
-
const psLen = k - data.length - 3;
|
|
23
|
-
if (psLen < 8) throw new Error("rsa: message too long");
|
|
24
|
-
const ps = new Uint8Array(psLen);
|
|
25
|
-
for (;;) {
|
|
26
|
-
crypto.getRandomValues(ps);
|
|
27
|
-
let ok = true;
|
|
28
|
-
for (let i = 0; i < psLen; i++) {
|
|
29
|
-
if (ps[i] === 0) {
|
|
30
|
-
ok = false;
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (ok) break;
|
|
35
|
-
}
|
|
36
|
-
const em = new Uint8Array(k);
|
|
37
|
-
em[0] = 0x00;
|
|
38
|
-
em[1] = 0x02;
|
|
39
|
-
em.set(ps, 2);
|
|
40
|
-
em[2 + psLen] = 0x00;
|
|
41
|
-
em.set(data, 3 + psLen);
|
|
42
|
-
let m = 0n;
|
|
43
|
-
for (let i = 0; i < k; i++) m = (m << 8n) | BigInt(em[i]);
|
|
44
|
-
const c = modPow(m, e, n);
|
|
45
|
-
const out = new Uint8Array(k);
|
|
46
|
-
let v = c;
|
|
47
|
-
for (let i = k - 1; i >= 0; i--) {
|
|
48
|
-
out[i] = Number(v & 0xffn);
|
|
49
|
-
v >>= 8n;
|
|
50
|
-
}
|
|
51
|
-
return b64(out);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export { b64, utf8 };
|
|
1
|
+
// vendor 自 _shared/crypto.js 的 RSA 段(BigInt modPow + PKCS#1 v1.5 type-2),逐字搬。
|
|
2
|
+
// 模数取 constants.js 的 RSA_MODULUS_HEX(与上游一致,勿改)。
|
|
3
|
+
import { b64, utf8 } from "./crypto.js";
|
|
4
|
+
import { RSA_MODULUS_HEX, RSA_EXPONENT } from "./constants.js";
|
|
5
|
+
|
|
6
|
+
export const RSA_N = BigInt("0x" + RSA_MODULUS_HEX);
|
|
7
|
+
export const RSA_E = BigInt(RSA_EXPONENT);
|
|
8
|
+
|
|
9
|
+
function modPow(base, exp, mod) {
|
|
10
|
+
let result = 1n;
|
|
11
|
+
let b = base % mod;
|
|
12
|
+
let e = exp;
|
|
13
|
+
while (e > 0n) {
|
|
14
|
+
if (e & 1n) result = (result * b) % mod;
|
|
15
|
+
b = (b * b) % mod;
|
|
16
|
+
e >>= 1n;
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function rsaPkcs1Encrypt(data, n = RSA_N, e = RSA_E, k = 128) {
|
|
22
|
+
const psLen = k - data.length - 3;
|
|
23
|
+
if (psLen < 8) throw new Error("rsa: message too long");
|
|
24
|
+
const ps = new Uint8Array(psLen);
|
|
25
|
+
for (;;) {
|
|
26
|
+
crypto.getRandomValues(ps);
|
|
27
|
+
let ok = true;
|
|
28
|
+
for (let i = 0; i < psLen; i++) {
|
|
29
|
+
if (ps[i] === 0) {
|
|
30
|
+
ok = false;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (ok) break;
|
|
35
|
+
}
|
|
36
|
+
const em = new Uint8Array(k);
|
|
37
|
+
em[0] = 0x00;
|
|
38
|
+
em[1] = 0x02;
|
|
39
|
+
em.set(ps, 2);
|
|
40
|
+
em[2 + psLen] = 0x00;
|
|
41
|
+
em.set(data, 3 + psLen);
|
|
42
|
+
let m = 0n;
|
|
43
|
+
for (let i = 0; i < k; i++) m = (m << 8n) | BigInt(em[i]);
|
|
44
|
+
const c = modPow(m, e, n);
|
|
45
|
+
const out = new Uint8Array(k);
|
|
46
|
+
let v = c;
|
|
47
|
+
for (let i = k - 1; i >= 0; i--) {
|
|
48
|
+
out[i] = Number(v & 0xffn);
|
|
49
|
+
v >>= 8n;
|
|
50
|
+
}
|
|
51
|
+
return b64(out);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export { b64, utf8 };
|