From 14a922bea7cae17ed1484ce8b57dd21bd254d7e2 Mon Sep 17 00:00:00 2001 From: chee Date: Mon, 12 Aug 2019 14:16:33 +0100 Subject: [PATCH] remove docker things --- .eslintrc.js | 17 +++++ README.md | 64 +++++++--------- commands/create-snoot.js | 36 +++------ jsconfig.json | 6 ++ library/skeletons.js | 134 ++++----------------------------- library/snoots.js | 156 ++++++++++----------------------------- library/unix.js | 13 ++-- 7 files changed, 124 insertions(+), 302 deletions(-) create mode 100644 .eslintrc.js create mode 100644 jsconfig.json diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..5f63b0c --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,17 @@ +module.exports = { + "env": { + "commonjs": true, + "es6": true, + "node": true + }, + "extends": "eslint:recommended", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018 + }, + "rules": { + } +}; \ No newline at end of file diff --git a/README.md b/README.md index 9706b3e..dad4d84 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Create snoot ## the snoot maintenance module -This is the module used on the [snoot.club](https://snoot.club) server for creating and working with snoots. +This is the module used on the [snoot.club](https://snoot.club) server for +creating and working with snoots. -It's specific to the setup of that server and would need changes in order to be useful to anyone else, but the code is here should anyone ever want to look at it or reuse any of the code. +It's specific to the setup of that server and would need changes in order to be +useful to anyone else, but the code is here should anyone ever want to look at +it or reuse any of the code. -It would be nice to make the non-specific parts of it work without running in that environment, so one could have a local snoot setup, but that's not the focus right now. +It would be nice to make the non-specific parts of it work without running in +that environment, so one could have a local snoot setup, but ## commands @@ -28,30 +32,32 @@ then it will ask for a `name`, and a `githubUsername`. ? what's their github username? ``` -it'll grab their authorized_keys file from `https://github.com/${githubUsername}.keys` +it'll grab their authorized_keys file from +`https://github.com/${githubUsername}.keys` -then it will let you edit their authorized_keys in your `$EDITOR` so you can add any -others you've been provided. +then it will let you edit their authorized_keys in your `$EDITOR` so you can add +any others you've been provided. -once it's gathered all that snoot data, it will create them a unix user with that `name`, -putting them in the groups `common` and `undercommon`. the `common` group owns some files -that every snoot needs to touch, and members of the `undercommon` group can only connect -_*directly*_ to `snoot.club` via `sftp`. these snoot can still log in to their own container -with `ssh`. the user's home directory will be `/snoots/${name}`, which is only used during -`sftp` connections. it's used by `sftp` as a `chroot` root for that snoot. +once it's gathered all that snoot data, it will create them a unix user with +that `name`, putting them in the groups `common` and `undercommon`. -the tool will then create them a base application at `/www/snoot.club/snoots/${name}`. at -the moment this base application is defined in the [skeletons](https://github.com/snootclub/create-snoot/blob/40d842fa2d9c957014d85f815a3e8e601a6cd903/library/skeletons.js) +the tool will then create them a base application at +`/www/snoot.club/snoots/${name}`. at the moment this base application is defined +in the +[skeletons](https://github.com/snootclub/create-snoot/blob/40d842fa2d9c957014d85f815a3e8e601a6cd903/library/skeletons.js) file. in brief, it has: * `snoot.json` — some meta data about a snoot -* `nginx.conf` — an nginx configuration that defers mostly to blocks defined at [snootclub/nginx.conf](https://github.com/snootclub/nginx.conf) -* `docker-compose.yml` — a docker-compose file with a server-bound `/application` directory, forwarding for ssh and http, autorestarting & a start script. it uses the latest [snootclub/snoot docker image](https://hub.docker.com/r/snootclub/snoot) as defined at [snootclub/docker-image on github](https://github.com/snootclub/docker-image) -* `application/ecosystem.config.js` — a [pm2](https://pm2.io/doc/en/runtime/overview/) start script. -* `application/package.json` — an [npm package manifest](https://docs.npmjs.com/files/package.json) that uses [boop](https://github.com/snootclub/boop) for `build`, `watch` and `install` and [zeit's micro](https://github.com/zeit/micro) for `start` -* `application/index.js` — entry point that defers to [boop](https://github.com/snootclub/boop) -* `application/.start.sh` — a start script for the docker container -* `application/website/index.html` — a template html page that tells you how to access your new snoot +* `nginx.conf` — an nginx configuration that defers mostly to blocks defined at + [snootclub/nginx.conf](https://github.com/snootclub/nginx.conf) +* `application/package.json` — an [npm package + manifest](https://docs.npmjs.com/files/package.json) that uses + [boop](https://github.com/snootclub/boop) for `build`, `watch` and `install` + and [zeit's micro](https://github.com/zeit/micro) for `start` +* `application/index.js` — entry point that defers to + [boop](https://github.com/snootclub/boop) +* `application/website/index.html` — a template html page that tells you how to + access your new snoot then it binds👀 the `website` directory into the snoot's sftp chroot root @@ -64,19 +70,3 @@ a few seconds later, the snoot has boot and is ready to toot ### snoot ls list the names of all the snoot, separated by newlines. - -### snoot enter - -enter a running snoot's container - -### snoot start - -start a stopped snoot's container - -### snoot stop - -stop a running snoot's container - -### snoot each - -run a shell command in each snoot. the environment variable `SNOOT_NAME` will be available. diff --git a/commands/create-snoot.js b/commands/create-snoot.js index b6dfef5..8914b83 100755 --- a/commands/create-snoot.js +++ b/commands/create-snoot.js @@ -21,7 +21,7 @@ process.on("uncaughtException", error => { process.exit(222) }) -function getKeysFromGithub (githubUsername) { +async function getKeysFromGithub (githubUsername) { log("gonna get them an authorized_keys file from github") return fetch(`https://github.com/${githubUsername}.keys`) @@ -128,43 +128,25 @@ module.exports = async function createSnoot () { }) } - let snootWebsitePath = snoots.chrootResolver(snoot, "website").path - - if (!await fs.pathExists(snootWebsitePath)) { - await fs.mkdirp(snootWebsitePath) - } - log("adding their authorized_keys ➕🔑 file so they can log in (:") - await snoots.createChrootSshConfiguration(snoot, {authorizedKeys}) + await snoots.createHomeSshConfiguration(snoot, {authorizedKeys}) log("creating a bare git repo for them to live at /repo") await snoots.createBareRepo(snoot) - let { - sshPort, - webPort - } = await snoots.getPorts(snoot) + log("giving them a gitconfig") + await snoots.createHomeGitConfiguration(snoot) log("generating their base application files! 📠 🎰") - await snoots.createBaseApplication(snoot, { - authorizedKeys, - sshPort, - webPort - }) + await snoots.createBaseApplication(snoot) - log("binding snoots 👀") - await snoots.bind() - - log("booting snoot container 👢") - await snoots.bootContainer(snoot) + await fs.move( + snoots.applicationResolver("nginx.conf").path, + snoots.rootResolver("snoots-nginx")(`${snoot}.conf`).path + ) log("restarting nginx 🔂") await shell.run("nginx -s reload") - - if (!snootAlreadyExists) { - log("updating next snoot port 🌸") - await snoots.setNextPort(webPort + 1) - } } let beingRunDirectly = process.argv[1].match(/create-snoot($|\.js$)/) diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..3eb5db6 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,6 @@ +{ + "lib": "es2019", + "compilerOptions": { + "downlevelIteration": true + } +} diff --git a/library/skeletons.js b/library/skeletons.js index 47a7d60..351bbbf 100644 --- a/library/skeletons.js +++ b/library/skeletons.js @@ -4,16 +4,7 @@ let inquirer = require("inquirer") exports.files = { logs: {}, - "snoot.json" ({snoot, githubUsername, webPort, sshPort, authorizedKeys}) { - return JSON.stringify({ - snoot, - webPort, - sshPort, - authorizedKeys, - githubUsername - }, null, "\t") + os.EOL - }, - "nginx.conf" ({snoot, webPort}) { + "nginx.conf" (snoot) { return `server { include /www/snoot.club/blocks/error_page.nginx; include /www/snoot.club/blocks/ssl.nginx; @@ -21,12 +12,12 @@ exports.files = { default_type text/plain; server_name ${snoot}.snoot.club; - access_log /www/snoot.club/snoots/${snoot}/logs/access.ssl.log; - error_log /www/snoot.club/snoots/${snoot}/logs/error.ssl.log; + access_log /www/snoot.club/snoots/logs/${snoot}.access.ssl.log; + error_log /www/snoot.club/snoots/logs/${snoot}.error.ssl.log; location / { include /www/snoot.club/blocks/cors.nginx; - proxy_pass http://127.0.0.1:${webPort}/; + proxy_pass http://unix:/www/snoot.club/snoots/${snoot}/application/sock:/; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -43,22 +34,6 @@ server { server_name ${snoot}.snoot.club; return 301 https://${snoot}.snoot.club$request_uri; } -` - }, - "docker-compose.yml" ({sshPort, webPort}) { - return `version: "3" -services: - snoot: - image: "snootclub/snoot:soft" - working_dir: /application - volumes: - - ./application/:/application - - ./repo:/repo - ports: - - "${sshPort}:22" - - "${webPort}:80" - restart: always - command: "/application/.start.sh" ` }, repo: { @@ -78,17 +53,7 @@ npx @snootclub/post-receive` .cache/ ` }, - "ecosystem.config.js" () { - return `module.exports = { - apps : [{ - name: "snoot", - script: "npm start", - watch: true - }] -} -` - }, - "package.json" ({snoot}) { + "package.json" (snoot) { return `{ "name": "${snoot}-application", "version": "1.0.0", @@ -97,13 +62,13 @@ npx @snootclub/post-receive` "install": "boop", "watch": "boop", "build": "boop", - "start": "micro -l tcp://0.0.0.0:80" +"start": "micro -l unix:sock" }, "author": "${snoot} <${snoot}@snoot.club>", "license": "GPL-3.0+", "description": "${snoot} application on snoot.club", "dependencies": { - "@snootclub/boop": "^0.0.9", + "@snootclub/boop": "^0.0.14", "micro": "^9.3.3" } } @@ -116,37 +81,8 @@ module.exports = (request, response) => boop(request, response) ` }, - ".start.sh" ({snoot}) { - return `#!/bin/sh -mv /application/authorized_keys /root/.ssh/authorized_keys -chown root.root /root/.ssh/authorized_keys -/bin/sshd -cd /application -npm install -npm run-script build -pm2 start ecosystem.config.js -if [ ! -e .git ]; then - git init - git remote add origin ../repo - git branch -u origin/master - if $(git pull origin master); then - echo get your coat mate youve pulled - else - git config --global user.name ${snoot} - git config --global user.email ${snoot}@snoot.club - git add . - git commit -m "${snoot}'s snoot starts here" - git push -u origin master - fi -fi -tail -f /dev/null -` - }, - "authorized_keys" ({authorizedKeys}) { - return authorizedKeys - }, website: { - "index.html" ({snoot, sshPort}) { + "index.html" (snoot) { return ` ${snoot}'s a snoot @@ -200,57 +136,19 @@ tail -f /dev/null

- if you are ${snoot}, then you have two choices: + if you are ${snoot}, you can now ssh or ftp into your account!

-
    -
  • -

    sftp into the snoot.club server

    -

    - this is if you only want to set up static files. anything - you drop in the website/ folder will be available publicly at ${snoot}.snoot.club -

    -
      -
    • sftp ${snoot}@snoot.club
    • -
    • - the page you are reading right now is the file located at - ./website/index.html -
    • -
    -
  • -
  • -

    ssh into the ${snoot}.snoot.club container

    -

    - this allows you to edit the whole application. you're a full - administrator and anything you set up to listen on port 80 - will be available at this address. -

    -
      -
    • ssh root@snoot.club -p ${sshPort}
    • -
    • - the page you are reading right now is the file located at - /application/website/index.html. -
    • -
    -
  • -
- -
-

- if you want to ssh in without remembering the port, adding - the below to the ~/.ssh/config on your local machine - will let you access it by running ssh snoot in a terminal. + the page you are reading right now is the file located at + ./application/website/index.html

-
-
-Host snoot
-	User root
-	HostName snoot.club
-	Port ${sshPort}
-
-
+

+ the start script in your package.json will be run automatically. + it needs to create a unix domain socket called sock in + the application directory. +

` } } diff --git a/library/snoots.js b/library/snoots.js index 18132b9..172bd92 100644 --- a/library/snoots.js +++ b/library/snoots.js @@ -3,11 +3,11 @@ let createResolver = require("./create-path-resolver.js") let unix = require("./unix.js") let shell = require("./shell.js") let skeletons = require("./skeletons.js") -let {warn, shout} = require("./loggo.js") +let {shout} = require("./loggo.js") let rootResolver = createResolver("/www/snoot.club") let resolver = rootResolver("snoots") -let chrootResolver = createResolver("/snoots") +let homeResolver = createResolver("/snoots") let validNameRegex = /^[a-z][a-z0-9]{0,30}$/ @@ -17,16 +17,16 @@ let validateName = snoot => let applicationResolver = (snoot, ...paths) => resolver(snoot, "application", ...paths) - let repoResolver = (snoot, ...paths) => resolver(snoot, "repo", ...paths) let websiteResolver = (snoot, ...paths) => resolver(snoot, "application", "website", ...paths) -async function createChrootSshConfiguration (snoot, {authorizedKeys}) { - let snootChrootResolver = chrootResolver(snoot) - let sshDirectoryResolver = snootChrootResolver(".ssh") +async function createHomeSshConfiguration (snoot, {authorizedKeys}) { + let snootHomeResolver = homeResolver(snoot) + let snootResolver = resolver(snoot) + let sshDirectoryResolver = snootResolver(".ssh") let authorizedKeysPath = sshDirectoryResolver("authorized_keys").path await fs.outputFile( @@ -35,15 +35,20 @@ async function createChrootSshConfiguration (snoot, {authorizedKeys}) { ) let rootOwnedPaths = [ - chrootResolver.path, - snootChrootResolver.path, + homeResolver ] let snootOwnedPaths = [ sshDirectoryResolver.path, - authorizedKeysPath + authorizedKeysPath, + snootHomeResolver.path ] + await unix.ln({ + from: snootHomeResolver.path, + to: snootResolver.path + }) + let snootId = await unix.getUserId(snoot) let commonId = await unix.getCommonGid() @@ -62,11 +67,30 @@ async function createChrootSshConfiguration (snoot, {authorizedKeys}) { } } +async function createHomeGitConfiguration (snoot) { + let snootResolver = resolver(snoot) + let gitconfigPath = snootResolver(".gitconfig").path + + let gitconfig = `[user] + name = ${snoot} + email ${snoot}@snoot.club +` + + await fs.outputFile( + gitconfig, + gitconfigPath + ) + + let snootId = await unix.getUserId(snoot) + let commonId = await unix.getCommonGid() + await fs.chown(gitconfigPath, snootId, commonId) +} + async function createUnixAccount (snoot) { return await unix.createUser({ user: snoot, groups: [unix.commonGroupName, unix.lowerGroupName], - homeDirectory: chrootResolver(snoot).path + homeDirectory: homeResolver(snoot).path }) } @@ -81,30 +105,17 @@ async function createBareRepo (snoot) { }) } -async function createBaseApplication (snoot, options = {}) { - let { - authorizedKeys = "", - sshPort = 22222, - webPort = 22333 - } = options - +async function createBaseApplication (snoot) { await skeletons.write({ resolver: resolver(snoot), uid: await unix.getUserId(snoot), gid: await unix.getCommonGid(), - render: compile => compile({ - snoot, - snootRoot: resolver.path, - authorizedKeys, - sshPort, - webPort - }), + render: compile => compile(snoot), getPermissions ({filePath, fileType}) { if (fileType == skeletons.fileTypes.file) { let rwxr_xr_x = 0o755 - let startScript = applicationResolver(snoot, ".start.sh").path let postReceive = repoResolver(snoot, "hooks", "post-receive").path - if (filePath == startScript || filePath == postReceive) { + if (filePath == postReceive) { return { mode: rwxr_xr_x } @@ -114,40 +125,10 @@ async function createBaseApplication (snoot, options = {}) { }) } -function bootContainer (snoot) { - let result = shell.run("docker-compose up -d", { - cwd: resolver(snoot).path - }) - - result.stdout.pipe(process.stdout) - - return result.then(code => ( - code && warn(`couldn't boot the snoot! (${snoot})`), - result.stderr.pipe(process.stderr), - code - )) -} - -let nextPortPath = resolver(".next-port").path - -async function getNextPort () { - return await fs.pathExists(nextPortPath) - ? Number(await fs.readFile(nextPortPath)) - : 22222 -} - -async function setNextPort (port) { - return fs.outputFile(nextPortPath, port) -} - -function getConfigPath (snoot) { - return resolver(snoot, "snoot.json").path -} - async function getNames () { let files = await fs.readdir(resolver.path) return files.filter(name => - validateName(name) && fs.pathExistsSync(getConfigPath(name)) + validateName(name) ) } @@ -157,61 +138,11 @@ async function each (fn) { } } -async function bind () { - await each(async snoot => { - let websitePath = websiteResolver(snoot).path - let chrootWebsitePath = chrootResolver(snoot, "website").path - await fs.mkdirp(websitePath) - await unix.unmount(chrootWebsitePath).catch(_ => _) - await fs.pathExists(websitePath) && - await unix.bind(websitePath, chrootWebsitePath) - .catch(() => { - warn(`couldn't bind snoot called "${snoot}", maybe not supported on os?`) - }) - }) -} - async function checkExists (snoot) { let names = await getNames() return names.includes(snoot) } -async function getConfig (snoot) { - if (!await checkExists(snoot)) { - return Promise.reject(`can't get config for no such snoot: ${snoot}`) - } - - let configPath = getConfigPath(snoot) - - if (!await fs.pathExists(configPath)) { - return Promise.reject(`can't get config for ${snoot}, no snoot.json`) - } - - return fs.readJson(configPath) -} - -async function getPorts (snoot) { - if (await checkExists(snoot)) { - let { - sshPort, - webPort - } = await getConfig(snoot) - - return { - sshPort, - webPort - } - } - - let sshPort = await getNextPort() - let webPort = sshPort + 1 - - return { - sshPort, - webPort - } -} - async function demandExistence (snoot) { let names = await getNames() @@ -224,22 +155,17 @@ async function demandExistence (snoot) { module.exports = { rootResolver, resolver, - chrootResolver, + homeResolver, applicationResolver, websiteResolver, - createChrootSshConfiguration, + createHomeSshConfiguration, + createHomeGitConfiguration, createUnixAccount, createBaseApplication, - bootContainer, - setNextPort, - getNextPort, each, - bind, checkExists, validateName, getNames, - getConfig, - getPorts, demandExistence, createBareRepo } diff --git a/library/unix.js b/library/unix.js index 95e06fe..835d1b8 100644 --- a/library/unix.js +++ b/library/unix.js @@ -84,10 +84,13 @@ exports.unmount = directory => {sudo: true} ) -exports.bind = async (boy, bedposts) => { - await fs.mkdirp(bedposts) +exports.ln = async function ln ({from, to, symbolic = true, sudo = true}) { + let s = symbolic + ? "-s" + : "" + return shell.run( - `mount --bind ${boy} ${bedposts}`, - {sudo: true} - ).then(code => code && Promise.reject("couldnt bind")) + `ln ${s} ${to} ${from}`, + {sudo} + ) }