chore: Adds lom with basic commands parsing.

This commit is contained in:
greysoh 2024-05-06 11:31:51 -04:00
parent 7c1e26b150
commit 3a773e5b9b
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37
10 changed files with 451 additions and 10 deletions

View file

@ -97,9 +97,14 @@ jobs:
- name: Build all docker images - name: Build all docker images
run: | run: |
docker build ./api --tag ghcr.io/greysoh/api:$(cat VERSION) docker build ./api --tag ghcr.io/greysoh/api:$(cat VERSION)
docker build ./lom --tag ghcr.io/greysoh/lom:$(cat VERSION)
- name: Publish all docker images - name: Publish all docker images
run: | run: |
docker tag ghcr.io/greysoh/api:$(cat VERSION) ghcr.io/greysoh/api:latest docker tag ghcr.io/greysoh/api:$(cat VERSION) ghcr.io/greysoh/api:latest
docker push ghcr.io/greysoh/api:$(cat VERSION) docker push ghcr.io/greysoh/api:$(cat VERSION)
docker push ghcr.io/greysoh/api:latest docker push ghcr.io/greysoh/api:latest
docker tag ghcr.io/greysoh/lom:$(cat VERSION) ghcr.io/greysoh/lom:latest
docker push ghcr.io/greysoh/lom:$(cat VERSION)
docker push ghcr.io/greysoh/lom:latest

3
.gitignore vendored
View file

@ -1,3 +1,6 @@
# LOM
lom/keys
# Rust # Rust
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables

View file

@ -1,4 +1,7 @@
#!/bin/bash #!/bin/bash
export NODE_ENV="production"
export DATABASE_URL="postgresql://$POSTGRES_USERNAME:$POSTGRES_PASSWORD@nextnet-postgres:5432/$POSTGRES_DB?schema=nextnet"
echo "Welcome to NextNet." echo "Welcome to NextNet."
echo "Running database migrations..." echo "Running database migrations..."
npx prisma migrate deploy npx prisma migrate deploy

View file

@ -3,11 +3,21 @@ services:
image: ghcr.io/greysoh/api:latest image: ghcr.io/greysoh/api:latest
container_name: nextnet-api container_name: nextnet-api
restart: always restart: always
env_file:
- .env
ports: ports:
- 3000:3000 - 3000:3000
environment:
NODE_ENV: production # NOTE: For this to work correctly, the nextnet-api must be version > 0.1.1
DATABASE_URL: "postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@nextnet-postgres:5432/${POSTGRES_DB}?schema=nextnet" # or have a version with backported username support, incl. logins
nextnet-lom:
image: ghcr.io/greysoh/nextnet-ssh:latest
container_name: nextnet_api
restart: always
ports:
- 2222:2222
volumes:
- ssh_key_data:/app/keys
postgres: postgres:
image: postgres:15.4 image: postgres:15.4
@ -22,3 +32,4 @@ services:
volumes: volumes:
postgres_data: postgres_data:
ssh_key_data:

14
lom/Dockerfile Normal file
View file

@ -0,0 +1,14 @@
FROM node:20.11.1-bookworm
LABEL org.opencontainers.image.source="https://github.com/greysoh/nextnet"
WORKDIR /app/
COPY src /app/src
COPY tsconfig.json /app/
COPY package.json /app/
COPY package-lock.json /app/
COPY docker-entrypoint.sh /app/
RUN npm install --save-dev
RUN npm run build
RUN rm out/**/*.ts out/**/*.map
RUN rm -rf src
RUN npm prune --production
ENTRYPOINT sh docker-entrypoint.sh

5
lom/docker-entrypoint.sh Executable file
View file

@ -0,0 +1,5 @@
#!/bin/bash
export NODE_ENV="production"
export SERVER_BASE_URL="http://nextnet-api:3000/"
npm start

220
lom/package-lock.json generated
View file

@ -1,18 +1,52 @@
{ {
"name": "typescript-base", "name": "nextnet-lom",
"version": "1.0.0", "version": "0.1.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "typescript-base", "name": "nextnet-lom",
"version": "1.0.0", "version": "0.1.0",
"license": "UNLICENSED", "license": "BSD-3-Clause",
"dependencies": {
"axios": "^1.6.8",
"ssh2": "^1.15.0",
"string-argv": "^0.3.2"
},
"devDependencies": { "devDependencies": {
"@types/node": "^20.12.8",
"@types/ssh2": "^1.15.0",
"nodemon": "^3.0.3", "nodemon": "^3.0.3",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }
}, },
"node_modules/@types/node": {
"version": "20.12.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.8.tgz",
"integrity": "sha512-NU0rJLJnshZWdE/097cdCBbyW1h4hEg0xpovcoAQYHl8dnEyp/NAOiE45pvc+Bd1Dt+2r94v2eGFpQJ4R7g+2w==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/@types/ssh2": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-1.15.0.tgz",
"integrity": "sha512-YcT8jP5F8NzWeevWvcyrrLB3zcneVjzYY9ZDSMAMboI+2zR1qYWFhwsyOFVzT7Jorn67vqxC0FRiw8YyG9P1ww==",
"dev": true,
"dependencies": {
"@types/node": "^18.11.18"
}
},
"node_modules/@types/ssh2/node_modules/@types/node": {
"version": "18.19.31",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
"integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/abbrev": { "node_modules/abbrev": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -32,12 +66,43 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/axios": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
"integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": { "node_modules/balanced-match": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true "dev": true
}, },
"node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dependencies": {
"tweetnacl": "^0.14.3"
}
},
"node_modules/binary-extensions": { "node_modules/binary-extensions": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -69,6 +134,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/buildcheck": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz",
"integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==",
"optional": true,
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/chokidar": { "node_modules/chokidar": {
"version": "3.5.3", "version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@ -96,12 +170,37 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": { "node_modules/concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true "dev": true
}, },
"node_modules/cpu-features": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",
"integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
"hasInstallScript": true,
"optional": true,
"dependencies": {
"buildcheck": "~0.0.6",
"nan": "^2.19.0"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "4.3.4", "version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@ -119,6 +218,14 @@
} }
} }
}, },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@ -131,6 +238,38 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -226,6 +365,25 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": { "node_modules/minimatch": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -244,6 +402,12 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true "dev": true
}, },
"node_modules/nan": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz",
"integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==",
"optional": true
},
"node_modules/nodemon": { "node_modules/nodemon": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz",
@ -308,6 +472,11 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"node_modules/pstree.remy": { "node_modules/pstree.remy": {
"version": "1.1.8", "version": "1.1.8",
"resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
@ -326,6 +495,11 @@
"node": ">=8.10.0" "node": ">=8.10.0"
} }
}, },
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/semver": { "node_modules/semver": {
"version": "7.5.4", "version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
@ -353,6 +527,31 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/ssh2": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.15.0.tgz",
"integrity": "sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==",
"hasInstallScript": true,
"dependencies": {
"asn1": "^0.2.6",
"bcrypt-pbkdf": "^1.0.2"
},
"engines": {
"node": ">=10.16.0"
},
"optionalDependencies": {
"cpu-features": "~0.0.9",
"nan": "^2.18.0"
}
},
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/supports-color": { "node_modules/supports-color": {
"version": "5.5.0", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@ -389,6 +588,11 @@
"nodetouch": "bin/nodetouch.js" "nodetouch": "bin/nodetouch.js"
} }
}, },
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.3.3", "version": "5.3.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
@ -408,6 +612,12 @@
"integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
"dev": true "dev": true
}, },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
"node_modules/yallist": { "node_modules/yallist": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

View file

@ -3,6 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"description": "Lights Out Management, NextNet style", "description": "Lights Out Management, NextNet style",
"main": "index.js", "main": "index.js",
"type": "module",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc", "build": "tsc",
@ -13,7 +14,14 @@
"author": "greysoh", "author": "greysoh",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"devDependencies": { "devDependencies": {
"@types/node": "^20.12.8",
"@types/ssh2": "^1.15.0",
"nodemon": "^3.0.3", "nodemon": "^3.0.3",
"typescript": "^5.3.3" "typescript": "^5.3.3"
},
"dependencies": {
"axios": "^1.6.8",
"ssh2": "^1.15.0",
"string-argv": "^0.3.2"
} }
} }

37
lom/src/commands.ts Normal file
View file

@ -0,0 +1,37 @@
import type { Axios } from "axios";
type PrintLine = (...str: string[]) => void;
type Command = (
args: string[],
println: PrintLine,
axios: Axios,
apiKey: string,
) => Promise<void>;
type Commands = {
name: string;
description: string;
run: Command;
}[];
// TODO: add commands!
export const commands: Commands = [
{
name: "help",
description: "Prints help",
async run(_args: string[], printf: PrintLine) {
commands.forEach(command => {
printf(`${command.name}: ${command.description}\n`);
});
},
},
{
name: "clear",
description: "Clears screen",
async run(_args: string[], printf: PrintLine) {
printf("\x1B[2J\x1B[3J\x1B[H");
},
},
];

View file

@ -1 +1,146 @@
console.log("Hello, world!"); import { readFile, writeFile, mkdir } from "node:fs/promises";
import parseArgsStringToArgv from "string-argv";
import baseAxios from "axios";
import ssh2 from "ssh2";
import { commands } from "./commands.js";
let keyFile: Buffer | string | undefined;
const serverBaseURL: string =
process.env.SERVER_BASE_URL ?? "http://127.0.0.1:3000/";
const axios = baseAxios.create({
baseURL: serverBaseURL,
validateStatus(status) {
return true;
},
});
try {
keyFile = await readFile("../keys/host.key");
} catch (e) {
console.log("Error reading host key file! Creating new keypair...");
await mkdir("../keys").catch(() => null);
const keyPair: { private: string; public: string } = await new Promise(
resolve =>
ssh2.utils.generateKeyPair("ed25519", (err, keyPair) => resolve(keyPair)),
);
await writeFile("../keys/host.key", keyPair.private);
await writeFile("../keys/host.pub", keyPair.public);
keyFile = keyPair.private;
}
if (!keyFile) throw new Error("Somehow failed to fetch the key file!");
const server: ssh2.Server = new ssh2.Server({
hostKeys: [keyFile],
banner: "NextNet-LOM (c) NextNet project et al.",
greeting: "NextNet LOM (beta)",
});
server.on("connection", client => {
let token: string = "";
client.on("authentication", async auth => {
if (auth.method != "password") return auth.reject(["password"]); // We need to know the password to auth with the API
const response = await axios.post("/api/v1/users/login", {
username: auth.username,
password: auth.password,
});
if (response.status == 403) {
return auth.reject(["password"]);
}
token = response.data.token;
auth.accept();
});
client.on("ready", () => {
client.on("session", (accept, reject) => {
const conn = accept();
// We're dumb. We don't really care.
conn.on("pty", accept => accept());
conn.on("window-change", accept => accept());
conn.on("shell", async accept => {
const stream = accept();
stream.write(
"Welcome to NextNet LOM. Run 'help' to see commands.\r\n\r\n~$ ",
);
let line = "";
function println(...str: string[]) {
stream.write(str.join(" ").replace("\n", "\r\n"));
}
async function eventLoop(): Promise<any> {
const readStreamData = stream.read();
if (readStreamData == null) return setTimeout(eventLoop, 5);
if (readStreamData.includes("\r") || readStreamData.includes("\n")) {
line = line.replace("\r", "");
if (line == "") {
stream.write(`\r\n~$ `);
return setTimeout(eventLoop, 5);
}
const argv = parseArgsStringToArgv(line);
line = "";
if (argv[0] == "exit") {
stream.close();
} else {
stream.write("\r\n");
const command = commands.find(i => i.name == argv[0]);
if (!command) {
stream.write(
`Unknown command ${argv[0]}. Run 'help' to see commands.\r\n~$ `,
);
return setTimeout(eventLoop, 5);
}
await command.run(argv, println, axios, token);
stream.write(`~$ `);
}
} else if (readStreamData.includes("\x7F")) {
// \x7F = Ascii escape code for backspace (client side)
if (line == "" || line == "\r") return setTimeout(eventLoop, 5);
line = line.substring(0, line.length - 1);
// Ascii excape code for backspace (server side)
stream.write("\u0008 \u0008");
} else if (!readStreamData.includes("\x1B")) {
// (hacky) include all input but client sided ascii movement
// TODO: implement
line += readStreamData;
stream.write(readStreamData);
}
setTimeout(eventLoop, 5);
}
eventLoop();
});
});
});
});
server.listen(
2222,
process.env.NODE_ENV == "production" ? "0.0.0.0" : "127.0.0.1",
);
console.log("Started server at ::2222");