chore: Adds lom with basic commands parsing.
This commit is contained in:
parent
7c1e26b150
commit
3a773e5b9b
10 changed files with 451 additions and 10 deletions
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
|
@ -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
3
.gitignore
vendored
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -21,4 +31,5 @@ services:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
ssh_key_data:
|
14
lom/Dockerfile
Normal file
14
lom/Dockerfile
Normal 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
5
lom/docker-entrypoint.sh
Executable 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
220
lom/package-lock.json
generated
|
@ -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",
|
||||||
|
|
|
@ -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
37
lom/src/commands.ts
Normal 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");
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
147
lom/src/index.ts
147
lom/src/index.ts
|
@ -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");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue