Enable loading external plugins
This commit is contained in:
parent
bac948ea6f
commit
361e7103ea
|
@ -18,7 +18,7 @@ main() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
parcel build \
|
parcel build \
|
||||||
--public-url "/static/$(git rev-parse HEAD)/dist" \
|
--public-url "." \
|
||||||
--out-dir dist \
|
--out-dir dist \
|
||||||
$([[ $MINIFY ]] || echo --no-minify) \
|
$([[ $MINIFY ]] || echo --no-minify) \
|
||||||
src/browser/register.ts \
|
src/browser/register.ts \
|
||||||
|
|
|
@ -722,10 +722,10 @@ index eab8591492..26668701f7 100644
|
||||||
options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`);
|
options.logService.error(`${logPrefix} socketFactory.connect() failed. Error:`);
|
||||||
diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts
|
diff --git a/src/vs/server/browser/client.ts b/src/vs/server/browser/client.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..8fb2a87303
|
index 0000000000..3c0703b717
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/vs/server/browser/client.ts
|
+++ b/src/vs/server/browser/client.ts
|
||||||
@@ -0,0 +1,208 @@
|
@@ -0,0 +1,189 @@
|
||||||
+import { Emitter } from 'vs/base/common/event';
|
+import { Emitter } from 'vs/base/common/event';
|
||||||
+import { URI } from 'vs/base/common/uri';
|
+import { URI } from 'vs/base/common/uri';
|
||||||
+import { localize } from 'vs/nls';
|
+import { localize } from 'vs/nls';
|
||||||
|
@ -761,31 +761,12 @@ index 0000000000..8fb2a87303
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+/**
|
+/**
|
||||||
+ * Get options embedded in the HTML from the server.
|
+ * Get options embedded in the HTML.
|
||||||
+ */
|
+ */
|
||||||
+export const getOptions = <T extends Options>(): T => {
|
+export const getOptions = <T extends Options>(): T => {
|
||||||
+ if (typeof document === "undefined") {
|
|
||||||
+ return {} as T;
|
|
||||||
+ }
|
|
||||||
+ const el = document.getElementById("coder-options");
|
|
||||||
+ try {
|
+ try {
|
||||||
+ if (!el) {
|
+ return JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!);
|
||||||
+ throw new Error("no options element");
|
|
||||||
+ }
|
|
||||||
+ const value = el.getAttribute("data-settings");
|
|
||||||
+ if (!value) {
|
|
||||||
+ throw new Error("no options value");
|
|
||||||
+ }
|
|
||||||
+ const options = JSON.parse(value);
|
|
||||||
+ const parts = window.location.pathname.replace(/^\//g, "").split("/");
|
|
||||||
+ parts[parts.length - 1] = options.base;
|
|
||||||
+ const url = new URL(window.location.origin + "/" + parts.join("/"));
|
|
||||||
+ return {
|
|
||||||
+ ...options,
|
|
||||||
+ base: normalize(url.pathname, true),
|
|
||||||
+ };
|
|
||||||
+ } catch (error) {
|
+ } catch (error) {
|
||||||
+ console.warn(error);
|
|
||||||
+ return {} as T;
|
+ return {} as T;
|
||||||
+ }
|
+ }
|
||||||
+};
|
+};
|
||||||
|
@ -1306,16 +1287,15 @@ index 0000000000..56331ff1fc
|
||||||
+require('../../bootstrap-amd').load('vs/server/entry');
|
+require('../../bootstrap-amd').load('vs/server/entry');
|
||||||
diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
|
diff --git a/src/vs/server/ipc.d.ts b/src/vs/server/ipc.d.ts
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000000..5cc3e1f0f4
|
index 0000000000..7e1cd270c8
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/vs/server/ipc.d.ts
|
+++ b/src/vs/server/ipc.d.ts
|
||||||
@@ -0,0 +1,116 @@
|
@@ -0,0 +1,115 @@
|
||||||
+/**
|
+/**
|
||||||
+ * External interfaces for integration into code-server over IPC. No vs imports
|
+ * External interfaces for integration into code-server over IPC. No vs imports
|
||||||
+ * should be made in this file.
|
+ * should be made in this file.
|
||||||
+ */
|
+ */
|
||||||
+export interface Options {
|
+export interface Options {
|
||||||
+ base: string
|
|
||||||
+ disableTelemetry: boolean
|
+ disableTelemetry: boolean
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
|
|
@ -150,7 +150,7 @@ class Watcher {
|
||||||
cacheDir: path.join(this.rootPath, ".cache"),
|
cacheDir: path.join(this.rootPath, ".cache"),
|
||||||
minify: !!process.env.MINIFY,
|
minify: !!process.env.MINIFY,
|
||||||
logLevel: 1,
|
logLevel: 1,
|
||||||
publicUrl: "/static/development/dist",
|
publicUrl: ".",
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,32 +7,32 @@
|
||||||
"description": "Run editors on a remote server.",
|
"description": "Run editors on a remote server.",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-96.png",
|
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-96.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "96x96"
|
"sizes": "96x96"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-128.png",
|
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-128.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "128x128"
|
"sizes": "128x128"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-192.png",
|
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-192.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "192x192"
|
"sizes": "192x192"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-256.png",
|
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-256.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "256x256"
|
"sizes": "256x256"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png",
|
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "384x384"
|
"sizes": "384x384"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-512.png",
|
"src": "{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-512.png",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"sizes": "512x512"
|
"sizes": "512x512"
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,10 @@
|
||||||
content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
content="style-src 'self'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||||
/>
|
/>
|
||||||
<title>{{ERROR_TITLE}} - code-server</title>
|
<title>{{ERROR_TITLE}} - code-server</title>
|
||||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||||
<link
|
<link rel="manifest" href="{{CS_STATIC_BASE}}/src/browser/media/manifest.json" crossorigin="use-credentials" />
|
||||||
rel="manifest"
|
<link rel="apple-touch-icon" href="{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png" />
|
||||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
<link href="{{CS_STATIC_BASE}}/dist/register.css" rel="stylesheet" />
|
||||||
crossorigin="use-credentials"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
|
||||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/register.css" rel="stylesheet" />
|
|
||||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -33,6 +29,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -11,14 +11,10 @@
|
||||||
content="style-src 'self'; script-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
content="style-src 'self'; script-src 'self' 'unsafe-inline'; manifest-src 'self'; img-src 'self' data:; font-src 'self' data:;"
|
||||||
/>
|
/>
|
||||||
<title>code-server login</title>
|
<title>code-server login</title>
|
||||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||||
<link
|
<link rel="manifest" href="{{CS_STATIC_BASE}}/src/browser/media/manifest.json" crossorigin="use-credentials" />
|
||||||
rel="manifest"
|
<link rel="apple-touch-icon" href="{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png" />
|
||||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
<link href="{{CS_STATIC_BASE}}/dist/register.css" rel="stylesheet" />
|
||||||
crossorigin="use-credentials"
|
|
||||||
/>
|
|
||||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
|
||||||
<link href="{{BASE}}/static/{{COMMIT}}/dist/register.css" rel="stylesheet" />
|
|
||||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -50,7 +46,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
||||||
parts[parts.length - 1] = "{{BASE}}"
|
parts[parts.length - 1] = "{{BASE}}"
|
||||||
|
|
|
@ -24,21 +24,17 @@
|
||||||
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" />
|
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}" />
|
||||||
|
|
||||||
<!-- Workbench Icon/Manifest/CSS -->
|
<!-- Workbench Icon/Manifest/CSS -->
|
||||||
<link rel="icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
<link rel="icon" href="{{CS_STATIC_BASE}}/src/browser/media/favicon.ico" type="image/x-icon" />
|
||||||
<link
|
<link rel="manifest" href="{{CS_STATIC_BASE}}/src/browser/media/manifest.json" crossorigin="use-credentials" />
|
||||||
rel="manifest"
|
|
||||||
href="{{BASE}}/static/{{COMMIT}}/src/browser/media/manifest.json"
|
|
||||||
crossorigin="use-credentials"
|
|
||||||
/>
|
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.css">
|
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{CS_STATIC_BASE}}/lib/vscode/out/vs/workbench/workbench.web.api.css">
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
<link rel="apple-touch-icon" href="{{BASE}}/static/{{COMMIT}}/src/browser/media/pwa-icon-384.png" />
|
<link rel="apple-touch-icon" href="{{CS_STATIC_BASE}}/src/browser/media/pwa-icon-384.png" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
|
||||||
<!-- Prefetch to avoid waterfall -->
|
<!-- Prefetch to avoid waterfall -->
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<link rel="prefetch" href="{{BASE}}/static/{{COMMIT}}/lib/vscode/node_modules/semver-umd/lib/semver-umd.js">
|
<link rel="prefetch" href="{{CS_STATIC_BASE}}/lib/vscode/node_modules/semver-umd/lib/semver-umd.js">
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
|
|
||||||
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
<meta id="coder-options" data-settings="{{OPTIONS}}" />
|
||||||
|
@ -48,10 +44,6 @@
|
||||||
|
|
||||||
<!-- Startup (do not modify order of script tags!) -->
|
<!-- Startup (do not modify order of script tags!) -->
|
||||||
<script>
|
<script>
|
||||||
const parts = window.location.pathname.replace(/^\//g, "").split("/")
|
|
||||||
parts[parts.length - 1] = "{{BASE}}"
|
|
||||||
const url = new URL(window.location.origin + "/" + parts.join("/"))
|
|
||||||
const staticBase = url.href.replace(/\/+$/, "") + "/static/{{COMMIT}}/lib/vscode"
|
|
||||||
let nlsConfig
|
let nlsConfig
|
||||||
try {
|
try {
|
||||||
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
|
nlsConfig = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
|
||||||
|
@ -64,7 +56,7 @@
|
||||||
}
|
}
|
||||||
// FIXME: Only works if path separators are /.
|
// FIXME: Only works if path separators are /.
|
||||||
const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
|
const path = nlsConfig._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
|
||||||
fetch(`${url.href}/resource/?path=${encodeURIComponent(path)}`)
|
fetch(`{{BASE}}/resource/?path=${encodeURIComponent(path)}`)
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((json) => {
|
.then((json) => {
|
||||||
bundles[bundle] = json
|
bundles[bundle] = json
|
||||||
|
@ -77,26 +69,26 @@
|
||||||
/* Probably fine. */
|
/* Probably fine. */
|
||||||
}
|
}
|
||||||
self.require = {
|
self.require = {
|
||||||
baseUrl: `${staticBase}/out`,
|
baseUrl: "{{CS_STATIC_BASE}}/lib/vscode/out",
|
||||||
paths: {
|
paths: {
|
||||||
"vscode-textmate": `${staticBase}/node_modules/vscode-textmate/release/main`,
|
"vscode-textmate": `../node_modules/vscode-textmate/release/main`,
|
||||||
"vscode-oniguruma": `${staticBase}/node_modules/vscode-oniguruma/release/main`,
|
"vscode-oniguruma": `../node_modules/vscode-oniguruma/release/main`,
|
||||||
xterm: `${staticBase}/node_modules/xterm/lib/xterm.js`,
|
xterm: `../node_modules/xterm/lib/xterm.js`,
|
||||||
"xterm-addon-search": `${staticBase}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
"xterm-addon-search": `../node_modules/xterm-addon-search/lib/xterm-addon-search.js`,
|
||||||
"xterm-addon-unicode11": `${staticBase}/node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
"xterm-addon-unicode11": `../node_modules/xterm-addon-unicode11/lib/xterm-addon-unicode11.js`,
|
||||||
"xterm-addon-webgl": `${staticBase}/node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
"xterm-addon-webgl": `../node_modules/xterm-addon-webgl/lib/xterm-addon-webgl.js`,
|
||||||
"semver-umd": `${staticBase}/node_modules/semver-umd/lib/semver-umd.js`,
|
"semver-umd": `../node_modules/semver-umd/lib/semver-umd.js`,
|
||||||
"iconv-lite-umd": `${staticBase}/node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
"iconv-lite-umd": `../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js`,
|
||||||
jschardet: `${staticBase}/node_modules/jschardet/dist/jschardet.min.js`,
|
jschardet: `../node_modules/jschardet/dist/jschardet.min.js`,
|
||||||
},
|
},
|
||||||
"vs/nls": nlsConfig,
|
"vs/nls": nlsConfig,
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/dist/register.js"></script>
|
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/dist/register.js"></script>
|
||||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/loader.js"></script>
|
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/lib/vscode/out/vs/loader.js"></script>
|
||||||
<!-- PROD_ONLY
|
<!-- PROD_ONLY
|
||||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.nls.js"></script>
|
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/lib/vscode/out/vs/workbench/workbench.web.api.nls.js"></script>
|
||||||
<script data-cfasync="false" src="{{BASE}}/static/{{COMMIT}}/lib/vscode/out/vs/workbench/workbench.web.api.js"></script>
|
<script data-cfasync="false" src="{{CS_STATIC_BASE}}/lib/vscode/out/vs/workbench/workbench.web.api.js"></script>
|
||||||
END_PROD_ONLY -->
|
END_PROD_ONLY -->
|
||||||
<script>
|
<script>
|
||||||
require(["vs/code/browser/workbench/workbench"], function () {})
|
require(["vs/code/browser/workbench/workbench"], function () {})
|
||||||
|
|
|
@ -7,7 +7,7 @@ import "./pages/global.css"
|
||||||
import "./pages/login.css"
|
import "./pages/login.css"
|
||||||
|
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
const path = normalize(`${options.base}/static/${options.commit}/dist/serviceWorker.js`)
|
const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`)
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker
|
||||||
.register(path, {
|
.register(path, {
|
||||||
scope: options.base || "/",
|
scope: options.base || "/",
|
||||||
|
|
|
@ -2,9 +2,8 @@ import { logger, field } from "@coder/logger"
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
base: string
|
base: string
|
||||||
commit: string
|
csStaticBase: string
|
||||||
logLevel: number
|
logLevel: number
|
||||||
pid?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,21 +39,28 @@ export const trimSlashes = (url: string): string => {
|
||||||
return url.replace(/^\/+|\/+$/g, "")
|
return url.replace(/^\/+|\/+$/g, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a relative base against the window location. This is used for
|
||||||
|
* anything that doesn't work with a relative path.
|
||||||
|
*/
|
||||||
|
export const resolveBase = (base?: string): string => {
|
||||||
|
// After resolving the base will either start with / or be an empty string.
|
||||||
|
if (!base || base.startsWith("/")) {
|
||||||
|
return base || ""
|
||||||
|
}
|
||||||
|
const parts = location.pathname.replace(/^\//g, "").split("/")
|
||||||
|
parts[parts.length - 1] = base
|
||||||
|
const url = new URL(location.origin + "/" + parts.join("/"))
|
||||||
|
return normalize(url.pathname)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get options embedded in the HTML or query params.
|
* Get options embedded in the HTML or query params.
|
||||||
*/
|
*/
|
||||||
export const getOptions = <T extends Options>(): T => {
|
export const getOptions = <T extends Options>(): T => {
|
||||||
let options: T
|
let options: T
|
||||||
try {
|
try {
|
||||||
const el = document.getElementById("coder-options")
|
options = JSON.parse(document.getElementById("coder-options")!.getAttribute("data-settings")!)
|
||||||
if (!el) {
|
|
||||||
throw new Error("no options element")
|
|
||||||
}
|
|
||||||
const value = el.getAttribute("data-settings")
|
|
||||||
if (!value) {
|
|
||||||
throw new Error("no options value")
|
|
||||||
}
|
|
||||||
options = JSON.parse(value)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
options = {} as T
|
options = {} as T
|
||||||
}
|
}
|
||||||
|
@ -68,15 +74,10 @@ export const getOptions = <T extends Options>(): T => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options.logLevel !== "undefined") {
|
|
||||||
logger.level = options.logLevel
|
logger.level = options.logLevel
|
||||||
}
|
|
||||||
if (options.base) {
|
options.base = resolveBase(options.base)
|
||||||
const parts = location.pathname.replace(/^\//g, "").split("/")
|
options.csStaticBase = resolveBase(options.csStaticBase)
|
||||||
parts[parts.length - 1] = options.base
|
|
||||||
const url = new URL(location.origin + "/" + parts.join("/"))
|
|
||||||
options.base = normalize(url.pathname, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("got options", field("options", options))
|
logger.debug("got options", field("options", options))
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,9 @@ import { HttpProvider, HttpResponse, Route } from "../http"
|
||||||
import { pathToFsPath } from "../util"
|
import { pathToFsPath } from "../util"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static file HTTP provider. Regular static requests (the path is the request
|
* Static file HTTP provider. Static requests do not require authentication if
|
||||||
* itself) do not require authentication and they only allow access to resources
|
* the resource is in the application's directory except requests to serve a
|
||||||
* within the application. Requests for tars (the path is in a query parameter)
|
* directory as a tar which always requires authentication.
|
||||||
* do require permissions and can access any directory.
|
|
||||||
*/
|
*/
|
||||||
export class StaticHttpProvider extends HttpProvider {
|
export class StaticHttpProvider extends HttpProvider {
|
||||||
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
|
||||||
|
@ -22,7 +21,7 @@ export class StaticHttpProvider extends HttpProvider {
|
||||||
return this.getTarredResource(request, pathToFsPath(route.query.tar))
|
return this.getTarredResource(request, pathToFsPath(route.query.tar))
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await this.getReplacedResource(route)
|
const response = await this.getReplacedResource(request, route)
|
||||||
if (!this.isDev) {
|
if (!this.isDev) {
|
||||||
response.cache = true
|
response.cache = true
|
||||||
}
|
}
|
||||||
|
@ -32,17 +31,25 @@ export class StaticHttpProvider extends HttpProvider {
|
||||||
/**
|
/**
|
||||||
* Return a resource with variables replaced where necessary.
|
* Return a resource with variables replaced where necessary.
|
||||||
*/
|
*/
|
||||||
protected async getReplacedResource(route: Route): Promise<HttpResponse> {
|
protected async getReplacedResource(request: http.IncomingMessage, route: Route): Promise<HttpResponse> {
|
||||||
// The first part is always the commit (for caching purposes).
|
// The first part is always the commit (for caching purposes).
|
||||||
const split = route.requestPath.split("/").slice(1)
|
const split = route.requestPath.split("/").slice(1)
|
||||||
|
|
||||||
|
const resourcePath = path.resolve("/", ...split)
|
||||||
|
|
||||||
|
// Make sure it's in code-server or a plugin.
|
||||||
|
const validPaths = [this.rootPath, process.env.PLUGIN_DIR]
|
||||||
|
if (!validPaths.find((p) => typeof p !== "undefined" && p.length > 0 && resourcePath.startsWith(p))) {
|
||||||
|
this.ensureAuthenticated(request)
|
||||||
|
}
|
||||||
|
|
||||||
switch (split[split.length - 1]) {
|
switch (split[split.length - 1]) {
|
||||||
case "manifest.json": {
|
case "manifest.json": {
|
||||||
const response = await this.getUtf8Resource(this.rootPath, ...split)
|
const response = await this.getUtf8Resource(resourcePath)
|
||||||
return this.replaceTemplates(route, response)
|
return this.replaceTemplates(route, response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.getResource(this.rootPath, ...split)
|
return this.getResource(resourcePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -209,11 +209,11 @@ export abstract class HttpProvider {
|
||||||
/**
|
/**
|
||||||
* Get the base relative to the provided route. For each slash we need to go
|
* Get the base relative to the provided route. For each slash we need to go
|
||||||
* up a directory. For example:
|
* up a directory. For example:
|
||||||
* / => ./
|
* / => .
|
||||||
* /foo => ./
|
* /foo => .
|
||||||
* /foo/ => ./../
|
* /foo/ => ./..
|
||||||
* /foo/bar => ./../
|
* /foo/bar => ./..
|
||||||
* /foo/bar/ => ./../../
|
* /foo/bar/ => ./../..
|
||||||
*/
|
*/
|
||||||
public base(route: Route): string {
|
public base(route: Route): string {
|
||||||
const depth = (route.originalPath.match(/\//g) || []).length
|
const depth = (route.originalPath.match(/\//g) || []).length
|
||||||
|
@ -240,16 +240,17 @@ export abstract class HttpProvider {
|
||||||
response: HttpStringFileResponse,
|
response: HttpStringFileResponse,
|
||||||
extraOptions?: Omit<T, "base" | "csStaticBase" | "logLevel">,
|
extraOptions?: Omit<T, "base" | "csStaticBase" | "logLevel">,
|
||||||
): HttpStringFileResponse {
|
): HttpStringFileResponse {
|
||||||
|
const base = this.base(route)
|
||||||
const options: Options = {
|
const options: Options = {
|
||||||
base: this.base(route),
|
base,
|
||||||
commit: this.options.commit,
|
csStaticBase: base + "/static/" + this.options.commit + this.rootPath,
|
||||||
logLevel: logger.level,
|
logLevel: logger.level,
|
||||||
...extraOptions,
|
...extraOptions,
|
||||||
}
|
}
|
||||||
response.content = response.content
|
response.content = response.content
|
||||||
.replace(/{{COMMIT}}/g, this.options.commit)
|
|
||||||
.replace(/{{TO}}/g, Array.isArray(route.query.to) ? route.query.to[0] : route.query.to || "/dashboard")
|
.replace(/{{TO}}/g, Array.isArray(route.query.to) ? route.query.to[0] : route.query.to || "/dashboard")
|
||||||
.replace(/{{BASE}}/g, this.base(route))
|
.replace(/{{BASE}}/g, options.base)
|
||||||
|
.replace(/{{CS_STATIC_BASE}}/g, options.csStaticBase)
|
||||||
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`)
|
.replace(/"{{OPTIONS}}"/, `'${JSON.stringify(options)}'`)
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,4 +49,8 @@ export const loadPlugins = async (httpServer: HttpServer, args: Args): Promise<v
|
||||||
logger.warn(error.message)
|
logger.warn(error.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (process.env.PLUGIN_DIR) {
|
||||||
|
await loadPlugin(process.env.PLUGIN_DIR, httpServer, args)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue