feat: v0
Signed-off-by: Avior <github@avior.me>
This commit is contained in:
parent
8442c7b4e3
commit
ae1b7f9ec4
3
.gitignore
vendored
3
.gitignore
vendored
@ -21,3 +21,6 @@ pnpm-debug.log*
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
slicers/*
|
slicers/*
|
||||||
|
|
||||||
|
# Coverage
|
||||||
|
coverage/
|
||||||
|
@ -47,15 +47,15 @@ ENV CONFIGS_PATH=./configs
|
|||||||
# ENV SLICER_PATH slic3r
|
# ENV SLICER_PATH slic3r
|
||||||
|
|
||||||
# Download & install PrusaSlicer
|
# Download & install PrusaSlicer
|
||||||
ADD https://github.com/prusa3d/PrusaSlicer/releases/download/version_2.5.2/PrusaSlicer-2.5.2+linux-x64-GTK3-202303231201.tar.bz2 ./
|
ADD https://github.com/prusa3d/PrusaSlicer/releases/download/version_2.6.0/PrusaSlicer-2.6.0+linux-x64-GTK3-202306191220.tar.bz2 ./
|
||||||
RUN tar -xvf PrusaSlicer-2.5.2+linux-x64-GTK3-202303231201.tar.bz2 -C /opt
|
RUN tar -xvf PrusaSlicer-2.6.0+linux-x64-GTK3-202306191220.tar.bz2 -C /opt
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends \
|
&& apt-get install -y --no-install-recommends \
|
||||||
prusa-slicer \
|
prusa-slicer \
|
||||||
&& apt-get remove prusa-slicer -y \
|
&& apt-get remove prusa-slicer -y \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
ENV PATH /opt/PrusaSlicer-2.5.2+linux-x64-GTK3-202303231201/bin:$PATH
|
ENV PATH /opt/PrusaSlicer-2.6.0+linux-x64-GTK3-202306191220/bin:$PATH
|
||||||
ENV SLICER_PATH prusa-slicer
|
ENV SLICER_PATH prusa-slicer
|
||||||
|
|
||||||
# run as non root user
|
# run as non root user
|
||||||
|
281
package-lock.json
generated
281
package-lock.json
generated
@ -10,15 +10,21 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^5.2.0",
|
"@astrojs/node": "^5.2.0",
|
||||||
"@astrojs/tailwind": "^3.1.3",
|
"@astrojs/tailwind": "^3.1.3",
|
||||||
|
"@dzeio/logger": "^3.0.0",
|
||||||
"@dzeio/object-util": "^1.5.0",
|
"@dzeio/object-util": "^1.5.0",
|
||||||
"@dzeio/url-manager": "^1.0.9",
|
"@dzeio/url-manager": "^1.0.9",
|
||||||
"astro": "^2.6.4",
|
"astro": "^2.6.4",
|
||||||
|
"bcryptjs": "^2.4.3",
|
||||||
|
"jsonwebtoken": "^9.0.0",
|
||||||
"mathjs": "^11.8.1",
|
"mathjs": "^11.8.1",
|
||||||
"mongoose": "^7.3.0",
|
"mongoose": "^7.3.0",
|
||||||
"tailwindcss": "^3.3.2"
|
"tailwindcss": "^3.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/jsonwebtoken": "^9.0.2",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
|
"@vitest/coverage-v8": "^0.32.2",
|
||||||
"cypress": "^12.15.0",
|
"cypress": "^12.15.0",
|
||||||
"vitest": "^0.32.2"
|
"vitest": "^0.32.2"
|
||||||
}
|
}
|
||||||
@ -519,6 +525,12 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@bcoe/v8-coverage": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@colors/colors": {
|
"node_modules/@colors/colors": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
||||||
@ -577,6 +589,14 @@
|
|||||||
"ms": "^2.1.1"
|
"ms": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@dzeio/logger": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@dzeio/logger/-/logger-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-CmqmIblP6XZdapWOwmoYG3/lBX7HX1vK0i6hY6ArjCyjg8dWpLierx6vagnfhk5NIIs1jpIS3hR759QJwFE9xw==",
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-colors": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@dzeio/object-util": {
|
"node_modules/@dzeio/object-util": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@dzeio/object-util/-/object-util-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@dzeio/object-util/-/object-util-1.5.0.tgz",
|
||||||
@ -941,6 +961,15 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@istanbuljs/schema": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||||
@ -1091,6 +1120,12 @@
|
|||||||
"@babel/types": "^7.20.7"
|
"@babel/types": "^7.20.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/bcryptjs": {
|
||||||
|
"version": "2.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz",
|
||||||
|
"integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/chai": {
|
"node_modules/@types/chai": {
|
||||||
"version": "4.3.5",
|
"version": "4.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
|
||||||
@ -1122,11 +1157,26 @@
|
|||||||
"@types/unist": "*"
|
"@types/unist": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/istanbul-lib-coverage": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/json5": {
|
"node_modules/@types/json5": {
|
||||||
"version": "0.0.30",
|
"version": "0.0.30",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.30.tgz",
|
||||||
"integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA=="
|
"integrity": "sha512-sqm9g7mHlPY/43fcSNrCYfOeX9zkTTK+euO5E6+CVijSMm5tTjkVdwdqRkY3ljjIAf8679vps5jKUoJBCLsMDA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/jsonwebtoken": {
|
||||||
|
"version": "9.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||||
|
"integrity": "sha512-drE6uz7QBKq1fYqqoFKTDRdFCPHd5TCub75BM+D+cMx7NU9hUz7SESLfC2fSCXVFMO5Yj8sOWHuGqPgjc+fz0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/mdast": {
|
"node_modules/@types/mdast": {
|
||||||
"version": "3.0.11",
|
"version": "3.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.11.tgz",
|
||||||
@ -1209,6 +1259,43 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vitest/coverage-v8": {
|
||||||
|
"version": "0.32.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-0.32.2.tgz",
|
||||||
|
"integrity": "sha512-/+V3nB3fyeuuSeKxCfi6XmWjDIxpky7AWSkGVfaMjAk7di8igBwRsThLjultwIZdTDH1RAxpjmCXEfSqsMFZOA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@ampproject/remapping": "^2.2.1",
|
||||||
|
"@bcoe/v8-coverage": "^0.2.3",
|
||||||
|
"istanbul-lib-coverage": "^3.2.0",
|
||||||
|
"istanbul-lib-report": "^3.0.0",
|
||||||
|
"istanbul-lib-source-maps": "^4.0.1",
|
||||||
|
"istanbul-reports": "^3.1.5",
|
||||||
|
"magic-string": "^0.30.0",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"std-env": "^3.3.2",
|
||||||
|
"test-exclude": "^6.0.0",
|
||||||
|
"v8-to-istanbul": "^9.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://opencollective.com/vitest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vitest": ">=0.32.0 <1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@vitest/coverage-v8/node_modules/magic-string": {
|
||||||
|
"version": "0.30.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz",
|
||||||
|
"integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/sourcemap-codec": "^1.4.13"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@vitest/expect": {
|
"node_modules/@vitest/expect": {
|
||||||
"version": "0.32.2",
|
"version": "0.32.2",
|
||||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz",
|
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz",
|
||||||
@ -1394,7 +1481,6 @@
|
|||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
|
||||||
"integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
|
"integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
@ -1734,6 +1820,11 @@
|
|||||||
"tweetnacl": "^0.14.3"
|
"tweetnacl": "^0.14.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bcryptjs": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
|
||||||
|
},
|
||||||
"node_modules/big-integer": {
|
"node_modules/big-integer": {
|
||||||
"version": "1.6.51",
|
"version": "1.6.51",
|
||||||
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
|
||||||
@ -1965,6 +2056,11 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-equal-constant-time": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||||
|
},
|
||||||
"node_modules/bundle-name": {
|
"node_modules/bundle-name": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
|
||||||
@ -3099,6 +3195,14 @@
|
|||||||
"safer-buffer": "^2.1.0"
|
"safer-buffer": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@ -4224,6 +4328,83 @@
|
|||||||
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
|
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/istanbul-lib-coverage": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-report": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"istanbul-lib-coverage": "^3.0.0",
|
||||||
|
"make-dir": "^3.0.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-report/node_modules/has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-report/node_modules/supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-lib-source-maps": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"istanbul-lib-coverage": "^3.0.0",
|
||||||
|
"source-map": "^0.6.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-reports": {
|
||||||
|
"version": "3.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz",
|
||||||
|
"integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"html-escaper": "^2.0.0",
|
||||||
|
"istanbul-lib-report": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/istanbul-reports/node_modules/html-escaper": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/javascript-natural-sort": {
|
"node_modules/javascript-natural-sort": {
|
||||||
"version": "0.7.1",
|
"version": "0.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
|
||||||
@ -4319,6 +4500,21 @@
|
|||||||
"graceful-fs": "^4.1.6"
|
"graceful-fs": "^4.1.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonwebtoken": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
|
||||||
|
"dependencies": {
|
||||||
|
"jws": "^3.2.2",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"semver": "^7.3.8"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12",
|
||||||
|
"npm": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsprim": {
|
"node_modules/jsprim": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz",
|
||||||
@ -4334,6 +4530,25 @@
|
|||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jwa": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-equal-constant-time": "1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jws": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||||
|
"dependencies": {
|
||||||
|
"jwa": "^1.4.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/kareem": {
|
"node_modules/kareem": {
|
||||||
"version": "2.5.1",
|
"version": "2.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz",
|
||||||
@ -4569,8 +4784,7 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.once": {
|
"node_modules/lodash.once": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@ -4813,6 +5027,30 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/make-dir": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"semver": "^6.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/make-dir/node_modules/semver": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"semver": "bin/semver.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/markdown-table": {
|
"node_modules/markdown-table": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
|
||||||
@ -7375,6 +7613,15 @@
|
|||||||
"npm": ">= 3.0.0"
|
"npm": ">= 3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/source-map": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||||
@ -7685,6 +7932,20 @@
|
|||||||
"node": ">=10.13.0"
|
"node": ">=10.13.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/test-exclude": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@istanbuljs/schema": "^0.1.2",
|
||||||
|
"glob": "^7.1.4",
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/thenify": {
|
"node_modules/thenify": {
|
||||||
"version": "3.3.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
|
||||||
@ -8159,6 +8420,20 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/v8-to-istanbul": {
|
||||||
|
"version": "9.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz",
|
||||||
|
"integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@jridgewell/trace-mapping": "^0.3.12",
|
||||||
|
"@types/istanbul-lib-coverage": "^2.0.1",
|
||||||
|
"convert-source-map": "^1.6.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/verror": {
|
"node_modules/verror": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
|
||||||
|
@ -9,20 +9,26 @@
|
|||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro",
|
||||||
"test": "vitest"
|
"test": "vitest --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/node": "^5.2.0",
|
"@astrojs/node": "^5.2.0",
|
||||||
"@astrojs/tailwind": "^3.1.3",
|
"@astrojs/tailwind": "^3.1.3",
|
||||||
|
"@dzeio/logger": "^3.0.0",
|
||||||
"@dzeio/object-util": "^1.5.0",
|
"@dzeio/object-util": "^1.5.0",
|
||||||
"@dzeio/url-manager": "^1.0.9",
|
"@dzeio/url-manager": "^1.0.9",
|
||||||
"astro": "^2.6.4",
|
"astro": "^2.6.4",
|
||||||
|
"bcryptjs": "^2.4.3",
|
||||||
|
"jsonwebtoken": "^9.0.0",
|
||||||
"mathjs": "^11.8.1",
|
"mathjs": "^11.8.1",
|
||||||
"mongoose": "^7.3.0",
|
"mongoose": "^7.3.0",
|
||||||
"tailwindcss": "^3.3.2"
|
"tailwindcss": "^3.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/bcryptjs": "^2.4.2",
|
||||||
|
"@types/jsonwebtoken": "^9.0.2",
|
||||||
"@types/node": "^20.3.1",
|
"@types/node": "^20.3.1",
|
||||||
|
"@vitest/coverage-v8": "^0.32.2",
|
||||||
"cypress": "^12.15.0",
|
"cypress": "^12.15.0",
|
||||||
"vitest": "^0.32.2"
|
"vitest": "^0.32.2"
|
||||||
}
|
}
|
||||||
|
3
src/env.d.ts
vendored
3
src/env.d.ts
vendored
@ -3,7 +3,10 @@
|
|||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
CONFIGS_PATH?: string
|
CONFIGS_PATH?: string
|
||||||
PRUSASLICER_PATH?: string
|
PRUSASLICER_PATH?: string
|
||||||
|
BAMBUSTUDIO_PATH?: string
|
||||||
MONGODB?: string
|
MONGODB?: string
|
||||||
|
PRIVATE_KEY?: string
|
||||||
|
PUBLIC_KEY?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
|
9
src/libs/AuthUtils.ts
Normal file
9
src/libs/AuthUtils.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import bcryptjs from 'bcryptjs'
|
||||||
|
|
||||||
|
export function hashPassword(password: string): Promise<string> {
|
||||||
|
return bcryptjs.hash(password, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function comparePassword(password: string, hash: string): Promise<boolean> {
|
||||||
|
return bcryptjs.compare(password, hash)
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
import type { ServerResponse } from 'node:http'
|
|
||||||
|
|
||||||
export default class CookieManager {
|
export default class CookieManager {
|
||||||
private cookies: Record<string, string> = {}
|
private cookies: Record<string, string> = {}
|
||||||
public constructor(data?: string | Record<string, string>) {
|
public constructor(data?: string | Record<string, string>) {
|
||||||
if (typeof data === 'string') {
|
if (typeof data === 'string') {
|
||||||
data.split(';').forEach((keyValuePair) => {
|
data.split(';').forEach((keyValuePair) => {
|
||||||
const [key, value] = keyValuePair.split('=')
|
const [key, value] = keyValuePair.split('=')
|
||||||
|
if (!key || !value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.cookies[key.trim()] = value.trim().replace(/%3B/g, ';')
|
this.cookies[key.trim()] = value.trim().replace(/%3B/g, ';')
|
||||||
})
|
})
|
||||||
} else if (typeof data === 'object') {
|
} else if (typeof data === 'object') {
|
||||||
@ -13,7 +14,7 @@ export default class CookieManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static addCookie(res: ServerResponse, cookie: {
|
public static addCookie(res: ResponseInit & { readonly headers: Headers; }, cookie: {
|
||||||
key: string
|
key: string
|
||||||
value: string
|
value: string
|
||||||
expire?: string
|
expire?: string
|
||||||
@ -46,7 +47,7 @@ export default class CookieManager {
|
|||||||
if (cookie.sameSite) {
|
if (cookie.sameSite) {
|
||||||
items.push(`SameSite=${cookie.sameSite}`)
|
items.push(`SameSite=${cookie.sameSite}`)
|
||||||
}
|
}
|
||||||
res.setHeader('Set-Cookie', items.join('; '))
|
res.headers.append('Set-Cookie', items.join('; '))
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): string | undefined {
|
public get(key: string): string | undefined {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import DaoFactory from '../models/DaoFactory'
|
import DaoFactory from '../models/DaoFactory'
|
||||||
import CookieManager from './CookieManager'
|
import CookieManager from './CookieManager'
|
||||||
import RFC7807, { buildRFC7807 } from './RFCs/RFC7807'
|
import { buildRFC7807 } from './RFCs/RFC7807'
|
||||||
|
|
||||||
interface Permission {
|
interface Permission {
|
||||||
name: string
|
name: string
|
||||||
|
@ -1,21 +1,83 @@
|
|||||||
|
import { objectOmit } from '@dzeio/object-util'
|
||||||
|
import mongoose from 'mongoose'
|
||||||
import type Config from '.'
|
import type Config from '.'
|
||||||
|
import Client from '../Client'
|
||||||
import Dao from '../Dao'
|
import Dao from '../Dao'
|
||||||
|
|
||||||
export default class ConfigDao extends Dao<Config> {
|
export default class ConfigDao extends Dao<Config> {
|
||||||
private idx = 0
|
|
||||||
public async create(obj: Omit<Config, 'id'>): Promise<Config | null> {
|
// @ts-expect-error typing fix
|
||||||
console.log('pouet', this.idx++)
|
private model = mongoose.models['Config'] as null ?? mongoose.model('Config', new mongoose.Schema({
|
||||||
return null
|
user: { type: String, required: true },
|
||||||
// throw new Error('Method not implemented.')
|
type: { type: String, required: true},
|
||||||
|
files: [{
|
||||||
|
name: { type: String, unique: true, required: true},
|
||||||
|
data: { type: Buffer, required: true }
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
timestamps: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
public async create(obj: Omit<Config, 'id' | 'created' | 'updated'>): Promise<Config | null> {
|
||||||
|
await Client.get()
|
||||||
|
return this.fromSource(await this.model.create(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findAll(query?: Partial<Config> | undefined): Promise<Config[]> {
|
public async findAll(query?: Partial<Config> | undefined): Promise<Config[]> {
|
||||||
throw new Error('Method not implemented.')
|
await Client.get()
|
||||||
|
try {
|
||||||
|
if (query?.id) {
|
||||||
|
const item = await this.model.findById(new mongoose.Types.ObjectId(query.id))
|
||||||
|
if (!item) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [this.fromSource(item)]
|
||||||
|
}
|
||||||
|
const resp = await this.model.find(query ? this.toSource(query as Config) : {})
|
||||||
|
return resp.map(this.fromSource)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async update(obj: Config): Promise<Config | null> {
|
public async update(obj: Config): Promise<Config | null> {
|
||||||
throw new Error('Method not implemented.')
|
await Client.get()
|
||||||
|
|
||||||
|
const query = await this.model.updateOne({
|
||||||
|
_id: new mongoose.Types.ObjectId(obj.id)
|
||||||
|
}, this.toSource(obj))
|
||||||
|
if (query.matchedCount >= 1) {
|
||||||
|
obj.updated = new Date()
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
// return this.fromSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
public async delete(obj: Config): Promise<boolean> {
|
public async delete(obj: Config): Promise<boolean> {
|
||||||
throw new Error('Method not implemented.')
|
await Client.get()
|
||||||
|
const res = await this.model.deleteOne({
|
||||||
|
_id: new mongoose.Types.ObjectId(obj.id)
|
||||||
|
})
|
||||||
|
return res.deletedCount > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
private toSource(obj: Config): Omit<Config, 'id'> {
|
||||||
|
return objectOmit(obj, 'id', 'updated', 'created')
|
||||||
|
}
|
||||||
|
|
||||||
|
private fromSource(doc: mongoose.Document<any, any, Config>): Config {
|
||||||
|
return {
|
||||||
|
id: doc._id.toString(),
|
||||||
|
user: doc.get('user'),
|
||||||
|
type: doc.get('type'),
|
||||||
|
files: doc.get('files') ?? [],
|
||||||
|
updated: doc.get('updatedAt'),
|
||||||
|
created: doc.get('createdAt')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
import type User from '../User'
|
|
||||||
|
|
||||||
export default interface Config {
|
export default interface Config {
|
||||||
id: string
|
id: string
|
||||||
user: string
|
user: string
|
||||||
|
type: 'prusa'
|
||||||
|
files: Array<{
|
||||||
|
name: string
|
||||||
|
data: Buffer
|
||||||
|
}>
|
||||||
|
created: Date
|
||||||
|
updated: Date
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import APIKeyDao from './APIKey/APIKeyDao'
|
import APIKeyDao from './APIKey/APIKeyDao'
|
||||||
import ConfigDao from './Config/ConfigDao'
|
import ConfigDao from './Config/ConfigDao'
|
||||||
import Dao from './Dao'
|
import SessionDao from './Session/SessionDao'
|
||||||
import UserDao from './User/UserDao'
|
import UserDao from './User/UserDao'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -18,6 +18,7 @@ interface DaoItem {
|
|||||||
config: ConfigDao
|
config: ConfigDao
|
||||||
user: UserDao
|
user: UserDao
|
||||||
apiKey: APIKeyDao
|
apiKey: APIKeyDao
|
||||||
|
session: SessionDao
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,11 +55,12 @@ export default class DaoFactory {
|
|||||||
* @param item the element to init
|
* @param item the element to init
|
||||||
* @returns a new initialized dao or undefined if no dao is linked
|
* @returns a new initialized dao or undefined if no dao is linked
|
||||||
*/
|
*/
|
||||||
private static initDao(item: keyof DaoItem): Dao<any> | undefined {
|
private static initDao(item: keyof DaoItem): any | undefined {
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case 'config': return new ConfigDao()
|
case 'config': return new ConfigDao()
|
||||||
case 'user': return new UserDao()
|
case 'user': return new UserDao()
|
||||||
case 'apiKey': return new APIKeyDao()
|
case 'apiKey': return new APIKeyDao()
|
||||||
|
case 'session': return new SessionDao()
|
||||||
default: return undefined
|
default: return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
53
src/models/Session/SessionDao.ts
Normal file
53
src/models/Session/SessionDao.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import jwt, { SignOptions } from 'jsonwebtoken'
|
||||||
|
import type Session from '.'
|
||||||
|
import CookieManager from '../../libs/CookieManager'
|
||||||
|
|
||||||
|
export interface SessionOptions {
|
||||||
|
cookieName: string
|
||||||
|
security: SignOptions
|
||||||
|
key?: string
|
||||||
|
privateKey?: string
|
||||||
|
publicKey?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default class SessionDao {
|
||||||
|
|
||||||
|
private options: SessionOptions = {
|
||||||
|
cookieName: 'session',
|
||||||
|
security: {
|
||||||
|
algorithm: 'ES512'
|
||||||
|
},
|
||||||
|
privateKey: import.meta.env.PRIVATE_KEY ?? '',
|
||||||
|
publicKey: import.meta.env.PUBLIC_KEY ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSession(req: Request): Session | null {
|
||||||
|
const cookie = new CookieManager(req.headers.get('Cookie') ?? '').get(this.options.cookieName)
|
||||||
|
if (!cookie) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return jwt.verify(cookie, (this.options.publicKey || this.options.key) as string) as Session
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSession(session: Session, res: ResponseInit & { readonly headers: Headers; }) {
|
||||||
|
const token = jwt.sign(session, (this.options.privateKey || this.options.key) as string, this.options.security)
|
||||||
|
CookieManager.addCookie(res, {
|
||||||
|
key: this.options.cookieName,
|
||||||
|
value: token,
|
||||||
|
httpOnly: true,
|
||||||
|
path: '/',
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'Strict',
|
||||||
|
maxAge: 365000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeSession(res: ResponseInit & { readonly headers: Headers; }) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
3
src/models/Session/index.ts
Normal file
3
src/models/Session/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export default interface Session {
|
||||||
|
userId: string
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { objectOmit } from '@dzeio/object-util'
|
import { objectOmit } from '@dzeio/object-util'
|
||||||
import mongoose, { ObjectId } from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
import User from '.'
|
import type User from '.'
|
||||||
import Client from '../Client'
|
import Client from '../Client'
|
||||||
import Dao from '../Dao'
|
import Dao from '../Dao'
|
||||||
|
|
||||||
@ -8,7 +8,8 @@ export default class UserDao extends Dao<User> {
|
|||||||
|
|
||||||
// @ts-expect-error typing fix
|
// @ts-expect-error typing fix
|
||||||
private model = mongoose.models['User'] as null ?? mongoose.model('User', new mongoose.Schema({
|
private model = mongoose.models['User'] as null ?? mongoose.model('User', new mongoose.Schema({
|
||||||
email: { type: String, required: true }
|
email: { type: String, required: true },
|
||||||
|
password: { type: String, required: true }
|
||||||
}, {
|
}, {
|
||||||
timestamps: true
|
timestamps: true
|
||||||
}))
|
}))
|
||||||
@ -62,6 +63,7 @@ export default class UserDao extends Dao<User> {
|
|||||||
return {
|
return {
|
||||||
id: doc._id.toString(),
|
id: doc._id.toString(),
|
||||||
email: doc.get('email'),
|
email: doc.get('email'),
|
||||||
|
password: doc.get('password'),
|
||||||
updated: doc.get('updatedAt'),
|
updated: doc.get('updatedAt'),
|
||||||
created: doc.get('createdAt')
|
created: doc.get('createdAt')
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export default interface User {
|
export default interface User {
|
||||||
id: string
|
id: string
|
||||||
email: string
|
email: string
|
||||||
|
password: string
|
||||||
created: Date
|
created: Date
|
||||||
updated: Date
|
updated: Date
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,23 @@ import URLManager from '@dzeio/url-manager'
|
|||||||
import Layout from '../../layouts/Layout.astro'
|
import Layout from '../../layouts/Layout.astro'
|
||||||
import DaoFactory from '../../models/DaoFactory'
|
import DaoFactory from '../../models/DaoFactory'
|
||||||
import { comparePassword } from '../../libs/AuthUtils'
|
import { comparePassword } from '../../libs/AuthUtils'
|
||||||
|
import Passthrough from '../../components/Passthrough.astro'
|
||||||
|
|
||||||
const logout = new URLManager(Astro.url).query('logout')
|
const logout = typeof new URLManager(Astro.url).query('logout') === 'string'
|
||||||
|
|
||||||
if (typeof logout === 'string') {
|
if (logout) {
|
||||||
DaoFactory.get('session').removeSession(Astro.response)
|
DaoFactory.get('session').removeSession(Astro.response)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DaoFactory.get('session').removeSession(Astro.response)
|
// DaoFactory.get('session').removeSession(Astro.response)
|
||||||
|
|
||||||
if (Astro.request.method === 'POST') {
|
let connected = false
|
||||||
|
const sessionDao = DaoFactory.get('session')
|
||||||
|
if (sessionDao.getSession(Astro.request) && !logout) {
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!connected && Astro.request.method === 'POST') {
|
||||||
const form = await Astro.request.formData()
|
const form = await Astro.request.formData()
|
||||||
const email = form.get('email') as string
|
const email = form.get('email') as string
|
||||||
const password = form.get('password') as string
|
const password = form.get('password') as string
|
||||||
@ -21,27 +28,39 @@ if (Astro.request.method === 'POST') {
|
|||||||
email
|
email
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!account) {
|
if (account) {
|
||||||
return
|
const valid = await comparePassword(password, account.password)
|
||||||
|
if (valid) {
|
||||||
|
DaoFactory.get('session').setSession({
|
||||||
|
userId: account.id
|
||||||
|
}, Astro.response)
|
||||||
|
connected = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const valid = await comparePassword(password, account.password)
|
|
||||||
if (!valid) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
DaoFactory.get('session').setSession({
|
|
||||||
userId: account.id
|
|
||||||
}, Astro.response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Welcome to Astro.">
|
<Layout title="Welcome to Astro.">
|
||||||
<main>
|
<main>
|
||||||
<form>
|
<form method="post">
|
||||||
<input type="email" name="email" />
|
<input type="email" name="email" />
|
||||||
<input type="password" name="password" />
|
<input type="password" name="password" />
|
||||||
<button>Connect</button>
|
<button>Connect</button>
|
||||||
<button></button>
|
<button></button>
|
||||||
</form>
|
</form>
|
||||||
</main>
|
</main>
|
||||||
|
<Passthrough connected={connected} />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
<script>import { load } from '../../components/Passthrough.astro'
|
||||||
|
|
||||||
|
const {
|
||||||
|
connected
|
||||||
|
} = load<{connected: boolean}>()
|
||||||
|
|
||||||
|
if (connected) {
|
||||||
|
window.location = '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@ -7,19 +7,31 @@ const user = await DaoFactory.get('user').get('648f81f857503c7d29465318')
|
|||||||
const list = await DaoFactory.get('apiKey').findAll({
|
const list = await DaoFactory.get('apiKey').findAll({
|
||||||
user: user!.id
|
user: user!.id
|
||||||
})
|
})
|
||||||
|
const configs = await DaoFactory.get('config').findAll({
|
||||||
|
user: user!.id
|
||||||
|
})
|
||||||
const userId = user?.id ?? 'unknown'
|
const userId = user?.id ?? 'unknown'
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Welcome to Astro.">
|
<Layout title="Welcome to Astro.">
|
||||||
<main>
|
<main>
|
||||||
|
<h1>{user?.id}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>API Keys</li>
|
||||||
{list.map((it) => (
|
{list.map((it) => (
|
||||||
<li>
|
<li>
|
||||||
<p>access key: {it.key}</p>
|
<p>access key: {it.key}</p>
|
||||||
<p>permissions: {it.permissions}</p>
|
<p>permissions: {it.permissions}</p>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
<li>Configurations</li>
|
||||||
|
{configs.map((it) => (
|
||||||
|
<li>
|
||||||
|
<p>{it.id}: {it.type}</p>
|
||||||
|
<p>{it.files.map((it) => it.name)}</p>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
|
||||||
<button>Create a new API Key</button>
|
<button>Create a new API Key</button>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
|
import Logger from '@dzeio/logger'
|
||||||
import { objectMap, objectOmit } from '@dzeio/object-util'
|
import { objectMap, objectOmit } from '@dzeio/object-util'
|
||||||
import URLManager from '@dzeio/url-manager'
|
import URLManager from '@dzeio/url-manager'
|
||||||
import type { APIRoute } from 'astro'
|
import type { APIRoute } from 'astro'
|
||||||
import { evaluate } from 'mathjs'
|
import { evaluate } from 'mathjs'
|
||||||
import { exec as execSync } from 'node:child_process'
|
import { exec as execSync, spawn } from 'node:child_process'
|
||||||
import fs from 'node:fs/promises'
|
import fs from 'node:fs/promises'
|
||||||
import os from 'node:os'
|
import os from 'node:os'
|
||||||
import path from 'node:path/posix'
|
import path from 'node:path'
|
||||||
import { promisify } from 'node:util'
|
import { promisify } from 'node:util'
|
||||||
import FilesUtils from '../../../libs/FilesUtils'
|
|
||||||
import { buildRFC7807 } from '../../../libs/RFCs/RFC7807'
|
import { buildRFC7807 } from '../../../libs/RFCs/RFC7807'
|
||||||
import { getParams } from '../../../libs/gcodeUtils'
|
import { getParams } from '../../../libs/gcodeUtils'
|
||||||
|
import { validateAuth } from '../../../libs/validateAuth'
|
||||||
|
import DaoFactory from '../../../models/DaoFactory'
|
||||||
|
|
||||||
const exec = promisify(execSync)
|
const exec = promisify(execSync)
|
||||||
|
|
||||||
@ -21,50 +23,101 @@ let tmpDir: string
|
|||||||
* price: algorithm from settings
|
* price: algorithm from settings
|
||||||
* adionnal settings from https://manual.slic3r.org/advanced/command-line
|
* adionnal settings from https://manual.slic3r.org/advanced/command-line
|
||||||
*/
|
*/
|
||||||
export const post: APIRoute = async ({ request }) => {
|
export const post: APIRoute = async ({ params, request }) => {
|
||||||
|
const res = await validateAuth(request, {
|
||||||
|
name: 'slicing.slice',
|
||||||
|
api: true,
|
||||||
|
cookie: true
|
||||||
|
})
|
||||||
|
if (res) {
|
||||||
|
return res
|
||||||
|
}
|
||||||
if (!tmpDir) {
|
if (!tmpDir) {
|
||||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'paas-'))
|
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'saas-'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const configId = params.configId ?? 'undefined'
|
||||||
|
const config = await DaoFactory.get('config').get(configId)
|
||||||
|
|
||||||
|
if (!config) {
|
||||||
|
return buildRFC7807({
|
||||||
|
type: '/missing-config',
|
||||||
|
status: 404,
|
||||||
|
title: 'The configuration does not exists',
|
||||||
|
details: `The configuration ${configId} does not exists`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = new URLManager(request.url).query()
|
const query = new URLManager(request.url).query()
|
||||||
const file = (Math.random() * 1000000).toFixed(0)
|
|
||||||
console.log('started processing new request', file)
|
|
||||||
await fs.mkdir(`${tmpDir}/files`, { recursive: true })
|
|
||||||
|
|
||||||
const overrides = objectOmit(query, 'algo', 'config')
|
const processId = (Math.random() * 1000000).toFixed(0)
|
||||||
const configName = query?.config ?? 'config'
|
const logger = new Logger(`process-${processId}`)
|
||||||
let config = `${import.meta.env.CONFIGS_PATH}/` + configName + '.ini'
|
const processFolder = `${tmpDir}/${processId}`
|
||||||
if (!await FilesUtils.exists(config)) {
|
const pouet = await fs.mkdir(processFolder, { recursive: true })
|
||||||
console.log('request finished in error :(', file)
|
|
||||||
return buildRFC7807({
|
logger.log('poeut', pouet)
|
||||||
type: '/missing-config-file',
|
|
||||||
status: 404,
|
logger.log('started processing request')
|
||||||
title: 'Configuration file is missing',
|
|
||||||
details: `the configuration file "${configName}" is not available on the remote server`
|
logger.log('writing configs to dir')
|
||||||
})
|
for (const file of config.files) {
|
||||||
|
await fs.writeFile(`${processFolder}/${file.name}`, file.data)
|
||||||
}
|
}
|
||||||
const stlPath = `${tmpDir}/files/${file}.stl`
|
|
||||||
const gcodePath = `${tmpDir}/files/${file}.gcode`
|
|
||||||
|
|
||||||
// write file
|
|
||||||
|
const overrides = objectOmit(query, 'algo')
|
||||||
|
|
||||||
|
const stlPath = `${processFolder}/input.stl`
|
||||||
|
const gcodePath = `${processFolder}/output.gcode`
|
||||||
|
|
||||||
|
logger.log('writing STL to filesystem')
|
||||||
|
// write input
|
||||||
await fs.writeFile(stlPath, new Uint8Array(Buffer.from(await request.arrayBuffer())), {
|
await fs.writeFile(stlPath, new Uint8Array(Buffer.from(await request.arrayBuffer())), {
|
||||||
encoding: null
|
encoding: null
|
||||||
})
|
})
|
||||||
// console.log(fs.statSync(stlPath).size, req.body.length)
|
|
||||||
|
// additionnal parameters
|
||||||
let additionnalParams = objectMap(overrides, (value, key) => `--${(key as string).replace(/_/g, '-')} ${value}`).join(' ')
|
let additionnalParams = objectMap(overrides, (value, key) => `--${(key as string).replace(/_/g, '-')} ${value}`).join(' ')
|
||||||
const slicer = import.meta.env.PRUSASLICER_PATH ?? 'prusa-slicer'
|
|
||||||
if (slicer.includes('prusa')) {
|
|
||||||
|
let slicerPath: string
|
||||||
|
let slicerCommand: string
|
||||||
|
|
||||||
|
if (config.type === 'prusa' || true) {
|
||||||
|
slicerPath = import.meta.env.PRUSASLICER_PATH ?? 'prusa-slicer'
|
||||||
additionnalParams += ' --export-gcode'
|
additionnalParams += ' --export-gcode'
|
||||||
|
slicerCommand = `${path.normalize(stlPath)} --load ${path.normalize(`${processFolder}/config.ini`)} --output ${path.normalize(gcodePath)} ${additionnalParams}`
|
||||||
}
|
}
|
||||||
const cmd = `${slicer} ${stlPath} --load ${config} --output ${gcodePath} ${additionnalParams}`
|
|
||||||
try {
|
try {
|
||||||
await exec(cmd, {
|
logger.log('Running', slicerPath, slicerCommand)
|
||||||
timeout: 60000
|
await new Promise<void>((res, rej) => {
|
||||||
|
const slicer = spawn(slicerPath, slicerCommand.split(' '))
|
||||||
|
slicer.stdout.on('data', (data) => {
|
||||||
|
logger.log('[stdout]',data.toString('utf8'))
|
||||||
|
})
|
||||||
|
slicer.stderr.on('data', (data: Buffer) => {
|
||||||
|
logger.log('[stderr]', data.toString('utf8'))
|
||||||
|
})
|
||||||
|
slicer.on('error', (err) => {
|
||||||
|
logger.log('error', err)
|
||||||
|
rej(err)
|
||||||
|
})
|
||||||
|
slicer.on('close', (code, signal) => {
|
||||||
|
logger.log('code', code)
|
||||||
|
logger.log('signal', signal)
|
||||||
|
if (typeof code === 'number' && code > 0) {
|
||||||
|
|
||||||
|
rej(code)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.log('request finished in error :(', file)
|
logger.log('request finished in error :(', processId)
|
||||||
const line = e.toString()
|
const line = e.toString()
|
||||||
console.error(e)
|
logger.error(e)
|
||||||
if (line.includes('Objects could not fit on the bed')) {
|
if (line.includes('Objects could not fit on the bed')) {
|
||||||
await fs.rm(stlPath)
|
await fs.rm(stlPath)
|
||||||
return buildRFC7807({
|
return buildRFC7807({
|
||||||
@ -78,7 +131,7 @@ export const post: APIRoute = async ({ request }) => {
|
|||||||
type: '/missing-config-file',
|
type: '/missing-config-file',
|
||||||
status: 404,
|
status: 404,
|
||||||
title: 'Configuration file is missing',
|
title: 'Configuration file is missing',
|
||||||
details: `the configuration file "${configName}" is not available on the remote server`
|
details: `the configuration file "${configId}" is not available on the remote server`
|
||||||
})
|
})
|
||||||
} else if (line.includes('Unknown option')) {
|
} else if (line.includes('Unknown option')) {
|
||||||
await fs.rm(stlPath)
|
await fs.rm(stlPath)
|
||||||
@ -115,18 +168,18 @@ export const post: APIRoute = async ({ request }) => {
|
|||||||
status: 500,
|
status: 500,
|
||||||
title: 'General I/O error',
|
title: 'General I/O error',
|
||||||
details: 'A server error make it impossible to slice the file, please contact an administrator with the json error',
|
details: 'A server error make it impossible to slice the file, please contact an administrator with the json error',
|
||||||
fileId: file,
|
fileId: processId,
|
||||||
config: configName,
|
config: configId,
|
||||||
// fileSize: req.body.length,
|
// fileSize: req.body.length,
|
||||||
overrides: overrides,
|
overrides: overrides,
|
||||||
serverMessage:
|
serverMessage:
|
||||||
e.toString().replace(cmd, '***SLICER***').replace(stlPath, configName ?? `***FILE***`).replace(`${path}/configs/`, '').replace('.ini', '')
|
e.toString().replace(new RegExp(stlPath), `***FILE***`).replace(new RegExp(processFolder), '')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const gcode = await fs.readFile(gcodePath, 'utf-8')
|
const gcode = await fs.readFile(gcodePath, 'utf-8')
|
||||||
await fs.rm(stlPath)
|
await fs.rm(processFolder, { recursive: true, force: true })
|
||||||
await fs.rm(gcodePath)
|
logger.log('Getting parameters')
|
||||||
const params = getParams(gcode)
|
const gcodeParams = getParams(gcode)
|
||||||
let price: string | undefined
|
let price: string | undefined
|
||||||
if (query?.algo) {
|
if (query?.algo) {
|
||||||
let algo = decodeURI(query.algo as string)
|
let algo = decodeURI(query.algo as string)
|
||||||
@ -139,7 +192,8 @@ export const post: APIRoute = async ({ request }) => {
|
|||||||
// }
|
// }
|
||||||
// })
|
// })
|
||||||
try {
|
try {
|
||||||
const tmp = evaluate(algo, params)
|
logger.log('Evaluating Alogrithm')
|
||||||
|
const tmp = evaluate(algo, gcodeParams)
|
||||||
if (typeof tmp === 'number') {
|
if (typeof tmp === 'number') {
|
||||||
price = tmp.toFixed(2)
|
price = tmp.toFixed(2)
|
||||||
} else {
|
} else {
|
||||||
@ -150,11 +204,11 @@ export const post: APIRoute = async ({ request }) => {
|
|||||||
details: 'It seems the algorithm resolution failed',
|
details: 'It seems the algorithm resolution failed',
|
||||||
algorithm: algo,
|
algorithm: algo,
|
||||||
algorithmError: 'Algorithm return a Unit',
|
algorithmError: 'Algorithm return a Unit',
|
||||||
parameters: params
|
parameters: gcodeParams
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.dir(e)
|
logger.dir(e)
|
||||||
return buildRFC7807({
|
return buildRFC7807({
|
||||||
type: '/algorithm-error',
|
type: '/algorithm-error',
|
||||||
status: 500,
|
status: 500,
|
||||||
@ -162,11 +216,11 @@ export const post: APIRoute = async ({ request }) => {
|
|||||||
details: 'It seems the algorithm resolution failed',
|
details: 'It seems the algorithm resolution failed',
|
||||||
algorithm: algo,
|
algorithm: algo,
|
||||||
algorithmError: e,
|
algorithmError: e,
|
||||||
parameters: params
|
parameters: gcodeParams
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('request successfull :)', file)
|
logger.log('request successfull :)')
|
||||||
return {
|
return {
|
||||||
status: 200,
|
status: 200,
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
import { objectOmit } from '@dzeio/object-util'
|
||||||
|
import type { APIRoute } from 'astro'
|
||||||
|
import { buildRFC7807 } from '../../../../../../../libs/RFCs/RFC7807'
|
||||||
|
import DaoFactory from '../../../../../../../models/DaoFactory'
|
||||||
|
|
||||||
|
export const get: APIRoute = async ({ params, request }) => {
|
||||||
|
const userId = params.userId as string
|
||||||
|
const configId = params.configId as string
|
||||||
|
const fileName = params.fileName as string
|
||||||
|
|
||||||
|
|
||||||
|
const dao = await DaoFactory.get('config').get(configId)
|
||||||
|
|
||||||
|
if (!dao) {
|
||||||
|
return buildRFC7807({
|
||||||
|
title: 'Config does not exists :('
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = dao.files.find((it) => it.name === fileName)
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: file?.data
|
||||||
|
}
|
||||||
|
}
|
44
src/pages/api/users/[userId]/configs/index.ts
Normal file
44
src/pages/api/users/[userId]/configs/index.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { objectOmit } from '@dzeio/object-util'
|
||||||
|
import type { APIRoute } from 'astro'
|
||||||
|
import { buildRFC7807 } from '../../../../../libs/RFCs/RFC7807'
|
||||||
|
import DaoFactory from '../../../../../models/DaoFactory'
|
||||||
|
|
||||||
|
export const post: APIRoute = async ({ params, request }) => {
|
||||||
|
const userId = params.userId as string
|
||||||
|
|
||||||
|
const body = request.body
|
||||||
|
|
||||||
|
if (!body) {
|
||||||
|
return buildRFC7807({
|
||||||
|
title: 'Missing config file'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = body.getReader()
|
||||||
|
|
||||||
|
const chunks: Array<Uint8Array> = []
|
||||||
|
|
||||||
|
let finished= false
|
||||||
|
do {
|
||||||
|
const { done, value } = await reader.read()
|
||||||
|
finished = done
|
||||||
|
if (value) {
|
||||||
|
chunks.push(value)
|
||||||
|
}
|
||||||
|
} while (!finished)
|
||||||
|
|
||||||
|
const buffer = Buffer.concat(chunks)
|
||||||
|
|
||||||
|
const dao = await DaoFactory.get('config').create({
|
||||||
|
user: userId,
|
||||||
|
type: 'prusa',
|
||||||
|
files: [{
|
||||||
|
name: 'config.ini',
|
||||||
|
data: buffer
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
status: 201,
|
||||||
|
body: JSON.stringify(objectOmit(dao ?? {}, 'files'))
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,14 @@
|
|||||||
import type { APIRoute } from 'astro'
|
import type { APIRoute } from 'astro'
|
||||||
import crypto from 'node:crypto'
|
import crypto from 'node:crypto'
|
||||||
|
import { validateAuth } from '../../../../../libs/validateAuth'
|
||||||
import DaoFactory from '../../../../../models/DaoFactory'
|
import DaoFactory from '../../../../../models/DaoFactory'
|
||||||
|
|
||||||
export const post: APIRoute = async ({ params, request }) => {
|
export const post: APIRoute = async ({ params, request }) => {
|
||||||
|
validateAuth(request, {
|
||||||
|
name: 'keys.create',
|
||||||
|
cookie: true,
|
||||||
|
api: false
|
||||||
|
})
|
||||||
const userId = params.userId as string
|
const userId = params.userId as string
|
||||||
|
|
||||||
const dao = await DaoFactory.get('apiKey').create({
|
const dao = await DaoFactory.get('apiKey').create({
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { assert, expect, test } from 'vitest'
|
import { assert, expect, test } from 'vitest'
|
||||||
|
import { comparePassword, hashPassword } from '../src/libs/AuthUtils'
|
||||||
|
|
||||||
// Edit an assertion and save to see HMR in action
|
// Edit an assertion and save to see HMR in action
|
||||||
|
|
||||||
@ -19,3 +20,14 @@ test('JSON', () => {
|
|||||||
expect(output).eq('{"foo":"hello","bar":"world"}');
|
expect(output).eq('{"foo":"hello","bar":"world"}');
|
||||||
assert.deepEqual(JSON.parse(output), input, 'matches original');
|
assert.deepEqual(JSON.parse(output), input, 'matches original');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('auth util', async () => {
|
||||||
|
const password = 'pouet'
|
||||||
|
|
||||||
|
const out1 = await hashPassword(password)
|
||||||
|
expect(out1).not.toBe(password)
|
||||||
|
const out2 = await hashPassword(password)
|
||||||
|
expect(out2).not.toBe(out1)
|
||||||
|
expect(await comparePassword(password, out1)).toBe(true)
|
||||||
|
expect(await comparePassword(password, out2)).toBe(true)
|
||||||
|
})
|
||||||
|
3
tsconfig.json
Normal file
3
tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"extends": "./node_modules/astro/tsconfigs/strictest.json"
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user