openlearn-next 0.4.2 → 0.7.3
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/README.md +26 -21
- package/cli-data.mjs +535 -40
- package/cli-doctor.mjs +456 -17
- package/cli.mjs +214 -12
- package/dist/assets/AcademicYearFilter-DUUGpDKt.js +1 -0
- package/dist/assets/ActivityWorkspaceWidget-5PzyxF6a.js +1 -0
- package/dist/assets/AdminDirectoryView-BCtmQTEK.js +5 -0
- package/dist/assets/AssessmentCenter-B43ojHG-.js +1 -0
- package/dist/assets/BatchPickerModal-CbmjInp7.js +1 -0
- package/dist/assets/ClassesView-DEnMaDOt.js +32 -0
- package/dist/assets/ClassroomCountdownWidget-CHq4983w.js +2 -0
- package/dist/assets/CloudDriveModal-D2t3Uyzr.js +1 -0
- package/dist/assets/ComputerLabView-YtnoT5Rb.js +1 -0
- package/dist/assets/CourseManagement-DOXyJ_j-.js +1 -0
- package/dist/assets/CourseWizardModal-Dbi6Caw2.js +3 -0
- package/dist/assets/CoursewareHubPanel-CyxDIJAF.js +1 -0
- package/dist/assets/Dashboard-2rLu_ZBy.js +8 -0
- package/dist/assets/ExportWeightModal-BrmAh6VX.js +1 -0
- package/dist/assets/GLTFLoader-CZJbo_y1.js +1 -0
- package/dist/assets/HelpTour-D_q1z_MI.js +1 -0
- package/dist/assets/HelpView-CVBrKDrd.js +204 -0
- package/dist/assets/ImportLessonsModal-PhHtX31R.js +1 -0
- package/dist/assets/ImportModal-DqjqNeH4.js +2 -0
- package/dist/assets/InteractiveCoursewareViewer-Vi6lLz7a.js +1 -0
- package/dist/assets/InteractiveWhiteboard-lTzeayX5.js +65 -0
- package/dist/assets/LazyCourseware-KIt0rGtW.js +2 -0
- package/dist/assets/LazyWhiteboard-CCN3pYcW.js +2 -0
- package/dist/assets/LessonEditorView-D_GVhHuM.js +1 -0
- package/dist/assets/LiveClassroomView-BRsZ6QEq.js +61 -0
- package/dist/assets/NotificationDetailModal-tY5rxYCN.js +1 -0
- package/dist/assets/OrbitControls-CQjN_uwS.js +1 -0
- package/dist/assets/PluginView-CedpAW6d.js +77 -0
- package/dist/assets/ProcessLogsModal-Cfr-T9Gd.js +1 -0
- package/dist/assets/QuizGeneratorModal-bUA002kP.js +1 -0
- package/dist/assets/StudentAssignmentView-BhAz6Hfk.js +1 -0
- package/dist/assets/StudentLessonView-DC1yX4kG.js +1 -0
- package/dist/assets/StudentView-PHKxIV9T.js +2 -0
- package/dist/assets/SystemResourceLibraryModal-DgXYe6_x.js +1 -0
- package/dist/assets/TeacherView-DscJtOJ9.js +2 -0
- package/dist/assets/TimetableView-D2ozoj_D.js +6 -0
- package/dist/assets/UTIF-FfCsrHhe.js +1 -0
- package/dist/assets/__vite-optional-peer-dep_ai_ooxml-ui-BIHI7g3E.js +1 -0
- package/dist/assets/browser-DEI0QxZC.js +1 -0
- package/dist/assets/html2canvas-pro.esm-Bo50djkB.js +12 -0
- package/dist/assets/index-2676X8YB.js +131 -0
- package/dist/assets/index-C6hlh8pw.css +1 -0
- package/dist/assets/{index.es-C5eWEO4o.js → index.es-DyEF0CZ9.js} +1 -1
- package/dist/assets/pluginParsers-e4PSm2Iy.js +1 -0
- package/dist/assets/react_pptx-react-viewer-BIHI7g3E.js +1 -0
- package/dist/assets/teaching-modes-client-BeVaDdJ-.js +1 -0
- package/dist/assets/three.module-iOYB3rD4.js +4228 -0
- package/dist/assets/timeline-duration-BgdJCSrW.js +1 -0
- package/dist/assets/{vendor-charts-qLbgF1eL.js → vendor-charts-SrpBsvM3.js} +2 -2
- package/dist/assets/{vendor-icons-BRmhY6fg.js → vendor-icons-CXrZ3R2V.js} +2 -2
- package/dist/assets/{vendor-konva-CEOq4dcl.js → vendor-konva-Dne0Z-WC.js} +1 -1
- package/dist/assets/{vendor-pdf-D7rGevI1.js → vendor-pdf-C1Vh2Aqq.js} +56 -56
- package/dist/assets/vendor-pptx-Bzn6whfK.js +11311 -0
- package/dist/assets/vendor-pptx-DIWdXF1L.css +1 -0
- package/dist/assets/{vendor-react-B0t7H3hh.js → vendor-react-Kv_JATwr.js} +1 -1
- package/dist/assets/vendor-utils-aM7aYvPP.js +1 -0
- package/dist/cli-migrator.cjs +310 -0
- package/dist/env-validation.cjs +351 -0
- package/dist/index.html +13 -10
- package/dist/plugin-net-preload.cjs +263 -0
- package/dist/server.cjs +51140 -27229
- package/migrations/000_initial_schema.sql +410 -0
- package/migrations/001_add_execution_mode.sql +6 -0
- package/migrations/002_add_client_session_expiry.sql +6 -0
- package/migrations/003_classroom_runtime.sql +33 -0
- package/migrations/004_courseware_score_config.sql +26 -0
- package/migrations/005_assignment_hub.sql +155 -0
- package/migrations/006_classroom_event_bus.sql +28 -0
- package/migrations/007_interactive_classroom.sql +119 -0
- package/migrations/008_teaching_modes.sql +36 -0
- package/migrations/009_classroom_peer_review.sql +159 -0
- package/migrations/010_class_groups.sql +33 -0
- package/migrations/011_classroom_feed.sql +34 -0
- package/migrations/012_auto_record_score.sql +48 -0
- package/migrations/013_score_source_strategy.sql +81 -0
- package/migrations/014_performance_indexes.sql +21 -0
- package/migrations/015_demo_data_registry.sql +26 -0
- package/migrations/016_preset_polls_and_passcode_expiry.sql +33 -0
- package/migrations/017_pacing_signals_segment.sql +6 -0
- package/migrations/018_processes_plugin_owner.sql +26 -0
- package/migrations/019_plugins_version.sql +61 -0
- package/migrations/020_upload_max_file_mb.sql +14 -0
- package/migrations/021_class_owner_and_password_gate.sql +11 -0
- package/migrations/022_plugin_public_routes.sql +14 -0
- package/migrations/023_encrypt_class_passcodes.sql +18 -0
- package/migrations/024_segment_gates.sql +37 -0
- package/migrations/025_assignment_lookup_indexes.sql +11 -0
- package/migrations/026_plugin_grants.sql +21 -0
- package/migrations/027_academic_year.sql +26 -0
- package/migrations/028_classroom_indexes.sql +14 -0
- package/migrations/029_clean_lesson_think_artifacts.sql +13 -0
- package/migrations/030_backfill_academic_year.sql +30 -0
- package/migrations/031_assessment_core.sql +158 -0
- package/migrations/032_progress_verification.sql +17 -0
- package/migrations/033_student_lock_mode.sql +9 -0
- package/migrations/034_plugin_orphan_data.sql +27 -0
- package/migrations/035_icebreaker_checkins.sql +26 -0
- package/migrations/036_student_read_notifications_created_at.sql +19 -0
- package/migrations/037_plugin_config_scopes.sql +40 -0
- package/migrations/038_assessment_ai_grading_suggestion.sql +10 -0
- package/migrations/039_question_bank_sharing_and_papers.sql +14 -0
- package/migrations/040_assignment_grade_history.sql +37 -0
- package/migrations/041_course_package_idempotency.sql +33 -0
- package/migrations/042_assignment_grade_resubmit_audit.sql +12 -0
- package/migrations/043_mark_sha256_passwords.sql +31 -0
- package/migrations/README.md +61 -0
- package/migrations/schema-golden.json +640 -0
- package/package.json +54 -28
- package/dist/assets/AdminDirectoryView-DY--WM5Z.js +0 -1
- package/dist/assets/BatchPickerModal-BpWu0Lil.js +0 -1
- package/dist/assets/ClassesView-KbHEqJto.js +0 -22
- package/dist/assets/ClassroomCountdownWidget-96WFRO9A.js +0 -2
- package/dist/assets/CloudDriveModal-DEQ1nkNk.js +0 -1
- package/dist/assets/ComputerLabView-1qWDNRQ2.js +0 -1
- package/dist/assets/CourseManagement-D3ZpxY0l.js +0 -1
- package/dist/assets/CourseWizardModal-Ck_-M8pk.js +0 -3
- package/dist/assets/CoursewareHubPanel-CaEizhxl.js +0 -1
- package/dist/assets/Dashboard-CYbpbofV.js +0 -8
- package/dist/assets/ExportWeightModal-DW2bu9Zz.js +0 -1
- package/dist/assets/HelpTour-CMJbbGne.js +0 -1
- package/dist/assets/HelpView-CtzdqhBq.js +0 -204
- package/dist/assets/ImportLessonsModal-jBuIK453.js +0 -1
- package/dist/assets/ImportModal-D7L-KNhZ.js +0 -1
- package/dist/assets/InteractiveCoursewareViewer-Bj7ahXMs.js +0 -1
- package/dist/assets/InteractiveWhiteboard-B7JcJvDu.js +0 -77
- package/dist/assets/LazyCourseware-CuiPxhDg.js +0 -2
- package/dist/assets/LazyWhiteboard-BJwCEZAU.js +0 -2
- package/dist/assets/LessonEditorView-DFrOp2qp.js +0 -1
- package/dist/assets/LiveClassroomView-BZ5nGee3.js +0 -59
- package/dist/assets/NotificationDetailModal-Baqnc5pU.js +0 -1
- package/dist/assets/PluginView-CCbIuZ24.js +0 -66
- package/dist/assets/ProcessLogsModal-DmFXg9mG.js +0 -1
- package/dist/assets/QuizGeneratorModal-BBEDssp7.js +0 -1
- package/dist/assets/StudentAssignmentView-DgIjUsXz.js +0 -1
- package/dist/assets/StudentLessonView-CBJbI5x6.js +0 -1
- package/dist/assets/StudentPreviewModal-Bh8OZs0t.js +0 -1
- package/dist/assets/StudentView--uGxc5TJ.js +0 -2
- package/dist/assets/SystemResourceLibraryModal-BVCclcqA.js +0 -1
- package/dist/assets/TeacherView-D4Zsc0eZ.js +0 -2
- package/dist/assets/TimetableView-BQG-rEb5.js +0 -6
- package/dist/assets/index-BKBCBKvy.js +0 -217
- package/dist/assets/index-CvGu7LSj.css +0 -1
- package/dist/assets/purify.es-CYR4BTuT.js +0 -3
- package/dist/assets/vendor-pptx-C5-U7ieS.js +0 -39
- package/dist/assets/vendor-utils-m0Urvtws.js +0 -1
package/dist/index.html
CHANGED
|
@@ -4,18 +4,21 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>OpenLearn Next</title>
|
|
7
|
-
<meta
|
|
7
|
+
<meta
|
|
8
|
+
name="description"
|
|
9
|
+
content="An AI-powered Learning Management System featuring interactive classrooms, stage management, real-time student response systems, lesson editor, auto-grading, and an extensible third-party plugin ecosystem."
|
|
10
|
+
/>
|
|
8
11
|
<meta property="og:title" content="OpenLearn Next" />
|
|
9
|
-
<meta
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
12
|
+
<meta
|
|
13
|
+
property="og:description"
|
|
14
|
+
content="An AI-powered Learning Management System featuring interactive classrooms, stage management, real-time student response systems, lesson editor, auto-grading, and an extensible third-party plugin ecosystem."
|
|
15
|
+
/>
|
|
16
|
+
<script type="module" crossorigin src="/assets/index-2676X8YB.js"></script>
|
|
17
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-utils-aM7aYvPP.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-react-Kv_JATwr.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-icons-CXrZ3R2V.js">
|
|
15
20
|
<link rel="modulepreload" crossorigin href="/assets/vendor-motion-BFAPOs-b.js">
|
|
16
|
-
<link rel="
|
|
17
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-charts-qLbgF1eL.js">
|
|
18
|
-
<link rel="stylesheet" crossorigin href="/assets/index-CvGu7LSj.css">
|
|
21
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C6hlh8pw.css">
|
|
19
22
|
</head>
|
|
20
23
|
<body>
|
|
21
24
|
<div id="root"></div>
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子进程出站网络默认拒绝。
|
|
3
|
+
*
|
|
4
|
+
* Node 22/24 的权限模型没有 --allow-net,所以在进程入口包一层:
|
|
5
|
+
* 原始 socket / UDP / DNS 一律拒绝;fetch 与 http(s).request 只把「已批准域名」
|
|
6
|
+
* 交给宿主代发。允许名单在本文件加载时从环境变量拍下来,随后删掉,
|
|
7
|
+
* 插件代码改环境变量不能把自己加进名单。
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const EventEmitter = require('node:events');
|
|
12
|
+
const net = require('node:net');
|
|
13
|
+
const http = require('node:http');
|
|
14
|
+
const https = require('node:https');
|
|
15
|
+
const dns = require('node:dns');
|
|
16
|
+
|
|
17
|
+
const ALLOW_ENV = 'OPENLEARN_PLUGIN_NET_ALLOW';
|
|
18
|
+
const allowed = new Set(
|
|
19
|
+
String(process.env[ALLOW_ENV] || '')
|
|
20
|
+
.split(',')
|
|
21
|
+
.map((item) => item.trim().toLowerCase())
|
|
22
|
+
.filter(Boolean),
|
|
23
|
+
);
|
|
24
|
+
delete process.env[ALLOW_ENV];
|
|
25
|
+
|
|
26
|
+
function denied(message) {
|
|
27
|
+
const error = new Error(message);
|
|
28
|
+
error.code = 'ERR_ACCESS_DENIED';
|
|
29
|
+
return error;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function hostAllowed(hostname) {
|
|
33
|
+
return allowed.has(
|
|
34
|
+
String(hostname || '')
|
|
35
|
+
.trim()
|
|
36
|
+
.toLowerCase(),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function proxy(method, url, headers, body) {
|
|
41
|
+
const id = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const onMessage = (msg) => {
|
|
44
|
+
if (!msg || msg.type !== 'ol-net-proxy-result' || msg.id !== id) return;
|
|
45
|
+
process.off('message', onMessage);
|
|
46
|
+
if (!msg.ok) {
|
|
47
|
+
reject(denied(msg.error || 'network proxy denied'));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
resolve(msg);
|
|
51
|
+
};
|
|
52
|
+
process.on('message', onMessage);
|
|
53
|
+
try {
|
|
54
|
+
let bodyBase64 = '';
|
|
55
|
+
if (body) {
|
|
56
|
+
bodyBase64 = Buffer.isBuffer(body) ? body.toString('base64') : Buffer.from(body).toString('base64');
|
|
57
|
+
}
|
|
58
|
+
process.send({
|
|
59
|
+
type: 'ol-net-proxy',
|
|
60
|
+
id,
|
|
61
|
+
method,
|
|
62
|
+
url,
|
|
63
|
+
headers: headers || {},
|
|
64
|
+
bodyBase64,
|
|
65
|
+
});
|
|
66
|
+
} catch (error) {
|
|
67
|
+
process.off('message', onMessage);
|
|
68
|
+
reject(error);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function blockConnect() {
|
|
74
|
+
throw denied('plugin outbound sockets are denied; use fetch/http for an approved host');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
net.Socket.prototype.connect = blockConnect;
|
|
78
|
+
net.connect = blockConnect;
|
|
79
|
+
net.createConnection = blockConnect;
|
|
80
|
+
if (net.default) {
|
|
81
|
+
net.default.connect = blockConnect;
|
|
82
|
+
net.default.createConnection = blockConnect;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 拦截 UDP (dgram)
|
|
86
|
+
try {
|
|
87
|
+
const dgram = require('node:dgram');
|
|
88
|
+
function blockDgram() {
|
|
89
|
+
throw denied('plugin UDP sockets are denied');
|
|
90
|
+
}
|
|
91
|
+
dgram.createSocket = blockDgram;
|
|
92
|
+
if (dgram.Socket && dgram.Socket.prototype) {
|
|
93
|
+
dgram.Socket.prototype.bind = blockDgram;
|
|
94
|
+
dgram.Socket.prototype.connect = blockDgram;
|
|
95
|
+
dgram.Socket.prototype.send = blockDgram;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
/* node:dgram unavailable */
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 拦截 TLS 与 HTTP2 底层连接
|
|
102
|
+
try {
|
|
103
|
+
const tls = require('node:tls');
|
|
104
|
+
tls.connect = blockConnect;
|
|
105
|
+
} catch {}
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const http2 = require('node:http2');
|
|
109
|
+
http2.connect = blockConnect;
|
|
110
|
+
} catch {}
|
|
111
|
+
|
|
112
|
+
// 拦截 DNS 全方法与 Resolver 原型
|
|
113
|
+
function blockDns() {
|
|
114
|
+
throw denied('plugin DNS lookups are denied');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
for (const name of Object.getOwnPropertyNames(dns)) {
|
|
118
|
+
if (
|
|
119
|
+
typeof dns[name] === 'function' &&
|
|
120
|
+
(name.startsWith('resolve') || name.startsWith('lookup') || name === 'reverse')
|
|
121
|
+
) {
|
|
122
|
+
dns[name] = blockDns;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (dns.promises) {
|
|
127
|
+
for (const name of Object.getOwnPropertyNames(dns.promises)) {
|
|
128
|
+
if (
|
|
129
|
+
typeof dns.promises[name] === 'function' &&
|
|
130
|
+
(name.startsWith('resolve') || name.startsWith('lookup') || name === 'reverse')
|
|
131
|
+
) {
|
|
132
|
+
dns.promises[name] = async () => blockDns();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (dns.Resolver && dns.Resolver.prototype) {
|
|
138
|
+
for (const name of Object.getOwnPropertyNames(dns.Resolver.prototype)) {
|
|
139
|
+
if (
|
|
140
|
+
typeof dns.Resolver.prototype[name] === 'function' &&
|
|
141
|
+
(name.startsWith('resolve') || name.startsWith('reverse') || name.startsWith('set'))
|
|
142
|
+
) {
|
|
143
|
+
dns.Resolver.prototype[name] = blockDns;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
globalThis.fetch = async function pluginFetch(input, init) {
|
|
149
|
+
const url = typeof input === 'string' ? input : input && input.url;
|
|
150
|
+
const parsed = new URL(url);
|
|
151
|
+
if (!hostAllowed(parsed.hostname)) {
|
|
152
|
+
throw denied(`outbound host "${parsed.hostname}" is not approved`);
|
|
153
|
+
}
|
|
154
|
+
const method = (init && init.method) || (typeof input !== 'string' && input.method) || 'GET';
|
|
155
|
+
let body = init && init.body;
|
|
156
|
+
let bodyBuffer = null;
|
|
157
|
+
if (body) {
|
|
158
|
+
if (Buffer.isBuffer(body)) {
|
|
159
|
+
bodyBuffer = body;
|
|
160
|
+
} else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {
|
|
161
|
+
bodyBuffer = Buffer.from(body.buffer, body.byteOffset, body.byteLength);
|
|
162
|
+
} else if (typeof body === 'string') {
|
|
163
|
+
bodyBuffer = Buffer.from(body, 'utf8');
|
|
164
|
+
} else {
|
|
165
|
+
bodyBuffer = Buffer.from(String(body), 'utf8');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const headers = {};
|
|
170
|
+
const rawHeaders = (init && init.headers) || (typeof input !== 'string' && input.headers);
|
|
171
|
+
if (rawHeaders) {
|
|
172
|
+
if (typeof rawHeaders.forEach === 'function') {
|
|
173
|
+
rawHeaders.forEach((value, key) => {
|
|
174
|
+
headers[key] = value;
|
|
175
|
+
});
|
|
176
|
+
} else if (Array.isArray(rawHeaders)) {
|
|
177
|
+
for (const [key, value] of rawHeaders) {
|
|
178
|
+
headers[key] = value;
|
|
179
|
+
}
|
|
180
|
+
} else if (typeof rawHeaders === 'object') {
|
|
181
|
+
Object.assign(headers, rawHeaders);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const result = await proxy(method, parsed.toString(), headers, bodyBuffer);
|
|
186
|
+
const text = Buffer.from(result.bodyBase64 || '', 'base64').toString('utf8');
|
|
187
|
+
return {
|
|
188
|
+
ok: result.status >= 200 && result.status < 300,
|
|
189
|
+
status: result.status,
|
|
190
|
+
headers: { get: (name) => result.headers?.[String(name).toLowerCase()] },
|
|
191
|
+
text: async () => text,
|
|
192
|
+
json: async () => JSON.parse(text || 'null'),
|
|
193
|
+
arrayBuffer: async () => Buffer.from(result.bodyBase64 || '', 'base64'),
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
function proxiedRequest(protocol) {
|
|
198
|
+
return function pluginHttpRequest(urlOrOptions, options, callback) {
|
|
199
|
+
let url;
|
|
200
|
+
let opts = options;
|
|
201
|
+
let cb = callback;
|
|
202
|
+
if (typeof urlOrOptions === 'string' || urlOrOptions instanceof URL) {
|
|
203
|
+
url = new URL(urlOrOptions);
|
|
204
|
+
if (typeof opts === 'function') {
|
|
205
|
+
cb = opts;
|
|
206
|
+
opts = {};
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
opts = urlOrOptions || {};
|
|
210
|
+
if (typeof options === 'function') cb = options;
|
|
211
|
+
const host = opts.hostname || opts.host;
|
|
212
|
+
url = new URL(`${protocol}//${host}${opts.path || '/'}`);
|
|
213
|
+
}
|
|
214
|
+
if (!hostAllowed(url.hostname)) {
|
|
215
|
+
throw denied(`outbound host "${url.hostname}" is not approved`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const chunks = [];
|
|
219
|
+
const request = new EventEmitter();
|
|
220
|
+
request.setHeader = () => request;
|
|
221
|
+
request.write = (chunk) => {
|
|
222
|
+
chunks.push(Buffer.from(chunk));
|
|
223
|
+
return true;
|
|
224
|
+
};
|
|
225
|
+
request.end = (chunk) => {
|
|
226
|
+
if (chunk) chunks.push(Buffer.from(chunk));
|
|
227
|
+
const body = Buffer.concat(chunks);
|
|
228
|
+
proxy(opts.method || 'GET', url.toString(), opts.headers, body)
|
|
229
|
+
.then((result) => {
|
|
230
|
+
const response = new EventEmitter();
|
|
231
|
+
response.statusCode = result.status;
|
|
232
|
+
response.headers = result.headers || {};
|
|
233
|
+
if (typeof cb === 'function') cb(response);
|
|
234
|
+
request.emit('response', response);
|
|
235
|
+
process.nextTick(() => {
|
|
236
|
+
response.emit('data', Buffer.from(result.bodyBase64 || '', 'base64'));
|
|
237
|
+
response.emit('end');
|
|
238
|
+
});
|
|
239
|
+
})
|
|
240
|
+
.catch((error) => {
|
|
241
|
+
request.emit('error', error);
|
|
242
|
+
});
|
|
243
|
+
return request;
|
|
244
|
+
};
|
|
245
|
+
request.abort = () => {};
|
|
246
|
+
request.destroy = () => {};
|
|
247
|
+
|
|
248
|
+
return request;
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
http.request = proxiedRequest('http:');
|
|
253
|
+
http.get = function pluginHttpGet(url, options, callback) {
|
|
254
|
+
const request = http.request(url, options, callback);
|
|
255
|
+
request.end();
|
|
256
|
+
return request;
|
|
257
|
+
};
|
|
258
|
+
https.request = proxiedRequest('https:');
|
|
259
|
+
https.get = function pluginHttpsGet(url, options, callback) {
|
|
260
|
+
const request = https.request(url, options, callback);
|
|
261
|
+
request.end();
|
|
262
|
+
return request;
|
|
263
|
+
};
|