Archived
1
0
This repository has been archived on 2024-09-09. You can view files and clone it, but cannot push or open issues or pull requests.
code-server/src/node/util.ts

515 lines
15 KiB
TypeScript
Raw Normal View History

import { logger } from "@coder/logger"
import * as argon2 from "argon2"
2020-02-04 20:27:46 +01:00
import * as cp from "child_process"
import * as crypto from "crypto"
2020-08-04 22:51:39 +02:00
import envPaths from "env-paths"
import { promises as fs } from "fs"
2020-09-15 23:51:43 +02:00
import * as net from "net"
2020-02-04 20:27:46 +01:00
import * as os from "os"
import * as path from "path"
import safeCompare from "safe-compare"
2020-02-04 20:27:46 +01:00
import * as util from "util"
import xdgBasedir from "xdg-basedir"
import { vsRootPath } from "./constants"
2020-02-04 20:27:46 +01:00
2021-05-11 01:27:47 +02:00
export interface Paths {
data: string
config: string
2021-05-11 01:17:30 +02:00
runtime: string
}
// From https://github.com/chalk/ansi-regex
const pattern = [
"[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
"(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))",
].join("|")
const re = new RegExp(pattern, "g")
/**
* Split stdout on newlines and strip ANSI codes.
*/
export const onLine = (proc: cp.ChildProcess, callback: (strippedLine: string, originalLine: string) => void): void => {
let buffer = ""
if (!proc.stdout) {
throw new Error("no stdout")
}
proc.stdout.setEncoding("utf8")
proc.stdout.on("data", (d) => {
const data = buffer + d
const split = data.split("\n")
const last = split.length - 1
for (let i = 0; i < last; ++i) {
callback(split[i].replace(re, ""), split[i])
}
// The last item will either be an empty string (the data ended with a
// newline) or a partial line (did not end with a newline) and we must
// wait to parse it until we get a full line.
buffer = split[last]
})
}
export const paths = getEnvPaths()
/**
* Gets the config and data paths for the current platform/configuration.
* On MacOS this function gets the standard XDG directories instead of using the native macOS
* ones. Most CLIs do this as in practice only GUI apps use the standard macOS directories.
*/
2021-05-11 01:17:30 +02:00
export function getEnvPaths(): Paths {
2021-05-11 01:27:47 +02:00
const paths = envPaths("code-server", { suffix: "" })
const append = (p: string): string => path.join(p, "code-server")
switch (process.platform) {
case "darwin":
return {
// envPaths uses native directories so force Darwin to use the XDG spec
// to align with other CLI tools.
data: xdgBasedir.data ? append(xdgBasedir.data) : paths.data,
config: xdgBasedir.config ? append(xdgBasedir.config) : paths.config,
// Fall back to temp if there is no runtime dir.
runtime: xdgBasedir.runtime ? append(xdgBasedir.runtime) : paths.temp,
}
case "win32":
return {
data: paths.data,
config: paths.config,
// Windows doesn't have a runtime dir.
runtime: paths.temp,
}
default:
return {
data: paths.data,
config: paths.config,
// Fall back to temp if there is no runtime dir.
runtime: xdgBasedir.runtime ? append(xdgBasedir.runtime) : paths.temp,
}
2020-02-04 20:27:46 +01:00
}
2019-07-26 00:39:43 +02:00
}
/**
* humanPath replaces the home directory in p with ~.
* Makes it more readable.
*
* @param p
*/
export function humanPath(p?: string): string {
if (!p) {
return ""
}
return p.replace(os.homedir(), "~")
}
2020-02-04 20:27:46 +01:00
export const generateCertificate = async (hostname: string): Promise<{ cert: string; certKey: string }> => {
const certPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.crt`)
const certKeyPath = path.join(paths.data, `${hostname.replace(/\./g, "_")}.key`)
// Try generating the certificates if we can't access them (which probably
// means they don't exist).
try {
await Promise.all([fs.access(certPath), fs.access(certKeyPath)])
} catch (error) {
2020-02-04 20:27:46 +01:00
// Require on demand so openssl isn't required if you aren't going to
// generate certificates.
const pem = require("pem") as typeof import("pem")
const certs = await new Promise<import("pem").CertificateCreationResult>((resolve, reject): void => {
pem.createCertificate(
{
selfSigned: true,
commonName: hostname,
config: `
[req]
req_extensions = v3_req
[ v3_req ]
basicConstraints = CA:true
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${hostname}
`,
},
(error, result) => {
return error ? reject(error) : resolve(result)
},
)
2020-02-04 20:27:46 +01:00
})
await fs.mkdir(paths.data, { recursive: true })
await Promise.all([fs.writeFile(certPath, certs.certificate), fs.writeFile(certKeyPath, certs.serviceKey)])
}
return {
cert: certPath,
certKey: certKeyPath,
2020-02-04 20:27:46 +01:00
}
2019-09-04 23:57:23 +02:00
}
2020-02-04 20:27:46 +01:00
export const generatePassword = async (length = 24): Promise<string> => {
const buffer = Buffer.alloc(Math.ceil(length / 2))
await util.promisify(crypto.randomFill)(buffer)
return buffer.toString("hex").substring(0, length)
}
2019-07-12 22:21:00 +02:00
/**
* Used to hash the password.
*/
export const hash = async (password: string): Promise<string> => {
try {
return await argon2.hash(password)
} catch (error: any) {
logger.error(error)
return ""
}
}
/**
* Used to verify if the password matches the hash
*/
export const isHashMatch = async (password: string, hash: string) => {
if (password === "" || hash === "" || !hash.startsWith("$")) {
return false
}
try {
return await argon2.verify(hash, password)
} catch (error: any) {
throw new Error(error)
}
}
/**
* Used to hash the password using the sha256
* algorithm. We only use this to for checking
* the hashed-password set in the config.
*
* Kept for legacy reasons.
*/
export const hashLegacy = (str: string): string => {
return crypto.createHash("sha256").update(str).digest("hex")
}
/**
* Used to check if the password matches the hash using
* the hashLegacy function
*/
export const isHashLegacyMatch = (password: string, hashPassword: string) => {
const hashedWithLegacy = hashLegacy(password)
return safeCompare(hashedWithLegacy, hashPassword)
2020-02-04 20:27:46 +01:00
}
export type PasswordMethod = "SHA256" | "ARGON2" | "PLAIN_TEXT"
/**
* Used to determine the password method.
*
* There are three options for the return value:
* 1. "SHA256" -> the legacy hashing algorithm
* 2. "ARGON2" -> the newest hashing algorithm
* 3. "PLAIN_TEXT" -> regular ol' password with no hashing
*
* @returns {PasswordMethod} "SHA256" | "ARGON2" | "PLAIN_TEXT"
*/
export function getPasswordMethod(hashedPassword: string | undefined): PasswordMethod {
if (!hashedPassword) {
return "PLAIN_TEXT"
}
// This is the new hashing algorithm
if (hashedPassword.includes("$argon")) {
return "ARGON2"
}
// This is the legacy hashing algorithm
return "SHA256"
}
type PasswordValidation = {
isPasswordValid: boolean
hashedPassword: string
}
type HandlePasswordValidationArgs = {
/** The PasswordMethod */
passwordMethod: PasswordMethod
/** The password provided by the user */
passwordFromRequestBody: string
/** The password set in PASSWORD or config */
passwordFromArgs: string | undefined
/** The hashed-password set in HASHED_PASSWORD or config */
hashedPasswordFromArgs: string | undefined
}
/**
* Checks if a password is valid and also returns the hash
* using the PasswordMethod
*/
export async function handlePasswordValidation({
passwordMethod,
passwordFromArgs,
passwordFromRequestBody,
hashedPasswordFromArgs,
}: HandlePasswordValidationArgs): Promise<PasswordValidation> {
const passwordValidation = <PasswordValidation>{
isPasswordValid: false,
hashedPassword: "",
}
switch (passwordMethod) {
case "PLAIN_TEXT": {
const isValid = passwordFromArgs ? safeCompare(passwordFromRequestBody, passwordFromArgs) : false
passwordValidation.isPasswordValid = isValid
const hashedPassword = await hash(passwordFromRequestBody)
passwordValidation.hashedPassword = hashedPassword
break
}
case "SHA256": {
const isValid = isHashLegacyMatch(passwordFromRequestBody, hashedPasswordFromArgs || "")
passwordValidation.isPasswordValid = isValid
passwordValidation.hashedPassword = hashedPasswordFromArgs || (await hashLegacy(passwordFromRequestBody))
break
}
case "ARGON2": {
const isValid = await isHashMatch(passwordFromRequestBody, hashedPasswordFromArgs || "")
passwordValidation.isPasswordValid = isValid
passwordValidation.hashedPassword = hashedPasswordFromArgs || ""
break
}
default:
break
}
return passwordValidation
}
export type IsCookieValidArgs = {
passwordMethod: PasswordMethod
cookieKey: string
hashedPasswordFromArgs: string | undefined
passwordFromArgs: string | undefined
}
/** Checks if a req.cookies.key is valid using the PasswordMethod */
export async function isCookieValid({
passwordFromArgs = "",
cookieKey,
hashedPasswordFromArgs = "",
passwordMethod,
}: IsCookieValidArgs): Promise<boolean> {
let isValid = false
switch (passwordMethod) {
case "PLAIN_TEXT":
isValid = await isHashMatch(passwordFromArgs, cookieKey)
break
case "ARGON2":
case "SHA256":
isValid = safeCompare(cookieKey, hashedPasswordFromArgs)
break
default:
break
}
return isValid
}
2021-06-07 23:46:59 +02:00
/** Ensures that the input is sanitized by checking
* - it's a string
* - greater than 0 characters
* - trims whitespace
*/
export function sanitizeString(str: string): string {
// Very basic sanitization of string
// Credit: https://stackoverflow.com/a/46719000/3015595
return typeof str === "string" && str.trim().length > 0 ? str.trim() : ""
}
2020-02-04 20:27:46 +01:00
const mimeTypes: { [key: string]: string } = {
".aac": "audio/x-aac",
".avi": "video/x-msvideo",
".bmp": "image/bmp",
".css": "text/css",
".flv": "video/x-flv",
".gif": "image/gif",
".html": "text/html",
".ico": "image/x-icon",
".jpe": "image/jpg",
".jpeg": "image/jpg",
".jpg": "image/jpg",
".js": "application/javascript",
".json": "application/json",
".m1v": "video/mpeg",
".m2a": "audio/mpeg",
".m2v": "video/mpeg",
".m3a": "audio/mpeg",
".mid": "audio/midi",
".midi": "audio/midi",
".mk3d": "video/x-matroska",
".mks": "video/x-matroska",
".mkv": "video/x-matroska",
".mov": "video/quicktime",
".movie": "video/x-sgi-movie",
".mp2": "audio/mpeg",
".mp2a": "audio/mpeg",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".mp4a": "audio/mp4",
".mp4v": "video/mp4",
".mpe": "video/mpeg",
".mpeg": "video/mpeg",
".mpg": "video/mpeg",
".mpg4": "video/mp4",
".mpga": "audio/mpeg",
".oga": "audio/ogg",
".ogg": "audio/ogg",
".ogv": "video/ogg",
".png": "image/png",
".psd": "image/vnd.adobe.photoshop",
".qt": "video/quicktime",
".spx": "audio/ogg",
".svg": "image/svg+xml",
".tga": "image/x-tga",
".tif": "image/tiff",
".tiff": "image/tiff",
".txt": "text/plain",
".wav": "audio/x-wav",
".wasm": "application/wasm",
".webm": "video/webm",
".webp": "image/webp",
".wma": "audio/x-ms-wma",
".wmv": "video/x-ms-wmv",
".woff": "application/font-woff",
}
2019-07-12 22:21:00 +02:00
export const getMediaMime = (filePath?: string): string => {
2020-02-04 20:27:46 +01:00
return (filePath && mimeTypes[path.extname(filePath)]) || "text/plain"
}
2019-07-15 20:31:05 +02:00
export const isWsl = async (): Promise<boolean> => {
2020-02-04 20:27:46 +01:00
return (
2020-05-14 09:17:17 +02:00
(process.platform === "linux" && os.release().toLowerCase().indexOf("microsoft") !== -1) ||
2020-02-04 20:27:46 +01:00
(await fs.readFile("/proc/version", "utf8")).toLowerCase().indexOf("microsoft") !== -1
)
}
2019-07-15 20:31:05 +02:00
2020-02-04 20:27:46 +01:00
/**
fix(testing): revert change & fix playwright tests (#4310) * fix(testing): revert change & fix playwright tests * fix(constants): add type to import statement * refactor(e2e): delete browser test This test was originally added to ensure playwright was working. At this point, we know it works so removing this test because it doesn't help with anything specific to code-server and only adds unnecessary code to the codebase plus increases the e2e test job duration. * chore(e2e): use 1 worker for e2e test I don't know if it's a resources issue, playwright, or code-server but it seems like the e2e tests choke when multiple workers are used. This change is okay because our CI runner only has 2 cores so it would only use 1 worker anyway, but by specifying it in our playwright config, we ensure more stability in our e2e tests working correctly. See these PRs: - https://github.com/cdr/code-server/pull/3263 - https://github.com/cdr/code-server/pull/4310 * revert(vscode): add missing route with redirect * chore(vscode): update to latest fork * Touch up compilation step. * Bump vendor. * Fix VS Code minification step * Move ClientConfiguration to common Common code must not import Node code as it is imported by the browser. * Ensure lib directory exists before curling cURL errors now because VS Code was moved and the directory does not exist. * Update incorrect e2e test help output Revert workers change as well; this can be overridden when desired. * Add back extension compilation step * Include missing resources in release This includes a favicon, for example. I opted to include the entire directory to make sure we do not miss anything. Some of the other stuff looks potentially useful (like completions). * Set quality property in product configuration When httpWebWorkerExtensionHostIframe.html is fetched it uses the web endpoint template (in which we do not include the commit) but if the quality is not set it prepends the commit to the web endpoint instead. The new static endpoint does not use/handle commits so this 404s. Long-term we might want to make the new static endpoint use commits like the old one but we will also need to update the various other static URLs to include the commit. For now I just fixed this by adding the quality since: 1. Probably faster than trying to find and update all static uses. 2. VS Code probably expects it anyway. 3. Gives us better control over the endpoint. * Update VS Code This fixes several build issues. * Bump vscode. * Bump. * Bump. * Use CLI directly. * Update tests to reflect new upstream behavior. * Move unit tests to after the build Our code has new dependencies on VS Code that are pulled in when the unit tests run. Because of this we need to build VS Code before running the unit tests (as it only pulls built code). * Upgrade proxy-agent dependencies This resolves a security report with one of its dependencies (vm2). * Symlink VS Code output directory before unit tests This is necessary now that we import from the out directory. * Fix issues surrounding persistent processes between tests. * Update VS Code cache directories These were renamed so the cached paths need to be updated. I changed the key as well to force a rebuild. * Move test symlink to script This way it works for local testing as well. I had to use out-build instead of out-vscode-server-min because Jest throws some obscure error about a handlebars haste map. * Fix listening on a socket * Update VS Code It contains fixes for missing files in the build. * Standardize disposals * Dispose HTTP server Shares code with the test HTTP server. For now it is a function but maybe we should make it a class that is extended by tests. * Dispose app on exit * Fix logging link errors Unfortunately the logger currently chokes when provided with error objects. Also for some reason the bracketed text was not displaying... * Update regex used by e2e to extract address The address was recently changed to use URL which seems to add a trailing slash when using toString, causing the regex match to fail. * Log browser console in e2e tests * Add base back to login page This is used to set cookies when using a base path. * Remove login page test The file this was testing no longer exists. * Use path.posix for static base Since this is a web path and not platform-dependent. * Add test for invalid password Co-authored-by: Teffen Ellis <teffen@nirri.us> Co-authored-by: Asher <ash@coder.com>
2021-10-28 22:27:17 +02:00
* Try opening an address using whatever the system has set for opening URLs.
2020-02-04 20:27:46 +01:00
*/
fix(testing): revert change & fix playwright tests (#4310) * fix(testing): revert change & fix playwright tests * fix(constants): add type to import statement * refactor(e2e): delete browser test This test was originally added to ensure playwright was working. At this point, we know it works so removing this test because it doesn't help with anything specific to code-server and only adds unnecessary code to the codebase plus increases the e2e test job duration. * chore(e2e): use 1 worker for e2e test I don't know if it's a resources issue, playwright, or code-server but it seems like the e2e tests choke when multiple workers are used. This change is okay because our CI runner only has 2 cores so it would only use 1 worker anyway, but by specifying it in our playwright config, we ensure more stability in our e2e tests working correctly. See these PRs: - https://github.com/cdr/code-server/pull/3263 - https://github.com/cdr/code-server/pull/4310 * revert(vscode): add missing route with redirect * chore(vscode): update to latest fork * Touch up compilation step. * Bump vendor. * Fix VS Code minification step * Move ClientConfiguration to common Common code must not import Node code as it is imported by the browser. * Ensure lib directory exists before curling cURL errors now because VS Code was moved and the directory does not exist. * Update incorrect e2e test help output Revert workers change as well; this can be overridden when desired. * Add back extension compilation step * Include missing resources in release This includes a favicon, for example. I opted to include the entire directory to make sure we do not miss anything. Some of the other stuff looks potentially useful (like completions). * Set quality property in product configuration When httpWebWorkerExtensionHostIframe.html is fetched it uses the web endpoint template (in which we do not include the commit) but if the quality is not set it prepends the commit to the web endpoint instead. The new static endpoint does not use/handle commits so this 404s. Long-term we might want to make the new static endpoint use commits like the old one but we will also need to update the various other static URLs to include the commit. For now I just fixed this by adding the quality since: 1. Probably faster than trying to find and update all static uses. 2. VS Code probably expects it anyway. 3. Gives us better control over the endpoint. * Update VS Code This fixes several build issues. * Bump vscode. * Bump. * Bump. * Use CLI directly. * Update tests to reflect new upstream behavior. * Move unit tests to after the build Our code has new dependencies on VS Code that are pulled in when the unit tests run. Because of this we need to build VS Code before running the unit tests (as it only pulls built code). * Upgrade proxy-agent dependencies This resolves a security report with one of its dependencies (vm2). * Symlink VS Code output directory before unit tests This is necessary now that we import from the out directory. * Fix issues surrounding persistent processes between tests. * Update VS Code cache directories These were renamed so the cached paths need to be updated. I changed the key as well to force a rebuild. * Move test symlink to script This way it works for local testing as well. I had to use out-build instead of out-vscode-server-min because Jest throws some obscure error about a handlebars haste map. * Fix listening on a socket * Update VS Code It contains fixes for missing files in the build. * Standardize disposals * Dispose HTTP server Shares code with the test HTTP server. For now it is a function but maybe we should make it a class that is extended by tests. * Dispose app on exit * Fix logging link errors Unfortunately the logger currently chokes when provided with error objects. Also for some reason the bracketed text was not displaying... * Update regex used by e2e to extract address The address was recently changed to use URL which seems to add a trailing slash when using toString, causing the regex match to fail. * Log browser console in e2e tests * Add base back to login page This is used to set cookies when using a base path. * Remove login page test The file this was testing no longer exists. * Use path.posix for static base Since this is a web path and not platform-dependent. * Add test for invalid password Co-authored-by: Teffen Ellis <teffen@nirri.us> Co-authored-by: Asher <ash@coder.com>
2021-10-28 22:27:17 +02:00
export const open = async (address: URL | string): Promise<void> => {
if (typeof address === "string") {
throw new Error("Cannot open socket paths")
}
// Web sockets do not seem to work if browsing with 0.0.0.0.
const url = new URL(address)
if (url.hostname === "0.0.0.0") {
url.hostname = "localhost"
}
2020-02-04 20:27:46 +01:00
const args = [] as string[]
const options = {} as cp.SpawnOptions
const platform = (await isWsl()) ? "wsl" : process.platform
let command = platform === "darwin" ? "open" : "xdg-open"
if (platform === "win32" || platform === "wsl") {
command = platform === "wsl" ? "cmd.exe" : "cmd"
args.push("/c", "start", '""', "/b")
fix(testing): revert change & fix playwright tests (#4310) * fix(testing): revert change & fix playwright tests * fix(constants): add type to import statement * refactor(e2e): delete browser test This test was originally added to ensure playwright was working. At this point, we know it works so removing this test because it doesn't help with anything specific to code-server and only adds unnecessary code to the codebase plus increases the e2e test job duration. * chore(e2e): use 1 worker for e2e test I don't know if it's a resources issue, playwright, or code-server but it seems like the e2e tests choke when multiple workers are used. This change is okay because our CI runner only has 2 cores so it would only use 1 worker anyway, but by specifying it in our playwright config, we ensure more stability in our e2e tests working correctly. See these PRs: - https://github.com/cdr/code-server/pull/3263 - https://github.com/cdr/code-server/pull/4310 * revert(vscode): add missing route with redirect * chore(vscode): update to latest fork * Touch up compilation step. * Bump vendor. * Fix VS Code minification step * Move ClientConfiguration to common Common code must not import Node code as it is imported by the browser. * Ensure lib directory exists before curling cURL errors now because VS Code was moved and the directory does not exist. * Update incorrect e2e test help output Revert workers change as well; this can be overridden when desired. * Add back extension compilation step * Include missing resources in release This includes a favicon, for example. I opted to include the entire directory to make sure we do not miss anything. Some of the other stuff looks potentially useful (like completions). * Set quality property in product configuration When httpWebWorkerExtensionHostIframe.html is fetched it uses the web endpoint template (in which we do not include the commit) but if the quality is not set it prepends the commit to the web endpoint instead. The new static endpoint does not use/handle commits so this 404s. Long-term we might want to make the new static endpoint use commits like the old one but we will also need to update the various other static URLs to include the commit. For now I just fixed this by adding the quality since: 1. Probably faster than trying to find and update all static uses. 2. VS Code probably expects it anyway. 3. Gives us better control over the endpoint. * Update VS Code This fixes several build issues. * Bump vscode. * Bump. * Bump. * Use CLI directly. * Update tests to reflect new upstream behavior. * Move unit tests to after the build Our code has new dependencies on VS Code that are pulled in when the unit tests run. Because of this we need to build VS Code before running the unit tests (as it only pulls built code). * Upgrade proxy-agent dependencies This resolves a security report with one of its dependencies (vm2). * Symlink VS Code output directory before unit tests This is necessary now that we import from the out directory. * Fix issues surrounding persistent processes between tests. * Update VS Code cache directories These were renamed so the cached paths need to be updated. I changed the key as well to force a rebuild. * Move test symlink to script This way it works for local testing as well. I had to use out-build instead of out-vscode-server-min because Jest throws some obscure error about a handlebars haste map. * Fix listening on a socket * Update VS Code It contains fixes for missing files in the build. * Standardize disposals * Dispose HTTP server Shares code with the test HTTP server. For now it is a function but maybe we should make it a class that is extended by tests. * Dispose app on exit * Fix logging link errors Unfortunately the logger currently chokes when provided with error objects. Also for some reason the bracketed text was not displaying... * Update regex used by e2e to extract address The address was recently changed to use URL which seems to add a trailing slash when using toString, causing the regex match to fail. * Log browser console in e2e tests * Add base back to login page This is used to set cookies when using a base path. * Remove login page test The file this was testing no longer exists. * Use path.posix for static base Since this is a web path and not platform-dependent. * Add test for invalid password Co-authored-by: Teffen Ellis <teffen@nirri.us> Co-authored-by: Asher <ash@coder.com>
2021-10-28 22:27:17 +02:00
url.search = url.search.replace(/&/g, "^&")
2020-02-04 20:27:46 +01:00
}
fix(testing): revert change & fix playwright tests (#4310) * fix(testing): revert change & fix playwright tests * fix(constants): add type to import statement * refactor(e2e): delete browser test This test was originally added to ensure playwright was working. At this point, we know it works so removing this test because it doesn't help with anything specific to code-server and only adds unnecessary code to the codebase plus increases the e2e test job duration. * chore(e2e): use 1 worker for e2e test I don't know if it's a resources issue, playwright, or code-server but it seems like the e2e tests choke when multiple workers are used. This change is okay because our CI runner only has 2 cores so it would only use 1 worker anyway, but by specifying it in our playwright config, we ensure more stability in our e2e tests working correctly. See these PRs: - https://github.com/cdr/code-server/pull/3263 - https://github.com/cdr/code-server/pull/4310 * revert(vscode): add missing route with redirect * chore(vscode): update to latest fork * Touch up compilation step. * Bump vendor. * Fix VS Code minification step * Move ClientConfiguration to common Common code must not import Node code as it is imported by the browser. * Ensure lib directory exists before curling cURL errors now because VS Code was moved and the directory does not exist. * Update incorrect e2e test help output Revert workers change as well; this can be overridden when desired. * Add back extension compilation step * Include missing resources in release This includes a favicon, for example. I opted to include the entire directory to make sure we do not miss anything. Some of the other stuff looks potentially useful (like completions). * Set quality property in product configuration When httpWebWorkerExtensionHostIframe.html is fetched it uses the web endpoint template (in which we do not include the commit) but if the quality is not set it prepends the commit to the web endpoint instead. The new static endpoint does not use/handle commits so this 404s. Long-term we might want to make the new static endpoint use commits like the old one but we will also need to update the various other static URLs to include the commit. For now I just fixed this by adding the quality since: 1. Probably faster than trying to find and update all static uses. 2. VS Code probably expects it anyway. 3. Gives us better control over the endpoint. * Update VS Code This fixes several build issues. * Bump vscode. * Bump. * Bump. * Use CLI directly. * Update tests to reflect new upstream behavior. * Move unit tests to after the build Our code has new dependencies on VS Code that are pulled in when the unit tests run. Because of this we need to build VS Code before running the unit tests (as it only pulls built code). * Upgrade proxy-agent dependencies This resolves a security report with one of its dependencies (vm2). * Symlink VS Code output directory before unit tests This is necessary now that we import from the out directory. * Fix issues surrounding persistent processes between tests. * Update VS Code cache directories These were renamed so the cached paths need to be updated. I changed the key as well to force a rebuild. * Move test symlink to script This way it works for local testing as well. I had to use out-build instead of out-vscode-server-min because Jest throws some obscure error about a handlebars haste map. * Fix listening on a socket * Update VS Code It contains fixes for missing files in the build. * Standardize disposals * Dispose HTTP server Shares code with the test HTTP server. For now it is a function but maybe we should make it a class that is extended by tests. * Dispose app on exit * Fix logging link errors Unfortunately the logger currently chokes when provided with error objects. Also for some reason the bracketed text was not displaying... * Update regex used by e2e to extract address The address was recently changed to use URL which seems to add a trailing slash when using toString, causing the regex match to fail. * Log browser console in e2e tests * Add base back to login page This is used to set cookies when using a base path. * Remove login page test The file this was testing no longer exists. * Use path.posix for static base Since this is a web path and not platform-dependent. * Add test for invalid password Co-authored-by: Teffen Ellis <teffen@nirri.us> Co-authored-by: Asher <ash@coder.com>
2021-10-28 22:27:17 +02:00
const proc = cp.spawn(command, [...args, url.toString()], options)
await new Promise<void>((resolve, reject) => {
2020-02-04 20:27:46 +01:00
proc.on("error", reject)
proc.on("close", (code) => {
return code !== 0 ? reject(new Error(`Failed to open with code ${code}`)) : resolve()
})
})
}
2019-07-17 02:26:05 +02:00
2020-02-04 20:27:46 +01:00
/**
* For iterating over an enum's values.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2019-08-10 01:50:05 +02:00
export const enumToArray = (t: any): string[] => {
2020-02-04 20:27:46 +01:00
const values = [] as string[]
for (const k in t) {
values.push(t[k])
}
return values
}
2019-08-10 01:50:05 +02:00
2020-02-04 20:27:46 +01:00
/**
* For displaying all allowed options in an enum.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2019-08-10 01:50:05 +02:00
export const buildAllowedMessage = (t: any): string => {
2020-02-04 20:27:46 +01:00
const values = enumToArray(t)
return `Allowed value${values.length === 1 ? " is" : "s are"} ${values.map((t) => `'${t}'`).join(", ")}`
}
export const isObject = <T extends object>(obj: T): obj is T => {
return !Array.isArray(obj) && typeof obj === "object" && obj !== null
}
2020-09-15 23:51:43 +02:00
/**
* Return a promise that resolves with whether the socket path is active.
*/
export function canConnect(path: string): Promise<boolean> {
return new Promise((resolve) => {
const socket = net.connect(path)
socket.once("error", () => resolve(false))
socket.once("connect", () => {
socket.destroy()
resolve(true)
})
})
}
export const isFile = async (path: string): Promise<boolean> => {
try {
const stat = await fs.stat(path)
return stat.isFile()
} catch (error) {
return false
}
}
/**
* Escapes any HTML string special characters, like &, <, >, ", and '.
*
* Source: https://stackoverflow.com/a/6234804/3015595
**/
export function escapeHtml(unsafe: string): string {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;")
}
2021-09-13 23:35:12 +02:00
/**
* A helper function which returns a boolean indicating whether
* the given error is a NodeJS.ErrnoException by checking if
* it has a .code property.
*/
export function isNodeJSErrnoException(error: unknown): error is NodeJS.ErrnoException {
return error instanceof Error && (error as NodeJS.ErrnoException).code !== undefined
}
// TODO: Replace with proper templating system.
export const escapeJSON = (value: cp.Serializable) => JSON.stringify(value).replace(/"/g, "&quot;")
type AMDModule<T> = { [exportName: string]: T }
/**
* Loads AMD module, typically from a compiled VSCode bundle.
*
* @deprecated This should be gradually phased out as code-server migrates to lib/vscode
* @param amdPath Path to module relative to lib/vscode
* @param exportName Given name of export in the file
*/
export const loadAMDModule = async <T>(amdPath: string, exportName: string): Promise<T> => {
const module = await new Promise<AMDModule<T>>((resolve, reject) => {
require(path.join(vsRootPath, "out/bootstrap-amd")).load(amdPath, resolve, reject)
})
return module[exportName] as T
}