Merge pull request #857 from cdr/web

[v2] Rewrite code-server to use new web stuff
This commit is contained in:
Asher 2019-09-12 11:59:19 -05:00 committed by GitHub
commit c3c50e9a6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
325 changed files with 5673 additions and 40707 deletions

View File

@ -1,9 +1,10 @@
Dockerfile
# Docs
doc/
# GitHub stuff
build
deployment
doc
.github
.gitignore
.node-version
.travis.yml
LICENSE
README.md

7
.gitignore vendored
View File

@ -1,8 +1,3 @@
/lib
node_modules
dist
out
.DS_Store
build
release
.vscode
.cache

View File

@ -1 +1 @@
10.15.1
10.16.0

1
.npmrc Normal file
View File

@ -0,0 +1 @@
scripts-prepend-node-path=true

View File

@ -1,6 +1,6 @@
language: node_js
node_js:
- 10.15.1
- 10.16.0
services:
- docker
matrix:
@ -8,20 +8,19 @@ matrix:
- os: linux
dist: trusty
env:
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION" TARGET="centos"
- VSCODE_VERSION="e8fc7db0d1e3f3a94b1cdcc136d146134b7a4c9a" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux"
- os: linux
dist: trusty
env:
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION" TARGET="alpine"
- VSCODE_VERSION="e8fc7db0d1e3f3a94b1cdcc136d146134b7a4c9a" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine"
- os: osx
env:
- VSCODE_VERSION="1.33.1" MAJOR_VERSION="1" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER-vsc$VSCODE_VERSION"
- VSCODE_VERSION="e8fc7db0d1e3f3a94b1cdcc136d146134b7a4c9a" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install libxkbfile-dev
libsecret-1-dev; fi
- npm install -g yarn@1.12.3
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export PACKAGE="true"; fi
script:
- scripts/build.sh
- scripts/ci.bash
before_deploy:
- echo "$VERSION" "$TRAVIS_COMMIT"
- git config --local user.name "$USER_NAME"

View File

@ -1,4 +1,6 @@
FROM node:10.15.1
FROM node:10.16.0
ARG codeServerVersion=docker
ARG vscodeVersion
# Install VS Code's deps. These are the only two it seems we need.
RUN apt-get update && apt-get install -y \
@ -11,9 +13,10 @@ RUN npm install -g yarn@1.13
WORKDIR /src
COPY . .
# In the future, we can use https://github.com/yarnpkg/rfcs/pull/53 to make yarn use the node_modules
# directly which should be fast as it is slow because it populates its own cache every time.
RUN yarn && NODE_ENV=production yarn task build:server:binary
RUN yarn \
&& MINIFY=true yarn build "${vscodeVersion}" "${codeServerVersion}" \
&& yarn binary "${vscodeVersion}" "${codeServerVersion}" \
&& mv "/src/build/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x86_64-built/code-server${codeServerVersion}-vsc${vscodeVersion}-linux-x86_64" /src/build/code-server
# We deploy with ubuntu so that devs have a familiar environment.
FROM ubuntu:18.04
@ -30,7 +33,7 @@ RUN apt-get update && apt-get install -y \
wget
RUN locale-gen en_US.UTF-8
# We unfortunately cannot use update-locale because docker will not use the env variables
# We cannot use update-locale because docker will not use the env variables
# configured in /etc/default/locale so we need to set it manually.
ENV LC_ALL=en_US.UTF-8
@ -38,16 +41,17 @@ RUN adduser --gecos '' --disabled-password coder && \
echo "coder ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/nopasswd
USER coder
# We create first instead of just using WORKDIR as when WORKDIR creates, the user is root.
# We create first instead of just using WORKDIR as when WORKDIR creates, the
# user is root.
RUN mkdir -p /home/coder/project
WORKDIR /home/coder/project
# This assures we have a volume mounted even if the user forgot to do bind mount.
# So that they do not lose their data if they delete the container.
# This ensures we have a volume mounted even if the user forgot to do bind
# mount. So that they do not lose their data if they delete the container.
VOLUME [ "/home/coder/project" ]
COPY --from=0 /src/packages/server/cli-linux-x64 /usr/local/bin/code-server
EXPOSE 8443
COPY --from=0 /src/build/code-server /usr/local/bin/code-server
EXPOSE 8080
ENTRYPOINT ["dumb-init", "code-server"]
ENTRYPOINT ["dumb-init", "code-server", "--host", "0.0.0.0"]

147
README.md
View File

@ -1,92 +1,133 @@
# code-server [!["Open Issues"](https://img.shields.io/github/issues-raw/cdr/code-server.svg)](https://github.com/cdr/code-server/issues) [!["Latest Release"](https://img.shields.io/github/release/cdr/code-server.svg)](https://github.com/cdr/code-server/releases/latest) [![MIT license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cdr/code-server/blob/master/LICENSE) [![Discord](https://img.shields.io/discord/463752820026376202.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/zxSwN8Z)
# code-server · [![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/cdr/code-server/blob/master/LICENSE) [!["Latest Release"](https://img.shields.io/github/release/cdr/code-server.svg)](https://github.com/cdr/code-server/releases/latest) [![Build Status](https://img.shields.io/travis/com/cdr/code-server/master)](https://github.com/cdr/code-server)
**code-server v2 is almost out!**
[Get the preview here](https://github.com/cdr/code-server/releases).
(Linux builds only at the moment.)
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a remote server, accessible through the browser.
`code-server` is [VS Code](https://github.com/Microsoft/vscode) running on a
remote server, accessible through the browser.
Try it out:
```bash
docker run -it -p 127.0.0.1:8443:8443 -v "${HOME}/.local/share/code-server:/home/coder/.local/share/code-server" -v "${PWD}:/home/coder/project" codercom/code-server --allow-http --no-auth
docker run -it -p 127.0.0.1:8080:8080 -v "${HOME}/.local/share/code-server:/home/coder/.local/share/code-server" -v "$PWD:/home/coder/project" codercom/code-server
```
- Code on your Chromebook, tablet, and laptop with a consistent dev environment.
- If you have a Windows or Mac workstation, more easily develop for Linux.
- Take advantage of large cloud servers to speed up tests, compilations, downloads, and more.
- Preserve battery life when you're on the go.
- All intensive computation runs on your server.
- You're no longer running excess instances of Chrome.
- **Consistent environment:** Code on your Chromebook, tablet, and laptop with a
consistent dev environment. develop more easily for Linux if you have a
Windows or Mac, and pick up where you left off when switching workstations.
- **Server-powered:** Take advantage of large cloud servers to speed up tests,
compilations, downloads, and more. Preserve battery life when you're on the go
since all intensive computation runs on your server.
![Screenshot](/doc/assets/ide.png)
![Screenshot](/doc/assets/ide.gif)
## Getting Started
[![Create a Droplet](./doc/assets/do-new-droplet-btn.svg)](https://marketplace.digitalocean.com/apps/code-server?action=deploy)
### Run over SSH
Use [sshcode](https://github.com/codercom/sshcode) for a simple setup.
### Docker
See the Docker one-liner mentioned above. Dockerfile is at [/Dockerfile](/Dockerfile).
See docker oneliner mentioned above. Dockerfile is at [/Dockerfile](/Dockerfile).
To debug Golang using the
[ms-vscode-go extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go),
you need to add `--security-opt seccomp=unconfined` to your `docker run`
arguments when launching code-server with Docker. See
[#725](https://github.com/cdr/code-server/issues/725) for details.
### Binaries
1. [Download a binary](https://github.com/cdr/code-server/releases). (Linux and
OS X supported. Windows coming soon)
2. Unpack the downloaded file then run the binary.
3. In your browser navigate to `localhost:8080`.
1. [Download a binary](https://github.com/cdr/code-server/releases) (Linux and OS X supported. Windows coming soon)
2. Start the binary with the project directory as the first argument
- For self-hosting and other information see [doc/quickstart.md](doc/quickstart.md).
- For hosting on cloud platforms see [doc/deploy.md](doc/deploy.md).
```
code-server <initial directory to open>
```
> You will be prompted to enter the password shown in the CLI
`code-server` should now be running at https://localhost:8443.
> code-server uses a self-signed SSL certificate that may prompt your browser to ask you some additional questions before you proceed. Please [read here](doc/self-hosted/index.md) for more information.
For detailed instructions and troubleshooting, see the [self-hosted quick start guide](doc/self-hosted/index.md).
Quickstart guides for [Google Cloud](doc/admin/install/google_cloud.md), [AWS](doc/admin/install/aws.md), and [DigitalOcean](doc/admin/install/digitalocean.md).
How to [secure your setup](/doc/security/ssl.md).
## Development
### Known Issues
### Build
- If you also plan on developing, set the `OUT` environment variable. Otherwise
it will build in this directory which will cause issues because `yarn watch`
will try to compile the build directory as well.
- For now `@coder/nbin` is a global dependency.
- Run `yarn build ${vscodeVersion} ${codeServerVersion}` in this directory (for
example: `yarn build 1.36.0 development`).
- If you target the same VS Code version our Travis builds do everything will
work but if you target some other version it might not (we have to do some
patching to VS Code so different versions aren't always compatible).
- You can run the built code with `node path/to/build/out/vs/server/main.js` or run
`yarn binary` with the same arguments in the previous step to package the
code into a single binary.
## Known Issues
- Uploading .vsix files doesn't work.
- Creating custom VS Code extensions and debugging them doesn't work.
- To debug Golang using [ms-vscode-go extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go), you need to add `--security-opt seccomp=unconfined` to your `docker run` arguments when launching code-server with Docker. See [#725](https://github.com/cdr/code-server/issues/725) for details.
- Extension profiling and tips are currently disabled.
### Future
## Future
- **Stay up to date!** Get notified about new releases of code-server.
![Screenshot](/doc/assets/release.gif)
- Windows support.
- Electron and Chrome OS applications to bridge the gap between local<->remote.
- Run VS Code unit tests against our builds to ensure features work as expected.
### Extensions
At the moment we can't use the official VSCode Marketplace. We've created a custom extension marketplace focused around open-sourced extensions. However, if you have access to the `.vsix` file, you can manually install the extension.
## Extensions
At the moment we can't use the official VS Code Marketplace. We've created a
custom extension marketplace focused around open-sourced extensions. However,
you can manually download the extension to your extensions directory. It's also
possible to set your own marketplace URLs by setting the `SERVICE_URL` and
`ITEM_URL` environment variables.
## Telemetry
Use the `--disable-telemetry` flag or set `DISABLE_TELEMETRY=true` to disable tracking ENTIRELY.
We use data collected to improve code-server.
Use the `--disable-telemetry` flag to completely disable telemetry. We use the
data collected to improve code-server.
## Contributing
### Development
```shell
git clone https://github.com/microsoft/vscode
cd vscode
git checkout <see travis.yml for the VS Code version to use here>
git clone https://github.com/cdr/code-server src/vs/server
cd src/vs/server
yarn patch:apply
yarn
yarn watch
# Wait for the initial compilation to complete (it will say "Finished compilation").
# Run the next command in another shell.
yarn start
# Visit http://localhost:8080
```
Development guides are coming soon.
If you run into issues about a different version of Node being used, try running
`npm rebuild` in the VS Code directory and ignore the error at the end from
`vscode-ripgrep`.
### Upgrading VS Code
We patch VS Code to provide and fix some functionality. As the web portion of VS
Code matures, we'll be able to shrink and maybe even entirely eliminate our
patch. In the meantime, however, upgrading the VS Code version requires ensuring
that the patch still applies and has the intended effects.
To generate a new patch, **stage all the changes** you want to be included in
the patch in the VS Code source, then run `yarn patch:generate` in this
directory.
Our changes include:
- Change the remote schema to `code-server`.
- Allow multiple extension directories (both user and built-in).
- Modify the loader, websocket, webview, service worker, and asset requests to
use the URL of the page as a base (and TLS if necessary for the websocket).
- Send client-side telemetry through the server and get the initial log level
from the server.
- Add an upload service for use in editor windows and the explorer along with a
file prefix to ignore for temporary files created during upload.
- Make changing the display language work.
- Make hiding or toggling the menu bar possible.
- Make it possible for us to load code on the client.
- Modify the build process to include our code.
## License
[MIT](LICENSE)
## Enterprise
Visit [our website](https://coder.com/) for more information about our enterprise offering.
Visit [our enterprise page](https://coder.com/enterprise) for more information
about our enterprise offering.
## Commercialization
If you would like to commercialize code-server, please contact contact@coder.com.
If you would like to commercialize code-server, please contact
contact@coder.com.

View File

@ -1,42 +0,0 @@
/**
* Script that detects platform name and arch.
* Cannot use os.platform() as that won't detect libc version
*/
import * as cp from "child_process";
import * as fs from "fs";
import * as os from "os";
enum Lib {
GLIBC,
MUSL,
}
const CLIB: Lib | undefined = ((): Lib | undefined => {
if (os.platform() !== "linux") {
return;
}
const glibc = cp.spawnSync("getconf", ["GNU_LIBC_VERSION"]);
if (glibc.status === 0) {
return Lib.GLIBC;
}
const ldd = cp.spawnSync("ldd", ["--version"]);
if (ldd.stdout && ldd.stdout.indexOf("musl") !== -1) {
return Lib.MUSL;
}
const muslFile = fs.readdirSync("/lib").find((value) => value.startsWith("libc.musl"));
if (muslFile) {
return Lib.MUSL;
}
return Lib.GLIBC;
})();
export const platform = (): NodeJS.Platform | "musl" => {
if (CLIB === Lib.MUSL) {
return "musl";
}
return os.platform();
};

View File

@ -1,211 +0,0 @@
import { register, run } from "@coder/runner";
import { logger, field } from "@coder/logger";
import * as fs from "fs";
import * as fse from "fs-extra";
import * as os from "os";
import { platform } from "./platform";
import * as path from "path";
import * as zlib from "zlib";
import * as https from "https";
import * as tar from "tar";
const isWin = os.platform() === "win32";
const libPath = path.join(__dirname, "../lib");
const vscodePath = path.join(libPath, "vscode");
const defaultExtensionsPath = path.join(libPath, "extensions");
const pkgsPath = path.join(__dirname, "../packages");
const vscodeVersion = process.env.VSCODE_VERSION || "1.33.1";
const vsSourceUrl = `https://codesrv-ci.cdr.sh/vstar-${vscodeVersion}.tar.gz`;
const buildServerBinary = register("build:server:binary", async (runner) => {
logger.info("Building with environment", field("env", {
NODE_ENV: process.env.NODE_ENV,
VERSION: process.env.VERSION,
OSTYPE: process.env.OSTYPE,
TARGET: process.env.TARGET,
}));
await ensureInstalled();
await Promise.all([
buildBootstrapFork(),
buildWeb(),
buildServerBundle(),
buildAppBrowser(),
]);
await buildServerBinaryPackage();
});
const buildServerBinaryPackage = register("build:server:binary:package", async (runner) => {
const cliPath = path.join(pkgsPath, "server");
runner.cwd = cliPath;
if (!fs.existsSync(path.join(cliPath, "out"))) {
throw new Error("Cannot build binary without server bundle built");
}
await buildServerBinaryCopy();
const resp = await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build:binary"]);
if (resp.exitCode !== 0) {
throw new Error(`Failed to package binary: ${resp.stderr}`);
}
});
const buildServerBinaryCopy = register("build:server:binary:copy", async (runner) => {
const cliPath = path.join(pkgsPath, "server");
const cliBuildPath = path.join(cliPath, "build");
fse.removeSync(cliBuildPath);
fse.mkdirpSync(path.join(cliBuildPath, "extensions"));
const bootstrapForkPath = path.join(pkgsPath, "vscode", "out", "bootstrap-fork.js");
const webOutputPath = path.join(pkgsPath, "web", "out");
const browserAppOutputPath = path.join(pkgsPath, "app", "browser", "out");
let ripgrepPath = path.join(pkgsPath, "..", "lib", "vscode", "node_modules", "vscode-ripgrep", "bin", "rg");
if (isWin) {
ripgrepPath += ".exe";
}
if (!fs.existsSync(webOutputPath)) {
throw new Error("Web bundle must be built");
}
if (!fs.existsSync(defaultExtensionsPath)) {
throw new Error("Default extensions must be built");
}
if (!fs.existsSync(bootstrapForkPath)) {
throw new Error("Bootstrap fork must exist");
}
if (!fs.existsSync(ripgrepPath)) {
throw new Error("Ripgrep must exist");
}
fse.copySync(defaultExtensionsPath, path.join(cliBuildPath, "extensions"));
fs.writeFileSync(path.join(cliBuildPath, "bootstrap-fork.js.gz"), zlib.gzipSync(fs.readFileSync(bootstrapForkPath)));
const cpDir = (dir: string, rootPath: string, subdir?: "login"): void => {
const stat = fs.statSync(dir);
if (stat.isDirectory()) {
const paths = fs.readdirSync(dir);
paths.forEach((p) => cpDir(path.join(dir, p), rootPath, subdir));
} else if (stat.isFile()) {
const newPath = path.join(cliBuildPath, "web", subdir || "", path.relative(rootPath, dir));
fse.mkdirpSync(path.dirname(newPath));
fs.writeFileSync(newPath + ".gz", zlib.gzipSync(fs.readFileSync(dir)));
} else {
// Nothing
}
};
cpDir(webOutputPath, webOutputPath);
cpDir(browserAppOutputPath, browserAppOutputPath, "login");
fse.mkdirpSync(path.join(cliBuildPath, "dependencies"));
fse.copySync(ripgrepPath, path.join(cliBuildPath, "dependencies", "rg"));
});
const buildServerBundle = register("build:server:bundle", async (runner) => {
const cliPath = path.join(pkgsPath, "server");
runner.cwd = cliPath;
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
});
const buildBootstrapFork = register("build:bootstrap-fork", async (runner) => {
await ensureInstalled();
await ensurePatched();
const vscodePkgPath = path.join(pkgsPath, "vscode");
runner.cwd = vscodePkgPath;
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build:bootstrap-fork"]);
});
const buildAppBrowser = register("build:app:browser", async (runner) => {
await ensureInstalled();
const appPath = path.join(pkgsPath, "app/browser");
runner.cwd = appPath;
fse.removeSync(path.join(appPath, "out"));
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
});
const buildWeb = register("build:web", async (runner) => {
await ensureInstalled();
await ensurePatched();
const webPath = path.join(pkgsPath, "web");
runner.cwd = webPath;
fse.removeSync(path.join(webPath, "out"));
await runner.execute(isWin ? "npm.cmd" : "npm", ["run", "build"]);
});
const ensureInstalled = register("vscode:install", async (runner) => {
runner.cwd = libPath;
if (fs.existsSync(vscodePath) && fs.existsSync(defaultExtensionsPath)) {
const pkgVersion = JSON.parse(fs.readFileSync(path.join(vscodePath, "package.json")).toString("utf8")).version;
if (pkgVersion === vscodeVersion) {
runner.cwd = vscodePath;
const reset = await runner.execute("git", ["reset", "--hard"]);
if (reset.exitCode !== 0) {
throw new Error(`Failed to clean git repository: ${reset.stderr}`);
}
return;
}
}
fse.removeSync(libPath);
fse.mkdirpSync(libPath);
await new Promise<void>((resolve, reject): void => {
https.get(vsSourceUrl, (res) => {
if (res.statusCode !== 200) {
return reject(res.statusMessage);
}
res.pipe(tar.x({
C: libPath,
}).on("finish", () => {
resolve();
}).on("error", (err: Error) => {
reject(err);
}));
}).on("error", (err) => {
reject(err);
});
});
});
const ensurePatched = register("vscode:patch", async (runner) => {
if (!fs.existsSync(vscodePath)) {
throw new Error("vscode must be cloned to patch");
}
await ensureInstalled();
runner.cwd = vscodePath;
const patchPath = path.join(__dirname, "../scripts/vscode.patch");
const apply = await runner.execute("git", ["apply", "--unidiff-zero", patchPath]);
if (apply.exitCode !== 0) {
throw new Error(`Failed to apply patches: ${apply.stderr}`);
}
});
register("package", async (runner, releaseTag) => {
if (!releaseTag) {
throw new Error("Please specify the release tag.");
}
const releasePath = path.resolve(__dirname, "../release");
const archiveName = `code-server${releaseTag}-${platform()}-${os.arch()}`;
const archiveDir = path.join(releasePath, archiveName);
fse.removeSync(archiveDir);
fse.mkdirpSync(archiveDir);
const binaryPath = path.join(__dirname, `../packages/server/cli-${platform()}-${os.arch()}`);
const binaryDestination = path.join(archiveDir, "code-server");
fse.copySync(binaryPath, binaryDestination);
fs.chmodSync(binaryDestination, "755");
["README.md", "LICENSE"].forEach((fileName) => {
fse.copySync(path.resolve(__dirname, `../${fileName}`), path.join(archiveDir, fileName));
});
runner.cwd = releasePath;
await (os.platform() === "linux"
? runner.execute("tar", ["-cvzf", `${archiveName}.tar.gz`, `${archiveName}`])
: runner.execute("zip", ["-r", `${archiveName}.zip`, `${archiveName}`]));
});
run();

View File

@ -1,5 +0,0 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for code-server
name: code-server
version: 1.0.0

View File

@ -1,115 +0,0 @@
# code-server
[code-server](https://github.com/cdr/code-server) code-server is VS Code running
on a remote server, accessible through the browser.
## TL;DR;
```console
$ git clone https://github.com/cdr/code-server.git
$ helm install deployment/chart
```
## Introduction
This chart bootstraps a code-server deployment on a
[Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh)
package manager.
## Prerequisites
- Kubernetes 1.6+
## Installing the Chart
To install the chart with the release name `my-release`:
```console
$ helm install --name my-release deployment/chart
```
The command deploys code-server on the Kubernetes cluster in the default
configuration. The [configuration](#configuration) section lists the parameters
that can be configured during installation.
> **Tip**: List all releases using `helm list`
## Uninstalling the Chart
To uninstall/delete the `my-release` deployment:
```console
$ helm delete my-release
```
The command removes all the Kubernetes components associated with the chart and
deletes the release.
## Configuration
The following table lists the configurable parameters of the nginx-ingress chart
and their default values.
The following table lists the configurable parameters of the code-server chart
and their default values.
| Parameter | Description | Default |
| --------------------------------- | ------------------------------------------ | --------------------------------------------------------- |
| `image.registry` | Code-server image registry | `docker.io` |
| `image.repository` | Code-server Image name | `codercom/code-server` |
| `image.tag` | Code-server Image tag | `{TAG_NAME}` |
| `image.pullPolicy` | Code-server image pull policy | `IfNotPresent` |
| `nameOverride` | String to partially override code-server.fullname template with a string (will prepend the release name) | `nil` |
| `fullnameOverride` | String to fully override code-server.fullname template with a string |
| `hostnameOverride` | String to fully override code-server container hostname |
| `service.type` | Kubernetes Service type | `NodePort` |
| `service.port` | Service HTTP port | `8443` |
| `ingress.enabled` | Enable ingress controller resource | `false` |
| `ingress.hosts[0].name` | Hostname to your code-server installation | `code-server.local` |
| `ingress.hosts[0].path` | Path within the url structure | `/` |
| `ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` |
| `ingress.hosts[0].certManager` | Add annotations for cert-manager | `false` |
| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `code-server.local-tls-secret` |
| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` |
| `ingress.secrets[0].name` | TLS Secret Name | `nil` |
| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` |
| `ingress.secrets[0].key` | TLS Secret Key | `nil` |
| `extraArgs` | Additional code-server container arguments | `{}` |
| `extraVars` | Optional environment variables for code-server | `{}` |
| `volumePermissions.enabled` | Enable volume permissions init container | `true` |
| `volumePermissions.securityContext.runAsUser` | User ID for the init container | `0` |
| `securityContext.enabled` | Enable security context | `true` |
| `securityContext.fsGroup` | Group ID for the container | `1000` |
| `securityContext.runAsUser` | User ID for the container | `1000` |
| `resources` | CPU/Memory resource requests/limits | `{}` |
| `persistence.enabled` | Enable persistence using PVC | `true` |
| `persistence.storageClass` | PVC Storage Class for code-server volume | `nil` |
| `persistence.accessMode` | PVC Access Mode for code-server volume | `ReadWriteOnce` |
| `persistence.size` | PVC Storage Request for code-server volume | `8Gi` |
| `extraContainers` | Sidecar containers to add to the code-server pod | `{}` |
| `extraSecretMounts` | Additional code-server server secret mounts | `[]` |
| `extraVolumeMounts` | Additional code-server server volume mounts | `[]` |
| `extraConfigmapMounts` | Additional code-server server configMap volume mounts | `[]` |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm
install`. For example,
```console
$ helm install --name my-release \
--set persistence.enabled=false \
deployment/chart
```
The above command sets the the persistence storage to false.
Alternatively, a YAML file that specifies the values for the above parameters
can be provided while installing the chart. For example,
```console
$ helm install --name my-release -f values.yaml deployment/chart
```
> **Tip**: You can use the default [values.yaml](values.yaml)

View File

@ -1,25 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "code-server.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "code-server.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "code-server.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "code-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}
Administrator credentials:
Password : $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "code-server.fullname" . }} -o jsonpath="{.data.password}" | base64 --decode)

View File

@ -1,43 +0,0 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "code-server.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "code-server.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "code-server.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create the name of the service account to use
*/}}
{{- define "code-server.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "code-server.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}

View File

@ -1,144 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "code-server.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
{{- if .Values.hostnameOverride }}
hostname: {{ .Values.hostnameOverride }}
{{- end }}
{{- if .Values.securityContext.enabled }}
securityContext:
fsGroup: {{ .Values.securityContext.fsGroup }}
{{- end }}
{{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }}
initContainers:
- name: init-chmod-data
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
- sh
- -c
- |
chown -R {{ .Values.securityContext.runAsUser }}:{{ .Values.securityContext.fsGroup }} /home/coder
securityContext:
runAsUser: {{ .Values.volumePermissions.securityContext.runAsUser }}
volumeMounts:
- name: data
mountPath: /home/coder
{{- end }}
containers:
{{- if .Values.extraContainers }}
{{ toYaml .Values.extraContainers | indent 8}}
{{- end }}
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.securityContext.enabled }}
securityContext:
runAsUser: {{ .Values.securityContext.runAsUser }}
{{- end }}
env:
{{- if .Values.extraVars }}
{{ toYaml .Values.extraVars | indent 10 }}
{{- end }}
- name: PASSWORD
valueFrom:
secretKeyRef:
{{- if .Values.existingSecret }}
name: {{ .Values.existingSecret }}
{{- else }}
name: {{ template "code-server.fullname" . }}
{{- end }}
key: password
{{- if .Values.extraArgs }}
args:
{{ toYaml .Values.extraArgs | indent 10 }}
{{- end }}
volumeMounts:
- name: data
mountPath: /home/coder/project
subPath: project
- name: data
mountPath: /home/coder/.local/share/code-server
subPath: code-server
{{- range .Values.extraConfigmapMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
{{- range .Values.extraSecretMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
readOnly: {{ .readOnly }}
{{- end }}
{{- range .Values.extraVolumeMounts }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
subPath: {{ .subPath | default "" }}
readOnly: {{ .readOnly }}
{{- end }}
ports:
- name: http
containerPort: 8443
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "code-server.serviceAccountName" . }}
volumes:
- name: data
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (include "code-server.fullname" .) }}
{{- else }}
emptyDir: {}
{{- end -}}
{{- range .Values.extraSecretMounts }}
- name: {{ .name }}
secret:
secretName: {{ .secretName }}
defaultMode: {{ .defaultMode }}
{{- end }}
{{- range .Values.extraVolumeMounts }}
- name: {{ .name }}
persistentVolumeClaim:
claimName: {{ .existingClaim }}
{{- end }}

View File

@ -1,39 +0,0 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "code-server.fullname" . -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ . }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
{{- end }}

View File

@ -1,29 +0,0 @@
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ include "code-server.fullname" . }}
namespace: {{ .Release.Namespace }}
{{- with .Values.persistence.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistence.storageClass }}"
{{- end }}
{{- end }}
{{- end }}

View File

@ -1,18 +0,0 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ include "code-server.fullname" . }}
annotations:
"helm.sh/hook": "pre-install"
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
type: Opaque
data:
{{ if .Values.password }}
password: "{{ .Values.password | b64enc }}"
{{ else }}
password: "{{ randAlphaNum 24 | b64enc }}"
{{ end }}

View File

@ -1,19 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "code-server.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: {{ include "code-server.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}

View File

@ -1,11 +0,0 @@
{{- if or .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
name: {{ template "code-server.serviceAccountName" . }}
{{- end -}}

View File

@ -1,18 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "code-server.fullname" . }}-test-connection"
labels:
app.kubernetes.io/name: {{ include "code-server.name" . }}
helm.sh/chart: {{ include "code-server.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "code-server.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

View File

@ -1,135 +0,0 @@
# Default values for code-server.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
image:
repository: codercom/code-server
tag: 1.1156-vsc1.33.1
pullPolicy: Always
nameOverride: ""
fullnameOverride: ""
hostnameOverride: ""
service:
type: NodePort
port: 8443
ingress:
enabled: false
#annotations:
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
#hosts:
# - host: code-server.example.loc
# paths:
# - /
#tls:
# - secretName: code-server
# hosts:
# - code-server.example.loc
# Optional additional arguments
extraArgs: []
# - --allow-http
# - --no-auth
# Optional additional environment variables
extraVars: []
# - name: DISABLE_TELEMETRY
# value: true
##
## Init containers parameters:
## volumePermissions: Change the owner of the persist volume mountpoint to RunAsUser:fsGroup
##
volumePermissions:
enabled: true
securityContext:
runAsUser: 0
## Pod Security Context
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
##
securityContext:
enabled: true
fsGroup: 1000
runAsUser: 1000
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 1000Mi
nodeSelector: {}
tolerations: []
affinity: {}
## Persist data to a persistent volume
persistence:
enabled: true
## code-server data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
accessMode: ReadWriteOnce
size: 1Gi
annotations: {}
serviceAccount:
create: true
name:
## Enable an Specify container in extraContainers.
## This is meant to allow adding code-server dependencies, like docker-dind.
extraContainers: |
#- name: docker-dind
# image: docker:19.03-dind
# imagePullPolicy: IfNotPresent
# resources:
# requests:
# cpu: 250m
# memory: 256M
# securityContext:
# privileged: true
# procMount: Default
# env:
# - name: DOCKER_TLS_CERTDIR
# value: ""
# - name: DOCKER_DRIVER
# value: "overlay2"
## Additional code-server secret mounts
extraSecretMounts: []
# - name: secret-files
# mountPath: /etc/secrets
# secretName: code-server-secret-files
# readOnly: true
## Additional code-server volume mounts
extraVolumeMounts: []
# - name: extra-volume
# mountPath: /mnt/volume
# readOnly: true
# existingClaim: volume-claim
extraConfigmapMounts: []
# - name: certs-configmap
# mountPath: /etc/code-server/ssl/
# subPath: certificates.crt # (optional)
# configMap: certs-configmap
# readOnly: true

View File

@ -1,116 +0,0 @@
# Deploy on AWS EC2
This tutorial shows you how to deploy `code-server` on an AWS EC2 instance.
If you're just starting out, we recommend
[installing code-server locally](self-hosted-docs). It takes only a few minutes
and lets you try out all of the features locally.
If you get stuck or need help at anytime, [file an issue](create-issue),
[tweet (@coderhq)](twitter-coderhq) or [email](email-coder).
[self-hosted-docs]: ../../self-hosted/index.md
[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+AWS+quickstart+guide
[twitter-coderhq]: https://twitter.com/coderhq
[email-coder]: mailto:support@coder.com?subject=AWS%20quickstart%20guide
---
### Creating an Instance using the AWS Launch Wizard
1. Click **Launch Instance** from your [EC2 dashboard](ec2-home).
2. Select the "Ubuntu Server 18.04 LTS (HVM), SSD Volume Type" AMI..
3. Select an appropriate instance size (we recommend t2.medium/large, depending
on team size and number of repositories/languages enabled), then **Next:
Configure Instance Details**.
4. Select **Next: ...** until you get to the **Configure Security Group** page,
then add a **Custom TCP Rule** rule with port range set to `8443` and source
set to "Anywhere".
> Rules with source of 0.0.0.0/0 allow all IP addresses to access your
> instance. We recommend setting [security group rules](ec2-sg-docs) to allow
> access from known IP addresses only.
5. Click **Launch**.
6. You will be prompted to create a keypair.
> A key pair consists of a public key that AWS stores, and a private key file
> that you store. For Linux AMIs, the private key file allows you to
> securely SSH into your instance.
7. From the dropdown choose "create a new pair", give the key pair a name.
8. Click **Download Key Pair**. This is necessary before you proceed. A `.pem`
file will be downloaded. make sure you store is in a safe location because it
can't be retrieved once we move on.
9. Finally, click **Launch Instances**.
[ec2-home]: https://console.aws.amazon.com/ec2/v2/home
[ec2-sg-docs]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console
---
### Installing code-server onto an AWS Instance
1. First head to your [EC2 dashboard](ec2-home) and choose **Instances** on the
left sidebar.
2. Select the instance you just created, and in the description tab at the
bottom of the screen copy the **Public DNS (IPv4)** address using the copy to
clipboard button.
3. Open a terminal on your computer and use the following command to SSH into
your EC2 instance. If you're using Windows, you can use [PuTTY](putty-guide)
to open an SSH connection.
```
ssh -i "path/to/your/keypair.pem" ubuntu@(paste the public DNS here)
```
> For example: `ssh -i "/Users/John/Downloads/TestInstance.pem" ubuntu@ec2-3-45-678-910.compute-1.amazonaws.co`
4. If you get a warning about an unknown server key fingerprint, type "yes" to
approve the remote host.
5. You should see a prompt for your EC2 instance like so:
<img src="../../assets/aws_ubuntu.png">
6. At this point it is time to download the `code-server` binary. We will, of
course, want the linux version. Find the latest code-server release from the
[GitHub releases](code-server-latest) page.
7. Right click the Linux x64 `.tar.gz` release asset and copy the URL. In the
SSH terminal, run the following command:
```
wget (paste the URL here)
```
8. Extract the downloaded file with the following command:
```
tar -xvzf code-server*.tar.gz
```
9. Navigate to extracted directory with this command:
```
cd code-server*/
```
10. Ensure the code-server binary is executable with the following command:
```
chmod +x code-server
```
11. Finally, to start code-server run this command:
```
./code-server
```
12. code-server will start up, and the password will be printed in the output.
Make sure to copy the password for the next step.
13. Open your browser and visit `https://$public_ip:8443/` (where `$public_ip`
is your AWS instance's public IP address). You will be greeted with a page
similar to the following screenshot. code-server is using a self-signed SSL
certificate for easy setup. In Chrome/Chromium, click **Advanced** then
click **proceed anyway**. In Firefox, click **Advanced**, then **Add
Exception**, then finally **Confirm Security Exception**.
<img src="../../assets/chrome_warning.png">
[putty-guide]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/putty.html
[code-server-latest]: https://github.com/cdr/code-server/releases/latest
---
### Post Installation Steps
To ensure the connection between you and your server is encrypted, view our
guides on [securing your setup](security-guide).
For instructions on how to keep the server running after you end your SSH
session please checkout [how to use systemd](systemd-guide). systemd will run
code-server for you in the background as a service and restart it for you if it
crashes.
[security-guide]: ../../security/index.md
[systemd-guide]: https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples

View File

@ -1,125 +0,0 @@
# Deploy on DigitalOcean
This tutorial shows you how to deploy `code-server` to a single node running on DigitalOcean.
If you're just starting out, we recommend
[installing code-server locally](self-hosted-docs). It takes only a few minutes
and lets you try out all of the features locally.
If you get stuck or need help at anytime, [file an issue](create-issue),
[tweet (@coderhq)](twitter-coderhq) or [email](email-coder).
[self-hosted-docs]: ../../self-hosted/index.md
[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+DigitalOcean+quickstart+guide
[twitter-coderhq]: https://twitter.com/coderhq
[email-coder]: mailto:support@coder.com?subject=DigitalOcean%20quickstart%20guide
---
### Recommended: Using the Marketplace
[![Create a Droplet](../../assets/do-new-droplet-btn.svg)](https://marketplace.digitalocean.com/apps/code-server?action=deploy)
1. On the **Create Droplets** page, choose a plan for your new code-server
instance. We recommend picking an instance with at least 4 GB of RAM and 2
CPU cores, or more depending on team size and number of
repositories/languages enabled.
2. Optionally enable backups and add block storage.
3. Choose the closest available region to your physical location to reduce
latency.
4. Select an SSH key that you already have in your account, or click **New SSH
Key** and follow the tutorial on how to make your own SSH key.
5. Click **Create Droplet**, then click on the droplet to expand it.
6. While you're waiting for the droplet to deploy, copy the **IPv4** address.
7. Once the droplet is ready, connect using SSH with the key you specified or
created earlier. You should be greeted with information on how to access your
code-server instance and how to view/change the password.
> You can SSH into your server using PuTTY or by running
> `ssh root@(paste ipv4 address here)`.
8. In the droplet's terminal, run `cat /etc/code-server/pass` to view the
code-server password.
9. Open your browser and visit `https://$public_ip` (where `$public_ip`
is your Droplet's public IP address). You will be greeted with a page similar
to the following screenshot. code-server is using a self-signed SSL
certificate for easy setup. In Chrome/Chromium, click **Advanced** then
click **proceed anyway**. In Firefox, click **Advanced**, then **Add
Exception**, then finally **Confirm Security Exception**.
<img src="../../assets/chrome_warning.png">
---
### Using the "Create Droplets" Wizard
If you used the Marketplace to set up code-server, you don't need to follow this
section.
[Open your DigitalOcean dashboard](create-droplet) to create a new droplet.
1. **Choose an image:** Select the **Distributions** tab and then choose
**Ubuntu 18.04.3 (LTS) x64**.
2. **Choose a size:** We recommend at least 4GB RAM and 2 CPU, or more depending
on team size and number of repositories/languages enabled.
3. Select an SSH key that you already have in your account, or click **New SSH
Key** and follow the tutorial on how to make your own SSH key.
4. Click **Create Droplet**, then click on the droplet to expand it.
5. While you're waiting for the droplet to deploy, copy the **IPv4** address.
6. Once the droplet is ready, connect using SSH with the key you specified or
created earlier. You should be greeted with information on how to access your
code-server instance and how to view/change the password.
> You can SSH into your server using PuTTY or by running
> `ssh root@(paste ipv4 address here)`.
7. If you get a warning about an unknown server key fingerprint, type "yes" to
approve the remote host.
8. You should see a prompt for your Droplet like so:
<img src="../../assets/digitalocean_ubuntu.png">
9. At this point it is time to download the `code-server` binary. We will, of
course, want the linux version. Find the latest code-server release from the
[GitHub releases](code-server-latest) page.
10. Right click the Linux x64 `.tar.gz` release asset and copy the URL. In the
SSH terminal, run the following command:
```
wget (paste the URL here)
```
11. Extract the downloaded file with the following command:
```
tar -xvzf code-server*.tar.gz
```
12. Navigate to extracted directory with this command:
```
cd code-server*/
```
13. Ensure the code-server binary is executable with the following command:
```
chmod +x code-server
```
14. Finally, to start code-server run this command:
```
./code-server
```
12. code-server will start up, and the password will be printed in the output.
Make sure to copy the password for the next step.
13. Open your browser and visit `https://$public_ip:8443/` (where `$public_ip`
is your Droplet's public IP address). You will be greeted with a page
similar to the following screenshot. code-server is using a self-signed SSL
certificate for easy setup. In Chrome/Chromium, click **Advanced** then
click **proceed anyway**. In Firefox, click **Advanced**, then **Add
Exception**, then finally **Confirm Security Exception**.
<img src="../../assets/chrome_warning.png">
[create-droplet]: https://cloud.digitalocean.com/droplets/new
[code-server-latest]: https://github.com/cdr/code-server/releases/latest
---
### Post Installation Steps
To ensure the connection between you and your server is encrypted, view our
guides on [securing your setup](security-guide).
For instructions on how to keep the server running after you end your SSH
session please checkout [how to use systemd](systemd-guide). systemd will run
code-server for you in the background as a service and restart it for you if it
crashes. (Note: this doesn't apply for users of the Marketplace Droplet image.)
[security-guide]: ../../security/index.md
[systemd-guide]: https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples

View File

@ -1,101 +0,0 @@
# Deploy on Google Cloud Platform
This tutorial shows you how to deploy `code-server` to a single node running on
Google Cloud Platform.
If you're just starting out, we recommend
[installing code-server locally](self-hosted-docs). It takes only a few minutes
and lets you try out all of the features locally.
If you get stuck or need help at anytime, [file an issue](create-issue),
[tweet (@coderhq)](twitter-coderhq) or [email](email-coder).
[self-hosted-docs]: ../../self-hosted/index.md
[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+Google+Cloud+quickstart+guide
[twitter-coderhq]: https://twitter.com/coderhq
[email-coder]: mailto:support@coder.com?subject=Google%20Cloud%20quickstart%20guide
---
## Deploy to Google Cloud VM
[Open your Google Cloud console](create-instance) to create a new VM instance.
1. Click **Create Instance**.
2. Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, or
more depending on team size and number of repositories/languages enabled).
3. Choose **Ubuntu 16.04 LTS** as your boot disk.
4. Expand the **Management, security, disks, networking, sole tenancy** section,
go to the **Networking** tab, then under network tags add `code-server`.
5. Create your VM, and **take note** of its public IP address.
6. Visit **VPC networks** in the console and go to **Firewall rules**. Create a
new firewall rule called `http-8443`. Under **Target tags**, add
`code-server`, and under **Protocols and ports** tick **Specified protocols and
ports** and **tcp**. Beside **tcp**, add `8443`, then create the rule.
[create-instance]: https://console.cloud.google.com/compute/instances
---
## Final Steps
Please [set up Google Cloud SDK](gcloud-sdk) on your local machine, or access
your instance terminal using another method.
<!-- TODO: add a screenshot of the initial terminal like other guides -->
1. SSH into your Google Cloud VM:
```
gcloud compute ssh --zone [region] [instance name]
```
2. At this point it is time to download the `code-server` binary. We will, of
course, want the linux version. Find the latest code-server release from the
[GitHub releases](code-server-latest) page.
3. Right click the Linux x64 `.tar.gz` release asset and copy the URL. In the
SSH terminal, run the following command:
```
wget (paste the URL here)
```
4. Extract the downloaded file with the following command:
```
tar -xvzf code-server*.tar.gz
```
5. Navigate to extracted directory with this command:
```
cd code-server*/
```
6. Ensure the code-server binary is executable with the following command:
```
chmod +x code-server
```
7. Finally, to start code-server run this command:
```
./code-server
```
8. code-server will start up, and the password will be printed in the output.
Make sure to copy the password for the next step.
9. Open your browser and visit `https://$public_ip:8443/` (where `$public_ip`
is your Instance's public IP address). You will be greeted with a page
similar to the following screenshot. code-server is using a self-signed SSL
certificate for easy setup. In Chrome/Chromium, click **Advanced** then
click **proceed anyway**. In Firefox, click **Advanced**, then **Add
Exception**, then finally **Confirm Security Exception**.
<img src="../../assets/chrome_warning.png">
[gcloud-sdk]: https://cloud.google.com/sdk/docs/
[code-server-latest]: https://github.com/cdr/code-server/releases/latest
---
### Post Installation Steps
To ensure the connection between you and your server is encrypted, view our
guides on [securing your setup](security-guide).
For instructions on how to keep the server running after you end your SSH
session please checkout [how to use systemd](systemd-guide). systemd will run
code-server for you in the background as a service and restart it for you if it
crashes.
[security-guide]: ../../security/index.md
[systemd-guide]: https://www.digitalocean.com/community/tutorials/how-to-configure-a-linux-service-to-start-automatically-after-a-crash-or-reboot-part-1-practical-examples

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="200px" height="40px" viewBox="0 0 200 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>do-btn-blue-ghost</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Partner-welcome-kit-Copy-3" transform="translate(-651.000000, -828.000000)">
<g id="do-btn-blue-ghost" transform="translate(651.000000, 828.000000)">
<rect id="Rectangle-Copy-4" stroke="#0069FF" x="0.5" y="0.5" width="199" height="39" rx="6"></rect>
<path d="M6,0 L47,0 L47,40 L6,40 C2.6862915,40 4.05812251e-16,37.3137085 0,34 L-8.8817842e-16,6 C-1.29399067e-15,2.6862915 2.6862915,6.08718376e-16 6,0 Z" id="Rectangle-Copy-5" fill="#0069FF"></path>
<g id="DO_Logo_horizontal_blue-Copy-3" transform="translate(13.000000, 10.000000)" fill="#FFFFFF">
<path d="M10.0098493,20 L10.0098493,16.1262429 C14.12457,16.1262429 17.2897398,12.0548452 15.7269372,7.74627862 C15.1334679,6.14538921 13.8674,4.86072487 12.2650328,4.28756693 C7.952489,2.72620566 3.87733294,5.88845634 3.87733294,9.99938223 C3.87733294,9.99938223 3.87733294,9.99938223 3.87733294,9.99938223 L0,9.99938223 C0,3.45747613 6.3303395,-1.64165309 13.1948014,0.492866119 C16.2017127,1.42177726 18.57559,3.81322933 19.5053586,6.79760341 C21.6418482,13.6754986 16.5577943,20 10.0098493,20 Z" id="XMLID_49_"></path>
<polygon id="XMLID_47_" points="9.52380952 16.1904762 5.71428571 16.1904762 5.71428571 12.3809524 5.71428571 12.3809524 9.52380952 12.3809524 9.52380952 12.3809524"></polygon>
<polygon id="XMLID_46_" points="6.66666667 19.047619 3.80952381 19.047619 3.80952381 19.047619 3.80952381 16.1904762 6.66666667 16.1904762"></polygon>
<polygon id="XMLID_45_" points="3.80952381 16.1904762 0.952380952 16.1904762 0.952380952 16.1904762 0.952380952 13.3333333 0.952380952 13.3333333 3.80952381 13.3333333 3.80952381 13.3333333"></polygon>
</g>
<!-- Modified to add GitHub font-family after DigitalOcean's font-family, otherwise it looks bad on GitHub -->
<text id="Create-a-Droplet-Copy-3" font-family="Sailec-Medium, Sailec, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol" font-size="16" font-weight="400" fill="#0069FF">
<tspan x="58" y="26">Create a Droplet</tspan>
</text>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

BIN
doc/assets/ide.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 603 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

75
doc/cros-install.md Normal file
View File

@ -0,0 +1,75 @@
# Installing code-server in your ChromiumOS/ChromeOS/CloudReady machine
This guide will show you how to install code-server into your CrOS machine.
## Using Crostini
One of the easier ways to run code-server is via
[Crostini](https://www.aboutchromebooks.com/tag/project-crostini/), the Linux
apps support feature in CrOS. Make sure you have enough RAM, HDD space and your
CPU has VT-x/ AMD-V support. If your chromebook has this, then you are
qualified to use Crostini.
If you are running R69, you might want to enable this on
[Chrome Flags](chrome://flags/#enable-experimental-crostini-ui).
If you run R72, however, this is already enabled for you.
After checking your prerequisites, follow the steps in [the self-host install guide](index.md)
on installing code-server. Once done, make sure code-server works by running
it. After running it, simply go to `penguin.linux.test:8080` to access
code-server. Now you should be greeted with this screen. If you did,
congratulations, you have installed code-server in your Chromebook!
![code-server on Chromebook](assets/cros.png)
Alternatively, if you ran code-server in another container and you need the IP
for that specific container, simply go to Termina's shell via `crosh` and type
`vsh termina`.
```bash
Loading extra module: /usr/share/crosh/dev.d/50-crosh.sh
Welcome to crosh, the Chrome OS developer shell.
If you got here by mistake, don't panic! Just close this tab and carry on.
Type 'help' for a list of commands.
If you want to customize the look/behavior, you can use the options page.
Load it by using the Ctrl+Shift+P keyboard shortcut.
crosh> vsh termina
(termina) chronos@localhost ~ $
```
While in termina, run `lxc list`. It should output the list of running containers.
```bash
(termina) chronos@localhost ~ $ lxc list
+---------|---------|-----------------------|------|------------|-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------|---------|-----------------------|------|------------|-----------+
| penguin | RUNNING | 100.115.92.199 (eth0) | | PERSISTENT | 0 |
+---------|---------|-----------------------|------|------------|-----------+
(termina) chronos@localhost ~ $
```
For this example, we show the default `penguin` container, which is exposed on
`eth0` at 100.115.92.199. Simply enter the IP of the container where the
code-server runs to Chrome.
## Using Crouton
[Crouton](https://github.com/dnschneid/crouton) is one of the old ways to get a
running full Linux via `chroot` on a Chromebook. To use crouton, enable
developer mode and go to `crosh`. This time, run `shell`, which should drop you
to `bash`.
Make sure you downloaded `crouton`, if so, go ahead and run it under
`~/Downloads`. After installing your chroot container via crouton, go ahead and
enter `enter-chroot` to enter your container.
Follow the instructions set in [the self-host install guide](index.md) to
install code-server. After that is done, run `code-server` and verify it works
by going to `localhost:8080`.
> At this point in writing, `localhost` seems to work in this method. However,
> the author is not sure if it applies still to newer Chromebooks.

73
doc/deploy.md Normal file
View File

@ -0,0 +1,73 @@
# Set up instance
## EC2 on AWS
- Click **Launch Instance** from your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home).
- Select the Ubuntu Server 18.04 LTS (HVM), SSD Volume Type
- Select an appropriate instance size (we recommend t2.medium/large, depending
on team size and number of repositories/languages enabled), then
**Next: Configure Instance Details**.
- Select **Next: ...** until you get to the **Configure Security Group** page,
then add a **Custom TCP Rule** rule with port range set to `8080` and source
set to "Anywhere".
> Rules with source of 0.0.0.0/0 allow all IP addresses to access your
> instance. We recommend setting [security group rules](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-network-security.html?icmpid=docs_ec2_console)
> to allow access from known IP addresses only.
- Click **Launch**.
- You will be prompted to create a key pair.
- From the dropdown choose "create a new pair", give the key pair a name.
- Click **Download Key Pair** and store the file in a safe place.
- Click **Launch Instances**.
- Head to your [EC2 dashboard](https://console.aws.amazon.com/ec2/v2/home)
and choose instances from the left panel.
- In the description of your EC2 instance copy the public DNS (iPv4) address
using the copy to clipboard button.
- Open a terminal on your computer and SSH into your instance:
```
ssh -i ${path to key pair} ubuntu@${public address}
```
## DigitalOcean
[Open your DigitalOcean dashboard](https://cloud.digitalocean.com/droplets/new)
to create a new droplet
- **Choose an image -** Select the **Distributions** tab and then choose Ubuntu.
- **Choose a size -** We recommend at least 4GB RAM and 2 CPU, more depending
on team size and number of repositories/languages enabled.
- Launch your instance.
- Open a terminal on your computer and SSH into your instance:
```
ssh root@${instance ip}
```
## Google Cloud
> Pre-requisite: Set up the [Google Cloud SDK](https://cloud.google.com/sdk/docs/)
> on your local machine
- [Open your Google Cloud console](https://console.cloud.google.com/compute/instances)
to create a new VM instance and click **Create Instance**.
- Choose an appropriate machine type (we recommend 2 vCPU and 7.5 GB RAM, more
depending on team size and number of repositories/languages enabled).
- Choose Ubuntu 16.04 LTS as your boot disk.
- Expand the "Management, security, disks, networking, sole tenancy" section,
go to the "Networking" tab, then under network tags add "code-server".
- Create your VM, and **take note** of its public IP address.
- Visit "VPC network" in the console and go to "Firewall rules". Create a new
firewall rule called "http-8080". Under "Target tags" add "code-server", and
under "Protocols and ports" tick "Specified protocols and ports" and "tcp".
Beside "tcp", add "8080", then create the rule.
- Open a terminal on your computer and SSH into your Google Cloud VM:
```
gcloud compute ssh --zone ${region} ${instance name}
```
# Run code-server
- Download the latest code-server release from the
[releases page](https://github.com/cdr/code-server/releases/latest)
to the instance, extract the file, then run the code-server binary:
```
wget https://github.com/cdr/code-server/releases/download/{version}/code-server{version}-linux-x64.tar.gz
tar -xvzf code-server{version}-linux-x64.tar.gz
cd code-server{version}-linux-x64
./code-server
```
- Open your browser and visit http://$public_ip:8080/ where `$public_ip` is
your instance's public IP address.
- For long-term use, set up a systemd service to run code-server.

View File

@ -0,0 +1,15 @@
# Fail2Ban filter for code-server
[Definition]
failregex = ^INFO\s+Failed login attempt\s+{\"password\":\"(\\.|[^"])*\",\"remoteAddress\":\"<HOST>\"
# Use this instead for proxies (ensure the proxy is configured to send the
# X-Forwarded-For header).
# failregex = ^INFO\s+Failed login attempt\s+{\"password\":\"(\\.|[^"])*\",\"xForwardedFor\":\"<HOST>\"
ignoreregex =
datepattern = "timestamp":{EPOCH}}$
# Author: Dean Sheather

View File

@ -10,7 +10,7 @@ metadata:
namespace: code-server
spec:
ports:
- port: 8443
- port: 8080
name: https
protocol: TCP
selector:
@ -62,7 +62,7 @@ spec:
imagePullPolicy: Always
name: code-servery
ports:
- containerPort: 8443
- containerPort: 8080
name: https
volumeMounts:
- name: code-server-storage
@ -71,4 +71,3 @@ spec:
- name: code-server-storage
persistentVolumeClaim:
claimName: code-store

View File

@ -10,7 +10,7 @@ metadata:
namespace: code-server
spec:
ports:
- port: 8443
- port: 8080
name: https
protocol: TCP
selector:
@ -39,5 +39,5 @@ spec:
imagePullPolicy: Always
name: code-server
ports:
- containerPort: 8443
- containerPort: 8080
name: https

35
doc/fail2ban.md Normal file
View File

@ -0,0 +1,35 @@
# Protecting code-server from bruteforce attempts
code-server outputs all failed login attempts, along with the IP address,
provided password, user agent and timestamp by default.
When using a reverse proxy such as Nginx or Apache, the remote address may
appear to be `127.0.0.1` or a similar address so `X-Forwarded-For` should be
used instead. Ensure that you are setting this value in your reverse proxy:
Nginx:
```
location / {
...
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
}
```
Apache:
```
<VirtualEnv>
...
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
...
</VirtualEnv>
```
It is extremely important that you ensure that your code-server instance is not
accessible from the internet (use localhost or block it in your firewall).
## Fail2Ban
Fail2Ban allows for automatically banning and logging repeated failed
authentication attempts for many applications through regex filters. A working
filter for code-server can be found in `./code-server.fail2ban.conf`. Once this
is installed and configured correctly, repeated failed login attempts should
automatically be banned from connecting to your server.

57
doc/quickstart.md Normal file
View File

@ -0,0 +1,57 @@
# Quickstart Guide
1. Visit the [releases page](https://github.com/cdr/code-server/releases) and
download the latest binary for your operating system.
2. Unpack the downloaded file then run the binary.
3. In your browser navigate to `localhost:8080`.
## Usage
Run `code-server --help` to view available options.
### Encrypting traffic with HTTPS
To encrypt the traffic between the browser and server use `code-server --cert`
followed by the path to your certificate. Additionally, you can use certificate
keys with `--cert-key` followed by the path to your key. If you pass `--cert`
without any path code-server will generate a self-signed certificate.
You can use [Let's Encrypt](https://letsencrypt.org/) to get an SSL certificate
for free.
### Nginx Reverse Proxy
The trailing slashes are important.
```
server {
listen 80;
listen [::]:80;
server_name code.example.com code.example.org;
location /some/path/ { # Or / if hosting at the root.
proxy_pass http://localhost:8080/;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
}
}
```
### Apache Reverse Proxy
```
<VirtualHost *:80>
ServerName code.example.com
RewriteEngine On
RewriteCond %{HTTP:Upgrade} =websocket [NC]
RewriteRule /(.*) ws://localhost:8080/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket [NC]
RewriteRule /(.*) http://localhost:8080/$1 [P,L]
ProxyRequests off
RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Port 443
ProxyPass / http://localhost:8080/ nocanon
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
```

View File

@ -1,11 +0,0 @@
# Fail2Ban filter for code-server
[Definition]
failregex = ^INFO\s+Failed login attempt\s+{\"password\":\"(\\.|[^"])*\",\"remote_address\":\"<HOST>\"
ignoreregex =
datepattern = "timestamp":{EPOCH}}$
# Author: Dean Sheather

View File

@ -1,44 +0,0 @@
# Protecting code-server from Bruteforce Attempts
<!-- TODO: remove this notice -->
### **NOTE: FAILED LOGIN ATTEMPT LOGGING IS NOT IN THE CURRENT VERSION AND WILL BE RELEASED IN V2.**
code-server outputs all failed login attempts, along with the IP address,
provided password, user agent and timestamp by default. When using a reverse
proxy such as Nginx or Apache, the remote address may appear to be `127.0.0.1`
or a similar address unless the `--trust-proxy` argument is provided to
code-server.
When used with the `--trust-proxy` argument, code-server will use the last IP in
`X-Forwarded-For` (if provided) instead of the remote socket address. Ensure
that you are setting this value in your reverse proxy:
Nginx:
```
location / {
...
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
...
}
```
Apache:
```
<VirtualEnv>
...
SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
...
</VirtualEnv>
```
It is extremely important that if you enable `--trust-proxy` you ensure your
code-server instance is not accessible from the internet (block it in your
firewall).
## Fail2Ban
Fail2Ban allows for automatically banning and logging repeated failed
authentication attempts for many applications through regex filters. A working
filter for code-server can be found in `./code-server.fail2ban.conf`. Once this
is installed and configured correctly, repeated failed login attempts should
automatically be banned from connecting to your server.

View File

@ -1,8 +0,0 @@
# Security Guides
We recommend users running code-server setup SSL and fail2ban on their
instances for improved security and resilience to attacks.
* [Self-signed SSL guide](./ssl.md)
* [Let's Encrypt SSL guide](./ssl-certbot.md)
* [Fail2Ban setup guide](./fail2ban.md)

View File

@ -1,63 +0,0 @@
# Generate a Certificate Using Let's Encrypt 🔒
To get around the certificate warnings in Chrome, you might want to install a
certificate from a trusted Certificate Authority (CA). Luckily, there are CAs
like [Let's Encrypt](lets-encrypt) which provide certificates for free.
[lets-encrypt]: https://letsencrypt.org/
---
### Using Certbot
[Certbot](certbot) is the program we'll be using to issue certificates from
Let's Encrypt.
> Pre-requisites: You will need a domain name or subdomain pointed to the IP
> address of your server.
1. Install Certbot by heading to the [instructions page](certbot-instructions).
Select **None of the above** for the software and the right operating system
for your setup.
2. Follow the installation instructions, and stop once you get up to the part
where you run the `certbot certonly` command.
3. Ensure your code-server instance isn't running, and any other webservers that
could interfere are also stopped.
4. Run the following command, replacing `code.example.com` with the
hostname/domain you want to run your server on, to issue a certificate:
```
sudo certbot certonly --standalone -d code.example.com
```
5. Follow the prompts, providing your email address and accepting the terms
where required.
6. Once the process is complete, it should print the paths to the certificates
and keys that were generated. You can now restart any webservers you stopped
in step 2.
[certbot]: https://certbot.eff.org/
[certbot-instructions]: https://certbot.eff.org/instructions
---
### Starting code-server with a Certificate and Key
Just add the `--cert` and `--cert-key` flags when you run code-server:
```shell
./code-server --cert=/etc/letsencrypt/live/code.example.com/fullchain.pem --cert-key=/etc/letsencrypt/live/code.example.com/privkey.pem
```
You can now verify that your SSL installation is working properly by checking
your site with [SSL Labs' SSL Test](ssl-labs-test).
[ssl-labs-test]: https://www.ssllabs.com/ssltest/
---
### Next Steps
You probably want to setup automatic renewal of your certificates, as they
expire every 3 months. You can find instructions on how to do this in
[Certbot's documentation](certbot-renew-docs).
[certbot-renew-docs]: https://certbot.eff.org/docs/using.html?highlight=hooks#renewing-certificates

View File

@ -1,70 +0,0 @@
# Generate a Self-signed Certificate 🔒
code-server has the ability to secure your connection between client and server
using SSL/TSL certificates. By default, the server will start with an
unencrypted connection. We recommend Self-signed TLS/SSL certificates for
personal use of code-server or within an organization.
This guide will show you how to create a self-signed certificate and start
code-server using your certificate/key.
## TLS / HTTPS
You can specify any location that you want to save the certificate and key. In
this example, we will navigate to the root directory, create a folder called
`certs` and cd into it.
```shell
mkdir ~/certs && cd ~/certs
```
If you don't already have a TLS certificate and key, you can generate them with
the command below. They will be placed in `~/certs`.
```shell
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ~/certs/MyKey.key -out ~/certs/MyCertificate.crt
```
You will be prompted to add some identifying information about your
organization:
```shell
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:TX
Locality Name (eg, city) []:Austin
Organization Name (eg, company) [Coder Technologies]:Coder
Organizational Unit Name (eg, section) []:Docs
Common Name (e.g. server FQDN or YOUR name) []:hostname.example.com
Email Address []:admin@example.com
```
> If you already have a TLS certificate and key, you can simply reference them
> in the `--cert` and `--cert-key` flags when launching code-server.
## Starting code-server with a Certificate and Key
Just add the `--cert` and `--cert-key` flags when you run code-server:
```shell
./code-server --cert=~/certs/MyCertificate.crt --cert-key=~/certs/MyKey.key
```
> You should check that the
> `WARN No certificate specified. This could be insecure` are no longer visible
> in the output.
## Other Options
For larger organizations you may wish to rely on a trusted Certificate Authority
as opposed to a self-signed certificate. For more information on generating free
and open certificates for your site, please check out EFF's
[certbot](https://certbot.eff.org/). Certbot is a cli to generate certificates
using [LetsEncrypt](https://letsencrypt.org/).

View File

@ -1,81 +0,0 @@
# Installng code-server on a ChromeOS/CloudReady machine
This guide will show you how to install code-server on your CrOS machine.
## Using Crostini
One of the easier ways to run code-server is via [Crostini](crostini), the Linux
apps support feature in CrOS. Make sure you have enough RAM, HDD space and your
CPU has VT-x/AMD-V support. If your Chromebook has this, then you are qualified
to use Crostini.
If you are running R69, you might want to enable this on
[Chrome Flags](r69-flag). If you run R72, however, this is already enabled for
you.
After checking your prerequisites, follow the steps in [the self-host install
guide](self-hosted-guide) on installing code-server. Once done, make sure
code-server works by running it, then simply go to `penguin.linux.test:8443` to
access code-server. You should be greeted with the following screen. If it
works, congratulations, you have installed code-server in your Chromebook!
![code-server on Chromebook](../assets/cros.png)
Alternatively, if you ran code-server in another container and you need the IP
for that specific container, simply go to Termina's shell via `crosh` and type
`vsh termina`.
```
Loading extra module: /usr/share/crosh/dev.d/50-crosh.sh
Welcome to crosh, the Chrome OS developer shell.
If you got here by mistake, don't panic! Just close this tab and carry on.
Type 'help' for a list of commands.
If you want to customize the look/behavior, you can use the options page.
Load it by using the Ctrl+Shift+P keyboard shortcut.
crosh> vsh termina
(termina) chronos@localhost ~ $
```
While in termina, run `lxc list`. It should output the list of running
containers.
```
(termina) chronos@localhost ~ $ lxc list
+---------+---------+-----------------------+------+------------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------+---------+-----------------------+------+------------+-----------+
| penguin | RUNNING | 100.115.92.199 (eth0) | | PERSISTENT | 0 |
+---------+---------+-----------------------+------+------------+-----------+
(termina) chronos@localhost ~ $
```
For this example, we show the default `penguin` container, which is exposed on
`eth0` at 100.115.92.199. Simply enter the IP of the container where code-server
is running into Chrome to access code-server.
[crostini]: https://www.aboutchromebooks.com/tag/project-crostini/
[r69-flag]: chrome://flags/#enable-experimental-crostini-ui
[self-hosted-guide]: ./index.md
## Using Crouton
[Crouton](crouton) is one of the old ways to get a running full Linux via
`chroot` on a Chromebook. To use crouton, enable developer mode and go to
`crosh`. This time, run `shell`, which should drop you to `bash`.
Make sure you downloaded `crouton`, if so, go ahead and run it under
`~/Downloads`. After installing your chroot container via crouton, go ahead and
enter `enter-chroot` to enter your container.
Follow the instructions set in [the self-host install guide](self-hosted-guide)
to install code-server. After that is done, run `code-server` and verify it
works by going to `localhost:8443`.
> At this point in writing, `localhost` seems to work in this method. However,
> it might not apply to newer Chromebooks.
[crouton]: https://github.com/dnschneid/crouton

View File

@ -1,306 +0,0 @@
# Getting Started
This document pertains to Coder-specific implementation of VS Code: code-server.
For documentation on how to use VS Code itself, please refer to the official
[VS Code documentation](vscode-documentation).
If you get stuck or need help at anytime, [file an issue](create-issue),
[tweet (@coderhq)](twitter-coderhq) or [email](email-coder).
[vscode-documentation]: https://code.visualstudio.com/docs
[create-issue]: https://github.com/cdr/code-server/issues/new?title=Improve+self-hosted+quickstart+guide
[twitter-coderhq]: https://twitter.com/coderhq
[email-coder]: mailto:support@coder.com?subject=Self-hosted%20quickstart%20guide
## Quickstart Guide
It takes just a few minutes to get your own self-hosted server running. If
you've got a machine running macOS or Linux, you're ready to start the
binary which listens on port `8443` by default.
<!-- DO NOT CHANGE THIS TO A CODEBLOCK. We want line breaks for readability, but
backslashes to escape them do not work cross-platform. This uses line
breaks that are rendered but not copy-pasted to the clipboard. -->
1. Visit the [releases](code-server-releases) page and download the latest
release for your operating system.
2. Extract the archive and double click the executable to run in the current
directory.
3. Copy the password that appears in the output.
<img src="../assets/cli.png">
4. In your browser navigate to https://localhost:8443. You will be greeted with
an SSL warning as code-server uses a self-signed certificate (more on that
below). Skip the warning.
5. Login using the password from earlier.
Be careful about who you share your password with, as it will grant them full
access to your server.
[code-server-releases]: https://github.com/cdr/code-server/releases
### Security Warnings
When you visit your code-server instance, you will be greeted with a warning
page similar to the following screenshot. code-server is using a self-signed SSL
certificate for easy setup. In Chrome/Chromium, click **Advanced** then click
**proceed anyway**. In Firefox, click **Advanced**, then **Add Exception**,
then finally **Confirm Security Exception**.
<img src="../assets/chrome_warning.png">
## code-server Usage
You can bring up code-server usage by using `code-server --help`. Arguments let
you customize your working directory, host, port, SSL certificates, and more.
Flags can be supplied to code-server like `--flag-name value` or
`--flag-name=value`. To supply values with whitespace, use double quotes.
```
$ code-server --help
Usage: code-server [options]
Run VS Code on a remote server.
Options:
-V, --version output the version number
--cert <value>
--cert-key <value>
-e, --extensions-dir <dir> Override the main default path for user extensions.
--extra-extensions-dir [dir] Path to an extra user extension directory (repeatable). (default: [])
--extra-builtin-extensions-dir [dir] Path to an extra built-in extension directory (repeatable). (default: [])
-d --user-data-dir <dir> Specifies the directory that user data is kept in, useful when running as root.
-h, --host <value> Customize the hostname. (default: "0.0.0.0")
-o, --open Open in the browser on startup.
-p, --port <number> Port to bind on. (default: 8443)
-N, --no-auth Start without requiring authentication.
-H, --allow-http Allow http connections.
--disable-telemetry Disables ALL telemetry.
--socket <value> Listen on a UNIX socket. Host and port will be ignored when set.
--install-extension <value> Install an extension by its ID.
-h, --help output usage information
```
By default, code-server listens on `0.0.0.0:8443`. If you'd like to customize
this, use the `--host` and `--port` flags:
`code-server --host 127.0.0.1 --port 1234`.
You can instruct code-server to automatically open itself in your default
browser by using the `-o` or `--open` flag.
Use `code-server -d path/to/directory` to specify where code-server stores it's
configuration data. You can specify where extensions are installed using the
`-e`, `--extra-extensions-dir` and `--extra-builtin-extensions-dir` flags.
### SSL Certificates
To change the certificate code-server uses for HTTPS connections, specify a
certificate with `--cert` and a private key with `--cert-key`.
If you're using Let's Encrypt, you should be using the `fullchain.pem` file as
the certificate and `privkey.pem` as the private key.
```
code-server \
--cert /etc/letsencrypt/live/example.com/fullchain.pem \
--cert-key /etc/letsencrypt/live/example.com/privkey.pem
```
For more information on security and SSL configuration, please visit the
[security documentation](../security).
#### Telemetry
Telemetry can be disabled by using the `--disable-telemetry` flag or by setting
the `DISABLE_TELEMETRY` environment variable to `true`. If telemetry is enabled,
code-server will send the following data along with VS Code's telemetry data:
- Unique machine ID
- CPU core count and model
- Memory information
- Shell information (which shell you use)
- OS release and architecture
### Nginx Reverse Proxy
The following site configuration file works with code-server. When starting
code-server, be sure to provide the `--allow-http` and `--trust-proxy` flags so
Nginx can connect to code-server properly.
Some of these directives require a version of Nginx greater than or equal to
`1.13.0`, which might not be available in your distro's repositories. Check out
[Nginx's documentation](nginx-install) for more information on how to install
the latest version of Nginx from the official repository.
```
# HTTP configuration
server {
listen 80;
listen [::]:80;
server_name code.example.com code.example.org;
# If you're using CloudFlare, uncomment the following line.
# real_ip_header CF-Connecting-IP;
# Other security options.
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location / {
proxy_pass http://localhost:8443/;
proxy_set_header Accept-Encoding gzip;
proxy_set_header Connection upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# HTTPS configuration. Scores an A on SSL Labs' SSL Server Test.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name code.example.com code.example.org;
# If you're using CloudFlare, uncomment the following line.
# real_ip_header CF-Connecting-IP;
# SSL certificate and key.
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/cert-key.pem;
# Strong TLS configuration. Originally taken from https://cipherli.st/.
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Other security options.
# add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location / {
proxy_pass http://localhost:8443/;
proxy_set_header Accept-Encoding gzip;
proxy_set_header Connection upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
Make sure to set the `proxy_pass` directive to the actual address of your
code-server instance and the `server_name` directive to the hostname/s of your
website. If you're using an SSL certificate, make sure to change the
`ssl_certificate` and `ssl_certificate_key` directives. If not, remove the HTTPS
`server` block entirely.
[nginx-install]: https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/#installing-a-prebuilt-package
### Apache Reverse Proxy
The following virtual host configuration file works with code-server. When
starting code-server, be sure to provide the `--allow-http` and `--trust-proxy`
flags so Apache can connect to code-server properly.
Some of these directives require a version of Apache greater than or equal to
`2.4.0`, which might not be available in your distro's repositories. You will
also need to enable the following modules: `rewrite`, `proxy`, `proxy_http`,
`proxy_wstunnel`, `ssl`, and `socache_shmcb`.
```
# HTTP configuration.
<VirtualHost *:80>
ServerName code.example.com
# If you're using CloudFlare, uncomment the following line.
# RemoteIPHeader CF-Connecting-IP;
# Other security options.
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* "ws://localhost:8443%{REQUEST_URI}" [P]
RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Port 443
ProxyRequests off
ProxyPass / http://localhost:8443/ nocanon
ProxyPassReverse / http://localhost:8443/
</VirtualHost>
# HTTPS configuration. Scores an A on SSL Labs' SSL Server Test.
<IfModule mod_ssl.c>
SSLStaplingCache shmcb:/tmp/stapling_cache(150000)
<VirtualHost *:443>
ServerName code.example.com
# If you're using CloudFlare, uncomment the following line.
# RemoteIPHeader CF-Connecting-IP;
# SSL certificate and key.
SSLEngine On
SSLCertificateFile /path/to/cert.pem
SSLCertifcateKeyFile /path/to/cert-key.pem
SSLCertificateChainFile /path/to/chain.pem
# Strong TLS configuration. Originally taken from https://cipherli.st/.
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM
SSLProtocol -all +TLSv1.2
SSLHonorCipherOrder On
SSLCompression off
SSLUseStapling on
SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
SSLSessionTickets Off
# Other security options.
# Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always set X-Frame-Options DENY
Header always set X-Content-Type-Options nosniff
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule .* "ws://localhost:8443%{REQUEST_URI}" [P]
RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Port 443
ProxyRequests off
ProxyPass / http://localhost:8443/ nocanon
ProxyPassReverse / http://localhost:8443/
</VirtualHost>
</IfModule>
```
Make sure to set the `ProxyPass`, `ProxyPassReverse` and `RewriteRule`
directives to the actual address of your code-server instance and the
`ServerName` directive to the hostname of your website. If you're using SSL,
make sure to change the `SSLCertificateFile`, `SSLCertificateKeyFile`, and
`SSLCertificateChainFile` directives. If not, remove the HTTPS `IfModule` block
entirely.
For more details about Apache reverse proxy configuration, check out the
[mod_proxy documentation](apache-mod_proxy).
[apache-mod_proxy]: https://httpd.apache.org/docs/current/mod/mod_proxy.html

7
main.js Normal file
View File

@ -0,0 +1,7 @@
// Once our entry file is loaded we no longer need nbin to bypass normal Node
// execution. We can still shim the fs into the binary even when bypassing. This
// will ensure for example that a spawn like `${process.argv[0]} -e` will work
// while still allowing us to access files within the binary.
process.env.NBIN_BYPASS = true;
require("../../bootstrap-amd").load("vs/server/src/cli");

View File

@ -1,70 +1,34 @@
{
"name": "@coder/code-server",
"repository": "https://github.com/cdr/code-server",
"author": "Coder",
"license": "MIT",
"description": "Run VS Code remotely.",
"scripts": {
"build:rules": "cd ./rules && tsc -p .",
"packages:install": "cd ./packages && yarn",
"postinstall": "npm-run-all --parallel packages:install build:rules",
"start": "cd ./packages/server && yarn start",
"task": "ts-node -r tsconfig-paths/register build/tasks.ts",
"test": "cd ./packages && yarn test"
"ensure-in-vscode": "bash ./scripts/tasks.bash ensure-in-vscode",
"preinstall": "yarn ensure-in-vscode && cd ../../../ && yarn || true",
"postinstall": "rm -rf node_modules/@types/node",
"start": "yarn ensure-in-vscode && nodemon --watch ../../../out --verbose ../../../out/vs/server/main.js",
"watch": "yarn ensure-in-vscode && cd ../../../ && yarn watch",
"build": "bash ./scripts/tasks.bash build",
"package": "bash ./scripts/tasks.bash package",
"package-prebuilt": "bash ./scripts/tasks.bash package-prebuilt",
"binary": "bash ./scripts/tasks.bash binary",
"patch:generate": "yarn ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch",
"patch:apply": "yarn ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch"
},
"devDependencies": {
"@types/fs-extra": "^5.0.4",
"@types/node": "^10.12.18",
"@types/tar": "^4.0.0",
"@types/trash": "^4.3.1",
"cache-loader": "^2.0.1",
"cross-env": "^5.2.0",
"crypto-browserify": "^3.12.0",
"css-loader": "^2.1.0",
"file-loader": "^3.0.1",
"fork-ts-checker-webpack-plugin": "^0.5.2",
"fs-extra": "^7.0.1",
"happypack": "^5.0.1",
"html-webpack-plugin": "^3.2.0",
"http-browserify": "^1.7.0",
"ignore-loader": "^0.1.2",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0",
"npm-run-all": "^4.1.5",
"path-browserify": "^1.0.0",
"preload-webpack-plugin": "^3.0.0-beta.2",
"sass-loader": "^7.1.0",
"string-replace-loader": "^2.1.1",
"style-loader": "^0.23.1",
"tar": "^4.4.8",
"terser-webpack-plugin": "^1.2.3",
"ts-loader": "^5.3.3",
"ts-node": "^7.0.1",
"tsconfig-paths": "^3.8.0",
"tslib": "^1.9.3",
"tslint": "^5.12.1",
"typescript": "^3.2.2",
"typescript-tslint-plugin": "^0.2.1",
"uglifyjs-webpack-plugin": "^2.1.1",
"url-loader": "^1.1.2",
"util": "^0.11.1",
"webpack": "^4.28.4",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-cli": "^3.2.1",
"webpack-dev-middleware": "^3.5.0",
"webpack-dev-server": "^3.1.14",
"webpack-hot-middleware": "^2.24.3",
"webpack-pwa-manifest": "^4.0.0",
"workbox-webpack-plugin": "^4.1.0",
"write-file-webpack-plugin": "^4.5.0"
"@coder/nbin": "^1.2.0",
"@types/pem": "^1.9.5",
"@types/safe-compare": "^1.1.0",
"@types/tar-stream": "^1.6.1",
"nodemon": "^1.19.1"
},
"resolutions": {
"bindings": "1.3.0"
"@types/node": "^10.12.12",
"safe-buffer": "^5.1.1"
},
"dependencies": {
"node-loader": "^0.6.0",
"node-pty": "0.8.1",
"spdlog": "0.8.1",
"webpack-merge": "^4.2.1"
"@coder/logger": "^1.1.8",
"httpolyglot": "^0.1.2",
"pem": "^1.14.2",
"safe-compare": "^1.1.4",
"tar-stream": "^2.1.0"
}
}

View File

@ -1,12 +0,0 @@
{
"name": "@coder/app",
"scripts": {
"start": "node ../../../node_modules/webpack-dev-server/bin/webpack-dev-server.js --config ./webpack.config.js",
"build": "node ../../../node_modules/webpack/bin/webpack.js --config ./webpack.config.js"
},
"dependencies": {
"@material/checkbox": "^0.44.1",
"@material/textfield": "^0.44.1",
"material-components-web": "^0.44.0"
}
}

View File

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">
<title>Authenticate: code-server</title>
</head>
<body>
<form id="login-form">
<div class="login">
<div class="back">
<- Back </div> <h4 class="title">code-server</h4>
<h2 class="subtitle">
Enter server password
</h2>
<div class="mdc-text-field">
<input type="password" id="password" class="mdc-text-field__input" required>
<label class="mdc-floating-label" for="password">Password</label>
<div class="mdc-line-ripple"></div>
</div>
<button id="submit" class="mdc-button mdc-button--unelevated">
<span class="mdc-button__label">Enter IDE</span>
</button>
<div id="error-display"></div>
</div>
</form>
</body>
</html>

View File

@ -1,121 +0,0 @@
@import url("https://use.typekit.net/vzk7ygg.css");
html, body {
background-color: #FFFFFF;
min-height: 100%;
}
body {
font-family: 'aktiv-grotesk';
display: flex;
align-items: center;
justify-content: center;
height: calc(100vh - 20px);
margin: 0;
padding: 10px;
--mdc-theme-primary: #AAADA1;
--mdc-theme-secondary: #AAADA1;
&.in-app {
.back {
pointer-events: all;
opacity: 1;
}
}
}
.login {
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
max-width: 328px;
width: 100%;
padding: 40px;
border-radius: 5px;
position: relative;
color: #575962;
.title {
margin-bottom: 0px;
font-size: 12px;
font-weight: 500;
letter-spacing: 1.5px;
line-height: 15px;
margin-bottom: 5px;
margin-top: 0px;
text-align: center;
text-transform: uppercase;
}
.subtitle {
text-align: center;
margin: 0;
font-size: 19px;
font-weight: bold;
line-height: 25px;
margin-bottom: 45px;
}
.mdc-text-field {
width: 100%;
background: none !important;
&::before {
background: none !important;
}
}
.mdc-form-field {
text-align: left;
font-size: 12px;
color: #797E84;
margin-top: 16px;
}
.mdc-button {
border-radius: 24px;
padding-left: 75px;
padding-right: 75px;
padding-top: 15px;
padding-bottom: 15px;
height: 48px;
margin: 0 auto;
display: block;
box-shadow: 0 12px 17px 2px rgba(171,173,163,0.14), 0 5px 22px 4px rgba(171,173,163,0.12), 0 7px 8px -4px rgba(171,173,163,0.2);
margin-top: 40px;
}
}
.mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label {
color: var(--mdc-theme-primary);
}
.mdc-floating-label--float-above {
transform: translateY(-70%) scale(0.75);
}
.mdc-text-field:not(.mdc-text-field--disabled):not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mdc-text-field__input, .mdc-text-field:not(.mdc-text-field--disabled):not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mdc-text-field__input:hover {
border-bottom-color: #EBEDF2;
}
.back {
position: absolute;
top: -50px;
left: -50px;
font-weight: bold;
opacity: 0;
pointer-events: none;
// transition: 500ms opacity ease;
}
#error-display {
box-sizing: border-box;
color: #bb2d0f;
font-size: 14px;
font-weight: 400;
letter-spacing: 0.3px;
line-height: 12px;
padding: 8px;
padding-bottom: 0;
padding-top: 20px;
text-align: center;
}

View File

@ -1,46 +0,0 @@
//@ts-ignore
import { MDCTextField } from "@material/textfield";
//@ts-ignore
import { MDCCheckbox } from "@material/checkbox";
import "material-components-web/dist/material-components-web.css";
import "./app.scss";
document.querySelectorAll(".mdc-text-field").forEach((d) => new MDCTextField(d));
document.querySelectorAll(".mdc-checkbox").forEach((d) => new MDCCheckbox(d));
window.addEventListener("message", (event) => {
if (event.data === "app") {
document.body.classList.add("in-app");
const back = document.querySelector(".back")!;
back.addEventListener("click", () => {
(event.source as Window).postMessage("back", event.origin);
});
}
});
const password = document.getElementById("password") as HTMLInputElement;
const form = document.getElementById("login-form") as HTMLFormElement;
if (!form) {
throw new Error("No password form found");
}
form.addEventListener("submit", (e) => {
e.preventDefault();
document.cookie = `password=${password.value}; `
+ `path=${location.pathname.replace(/\/login\/?$/, "/")}; `
+ `domain=${location.hostname}`;
location.reload();
});
/**
* Notify user on load of page if previous password was unsuccessful
*/
const reg = new RegExp(`password=(\\w+);?`);
const matches = document.cookie.match(reg);
const errorDisplay = document.getElementById("error-display") as HTMLDivElement;
if (document.referrer === document.location.href && matches) {
errorDisplay.innerText = "Password is incorrect!";
}

View File

@ -1,16 +0,0 @@
const path = require("path");
const webpack = require("webpack");
const merge = require("webpack-merge");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const root = path.resolve(__dirname, "../../..");
module.exports = merge(
require(path.join(root, "scripts/webpack.client.config.js"))({
dirname: __dirname,
entry: path.join(__dirname, "src/app.ts"),
name: "login",
template: path.join(__dirname, "src/app.html"),
}), {
},
);

View File

@ -1,606 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@material/animation@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.41.0.tgz#315b45b32e1aeebee8a4cf555b8ad52076d09ddd"
integrity sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==
"@material/auto-init@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.41.0.tgz#8a59bb0b83e0f51ead9508074f9a29b2b6a20eec"
integrity sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==
"@material/base@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/base/-/base-0.41.0.tgz#badadce711b4c25b1eb889a5e7581e32cd07c421"
integrity sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==
"@material/button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/button/-/button-0.44.0.tgz#f01dcbea88bdc314e7640b76e5558101c8b4d69d"
integrity sha512-T8u8s8rlB49D9/5Nh5b0XsKRgSq3X0yWGo71MgaTnCnwxt8oZ6PxW/cH6Nn3Xp0NCr3mlSVQs08BviUfAmtlsg==
dependencies:
"@material/elevation" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/card@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/card/-/card-0.44.0.tgz#e62050e3e77f525173a015119200055cd7b71bf0"
integrity sha512-fUixXuh133bVp5c1gPIHreL5jwMJEeVIQf0E4xdxhkA+i4ku8fIAvIW62EuCmfJsXicv4q8NG3Ip6pCY+NW3ZA==
dependencies:
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/checkbox@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.0.tgz#5d0eee1db006db9f0fb700bf1c20408292305cf7"
integrity sha512-IzucxG+NuPNyByGmHg/cuYJ5ooMKouuj994PZXZyqb7owfrjjtXm7wjav66cvCowbVbcoa1owQMGBi18C9f4TQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/checkbox@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.1.tgz#7e69271ccab7c57914a475da3a15d4d36702c1c4"
integrity sha512-RFUNc+9RKRozL+gXfJ8V57tXfC31Q9R9tRMTHpe62NXZriTrwNJDnSkFIERDXqtMGtkKUnIlPfPE5znF6XyPUw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/feature-targeting" "^0.44.1"
"@material/ripple" "^0.44.1"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.1"
"@material/theme" "^0.43.0"
"@material/chips@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/chips/-/chips-0.44.0.tgz#bf553a5bf5db7320978402ac92069c9688b84d5a"
integrity sha512-+qrme6sGwYmX/ixHAo3Z1M7lorsxRyKexn1l+BSBX5PBc2f4w5Ml1eYYYcyVGfLX9LXmefRk0G6dUXXPyCE00g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/checkbox" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/dialog@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.44.0.tgz#388f93f9f225824c75cbe9da8c464a52d79972e8"
integrity sha512-V6ButfknOMKOscL0Y39yLjamxvrIuyugobjf5s44ZeJc+9jUSkC7M3zP+T7rh358NcX+JSPP8iCGmUn/+LXpMQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/dom@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-0.41.0.tgz#6756865f97bad4c91ee75e69d769d7cdc25398ae"
integrity sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==
"@material/drawer@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.44.0.tgz#74b3ddfb741bffc72331c7a73cf62716fd3f0ab3"
integrity sha512-AYwFe0jgqqSmJd1bny8JJTA2SScF86Wfbk99lXXEwd/acS8IbnnuH6zfAg6MyJX12FDb8dE8Z/Ok1IwLiVa9sQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/list" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/elevation@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.44.0.tgz#ca16a67188ce9810dc2fa3d7a39073e72df4b754"
integrity sha512-edNou34yFCSMb6XXe/6Y7AEh8DigWAhBUyIeMiMBD4k1km2xYCJbcnl8FBPJFteOrca97KoJComRlJPB6EurRQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/fab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.44.0.tgz#0bcbbdfb6f24c53d59e08c9c0d400d2616dea184"
integrity sha512-1CEP4NlXDYioJ/YpSjh/MlIygtoC7CaHqIbucxX1O5WRPmS7K1uPt+o7netbLErAmcJdV/JrI/tqh9kKuX2x/Q==
dependencies:
"@material/animation" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/feature-targeting@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.0.tgz#52cc73f0c8a83159de0357aebe74f15f9856fb4c"
integrity sha512-ShuC2TOLfjFpYUCQFtvkqDJhM6HTaucSx5HkRbOvOG+VlpzDx6pAqRUmdVaq2p7tHoQf2vwPMlSVm3gOjWt4VQ==
"@material/feature-targeting@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.1.tgz#afafc80294e5efab94bee31a187273d43d34979a"
integrity sha512-90cc7njn4aHbH9UxY8qgZth1W5JgOgcEdWdubH1t7sFkwqFxS5g3zgxSBt46TygFBVIXNZNq35Xmg80wgqO7Pg==
"@material/floating-label@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.0.tgz#8694cd49f6905641b67a9e7a112b820d028f09c7"
integrity sha512-k4npGNxyMtnjgJZNjU5VvqqaUqlbzlbVAhepT8PxYTpj+4Skg6PjHwieTCDCgsbqHvFcQX+WfUrSZXY7wFV7cw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/floating-label@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.1.tgz#39af84a3a0abbfa6d210911d5f4200a65c2ef59b"
integrity sha512-umj5q5feJcZuB8snRX5aVBrwQNnrt/HcvN7pENzgqaYZNcmBnxRl0OutTlHCn6l7OVU9VlWhFMf77DYwmMWKJQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.1"
"@material/form-field@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.44.0.tgz#b7518e885c0e953a2a5fe0140af927c30e066f4e"
integrity sha512-SK+V34dzoBCQ/CHn5nBp8BAh21Vj9p1pcok+/WpYBTeg4EphTYP2nUQLMNEN92l6zjgAYf+g9Ocj3t26HNHWqA==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/grid-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.44.0.tgz#bd31d992ab1a910731e4a47c11fe91d44e3bc02b"
integrity sha512-NxLL0A48K1O14ZZymFIyf6HDbF33+NgXYXqP2yosTC3Jw4iwmUcJTpFTmSw1U/m1xT4zEpeKEGJ4vjVUWpS9Mg==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/icon-button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-0.44.0.tgz#febbcfd27d91eca8096ae042b9c07ed0f65345e9"
integrity sha512-n6L7RaRyEci6eGsuBTSEG+t9ATHAHaMlf9zuTWorEnIXY4DAmGO7ggBjw4+1XIOjhpLeIjyJdcvUK6Yz/UVM6Q==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/icon-toggle@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.44.0.tgz#b9de32f194b5aa9721ca799d59be0f477a5c5305"
integrity sha512-8T1b4iK61/q/3U0iIjEDJ9do5viCQ45IbrQqa8EYCZ1KDU/Q8z5N+bvOzQK8XnTL51BdDRMgP9lfQZh6nszmkA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/image-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-0.44.0.tgz#a27996962044ac8c9ce6cb509f63746f08ed2e98"
integrity sha512-kI9aKJdc1Bd02l8nRTGG1wy/lNkECScfnBmCiLQ3XjAFtRYd2eWO0Z/AVvUG3egsIZnZBxqFGGsf5Htm9E/HiQ==
dependencies:
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/layout-grid@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.41.0.tgz#2e7d3be76313e0684d573b10c2c6a88b3230d251"
integrity sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==
"@material/line-ripple@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-0.43.0.tgz#6cb530bab53f055f3583646a21ad20c1703f3a83"
integrity sha512-sXZYW4Em5uLEnAuVsQCO+sVHsTg7J2TOTJ0+akwZFMmd2tmNicjarQdlGIE9iU7Wjm51NOoLAu6Mz+8kLg90bQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/linear-progress@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.43.0.tgz#4821424aa24c78de256e74a91d5be3df55c534d9"
integrity sha512-bqkDcob+xp1mFkyBsOkoaLgrtapmz7jznGoI3nmkqyk75EB2XQcn1H8Vr6cnp/jkF4nbKu0GdVJO3VXUFmGmrQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/list/-/list-0.44.0.tgz#cf1910e15b66759334b8618d1110fbcc72c3d326"
integrity sha512-35gkN1+XZaau9d9ngyN2x14bzkj/ajZCDm7mbWibDQy272A16j6KuFLQFA8RUQV04OgL4YPVxY87dpCn/p+uTg==
dependencies:
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/menu-surface@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-0.44.0.tgz#902c081df42859b925a5b4502791b3febf48f1ae"
integrity sha512-s49kvIlQ4H5wvMD4yeHMMqnamPod06IUagMK6Ry0oTpUANSnyeNXxa3HkScl7DMJiS8IJeV21fSLAzlZYP2PDQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/menu@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.44.0.tgz#776ec8a04406266a0a0a13eb140b1fd691e442cb"
integrity sha512-92XvAcv9rBW1jQ3UvwJ8zk9hbSRe/FqSuFdZ9fNPE348dCY2pbcdQfnUJTe3ycAN/I1c5frkrhx8F0II+nfbNQ==
dependencies:
"@material/base" "^0.41.0"
"@material/list" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/notched-outline@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.0.tgz#d5a2e1d649921575a7cd2e88ee4581e4a1809573"
integrity sha512-c3nqOqUQAmW3h4zBbZVbMRdf4nNTYm0tVwXIAwmcCs5nvAthEHnzHwwFddNP7/9Wju6LZ0uqWn6xlyKly0uipw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/notched-outline@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.1.tgz#dba4812286ba4c20f0361e6040bf9b9cad307434"
integrity sha512-x1ZJtrrqZgXT8gYE7aRF+6hTWpX7XaKZzsuwD+e0HBsogYNNsYmkBdLjl4YwhhFuHhX8vWzgkay41GtbgQx84Q==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.1"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.44.1"
"@material/theme" "^0.43.0"
"@material/radio@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.44.0.tgz#f4cacdfabc7d765aa000cb34c5a37966f6d4fd6d"
integrity sha512-ar7uhlfHuSwM9JUUjpv7pLDLE0p436cCMxNTpmMjWabfvo3pMWlExvk72Oj81tBgfxY/uASLB3oj4neudXu9JQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/ripple@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.0.tgz#98920ff8ec4bf5714c97df3d190f02f8a5b476cc"
integrity sha512-MlaW4nUDgzS0JOBfsUawXyTOilr0jn+xvTVn6PEaGh2rmhNA54AhixXvdsVUWE9lfmHAsZV0AJHz2z7nunNhbQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/feature-targeting" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/ripple@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.1.tgz#79cb2ddf1f998498d877d3e3c46b50fed6f13b01"
integrity sha512-prJ1p3bR+GvwAtJgtdeIixsnRVApN3bizGnX7upKoqxsqbBDHj84JxaO8EsG9bjruG/LJu8Fb6WKKdIp2oXHTA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/feature-targeting" "^0.44.1"
"@material/theme" "^0.43.0"
"@material/rtl@^0.42.0":
version "0.42.0"
resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.42.0.tgz#1836e78186c2d8b996f6fbf97adab203535335bc"
integrity sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==
"@material/select@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/select/-/select-0.44.0.tgz#8041b4fe6247d013b0f12685fbdf50aa9ff57b35"
integrity sha512-tw3/QIBLuRCT+5IXx4IPiJk7FzeGeR65JEizdRUItH8yzoIiQLs/b2i3KtHM2YBXHgeUcEBF2AOqPX2opdYhug==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/selection-control@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.0.tgz#63d5c65a47a9f54f5a0316b5ecdb5e5f35108609"
integrity sha512-HgCAPnMVMEj4X4ILkFSifqtZ3Tcc5HkU+Lfk9g0807sCaN/qBKWkYKLH2WJUbW8uk+MXK7DgP1khtS5zzanJWA==
dependencies:
"@material/ripple" "^0.44.0"
"@material/selection-control@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.1.tgz#77a47354a4c5128fa34e3ba98d9cc26e8a92839a"
integrity sha512-Xf1ee2ZV2XJ+rK8OcOD1DZOihfU0uVRdY6iYX/Bqi8k8RXnAbLIBoh6zG3xSwjRNODNvAyHEQaS/ozEfH8eehg==
dependencies:
"@material/ripple" "^0.44.1"
"@material/shape@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.43.0.tgz#b877acfd8be8abc9ddcf6601eb60dd0588292415"
integrity sha512-KGnoQV4G2OQbMe5Lr5Xbk8XNlO93Qi/juxXtd2wrAfiaPmktD8ug0CwdVDOPBOmj9a0gX3Ofi9XWcoU+tLEVjg==
"@material/shape@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.44.1.tgz#ff4d5d42b07c5781306677bffee43234b756ea8e"
integrity sha512-8mCDQmyTEhDK+HX8Tap2Lc82QlVySlXU8zDCNkWoIn1ge+UnRezSDjE4y4P1ABegN5PrkJZPartuQ1U0ttIYXw==
dependencies:
"@material/feature-targeting" "^0.44.1"
"@material/slider@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.44.0.tgz#2055df894eb725e541cde50a544719c07934755b"
integrity sha512-Lnn2fdUesXX4O0UpJzveEuOj+og+dXCwhal73u3l3NXEdc/eRgYxwWdF3ww4MmCZ786EwUmjb4vIc9olN4DO3A==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/snackbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.44.0.tgz#d98672b849f5f295e4fac2d474a9c80f11945518"
integrity sha512-KhCrmJm8Zu/ZZPuRCGfMKsZ0vudINlNgTjlOau0kQ/UgR1xBUvLOE8NjyXZr0RQz5obyW7xpyIWIpscn0IUeyw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/icon-button" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/switch@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.44.0.tgz#f2cbb447437b12eb3bc7f0ec8318dbd3b4f0afce"
integrity sha512-EadCg6lHUF260R2Q/l++vXIITqacvbXlobSoewA5ib6y9BU2g7l13wL1W8xAVJNUMgFa/PyN+EKT3oCql7jZLg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/tab-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-0.44.0.tgz#b17d791bd557b1d84892fef1a1d8b8d6fef7c6d6"
integrity sha512-kCrt05d61YXyY43SNc0dPGuqysbcLr/KRDBvzpXgE4gv2jCCVhhjAH10KPlx8pthp/UtvrYJHb34acAKEGzdHA==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-scroller" "^0.44.0"
"@material/tab-indicator@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-0.43.0.tgz#37fd05513ba55ae218d9068c986c2676096fd6eb"
integrity sha512-RMNMQpWYghWpM6d0ayfuHEPzTiebKG0bMthViiD6tly8PubmOT8mShNhPm8ihybhDPUOLSz+7V4QNE5wikLEYg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/tab-scroller@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-0.44.0.tgz#82d092ed45d2ee9d82038bed318e6ff6bdc36dad"
integrity sha512-Ufd3NWBN11kY2oA7bGmTYWGP1uz2mq0tfDM0JOiqoLMgD7y3Z18kmxnpq2qkg1vi4kvix28hBYGGMfLlq9rGDA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/tab" "^0.44.0"
"@material/tab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab/-/tab-0.44.0.tgz#254b92cff99015f0bd59a86d08d3f1c4744d0742"
integrity sha512-czrbGjtKkmUS3iYBX523xT5GOkjP0h+0x9fTnw+heFNpw5dCn6cZvlj3D9ayZU+ZH93x68TFhFVBuLU5f0EBXw==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/tab-indicator" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/textfield@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.0.tgz#277b33948ddff33f7f643323895e5a683f013601"
integrity sha512-IMBwMcE82eVU+Wifpu0t84tozvBPLCeqQELDtZNYujKg3RxaultzJLwIyGKPMZ9R4yPEpV2vgXPGKE+2/AWt0g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/textfield@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.1.tgz#2bba41cc94e68e328683997a1acf222b643dea9c"
integrity sha512-zy+56+uqr+L9DGrdOfQjOIMdKlai/7ruyqVfqIY6ieABM7LEGsOsxHhyExQmXo9IiuFhrOceWKFa4yIb8jBsmQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.1"
"@material/line-ripple" "^0.43.0"
"@material/notched-outline" "^0.44.1"
"@material/ripple" "^0.44.1"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.44.1"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.1"
"@material/theme@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.43.0.tgz#6d9fa113c82e841817882172c152d60d2d203ca6"
integrity sha512-/zndZL6EihI18v2mYd4O8xvOBAAXmLeHyHVK28LozSAaJ9okQgD25wq5Ktk95oMTmPIC+rH66KcK6371ivNk8g==
"@material/toolbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.44.0.tgz#6689aecdeccc78b7a890a3abbe8b68a2c6339307"
integrity sha512-YgLlOFQ5VzFLQBpXYSMviEbYox0fia+sasHuYPUhTAtas1ExVt9EEiIolDSVvhv2PruTReKKefxSbXAqGlOHog==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/top-app-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-0.44.0.tgz#2495c7f9567568fb961ccced24f479c4806a72af"
integrity sha512-tf0yXQJARYs8UPaH8oo3LnsSHEiur7Zm8Fc3hv3F0gNRRaZYBjwsMQMVbZZaWoQCWskMALyntBg+Fo18zdgDxw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/typography@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.0.tgz#cf61dce2ee89bfa084d86e1b0f270a585bf9dfaf"
integrity sha512-m4SjA9OjZRDKowN3cPzEa8e2GlTlEn3ZmW/Fy9eRNSp83iY+8a0xl6kCaF80v5qAVwVcpfEFyEHWxMJtkBw2uA==
"@material/typography@^0.44.1":
version "0.44.1"
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.1.tgz#a94f01172f9122180bc2ce0aa55658183a35590d"
integrity sha512-wMXHusg+Lp5Fdgoj3m0c+Lt6GCeGSh3EPRtQ1TQ2bwdBa0et2FqBaQRgXoq3tVmr0O/7unTfa0DoXlh4nVp1wA==
dependencies:
"@material/feature-targeting" "^0.44.1"
focus-trap@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
dependencies:
tabbable "^3.1.2"
xtend "^4.0.1"
material-components-web@^0.44.0:
version "0.44.0"
resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.44.0.tgz#ff782e8d7bdd8212d3c6022a731258d0d42da531"
integrity sha512-BSRLf58SMVhAvlDhJDlcgYuvzeMwbMHKTJ7oIB8LaM24ZpXBxP9XCYJpKheMtiVLrgllCGDlJ/47OIDReHQXdQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/auto-init" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/card" "^0.44.0"
"@material/checkbox" "^0.44.0"
"@material/chips" "^0.44.0"
"@material/dialog" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/drawer" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/fab" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/floating-label" "^0.44.0"
"@material/form-field" "^0.44.0"
"@material/grid-list" "^0.44.0"
"@material/icon-button" "^0.44.0"
"@material/icon-toggle" "^0.44.0"
"@material/image-list" "^0.44.0"
"@material/layout-grid" "^0.41.0"
"@material/line-ripple" "^0.43.0"
"@material/linear-progress" "^0.43.0"
"@material/list" "^0.44.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/radio" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/select" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/slider" "^0.44.0"
"@material/snackbar" "^0.44.0"
"@material/switch" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-bar" "^0.44.0"
"@material/tab-indicator" "^0.43.0"
"@material/tab-scroller" "^0.44.0"
"@material/textfield" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/toolbar" "^0.44.0"
"@material/top-app-bar" "^0.44.0"
"@material/typography" "^0.44.0"
tabbable@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
xtend@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 B

View File

@ -1,42 +0,0 @@
{
"manifest_version": 2,
"name": "Coder",
"version": "1",
"icons": {
"128": "icon_128.png"
},
"permissions": [
"storage",
"webview",
"http://*/*",
"https://*/*"
],
"app": {
"background": {
"scripts": [
"out/background.js"
]
},
"content": {
"scripts": [
"out/content.js"
]
}
},
"commands": {
"toggle-feature-foo": {
"suggested_key": {
"default": "Ctrl+W"
},
"description": "Toggle feature foo",
"global": true
}
},
"sockets": {
"tcpServer": {
"listen": [
""
]
}
}
}

View File

@ -1,9 +0,0 @@
{
"name": "@coder/chrome-app",
"dependencies": {
"@types/chrome": "^0.0.79"
},
"scripts": {
"build": "../../../node_modules/.bin/webpack --config ./webpack.config.js"
}
}

View File

@ -1,13 +0,0 @@
/// <reference path="../node_modules/@types/chrome/index.d.ts" />
// tslint:disable-next-line:no-any
const chromeApp = (<any>chrome).app;
chromeApp.runtime.onLaunched.addListener(() => {
chromeApp.window.create("src/index.html", {
outerBounds: {
width: 400,
height: 500,
},
});
});

View File

@ -1,92 +0,0 @@
//@ts-ignore
import { TcpHost, TcpServer, TcpConnection } from "@coder/app/common/src/app";
import { Event, Emitter } from "@coder/events/src";
export const tcpHost: TcpHost = {
listen(host: string, port: number): Promise<TcpServer> {
const socketApi: {
readonly tcpServer: {
create(props: {}, cb: (createInfo: { readonly socketId: number }) => void): void;
listen(socketId: number, address: string, port: number, callback: (result: number) => void): void;
disconnect(socketId: number, callback: () => void): void;
readonly onAccept: {
addListener(callback: (info: { readonly socketId: number; readonly clientSocketId: number }) => void): void;
};
};
readonly tcp: {
readonly onReceive: {
addListener(callback: (info: { readonly socketId: number; readonly data: ArrayBuffer; }) => void): void;
};
close(socketId: number, callback?: () => void): void;
send(socketId: number, data: ArrayBuffer, callback?: () => void): void;
setPaused(socketId: number, value: boolean): void;
};
// tslint:disable-next-line:no-any
} = (<any>chrome).sockets;
return new Promise((resolve, reject): void => {
socketApi.tcpServer.create({}, (createInfo) => {
const serverSocketId = createInfo.socketId;
socketApi.tcpServer.listen(serverSocketId, host, port, (result) => {
if (result < 0) {
return reject("Failed to listen: " + chrome.runtime.lastError);
}
const connectionEmitter = new Emitter<TcpConnection>();
socketApi.tcpServer.onAccept.addListener((info) => {
if (info.socketId !== serverSocketId) {
return;
}
const dataEmitter = new Emitter<ArrayBuffer>();
socketApi.tcp.onReceive.addListener((recvInfo) => {
if (recvInfo.socketId !== info.clientSocketId) {
return;
}
dataEmitter.emit(recvInfo.data);
});
socketApi.tcp.setPaused(info.clientSocketId, false);
connectionEmitter.emit({
send: (data): Promise<void> => {
return new Promise<void>((res): void => {
socketApi.tcp.send(info.clientSocketId, data, () => {
res();
});
});
},
close: (): Promise<void> => {
return new Promise((res): void => {
socketApi.tcp.close(info.clientSocketId, () => {
res();
});
});
},
get onData(): Event<ArrayBuffer> {
return dataEmitter.event;
},
});
});
resolve({
get onConnection(): Event<TcpConnection> {
return connectionEmitter.event;
},
close: (): Promise<void> => {
return new Promise((res): void => {
socketApi.tcpServer.disconnect(serverSocketId, () => {
res();
});
});
},
});
});
});
});
},
};

View File

@ -1,33 +0,0 @@
import { create } from "@coder/app/common/src/app";
import { tcpHost } from "./chome";
create({
storage: {
get: <T>(key: string): Promise<T | undefined> => {
return new Promise<T | undefined>((resolve, reject): void => {
try {
chrome.storage.sync.get(key, (items) => {
resolve(items[key]);
});
} catch (ex) {
reject(ex);
}
});
},
set: <T>(key: string, value: T): Promise<void> => {
return new Promise<void>((resolve, reject): void => {
try {
chrome.storage.sync.set({
[key]: value,
}, () => {
resolve();
});
} catch (ex) {
reject(ex);
}
});
},
},
tcp: tcpHost,
node: document.getElementById("main") as HTMLDivElement,
});

View File

@ -1,15 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="style-src 'self' https://use.typekit.net; font-src 'self' https://use.typekit.net;">
<link rel="stylesheet" type="text/css" href="/out/main.css">
</head>
<body>
<div id="main"></div>
<script src="/out/content.js"></script>
</body>
</html>

View File

@ -1,37 +0,0 @@
const path = require("path");
const webpack = require("webpack");
const merge = require("webpack-merge");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const HtmlWebpackPlugin = require("html-webpack-plugin");
const prod = process.env.NODE_ENV === "production";
module.exports = [
merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
devtool: "none",
mode: "development",
target: "web",
output: {
path: path.join(__dirname, "out"),
filename: "background.js",
},
entry: [
"./packages/app/chrome/src/background.ts"
],
plugins: [
]
}),
merge(require(path.join(__dirname, "../../../scripts", "webpack.general.config.js"))(), {
devtool: "none",
mode: "development",
target: "web",
output: {
path: path.join(__dirname, "out"),
filename: "content.js",
},
entry: [
"./packages/app/chrome/src/content.ts"
],
plugins: [
]
}),
];

View File

@ -1,22 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/chrome@^0.0.79":
version "0.0.79"
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.79.tgz#1c83b35bd9b21b6204fb56e4816a1ea65dc013e5"
integrity sha512-4+Xducpig6lpwVX65Hk8KSZwRoURHXMDbd38SDNcV8TBaw4xyJki39fjB1io2h7ip+BsyFvgTm9OxR5qneLPiA==
dependencies:
"@types/filesystem" "*"
"@types/filesystem@*":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.29.tgz#ee3748eb5be140dcf980c3bd35f11aec5f7a3748"
integrity sha512-85/1KfRedmfPGsbK8YzeaQUyV1FQAvMPMTuWFQ5EkLd2w7szhNO96bk3Rh/SKmOfd9co2rCLf0Voy4o7ECBOvw==
dependencies:
"@types/filewriter" "*"
"@types/filewriter@*":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
integrity sha1-wFTor02d11205jq8dviFFocU1LM=

View File

@ -1,13 +0,0 @@
{
"name": "@coder/app-common",
"main": "src/app.ts",
"dependencies": {
"material-components-web": "^0.44.0",
"react": "^16.8.1",
"react-dom": "^16.8.1"
},
"devDependencies": {
"@types/react": "^16.8.2",
"@types/react-dom": "^16.8.0"
}
}

View File

@ -1,279 +0,0 @@
@font-face {
font-family: 'aktiv-grotesk';
font-weight: 400;
// src: url("fonts/AktivGroteskRegular.ttf"); /* IE9 Compat Modes */
src: url("fonts/AktivGroteskRegular.woff2") format("woff2"), url("fonts/AktivGroteskRegular.woff") format("woff"); /* Pretty Modern Browsers */
}
@font-face {
font-family: 'aktiv-grotesk';
font-weight: 500;
src: url("fonts/AktivGroteskMedium.woff2") format("woff2"), url("fonts/AktivGroteskMedium.woff") format("woff"); /* Pretty Modern Browsers */
// src: url("fonts/AktivGroteskMedium.ttf");
}
@font-face {
font-family: 'aktiv-grotesk';
font-weight: 700;
src: url("fonts/AktivGroteskBold.woff2") format("woff2"), url("fonts/AktivGroteskBold.woff") format("woff"); /* Pretty Modern Browsers */
// src: url("fonts/AktivGroteskBold.ttf") format("ttf"); /* IE9 Compat Modes */
}
body, button, input {
font-family: 'aktiv-grotesk',sans-serif !important;
}
body {
margin: 0;
background-color: #F6F8FB;
--mdc-theme-primary: #2A2E37;
}
webview {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
opacity: 0;
pointer-events: none;
transition: 150ms opacity ease;
&.active {
opacity: 1;
pointer-events: all;
}
}
.logo-fill {
fill: #2A2E37;
}
.main {
& > .header {
width: 100%;
height: 71px;
border-bottom: 1px solid rgba(117, 122, 131, 0.1);
display: flex;
margin-bottom: 60px;
.logo {
max-height: fit-content;
width: 145px;
}
.shrinker {
max-width: 1145px;
width: 100%;
margin: 0 auto;
display: flex;
}
}
.content {
max-width: 960px;
width: 100%;
padding-bottom: 100px;
margin: 0 auto;
}
}
.servers {
color: #2B343B;
& > .header {
display: flex;
flex-direction: row;
align-items: center;
padding-bottom: 21px;
h3 {
font-size: 24px;
font-weight: 500;
letter-spacing: 0.35px;
line-height: 33px;
margin: 0;
margin-left: 30px;
}
.add-server {
margin-left: auto;
border-radius: 24px;
font-weight: bold;
font-size: 14px;
letter-spacing: 1.25px;
}
.refresh {
margin-left: 16px;
margin-right: 15px;
cursor: pointer;
svg {
@keyframes rotate {
100% { transform: rotate(360deg); }
}
&.refreshing {
animation: rotate 1s linear infinite;
}
}
}
}
& > .grid {
display: grid;
grid-template-columns: 1fr 1.6fr 1.3fr 1.1fr 0.6fr 0.4fr;
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
border-radius: 0 0 5px 5px;
.mdc-linear-progress {
grid-column-start: 1;
grid-column-end: 7;
// height: 0;
position: relative;
--mdc-theme-primary: rgb(107, 109, 102);
height: 5px;
&:after {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: #2A2E37;
transition: 500ms opacity ease;
content: " ";
}
&.loading {
&:after {
opacity: 0;
}
}
}
.title, .value {
padding-top: 14px;
padding-bottom: 14px;
}
.title {
background-color: var(--mdc-theme-primary);
font-size: 10px;
color: #9D9FA4;
font-weight: bold;
letter-spacing: 2px;
line-height: 12px;
text-transform: uppercase;
// padding-top: 15px;
// padding-bottom: 10px;
&:first-child {
padding-left: 30px;
border-radius: 10px 0 0 0;
}
&:nth-child(6) {
padding-right: 30px;
border-radius: 0 10px 0 0;
}
&.servername {
color: white;
}
}
.value {
border-top: 1px solid #EBEBF2;
font-size: 14px;
letter-spacing: 0.2px;
display: flex;
align-items: center;
color: #717680;
background-color: white;
&.dark {
background-color: #F6F8FB;
}
&.servername {
.logo {
height: 25px;
}
}
&.strong {
font-weight: 600;
color: #2B343B;
font-size: 14px;
letter-spacing: 0.6px;
}
&.status {
padding-left: 36px;
span {
margin-left: 7px;
line-height: 0px;
}
}
&.buttons {
button {
margin-left: auto;
border-radius: 24px;
border: 1px solid #CFD1D7;
font-size: 14px;
font-weight: bold;
letter-spacing: 1.25px;
line-height: 16px;
padding-left: 18px;
padding-right: 18px;
}
}
&.icons {
padding-left: 16px;
}
&:last-child {
border-bottom-right-radius: 5px;
}
&:nth-last-child(6) {
border-bottom-left-radius: 5px;
}
}
}
}
.flex-row {
display: flex;
flex-direction: row;
}
.floater {
box-shadow: 0 8px 80px 10px rgba(69, 65, 78, 0.08);
border-radius: 10px;
padding: 3em;
min-width: 300px;
width: 100%;
& > h1 {
font-size: 3.5em;
margin-top: 0px;
// margin-bottom: 0px;
}
}
.mdc-ripple-upgraded--unbounded {
padding: 2px;
padding-top: 5px;
cursor: pointer;
}

View File

@ -1,33 +0,0 @@
//@ts-ignore
import { MDCTextField } from "@material/textfield";
import { TcpHost } from "./connection";
import { StorageProvider } from "./storage";
import "material-components-web/dist/material-components-web.css";
import "./app.scss";
import "./tooltip.scss";
import * as React from "react";
import { render } from "react-dom";
import { Main } from "./containers";
export * from "./connection";
export interface App {
readonly tcp: TcpHost;
readonly storage: StorageProvider;
readonly node: HTMLElement;
}
export interface RegisteredServer {
readonly host: "coder" | "self";
readonly hostname: string;
readonly name: string;
}
export const create = async (app: App): Promise<void> => {
let servers = await app.storage.get<RegisteredServer[]>("servers");
if (!servers) {
servers = [];
}
render(<Main />, app.node);
};

View File

@ -1,17 +0,0 @@
import { Event } from "@coder/events";
import { TunnelCloseEvent } from "@coder/tunnel/src/client";
export interface TcpHost {
listen(host: string, port: number): Promise<TcpServer>;
}
export interface TcpServer {
readonly onConnection: Event<TcpConnection>;
close(): Promise<void>;
}
export interface TcpConnection {
readonly onData: Event<ArrayBuffer>;
send(data: ArrayBuffer): Promise<void>;
close(): Promise<void>;
}

View File

@ -1,573 +0,0 @@
//@ts-ignore
import { MDCRipple } from "@material/ripple";
//@ts-ignore
import { MDCTextField } from "@material/textfield";
//@ts-ignore
import { MDCLinearProgress } from "@material/linear-progress";
import * as React from "react";
import * as ReactDOM from "react-dom";
import { RegisteredServer } from "./app";
// tslint:disable-next-line:no-any
declare var WebSettings: any;
interface AuthedUser {
readonly username: string;
}
export class Main extends React.Component<void, {
readonly view: "servers" | "add-server";
readonly loading: boolean;
}> {
private webview: HTMLWebViewElement | undefined;
public constructor(props: void) {
super(props);
this.state = {
view: "servers",
loading: false,
};
}
public componentDidMount(): void {
window.addEventListener("message", (event) => {
if (event.data === "back") {
if (this.webview) {
this.webview.classList.remove("active");
}
}
if (event.data === "loaded") {
if (this.webview) {
// this.setState({ loading: false });
// this.webview.classList.add("active");
}
}
});
if (this.webview) {
this.webview.addEventListener("error", (event) => {
console.error(event);
});
this.webview.addEventListener("loadstart", (event) => {
this.setState({ loading: true });
});
this.webview.addEventListener("loadstop", (event) => {
this.setState({ loading: false });
this.webview!.classList.add("active");
// tslint:disable-next-line:no-any
const cw = (this.webview as any).contentWindow as Window;
cw.postMessage("app", "*");
});
}
}
public render(): JSX.Element {
return (
<div className="main">
<div className="header">
<div className="shrinker">
<Logo />
</div>
</div>
<div className="content">
{((): JSX.Element => {
switch (this.state.view) {
case "servers":
return (
<Servers servers={[
{
host: "coder",
hostname: "--",
name: "Coder",
},
{
host: "self",
hostname: "http://localhost:8080",
name: "Dev Server",
},
]}
user={{
username: "Kyle",
}}
onSelect={(server): void => {
if (this.webview) {
this.webview.setAttribute("src", server.hostname);
}
}}
onAddServer={() => this.setState({ view: "add-server" })}
loading={this.state.loading}
/>
);
case "add-server":
return (
<div>Add server</div>
);
}
})()}
</div>
<webview ref={(wv: HTMLWebViewElement): HTMLWebViewElement => this.webview = wv}></webview>
</div>
);
}
}
export class AddServer extends React.Component {
public render(): JSX.Element {
return (
<div className="add-server">
<h3>Add Server</h3>
<p>Something about what you can do once you add your own server. A link to setup guides for this would be great as well.</p>
<Input label="Address" id="address" />
<br></br>
</div>
);
}
}
export class Servers extends React.Component<{
readonly user?: AuthedUser;
readonly servers: ReadonlyArray<RegisteredServer>;
readonly onSelect: (server: RegisteredServer) => void;
readonly onAddServer: () => void;
readonly loading: boolean;
}, {
readonly refreshing: boolean;
}> {
// tslint:disable-next-line:no-any
public constructor(props: any) {
super(props);
this.state = {
refreshing: false,
};
}
public render(): JSX.Element {
return (
<div className="servers">
<div className="header">
<h3>Servers</h3>
<Button onClick={(): void => this.props.onAddServer()} className="add-server" type="unelevated">Add Server</Button>
<Ripple>
<div className="refresh">
<svg onClick={(): void => this.doRefresh()} className={this.state.refreshing ? "refreshing" : ""} width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g>
<g transform="translate(4.000000, 4.000000)" fill="#2A2E37">
<path d="M8,3 C9.179,3 10.311,3.423 11.205,4.17 L8.883,6.492 L15.094,7.031 L14.555,0.82 L12.625,2.75 C11.353,1.632 9.71,1 8,1 C4.567,1 1.664,3.454 1.097,6.834 L3.07,7.165 C3.474,4.752 5.548,3 8,3 Z" id="Path"></path>
<path d="M8,13 C6.821,13 5.689,12.577 4.795,11.83 L7.117,9.508 L0.906,8.969 L1.445,15.18 L3.375,13.25 C4.647,14.368 6.29,15 8,15 C11.433,15 14.336,12.546 14.903,9.166 L12.93,8.835 C12.526,11.248 10.452,13 8,13 Z" id="Path"></path>
</g>
<rect id="Rectangle" fillRule="nonzero" x="0" y="0" width="24" height="24"></rect>
</g>
</g>
</svg>
</div>
</Ripple>
</div>
<div className="grid">
<div className="title status">
Status
</div>
<div className="title servername">
Server Name
</div>
<div className="title hostname">
Hostname
</div>
<div className="title details">
Details
</div>
<div className="title">
{/* Used for continue/launch buttons */}
</div>
<div className="title">
{/* Used for logout and delete buttons */}
</div>
<div role="progressbar" className={`mdc-linear-progress mdc-linear-progress--indeterminate ${this.props.loading ? "loading" : ""}`} ref={(d) => {
if (d) new MDCLinearProgress(d)}}>
<div className="mdc-linear-progress__buffering-dots"></div>
<div className="mdc-linear-progress__buffer"></div>
<div className="mdc-linear-progress__bar mdc-linear-progress__primary-bar">
<span className="mdc-linear-progress__bar-inner"></span>
</div>
<div className="mdc-linear-progress__bar mdc-linear-progress__secondary-bar">
<span className="mdc-linear-progress__bar-inner"></span>
</div>
</div>
{this.props.servers.map((server, i) => {
return (
<Server key={server.hostname + i} user={this.props.user} server={server} onSelect={(): void => this.props.onSelect(server)} />
);
})}
</div>
</div>
);
}
private doRefresh(): void {
if (this.state.refreshing) {
return;
}
this.setState({
refreshing: true,
}, () => {
setTimeout(() => {
this.setState({
refreshing: false,
});
}, 1500);
});
}
}
interface ServerProps {
readonly user?: AuthedUser;
readonly server: RegisteredServer;
readonly onSelect: () => void;
}
export class Server extends React.Component<ServerProps, {
readonly user?: AuthedUser;
readonly status: "Online" | "Offline" | "Checking";
readonly version: string;
}> {
// tslint:disable-next-line:no-any
public constructor(props: ServerProps) {
super(props);
this.state = {
status: props.server.host === "coder" ? "Online" : "Checking",
version: "",
};
}
public componentWillMount(): void {
if (this.props.server.host !== "self") {
return;
}
const xhr = new XMLHttpRequest();
xhr.open("GET", this.props.server.hostname);
xhr.addEventListener("error", (err) => {
this.setState({
status: "Offline",
});
});
xhr.addEventListener("loadend", () => {
if (xhr.status === 200) {
this.setState({
status: "Online",
version: process.env.VERSION,
});
} else {
this.setState({
status: "Offline",
});
}
});
xhr.send();
}
public render(): JSX.Element {
return (
<>
<div className={`status value ${this.extraClasses}`}>
{((): JSX.Element => {
switch (this.state.status) {
case "Offline":
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard-Copy-3" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<circle id="Oval" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" cx="8" cy="8" r="7.25"></circle>
<path d="M5.15444712,5.15444712 L10.8455529,10.8455529" id="Path-4" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero"></path>
<path d="M5.15444712,5.15444712 L10.8455529,10.8455529" id="Path-4" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" transform="translate(8.000000, 8.000000) scale(-1, 1) translate(-8.000000, -8.000000) "></path>
</g>
</svg>
);
case "Online":
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard-Copy-4" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="checkmark-copy-21" fillRule="nonzero">
<circle id="Oval" fill="#2B343B" cx="8" cy="8" r="8"></circle>
<polyline id="Path-2" stroke="#FFFFFF" strokeWidth="1.5" points="3.46296296 8.62222222 6.05555556 11.1111111 12.537037 4.88888889"></polyline>
</g>
</g>
</svg>
);
case "Checking":
return (
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard-Copy-5" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<circle id="Oval" stroke="#2B343B" strokeWidth="1.5" fillRule="nonzero" cx="8" cy="8" r="7.25"></circle>
<polyline id="Path" stroke="#2B343B" strokeWidth="1.5" points="7.90558664 4.63916767 7.90558664 8.63916767 11.9055866 8.63916767"></polyline>
</g>
</svg>
);
default:
throw new Error("unsupported status");
}
})()}
<span>
{this.state.status}
</span>
</div>
<div className={`servername value strong ${this.extraClasses}`}>
{this.props.server.host === "coder" ? (
<Logo />
) : this.props.server.name}
</div>
<div className={`hostname value ${this.extraClasses}`}>
{this.props.server.hostname}
</div>
<div className={`details value ${this.extraClasses}`}>
{this.props.server.host === "coder" && this.props.user ? `Logged in as ${this.props.user.username}` : this.state.version}
</div>
<div className={`buttons value ${this.extraClasses}`}>
<Button onClick={(): void => this.props.onSelect()} className="add-server" type="outlined">{this.props.server.host === "coder" ? "Continue" : "Launch"}</Button>
</div>
<div className={`icons value ${this.extraClasses}`}>
<Ripple>
<div>
{this.props.server.host === "coder" ? (
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="log-out-copy-2" transform="translate(4.000000, 4.000000)" fill="#2A2E37">
<polygon id="Path" points="4 4 0 8 4 12 4 9 10 9 10 7 4 7"></polygon>
<path d="M15,16 L6,16 C5.4,16 5,15.6 5,15 L5,12 L7,12 L7,14 L14,14 L14,2 L7,2 L7,4 L5,4 L5,1 C5,0.4 5.4,0 6,0 L15,0 C15.6,0 16,0.4 16,1 L16,15 C16,15.6 15.6,16 15,16 Z" id="Path"></path>
</g>
</g>
</svg>
) : (
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
<g id="Artboard" stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
<g id="bin" transform="translate(4.000000, 4.000000)" fill="#2B343B">
<rect id="Rectangle" x="5" y="7" width="2" height="6"></rect>
<rect id="Rectangle" x="9" y="7" width="2" height="6"></rect>
<path d="M12,1 C12,0.4 11.6,0 11,0 L5,0 C4.4,0 4,0.4 4,1 L4,3 L0,3 L0,5 L1,5 L1,15 C1,15.6 1.4,16 2,16 L14,16 C14.6,16 15,15.6 15,15 L15,5 L16,5 L16,3 L12,3 L12,1 Z M6,2 L10,2 L10,3 L6,3 L6,2 Z M13,5 L13,14 L3,14 L3,5 L13,5 Z" id="Shape" fillRule="nonzero"></path>
</g>
</g>
</svg>
)}
</div>
</Ripple>
</div>
</>
);
}
private get extraClasses(): string {
return this.props.server.host === "coder" ? "dark" : "";
}
}
export class Input extends React.Component<{
readonly label: string;
readonly id: string;
readonly type?: string;
}> {
private wrapper: HTMLDivElement | undefined;
public componentDidMount(): void {
if (this.wrapper) {
const textInput = new MDCTextField(this.wrapper);
}
}
public render(): JSX.Element {
return (
<div className="mdc-text-field mdc-text-field--outlined" ref={(i: HTMLDivElement): HTMLDivElement => this.wrapper = i}>
<input type={this.props.type || "text"} id={this.props.id} className="mdc-text-field__input" spellCheck={false}></input>
<div className="mdc-notched-outline">
<div className="mdc-notched-outline__leading"></div>
<div className="mdc-notched-outline__notch">
<label htmlFor={this.props.id} className="mdc-floating-label">{this.props.label}</label>
</div>
<div className="mdc-notched-outline__trailing"></div>
</div>
</div>
);
}
}
export class Button extends React.Component<{
readonly type: "outlined" | "unelevated";
readonly className?: string;
readonly onClick?: () => void;
}> {
private button: HTMLButtonElement | undefined;
public componentDidMount(): void {
if (this.button) {
const b = new MDCRipple(this.button);
}
}
public render(): JSX.Element {
return (
<button onClick={() => this.props.onClick ? this.props.onClick() : undefined} className={`mdc-button mdc-button--${this.props.type} ${this.props.className || ""}`} ref={(b: HTMLButtonElement): HTMLButtonElement => this.button = b}>
<span className="mdc-button__label">{this.props.children}</span>
</button>
);
}
}
export class Tooltip extends React.Component<{
readonly message: string;
}> {
public componentDidMount(): void {
Object.keys(this.refs).forEach((ref) => {
const el = this.refs[ref];
if (el) {
const element = ReactDOM.findDOMNode(el);
if (element) {
const te = document.createElement("div");
te.className = "md-tooltip-content";
te.innerHTML = this.props.message;
element.appendChild(te);
(element as HTMLElement).classList.add("md-tooltip");
}
}
});
}
public render(): JSX.Element {
return (
<>
{React.Children.map(this.props.children, (element, idx) => {
return React.cloneElement(element as any, { ref: idx });
})}
</>
);
}
}
export class Ripple extends React.Component<{
readonly className?: string;
}> {
public componentDidMount(): void {
Object.keys(this.refs).forEach((ref) => {
const el = this.refs[ref];
if (el) {
const element = ReactDOM.findDOMNode(el);
if (element) {
(element as HTMLElement).classList.add("mdc-ripple-surface");
(element as HTMLElement).setAttribute("data-mdc-ripple-is-unbounded", "");
const r = new MDCRipple(element);
}
}
});
}
public render(): JSX.Element {
return (
<>
{React.Children.map(this.props.children, (element, idx) => {
return React.cloneElement(element as any, { ref: idx });
})}
</>
);
}
}
export class Logo extends React.Component {
public render(): JSX.Element {
return (
<svg className="logo" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 471 117"
style={{enableBackground: "new 0 0 471 117"} as any} xmlSpace="preserve">
<g>
<g>
<path className="logo-fill" d="M217,75.6c5.9,0,10.7-2.3,14.5-7l7.7,7.9c-6.1,6.9-13.3,10.3-21.6,10.3s-15.1-2.6-20.5-7.9
C191.7,73.7,189,67,189,59s2.7-14.7,8.2-20s12.2-8,20.1-8c8.8,0,16.2,3.4,22.2,10.1l-7.5,8.5c-3.8-4.7-8.5-7.1-14.2-7.1
c-4.5,0-8.4,1.5-11.6,4.4c-3.2,3-4.8,6.9-4.8,11.9s1.5,9,4.5,12.1C209,74.1,212.6,75.6,217,75.6z M284.1,46.7
c-3.1-3.4-6.9-5.1-11.4-5.1s-8.3,1.7-11.4,5.1s-4.6,7.5-4.6,12.3s1.5,8.9,4.6,12.3s6.9,5,11.4,5s8.3-1.7,11.4-5
c3.1-3.4,4.6-7.5,4.6-12.3S287.2,50.1,284.1,46.7z M272.7,86.8c-8,0-14.7-2.7-20.1-8s-8.2-11.9-8.2-19.9c0-7.9,2.7-14.5,8.2-19.9
c5.4-5.3,12.2-8,20.1-8c8,0,14.7,2.7,20.1,8s8.2,11.9,8.2,19.9c0,7.9-2.7,14.5-8.2,19.9C287.4,84.1,280.7,86.8,272.7,86.8z
M352.3,39.4c5.1,4.7,7.7,11.2,7.7,19.6s-2.5,15-7.5,19.9s-12.7,7.3-22.9,7.3h-18.4V32.3h19C339.8,32.4,347.2,34.7,352.3,39.4z
M343.5,71.5c3-2.8,4.4-6.8,4.4-12.1s-1.5-9.4-4.4-12.2c-3-2.9-7.5-4.3-13.6-4.3h-6.7v32.8h7.6C336.3,75.6,340.5,74.2,343.5,71.5z
M409.3,32.4v10.7h-26.8v11.1h24.1v10.3h-24.1v11.2h27.7v10.6h-39.7V32.4H409.3L409.3,32.4z M464.6,50.3c0,8.6-3.4,14.2-10.3,16.7
l13.6,19.3h-14.8l-11.9-17.2h-8.3v17.2h-12V32.4h20.4c8.4,0,14.4,1.4,17.9,4.2C462.8,39.4,464.6,44,464.6,50.3z M450.1,56.7
c1.5-1.3,2.2-3.5,2.2-6.4s-0.8-4.9-2.3-6s-4.2-1.6-8.1-1.6h-9v16h8.8C445.8,58.7,448.6,58,450.1,56.7z"/>
</g>
<g>
<path className="logo-fill" d="M164.8,50.9c-3.3,0-5.5-1.9-5.5-5.8V22.7c0-14.3-6-22.2-21.5-22.2h-7.2v15.1h2.2c6.1,0,9,3.3,9,9.2v19.8
c0,8.6,2.6,12.1,8.3,13.9c-5.7,1.7-8.3,5.3-8.3,13.9c0,4.9,0,9.8,0,14.7c0,4.1,0,8.1-1.1,12.2c-1.1,3.8-2.9,7.4-5.4,10.5
c-1.4,1.8-3,3.3-4.8,4.7v2h7.2c15.5,0,21.5-7.9,21.5-22.2V71.9c0-4,2.1-5.8,5.5-5.8h4.1V51h-4V50.9L164.8,50.9z"/>
<path className="logo-fill" d="M115.8,23.3H93.6c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h22.3c0.5,0,0.9,0.4,0.9,0.9v1.7
C116.8,22.9,116.3,23.3,115.8,23.3z"/>
<path className="logo-fill" d="M119.6,44.9h-16.2c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h16.2c0.5,0,0.9,0.4,0.9,0.9V44
C120.5,44.4,120.1,44.9,119.6,44.9z"/>
<path className="logo-fill" d="M126,34.1H93.6c-0.5,0-0.9-0.4-0.9-0.9v-1.7c0-0.5,0.4-0.9,0.9-0.9h32.3c0.5,0,0.9,0.4,0.9,0.9v1.7
C126.8,33.6,126.5,34.1,126,34.1z"/>
<g>
<path className="logo-fill" d="M67.9,28.2c2.2,0,4.4,0.2,6.5,0.7v-4.1c0-5.8,3-9.2,9-9.2h2.2V0.5h-7.2c-15.5,0-21.5,7.9-21.5,22.2v7.4
C60.4,28.9,64.1,28.2,67.9,28.2z"/>
</g>
<path className="logo-fill" d="M132.8,82.6c-1.6-12.7-11.4-23.3-24-25.7c-3.5-0.7-7-0.8-10.4-0.2c-0.1,0-0.1-0.1-0.2-0.1
c-5.5-11.5-17.3-19.1-30.1-19.1S43.6,44.9,38,56.4c-0.1,0-0.1,0.1-0.2,0.1c-3.6-0.4-7.2-0.2-10.8,0.7c-12.4,3-21.8,13.4-23.5,26
c-0.2,1.3-0.3,2.6-0.3,3.8c0,3.8,2.6,7.3,6.4,7.8c4.7,0.7,8.8-2.9,8.7-7.5c0-0.7,0-1.5,0.1-2.2c0.8-6.4,5.7-11.8,12.1-13.3
c2-0.5,4-0.6,5.9-0.3c6.1,0.8,12.1-2.3,14.7-7.7c1.9-4,4.9-7.5,8.9-9.4c4.4-2.1,9.4-2.4,14-0.8c4.8,1.7,8.4,5.3,10.6,9.8
c2.3,4.4,3.4,7.5,8.3,8.1c2,0.3,7.6,0.2,9.7,0.1c4.1,0,8.2,1.4,11.1,4.3c1.9,2,3.3,4.5,3.9,7.3c0.9,4.5-0.2,9-2.9,12.4
c-1.9,2.4-4.5,4.2-7.4,5c-1.4,0.4-2.8,0.5-4.2,0.5c-0.8,0-1.9,0-3.2,0c-4,0-12.5,0-18.9,0c-4.4,0-7.9-3.5-7.9-7.9V78.4V63.9
c0-1.2-1-2.2-2.2-2.2h-3.1c-6.1,0.1-11,6.9-11,14.1s0,26.3,0,26.3c0,7.8,6.3,14.1,14.1,14.1c0,0,34.7-0.1,35.2-0.1
c8-0.8,15.4-4.9,20.4-11.2C131.5,98.8,133.8,90.8,132.8,82.6z"/>
</g>
</g>
</svg>
);
}
}
// const $ = <K extends keyof HTMLElementTagNameMap>(tagName: K, className?: string, content?: string): HTMLElementTagNameMap[K] => {
// const el = document.createElement(tagName);
// if (className) {
// el.className = className;
// }
// if (content) {
// el.innerText = content;
// }
// return el;
// };
// const createInput = (id: string, labelName: string, type: string = "text"): HTMLDivElement => {
// // <div class="mdc-text-field mdc-text-field--outlined">
// // <input type="password" id="password" class="mdc-text-field__input">
// // <!-- <label class="mdc-floating-label" for="name">Name</label>
// // <div class="mdc-line-ripple"></div> -->
// // <div class="mdc-notched-outline">
// // <div class="mdc-notched-outline__leading"></div>
// // <div class="mdc-notched-outline__notch">
// // <label for="password" class="mdc-floating-label">Password</label>
// // </div>
// // <div class="mdc-notched-outline__trailing"></div>
// // </div>
// const wrapper = $("div", "mdc-text-field mdc-text-field--outlined");
// const input = $("input", "mdc-text-field__input");
// input.type = type;
// input.id = id;
// wrapper.appendChild(input);
// const notchedOutline = $("div", "mdc-notched-outline");
// notchedOutline.appendChild($("div", "mdc-notched-outline__leading"));
// const notch = $("div", "mdc-notched-outline__notch");
// const label = $("label", "mdc-floating-label", labelName);
// label.setAttribute("for", id);
// notch.appendChild(label);
// notchedOutline.appendChild(notch);
// wrapper.appendChild(notchedOutline);
// wrapper.appendChild($("div", "mdc-notched-outline__trailing"));
// const field = new MDCTextField(wrapper);
// return wrapper;
// };
// export const createCoderLogin = (parentNode: HTMLElement): void => {
// parentNode.appendChild($("h1", "header", "Login with Coder"));
// parentNode.appendChild(createInput("username", "Username"));
// parentNode.appendChild($("br"));
// parentNode.appendChild($("br"));
// parentNode.appendChild(createInput("password", "Password", "password"));
// };

View File

@ -1,5 +0,0 @@
export interface StorageProvider {
set<T>(key: string, value: T): Promise<void>;
get<T>(key: string): Promise<T | undefined>;
}

View File

@ -1,24 +0,0 @@
.md-tooltip {
position: relative;
}
.md-tooltip-content {
position: absolute;
bottom: -35px;
left: 50%;
padding: 7px;
transform: translateX(-50%) scale(0);
transition: transform 0.15s cubic-bezier(0, 0, 0.2, 1);
transform-origin: top;
background: rgba(67, 67, 67, 0.97);
color: white;
letter-spacing: 0.3px;
border-radius: 3px;
font-size: 12px;
font-weight: 500;
z-index: 2;
}
.md-tooltip:hover .md-tooltip-content {
transform: translateX(-50%) scale(1);
}

View File

@ -1,601 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@material/animation@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.41.0.tgz#315b45b32e1aeebee8a4cf555b8ad52076d09ddd"
integrity sha512-yYAwJbX3Q2AFd4dr6IYOsWLQy2HN8zWOFVl9AbUXunjzTfJCa/ecfXCriaT6qkmoNoHeTdJHRrsQJZC5GsPvzA==
"@material/auto-init@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/auto-init/-/auto-init-0.41.0.tgz#8a59bb0b83e0f51ead9508074f9a29b2b6a20eec"
integrity sha512-jp6L8MpYu7DudgDfA8iTyD9BwQrYPEDsIJGbqzN9vcCBl5FoBatkB8pcFXKr+1mRBk7T1Qmf6+H5nDtxyXjHEQ==
"@material/base@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/base/-/base-0.41.0.tgz#badadce711b4c25b1eb889a5e7581e32cd07c421"
integrity sha512-tEyzwBRu3d1H120SfKsDVYZHcqT5lKohh/7cWKR93aAaPDkSvjpKJIjyu2yuSkjpDduVZGzVocYbOvhUKhhzXQ==
"@material/button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/button/-/button-0.44.0.tgz#f01dcbea88bdc314e7640b76e5558101c8b4d69d"
integrity sha512-T8u8s8rlB49D9/5Nh5b0XsKRgSq3X0yWGo71MgaTnCnwxt8oZ6PxW/cH6Nn3Xp0NCr3mlSVQs08BviUfAmtlsg==
dependencies:
"@material/elevation" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/card@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/card/-/card-0.44.0.tgz#e62050e3e77f525173a015119200055cd7b71bf0"
integrity sha512-fUixXuh133bVp5c1gPIHreL5jwMJEeVIQf0E4xdxhkA+i4ku8fIAvIW62EuCmfJsXicv4q8NG3Ip6pCY+NW3ZA==
dependencies:
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/checkbox@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/checkbox/-/checkbox-0.44.0.tgz#5d0eee1db006db9f0fb700bf1c20408292305cf7"
integrity sha512-IzucxG+NuPNyByGmHg/cuYJ5ooMKouuj994PZXZyqb7owfrjjtXm7wjav66cvCowbVbcoa1owQMGBi18C9f4TQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/chips@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/chips/-/chips-0.44.0.tgz#bf553a5bf5db7320978402ac92069c9688b84d5a"
integrity sha512-+qrme6sGwYmX/ixHAo3Z1M7lorsxRyKexn1l+BSBX5PBc2f4w5Ml1eYYYcyVGfLX9LXmefRk0G6dUXXPyCE00g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/checkbox" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/dialog@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/dialog/-/dialog-0.44.0.tgz#388f93f9f225824c75cbe9da8c464a52d79972e8"
integrity sha512-V6ButfknOMKOscL0Y39yLjamxvrIuyugobjf5s44ZeJc+9jUSkC7M3zP+T7rh358NcX+JSPP8iCGmUn/+LXpMQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/dom@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-0.41.0.tgz#6756865f97bad4c91ee75e69d769d7cdc25398ae"
integrity sha512-wOJrMwjPddYXpQFZAIaCLWI3TO/6KU1lxESTBzunni8A4FHQVWhokml5Xt85GqZwmPFeIF2s+D0wfbWyrGBuKQ==
"@material/drawer@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/drawer/-/drawer-0.44.0.tgz#74b3ddfb741bffc72331c7a73cf62716fd3f0ab3"
integrity sha512-AYwFe0jgqqSmJd1bny8JJTA2SScF86Wfbk99lXXEwd/acS8IbnnuH6zfAg6MyJX12FDb8dE8Z/Ok1IwLiVa9sQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/list" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
focus-trap "^4.0.2"
"@material/elevation@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/elevation/-/elevation-0.44.0.tgz#ca16a67188ce9810dc2fa3d7a39073e72df4b754"
integrity sha512-edNou34yFCSMb6XXe/6Y7AEh8DigWAhBUyIeMiMBD4k1km2xYCJbcnl8FBPJFteOrca97KoJComRlJPB6EurRQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/fab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/fab/-/fab-0.44.0.tgz#0bcbbdfb6f24c53d59e08c9c0d400d2616dea184"
integrity sha512-1CEP4NlXDYioJ/YpSjh/MlIygtoC7CaHqIbucxX1O5WRPmS7K1uPt+o7netbLErAmcJdV/JrI/tqh9kKuX2x/Q==
dependencies:
"@material/animation" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/feature-targeting@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-0.44.0.tgz#52cc73f0c8a83159de0357aebe74f15f9856fb4c"
integrity sha512-ShuC2TOLfjFpYUCQFtvkqDJhM6HTaucSx5HkRbOvOG+VlpzDx6pAqRUmdVaq2p7tHoQf2vwPMlSVm3gOjWt4VQ==
"@material/floating-label@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/floating-label/-/floating-label-0.44.0.tgz#8694cd49f6905641b67a9e7a112b820d028f09c7"
integrity sha512-k4npGNxyMtnjgJZNjU5VvqqaUqlbzlbVAhepT8PxYTpj+4Skg6PjHwieTCDCgsbqHvFcQX+WfUrSZXY7wFV7cw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/form-field@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/form-field/-/form-field-0.44.0.tgz#b7518e885c0e953a2a5fe0140af927c30e066f4e"
integrity sha512-SK+V34dzoBCQ/CHn5nBp8BAh21Vj9p1pcok+/WpYBTeg4EphTYP2nUQLMNEN92l6zjgAYf+g9Ocj3t26HNHWqA==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/grid-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/grid-list/-/grid-list-0.44.0.tgz#bd31d992ab1a910731e4a47c11fe91d44e3bc02b"
integrity sha512-NxLL0A48K1O14ZZymFIyf6HDbF33+NgXYXqP2yosTC3Jw4iwmUcJTpFTmSw1U/m1xT4zEpeKEGJ4vjVUWpS9Mg==
dependencies:
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/icon-button@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-0.44.0.tgz#febbcfd27d91eca8096ae042b9c07ed0f65345e9"
integrity sha512-n6L7RaRyEci6eGsuBTSEG+t9ATHAHaMlf9zuTWorEnIXY4DAmGO7ggBjw4+1XIOjhpLeIjyJdcvUK6Yz/UVM6Q==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/icon-toggle@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/icon-toggle/-/icon-toggle-0.44.0.tgz#b9de32f194b5aa9721ca799d59be0f477a5c5305"
integrity sha512-8T1b4iK61/q/3U0iIjEDJ9do5viCQ45IbrQqa8EYCZ1KDU/Q8z5N+bvOzQK8XnTL51BdDRMgP9lfQZh6nszmkA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/image-list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/image-list/-/image-list-0.44.0.tgz#a27996962044ac8c9ce6cb509f63746f08ed2e98"
integrity sha512-kI9aKJdc1Bd02l8nRTGG1wy/lNkECScfnBmCiLQ3XjAFtRYd2eWO0Z/AVvUG3egsIZnZBxqFGGsf5Htm9E/HiQ==
dependencies:
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/layout-grid@^0.41.0":
version "0.41.0"
resolved "https://registry.yarnpkg.com/@material/layout-grid/-/layout-grid-0.41.0.tgz#2e7d3be76313e0684d573b10c2c6a88b3230d251"
integrity sha512-Sa5RNoTGgfIojqJ9E94p7/k11V6q/tGk7HwKi4AQNAPjxield0zcl3G/SbsSb8YSHoK+D+7OXDN+n11x6EqF7g==
"@material/line-ripple@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/line-ripple/-/line-ripple-0.43.0.tgz#6cb530bab53f055f3583646a21ad20c1703f3a83"
integrity sha512-sXZYW4Em5uLEnAuVsQCO+sVHsTg7J2TOTJ0+akwZFMmd2tmNicjarQdlGIE9iU7Wjm51NOoLAu6Mz+8kLg90bQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/linear-progress@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/linear-progress/-/linear-progress-0.43.0.tgz#4821424aa24c78de256e74a91d5be3df55c534d9"
integrity sha512-bqkDcob+xp1mFkyBsOkoaLgrtapmz7jznGoI3nmkqyk75EB2XQcn1H8Vr6cnp/jkF4nbKu0GdVJO3VXUFmGmrQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/list@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/list/-/list-0.44.0.tgz#cf1910e15b66759334b8618d1110fbcc72c3d326"
integrity sha512-35gkN1+XZaau9d9ngyN2x14bzkj/ajZCDm7mbWibDQy272A16j6KuFLQFA8RUQV04OgL4YPVxY87dpCn/p+uTg==
dependencies:
"@material/base" "^0.41.0"
"@material/dom" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/menu-surface@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu-surface/-/menu-surface-0.44.0.tgz#902c081df42859b925a5b4502791b3febf48f1ae"
integrity sha512-s49kvIlQ4H5wvMD4yeHMMqnamPod06IUagMK6Ry0oTpUANSnyeNXxa3HkScl7DMJiS8IJeV21fSLAzlZYP2PDQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/menu@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/menu/-/menu-0.44.0.tgz#776ec8a04406266a0a0a13eb140b1fd691e442cb"
integrity sha512-92XvAcv9rBW1jQ3UvwJ8zk9hbSRe/FqSuFdZ9fNPE348dCY2pbcdQfnUJTe3ycAN/I1c5frkrhx8F0II+nfbNQ==
dependencies:
"@material/base" "^0.41.0"
"@material/list" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/notched-outline@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/notched-outline/-/notched-outline-0.44.0.tgz#d5a2e1d649921575a7cd2e88ee4581e4a1809573"
integrity sha512-c3nqOqUQAmW3h4zBbZVbMRdf4nNTYm0tVwXIAwmcCs5nvAthEHnzHwwFddNP7/9Wju6LZ0uqWn6xlyKly0uipw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/radio@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/radio/-/radio-0.44.0.tgz#f4cacdfabc7d765aa000cb34c5a37966f6d4fd6d"
integrity sha512-ar7uhlfHuSwM9JUUjpv7pLDLE0p436cCMxNTpmMjWabfvo3pMWlExvk72Oj81tBgfxY/uASLB3oj4neudXu9JQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/ripple@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.44.0.tgz#98920ff8ec4bf5714c97df3d190f02f8a5b476cc"
integrity sha512-MlaW4nUDgzS0JOBfsUawXyTOilr0jn+xvTVn6PEaGh2rmhNA54AhixXvdsVUWE9lfmHAsZV0AJHz2z7nunNhbQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/feature-targeting" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/rtl@^0.42.0":
version "0.42.0"
resolved "https://registry.yarnpkg.com/@material/rtl/-/rtl-0.42.0.tgz#1836e78186c2d8b996f6fbf97adab203535335bc"
integrity sha512-VrnrKJzhmspsN8WXHuxxBZ69yM5IwhCUqWr1t1eNfw3ZEvEj7i1g3P31HGowKThIN1dc1Wh4LE14rCISWCtv5w==
"@material/select@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/select/-/select-0.44.0.tgz#8041b4fe6247d013b0f12685fbdf50aa9ff57b35"
integrity sha512-tw3/QIBLuRCT+5IXx4IPiJk7FzeGeR65JEizdRUItH8yzoIiQLs/b2i3KtHM2YBXHgeUcEBF2AOqPX2opdYhug==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/selection-control@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/selection-control/-/selection-control-0.44.0.tgz#63d5c65a47a9f54f5a0316b5ecdb5e5f35108609"
integrity sha512-HgCAPnMVMEj4X4ILkFSifqtZ3Tcc5HkU+Lfk9g0807sCaN/qBKWkYKLH2WJUbW8uk+MXK7DgP1khtS5zzanJWA==
dependencies:
"@material/ripple" "^0.44.0"
"@material/shape@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/shape/-/shape-0.43.0.tgz#b877acfd8be8abc9ddcf6601eb60dd0588292415"
integrity sha512-KGnoQV4G2OQbMe5Lr5Xbk8XNlO93Qi/juxXtd2wrAfiaPmktD8ug0CwdVDOPBOmj9a0gX3Ofi9XWcoU+tLEVjg==
"@material/slider@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/slider/-/slider-0.44.0.tgz#2055df894eb725e541cde50a544719c07934755b"
integrity sha512-Lnn2fdUesXX4O0UpJzveEuOj+og+dXCwhal73u3l3NXEdc/eRgYxwWdF3ww4MmCZ786EwUmjb4vIc9olN4DO3A==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/snackbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/snackbar/-/snackbar-0.44.0.tgz#d98672b849f5f295e4fac2d474a9c80f11945518"
integrity sha512-KhCrmJm8Zu/ZZPuRCGfMKsZ0vudINlNgTjlOau0kQ/UgR1xBUvLOE8NjyXZr0RQz5obyW7xpyIWIpscn0IUeyw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/icon-button" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/switch@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/switch/-/switch-0.44.0.tgz#f2cbb447437b12eb3bc7f0ec8318dbd3b4f0afce"
integrity sha512-EadCg6lHUF260R2Q/l++vXIITqacvbXlobSoewA5ib6y9BU2g7l13wL1W8xAVJNUMgFa/PyN+EKT3oCql7jZLg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/selection-control" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/tab-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-bar/-/tab-bar-0.44.0.tgz#b17d791bd557b1d84892fef1a1d8b8d6fef7c6d6"
integrity sha512-kCrt05d61YXyY43SNc0dPGuqysbcLr/KRDBvzpXgE4gv2jCCVhhjAH10KPlx8pthp/UtvrYJHb34acAKEGzdHA==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-scroller" "^0.44.0"
"@material/tab-indicator@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/tab-indicator/-/tab-indicator-0.43.0.tgz#37fd05513ba55ae218d9068c986c2676096fd6eb"
integrity sha512-RMNMQpWYghWpM6d0ayfuHEPzTiebKG0bMthViiD6tly8PubmOT8mShNhPm8ihybhDPUOLSz+7V4QNE5wikLEYg==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/theme" "^0.43.0"
"@material/tab-scroller@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab-scroller/-/tab-scroller-0.44.0.tgz#82d092ed45d2ee9d82038bed318e6ff6bdc36dad"
integrity sha512-Ufd3NWBN11kY2oA7bGmTYWGP1uz2mq0tfDM0JOiqoLMgD7y3Z18kmxnpq2qkg1vi4kvix28hBYGGMfLlq9rGDA==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/tab" "^0.44.0"
"@material/tab@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/tab/-/tab-0.44.0.tgz#254b92cff99015f0bd59a86d08d3f1c4744d0742"
integrity sha512-czrbGjtKkmUS3iYBX523xT5GOkjP0h+0x9fTnw+heFNpw5dCn6cZvlj3D9ayZU+ZH93x68TFhFVBuLU5f0EBXw==
dependencies:
"@material/base" "^0.41.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/tab-indicator" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/textfield@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/textfield/-/textfield-0.44.0.tgz#277b33948ddff33f7f643323895e5a683f013601"
integrity sha512-IMBwMcE82eVU+Wifpu0t84tozvBPLCeqQELDtZNYujKg3RxaultzJLwIyGKPMZ9R4yPEpV2vgXPGKE+2/AWt0g==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/floating-label" "^0.44.0"
"@material/line-ripple" "^0.43.0"
"@material/notched-outline" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/theme@^0.43.0":
version "0.43.0"
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.43.0.tgz#6d9fa113c82e841817882172c152d60d2d203ca6"
integrity sha512-/zndZL6EihI18v2mYd4O8xvOBAAXmLeHyHVK28LozSAaJ9okQgD25wq5Ktk95oMTmPIC+rH66KcK6371ivNk8g==
"@material/toolbar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/toolbar/-/toolbar-0.44.0.tgz#6689aecdeccc78b7a890a3abbe8b68a2c6339307"
integrity sha512-YgLlOFQ5VzFLQBpXYSMviEbYox0fia+sasHuYPUhTAtas1ExVt9EEiIolDSVvhv2PruTReKKefxSbXAqGlOHog==
dependencies:
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/top-app-bar@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/top-app-bar/-/top-app-bar-0.44.0.tgz#2495c7f9567568fb961ccced24f479c4806a72af"
integrity sha512-tf0yXQJARYs8UPaH8oo3LnsSHEiur7Zm8Fc3hv3F0gNRRaZYBjwsMQMVbZZaWoQCWskMALyntBg+Fo18zdgDxw==
dependencies:
"@material/animation" "^0.41.0"
"@material/base" "^0.41.0"
"@material/elevation" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/shape" "^0.43.0"
"@material/theme" "^0.43.0"
"@material/typography" "^0.44.0"
"@material/typography@^0.44.0":
version "0.44.0"
resolved "https://registry.yarnpkg.com/@material/typography/-/typography-0.44.0.tgz#cf61dce2ee89bfa084d86e1b0f270a585bf9dfaf"
integrity sha512-m4SjA9OjZRDKowN3cPzEa8e2GlTlEn3ZmW/Fy9eRNSp83iY+8a0xl6kCaF80v5qAVwVcpfEFyEHWxMJtkBw2uA==
"@types/prop-types@*":
version "15.5.8"
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce"
integrity sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==
"@types/react-dom@^16.8.0":
version "16.8.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.0.tgz#c565f43f9d2ec911f9e0b8f3b74e25e67879aa3f"
integrity sha512-Jp4ufcEEjVJEB0OHq2MCZcE1u3KYUKO6WnSuiU/tZeYeiZxUoQavfa/TZeiIT+1XoN6l0lQVNM30VINZFDeolQ==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^16.8.2":
version "16.8.2"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.2.tgz#3b7a7f7ea89d1c7d68b00849fb5de839011c077b"
integrity sha512-6mcKsqlqkN9xADrwiUz2gm9Wg4iGnlVGciwBRYFQSMWG6MQjhOZ/AVnxn+6v8nslFgfYTV8fNdE6XwKu6va5PA==
dependencies:
"@types/prop-types" "*"
csstype "^2.2.0"
csstype@^2.2.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.2.tgz#3043d5e065454579afc7478a18de41909c8a2f01"
integrity sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow==
focus-trap@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-4.0.2.tgz#4ee2b96547c9ea0e4252a2d4b2cca68944194663"
integrity sha512-HtLjfAK7Hp2qbBtLS6wEznID1mPT+48ZnP2nkHzgjpL4kroYHg0CdqJ5cTXk+UO5znAxF5fRUkhdyfgrhh8Lzw==
dependencies:
tabbable "^3.1.2"
xtend "^4.0.1"
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
material-components-web@^0.44.0:
version "0.44.0"
resolved "https://registry.yarnpkg.com/material-components-web/-/material-components-web-0.44.0.tgz#ff782e8d7bdd8212d3c6022a731258d0d42da531"
integrity sha512-BSRLf58SMVhAvlDhJDlcgYuvzeMwbMHKTJ7oIB8LaM24ZpXBxP9XCYJpKheMtiVLrgllCGDlJ/47OIDReHQXdQ==
dependencies:
"@material/animation" "^0.41.0"
"@material/auto-init" "^0.41.0"
"@material/base" "^0.41.0"
"@material/button" "^0.44.0"
"@material/card" "^0.44.0"
"@material/checkbox" "^0.44.0"
"@material/chips" "^0.44.0"
"@material/dialog" "^0.44.0"
"@material/dom" "^0.41.0"
"@material/drawer" "^0.44.0"
"@material/elevation" "^0.44.0"
"@material/fab" "^0.44.0"
"@material/feature-targeting" "^0.44.0"
"@material/floating-label" "^0.44.0"
"@material/form-field" "^0.44.0"
"@material/grid-list" "^0.44.0"
"@material/icon-button" "^0.44.0"
"@material/icon-toggle" "^0.44.0"
"@material/image-list" "^0.44.0"
"@material/layout-grid" "^0.41.0"
"@material/line-ripple" "^0.43.0"
"@material/linear-progress" "^0.43.0"
"@material/list" "^0.44.0"
"@material/menu" "^0.44.0"
"@material/menu-surface" "^0.44.0"
"@material/notched-outline" "^0.44.0"
"@material/radio" "^0.44.0"
"@material/ripple" "^0.44.0"
"@material/rtl" "^0.42.0"
"@material/select" "^0.44.0"
"@material/selection-control" "^0.44.0"
"@material/shape" "^0.43.0"
"@material/slider" "^0.44.0"
"@material/snackbar" "^0.44.0"
"@material/switch" "^0.44.0"
"@material/tab" "^0.44.0"
"@material/tab-bar" "^0.44.0"
"@material/tab-indicator" "^0.43.0"
"@material/tab-scroller" "^0.44.0"
"@material/textfield" "^0.44.0"
"@material/theme" "^0.43.0"
"@material/toolbar" "^0.44.0"
"@material/top-app-bar" "^0.44.0"
"@material/typography" "^0.44.0"
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
prop-types@^15.6.2:
version "15.7.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.1.tgz#2fa61e0a699d428b40320127733ee2931f05d9d1"
integrity sha512-f8Lku2z9kERjOCcnDOPm68EBJAO2K00Q5mSgPAUE/gJuBgsYLbVy6owSrtcHj90zt8PvW+z0qaIIgsIhHOa1Qw==
dependencies:
object-assign "^4.1.1"
react-is "^16.8.1"
react-dom@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.1.tgz#ec860f98853d09d39bafd3a6f1e12389d283dbb4"
integrity sha512-N74IZUrPt6UiDjXaO7UbDDFXeUXnVhZzeRLy/6iqqN1ipfjrhR60Bp5NuBK+rv3GMdqdIuwIl22u1SYwf330bg==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.13.1"
react-is@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.1.tgz#a80141e246eb894824fb4f2901c0c50ef31d4cdb"
integrity sha512-ioMCzVDWvCvKD8eeT+iukyWrBGrA3DiFYkXfBsVYIRdaREZuBjENG+KjrikavCLasozqRWTwFUagU/O4vPpRMA==
react@^16.8.1:
version "16.8.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.8.1.tgz#ae11831f6cb2a05d58603a976afc8a558e852c4a"
integrity sha512-wLw5CFGPdo7p/AgteFz7GblI2JPOos0+biSoxf1FPsGxWQZdN/pj6oToJs1crn61DL3Ln7mN86uZ4j74p31ELQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
prop-types "^15.6.2"
scheduler "^0.13.1"
scheduler@^0.13.1:
version "0.13.1"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.1.tgz#1a217df1bfaabaf4f1b92a9127d5d732d85a9591"
integrity sha512-VJKOkiKIN2/6NOoexuypwSrybx13MY7NSy9RNt8wPvZDMRT1CW6qlpF5jXRToXNHz3uWzbm2elNpZfXfGPqP9A==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
tabbable@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
xtend@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=

View File

@ -1,4 +0,0 @@
{
"name": "@coder/disposable",
"main": "src/index.ts"
}

View File

@ -1,3 +0,0 @@
export interface IDisposable {
dispose(): void;
}

View File

@ -1 +0,0 @@
export * from "./disposable";

View File

@ -1,4 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1

View File

@ -1,18 +0,0 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
# If you would like to upload your .git directory, .gitignore file or files
# from your .gitignore file, remove the corresponding line
# below:
.git
.gitignore
src
# Node.js dependencies:
node_modules/

View File

@ -1,8 +0,0 @@
FROM node
COPY out/main.js /main.js
COPY package.json /package.json
RUN yarn
ENV NODE_ENV production
CMD ["node", "/main.js"]

View File

@ -1,5 +0,0 @@
runtime: nodejs10
service: cdrdns
network:
forwarded_ports:
- 53/udp

View File

@ -1,14 +0,0 @@
{
"name": "@coder/dns",
"main": "out/main.js",
"scripts": {
"build": "../../node_modules/.bin/webpack --config ./webpack.config.js"
},
"dependencies": {
"node-named": "^0.0.1"
},
"devDependencies": {
"ip-address": "^5.8.9",
"@types/ip-address": "^5.8.2"
}
}

View File

@ -1,109 +0,0 @@
import { field, logger } from "@coder/logger";
import * as http from "http";
//@ts-ignore
import * as named from "node-named";
import * as ip from "ip-address";
import { words, wordKeys } from "./words";
import * as dgram from "dgram";
const oldCreate = dgram.createSocket;
// tslint:disable-next-line:no-any
(<any>dgram).createSocket = (_: any, callback: any): dgram.Socket => {
return oldCreate("udp4", callback);
};
interface DnsQuery {
name(): string;
// tslint:disable-next-line:no-any
addAnswer(domain: string, target: any, ttl: number): void;
}
const dnsServer: {
listen(port: number, host: string, callback: () => void): void;
on(event: "query", callback: (query: DnsQuery) => void): void;
send(query: DnsQuery): void;
} = named.createServer();
const isDev = process.env.NODE_ENV !== "production";
const dnsPort = isDev ? 9999 : 53;
dnsServer.listen(dnsPort, "0.0.0.0", () => {
logger.info("DNS server started", field("port", dnsPort));
});
dnsServer.on("query", (query) => {
const domain = query.name();
const reqParts = domain.split(".");
if (reqParts.length < 2) {
dnsServer.send(query);
logger.info("Invalid request", field("request", domain));
return;
}
const allWords = reqParts.shift()!;
if (allWords.length > 16) {
dnsServer.send(query);
logger.info("Invalid request", field("request", domain));
return;
}
const wordParts = allWords.split(/(?=[A-Z])/);
const ipParts: string[] = [];
// Should be left with HowAreYouNow
for (let i = 0; i < wordParts.length; i++) {
const part = wordParts[i];
if (part.length > 4) {
dnsServer.send(query);
logger.info("Words too long", field("request", domain));
return;
}
const ipPart = words[part.toLowerCase()];
if (typeof ipPart === "undefined") {
dnsServer.send(query);
logger.info("Word not found in index", field("part", part), field("request", domain));
return;
}
ipParts.push(ipPart.toString());
}
const address = new ip.Address4(ipParts.join("."));
if (address.isValid()) {
logger.info("Responded with valid address query", field("address", address.address), field("request", domain));
query.addAnswer(domain, new named.ARecord(address.address), 99999);
} else {
logger.warn("Received invalid request", field("request", domain));
}
dnsServer.send(query);
});
const httpServer = http.createServer((request, response) => {
const remoteAddr = request.connection.remoteAddress;
if (!remoteAddr) {
response.writeHead(422);
response.end();
return;
}
const hostHeader = request.headers.host;
if (!hostHeader) {
response.writeHead(422);
response.end();
return;
}
const host = remoteAddr.split(".").map(p => wordKeys[Number.parseInt(p, 10)]).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join("");
logger.info("Resolved host", field("remote-addr", remoteAddr), field("host", host));
response.writeHead(200);
response.write(`${host}.${hostHeader}`);
response.end();
});
const httpPort = isDev ? 3000 : 80;
httpServer.listen(httpPort, "0.0.0.0", () => {
logger.info("HTTP server started", field("port", httpPort));
});

View File

@ -1,260 +0,0 @@
export const words: { readonly [key: string]: number } = {
term: 0,
salt: 1,
barn: 2,
corn: 3,
went: 4,
feel: 5,
rest: 6,
will: 7,
pale: 8,
cave: 9,
dirt: 10,
time: 11,
in: 12,
pie: 13,
star: 14,
iron: 15,
door: 16,
tone: 17,
want: 18,
task: 19,
zoo: 20,
nor: 21,
fall: 22,
tell: 23,
noon: 24,
new: 25,
per: 26,
end: 27,
arm: 28,
been: 29,
wolf: 30,
port: 31,
beat: 32,
pour: 33,
far: 34,
may: 35,
tie: 36,
moon: 37,
duck: 38,
us: 39,
led: 40,
met: 41,
bank: 42,
day: 43,
due: 44,
both: 45,
pet: 46,
gate: 47,
pain: 48,
rock: 49,
fill: 50,
open: 51,
thus: 52,
mark: 53,
our: 54,
loud: 55,
wife: 56,
say: 57,
flag: 58,
as: 59,
ride: 60,
once: 61,
sun: 62,
duty: 63,
pure: 64,
made: 65,
gulf: 66,
pig: 67,
fish: 68,
name: 69,
army: 70,
have: 71,
ill: 72,
meal: 73,
ago: 74,
late: 75,
view: 76,
atom: 77,
pen: 78,
mud: 79,
tail: 80,
sink: 81,
cow: 82,
rear: 83,
fur: 84,
go: 85,
suit: 86,
come: 87,
fear: 88,
also: 89,
sail: 90,
row: 91,
lay: 92,
noun: 93,
hat: 94,
am: 95,
mail: 96,
keep: 97,
drop: 98,
than: 99,
weak: 100,
by: 101,
who: 102,
fire: 103,
good: 104,
sick: 105,
care: 106,
pink: 107,
lady: 108,
war: 109,
sets: 110,
swam: 111,
well: 112,
shoe: 113,
bent: 114,
fuel: 115,
wet: 116,
fog: 117,
land: 118,
lead: 119,
tax: 120,
deal: 121,
verb: 122,
take: 123,
save: 124,
gift: 125,
had: 126,
gold: 127,
slow: 128,
drew: 129,
lamp: 130,
roof: 131,
hung: 132,
wild: 133,
able: 134,
girl: 135,
warn: 136,
were: 137,
know: 138,
camp: 139,
milk: 140,
neck: 141,
aid: 142,
fair: 143,
bell: 144,
dig: 145,
hope: 146,
wood: 147,
away: 148,
cook: 149,
just: 150,
form: 151,
food: 152,
hall: 153,
mind: 154,
for: 155,
card: 156,
half: 157,
sat: 158,
now: 159,
team: 160,
rush: 161,
face: 162,
wire: 163,
such: 164,
tool: 165,
make: 166,
fat: 167,
hold: 168,
inch: 169,
bill: 170,
mean: 171,
tide: 172,
burn: 173,
talk: 174,
tape: 175,
hard: 176,
mine: 177,
on: 178,
year: 179,
rich: 180,
sum: 181,
yes: 182,
baby: 183,
wide: 184,
how: 185,
clay: 186,
car: 187,
here: 188,
cent: 189,
bowl: 190,
post: 191,
said: 192,
see: 193,
raw: 194,
foot: 195,
life: 196,
bar: 197,
from: 198,
path: 199,
meat: 200,
show: 201,
sent: 202,
wait: 203,
mice: 204,
ten: 205,
pot: 206,
nice: 207,
idea: 208,
or: 209,
onto: 210,
rose: 211,
your: 212,
this: 213,
cat: 214,
bet: 215,
took: 216,
hang: 217,
very: 218,
bend: 219,
mix: 220,
base: 221,
jack: 222,
her: 223,
leg: 224,
own: 225,
book: 226,
love: 227,
dawn: 228,
deer: 229,
hit: 230,
rain: 231,
gas: 232,
eat: 233,
tube: 234,
case: 235,
pipe: 236,
get: 237,
joy: 238,
ever: 239,
nest: 240,
home: 241,
egg: 242,
pack: 243,
hand: 244,
cold: 245,
hot: 246,
frog: 247,
peep: 248,
seed: 249,
rawr: 250,
top: 251,
meow: 252,
bark: 253,
eel: 254,
swap: 255,
};
export const wordKeys = Object.keys(words);

View File

@ -1,18 +0,0 @@
const path = require("path");
const merge = require("webpack-merge");
const root = path.resolve(__dirname, "../..");
module.exports = merge(
require(path.join(root, "scripts/webpack.node.config.js"))({
dirname: __dirname,
name: "dns",
}), {
externals: {
"node-named": "commonjs node-named",
},
entry: [
"./packages/dns/src/dns.ts"
],
},
);

View File

@ -1,88 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/ip-address@^5.8.2":
version "5.8.2"
resolved "https://registry.yarnpkg.com/@types/ip-address/-/ip-address-5.8.2.tgz#5e413c477f78b3a264745eac937538a6e6e0c1f6"
integrity sha512-LFlDGRjJDnahfPyNCZGXvlaevSmZTi/zDxjTdXeTs8TQ9pQkNZKbCWaJXW29a3bGPRsASqeO+jGgZlaTUi9jTw==
dependencies:
"@types/jsbn" "*"
"@types/jsbn@*":
version "1.2.29"
resolved "https://registry.yarnpkg.com/@types/jsbn/-/jsbn-1.2.29.tgz#28229bc0262c704a1506c3ed69a7d7e115bd7832"
integrity sha512-2dVz9LTEGWVj9Ov9zaDnpvqHFV+W4bXtU0EUEGAzWfdRNO3dlUuosdHpENI6/oQW+Kejn0hAjk6P/czs9h/hvg==
bunyan@0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-0.7.0.tgz#921065e70c936fe302a740e2c5605775beea2f42"
integrity sha1-khBl5wyTb+MCp0DixWBXdb7qL0I=
"coffee-script@>= 1.1.1":
version "1.12.7"
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==
ip-address@^5.8.9:
version "5.8.9"
resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.8.9.tgz#6379277c23fc5adb20511e4d23ec2c1bde105dfd"
integrity sha512-7ay355oMN34iXhET1BmCJVsHjOTSItEEIIpOs38qUC23AIhOy+xIPnkrTuEFjeLMrTJ7m8KMXWgWfy/2Vn9sDw==
dependencies:
jsbn "1.1.0"
lodash.find "^4.6.0"
lodash.max "^4.0.1"
lodash.merge "^4.6.0"
lodash.padstart "^4.6.1"
lodash.repeat "^4.1.0"
sprintf-js "1.1.0"
ipaddr.js@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-0.1.1.tgz#28c6a7c116a021c555544f906ab1ad540b1d635a"
integrity sha1-KManwRagIcVVVE+QarGtVAsdY1o=
dependencies:
coffee-script ">= 1.1.1"
jsbn@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040"
integrity sha1-sBMHyym2GKHtJux56RH4A8TaAEA=
lodash.find@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
lodash.max@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.max/-/lodash.max-4.0.1.tgz#8735566c618b35a9f760520b487ae79658af136a"
integrity sha1-hzVWbGGLNan3YFILSHrnllivE2o=
lodash.merge@^4.6.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54"
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==
lodash.padstart@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b"
integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs=
lodash.repeat@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/lodash.repeat/-/lodash.repeat-4.1.0.tgz#fc7de8131d8c8ac07e4b49f74ffe829d1f2bec44"
integrity sha1-/H3oEx2MisB+S0n3T/6CnR8r7EQ=
node-named@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/node-named/-/node-named-0.0.1.tgz#3607b434cf237ab99440f5ff6d19c05e3a93e217"
integrity sha1-Nge0NM8jermUQPX/bRnAXjqT4hc=
dependencies:
bunyan "0.7.0"
ipaddr.js "0.1.1"
sprintf-js@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.0.tgz#cffcaf702daf65ea39bb4e0fa2b299cec1a1be46"
integrity sha1-z/yvcC2vZeo5u04PorKZzsGhvkY=

View File

@ -1,4 +0,0 @@
{
"name": "@coder/events",
"main": "./src/index.ts"
}

View File

@ -1,99 +0,0 @@
import { IDisposable } from "@coder/disposable";
export interface Event<T> {
(listener: (value: T) => void): IDisposable;
(id: number | string, listener: (value: T) => void): IDisposable;
}
/**
* Emitter typecasts for a single event type. You can optionally use IDs, but
* using undefined with IDs will not work. If you emit without an ID, *all*
* listeners regardless of their ID (or lack thereof) will receive the event.
* Similarly, if you listen without an ID you will get *all* events for any or
* no ID.
*/
export class Emitter<T> {
private listeners = <Array<(value: T) => void>>[];
private readonly idListeners = new Map<number | string, Array<(value: T) => void>>();
public get event(): Event<T> {
return (id: number | string | ((value: T) => void), cb?: (value: T) => void): IDisposable => {
if (typeof id !== "function") {
if (this.idListeners.has(id)) {
this.idListeners.get(id)!.push(cb!);
} else {
this.idListeners.set(id, [cb!]);
}
return {
dispose: (): void => {
if (this.idListeners.has(id)) {
const cbs = this.idListeners.get(id)!;
const i = cbs.indexOf(cb!);
if (i !== -1) {
cbs.splice(i, 1);
}
}
},
};
}
cb = id;
this.listeners.push(cb);
return {
dispose: (): void => {
const i = this.listeners.indexOf(cb!);
if (i !== -1) {
this.listeners.splice(i, 1);
}
},
};
};
}
/**
* Emit an event with a value.
*/
public emit(value: T): void;
public emit(id: number | string, value: T): void;
public emit(id: number | string | T, value?: T): void {
if ((typeof id === "number" || typeof id === "string") && typeof value !== "undefined") {
if (this.idListeners.has(id)) {
this.idListeners.get(id)!.forEach((cb) => cb(value!));
}
this.listeners.forEach((cb) => cb(value!));
} else {
this.idListeners.forEach((cbs) => cbs.forEach((cb) => cb((id as T)!)));
this.listeners.forEach((cb) => cb((id as T)!));
}
}
/**
* Dispose the current events.
*/
public dispose(): void;
public dispose(id: number | string): void;
public dispose(id?: number | string): void {
if (typeof id !== "undefined") {
this.idListeners.delete(id);
} else {
this.listeners = [];
this.idListeners.clear();
}
}
public get counts(): { [key: string]: number } {
const counts = <{ [key: string]: number }>{};
if (this.listeners.length > 0) {
counts["n/a"] = this.listeners.length;
}
this.idListeners.forEach((cbs, id) => {
if (cbs.length > 0) {
counts[`${id}`] = cbs.length;
}
});
return counts;
}
}

View File

@ -1 +0,0 @@
export * from "./events";

View File

@ -1,122 +0,0 @@
import { Emitter } from "../src/events";
describe("Event", () => {
const emitter = new Emitter<number>();
it("should listen to global event", () => {
const fn = jest.fn();
const d = emitter.event(fn);
emitter.emit(10);
expect(fn).toHaveBeenCalledWith(10);
d.dispose();
});
it("should listen to id event", () => {
const fn = jest.fn();
const d = emitter.event(0, fn);
emitter.emit(0, 5);
expect(fn).toHaveBeenCalledWith(5);
d.dispose();
});
it("should listen to string id event", () => {
const fn = jest.fn();
const d = emitter.event("string", fn);
emitter.emit("string", 55);
expect(fn).toHaveBeenCalledWith(55);
d.dispose();
});
it("should not listen wrong id event", () => {
const fn = jest.fn();
const d = emitter.event(1, fn);
emitter.emit(0, 5);
emitter.emit(1, 6);
expect(fn).toHaveBeenCalledWith(6);
expect(fn).toHaveBeenCalledTimes(1);
d.dispose();
});
it("should listen to id event globally", () => {
const fn = jest.fn();
const d = emitter.event(fn);
emitter.emit(1, 11);
expect(fn).toHaveBeenCalledWith(11);
d.dispose();
});
it("should listen to global event", () => {
const fn = jest.fn();
const d = emitter.event(3, fn);
emitter.emit(14);
expect(fn).toHaveBeenCalledWith(14);
d.dispose();
});
it("should listen to id event multiple times", () => {
const fn = jest.fn();
const disposers = [
emitter.event(934, fn),
emitter.event(934, fn),
emitter.event(934, fn),
emitter.event(934, fn),
];
emitter.emit(934, 324);
expect(fn).toHaveBeenCalledTimes(4);
expect(fn).toHaveBeenCalledWith(324);
disposers.forEach((d) => d.dispose());
});
it("should dispose individually", () => {
const fn = jest.fn();
const d = emitter.event(fn);
const fn2 = jest.fn();
const d2 = emitter.event(1, fn2);
d.dispose();
emitter.emit(12);
emitter.emit(1, 12);
expect(fn).not.toBeCalled();
expect(fn2).toBeCalledTimes(2);
d2.dispose();
emitter.emit(12);
emitter.emit(1, 12);
expect(fn).not.toBeCalled();
expect(fn2).toBeCalledTimes(2);
});
it("should dispose by id", () => {
const fn = jest.fn();
emitter.event(fn);
const fn2 = jest.fn();
emitter.event(1, fn2);
emitter.dispose(1);
emitter.emit(12);
emitter.emit(1, 12);
expect(fn).toBeCalledTimes(2);
expect(fn2).not.toBeCalled();
});
it("should dispose all", () => {
const fn = jest.fn();
emitter.event(fn);
emitter.event(1, fn);
emitter.dispose();
emitter.emit(12);
emitter.emit(1, 12);
expect(fn).not.toBeCalled();
});
});

Some files were not shown because too many files have changed in this diff Show More