Drop privileges to respective uid
This commit is contained in:
		
							parent
							
								
									afad563d56
								
							
						
					
					
						commit
						91fe6ffd65
					
				| 
						 | 
					@ -2,6 +2,9 @@ FROM ubuntu:focal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ARG UID
 | 
					ARG UID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY scripts/docker-install-phase0.bash /tmp/
 | 
				
			||||||
 | 
					RUN /tmp/docker-install-phase0.bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY scripts/docker-install-phase1.bash /tmp/
 | 
					COPY scripts/docker-install-phase1.bash /tmp/
 | 
				
			||||||
RUN /tmp/docker-install-phase1.bash
 | 
					RUN /tmp/docker-install-phase1.bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +34,7 @@ RUN /tmp/docker-install-phase6.bash "$UID"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
USER docker
 | 
					USER docker
 | 
				
			||||||
WORKDIR /home/docker
 | 
					WORKDIR /home/docker
 | 
				
			||||||
 | 
					RUN chmod go-rwx /home/docker
 | 
				
			||||||
EXPOSE 6119
 | 
					EXPOSE 6119
 | 
				
			||||||
EXPOSE 6120
 | 
					EXPOSE 6120
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,9 @@ FROM ubuntu:focal
 | 
				
			||||||
# prod, it's not actually read by anything.
 | 
					# prod, it's not actually read by anything.
 | 
				
			||||||
ARG UID
 | 
					ARG UID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPY scripts/docker-install-phase0.bash /tmp/
 | 
				
			||||||
 | 
					RUN /tmp/docker-install-phase0.bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
COPY scripts/docker-install-phase1.bash /tmp/
 | 
					COPY scripts/docker-install-phase1.bash /tmp/
 | 
				
			||||||
RUN /tmp/docker-install-phase1.bash
 | 
					RUN /tmp/docker-install-phase1.bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +36,7 @@ RUN /tmp/docker-install-phase6.bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
USER docker
 | 
					USER docker
 | 
				
			||||||
WORKDIR /home/docker
 | 
					WORKDIR /home/docker
 | 
				
			||||||
 | 
					RUN chmod go-rwx /home/docker
 | 
				
			||||||
EXPOSE 6119
 | 
					EXPOSE 6119
 | 
				
			||||||
EXPOSE 6120
 | 
					EXPOSE 6120
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +44,7 @@ ENTRYPOINT ["/usr/local/bin/pid1.bash"]
 | 
				
			||||||
COPY scripts/pid1.bash /usr/local/bin/
 | 
					COPY scripts/pid1.bash /usr/local/bin/
 | 
				
			||||||
CMD ["yarn", "run", "server"]
 | 
					CMD ["yarn", "run", "server"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN mkdir /tmp/riju
 | 
					RUN mkdir /tmp/riju /tmp/riju/scripts
 | 
				
			||||||
COPY --chown=docker:docker package.json yarn.lock /tmp/riju/
 | 
					COPY --chown=docker:docker package.json yarn.lock /tmp/riju/
 | 
				
			||||||
RUN cd /tmp/riju && yarn install
 | 
					RUN cd /tmp/riju && yarn install
 | 
				
			||||||
COPY --chown=docker:docker webpack.config.js tsconfig.json tsconfig-webpack.json /tmp/riju/
 | 
					COPY --chown=docker:docker webpack.config.js tsconfig.json tsconfig-webpack.json /tmp/riju/
 | 
				
			||||||
| 
						 | 
					@ -48,10 +52,11 @@ COPY --chown=docker:docker frontend /tmp/riju/frontend
 | 
				
			||||||
RUN cd /tmp/riju && yarn run frontend
 | 
					RUN cd /tmp/riju && yarn run frontend
 | 
				
			||||||
COPY --chown=docker:docker backend /tmp/riju/backend
 | 
					COPY --chown=docker:docker backend /tmp/riju/backend
 | 
				
			||||||
RUN cd /tmp/riju && yarn run backend
 | 
					RUN cd /tmp/riju && yarn run backend
 | 
				
			||||||
 | 
					COPY --chown=docker:docker scripts/compile-system.bash /tmp/riju/scripts
 | 
				
			||||||
COPY --chown=docker:docker system /tmp/riju/system
 | 
					COPY --chown=docker:docker system /tmp/riju/system
 | 
				
			||||||
RUN cd /tmp/riju && RIJU_PRIVILEGED=1 yarn run system
 | 
					RUN cd /tmp/riju && RIJU_PRIVILEGED=1 yarn run system
 | 
				
			||||||
COPY --chown=docker:docker . /home/docker/src
 | 
					COPY --chown=docker:docker . /home/docker/src
 | 
				
			||||||
RUN cp -R /tmp/riju/* /home/docker/src/ && rm -rf /tmp/riju
 | 
					RUN sudo cp -a /tmp/riju/* /home/docker/src/ && rm -rf /tmp/riju
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /home/docker/src
 | 
					WORKDIR /home/docker/src
 | 
				
			||||||
RUN sudo deluser docker sudo
 | 
					RUN sudo deluser docker sudo
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							| 
						 | 
					@ -18,7 +18,7 @@ image-prod: ## Build Docker image for production
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: docker
 | 
					.PHONY: docker
 | 
				
			||||||
docker: image-dev ## Run shell with source code and deps inside Docker
 | 
					docker: image-dev ## Run shell with source code and deps inside Docker
 | 
				
			||||||
	scripts/docker.bash run -it --rm -v "$(PWD):/home/docker/src" -p 6119:6119 -p 6120:6120 riju bash
 | 
						scripts/docker.bash run -it --rm -v "$(PWD):/home/docker/src" -p 6119:6119 -p 6120:6120 -h riju riju bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: deploy
 | 
					.PHONY: deploy
 | 
				
			||||||
deploy: ## Deploy current master from GitHub to production
 | 
					deploy: ## Deploy current master from GitHub to production
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								README.md
								
								
								
								
							
							
						
						
									
										14
									
								
								README.md
								
								
								
								
							| 
						 | 
					@ -18,18 +18,18 @@ documenting it until it has reached feature-completeness.
 | 
				
			||||||
To run the webserver, all you need is Yarn. Just run `yarn install` as
 | 
					To run the webserver, all you need is Yarn. Just run `yarn install` as
 | 
				
			||||||
usual to install dependencies. For production, it's:
 | 
					usual to install dependencies. For production, it's:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $ yarn backend
 | 
					    $ yarn backend    |- or run all three with 'yarn build'
 | 
				
			||||||
    $ yarn frontend
 | 
					    $ yarn frontend   |
 | 
				
			||||||
    $ yarn system
 | 
					    $ yarn system     |
 | 
				
			||||||
    $ yarn server
 | 
					    $ yarn server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
For development with file watching and automatic server rebooting and
 | 
					For development with file watching and automatic server rebooting and
 | 
				
			||||||
all that, it's:
 | 
					all that, it's:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $ yarn backend-dev
 | 
					    $ yarn backend-dev    |- or run all four with 'yarn dev'
 | 
				
			||||||
    $ yarn frontend-dev
 | 
					    $ yarn frontend-dev   |
 | 
				
			||||||
    $ yarn system-dev
 | 
					    $ yarn system-dev     |
 | 
				
			||||||
    $ yarn server-dev
 | 
					    $ yarn server-dev     |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The webserver listens on `localhost:6119`. Now, although the server
 | 
					The webserver listens on `localhost:6119`. Now, although the server
 | 
				
			||||||
itself will work, the only languages that will work are the ones that
 | 
					itself will work, the only languages that will work are the ones that
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,49 +1,48 @@
 | 
				
			||||||
import * as fs from "fs";
 | 
					 | 
				
			||||||
import * as path from "path";
 | 
					import * as path from "path";
 | 
				
			||||||
import * as WebSocket from "ws";
 | 
					import * as WebSocket from "ws";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as mkdirp from "mkdirp";
 | 
					 | 
				
			||||||
import * as nodeCleanup from "node-cleanup";
 | 
					 | 
				
			||||||
import * as pty from "node-pty";
 | 
					import * as pty from "node-pty";
 | 
				
			||||||
import { IPty } from "node-pty";
 | 
					import { IPty } from "node-pty";
 | 
				
			||||||
import * as tmp from "tmp";
 | 
					 | 
				
			||||||
import { v4 as getUUID } from "uuid";
 | 
					import { v4 as getUUID } from "uuid";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PRIVILEGED } from "./config";
 | 
				
			||||||
import { LangConfig, langs } from "./langs";
 | 
					import { LangConfig, langs } from "./langs";
 | 
				
			||||||
import { borrowUser } from "./users";
 | 
					import { borrowUser } from "./users";
 | 
				
			||||||
 | 
					import { callPrivileged, getEnv, spawnPrivileged } from "./util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class Session {
 | 
					export class Session {
 | 
				
			||||||
  id: string;
 | 
					  uuid: string;
 | 
				
			||||||
  code: string;
 | 
					  code: string;
 | 
				
			||||||
  config: LangConfig;
 | 
					  config: LangConfig;
 | 
				
			||||||
  term: { pty: IPty | null; live: boolean };
 | 
					  term: { pty: IPty | null; live: boolean };
 | 
				
			||||||
  ws: WebSocket;
 | 
					  ws: WebSocket;
 | 
				
			||||||
  tmpdir: string | null;
 | 
					  homedir: string | null;
 | 
				
			||||||
  tmpdirCleanup: (() => void) | null;
 | 
					 | 
				
			||||||
  uid: number | null;
 | 
					  uid: number | null;
 | 
				
			||||||
  uidCleanup: (() => Promise<void>) | null;
 | 
					  uidCleanup: (() => Promise<void>) | null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  log = (msg: string) => console.log(`[${this.id}] ${msg}`);
 | 
					  log = (msg: string) => console.log(`[${this.uuid}] ${msg}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(ws: WebSocket, lang: string) {
 | 
					  constructor(ws: WebSocket, lang: string) {
 | 
				
			||||||
    this.id = getUUID();
 | 
					    this.uuid = getUUID();
 | 
				
			||||||
    this.log(`Creating session, language ${lang}`);
 | 
					    this.log(`Creating session, language ${lang}`);
 | 
				
			||||||
    this.ws = ws;
 | 
					    this.ws = ws;
 | 
				
			||||||
    this.config = langs[lang];
 | 
					    this.config = langs[lang];
 | 
				
			||||||
    this.term = { pty: null, live: false };
 | 
					    this.term = { pty: null, live: false };
 | 
				
			||||||
    this.code = "";
 | 
					    this.code = "";
 | 
				
			||||||
    this.tmpdir = null;
 | 
					    this.homedir = null;
 | 
				
			||||||
    this.tmpdirCleanup = null;
 | 
					 | 
				
			||||||
    this.uid = null;
 | 
					    this.uid = null;
 | 
				
			||||||
    this.uidCleanup = null;
 | 
					    this.uidCleanup = null;
 | 
				
			||||||
    ws.on("message", this.handleClientMessage);
 | 
					    ws.on("message", this.handleClientMessage);
 | 
				
			||||||
    ws.on("close", () =>
 | 
					    ws.on("close", () =>
 | 
				
			||||||
      this.cleanup().catch((err) =>
 | 
					      this.cleanup().catch((err) => {
 | 
				
			||||||
        this.log(`Error during session cleanup: ${err}`)
 | 
					        this.log(`Error during session cleanup`);
 | 
				
			||||||
      )
 | 
					        console.log(err);
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    nodeCleanup();
 | 
					    this.run().catch((err) => {
 | 
				
			||||||
    this.run().catch((err) => this.log(`Error while running: ${err}`));
 | 
					      this.log(`Error while setting up environment for pty`);
 | 
				
			||||||
 | 
					      console.log(err);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  handleClientMessage = (event: string) => {
 | 
					  handleClientMessage = (event: string) => {
 | 
				
			||||||
    let msg: any;
 | 
					    let msg: any;
 | 
				
			||||||
| 
						 | 
					@ -81,9 +80,18 @@ export class Session {
 | 
				
			||||||
      ({ uid: this.uid, cleanup: this.uidCleanup } = await borrowUser(
 | 
					      ({ uid: this.uid, cleanup: this.uidCleanup } = await borrowUser(
 | 
				
			||||||
        this.log
 | 
					        this.log
 | 
				
			||||||
      ));
 | 
					      ));
 | 
				
			||||||
 | 
					      this.log(`Borrowed uid ${this.uid}`);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    this.log(`Borrowed uid ${this.uid}`);
 | 
					    const {
 | 
				
			||||||
    const { name, repl, main, suffix, compile, run, hacks } = this.config;
 | 
					      name,
 | 
				
			||||||
 | 
					      repl,
 | 
				
			||||||
 | 
					      main,
 | 
				
			||||||
 | 
					      suffix,
 | 
				
			||||||
 | 
					      alwaysCreate,
 | 
				
			||||||
 | 
					      compile,
 | 
				
			||||||
 | 
					      run,
 | 
				
			||||||
 | 
					      hacks,
 | 
				
			||||||
 | 
					    } = this.config;
 | 
				
			||||||
    if (this.term.pty) {
 | 
					    if (this.term.pty) {
 | 
				
			||||||
      this.term.pty.kill();
 | 
					      this.term.pty.kill();
 | 
				
			||||||
      this.term.live = false;
 | 
					      this.term.live = false;
 | 
				
			||||||
| 
						 | 
					@ -93,20 +101,9 @@ export class Session {
 | 
				
			||||||
    } catch (err) {
 | 
					    } catch (err) {
 | 
				
			||||||
      //
 | 
					      //
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (this.tmpdir == null) {
 | 
					    if (this.homedir == null) {
 | 
				
			||||||
      ({ path: this.tmpdir, cleanup: this.tmpdirCleanup } = await new Promise(
 | 
					      this.homedir = `/tmp/riju/${this.uuid}`;
 | 
				
			||||||
        (resolve, reject) =>
 | 
					      await callPrivileged(["setup", `${this.uid}`, this.uuid], this.log);
 | 
				
			||||||
          tmp.dir(
 | 
					 | 
				
			||||||
            { unsafeCleanup: true, dir: "riju" },
 | 
					 | 
				
			||||||
            (err, path, cleanup) => {
 | 
					 | 
				
			||||||
              if (err) {
 | 
					 | 
				
			||||||
                reject(err);
 | 
					 | 
				
			||||||
              } else {
 | 
					 | 
				
			||||||
                resolve({ path, cleanup });
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
      ));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    let cmdline: string;
 | 
					    let cmdline: string;
 | 
				
			||||||
    if (!run) {
 | 
					    if (!run) {
 | 
				
			||||||
| 
						 | 
					@ -117,22 +114,33 @@ export class Session {
 | 
				
			||||||
        code += suffix;
 | 
					        code += suffix;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (main.includes("/")) {
 | 
					      if (main.includes("/")) {
 | 
				
			||||||
        await mkdirp(path.dirname(path.resolve(this.tmpdir!, main)));
 | 
					        await spawnPrivileged(
 | 
				
			||||||
 | 
					          this.uid,
 | 
				
			||||||
 | 
					          this.uuid,
 | 
				
			||||||
 | 
					          ["mkdir", "-p", path.dirname(path.resolve(this.homedir, main))],
 | 
				
			||||||
 | 
					          this.log
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      await new Promise((resolve, reject) =>
 | 
					      await spawnPrivileged(
 | 
				
			||||||
        fs.writeFile(path.resolve(this.tmpdir!, main), code, (err) => {
 | 
					        this.uid,
 | 
				
			||||||
          if (err) {
 | 
					        this.uuid,
 | 
				
			||||||
            reject(err);
 | 
					        ["sh", "-c", `cat > ${path.resolve(this.homedir, main)}`],
 | 
				
			||||||
          } else {
 | 
					        this.log,
 | 
				
			||||||
            resolve();
 | 
					        { input: code }
 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      cmdline = run;
 | 
					      cmdline = run;
 | 
				
			||||||
      if (compile) {
 | 
					      if (compile) {
 | 
				
			||||||
        cmdline = `( ${compile} ) && ( ${run} )`;
 | 
					        cmdline = `( ${compile} ) && ( ${run} )`;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else if (repl) {
 | 
					    } else if (repl) {
 | 
				
			||||||
 | 
					      if (alwaysCreate) {
 | 
				
			||||||
 | 
					        await spawnPrivileged(
 | 
				
			||||||
 | 
					          this.uid,
 | 
				
			||||||
 | 
					          this.uuid,
 | 
				
			||||||
 | 
					          ["touch", `${path.resolve(this.homedir, main)}`],
 | 
				
			||||||
 | 
					          this.log
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      cmdline = repl;
 | 
					      cmdline = repl;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      cmdline = `echo '${name} has no REPL, press Run to see it in action'`;
 | 
					      cmdline = `echo '${name} has no REPL, press Run to see it in action'`;
 | 
				
			||||||
| 
						 | 
					@ -140,32 +148,38 @@ export class Session {
 | 
				
			||||||
    if (hacks && hacks.includes("ghci-config") && run) {
 | 
					    if (hacks && hacks.includes("ghci-config") && run) {
 | 
				
			||||||
      if (this.code) {
 | 
					      if (this.code) {
 | 
				
			||||||
        const contents = ":load Main\nmain\n";
 | 
					        const contents = ":load Main\nmain\n";
 | 
				
			||||||
        await new Promise((resolve, reject) => {
 | 
					        await spawnPrivileged(
 | 
				
			||||||
          fs.writeFile(path.resolve(this.tmpdir!, ".ghci"), contents, (err) => {
 | 
					          this.uid,
 | 
				
			||||||
            if (err) {
 | 
					          this.uuid,
 | 
				
			||||||
              reject(err);
 | 
					          ["sh", "-c", `cat > ${path.resolve(this.homedir, ".ghci")}`],
 | 
				
			||||||
            } else {
 | 
					          this.log,
 | 
				
			||||||
              resolve();
 | 
					          { input: contents }
 | 
				
			||||||
            }
 | 
					        );
 | 
				
			||||||
          });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        await new Promise((resolve, reject) =>
 | 
					        await spawnPrivileged(
 | 
				
			||||||
          fs.unlink(path.resolve(this.tmpdir!, ".ghci"), (err) => {
 | 
					          this.uid,
 | 
				
			||||||
            if (err && err.code !== "ENOENT") {
 | 
					          this.uuid,
 | 
				
			||||||
              reject(err);
 | 
					          ["rm", "-f", path.resolve(this.homedir, ".ghci")],
 | 
				
			||||||
            } else {
 | 
					          this.log
 | 
				
			||||||
              resolve();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          })
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const args = PRIVILEGED
 | 
				
			||||||
 | 
					      ? [
 | 
				
			||||||
 | 
					          "/home/docker/src/system/out/riju-system-privileged",
 | 
				
			||||||
 | 
					          "spawn",
 | 
				
			||||||
 | 
					          `${this.uid}`,
 | 
				
			||||||
 | 
					          `${this.uuid}`,
 | 
				
			||||||
 | 
					          "bash",
 | 
				
			||||||
 | 
					          "-c",
 | 
				
			||||||
 | 
					          cmdline,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					      : ["bash", "-c", cmdline];
 | 
				
			||||||
 | 
					    const env = getEnv(this.uuid);
 | 
				
			||||||
    const term = {
 | 
					    const term = {
 | 
				
			||||||
      pty: pty.spawn("bash", ["-c", cmdline], {
 | 
					      pty: pty.spawn(args[0], args.slice(1), {
 | 
				
			||||||
        name: "xterm-color",
 | 
					        name: "xterm-color",
 | 
				
			||||||
        cwd: this.tmpdir!,
 | 
					        env,
 | 
				
			||||||
        env: process.env as { [key: string]: string },
 | 
					 | 
				
			||||||
      }),
 | 
					      }),
 | 
				
			||||||
      live: true,
 | 
					      live: true,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					@ -186,8 +200,8 @@ export class Session {
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  cleanup = async () => {
 | 
					  cleanup = async () => {
 | 
				
			||||||
    this.log(`Cleaning up session`);
 | 
					    this.log(`Cleaning up session`);
 | 
				
			||||||
    if (this.tmpdirCleanup) {
 | 
					    if (this.homedir) {
 | 
				
			||||||
      this.tmpdirCleanup();
 | 
					      await callPrivileged(["teardown", this.uuid], this.log);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (this.uidCleanup) {
 | 
					    if (this.uidCleanup) {
 | 
				
			||||||
      await this.uidCleanup();
 | 
					      await this.uidCleanup();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					import * as process from "process";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const PRIVILEGED = process.env.RIJU_PRIVILEGED ? true : false;
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ export interface LangConfig {
 | 
				
			||||||
  main: string;
 | 
					  main: string;
 | 
				
			||||||
  prefix?: string;
 | 
					  prefix?: string;
 | 
				
			||||||
  suffix?: string;
 | 
					  suffix?: string;
 | 
				
			||||||
 | 
					  alwaysCreate?: boolean;
 | 
				
			||||||
  compile?: string;
 | 
					  compile?: string;
 | 
				
			||||||
  run: string;
 | 
					  run: string;
 | 
				
			||||||
  template: string;
 | 
					  template: string;
 | 
				
			||||||
| 
						 | 
					@ -220,7 +221,7 @@ int main() {
 | 
				
			||||||
    monacoLang: "csharp",
 | 
					    monacoLang: "csharp",
 | 
				
			||||||
    main: "main.cs",
 | 
					    main: "main.cs",
 | 
				
			||||||
    compile: "mcs main.cs",
 | 
					    compile: "mcs main.cs",
 | 
				
			||||||
    run: "./main.exe",
 | 
					    run: "mono main.exe",
 | 
				
			||||||
    template: `class main {
 | 
					    template: `class main {
 | 
				
			||||||
    static void Main(string[] args) {
 | 
					    static void Main(string[] args) {
 | 
				
			||||||
        System.Console.WriteLine("Hello, world!");
 | 
					        System.Console.WriteLine("Hello, world!");
 | 
				
			||||||
| 
						 | 
					@ -326,9 +327,9 @@ output = "Hello, world!"
 | 
				
			||||||
    aliases: ["elv"],
 | 
					    aliases: ["elv"],
 | 
				
			||||||
    name: "Elvish",
 | 
					    name: "Elvish",
 | 
				
			||||||
    monacoLang: "plaintext",
 | 
					    monacoLang: "plaintext",
 | 
				
			||||||
    repl: "SHELL=/usr/bin/elvish HOME=. elvish",
 | 
					    repl: `SHELL=/usr/bin/elvish HOME="$PWD" elvish`,
 | 
				
			||||||
    main: ".elvish/rc.elv",
 | 
					    main: ".elvish/rc.elv",
 | 
				
			||||||
    run: "SHELL=/usr/bin/elvish HOME=. elvish",
 | 
					    run: `SHELL=/usr/bin/elvish HOME="$PWD" elvish`,
 | 
				
			||||||
    template: `echo "Hello, world!"
 | 
					    template: `echo "Hello, world!"
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -451,8 +452,8 @@ main = putStrLn "Hello, world!"
 | 
				
			||||||
    repl: "ink",
 | 
					    repl: "ink",
 | 
				
			||||||
    main: "main.ink",
 | 
					    main: "main.ink",
 | 
				
			||||||
    run: "ink main.ink; ink",
 | 
					    run: "ink main.ink; ink",
 | 
				
			||||||
    template: `std := load('../../opt/ink/std')
 | 
					    template: `std := load('../../../opt/ink/std')
 | 
				
			||||||
str := load('../../opt/ink/str')
 | 
					str := load('../../../opt/ink/str')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
log := std.log
 | 
					log := std.log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -535,9 +536,9 @@ PLEASE GIVE UP
 | 
				
			||||||
    aliases: ["kshell"],
 | 
					    aliases: ["kshell"],
 | 
				
			||||||
    name: "Ksh",
 | 
					    name: "Ksh",
 | 
				
			||||||
    monacoLang: "shell",
 | 
					    monacoLang: "shell",
 | 
				
			||||||
    repl: "SHELL=/usr/bin/ksh HOME=. ksh",
 | 
					    repl: `SHELL=/usr/bin/ksh HOME="$PWD" ksh`,
 | 
				
			||||||
    main: ".kshrc",
 | 
					    main: ".kshrc",
 | 
				
			||||||
    run: "SHELL=/usr/bin/ksh HOME=. ksh",
 | 
					    run: `SHELL=/usr/bin/ksh HOME="$PWD" ksh`,
 | 
				
			||||||
    template: `echo "Hello, world!"
 | 
					    template: `echo "Hello, world!"
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -830,9 +831,9 @@ binding_irb.run(IRB.conf)
 | 
				
			||||||
    aliases: ["shell", "posix", "posixsh", "ash", "dash", "posh"],
 | 
					    aliases: ["shell", "posix", "posixsh", "ash", "dash", "posh"],
 | 
				
			||||||
    name: "Sh",
 | 
					    name: "Sh",
 | 
				
			||||||
    monacoLang: "shell",
 | 
					    monacoLang: "shell",
 | 
				
			||||||
    repl: "SHELL=/usr/bin/sh HOME=. posh -l",
 | 
					    repl: `SHELL=/usr/bin/sh HOME="$PWD" posh -l`,
 | 
				
			||||||
    main: ".profile",
 | 
					    main: ".profile",
 | 
				
			||||||
    run: "SHELL=/usr/bin/sh HOME=. posh -l",
 | 
					    run: `SHELL=/usr/bin/sh HOME="$PWD" posh -l`,
 | 
				
			||||||
    template: `echo "Hello, world!"
 | 
					    template: `echo "Hello, world!"
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -992,7 +993,7 @@ END
 | 
				
			||||||
    monacoLang: "tcl",
 | 
					    monacoLang: "tcl",
 | 
				
			||||||
    repl: "tclsh",
 | 
					    repl: "tclsh",
 | 
				
			||||||
    main: ".tclshrc",
 | 
					    main: ".tclshrc",
 | 
				
			||||||
    run: "HOME=. tclsh",
 | 
					    run: `HOME="$PWD" tclsh`,
 | 
				
			||||||
    template: `puts {Hello, world!}
 | 
					    template: `puts {Hello, world!}
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -1000,9 +1001,9 @@ END
 | 
				
			||||||
    aliases: ["tcshell", "tcshrc"],
 | 
					    aliases: ["tcshell", "tcshrc"],
 | 
				
			||||||
    name: "Tcsh",
 | 
					    name: "Tcsh",
 | 
				
			||||||
    monacoLang: "shell",
 | 
					    monacoLang: "shell",
 | 
				
			||||||
    repl: "SHELL=/usr/bin/tcsh HOME=. tcsh",
 | 
					    repl: `SHELL=/usr/bin/tcsh HOME="$PWD" tcsh`,
 | 
				
			||||||
    main: ".tcshrc",
 | 
					    main: ".tcshrc",
 | 
				
			||||||
    run: "SHELL=/usr/bin/tcsh HOME=. tcsh",
 | 
					    run: `SHELL=/usr/bin/tcsh HOME="$PWD" tcsh`,
 | 
				
			||||||
    template: `echo "Hello, world!"
 | 
					    template: `echo "Hello, world!"
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -1104,7 +1105,8 @@ message:
 | 
				
			||||||
    monacoLang: "shell",
 | 
					    monacoLang: "shell",
 | 
				
			||||||
    repl: "SHELL=/usr/bin/zsh zsh",
 | 
					    repl: "SHELL=/usr/bin/zsh zsh",
 | 
				
			||||||
    main: ".zshrc",
 | 
					    main: ".zshrc",
 | 
				
			||||||
    run: "SHELL=/usr/bin/zsh ZDOTDIR=. zsh",
 | 
					    alwaysCreate: true,
 | 
				
			||||||
 | 
					    run: `SHELL=/usr/bin/zsh ZDOTDIR="$PWD" zsh`,
 | 
				
			||||||
    template: `echo "Hello, world!"
 | 
					    template: `echo "Hello, world!"
 | 
				
			||||||
`,
 | 
					`,
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,16 +1,17 @@
 | 
				
			||||||
import { spawn } from "child_process";
 | 
					import { spawn } from "child_process";
 | 
				
			||||||
import * as fs from "fs";
 | 
					import * as fs from "fs";
 | 
				
			||||||
import * as process from "process";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as AsyncLock from "async-lock";
 | 
					import * as AsyncLock from "async-lock";
 | 
				
			||||||
import * as _ from "lodash";
 | 
					import * as _ from "lodash";
 | 
				
			||||||
import * as parsePasswd from "parse-passwd";
 | 
					import * as parsePasswd from "parse-passwd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { PRIVILEGED } from "./config";
 | 
				
			||||||
 | 
					import { callPrivileged } from "./util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Keep in sync with system/src/riju-system-privileged.c
 | 
					// Keep in sync with system/src/riju-system-privileged.c
 | 
				
			||||||
const MIN_UID = 2000;
 | 
					const MIN_UID = 2000;
 | 
				
			||||||
const MAX_UID = 65000;
 | 
					const MAX_UID = 65000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PRIVILEGED = process.env.RIJU_PRIVILEGED ? true : false;
 | 
					 | 
				
			||||||
const CUR_UID = parseInt(process.env.UID || "") || null;
 | 
					const CUR_UID = parseInt(process.env.UID || "") || null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let availIds: number[] | null = null;
 | 
					let availIds: number[] | null = null;
 | 
				
			||||||
| 
						 | 
					@ -29,7 +30,7 @@ async function readExistingUsers(log: (msg: string) => void) {
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
    .filter(({ username }) => username.startsWith("riju_user"))
 | 
					    .filter(({ username }) => username.startsWith("riju"))
 | 
				
			||||||
    .map(({ uid }) => parseInt(uid))
 | 
					    .map(({ uid }) => parseInt(uid))
 | 
				
			||||||
    .filter((uid) => !isNaN(uid) && uid >= MIN_UID && uid < MAX_UID);
 | 
					    .filter((uid) => !isNaN(uid) && uid >= MIN_UID && uid < MAX_UID);
 | 
				
			||||||
  nextId = (_.max(availIds) || MIN_UID - 1) + 1;
 | 
					  nextId = (_.max(availIds) || MIN_UID - 1) + 1;
 | 
				
			||||||
| 
						 | 
					@ -40,33 +41,11 @@ async function createUser(log: (msg: string) => void): Promise<number> {
 | 
				
			||||||
  if (nextId! >= MAX_UID) {
 | 
					  if (nextId! >= MAX_UID) {
 | 
				
			||||||
    throw new Error("too many users");
 | 
					    throw new Error("too many users");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return await new Promise((resolve, reject) => {
 | 
					  const uid = nextId!;
 | 
				
			||||||
    const uid = nextId!;
 | 
					  await callPrivileged(["useradd", `${uid}`], log);
 | 
				
			||||||
    const useradd = spawn("system/out/riju-system-privileged", [
 | 
					  log(`Created new user with ID ${uid}`);
 | 
				
			||||||
      "useradd",
 | 
					  nextId! += 1;
 | 
				
			||||||
      `${uid}`,
 | 
					  return uid;
 | 
				
			||||||
    ]);
 | 
					 | 
				
			||||||
    let output = "";
 | 
					 | 
				
			||||||
    useradd.stdout.on("data", (data) => {
 | 
					 | 
				
			||||||
      output += `${data}`;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    useradd.stderr.on("data", (data) => {
 | 
					 | 
				
			||||||
      output += `${data}`;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    useradd.on("close", (code) => {
 | 
					 | 
				
			||||||
      output = output.trim();
 | 
					 | 
				
			||||||
      if (output) {
 | 
					 | 
				
			||||||
        log("Output from useradd:\n" + output);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      if (code === 0) {
 | 
					 | 
				
			||||||
        log(`Created new user with ID ${uid}`);
 | 
					 | 
				
			||||||
        nextId! += 1;
 | 
					 | 
				
			||||||
        resolve(uid);
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        reject(`useradd failed with error code ${code}`);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function borrowUser(log: (msg: string) => void) {
 | 
					export async function borrowUser(log: (msg: string) => void) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,83 @@
 | 
				
			||||||
 | 
					import { spawn, SpawnOptions } from "child_process";
 | 
				
			||||||
 | 
					import * as process from "process";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Options extends SpawnOptions {
 | 
				
			||||||
 | 
					  input?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function getEnv(uuid: string) {
 | 
				
			||||||
 | 
					  const cwd = `/tmp/riju/${uuid}`;
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    HOME: cwd,
 | 
				
			||||||
 | 
					    HOSTNAME: "riju",
 | 
				
			||||||
 | 
					    LANG: "C.UTF-8",
 | 
				
			||||||
 | 
					    LC_ALL: "C.UTF-8",
 | 
				
			||||||
 | 
					    PATH: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/bin",
 | 
				
			||||||
 | 
					    PWD: cwd,
 | 
				
			||||||
 | 
					    SHELL: "/usr/bin/bash",
 | 
				
			||||||
 | 
					    TERM: "xterm-color",
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function call(
 | 
				
			||||||
 | 
					  args: string[],
 | 
				
			||||||
 | 
					  log: (msg: string) => void,
 | 
				
			||||||
 | 
					  options?: Options
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  options = options || {};
 | 
				
			||||||
 | 
					  const input = options.input;
 | 
				
			||||||
 | 
					  delete options.input;
 | 
				
			||||||
 | 
					  const proc = spawn(args[0], args.slice(1), options);
 | 
				
			||||||
 | 
					  if (input) {
 | 
				
			||||||
 | 
					    proc.stdin!.end(input);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  let output = "";
 | 
				
			||||||
 | 
					  proc.stdout!.on("data", (data: Buffer) => {
 | 
				
			||||||
 | 
					    output += `${data}`;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  proc.stderr!.on("data", (data: Buffer) => {
 | 
				
			||||||
 | 
					    output += `${data}`;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  await new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
					    proc.on("error", reject);
 | 
				
			||||||
 | 
					    proc.on("close", (code: number) => {
 | 
				
			||||||
 | 
					      output = output.trim();
 | 
				
			||||||
 | 
					      if (output) {
 | 
				
			||||||
 | 
					        log(`Output from ${args[0]}:\n` + output);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (code === 0) {
 | 
				
			||||||
 | 
					        resolve();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        reject(`command ${args[0]} failed with error code ${code}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function callPrivileged(
 | 
				
			||||||
 | 
					  args: string[],
 | 
				
			||||||
 | 
					  log: (msg: string) => void,
 | 
				
			||||||
 | 
					  options?: Options
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  await call(
 | 
				
			||||||
 | 
					    ["/home/docker/src/system/out/riju-system-privileged"].concat(args),
 | 
				
			||||||
 | 
					    log,
 | 
				
			||||||
 | 
					    options
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function spawnPrivileged(
 | 
				
			||||||
 | 
					  uid: number,
 | 
				
			||||||
 | 
					  uuid: string,
 | 
				
			||||||
 | 
					  args: string[],
 | 
				
			||||||
 | 
					  log: (msg: string) => void,
 | 
				
			||||||
 | 
					  options?: Options
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  options = options || {};
 | 
				
			||||||
 | 
					  options.env = getEnv(uuid);
 | 
				
			||||||
 | 
					  await callPrivileged(
 | 
				
			||||||
 | 
					    ["spawn", `${uid}`, `${uuid}`].concat(args),
 | 
				
			||||||
 | 
					    log,
 | 
				
			||||||
 | 
					    options
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -10,92 +10,98 @@ interface RijuConfig {
 | 
				
			||||||
  template: string;
 | 
					  template: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const config: RijuConfig = (window as any).rijuConfig;
 | 
					async function main() {
 | 
				
			||||||
 | 
					  const config: RijuConfig = (window as any).rijuConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const term = new Terminal();
 | 
					  const term = new Terminal();
 | 
				
			||||||
const fitAddon = new FitAddon();
 | 
					  const fitAddon = new FitAddon();
 | 
				
			||||||
term.loadAddon(fitAddon);
 | 
					  term.loadAddon(fitAddon);
 | 
				
			||||||
term.open(document.getElementById("terminal")!);
 | 
					  term.open(document.getElementById("terminal")!);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fitAddon.fit();
 | 
					  fitAddon.fit();
 | 
				
			||||||
window.addEventListener("resize", () => fitAddon.fit());
 | 
					  window.addEventListener("resize", () => fitAddon.fit());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
term.write("Connecting to server...");
 | 
					  await new Promise((resolve) =>
 | 
				
			||||||
 | 
					    term.write("Connecting to server...", resolve)
 | 
				
			||||||
const initialRetryDelayMs = 200;
 | 
					 | 
				
			||||||
let retryDelayMs = initialRetryDelayMs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function tryConnect() {
 | 
					 | 
				
			||||||
  console.log("Connecting to server...");
 | 
					 | 
				
			||||||
  socket = new WebSocket(
 | 
					 | 
				
			||||||
    (document.location.protocol === "http:" ? "ws://" : "wss://") +
 | 
					 | 
				
			||||||
      document.location.host +
 | 
					 | 
				
			||||||
      `/api/v1/ws?lang=${encodeURIComponent(config.id)}`
 | 
					 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
  socket.addEventListener("open", () => {
 | 
					
 | 
				
			||||||
    console.log("Successfully connected to server");
 | 
					  const initialRetryDelayMs = 200;
 | 
				
			||||||
  });
 | 
					  let retryDelayMs = initialRetryDelayMs;
 | 
				
			||||||
  socket.addEventListener("message", (event: MessageEvent) => {
 | 
					
 | 
				
			||||||
    let message: any;
 | 
					  function tryConnect() {
 | 
				
			||||||
    try {
 | 
					    console.log("Connecting to server...");
 | 
				
			||||||
      message = JSON.parse(event.data);
 | 
					    socket = new WebSocket(
 | 
				
			||||||
    } catch (err) {
 | 
					      (document.location.protocol === "http:" ? "ws://" : "wss://") +
 | 
				
			||||||
      console.error("Malformed message from server:", event.data);
 | 
					        document.location.host +
 | 
				
			||||||
      return;
 | 
					        `/api/v1/ws?lang=${encodeURIComponent(config.id)}`
 | 
				
			||||||
    }
 | 
					    );
 | 
				
			||||||
    if (message?.event && message?.event !== "error") {
 | 
					    socket.addEventListener("open", () => {
 | 
				
			||||||
      retryDelayMs = initialRetryDelayMs;
 | 
					      console.log("Successfully connected to server");
 | 
				
			||||||
    }
 | 
					    });
 | 
				
			||||||
    switch (message?.event) {
 | 
					    socket.addEventListener("message", (event: MessageEvent) => {
 | 
				
			||||||
      case "terminalClear":
 | 
					      let message: any;
 | 
				
			||||||
        term.reset();
 | 
					      try {
 | 
				
			||||||
 | 
					        message = JSON.parse(event.data);
 | 
				
			||||||
 | 
					      } catch (err) {
 | 
				
			||||||
 | 
					        console.error("Malformed message from server:", event.data);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      case "terminalOutput":
 | 
					      }
 | 
				
			||||||
        if (typeof message.output !== "string") {
 | 
					      if (message?.event && message?.event !== "error") {
 | 
				
			||||||
 | 
					        retryDelayMs = initialRetryDelayMs;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      switch (message?.event) {
 | 
				
			||||||
 | 
					        case "terminalClear":
 | 
				
			||||||
 | 
					          term.reset();
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        case "terminalOutput":
 | 
				
			||||||
 | 
					          if (typeof message.output !== "string") {
 | 
				
			||||||
 | 
					            console.error("Unexpected message from server:", message);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          term.write(message.output);
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
          console.error("Unexpected message from server:", message);
 | 
					          console.error("Unexpected message from server:", message);
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
        }
 | 
					      }
 | 
				
			||||||
        term.write(message.output);
 | 
					    });
 | 
				
			||||||
        return;
 | 
					    socket.addEventListener("close", (event: CloseEvent) => {
 | 
				
			||||||
      default:
 | 
					      if (event.wasClean) {
 | 
				
			||||||
        console.error("Unexpected message from server:", message);
 | 
					        console.log("Connection closed cleanly");
 | 
				
			||||||
        return;
 | 
					      } else {
 | 
				
			||||||
    }
 | 
					        console.error("Connection died");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      scheduleConnect();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function scheduleConnect() {
 | 
				
			||||||
 | 
					    const delay = retryDelayMs * Math.random();
 | 
				
			||||||
 | 
					    console.log(`Trying to reconnect in ${Math.floor(delay)}ms`);
 | 
				
			||||||
 | 
					    setTimeout(tryConnect, delay);
 | 
				
			||||||
 | 
					    retryDelayMs *= 2;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let socket: WebSocket | null = null;
 | 
				
			||||||
 | 
					  tryConnect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  term.onData(
 | 
				
			||||||
 | 
					    (data) =>
 | 
				
			||||||
 | 
					      socket &&
 | 
				
			||||||
 | 
					      socket.send(JSON.stringify({ event: "terminalInput", input: data }))
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const editor = monaco.editor.create(document.getElementById("editor")!, {
 | 
				
			||||||
 | 
					    minimap: { enabled: false },
 | 
				
			||||||
 | 
					    scrollbar: { verticalScrollbarSize: 0 },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
  socket.addEventListener("close", (event: CloseEvent) => {
 | 
					  window.addEventListener("resize", () => editor.layout());
 | 
				
			||||||
    if (event.wasClean) {
 | 
					  editor.getModel()!.setValue(config.template);
 | 
				
			||||||
      console.log("Connection closed cleanly");
 | 
					  monaco.editor.setModelLanguage(editor.getModel()!, config.monacoLang);
 | 
				
			||||||
    } else {
 | 
					
 | 
				
			||||||
      console.error("Connection died");
 | 
					  document.getElementById("runButton")!.addEventListener("click", () => {
 | 
				
			||||||
    }
 | 
					    socket?.send(JSON.stringify({ event: "runCode", code: editor.getValue() }));
 | 
				
			||||||
    scheduleConnect();
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function scheduleConnect() {
 | 
					main().catch(console.error);
 | 
				
			||||||
  const delay = retryDelayMs * Math.random();
 | 
					 | 
				
			||||||
  console.log(`Trying to reconnect in ${Math.floor(delay)}ms`);
 | 
					 | 
				
			||||||
  setTimeout(tryConnect, delay);
 | 
					 | 
				
			||||||
  retryDelayMs *= 2;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
let socket: WebSocket | null = null;
 | 
					 | 
				
			||||||
tryConnect();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
term.onData(
 | 
					 | 
				
			||||||
  (data) =>
 | 
					 | 
				
			||||||
    socket &&
 | 
					 | 
				
			||||||
    socket.send(JSON.stringify({ event: "terminalInput", input: data }))
 | 
					 | 
				
			||||||
);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const editor = monaco.editor.create(document.getElementById("editor")!, {
 | 
					 | 
				
			||||||
  minimap: { enabled: false },
 | 
					 | 
				
			||||||
  scrollbar: { verticalScrollbarSize: 0 },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
window.addEventListener("resize", () => editor.layout());
 | 
					 | 
				
			||||||
editor.getModel()!.setValue(config.template);
 | 
					 | 
				
			||||||
monaco.editor.setModelLanguage(editor.getModel()!, config.monacoLang);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
document.getElementById("runButton")!.addEventListener("click", () => {
 | 
					 | 
				
			||||||
  socket?.send(JSON.stringify({ event: "runCode", code: editor.getValue() }));
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										12
									
								
								package.json
								
								
								
								
							
							
						
						
									
										12
									
								
								package.json
								
								
								
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "name": "riju",
 | 
					  "name": "riju",
 | 
				
			||||||
  "version": "0",
 | 
					  "version": "0.0.0",
 | 
				
			||||||
  "license": "MIT",
 | 
					  "license": "MIT",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,7 @@
 | 
				
			||||||
    "@types/lodash": "^4.14.155",
 | 
					    "@types/lodash": "^4.14.155",
 | 
				
			||||||
    "@types/mkdirp": "^1.0.1",
 | 
					    "@types/mkdirp": "^1.0.1",
 | 
				
			||||||
    "@types/parse-passwd": "^1.0.0",
 | 
					    "@types/parse-passwd": "^1.0.0",
 | 
				
			||||||
 | 
					    "@types/rimraf": "^3.0.0",
 | 
				
			||||||
    "@types/tmp": "^0.2.0",
 | 
					    "@types/tmp": "^0.2.0",
 | 
				
			||||||
    "@types/uuid": "^8.0.0",
 | 
					    "@types/uuid": "^8.0.0",
 | 
				
			||||||
    "app-root-path": "^3.0.0",
 | 
					    "app-root-path": "^3.0.0",
 | 
				
			||||||
| 
						 | 
					@ -21,13 +22,12 @@
 | 
				
			||||||
    "express-ws": "^4.0.0",
 | 
					    "express-ws": "^4.0.0",
 | 
				
			||||||
    "file-loader": "^6.0.0",
 | 
					    "file-loader": "^6.0.0",
 | 
				
			||||||
    "lodash": "^4.17.15",
 | 
					    "lodash": "^4.17.15",
 | 
				
			||||||
    "mkdirp": "^1.0.4",
 | 
					 | 
				
			||||||
    "monaco-editor": "^0.20.0",
 | 
					    "monaco-editor": "^0.20.0",
 | 
				
			||||||
    "node-cleanup": "^2.1.2",
 | 
					    "node-cleanup": "^2.1.2",
 | 
				
			||||||
    "node-pty": "^0.9.0",
 | 
					    "node-pty": "^0.9.0",
 | 
				
			||||||
 | 
					    "npm-run-all": "^4.1.5",
 | 
				
			||||||
    "parse-passwd": "^1.0.0",
 | 
					    "parse-passwd": "^1.0.0",
 | 
				
			||||||
    "style-loader": "^1.2.1",
 | 
					    "style-loader": "^1.2.1",
 | 
				
			||||||
    "tmp": "^0.2.1",
 | 
					 | 
				
			||||||
    "ts-loader": "^7.0.5",
 | 
					    "ts-loader": "^7.0.5",
 | 
				
			||||||
    "typescript": "^3.9.5",
 | 
					    "typescript": "^3.9.5",
 | 
				
			||||||
    "uuid": "^8.1.0",
 | 
					    "uuid": "^8.1.0",
 | 
				
			||||||
| 
						 | 
					@ -38,12 +38,14 @@
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "backend": "tsc",
 | 
					    "backend": "tsc",
 | 
				
			||||||
    "backend-dev": "tsc --watch",
 | 
					    "backend-dev": "tsc --watch --preserveWatchOutput",
 | 
				
			||||||
    "frontend": "webpack --production",
 | 
					    "frontend": "webpack --production",
 | 
				
			||||||
    "frontend-dev": "webpack --development --watch",
 | 
					    "frontend-dev": "webpack --development --watch",
 | 
				
			||||||
    "server": "scripts/setup.bash && node backend/out/server.js",
 | 
					    "server": "scripts/setup.bash && node backend/out/server.js",
 | 
				
			||||||
    "server-dev": "watchexec -w backend/out -r 'scripts/setup.bash && node backend/out/server.js'",
 | 
					    "server-dev": "watchexec -w backend/out -r 'scripts/setup.bash && node backend/out/server.js'",
 | 
				
			||||||
    "system": "scripts/compile-system.bash",
 | 
					    "system": "scripts/compile-system.bash",
 | 
				
			||||||
    "system-dev": "watchexec -w system/src -n scripts/compile-system.bash"
 | 
					    "system-dev": "watchexec -w system/src -n scripts/compile-system.bash",
 | 
				
			||||||
 | 
					    "build": "run-s backend frontend system",
 | 
				
			||||||
 | 
					    "dev": "run-p backend-dev frontend-dev system-dev server-dev"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set -e
 | 
				
			||||||
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export DEBIAN_FRONTEND=noninteractive
 | 
				
			||||||
 | 
					apt-get update
 | 
				
			||||||
 | 
					(yes || true) | unminimize
 | 
				
			||||||
 | 
					rm -rf /var/lib/apt/lists/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					rm "$0"
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dpkg --add-architecture i386
 | 
					dpkg --add-architecture i386
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packages="
 | 
					packages="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packages="
 | 
					packages="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packages="
 | 
					packages="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packages="
 | 
					packages="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
packages="
 | 
					packages="
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
npm config set unsafe-perm true
 | 
					npm config set unsafe-perm true
 | 
				
			||||||
PERL_MM_USE_DEFAULT=1 cpan App::cpanminus
 | 
					PERL_MM_USE_DEFAULT=1 cpan App::cpanminus
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Needed for project infrastructure
 | 
					# Needed for project infrastructure
 | 
				
			||||||
cd /tmp
 | 
					cd /tmp
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,19 +2,22 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set -e
 | 
					set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					set -x
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uid="$1"
 | 
					uid="$1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rm -rf /tmp/hsperfdata_root
 | 
					rm -rf /tmp/hsperfdata_root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [[ -n "$uid" ]] && (( "$uid" != 0 )); then
 | 
					if [[ -n "$uid" ]] && (( "$uid" != 0 )); then
 | 
				
			||||||
    useradd --uid="$uid" --create-home --groups sudo docker
 | 
					    useradd --uid="$uid" --password "!" --create-home --groups sudo docker
 | 
				
			||||||
    passwd -d docker
 | 
					 | 
				
			||||||
else
 | 
					else
 | 
				
			||||||
    useradd --create-home --groups sudo docker
 | 
					    useradd --password "!" --create-home --groups sudo docker
 | 
				
			||||||
    passwd -d docker
 | 
					 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tee /etc/sudoers.d/99-passwordless >/dev/null <<"EOF"
 | 
				
			||||||
 | 
					%sudo   ALL=(ALL:ALL) NOPASSWD: ALL
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
touch /home/docker/.zshrc
 | 
					touch /home/docker/.zshrc
 | 
				
			||||||
chown docker:docker /home/docker/.zshrc
 | 
					chown docker:docker /home/docker/.zshrc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,4 +18,4 @@ else
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
docker run ${it} -e TLS -e TLS_PRIVATE_KEY -e TLS_CERTIFICATE \
 | 
					docker run ${it} -e TLS -e TLS_PRIVATE_KEY -e TLS_CERTIFICATE \
 | 
				
			||||||
       --rm -p 0.0.0.0:80:6119 -p 0.0.0.0:443:6120 riju:prod
 | 
					       --rm -p 0.0.0.0:80:6119 -p 0.0.0.0:443:6120 -h riju riju:prod
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,4 +4,7 @@ set -e
 | 
				
			||||||
set -o pipefail
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdir -p /tmp/riju
 | 
					mkdir -p /tmp/riju
 | 
				
			||||||
rm -rf /tmp/riju/*
 | 
					if [[ -x system/out/riju-system-privileged ]]; then
 | 
				
			||||||
 | 
					    system/out/riju-system-privileged teardown "*"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					chmod a=x,u=rwx /tmp/riju
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,18 @@
 | 
				
			||||||
#define _GNU_SOURCE
 | 
					#define _GNU_SOURCE
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <grp.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Keep in sync with backend/src/users.ts
 | 
					// Keep in sync with backend/src/users.ts
 | 
				
			||||||
const int MIN_UID = 2000;
 | 
					const int MIN_UID = 2000;
 | 
				
			||||||
const int MAX_UID = 65000;
 | 
					const int MAX_UID = 65000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void die(const char *msg)
 | 
					void die(char *msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  fprintf(stderr, "%s\n", msg);
 | 
					  fprintf(stderr, "%s\n", msg);
 | 
				
			||||||
  exit(1);
 | 
					  exit(1);
 | 
				
			||||||
| 
						 | 
					@ -17,19 +21,84 @@ void die(const char *msg)
 | 
				
			||||||
void die_with_usage()
 | 
					void die_with_usage()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  die("usage:\n"
 | 
					  die("usage:\n"
 | 
				
			||||||
      "  riju-system-privileged useradd UID");
 | 
					      "  riju-system-privileged useradd UID\n"
 | 
				
			||||||
 | 
					      "  riju-system-privileged spawn UID CMDLINE...\n"
 | 
				
			||||||
 | 
					      "  riju-system-privileged setup UID UUID\n"
 | 
				
			||||||
 | 
					      "  riju-system-privileged teardown UUID");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int parseUID(char *str)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char *endptr;
 | 
				
			||||||
 | 
					  long uid = strtol(str, &endptr, 10);
 | 
				
			||||||
 | 
					  if (!*str || *endptr)
 | 
				
			||||||
 | 
					    die("uid must be an integer");
 | 
				
			||||||
 | 
					  if (uid < MIN_UID || uid >= MAX_UID)
 | 
				
			||||||
 | 
					    die("uid is out of range");
 | 
				
			||||||
 | 
					  return uid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *parseUUID(char *uuid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (!*uuid)
 | 
				
			||||||
 | 
					    die("illegal uuid");
 | 
				
			||||||
 | 
					  for (char *ptr = uuid; *ptr; ++ptr)
 | 
				
			||||||
 | 
					    if (!((*ptr >= 'a' && *ptr <= 'z') || (*ptr >= '0' && *ptr <= '9') || *ptr == '-'))
 | 
				
			||||||
 | 
					      die("illegal uuid");
 | 
				
			||||||
 | 
					  return uuid;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void useradd(int uid)
 | 
					void useradd(int uid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  char *cmdline;
 | 
					  char *cmdline;
 | 
				
			||||||
  if (asprintf(&cmdline, "useradd -M -N -l -r -u %1$d riju_user%1$d", uid) < 0) {
 | 
					  if (asprintf(&cmdline, "groupadd -g %1$d riju%1$d", uid) < 0)
 | 
				
			||||||
    die("asprintf failed");
 | 
					    die("asprintf failed");
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  int status = system(cmdline);
 | 
					  int status = system(cmdline);
 | 
				
			||||||
  if (status) {
 | 
					  if (status)
 | 
				
			||||||
 | 
					    die("groupadd failed");
 | 
				
			||||||
 | 
					  if (asprintf(&cmdline, "useradd -M -N -l -r -u %1$d -g %1$d -p '!' riju%1$d", uid) < 0)
 | 
				
			||||||
 | 
					    die("asprintf failed");
 | 
				
			||||||
 | 
					  status = system(cmdline);
 | 
				
			||||||
 | 
					  if (status)
 | 
				
			||||||
    die("useradd failed");
 | 
					    die("useradd failed");
 | 
				
			||||||
  }
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void spawn(int uid, char *uuid, char **cmdline)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char *cwd;
 | 
				
			||||||
 | 
					  if (asprintf(&cwd, "/tmp/riju/%s", uuid) < 0)
 | 
				
			||||||
 | 
					    die("asprintf failed");
 | 
				
			||||||
 | 
					  if (chdir(cwd) < 0)
 | 
				
			||||||
 | 
					    die("chdir failed");
 | 
				
			||||||
 | 
					  if (setgid(uid) < 0)
 | 
				
			||||||
 | 
					    die("setgid failed");
 | 
				
			||||||
 | 
					  if (setgroups(0, NULL) < 0)
 | 
				
			||||||
 | 
					    die("setgroups failed");
 | 
				
			||||||
 | 
					  if (setuid(uid) < 0)
 | 
				
			||||||
 | 
					    die("setuid failed");
 | 
				
			||||||
 | 
					  umask(077);
 | 
				
			||||||
 | 
					  execvp(cmdline[0], cmdline);
 | 
				
			||||||
 | 
					  die("execvp failed");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setup(int uid, char *uuid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char *cmdline;
 | 
				
			||||||
 | 
					  if (asprintf(&cmdline, "install -d -o riju%1$d -g riju%1$d -m 700 /tmp/riju/%2$s", uid, uuid) < 0)
 | 
				
			||||||
 | 
					    die("asprintf failed");
 | 
				
			||||||
 | 
					  int status = system(cmdline);
 | 
				
			||||||
 | 
					  if (status)
 | 
				
			||||||
 | 
					    die("install failed");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void teardown(char *uuid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  char *cmdline;
 | 
				
			||||||
 | 
					  if (asprintf(&cmdline, "rm -rf /tmp/riju/%s", uuid) < 0)
 | 
				
			||||||
 | 
					    die("asprintf failed");
 | 
				
			||||||
 | 
					  int status = system(cmdline);
 | 
				
			||||||
 | 
					  if (status)
 | 
				
			||||||
 | 
					    die("rm failed");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
| 
						 | 
					@ -40,15 +109,28 @@ int main(int argc, char **argv)
 | 
				
			||||||
  if (!strcmp(argv[1], "useradd")) {
 | 
					  if (!strcmp(argv[1], "useradd")) {
 | 
				
			||||||
    if (argc != 3)
 | 
					    if (argc != 3)
 | 
				
			||||||
      die_with_usage();
 | 
					      die_with_usage();
 | 
				
			||||||
    char *endptr;
 | 
					    useradd(parseUID(argv[2]));
 | 
				
			||||||
    long uid = strtol(argv[2], &endptr, 10);
 | 
					    return 0;
 | 
				
			||||||
    if (!argv[2] || *endptr) {
 | 
					  }
 | 
				
			||||||
      die("uid must be an integer");
 | 
					  if (!strcmp(argv[1], "spawn")) {
 | 
				
			||||||
    }
 | 
					    if (argc < 5)
 | 
				
			||||||
    if (uid < MIN_UID || uid >= MAX_UID) {
 | 
					      die_with_usage();
 | 
				
			||||||
      die("uid is out of range");
 | 
					    spawn(parseUID(argv[2]), parseUUID(argv[3]), &argv[4]);
 | 
				
			||||||
    }
 | 
					    return 0;
 | 
				
			||||||
    useradd(uid);
 | 
					  }
 | 
				
			||||||
 | 
					  if (!strcmp(argv[1], "setup")) {
 | 
				
			||||||
 | 
					    if (argc != 4)
 | 
				
			||||||
 | 
					      die_with_usage();
 | 
				
			||||||
 | 
					    int uid = parseUID(argv[2]);
 | 
				
			||||||
 | 
					    char *uuid = parseUUID(argv[3]);
 | 
				
			||||||
 | 
					    setup(uid, uuid);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if (!strcmp(argv[1], "teardown")) {
 | 
				
			||||||
 | 
					    if (argc != 3)
 | 
				
			||||||
 | 
					      die_with_usage();
 | 
				
			||||||
 | 
					    char *uuid = strcmp(argv[2], "*") ? parseUUID(argv[2]) : "*";
 | 
				
			||||||
 | 
					    teardown(uuid);
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  die_with_usage();
 | 
					  die_with_usage();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										313
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										313
									
								
								yarn.lock
								
								
								
								
							| 
						 | 
					@ -55,6 +55,14 @@
 | 
				
			||||||
    "@types/qs" "*"
 | 
					    "@types/qs" "*"
 | 
				
			||||||
    "@types/serve-static" "*"
 | 
					    "@types/serve-static" "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@types/glob@*":
 | 
				
			||||||
 | 
					  version "7.1.2"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.2.tgz#06ca26521353a545d94a0adc74f38a59d232c987"
 | 
				
			||||||
 | 
					  integrity sha512-VgNIkxK+j7Nz5P7jvUZlRvhuPSmsEfS03b0alKcq5V/STUKAa3Plemsn5mrQUO7am6OErJ4rhGEGJbACclrtRA==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    "@types/minimatch" "*"
 | 
				
			||||||
 | 
					    "@types/node" "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@types/json-schema@^7.0.4":
 | 
					"@types/json-schema@^7.0.4":
 | 
				
			||||||
  version "7.0.4"
 | 
					  version "7.0.4"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
 | 
					  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
 | 
				
			||||||
| 
						 | 
					@ -70,6 +78,11 @@
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5"
 | 
					  resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5"
 | 
				
			||||||
  integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==
 | 
					  integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@types/minimatch@*":
 | 
				
			||||||
 | 
					  version "3.0.3"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
 | 
				
			||||||
 | 
					  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@types/mkdirp@^1.0.1":
 | 
					"@types/mkdirp@^1.0.1":
 | 
				
			||||||
  version "1.0.1"
 | 
					  version "1.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-1.0.1.tgz#0930b948914a78587de35458b86c907b6e98bbf6"
 | 
					  resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-1.0.1.tgz#0930b948914a78587de35458b86c907b6e98bbf6"
 | 
				
			||||||
| 
						 | 
					@ -97,6 +110,14 @@
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
 | 
					  resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
 | 
				
			||||||
  integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
 | 
					  integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"@types/rimraf@^3.0.0":
 | 
				
			||||||
 | 
					  version "3.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.0.tgz#b9d03f090ece263671898d57bb7bb007023ac19f"
 | 
				
			||||||
 | 
					  integrity sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    "@types/glob" "*"
 | 
				
			||||||
 | 
					    "@types/node" "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"@types/serve-static@*":
 | 
					"@types/serve-static@*":
 | 
				
			||||||
  version "1.13.4"
 | 
					  version "1.13.4"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c"
 | 
					  resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c"
 | 
				
			||||||
| 
						 | 
					@ -663,7 +684,7 @@ camelcase@^5.0.0, camelcase@^5.3.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
 | 
					  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
 | 
				
			||||||
  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 | 
					  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
chalk@2.4.2, chalk@^2.3.0, chalk@^2.4.2:
 | 
					chalk@2.4.2, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
 | 
				
			||||||
  version "2.4.2"
 | 
					  version "2.4.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
 | 
					  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
 | 
				
			||||||
  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
 | 
					  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
 | 
				
			||||||
| 
						 | 
					@ -880,7 +901,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
 | 
				
			||||||
    safe-buffer "^5.0.1"
 | 
					    safe-buffer "^5.0.1"
 | 
				
			||||||
    sha.js "^2.4.8"
 | 
					    sha.js "^2.4.8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cross-spawn@6.0.5, cross-spawn@^6.0.0:
 | 
					cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
 | 
				
			||||||
  version "6.0.5"
 | 
					  version "6.0.5"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
 | 
					  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
 | 
				
			||||||
  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
 | 
					  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
 | 
				
			||||||
| 
						 | 
					@ -954,6 +975,13 @@ decode-uri-component@^0.2.0:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
 | 
					  resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
 | 
				
			||||||
  integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
 | 
					  integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					define-properties@^1.1.2, define-properties@^1.1.3:
 | 
				
			||||||
 | 
					  version "1.1.3"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
 | 
				
			||||||
 | 
					  integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    object-keys "^1.0.12"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
define-property@^0.2.5:
 | 
					define-property@^0.2.5:
 | 
				
			||||||
  version "0.2.5"
 | 
					  version "0.2.5"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
 | 
					  resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
 | 
				
			||||||
| 
						 | 
					@ -1100,6 +1128,39 @@ errno@^0.1.3, errno@~0.1.7:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    prr "~1.0.1"
 | 
					    prr "~1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error-ex@^1.3.1:
 | 
				
			||||||
 | 
					  version "1.3.2"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
 | 
				
			||||||
 | 
					  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    is-arrayish "^0.2.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
 | 
				
			||||||
 | 
					  version "1.17.6"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
 | 
				
			||||||
 | 
					  integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    es-to-primitive "^1.2.1"
 | 
				
			||||||
 | 
					    function-bind "^1.1.1"
 | 
				
			||||||
 | 
					    has "^1.0.3"
 | 
				
			||||||
 | 
					    has-symbols "^1.0.1"
 | 
				
			||||||
 | 
					    is-callable "^1.2.0"
 | 
				
			||||||
 | 
					    is-regex "^1.1.0"
 | 
				
			||||||
 | 
					    object-inspect "^1.7.0"
 | 
				
			||||||
 | 
					    object-keys "^1.1.1"
 | 
				
			||||||
 | 
					    object.assign "^4.1.0"
 | 
				
			||||||
 | 
					    string.prototype.trimend "^1.0.1"
 | 
				
			||||||
 | 
					    string.prototype.trimstart "^1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					es-to-primitive@^1.2.1:
 | 
				
			||||||
 | 
					  version "1.2.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
 | 
				
			||||||
 | 
					  integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    is-callable "^1.1.4"
 | 
				
			||||||
 | 
					    is-date-object "^1.0.1"
 | 
				
			||||||
 | 
					    is-symbol "^1.0.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
escape-html@~1.0.3:
 | 
					escape-html@~1.0.3:
 | 
				
			||||||
  version "1.0.3"
 | 
					  version "1.0.3"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
 | 
					  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
 | 
				
			||||||
| 
						 | 
					@ -1410,6 +1471,11 @@ fsevents@~2.1.2:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
 | 
					  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
 | 
				
			||||||
  integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
 | 
					  integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function-bind@^1.1.1:
 | 
				
			||||||
 | 
					  version "1.1.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
 | 
				
			||||||
 | 
					  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
get-caller-file@^2.0.1:
 | 
					get-caller-file@^2.0.1:
 | 
				
			||||||
  version "2.0.5"
 | 
					  version "2.0.5"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
 | 
					  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
 | 
				
			||||||
| 
						 | 
					@ -1500,6 +1566,11 @@ has-flag@^3.0.0:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
 | 
					  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
 | 
				
			||||||
  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
 | 
					  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					has-symbols@^1.0.0, has-symbols@^1.0.1:
 | 
				
			||||||
 | 
					  version "1.0.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
 | 
				
			||||||
 | 
					  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
has-value@^0.3.1:
 | 
					has-value@^0.3.1:
 | 
				
			||||||
  version "0.3.1"
 | 
					  version "0.3.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
 | 
					  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
 | 
				
			||||||
| 
						 | 
					@ -1531,6 +1602,13 @@ has-values@^1.0.0:
 | 
				
			||||||
    is-number "^3.0.0"
 | 
					    is-number "^3.0.0"
 | 
				
			||||||
    kind-of "^4.0.0"
 | 
					    kind-of "^4.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					has@^1.0.3:
 | 
				
			||||||
 | 
					  version "1.0.3"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
 | 
				
			||||||
 | 
					  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    function-bind "^1.1.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
hash-base@^3.0.0:
 | 
					hash-base@^3.0.0:
 | 
				
			||||||
  version "3.1.0"
 | 
					  version "3.1.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
 | 
					  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33"
 | 
				
			||||||
| 
						 | 
					@ -1564,6 +1642,11 @@ homedir-polyfill@^1.0.1:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    parse-passwd "^1.0.0"
 | 
					    parse-passwd "^1.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hosted-git-info@^2.1.4:
 | 
				
			||||||
 | 
					  version "2.8.8"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
 | 
				
			||||||
 | 
					  integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
http-errors@1.7.2:
 | 
					http-errors@1.7.2:
 | 
				
			||||||
  version "1.7.2"
 | 
					  version "1.7.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
 | 
					  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
 | 
				
			||||||
| 
						 | 
					@ -1695,6 +1778,11 @@ is-accessor-descriptor@^1.0.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    kind-of "^6.0.0"
 | 
					    kind-of "^6.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is-arrayish@^0.2.1:
 | 
				
			||||||
 | 
					  version "0.2.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
 | 
				
			||||||
 | 
					  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
is-binary-path@^1.0.0:
 | 
					is-binary-path@^1.0.0:
 | 
				
			||||||
  version "1.0.1"
 | 
					  version "1.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
 | 
					  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
 | 
				
			||||||
| 
						 | 
					@ -1714,6 +1802,11 @@ is-buffer@^1.1.5:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
 | 
					  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
 | 
				
			||||||
  integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
 | 
					  integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is-callable@^1.1.4, is-callable@^1.2.0:
 | 
				
			||||||
 | 
					  version "1.2.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
 | 
				
			||||||
 | 
					  integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
is-data-descriptor@^0.1.4:
 | 
					is-data-descriptor@^0.1.4:
 | 
				
			||||||
  version "0.1.4"
 | 
					  version "0.1.4"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
 | 
					  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
 | 
				
			||||||
| 
						 | 
					@ -1728,6 +1821,11 @@ is-data-descriptor@^1.0.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    kind-of "^6.0.0"
 | 
					    kind-of "^6.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is-date-object@^1.0.1:
 | 
				
			||||||
 | 
					  version "1.0.2"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
 | 
				
			||||||
 | 
					  integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
is-descriptor@^0.1.0:
 | 
					is-descriptor@^0.1.0:
 | 
				
			||||||
  version "0.1.6"
 | 
					  version "0.1.6"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
 | 
					  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
 | 
				
			||||||
| 
						 | 
					@ -1801,11 +1899,25 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    isobject "^3.0.1"
 | 
					    isobject "^3.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is-regex@^1.1.0:
 | 
				
			||||||
 | 
					  version "1.1.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff"
 | 
				
			||||||
 | 
					  integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    has-symbols "^1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
is-stream@^1.1.0:
 | 
					is-stream@^1.1.0:
 | 
				
			||||||
  version "1.1.0"
 | 
					  version "1.1.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
 | 
					  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
 | 
				
			||||||
  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
 | 
					  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					is-symbol@^1.0.2:
 | 
				
			||||||
 | 
					  version "1.0.3"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
 | 
				
			||||||
 | 
					  integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    has-symbols "^1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
is-windows@^1.0.1, is-windows@^1.0.2:
 | 
					is-windows@^1.0.1, is-windows@^1.0.2:
 | 
				
			||||||
  version "1.0.2"
 | 
					  version "1.0.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
 | 
					  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
 | 
				
			||||||
| 
						 | 
					@ -1848,7 +1960,7 @@ jake@^10.6.1:
 | 
				
			||||||
    filelist "^1.0.1"
 | 
					    filelist "^1.0.1"
 | 
				
			||||||
    minimatch "^3.0.4"
 | 
					    minimatch "^3.0.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
json-parse-better-errors@^1.0.2:
 | 
					json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
 | 
				
			||||||
  version "1.0.2"
 | 
					  version "1.0.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
 | 
					  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
 | 
				
			||||||
  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
 | 
					  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
 | 
				
			||||||
| 
						 | 
					@ -1903,6 +2015,16 @@ lcid@^2.0.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    invert-kv "^2.0.0"
 | 
					    invert-kv "^2.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					load-json-file@^4.0.0:
 | 
				
			||||||
 | 
					  version "4.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
 | 
				
			||||||
 | 
					  integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    graceful-fs "^4.1.2"
 | 
				
			||||||
 | 
					    parse-json "^4.0.0"
 | 
				
			||||||
 | 
					    pify "^3.0.0"
 | 
				
			||||||
 | 
					    strip-bom "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
loader-runner@^2.4.0:
 | 
					loader-runner@^2.4.0:
 | 
				
			||||||
  version "2.4.0"
 | 
					  version "2.4.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
 | 
					  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
 | 
				
			||||||
| 
						 | 
					@ -2021,6 +2143,11 @@ memory-fs@^0.5.0:
 | 
				
			||||||
    errno "^0.1.3"
 | 
					    errno "^0.1.3"
 | 
				
			||||||
    readable-stream "^2.0.1"
 | 
					    readable-stream "^2.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					memorystream@^0.3.1:
 | 
				
			||||||
 | 
					  version "0.3.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
 | 
				
			||||||
 | 
					  integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
merge-descriptors@1.0.1:
 | 
					merge-descriptors@1.0.1:
 | 
				
			||||||
  version "1.0.1"
 | 
					  version "1.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
 | 
					  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
 | 
				
			||||||
| 
						 | 
					@ -2141,11 +2268,6 @@ mkdirp@^0.5.1, mkdirp@^0.5.3:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    minimist "^1.2.5"
 | 
					    minimist "^1.2.5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mkdirp@^1.0.4:
 | 
					 | 
				
			||||||
  version "1.0.4"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
 | 
					 | 
				
			||||||
  integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
monaco-editor@^0.20.0:
 | 
					monaco-editor@^0.20.0:
 | 
				
			||||||
  version "0.20.0"
 | 
					  version "0.20.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
 | 
					  resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea"
 | 
				
			||||||
| 
						 | 
					@ -2251,6 +2373,16 @@ node-pty@^0.9.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    nan "^2.14.0"
 | 
					    nan "^2.14.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					normalize-package-data@^2.3.2:
 | 
				
			||||||
 | 
					  version "2.5.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
 | 
				
			||||||
 | 
					  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    hosted-git-info "^2.1.4"
 | 
				
			||||||
 | 
					    resolve "^1.10.0"
 | 
				
			||||||
 | 
					    semver "2 || 3 || 4 || 5"
 | 
				
			||||||
 | 
					    validate-npm-package-license "^3.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
normalize-path@^2.1.1:
 | 
					normalize-path@^2.1.1:
 | 
				
			||||||
  version "2.1.1"
 | 
					  version "2.1.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
 | 
					  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
 | 
				
			||||||
| 
						 | 
					@ -2263,6 +2395,21 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
 | 
					  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
 | 
				
			||||||
  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
 | 
					  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					npm-run-all@^4.1.5:
 | 
				
			||||||
 | 
					  version "4.1.5"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba"
 | 
				
			||||||
 | 
					  integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    ansi-styles "^3.2.1"
 | 
				
			||||||
 | 
					    chalk "^2.4.1"
 | 
				
			||||||
 | 
					    cross-spawn "^6.0.5"
 | 
				
			||||||
 | 
					    memorystream "^0.3.1"
 | 
				
			||||||
 | 
					    minimatch "^3.0.4"
 | 
				
			||||||
 | 
					    pidtree "^0.3.0"
 | 
				
			||||||
 | 
					    read-pkg "^3.0.0"
 | 
				
			||||||
 | 
					    shell-quote "^1.6.1"
 | 
				
			||||||
 | 
					    string.prototype.padend "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
npm-run-path@^2.0.0:
 | 
					npm-run-path@^2.0.0:
 | 
				
			||||||
  version "2.0.2"
 | 
					  version "2.0.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
 | 
					  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
 | 
				
			||||||
| 
						 | 
					@ -2284,6 +2431,16 @@ object-copy@^0.1.0:
 | 
				
			||||||
    define-property "^0.2.5"
 | 
					    define-property "^0.2.5"
 | 
				
			||||||
    kind-of "^3.0.3"
 | 
					    kind-of "^3.0.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object-inspect@^1.7.0:
 | 
				
			||||||
 | 
					  version "1.8.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
 | 
				
			||||||
 | 
					  integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1:
 | 
				
			||||||
 | 
					  version "1.1.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
 | 
				
			||||||
 | 
					  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object-visit@^1.0.0:
 | 
					object-visit@^1.0.0:
 | 
				
			||||||
  version "1.0.1"
 | 
					  version "1.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
 | 
					  resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
 | 
				
			||||||
| 
						 | 
					@ -2291,6 +2448,16 @@ object-visit@^1.0.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    isobject "^3.0.0"
 | 
					    isobject "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object.assign@^4.1.0:
 | 
				
			||||||
 | 
					  version "4.1.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
 | 
				
			||||||
 | 
					  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    define-properties "^1.1.2"
 | 
				
			||||||
 | 
					    function-bind "^1.1.1"
 | 
				
			||||||
 | 
					    has-symbols "^1.0.0"
 | 
				
			||||||
 | 
					    object-keys "^1.0.11"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
object.pick@^1.3.0:
 | 
					object.pick@^1.3.0:
 | 
				
			||||||
  version "1.3.0"
 | 
					  version "1.3.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
 | 
					  resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
 | 
				
			||||||
| 
						 | 
					@ -2386,6 +2553,14 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5:
 | 
				
			||||||
    pbkdf2 "^3.0.3"
 | 
					    pbkdf2 "^3.0.3"
 | 
				
			||||||
    safe-buffer "^5.1.1"
 | 
					    safe-buffer "^5.1.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					parse-json@^4.0.0:
 | 
				
			||||||
 | 
					  version "4.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
 | 
				
			||||||
 | 
					  integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    error-ex "^1.3.1"
 | 
				
			||||||
 | 
					    json-parse-better-errors "^1.0.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
parse-passwd@^1.0.0:
 | 
					parse-passwd@^1.0.0:
 | 
				
			||||||
  version "1.0.0"
 | 
					  version "1.0.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
 | 
					  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
 | 
				
			||||||
| 
						 | 
					@ -2426,11 +2601,23 @@ path-key@^2.0.0, path-key@^2.0.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
 | 
					  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
 | 
				
			||||||
  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
 | 
					  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					path-parse@^1.0.6:
 | 
				
			||||||
 | 
					  version "1.0.6"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
 | 
				
			||||||
 | 
					  integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
path-to-regexp@0.1.7:
 | 
					path-to-regexp@0.1.7:
 | 
				
			||||||
  version "0.1.7"
 | 
					  version "0.1.7"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
 | 
					  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
 | 
				
			||||||
  integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
 | 
					  integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					path-type@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
 | 
				
			||||||
 | 
					  integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    pify "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pbkdf2@^3.0.3:
 | 
					pbkdf2@^3.0.3:
 | 
				
			||||||
  version "3.1.1"
 | 
					  version "3.1.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
 | 
					  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
 | 
				
			||||||
| 
						 | 
					@ -2447,6 +2634,16 @@ picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
 | 
					  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
 | 
				
			||||||
  integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
 | 
					  integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pidtree@^0.3.0:
 | 
				
			||||||
 | 
					  version "0.3.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a"
 | 
				
			||||||
 | 
					  integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pify@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
 | 
				
			||||||
 | 
					  integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pify@^4.0.1:
 | 
					pify@^4.0.1:
 | 
				
			||||||
  version "4.0.1"
 | 
					  version "4.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
 | 
					  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
 | 
				
			||||||
| 
						 | 
					@ -2645,6 +2842,15 @@ raw-body@2.4.0:
 | 
				
			||||||
    iconv-lite "0.4.24"
 | 
					    iconv-lite "0.4.24"
 | 
				
			||||||
    unpipe "1.0.0"
 | 
					    unpipe "1.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					read-pkg@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
 | 
				
			||||||
 | 
					  integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    load-json-file "^4.0.0"
 | 
				
			||||||
 | 
					    normalize-package-data "^2.3.2"
 | 
				
			||||||
 | 
					    path-type "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
 | 
					"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
 | 
				
			||||||
  version "2.3.7"
 | 
					  version "2.3.7"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
 | 
					  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
 | 
				
			||||||
| 
						 | 
					@ -2741,6 +2947,13 @@ resolve-url@^0.2.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
 | 
					  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
 | 
				
			||||||
  integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 | 
					  integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resolve@^1.10.0:
 | 
				
			||||||
 | 
					  version "1.17.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
 | 
				
			||||||
 | 
					  integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    path-parse "^1.0.6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ret@~0.1.10:
 | 
					ret@~0.1.10:
 | 
				
			||||||
  version "0.1.15"
 | 
					  version "0.1.15"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
 | 
					  resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
 | 
				
			||||||
| 
						 | 
					@ -2753,13 +2966,6 @@ rimraf@^2.5.4, rimraf@^2.6.3:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    glob "^7.1.3"
 | 
					    glob "^7.1.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rimraf@^3.0.0:
 | 
					 | 
				
			||||||
  version "3.0.2"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
 | 
					 | 
				
			||||||
  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    glob "^7.1.3"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ripemd160@^2.0.0, ripemd160@^2.0.1:
 | 
					ripemd160@^2.0.0, ripemd160@^2.0.1:
 | 
				
			||||||
  version "2.0.2"
 | 
					  version "2.0.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
 | 
					  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
 | 
				
			||||||
| 
						 | 
					@ -2815,7 +3021,7 @@ schema-utils@^2.6.5, schema-utils@^2.6.6:
 | 
				
			||||||
    ajv "^6.12.2"
 | 
					    ajv "^6.12.2"
 | 
				
			||||||
    ajv-keywords "^3.4.1"
 | 
					    ajv-keywords "^3.4.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
semver@^5.5.0, semver@^5.6.0:
 | 
					"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0:
 | 
				
			||||||
  version "5.7.1"
 | 
					  version "5.7.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
 | 
					  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
 | 
				
			||||||
  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 | 
					  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
 | 
				
			||||||
| 
						 | 
					@ -2906,6 +3112,11 @@ shebang-regex@^1.0.0:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
 | 
					  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
 | 
				
			||||||
  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
 | 
					  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shell-quote@^1.6.1:
 | 
				
			||||||
 | 
					  version "1.7.2"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
 | 
				
			||||||
 | 
					  integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
signal-exit@^3.0.0:
 | 
					signal-exit@^3.0.0:
 | 
				
			||||||
  version "3.0.3"
 | 
					  version "3.0.3"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
 | 
					  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
 | 
				
			||||||
| 
						 | 
					@ -2980,6 +3191,32 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
 | 
					  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
 | 
				
			||||||
  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
 | 
					  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					spdx-correct@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.1.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
 | 
				
			||||||
 | 
					  integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    spdx-expression-parse "^3.0.0"
 | 
				
			||||||
 | 
					    spdx-license-ids "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					spdx-exceptions@^2.1.0:
 | 
				
			||||||
 | 
					  version "2.3.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
 | 
				
			||||||
 | 
					  integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					spdx-expression-parse@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
 | 
				
			||||||
 | 
					  integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    spdx-exceptions "^2.1.0"
 | 
				
			||||||
 | 
					    spdx-license-ids "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					spdx-license-ids@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.5"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
 | 
				
			||||||
 | 
					  integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
split-string@^3.0.1, split-string@^3.0.2:
 | 
					split-string@^3.0.1, split-string@^3.0.2:
 | 
				
			||||||
  version "3.1.0"
 | 
					  version "3.1.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
 | 
					  resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
 | 
				
			||||||
| 
						 | 
					@ -3048,6 +3285,30 @@ string-width@^3.0.0, string-width@^3.1.0:
 | 
				
			||||||
    is-fullwidth-code-point "^2.0.0"
 | 
					    is-fullwidth-code-point "^2.0.0"
 | 
				
			||||||
    strip-ansi "^5.1.0"
 | 
					    strip-ansi "^5.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string.prototype.padend@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.1.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz#dc08f57a8010dc5c153550318f67e13adbb72ac3"
 | 
				
			||||||
 | 
					  integrity sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    define-properties "^1.1.3"
 | 
				
			||||||
 | 
					    es-abstract "^1.17.0-next.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string.prototype.trimend@^1.0.1:
 | 
				
			||||||
 | 
					  version "1.0.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
 | 
				
			||||||
 | 
					  integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    define-properties "^1.1.3"
 | 
				
			||||||
 | 
					    es-abstract "^1.17.5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					string.prototype.trimstart@^1.0.1:
 | 
				
			||||||
 | 
					  version "1.0.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
 | 
				
			||||||
 | 
					  integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    define-properties "^1.1.3"
 | 
				
			||||||
 | 
					    es-abstract "^1.17.5"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
string_decoder@^1.0.0, string_decoder@^1.1.1:
 | 
					string_decoder@^1.0.0, string_decoder@^1.1.1:
 | 
				
			||||||
  version "1.3.0"
 | 
					  version "1.3.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
 | 
					  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
 | 
				
			||||||
| 
						 | 
					@ -3069,6 +3330,11 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    ansi-regex "^4.1.0"
 | 
					    ansi-regex "^4.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					strip-bom@^3.0.0:
 | 
				
			||||||
 | 
					  version "3.0.0"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
 | 
				
			||||||
 | 
					  integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
strip-eof@^1.0.0:
 | 
					strip-eof@^1.0.0:
 | 
				
			||||||
  version "1.0.0"
 | 
					  version "1.0.0"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
 | 
					  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
 | 
				
			||||||
| 
						 | 
					@ -3140,13 +3406,6 @@ timers-browserify@^2.0.4:
 | 
				
			||||||
  dependencies:
 | 
					  dependencies:
 | 
				
			||||||
    setimmediate "^1.0.4"
 | 
					    setimmediate "^1.0.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
tmp@^0.2.1:
 | 
					 | 
				
			||||||
  version "0.2.1"
 | 
					 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
 | 
					 | 
				
			||||||
  integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==
 | 
					 | 
				
			||||||
  dependencies:
 | 
					 | 
				
			||||||
    rimraf "^3.0.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
to-arraybuffer@^1.0.0:
 | 
					to-arraybuffer@^1.0.0:
 | 
				
			||||||
  version "1.0.1"
 | 
					  version "1.0.1"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
 | 
					  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
 | 
				
			||||||
| 
						 | 
					@ -3334,6 +3593,14 @@ v8-compile-cache@2.0.3:
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
 | 
					  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
 | 
				
			||||||
  integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
 | 
					  integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					validate-npm-package-license@^3.0.1:
 | 
				
			||||||
 | 
					  version "3.0.4"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
 | 
				
			||||||
 | 
					  integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
 | 
				
			||||||
 | 
					  dependencies:
 | 
				
			||||||
 | 
					    spdx-correct "^3.0.0"
 | 
				
			||||||
 | 
					    spdx-expression-parse "^3.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vary@~1.1.2:
 | 
					vary@~1.1.2:
 | 
				
			||||||
  version "1.1.2"
 | 
					  version "1.1.2"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
 | 
					  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue