mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 11:24:35 +00:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d12b900ad | ||
|
|
ae5aa02733 | ||
|
|
28a6a36bb7 | ||
|
|
4e7579dc10 | ||
|
|
b81d742c6c | ||
|
|
a61adbcac2 | ||
|
|
12000f4fc7 | ||
| 73792fb574 | |||
|
|
c08cfcbc38 | ||
|
|
8d38d5ac64 | ||
| e08bbcc543 | |||
|
|
eef3cb270d | ||
|
|
9cfbca23f8 | ||
|
|
aef411a0ea | ||
|
|
806ea4cb5c | ||
|
|
7205072358 | ||
|
|
32d372b42f | ||
|
|
e059bee7dc | ||
|
|
6f56aafab1 | ||
|
|
8734489cf0 | ||
|
|
7e6635f40f | ||
|
|
c0022a22f4 | ||
|
|
3fa2a7e2e3 | ||
| 8a617a73ae | |||
|
|
e7babb9f55 | ||
|
|
5ab35b02c4 | ||
|
|
ad82ee7106 | ||
|
|
d2e9456d81 | ||
|
|
e6d1989847 | ||
|
|
7a932383b4 | ||
|
|
576e18347e | ||
|
|
61815f8ae1 | ||
|
|
afff27fd21 | ||
|
|
a8ba378fd1 | ||
|
|
73c81a45dc | ||
|
|
12d424acce | ||
|
|
414fb19de3 | ||
|
|
cfddf1fb0c | ||
|
|
1f483b1afc | ||
|
|
0470239ef1 | ||
|
|
2c259fe1de | ||
|
|
b066734398 | ||
|
|
3b698fce5f | ||
|
|
5ad6ee5e0f | ||
|
|
7d11cc7916 |
105
CHANGELOG.md
105
CHANGELOG.md
@@ -1,3 +1,108 @@
|
|||||||
|
# [0.5.0](https://github.com/sasjs/server/compare/v0.4.2...v0.5.0) (2022-06-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* npm audit fix to avoid warnings on npm i ([28a6a36](https://github.com/sasjs/server/commit/28a6a36bb708b93fb5c2b74d587e9b2e055582be))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **api:** deployment through zipped/compressed file ([b81d742](https://github.com/sasjs/server/commit/b81d742c6c70d4cf1cab365b0e3efc087441db00))
|
||||||
|
|
||||||
|
## [0.4.2](https://github.com/sasjs/server/compare/v0.4.1...v0.4.2) (2022-06-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* appStream redesign ([73792fb](https://github.com/sasjs/server/commit/73792fb574c90bd280c4324e0b41c6fee7d572b6))
|
||||||
|
|
||||||
|
## [0.4.1](https://github.com/sasjs/server/compare/v0.4.0...v0.4.1) (2022-06-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add/remove group to User when adding/removing user from group and return group membership on getting user ([e08bbcc](https://github.com/sasjs/server/commit/e08bbcc5435cbabaee40a41a7fb667d4a1f078e6))
|
||||||
|
|
||||||
|
# [0.4.0](https://github.com/sasjs/server/compare/v0.3.10...v0.4.0) (2022-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* new APIs added for GET|PATCH|DELETE of user by username ([aef411a](https://github.com/sasjs/server/commit/aef411a0eac625c33274dfe3e88b6f75115c44d8))
|
||||||
|
|
||||||
|
## [0.3.10](https://github.com/sasjs/server/compare/v0.3.9...v0.3.10) (2022-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* correct syntax for encoding option ([32d372b](https://github.com/sasjs/server/commit/32d372b42fbf56b6c0779e8f704164eaae1c7548))
|
||||||
|
|
||||||
|
## [0.3.9](https://github.com/sasjs/server/compare/v0.3.8...v0.3.9) (2022-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* forcing utf 8 encoding. Closes [#76](https://github.com/sasjs/server/issues/76) ([8734489](https://github.com/sasjs/server/commit/8734489cf014aedaca3f325e689493e4fe0b71ca))
|
||||||
|
|
||||||
|
## [0.3.8](https://github.com/sasjs/server/compare/v0.3.7...v0.3.8) (2022-06-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* execution controller better error handling ([8a617a7](https://github.com/sasjs/server/commit/8a617a73ae63233332f5788c90f173d6cd5e1283))
|
||||||
|
* execution controller error details ([3fa2a7e](https://github.com/sasjs/server/commit/3fa2a7e2e32f90050f6b09e30ce3ef725eb0b15f))
|
||||||
|
|
||||||
|
## [0.3.7](https://github.com/sasjs/server/compare/v0.3.6...v0.3.7) (2022-06-08)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **appstream:** redirect to relative + nested resource should be accessed ([5ab35b0](https://github.com/sasjs/server/commit/5ab35b02c4417132dddb5a800982f31d0d50ef66))
|
||||||
|
|
||||||
|
## [0.3.6](https://github.com/sasjs/server/compare/v0.3.5...v0.3.6) (2022-06-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **appstream:** should serve only new files for same app stream name with new deployment ([e6d1989](https://github.com/sasjs/server/commit/e6d1989847761fbe562d7861ffa0ee542839b125))
|
||||||
|
|
||||||
|
## [0.3.5](https://github.com/sasjs/server/compare/v0.3.4...v0.3.5) (2022-05-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* bumping sasjs/core library ([61815f8](https://github.com/sasjs/server/commit/61815f8ae18be132e17c199cd8e3afbcc2fa0b60))
|
||||||
|
|
||||||
|
## [0.3.4](https://github.com/sasjs/server/compare/v0.3.3...v0.3.4) (2022-05-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **web:** system username for DESKTOP mode ([a8ba378](https://github.com/sasjs/server/commit/a8ba378fd1ff374ba025a96fdfae5c6c36954465))
|
||||||
|
|
||||||
|
## [0.3.3](https://github.com/sasjs/server/compare/v0.3.2...v0.3.3) (2022-05-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* usage of autoexec API in DESKTOP mode ([12d424a](https://github.com/sasjs/server/commit/12d424acce8108a6f53aefbac01fddcdc5efb48f))
|
||||||
|
|
||||||
|
## [0.3.2](https://github.com/sasjs/server/compare/v0.3.1...v0.3.2) (2022-05-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **web:** ability to use get/patch User API in desktop mode. ([2c259fe](https://github.com/sasjs/server/commit/2c259fe1de95d84e6929e311aaa6b895e66b42a3))
|
||||||
|
|
||||||
|
## [0.3.1](https://github.com/sasjs/server/compare/v0.3.0...v0.3.1) (2022-05-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **api:** username should be lowercase ([5ad6ee5](https://github.com/sasjs/server/commit/5ad6ee5e0f5d7d6faa45b72215f1d9d55cfc37db))
|
||||||
|
* **web:** reduced width for autoexec input ([7d11cc7](https://github.com/sasjs/server/commit/7d11cc79161e5a07f6c5392d742ef6b9d8658071))
|
||||||
|
|
||||||
# [0.3.0](https://github.com/sasjs/server/compare/v0.2.0...v0.3.0) (2022-05-25)
|
# [0.3.0](https://github.com/sasjs/server/compare/v0.2.0...v0.3.0) (2022-05-25)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
466
api/package-lock.json
generated
466
api/package-lock.json
generated
@@ -8,7 +8,7 @@
|
|||||||
"name": "api",
|
"name": "api",
|
||||||
"version": "0.0.2",
|
"version": "0.0.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/core": "^4.23.1",
|
"@sasjs/core": "^4.27.3",
|
||||||
"@sasjs/utils": "2.42.1",
|
"@sasjs/utils": "2.42.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"connect-mongo": "^4.6.0",
|
"connect-mongo": "^4.6.0",
|
||||||
@@ -24,12 +24,15 @@
|
|||||||
"mongoose-sequence": "^5.3.1",
|
"mongoose-sequence": "^5.3.1",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.3",
|
"multer": "^1.4.3",
|
||||||
"swagger-ui-express": "4.3.0"
|
"swagger-ui-express": "4.3.0",
|
||||||
|
"unzipper": "^0.10.11",
|
||||||
|
"url": "^0.10.3"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"api": "build/src/server.js"
|
"api": "build/src/server.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/adm-zip": "^0.5.0",
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@@ -44,6 +47,8 @@
|
|||||||
"@types/node": "^15.12.2",
|
"@types/node": "^15.12.2",
|
||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.11",
|
||||||
"@types/swagger-ui-express": "^4.1.3",
|
"@types/swagger-ui-express": "^4.1.3",
|
||||||
|
"@types/unzipper": "^0.10.5",
|
||||||
|
"adm-zip": "^0.5.9",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"http-headers-validation": "^0.0.1",
|
"http-headers-validation": "^0.0.1",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
@@ -1385,9 +1390,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/core": {
|
"node_modules/@sasjs/core": {
|
||||||
"version": "4.23.1",
|
"version": "4.27.3",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.23.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.27.3.tgz",
|
||||||
"integrity": "sha512-9d6yEPJRRvPLMUkpyaiQ62SXNMMyt2l815jxWgFjnVOxKeUQv9TPyZqZ0FpmWdVe6EY8dv8GLlyaBpOLDnY6Vg=="
|
"integrity": "sha512-8AaPPRGMwhmjw244CDSnTqHXdp/77ZBjIJMgwqw4wTrCf8Vzs2Y5hVihbvAniIGQctZHLMR6X5a3X4ccn9gRjg=="
|
||||||
},
|
},
|
||||||
"node_modules/@sasjs/utils": {
|
"node_modules/@sasjs/utils": {
|
||||||
"version": "2.42.1",
|
"version": "2.42.1",
|
||||||
@@ -1752,6 +1757,15 @@
|
|||||||
"yarn": ">=1.9.4"
|
"yarn": ">=1.9.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/adm-zip": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.1.15",
|
"version": "7.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
||||||
@@ -2175,6 +2189,15 @@
|
|||||||
"integrity": "sha512-MhSa0yylXtVMsyT8qFpHA1DLHj4DvQGH5ntxrhHSh8PxUVNi35Wk+P5hVgqbO2qZqOotqr9jaoPRL+iRjWYm/A==",
|
"integrity": "sha512-MhSa0yylXtVMsyT8qFpHA1DLHj4DvQGH5ntxrhHSh8PxUVNi35Wk+P5hVgqbO2qZqOotqr9jaoPRL+iRjWYm/A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/unzipper": {
|
||||||
|
"version": "0.10.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unzipper/-/unzipper-0.10.5.tgz",
|
||||||
|
"integrity": "sha512-NrLJb29AdnBARpg9S/4ktfPEisbJ0AvaaAr3j7Q1tg8AgcEUsq2HqbNzvgLRoWyRtjzeLEv7vuL39u1mrNIyNA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/webidl-conversions": {
|
"node_modules/@types/webidl-conversions": {
|
||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
|
||||||
@@ -2271,6 +2294,15 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/adm-zip": {
|
||||||
|
"version": "0.5.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
|
||||||
|
"integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/agent-base": {
|
"node_modules/agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
@@ -2683,6 +2715,26 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||||
"integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
|
"integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
|
||||||
},
|
},
|
||||||
|
"node_modules/big-integer": {
|
||||||
|
"version": "1.6.51",
|
||||||
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
|
||||||
|
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/binary": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
|
||||||
|
"dependencies": {
|
||||||
|
"buffers": "~0.1.1",
|
||||||
|
"chainsaw": "~0.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"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",
|
||||||
@@ -2709,6 +2761,11 @@
|
|||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/bluebird": {
|
||||||
|
"version": "3.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
|
||||||
|
"integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="
|
||||||
|
},
|
||||||
"node_modules/bn.js": {
|
"node_modules/bn.js": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||||
@@ -2880,10 +2937,26 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-indexof-polyfill": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/buffers": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/busboy": {
|
"node_modules/busboy": {
|
||||||
"version": "0.2.14",
|
"version": "0.2.14",
|
||||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
||||||
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
|
"integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"dicer": "0.2.5",
|
"dicer": "0.2.5",
|
||||||
"readable-stream": "1.1.x"
|
"readable-stream": "1.1.x"
|
||||||
@@ -3010,6 +3083,17 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/chainsaw": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"traverse": ">=0.3.0 <0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
@@ -3677,7 +3761,7 @@
|
|||||||
"node_modules/dicer": {
|
"node_modules/dicer": {
|
||||||
"version": "0.2.5",
|
"version": "0.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
||||||
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
|
"integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readable-stream": "1.1.x",
|
"readable-stream": "1.1.x",
|
||||||
"streamsearch": "0.1.2"
|
"streamsearch": "0.1.2"
|
||||||
@@ -3779,6 +3863,36 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/duplexer2": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": "^2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/duplexer2/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/duplexer2/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/duplexer3": {
|
"node_modules/duplexer3": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||||
@@ -4449,6 +4563,42 @@
|
|||||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fstream": {
|
||||||
|
"version": "1.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
|
||||||
|
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
|
||||||
|
"dependencies": {
|
||||||
|
"graceful-fs": "^4.1.2",
|
||||||
|
"inherits": "~2.0.0",
|
||||||
|
"mkdirp": ">=0.5 0",
|
||||||
|
"rimraf": "2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fstream/node_modules/mkdirp": {
|
||||||
|
"version": "0.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
|
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"minimist": "^1.2.6"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fstream/node_modules/rimraf": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
@@ -7063,6 +7213,11 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/listenercount": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ=="
|
||||||
|
},
|
||||||
"node_modules/locate-path": {
|
"node_modules/locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@@ -7590,9 +7745,10 @@
|
|||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
"node_modules/multer": {
|
"node_modules/multer": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
|
||||||
"integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==",
|
"integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==",
|
||||||
|
"deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"append-field": "^1.0.0",
|
"append-field": "^1.0.0",
|
||||||
"busboy": "^0.2.11",
|
"busboy": "^0.2.11",
|
||||||
@@ -8552,6 +8708,15 @@
|
|||||||
"node": ">=0.6"
|
"node": ">=0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/querystring": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
|
||||||
|
"deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.x"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/queue-microtask": {
|
"node_modules/queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
@@ -8899,6 +9064,11 @@
|
|||||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||||
|
},
|
||||||
"node_modules/setprototypeof": {
|
"node_modules/setprototypeof": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
||||||
@@ -9637,6 +9807,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/traverse": {
|
||||||
|
"version": "0.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
|
||||||
|
"integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/traverse-chain": {
|
"node_modules/traverse-chain": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
||||||
@@ -9915,6 +10093,45 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/unzipper": {
|
||||||
|
"version": "0.10.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
|
||||||
|
"integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"big-integer": "^1.6.17",
|
||||||
|
"binary": "~0.3.0",
|
||||||
|
"bluebird": "~3.4.1",
|
||||||
|
"buffer-indexof-polyfill": "~1.0.0",
|
||||||
|
"duplexer2": "~0.1.4",
|
||||||
|
"fstream": "^1.0.12",
|
||||||
|
"graceful-fs": "^4.2.2",
|
||||||
|
"listenercount": "~1.0.1",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "~1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unzipper/node_modules/readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"dependencies": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unzipper/node_modules/string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/update-notifier": {
|
"node_modules/update-notifier": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz",
|
||||||
@@ -9942,6 +10159,15 @@
|
|||||||
"url": "https://github.com/yeoman/update-notifier?sponsor=1"
|
"url": "https://github.com/yeoman/update-notifier?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/url": {
|
||||||
|
"version": "0.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
|
||||||
|
"integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": "1.3.2",
|
||||||
|
"querystring": "0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/url-parse-lax": {
|
"node_modules/url-parse-lax": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||||
@@ -9954,6 +10180,11 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/url/node_modules/punycode": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||||
|
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
|
||||||
|
},
|
||||||
"node_modules/util-deprecate": {
|
"node_modules/util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
@@ -11364,9 +11595,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sasjs/core": {
|
"@sasjs/core": {
|
||||||
"version": "4.23.1",
|
"version": "4.27.3",
|
||||||
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.23.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.27.3.tgz",
|
||||||
"integrity": "sha512-9d6yEPJRRvPLMUkpyaiQ62SXNMMyt2l815jxWgFjnVOxKeUQv9TPyZqZ0FpmWdVe6EY8dv8GLlyaBpOLDnY6Vg=="
|
"integrity": "sha512-8AaPPRGMwhmjw244CDSnTqHXdp/77ZBjIJMgwqw4wTrCf8Vzs2Y5hVihbvAniIGQctZHLMR6X5a3X4ccn9gRjg=="
|
||||||
},
|
},
|
||||||
"@sasjs/utils": {
|
"@sasjs/utils": {
|
||||||
"version": "2.42.1",
|
"version": "2.42.1",
|
||||||
@@ -11675,6 +11906,15 @@
|
|||||||
"validator": "^13.6.0"
|
"validator": "^13.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/adm-zip": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz",
|
||||||
|
"integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/babel__core": {
|
"@types/babel__core": {
|
||||||
"version": "7.1.15",
|
"version": "7.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz",
|
||||||
@@ -12072,6 +12312,15 @@
|
|||||||
"integrity": "sha512-MhSa0yylXtVMsyT8qFpHA1DLHj4DvQGH5ntxrhHSh8PxUVNi35Wk+P5hVgqbO2qZqOotqr9jaoPRL+iRjWYm/A==",
|
"integrity": "sha512-MhSa0yylXtVMsyT8qFpHA1DLHj4DvQGH5ntxrhHSh8PxUVNi35Wk+P5hVgqbO2qZqOotqr9jaoPRL+iRjWYm/A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/unzipper": {
|
||||||
|
"version": "0.10.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unzipper/-/unzipper-0.10.5.tgz",
|
||||||
|
"integrity": "sha512-NrLJb29AdnBARpg9S/4ktfPEisbJ0AvaaAr3j7Q1tg8AgcEUsq2HqbNzvgLRoWyRtjzeLEv7vuL39u1mrNIyNA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/webidl-conversions": {
|
"@types/webidl-conversions": {
|
||||||
"version": "6.1.1",
|
"version": "6.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
|
||||||
@@ -12152,6 +12401,12 @@
|
|||||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"adm-zip": {
|
||||||
|
"version": "0.5.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
|
||||||
|
"integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"agent-base": {
|
"agent-base": {
|
||||||
"version": "6.0.2",
|
"version": "6.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||||
@@ -12475,6 +12730,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||||
"integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
|
"integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
|
||||||
},
|
},
|
||||||
|
"big-integer": {
|
||||||
|
"version": "1.6.51",
|
||||||
|
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
|
||||||
|
"integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg=="
|
||||||
|
},
|
||||||
|
"binary": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
|
||||||
|
"integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==",
|
||||||
|
"requires": {
|
||||||
|
"buffers": "~0.1.1",
|
||||||
|
"chainsaw": "~0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"binary-extensions": {
|
"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",
|
||||||
@@ -12500,6 +12769,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"bluebird": {
|
||||||
|
"version": "3.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
|
||||||
|
"integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="
|
||||||
|
},
|
||||||
"bn.js": {
|
"bn.js": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
|
||||||
@@ -12626,10 +12900,20 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||||
},
|
},
|
||||||
|
"buffer-indexof-polyfill": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A=="
|
||||||
|
},
|
||||||
|
"buffers": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
|
||||||
|
"integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ=="
|
||||||
|
},
|
||||||
"busboy": {
|
"busboy": {
|
||||||
"version": "0.2.14",
|
"version": "0.2.14",
|
||||||
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
|
||||||
"integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
|
"integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"dicer": "0.2.5",
|
"dicer": "0.2.5",
|
||||||
"readable-stream": "1.1.x"
|
"readable-stream": "1.1.x"
|
||||||
@@ -12723,6 +13007,14 @@
|
|||||||
"integrity": "sha512-jUNz+a9blQTQVu4uFcn17uAD8IDizPzQkIKh3LCJfg9BkyIqExYYdyc/ZSlWUSKb8iYiXxKsxbv4zYSvkqjrxw==",
|
"integrity": "sha512-jUNz+a9blQTQVu4uFcn17uAD8IDizPzQkIKh3LCJfg9BkyIqExYYdyc/ZSlWUSKb8iYiXxKsxbv4zYSvkqjrxw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"chainsaw": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==",
|
||||||
|
"requires": {
|
||||||
|
"traverse": ">=0.3.0 <0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||||
@@ -13267,7 +13559,7 @@
|
|||||||
"dicer": {
|
"dicer": {
|
||||||
"version": "0.2.5",
|
"version": "0.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
|
||||||
"integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
|
"integrity": "sha512-FDvbtnq7dzlPz0wyYlOExifDEZcu8h+rErEXgfxqmLfRfC/kJidEFh4+effJRO3P0xmfqyPbSMG0LveNRfTKVg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"readable-stream": "1.1.x",
|
"readable-stream": "1.1.x",
|
||||||
"streamsearch": "0.1.2"
|
"streamsearch": "0.1.2"
|
||||||
@@ -13349,6 +13641,38 @@
|
|||||||
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
|
"integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"duplexer2": {
|
||||||
|
"version": "0.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
|
||||||
|
"integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==",
|
||||||
|
"requires": {
|
||||||
|
"readable-stream": "^2.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"duplexer3": {
|
"duplexer3": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||||
@@ -13871,6 +14195,35 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"fstream": {
|
||||||
|
"version": "1.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
|
||||||
|
"integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
|
||||||
|
"requires": {
|
||||||
|
"graceful-fs": "^4.1.2",
|
||||||
|
"inherits": "~2.0.0",
|
||||||
|
"mkdirp": ">=0.5 0",
|
||||||
|
"rimraf": "2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "0.5.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
|
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||||
|
"requires": {
|
||||||
|
"minimist": "^1.2.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rimraf": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"function-bind": {
|
"function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||||
@@ -15814,6 +16167,11 @@
|
|||||||
"type-check": "~0.3.2"
|
"type-check": "~0.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"listenercount": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ=="
|
||||||
|
},
|
||||||
"locate-path": {
|
"locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||||
@@ -16220,9 +16578,9 @@
|
|||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
"multer": {
|
"multer": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
|
||||||
"integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==",
|
"integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"append-field": "^1.0.0",
|
"append-field": "^1.0.0",
|
||||||
"busboy": "^0.2.11",
|
"busboy": "^0.2.11",
|
||||||
@@ -16933,6 +17291,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||||
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
|
||||||
},
|
},
|
||||||
|
"querystring": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||||
|
},
|
||||||
"queue-microtask": {
|
"queue-microtask": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||||
@@ -17189,6 +17552,11 @@
|
|||||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"setimmediate": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
|
||||||
|
},
|
||||||
"setprototypeof": {
|
"setprototypeof": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
||||||
@@ -17755,6 +18123,11 @@
|
|||||||
"punycode": "^2.1.1"
|
"punycode": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"traverse": {
|
||||||
|
"version": "0.3.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
|
||||||
|
"integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ=="
|
||||||
|
},
|
||||||
"traverse-chain": {
|
"traverse-chain": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz",
|
||||||
@@ -17942,6 +18315,47 @@
|
|||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
},
|
},
|
||||||
|
"unzipper": {
|
||||||
|
"version": "0.10.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
|
||||||
|
"integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
|
||||||
|
"requires": {
|
||||||
|
"big-integer": "^1.6.17",
|
||||||
|
"binary": "~0.3.0",
|
||||||
|
"bluebird": "~3.4.1",
|
||||||
|
"buffer-indexof-polyfill": "~1.0.0",
|
||||||
|
"duplexer2": "~0.1.4",
|
||||||
|
"fstream": "^1.0.12",
|
||||||
|
"graceful-fs": "^4.2.2",
|
||||||
|
"listenercount": "~1.0.1",
|
||||||
|
"readable-stream": "~2.3.6",
|
||||||
|
"setimmediate": "~1.0.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"update-notifier": {
|
"update-notifier": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz",
|
||||||
@@ -17963,6 +18377,22 @@
|
|||||||
"xdg-basedir": "^4.0.0"
|
"xdg-basedir": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"url": {
|
||||||
|
"version": "0.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
|
||||||
|
"integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
|
||||||
|
"requires": {
|
||||||
|
"punycode": "1.3.2",
|
||||||
|
"querystring": "0.2.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"punycode": {
|
||||||
|
"version": "1.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||||
|
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"url-parse-lax": {
|
"url-parse-lax": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
},
|
},
|
||||||
"author": "4GL Ltd",
|
"author": "4GL Ltd",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sasjs/core": "^4.23.1",
|
"@sasjs/core": "^4.27.3",
|
||||||
"@sasjs/utils": "2.42.1",
|
"@sasjs/utils": "2.42.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"connect-mongo": "^4.6.0",
|
"connect-mongo": "^4.6.0",
|
||||||
@@ -63,9 +63,12 @@
|
|||||||
"mongoose-sequence": "^5.3.1",
|
"mongoose-sequence": "^5.3.1",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.3",
|
"multer": "^1.4.3",
|
||||||
"swagger-ui-express": "4.3.0"
|
"swagger-ui-express": "4.3.0",
|
||||||
|
"unzipper": "^0.10.11",
|
||||||
|
"url": "^0.10.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/adm-zip": "^0.5.0",
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
"@types/cookie-parser": "^1.4.2",
|
"@types/cookie-parser": "^1.4.2",
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.12",
|
||||||
@@ -80,6 +83,8 @@
|
|||||||
"@types/node": "^15.12.2",
|
"@types/node": "^15.12.2",
|
||||||
"@types/supertest": "^2.0.11",
|
"@types/supertest": "^2.0.11",
|
||||||
"@types/swagger-ui-express": "^4.1.3",
|
"@types/swagger-ui-express": "^4.1.3",
|
||||||
|
"@types/unzipper": "^0.10.5",
|
||||||
|
"adm-zip": "^0.5.9",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"http-headers-validation": "^0.0.1",
|
"http-headers-validation": "^0.0.1",
|
||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
@@ -96,7 +101,7 @@
|
|||||||
},
|
},
|
||||||
"nodemonConfig": {
|
"nodemonConfig": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"tmp/**/*"
|
"sasjs_root/**/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,6 +310,21 @@ components:
|
|||||||
- displayName
|
- displayName
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
GroupResponse:
|
||||||
|
properties:
|
||||||
|
groupId:
|
||||||
|
type: number
|
||||||
|
format: double
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- groupId
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
UserDetailsResponse:
|
UserDetailsResponse:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
@@ -325,6 +340,10 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
autoExec:
|
autoExec:
|
||||||
type: string
|
type: string
|
||||||
|
groups:
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/GroupResponse'
|
||||||
|
type: array
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- displayName
|
- displayName
|
||||||
@@ -364,21 +383,6 @@ components:
|
|||||||
- password
|
- password
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
GroupResponse:
|
|
||||||
properties:
|
|
||||||
groupId:
|
|
||||||
type: number
|
|
||||||
format: double
|
|
||||||
name:
|
|
||||||
type: string
|
|
||||||
description:
|
|
||||||
type: string
|
|
||||||
required:
|
|
||||||
- groupId
|
|
||||||
- name
|
|
||||||
- description
|
|
||||||
type: object
|
|
||||||
additionalProperties: false
|
|
||||||
GroupDetailsResponse:
|
GroupDetailsResponse:
|
||||||
properties:
|
properties:
|
||||||
groupId:
|
groupId:
|
||||||
@@ -723,7 +727,8 @@ paths:
|
|||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {status: failure, message: 'Deployment failed!'}
|
value: {status: failure, message: 'Deployment failed!'}
|
||||||
summary: 'Creates/updates files within SASjs Drive using uploaded JSON file.'
|
description: "Accepts JSON file and zipped compressed JSON file as well.\nCompressed file should only contain one JSON file and should have same name\nas of compressed file e.g. deploy.JSON should be compressed to deploy.JSON.zip\nAny other file or JSON file in zipped will be ignored!"
|
||||||
|
summary: 'Creates/updates files within SASjs Drive using uploaded JSON/compressed JSON file.'
|
||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
@@ -985,6 +990,94 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/UserPayload'
|
$ref: '#/components/schemas/UserPayload'
|
||||||
|
'/SASjsApi/user/by/username/{username}':
|
||||||
|
get:
|
||||||
|
operationId: GetUserByUsername
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
|
description: 'Only Admin or user itself will get user autoExec code.'
|
||||||
|
summary: 'Get user properties - such as group memberships, userName, displayName.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The User''s username'
|
||||||
|
in: path
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: johnSnow01
|
||||||
|
patch:
|
||||||
|
operationId: UpdateUserByUsername
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
|
examples:
|
||||||
|
'Example 1':
|
||||||
|
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
|
||||||
|
summary: 'Update user properties - such as displayName. Can be performed either by admins, or the user in question.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The User''s username'
|
||||||
|
in: path
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: johnSnow01
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/UserPayload'
|
||||||
|
delete:
|
||||||
|
operationId: DeleteUserByUsername
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: 'No content'
|
||||||
|
summary: 'Delete a user. Can be performed either by admins, or the user in question.'
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
security:
|
||||||
|
-
|
||||||
|
bearerAuth: []
|
||||||
|
parameters:
|
||||||
|
-
|
||||||
|
description: 'The User''s username'
|
||||||
|
in: path
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: johnSnow01
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
'/SASjsApi/user/{userId}':
|
'/SASjsApi/user/{userId}':
|
||||||
get:
|
get:
|
||||||
operationId: GetUser
|
operationId: GetUser
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import { Request, Security, Route, Tags, Post, Body } from 'tsoa'
|
|||||||
import { ExecuteReturnJson, ExecutionController } from './internal'
|
import { ExecuteReturnJson, ExecutionController } from './internal'
|
||||||
import { ExecuteReturnJsonResponse } from '.'
|
import { ExecuteReturnJsonResponse } from '.'
|
||||||
import {
|
import {
|
||||||
getDesktopUserAutoExecPath,
|
|
||||||
getPreProgramVariables,
|
getPreProgramVariables,
|
||||||
|
getUserAutoExec,
|
||||||
ModeType,
|
ModeType,
|
||||||
parseLogToArray
|
parseLogToArray
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
import { readFile } from '@sasjs/utils'
|
|
||||||
|
|
||||||
interface ExecuteSASCodePayload {
|
interface ExecuteSASCodePayload {
|
||||||
/**
|
/**
|
||||||
@@ -43,7 +42,7 @@ const executeSASCode = async (
|
|||||||
const userAutoExec =
|
const userAutoExec =
|
||||||
process.env.MODE === ModeType.Server
|
process.env.MODE === ModeType.Server
|
||||||
? user?.autoExec
|
? user?.autoExec
|
||||||
: await readFile(getDesktopUserAutoExecPath())
|
: await getUserAutoExec()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { webout, log, httpHeaders } =
|
const { webout, log, httpHeaders } =
|
||||||
|
|||||||
@@ -96,7 +96,12 @@ export class DriveController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Creates/updates files within SASjs Drive using uploaded JSON file.
|
* Accepts JSON file and zipped compressed JSON file as well.
|
||||||
|
* Compressed file should only contain one JSON file and should have same name
|
||||||
|
* as of compressed file e.g. deploy.JSON should be compressed to deploy.JSON.zip
|
||||||
|
* Any other file or JSON file in zipped will be ignored!
|
||||||
|
*
|
||||||
|
* @summary Creates/updates files within SASjs Drive using uploaded JSON/compressed JSON file.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Example<DeployResponse>(successDeployResponse)
|
@Example<DeployResponse>(successDeployResponse)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import Group, { GroupPayload } from '../model/Group'
|
|||||||
import User from '../model/User'
|
import User from '../model/User'
|
||||||
import { UserResponse } from './user'
|
import { UserResponse } from './user'
|
||||||
|
|
||||||
interface GroupResponse {
|
export interface GroupResponse {
|
||||||
groupId: number
|
groupId: number
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
@@ -210,6 +210,9 @@ const updateUsersListInGroup = async (
|
|||||||
|
|
||||||
if (!updatedGroup) throw new Error('Unable to update group')
|
if (!updatedGroup) throw new Error('Unable to update group')
|
||||||
|
|
||||||
|
if (action === 'addUser') user.addGroup(group._id)
|
||||||
|
else user.removeGroup(group._id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
groupId: updatedGroup.groupId,
|
groupId: updatedGroup.groupId,
|
||||||
name: updatedGroup.name,
|
name: updatedGroup.name,
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export class ExecutionController {
|
|||||||
session?: Session
|
session?: Session
|
||||||
) {
|
) {
|
||||||
if (!(await fileExists(programPath)))
|
if (!(await fileExists(programPath)))
|
||||||
throw 'ExecutionController: SAS file does not exist.'
|
throw `The Stored Program at (${vars._program}) does not exist, or you do not have permission to view it.`
|
||||||
|
|
||||||
const program = await readFile(programPath)
|
const program = await readFile(programPath)
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,8 @@ ${autoExecContent}`
|
|||||||
session.path,
|
session.path,
|
||||||
'-AUTOEXEC',
|
'-AUTOEXEC',
|
||||||
autoExecPath,
|
autoExecPath,
|
||||||
|
'-ENCODING',
|
||||||
|
'UTF-8',
|
||||||
process.platform === 'win32' ? '-nosplash' : ''
|
process.platform === 'win32' ? '-nosplash' : ''
|
||||||
])
|
])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -14,8 +14,11 @@ import {
|
|||||||
Hidden,
|
Hidden,
|
||||||
Request
|
Request
|
||||||
} from 'tsoa'
|
} from 'tsoa'
|
||||||
|
import { desktopUser } from '../middlewares'
|
||||||
|
|
||||||
import User, { UserPayload } from '../model/User'
|
import User, { UserPayload } from '../model/User'
|
||||||
|
import { getUserAutoExec, updateUserAutoExec, ModeType } from '../utils'
|
||||||
|
import { GroupResponse } from './group'
|
||||||
|
|
||||||
export interface UserResponse {
|
export interface UserResponse {
|
||||||
id: number
|
id: number
|
||||||
@@ -30,6 +33,7 @@ interface UserDetailsResponse {
|
|||||||
isActive: boolean
|
isActive: boolean
|
||||||
isAdmin: boolean
|
isAdmin: boolean
|
||||||
autoExec?: string
|
autoExec?: string
|
||||||
|
groups?: GroupResponse[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Security('bearerAuth')
|
@Security('bearerAuth')
|
||||||
@@ -75,6 +79,26 @@ export class UserController {
|
|||||||
return createUser(body)
|
return createUser(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only Admin or user itself will get user autoExec code.
|
||||||
|
* @summary Get user properties - such as group memberships, userName, displayName.
|
||||||
|
* @param username The User's username
|
||||||
|
* @example username "johnSnow01"
|
||||||
|
*/
|
||||||
|
@Get('by/username/{username}')
|
||||||
|
public async getUserByUsername(
|
||||||
|
@Request() req: express.Request,
|
||||||
|
@Path() username: string
|
||||||
|
): Promise<UserDetailsResponse> {
|
||||||
|
const { MODE } = process.env
|
||||||
|
|
||||||
|
if (MODE === ModeType.Desktop) return getDesktopAutoExec()
|
||||||
|
|
||||||
|
const { user } = req
|
||||||
|
const getAutoExec = user!.isAdmin || user!.username == username
|
||||||
|
return getUser({ username }, getAutoExec)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only Admin or user itself will get user autoExec code.
|
* Only Admin or user itself will get user autoExec code.
|
||||||
* @summary Get user properties - such as group memberships, userName, displayName.
|
* @summary Get user properties - such as group memberships, userName, displayName.
|
||||||
@@ -86,9 +110,38 @@ export class UserController {
|
|||||||
@Request() req: express.Request,
|
@Request() req: express.Request,
|
||||||
@Path() userId: number
|
@Path() userId: number
|
||||||
): Promise<UserDetailsResponse> {
|
): Promise<UserDetailsResponse> {
|
||||||
|
const { MODE } = process.env
|
||||||
|
|
||||||
|
if (MODE === ModeType.Desktop) return getDesktopAutoExec()
|
||||||
|
|
||||||
const { user } = req
|
const { user } = req
|
||||||
const getAutoExec = user!.isAdmin || user!.userId == userId
|
const getAutoExec = user!.isAdmin || user!.userId == userId
|
||||||
return getUser(userId, getAutoExec)
|
return getUser({ id: userId }, getAutoExec)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Update user properties - such as displayName. Can be performed either by admins, or the user in question.
|
||||||
|
* @param username The User's username
|
||||||
|
* @example username "johnSnow01"
|
||||||
|
*/
|
||||||
|
@Example<UserDetailsResponse>({
|
||||||
|
id: 1234,
|
||||||
|
displayName: 'John Snow',
|
||||||
|
username: 'johnSnow01',
|
||||||
|
isAdmin: false,
|
||||||
|
isActive: true
|
||||||
|
})
|
||||||
|
@Patch('by/username/{username}')
|
||||||
|
public async updateUserByUsername(
|
||||||
|
@Path() username: string,
|
||||||
|
@Body() body: UserPayload
|
||||||
|
): Promise<UserDetailsResponse> {
|
||||||
|
const { MODE } = process.env
|
||||||
|
|
||||||
|
if (MODE === ModeType.Desktop)
|
||||||
|
return updateDesktopAutoExec(body.autoExec ?? '')
|
||||||
|
|
||||||
|
return updateUser({ username }, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,7 +161,26 @@ export class UserController {
|
|||||||
@Path() userId: number,
|
@Path() userId: number,
|
||||||
@Body() body: UserPayload
|
@Body() body: UserPayload
|
||||||
): Promise<UserDetailsResponse> {
|
): Promise<UserDetailsResponse> {
|
||||||
return updateUser(userId, body)
|
const { MODE } = process.env
|
||||||
|
|
||||||
|
if (MODE === ModeType.Desktop)
|
||||||
|
return updateDesktopAutoExec(body.autoExec ?? '')
|
||||||
|
|
||||||
|
return updateUser({ id: userId }, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @summary Delete a user. Can be performed either by admins, or the user in question.
|
||||||
|
* @param username The User's username
|
||||||
|
* @example username "johnSnow01"
|
||||||
|
*/
|
||||||
|
@Delete('by/username/{username}')
|
||||||
|
public async deleteUserByUsername(
|
||||||
|
@Path() username: string,
|
||||||
|
@Body() body: { password?: string },
|
||||||
|
@Query() @Hidden() isAdmin: boolean = false
|
||||||
|
) {
|
||||||
|
return deleteUser({ username }, isAdmin, body)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,7 +194,7 @@ export class UserController {
|
|||||||
@Body() body: { password?: string },
|
@Body() body: { password?: string },
|
||||||
@Query() @Hidden() isAdmin: boolean = false
|
@Query() @Hidden() isAdmin: boolean = false
|
||||||
) {
|
) {
|
||||||
return deleteUser(userId, isAdmin, body)
|
return deleteUser({ id: userId }, isAdmin, body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +235,22 @@ const createUser = async (data: UserPayload): Promise<UserDetailsResponse> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GetUserBy {
|
||||||
|
id?: number
|
||||||
|
username?: string
|
||||||
|
}
|
||||||
|
|
||||||
const getUser = async (
|
const getUser = async (
|
||||||
id: number,
|
findBy: GetUserBy,
|
||||||
getAutoExec: boolean
|
getAutoExec: boolean
|
||||||
): Promise<UserDetailsResponse> => {
|
): Promise<UserDetailsResponse> => {
|
||||||
const user = await User.findOne({ id })
|
const user = (await User.findOne(
|
||||||
|
findBy,
|
||||||
|
`id displayName username isActive isAdmin autoExec -_id`
|
||||||
|
).populate(
|
||||||
|
'groups',
|
||||||
|
'groupId name description -_id'
|
||||||
|
)) as unknown as UserDetailsResponse
|
||||||
|
|
||||||
if (!user) throw new Error('User is not found.')
|
if (!user) throw new Error('User is not found.')
|
||||||
|
|
||||||
@@ -177,12 +260,21 @@ const getUser = async (
|
|||||||
username: user.username,
|
username: user.username,
|
||||||
isActive: user.isActive,
|
isActive: user.isActive,
|
||||||
isAdmin: user.isAdmin,
|
isAdmin: user.isAdmin,
|
||||||
autoExec: getAutoExec ? user.autoExec ?? '' : undefined
|
autoExec: getAutoExec ? user.autoExec ?? '' : undefined,
|
||||||
|
groups: user.groups
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDesktopAutoExec = async () => {
|
||||||
|
return {
|
||||||
|
...desktopUser,
|
||||||
|
id: desktopUser.userId,
|
||||||
|
autoExec: await getUserAutoExec()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateUser = async (
|
const updateUser = async (
|
||||||
id: number,
|
findBy: GetUserBy,
|
||||||
data: Partial<UserPayload>
|
data: Partial<UserPayload>
|
||||||
): Promise<UserDetailsResponse> => {
|
): Promise<UserDetailsResponse> => {
|
||||||
const { displayName, username, password, isAdmin, isActive, autoExec } = data
|
const { displayName, username, password, isAdmin, isActive, autoExec } = data
|
||||||
@@ -192,8 +284,13 @@ const updateUser = async (
|
|||||||
if (username) {
|
if (username) {
|
||||||
// Checking if user is already in the database
|
// Checking if user is already in the database
|
||||||
const usernameExist = await User.findOne({ username })
|
const usernameExist = await User.findOne({ username })
|
||||||
if (usernameExist && usernameExist.id != id)
|
if (usernameExist) {
|
||||||
throw new Error('Username already exists.')
|
if (
|
||||||
|
(findBy.id && usernameExist.id != findBy.id) ||
|
||||||
|
(findBy.username && usernameExist.username != findBy.username)
|
||||||
|
)
|
||||||
|
throw new Error('Username already exists.')
|
||||||
|
}
|
||||||
params.username = username
|
params.username = username
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,9 +299,10 @@ const updateUser = async (
|
|||||||
params.password = User.hashPassword(password)
|
params.password = User.hashPassword(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedUser = await User.findOneAndUpdate({ id }, params, { new: true })
|
const updatedUser = await User.findOneAndUpdate(findBy, params, { new: true })
|
||||||
|
|
||||||
if (!updatedUser) throw new Error(`Unable to find user with id: ${id}`)
|
if (!updatedUser)
|
||||||
|
throw new Error(`Unable to find user with ${findBy.id || findBy.username}`)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: updatedUser.id,
|
id: updatedUser.id,
|
||||||
@@ -216,12 +314,21 @@ const updateUser = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateDesktopAutoExec = async (autoExec: string) => {
|
||||||
|
await updateUserAutoExec(autoExec)
|
||||||
|
return {
|
||||||
|
...desktopUser,
|
||||||
|
id: desktopUser.userId,
|
||||||
|
autoExec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const deleteUser = async (
|
const deleteUser = async (
|
||||||
id: number,
|
findBy: GetUserBy,
|
||||||
isAdmin: boolean,
|
isAdmin: boolean,
|
||||||
{ password }: { password?: string }
|
{ password }: { password?: string }
|
||||||
) => {
|
) => {
|
||||||
const user = await User.findOne({ id })
|
const user = await User.findOne(findBy)
|
||||||
if (!user) throw new Error('User is not found.')
|
if (!user) throw new Error('User is not found.')
|
||||||
|
|
||||||
if (!isAdmin) {
|
if (!isAdmin) {
|
||||||
@@ -229,5 +336,5 @@ const deleteUser = async (
|
|||||||
if (!validPass) throw new Error('Invalid password.')
|
if (!validPass) throw new Error('Invalid password.')
|
||||||
}
|
}
|
||||||
|
|
||||||
await User.deleteOne({ id })
|
await User.deleteOne(findBy)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
import { RequestHandler, Request, Response, NextFunction } from 'express'
|
import { RequestHandler, Request, Response, NextFunction } from 'express'
|
||||||
import jwt from 'jsonwebtoken'
|
import jwt from 'jsonwebtoken'
|
||||||
import { csrfProtection } from '../app'
|
import { csrfProtection } from '../app'
|
||||||
import { fetchLatestAutoExec, verifyTokenInDB } from '../utils'
|
import { fetchLatestAutoExec, ModeType, verifyTokenInDB } from '../utils'
|
||||||
|
import { desktopUser } from './desktop'
|
||||||
|
|
||||||
export const authenticateAccessToken: RequestHandler = async (
|
export const authenticateAccessToken: RequestHandler = async (
|
||||||
req,
|
req,
|
||||||
res,
|
res,
|
||||||
next
|
next
|
||||||
) => {
|
) => {
|
||||||
|
const { MODE } = process.env
|
||||||
|
if (MODE === ModeType.Desktop) {
|
||||||
|
req.user = desktopUser
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
|
||||||
// if request is coming from web and has valid session
|
// if request is coming from web and has valid session
|
||||||
// we can validate the request and check for CSRF Token
|
// it can be validated.
|
||||||
if (req.session?.loggedIn) {
|
if (req.session?.loggedIn) {
|
||||||
if (req.session.user) {
|
if (req.session.user) {
|
||||||
const user = await fetchLatestAutoExec(req.session.user)
|
const user = await fetchLatestAutoExec(req.session.user)
|
||||||
|
|||||||
@@ -1,20 +1,37 @@
|
|||||||
import { RequestHandler } from 'express'
|
import { RequestHandler, Request } from 'express'
|
||||||
|
import { userInfo } from 'os'
|
||||||
|
import { RequestUser } from '../types'
|
||||||
|
import { ModeType } from '../utils'
|
||||||
|
|
||||||
|
const regexUser = /^\/SASjsApi\/user\/[0-9]*$/ // /SASjsApi/user/1
|
||||||
|
|
||||||
|
const allowedInDesktopMode: { [key: string]: RegExp[] } = {
|
||||||
|
GET: [regexUser],
|
||||||
|
PATCH: [regexUser]
|
||||||
|
}
|
||||||
|
|
||||||
|
const reqAllowedInDesktopMode = (request: Request): boolean => {
|
||||||
|
const { method, originalUrl: url } = request
|
||||||
|
|
||||||
|
return !!allowedInDesktopMode[method]?.find((urlRegex) => urlRegex.test(url))
|
||||||
|
}
|
||||||
|
|
||||||
export const desktopRestrict: RequestHandler = (req, res, next) => {
|
export const desktopRestrict: RequestHandler = (req, res, next) => {
|
||||||
const { MODE } = process.env
|
const { MODE } = process.env
|
||||||
if (MODE?.trim() !== 'server')
|
|
||||||
return res.status(403).send('Not Allowed while in Desktop Mode.')
|
if (MODE === ModeType.Desktop) {
|
||||||
|
if (!reqAllowedInDesktopMode(req))
|
||||||
|
return res.status(403).send('Not Allowed while in Desktop Mode.')
|
||||||
|
}
|
||||||
|
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
export const desktopUsername: RequestHandler = (req, res, next) => {
|
|
||||||
const { MODE } = process.env
|
|
||||||
if (MODE?.trim() !== 'server')
|
|
||||||
return res.status(200).send({
|
|
||||||
userId: 12345,
|
|
||||||
username: 'DESKTOPusername',
|
|
||||||
displayName: 'DESKTOP User'
|
|
||||||
})
|
|
||||||
|
|
||||||
next()
|
export const desktopUser: RequestUser = {
|
||||||
|
userId: 12345,
|
||||||
|
clientId: 'desktop_app',
|
||||||
|
username: userInfo().username,
|
||||||
|
displayName: userInfo().username,
|
||||||
|
isAdmin: true,
|
||||||
|
isActive: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,22 @@
|
|||||||
import { RequestHandler } from 'express'
|
import { RequestHandler } from 'express'
|
||||||
|
|
||||||
|
// This middleware checks if a non-admin user trying to
|
||||||
|
// access information of other user
|
||||||
export const verifyAdminIfNeeded: RequestHandler = (req, res, next) => {
|
export const verifyAdminIfNeeded: RequestHandler = (req, res, next) => {
|
||||||
const { user } = req
|
const { user } = req
|
||||||
const userId = parseInt(req.params.userId)
|
|
||||||
|
|
||||||
if (!user?.isAdmin && user?.userId !== userId) {
|
if (!user?.isAdmin) {
|
||||||
return res.status(401).send('Admin account required')
|
let adminAccountRequired: boolean = true
|
||||||
|
|
||||||
|
if (req.params.userId) {
|
||||||
|
adminAccountRequired = user?.userId !== parseInt(req.params.userId)
|
||||||
|
} else if (req.params.username) {
|
||||||
|
adminAccountRequired = user?.username !== req.params.username
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adminAccountRequired)
|
||||||
|
return res.status(401).send('Admin account required')
|
||||||
}
|
}
|
||||||
|
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ interface IUserDocument extends UserPayload, Document {
|
|||||||
|
|
||||||
interface IUser extends IUserDocument {
|
interface IUser extends IUserDocument {
|
||||||
comparePassword(password: string): boolean
|
comparePassword(password: string): boolean
|
||||||
|
addGroup(groupObjectId: Schema.Types.ObjectId): Promise<IUser>
|
||||||
|
removeGroup(groupObjectId: Schema.Types.ObjectId): Promise<IUser>
|
||||||
}
|
}
|
||||||
interface IUserModel extends Model<IUser> {
|
interface IUserModel extends Model<IUser> {
|
||||||
hashPassword(password: string): string
|
hashPassword(password: string): string
|
||||||
@@ -106,6 +108,28 @@ userSchema.method('comparePassword', function (password: string): boolean {
|
|||||||
if (bcrypt.compareSync(password, this.password)) return true
|
if (bcrypt.compareSync(password, this.password)) return true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
userSchema.method(
|
||||||
|
'addGroup',
|
||||||
|
async function (groupObjectId: Schema.Types.ObjectId) {
|
||||||
|
const groupIdIndex = this.groups.indexOf(groupObjectId)
|
||||||
|
if (groupIdIndex === -1) {
|
||||||
|
this.groups.push(groupObjectId)
|
||||||
|
}
|
||||||
|
this.markModified('groups')
|
||||||
|
return this.save()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
userSchema.method(
|
||||||
|
'removeGroup',
|
||||||
|
async function (groupObjectId: Schema.Types.ObjectId) {
|
||||||
|
const groupIdIndex = this.groups.indexOf(groupObjectId)
|
||||||
|
if (groupIdIndex > -1) {
|
||||||
|
this.groups.splice(groupIdIndex, 1)
|
||||||
|
}
|
||||||
|
this.markModified('groups')
|
||||||
|
return this.save()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
export const User: IUserModel = model<IUser, IUserModel>('User', userSchema)
|
export const User: IUserModel = model<IUser, IUserModel>('User', userSchema)
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,12 @@ import { multerSingle } from '../../middlewares/multer'
|
|||||||
import { DriveController } from '../../controllers/'
|
import { DriveController } from '../../controllers/'
|
||||||
import {
|
import {
|
||||||
deployValidation,
|
deployValidation,
|
||||||
|
extractJSONFromZip,
|
||||||
|
extractName,
|
||||||
fileBodyValidation,
|
fileBodyValidation,
|
||||||
fileParamValidation,
|
fileParamValidation,
|
||||||
folderParamValidation
|
folderParamValidation,
|
||||||
|
isZipFile
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
|
|
||||||
const controller = new DriveController()
|
const controller = new DriveController()
|
||||||
@@ -49,7 +52,24 @@ driveRouter.post(
|
|||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
if (!req.file) return res.status(400).send('"file" is not present.')
|
if (!req.file) return res.status(400).send('"file" is not present.')
|
||||||
|
|
||||||
const fileContent = await readFile(req.file.path)
|
let fileContent: string = ''
|
||||||
|
|
||||||
|
const { value: zipFile } = isZipFile(req.file)
|
||||||
|
if (zipFile) {
|
||||||
|
fileContent = await extractJSONFromZip(zipFile)
|
||||||
|
const fileInZip = extractName(zipFile.originalname)
|
||||||
|
|
||||||
|
if (!fileContent) {
|
||||||
|
deleteFile(req.file.path)
|
||||||
|
return res
|
||||||
|
.status(400)
|
||||||
|
.send(
|
||||||
|
`No content present in ${fileInZip} of compressed file ${zipFile.originalname}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileContent = await readFile(req.file.path)
|
||||||
|
}
|
||||||
|
|
||||||
let jsonContent
|
let jsonContent
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import swaggerUi from 'swagger-ui-express'
|
|||||||
import {
|
import {
|
||||||
authenticateAccessToken,
|
authenticateAccessToken,
|
||||||
desktopRestrict,
|
desktopRestrict,
|
||||||
desktopUsername,
|
|
||||||
verifyAdmin
|
verifyAdmin
|
||||||
} from '../../middlewares'
|
} from '../../middlewares'
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ import sessionRouter from './session'
|
|||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
router.use('/info', infoRouter)
|
router.use('/info', infoRouter)
|
||||||
router.use('/session', desktopUsername, authenticateAccessToken, sessionRouter)
|
router.use('/session', authenticateAccessToken, sessionRouter)
|
||||||
router.use('/auth', desktopRestrict, authRouter)
|
router.use('/auth', desktopRestrict, authRouter)
|
||||||
router.use(
|
router.use(
|
||||||
'/client',
|
'/client',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Express } from 'express'
|
|||||||
import mongoose, { Mongoose } from 'mongoose'
|
import mongoose, { Mongoose } from 'mongoose'
|
||||||
import { MongoMemoryServer } from 'mongodb-memory-server'
|
import { MongoMemoryServer } from 'mongodb-memory-server'
|
||||||
import request from 'supertest'
|
import request from 'supertest'
|
||||||
|
import AdmZip from 'adm-zip'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
folderExists,
|
folderExists,
|
||||||
@@ -72,11 +73,52 @@ describe('drive', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('deploy', () => {
|
describe('deploy', () => {
|
||||||
const shouldFailAssertion = async (payload: any) => {
|
const makeRequest = async (payload: any, type: string = 'payload') => {
|
||||||
const res = await request(app)
|
const requestUrl =
|
||||||
.post('/SASjsApi/drive/deploy')
|
type === 'payload'
|
||||||
.auth(accessToken, { type: 'bearer' })
|
? '/SASjsApi/drive/deploy'
|
||||||
.send({ appLoc: '/Public', fileTree: payload })
|
: '/SASjsApi/drive/deploy/upload'
|
||||||
|
|
||||||
|
if (type === 'payload') {
|
||||||
|
return await request(app)
|
||||||
|
.post(requestUrl)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send({ appLoc: '/Public', fileTree: payload })
|
||||||
|
}
|
||||||
|
if (type === 'file') {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/Public',
|
||||||
|
fileTree: payload
|
||||||
|
})
|
||||||
|
return await request(app)
|
||||||
|
.post(requestUrl)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', Buffer.from(deployContents), 'deploy.json')
|
||||||
|
} else {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/Public',
|
||||||
|
fileTree: payload
|
||||||
|
})
|
||||||
|
const zip = new AdmZip()
|
||||||
|
// add file directly
|
||||||
|
zip.addFile(
|
||||||
|
'deploy.json',
|
||||||
|
Buffer.from(deployContents, 'utf8'),
|
||||||
|
'entry comment goes here'
|
||||||
|
)
|
||||||
|
|
||||||
|
return await request(app)
|
||||||
|
.post(requestUrl)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', zip.toBuffer(), 'deploy.json.zip')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldFailAssertion = async (
|
||||||
|
payload: any,
|
||||||
|
type: string = 'payload'
|
||||||
|
) => {
|
||||||
|
const res = await makeRequest(payload, type)
|
||||||
|
|
||||||
expect(res.statusCode).toEqual(400)
|
expect(res.statusCode).toEqual(400)
|
||||||
|
|
||||||
@@ -176,6 +218,240 @@ describe('drive', () => {
|
|||||||
|
|
||||||
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('upload', () => {
|
||||||
|
it('should respond with payload example if valid JSON file was not provided', async () => {
|
||||||
|
await shouldFailAssertion(null, 'file')
|
||||||
|
await shouldFailAssertion(undefined, 'file')
|
||||||
|
await shouldFailAssertion('data', 'file')
|
||||||
|
await shouldFailAssertion({}, 'file')
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
title: 'test is cool'
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
membersWRONG: []
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: {}
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
nameWRONG: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'WRONG',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'extract',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'makedata1',
|
||||||
|
type: 'service',
|
||||||
|
codeWRONG: '%put Hello World!;'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'file'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully deploy if valid JSON file was provided', async () => {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/public',
|
||||||
|
fileTree: getTreeExample()
|
||||||
|
})
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASjsApi/drive/deploy/upload')
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', Buffer.from(deployContents), 'deploy.json')
|
||||||
|
|
||||||
|
expect(res.statusCode).toEqual(200)
|
||||||
|
expect(res.text).toEqual(
|
||||||
|
'{"status":"success","message":"Files deployed successfully to @sasjs/server."}'
|
||||||
|
)
|
||||||
|
await expect(folderExists(getFilesFolder())).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const testJobFolder = path.join(
|
||||||
|
getFilesFolder(),
|
||||||
|
'public',
|
||||||
|
'jobs',
|
||||||
|
'extract'
|
||||||
|
)
|
||||||
|
await expect(folderExists(testJobFolder)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const exampleService = getExampleService()
|
||||||
|
const testJobFile =
|
||||||
|
path.join(testJobFolder, exampleService.name) + '.sas'
|
||||||
|
|
||||||
|
await expect(fileExists(testJobFile)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
await expect(readFile(testJobFile)).resolves.toEqual(
|
||||||
|
exampleService.code
|
||||||
|
)
|
||||||
|
|
||||||
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('upload - zipped', () => {
|
||||||
|
it('should respond with payload example if valid Zipped file was not provided', async () => {
|
||||||
|
await shouldFailAssertion(null, 'zip')
|
||||||
|
await shouldFailAssertion(undefined, 'zip')
|
||||||
|
await shouldFailAssertion('data', 'zip')
|
||||||
|
await shouldFailAssertion({}, 'zip')
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
userId: 1,
|
||||||
|
title: 'test is cool'
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
membersWRONG: []
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: {}
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
nameWRONG: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'WRONG',
|
||||||
|
members: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
await shouldFailAssertion(
|
||||||
|
{
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'jobs',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'extract',
|
||||||
|
type: 'folder',
|
||||||
|
members: [
|
||||||
|
{
|
||||||
|
name: 'makedata1',
|
||||||
|
type: 'service',
|
||||||
|
codeWRONG: '%put Hello World!;'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
'zip'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should successfully deploy if valid Zipped file was provided', async () => {
|
||||||
|
const deployContents = JSON.stringify({
|
||||||
|
appLoc: '/public',
|
||||||
|
fileTree: getTreeExample()
|
||||||
|
})
|
||||||
|
|
||||||
|
const zip = new AdmZip()
|
||||||
|
// add file directly
|
||||||
|
zip.addFile(
|
||||||
|
'deploy.json',
|
||||||
|
Buffer.from(deployContents, 'utf8'),
|
||||||
|
'entry comment goes here'
|
||||||
|
)
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASjsApi/drive/deploy/upload')
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.attach('file', zip.toBuffer(), 'deploy.json.zip')
|
||||||
|
|
||||||
|
expect(res.statusCode).toEqual(200)
|
||||||
|
expect(res.text).toEqual(
|
||||||
|
'{"status":"success","message":"Files deployed successfully to @sasjs/server."}'
|
||||||
|
)
|
||||||
|
await expect(folderExists(getFilesFolder())).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const testJobFolder = path.join(
|
||||||
|
getFilesFolder(),
|
||||||
|
'public',
|
||||||
|
'jobs',
|
||||||
|
'extract'
|
||||||
|
)
|
||||||
|
await expect(folderExists(testJobFolder)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
const exampleService = getExampleService()
|
||||||
|
const testJobFile =
|
||||||
|
path.join(testJobFolder, exampleService.name) + '.sas'
|
||||||
|
|
||||||
|
await expect(fileExists(testJobFile)).resolves.toEqual(true)
|
||||||
|
|
||||||
|
await expect(readFile(testJobFile)).resolves.toEqual(
|
||||||
|
exampleService.code
|
||||||
|
)
|
||||||
|
|
||||||
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('folder', () => {
|
describe('folder', () => {
|
||||||
|
|||||||
@@ -3,20 +3,20 @@ import mongoose, { Mongoose } from 'mongoose'
|
|||||||
import { MongoMemoryServer } from 'mongodb-memory-server'
|
import { MongoMemoryServer } from 'mongodb-memory-server'
|
||||||
import request from 'supertest'
|
import request from 'supertest'
|
||||||
import appPromise from '../../../app'
|
import appPromise from '../../../app'
|
||||||
import { UserController } from '../../../controllers/'
|
import { UserController, GroupController } from '../../../controllers/'
|
||||||
import { generateAccessToken, saveTokensInDB } from '../../../utils'
|
import { generateAccessToken, saveTokensInDB } from '../../../utils'
|
||||||
|
|
||||||
const clientId = 'someclientID'
|
const clientId = 'someclientID'
|
||||||
const adminUser = {
|
const adminUser = {
|
||||||
displayName: 'Test Admin',
|
displayName: 'Test Admin',
|
||||||
username: 'testAdminUsername',
|
username: 'testadminusername',
|
||||||
password: '12345678',
|
password: '12345678',
|
||||||
isAdmin: true,
|
isAdmin: true,
|
||||||
isActive: true
|
isActive: true
|
||||||
}
|
}
|
||||||
const user = {
|
const user = {
|
||||||
displayName: 'Test User',
|
displayName: 'Test User',
|
||||||
username: 'testUsername',
|
username: 'testusername',
|
||||||
password: '87654321',
|
password: '87654321',
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -68,6 +68,20 @@ describe('user', () => {
|
|||||||
expect(res.body.autoExec).toEqual(user.autoExec)
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should respond with new user having username as lowercase', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.post('/SASjsApi/user')
|
||||||
|
.auth(adminAccessToken, { type: 'bearer' })
|
||||||
|
.send({ ...user, username: user.username.toUpperCase() })
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(user.displayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
})
|
||||||
|
|
||||||
it('should respond with Unauthorized if access token is not present', async () => {
|
it('should respond with Unauthorized if access token is not present', async () => {
|
||||||
const res = await request(app)
|
const res = await request(app)
|
||||||
.post('/SASjsApi/user')
|
.post('/SASjsApi/user')
|
||||||
@@ -244,7 +258,7 @@ describe('user', () => {
|
|||||||
const dbUser1 = await controller.createUser(user)
|
const dbUser1 = await controller.createUser(user)
|
||||||
const dbUser2 = await controller.createUser({
|
const dbUser2 = await controller.createUser({
|
||||||
...user,
|
...user,
|
||||||
username: 'randomUser'
|
username: 'randomuser'
|
||||||
})
|
})
|
||||||
|
|
||||||
const res = await request(app)
|
const res = await request(app)
|
||||||
@@ -256,6 +270,102 @@ describe('user', () => {
|
|||||||
expect(res.text).toEqual('Error: Username already exists.')
|
expect(res.text).toEqual('Error: Username already exists.')
|
||||||
expect(res.body).toEqual({})
|
expect(res.body).toEqual({})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('by username', () => {
|
||||||
|
it('should respond with updated user when admin user requests', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const newDisplayName = 'My new display Name'
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.patch(`/SASjsApi/user/by/username/${user.username}`)
|
||||||
|
.auth(adminAccessToken, { type: 'bearer' })
|
||||||
|
.send({ ...user, displayName: newDisplayName })
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(newDisplayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with updated user when user himself requests', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser.id)
|
||||||
|
const newDisplayName = 'My new display Name'
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.patch(`/SASjsApi/user/by/username/${user.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send({
|
||||||
|
displayName: newDisplayName,
|
||||||
|
username: user.username,
|
||||||
|
password: user.password
|
||||||
|
})
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(newDisplayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Bad Request, only admin can update isAdmin/isActive', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser.id)
|
||||||
|
const newDisplayName = 'My new display Name'
|
||||||
|
|
||||||
|
await request(app)
|
||||||
|
.patch(`/SASjsApi/user/by/username/${user.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send({ ...user, displayName: newDisplayName })
|
||||||
|
.expect(400)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Unauthorized if access token is not present', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.patch('/SASjsApi/user/by/username/1234')
|
||||||
|
.send(user)
|
||||||
|
.expect(401)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Unauthorized')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Unauthorized when access token is not of an admin account or himself', async () => {
|
||||||
|
const dbUser1 = await controller.createUser(user)
|
||||||
|
const dbUser2 = await controller.createUser({
|
||||||
|
...user,
|
||||||
|
username: 'randomUser'
|
||||||
|
})
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser2.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.patch(`/SASjsApi/user/${dbUser1.id}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send(user)
|
||||||
|
.expect(401)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Admin account required')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Forbidden if username is already present', async () => {
|
||||||
|
const dbUser1 = await controller.createUser(user)
|
||||||
|
const dbUser2 = await controller.createUser({
|
||||||
|
...user,
|
||||||
|
username: 'randomuser'
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.patch(`/SASjsApi/user/by/username/${dbUser1.username}`)
|
||||||
|
.auth(adminAccessToken, { type: 'bearer' })
|
||||||
|
.send({ username: dbUser2.username })
|
||||||
|
.expect(403)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Error: Username already exists.')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('delete', () => {
|
describe('delete', () => {
|
||||||
@@ -349,6 +459,89 @@ describe('user', () => {
|
|||||||
expect(res.text).toEqual('Error: Invalid password.')
|
expect(res.text).toEqual('Error: Invalid password.')
|
||||||
expect(res.body).toEqual({})
|
expect(res.body).toEqual({})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('by username', () => {
|
||||||
|
it('should respond with OK when admin user requests', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.delete(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(adminAccessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with OK when user himself requests', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.delete(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send({ password: user.password })
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Bad Request when user himself requests and password is missing', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.delete(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(400)
|
||||||
|
|
||||||
|
expect(res.text).toEqual(`"password" is required`)
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Unauthorized when access token is not present', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.delete('/SASjsApi/user/by/username/RandomUsername')
|
||||||
|
.send(user)
|
||||||
|
.expect(401)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Unauthorized')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Unauthorized when access token is not of an admin account or himself', async () => {
|
||||||
|
const dbUser1 = await controller.createUser(user)
|
||||||
|
const dbUser2 = await controller.createUser({
|
||||||
|
...user,
|
||||||
|
username: 'randomUser'
|
||||||
|
})
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser2.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.delete(`/SASjsApi/user/by/username/${dbUser1.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send(user)
|
||||||
|
.expect(401)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Admin account required')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Forbidden when user himself requests and password is incorrect', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const accessToken = await generateAndSaveToken(dbUser.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.delete(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send({ password: 'incorrectpassword' })
|
||||||
|
.expect(403)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Error: Invalid password.')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('get', () => {
|
describe('get', () => {
|
||||||
@@ -378,6 +571,7 @@ describe('user', () => {
|
|||||||
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
expect(res.body.isActive).toEqual(user.isActive)
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
expect(res.body.autoExec).toEqual(user.autoExec)
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
expect(res.body.groups).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with user autoExec when admin user requests', async () => {
|
it('should respond with user autoExec when admin user requests', async () => {
|
||||||
@@ -395,6 +589,7 @@ describe('user', () => {
|
|||||||
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
expect(res.body.isActive).toEqual(user.isActive)
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
expect(res.body.autoExec).toEqual(user.autoExec)
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
expect(res.body.groups).toEqual([])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with user when access token is not of an admin account', async () => {
|
it('should respond with user when access token is not of an admin account', async () => {
|
||||||
@@ -417,6 +612,34 @@ describe('user', () => {
|
|||||||
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
expect(res.body.isActive).toEqual(user.isActive)
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
expect(res.body.autoExec).toBeUndefined()
|
expect(res.body.autoExec).toBeUndefined()
|
||||||
|
expect(res.body.groups).toEqual([])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with user along with associated groups', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const userId = dbUser.id
|
||||||
|
const accessToken = await generateAndSaveToken(userId)
|
||||||
|
|
||||||
|
const group = {
|
||||||
|
name: 'DCGroup1',
|
||||||
|
description: 'DC group for testing purposes.'
|
||||||
|
}
|
||||||
|
const groupController = new GroupController()
|
||||||
|
const dbGroup = await groupController.createGroup(group)
|
||||||
|
await groupController.addUserToGroup(dbGroup.groupId, dbUser.id)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.get(`/SASjsApi/user/${userId}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(user.displayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
expect(res.body.groups.length).toBeGreaterThan(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should respond with Unauthorized if access token is not present', async () => {
|
it('should respond with Unauthorized if access token is not present', async () => {
|
||||||
@@ -441,6 +664,86 @@ describe('user', () => {
|
|||||||
expect(res.text).toEqual('Error: User is not found.')
|
expect(res.text).toEqual('Error: User is not found.')
|
||||||
expect(res.body).toEqual({})
|
expect(res.body).toEqual({})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('by username', () => {
|
||||||
|
it('should respond with user autoExec when same user requests', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
const userId = dbUser.id
|
||||||
|
const accessToken = await generateAndSaveToken(userId)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.get(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(user.displayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with user autoExec when admin user requests', async () => {
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.get(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(adminAccessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(user.displayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
expect(res.body.autoExec).toEqual(user.autoExec)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with user when access token is not of an admin account', async () => {
|
||||||
|
const accessToken = await generateSaveTokenAndCreateUser({
|
||||||
|
...user,
|
||||||
|
username: 'randomUser'
|
||||||
|
})
|
||||||
|
|
||||||
|
const dbUser = await controller.createUser(user)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.get(`/SASjsApi/user/by/username/${dbUser.username}`)
|
||||||
|
.auth(accessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(200)
|
||||||
|
|
||||||
|
expect(res.body.username).toEqual(user.username)
|
||||||
|
expect(res.body.displayName).toEqual(user.displayName)
|
||||||
|
expect(res.body.isAdmin).toEqual(user.isAdmin)
|
||||||
|
expect(res.body.isActive).toEqual(user.isActive)
|
||||||
|
expect(res.body.autoExec).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Unauthorized if access token is not present', async () => {
|
||||||
|
const res = await request(app)
|
||||||
|
.get('/SASjsApi/user/by/username/randomUsername')
|
||||||
|
.send()
|
||||||
|
.expect(401)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Unauthorized')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should respond with Forbidden if username is incorrect', async () => {
|
||||||
|
await controller.createUser(user)
|
||||||
|
|
||||||
|
const res = await request(app)
|
||||||
|
.get('/SASjsApi/user/by/username/randomUsername')
|
||||||
|
.auth(adminAccessToken, { type: 'bearer' })
|
||||||
|
.send()
|
||||||
|
.expect(403)
|
||||||
|
|
||||||
|
expect(res.text).toEqual('Error: User is not found.')
|
||||||
|
expect(res.body).toEqual({})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('getAll', () => {
|
describe('getAll', () => {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const clientSecret = 'someclientSecret'
|
|||||||
const user = {
|
const user = {
|
||||||
id: 1234,
|
id: 1234,
|
||||||
displayName: 'Test User',
|
displayName: 'Test User',
|
||||||
username: 'testUsername',
|
username: 'testusername',
|
||||||
password: '87654321',
|
password: '87654321',
|
||||||
isAdmin: false,
|
isAdmin: false,
|
||||||
isActive: true
|
isActive: true
|
||||||
@@ -77,6 +77,7 @@ describe('web', () => {
|
|||||||
|
|
||||||
expect(res.body.loggedIn).toBeTruthy()
|
expect(res.body.loggedIn).toBeTruthy()
|
||||||
expect(res.body.user).toEqual({
|
expect(res.body.user).toEqual({
|
||||||
|
id: expect.any(Number),
|
||||||
username: user.username,
|
username: user.username,
|
||||||
displayName: user.displayName
|
displayName: user.displayName
|
||||||
})
|
})
|
||||||
@@ -155,7 +156,6 @@ const getCSRF = async (app: Express) => {
|
|||||||
const { header } = await request(app).get('/')
|
const { header } = await request(app).get('/')
|
||||||
const cookies = header['set-cookie'].join()
|
const cookies = header['set-cookie'].join()
|
||||||
|
|
||||||
console.log('cookies', cookies)
|
|
||||||
const csrfToken = extractCSRF(cookies)
|
const csrfToken = extractCSRF(cookies)
|
||||||
return { csrfToken, cookies }
|
return { csrfToken, cookies }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,10 +47,11 @@ stpRouter.post(
|
|||||||
query?._program
|
query?._program
|
||||||
)
|
)
|
||||||
|
|
||||||
if (response instanceof Buffer) {
|
// TODO: investigate if this code is required
|
||||||
res.writeHead(200, (req as any).sasHeaders)
|
// if (response instanceof Buffer) {
|
||||||
return res.end(response)
|
// res.writeHead(200, (req as any).sasHeaders)
|
||||||
}
|
// return res.end(response)
|
||||||
|
// }
|
||||||
|
|
||||||
res.send(response)
|
res.send(response)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
} from '../../middlewares'
|
} from '../../middlewares'
|
||||||
import {
|
import {
|
||||||
deleteUserValidation,
|
deleteUserValidation,
|
||||||
|
getUserValidation,
|
||||||
registerUserValidation,
|
registerUserValidation,
|
||||||
updateUserValidation
|
updateUserValidation
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
@@ -36,6 +37,25 @@ userRouter.get('/', authenticateAccessToken, async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
userRouter.get(
|
||||||
|
'/by/username/:username',
|
||||||
|
authenticateAccessToken,
|
||||||
|
async (req, res) => {
|
||||||
|
const { error, value: params } = getUserValidation(req.params)
|
||||||
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
|
const { username } = params
|
||||||
|
|
||||||
|
const controller = new UserController()
|
||||||
|
try {
|
||||||
|
const response = await controller.getUserByUsername(req, username)
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
userRouter.get('/:userId', authenticateAccessToken, async (req, res) => {
|
userRouter.get('/:userId', authenticateAccessToken, async (req, res) => {
|
||||||
const { userId } = req.params
|
const { userId } = req.params
|
||||||
|
|
||||||
@@ -48,6 +68,34 @@ userRouter.get('/:userId', authenticateAccessToken, async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
userRouter.patch(
|
||||||
|
'/by/username/:username',
|
||||||
|
authenticateAccessToken,
|
||||||
|
verifyAdminIfNeeded,
|
||||||
|
async (req, res) => {
|
||||||
|
const { user } = req
|
||||||
|
const { error: errorUsername, value: params } = getUserValidation(
|
||||||
|
req.params
|
||||||
|
)
|
||||||
|
if (errorUsername)
|
||||||
|
return res.status(400).send(errorUsername.details[0].message)
|
||||||
|
|
||||||
|
const { username } = params
|
||||||
|
|
||||||
|
// only an admin can update `isActive` and `isAdmin` fields
|
||||||
|
const { error, value: body } = updateUserValidation(req.body, user!.isAdmin)
|
||||||
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
|
const controller = new UserController()
|
||||||
|
try {
|
||||||
|
const response = await controller.updateUserByUsername(username, body)
|
||||||
|
res.send(response)
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
userRouter.patch(
|
userRouter.patch(
|
||||||
'/:userId',
|
'/:userId',
|
||||||
authenticateAccessToken,
|
authenticateAccessToken,
|
||||||
@@ -70,6 +118,34 @@ userRouter.patch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
userRouter.delete(
|
||||||
|
'/by/username/:username',
|
||||||
|
authenticateAccessToken,
|
||||||
|
verifyAdminIfNeeded,
|
||||||
|
async (req, res) => {
|
||||||
|
const { user } = req
|
||||||
|
const { error: errorUsername, value: params } = getUserValidation(
|
||||||
|
req.params
|
||||||
|
)
|
||||||
|
if (errorUsername)
|
||||||
|
return res.status(400).send(errorUsername.details[0].message)
|
||||||
|
|
||||||
|
const { username } = params
|
||||||
|
|
||||||
|
// only an admin can delete user without providing password
|
||||||
|
const { error, value: data } = deleteUserValidation(req.body, user!.isAdmin)
|
||||||
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
|
const controller = new UserController()
|
||||||
|
try {
|
||||||
|
await controller.deleteUserByUsername(username, data, user!.isAdmin)
|
||||||
|
res.status(200).send('Account Deleted!')
|
||||||
|
} catch (err: any) {
|
||||||
|
res.status(403).send(err.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
userRouter.delete(
|
userRouter.delete(
|
||||||
'/:userId',
|
'/:userId',
|
||||||
authenticateAccessToken,
|
authenticateAccessToken,
|
||||||
|
|||||||
@@ -23,13 +23,21 @@ export const appStreamHtml = (appStreamConfig: AppStreamConfig) => `
|
|||||||
${style}
|
${style}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>App Stream</h1>
|
<header>
|
||||||
|
<a href="/"><img src="/logo.png" alt="logo" class="logo"></a>
|
||||||
|
<h1>App Stream</h1>
|
||||||
|
</header>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
${Object.entries(appStreamConfig)
|
${Object.entries(appStreamConfig)
|
||||||
.map(([streamServiceName, entry]) =>
|
.map(([streamServiceName, entry]) =>
|
||||||
singleAppStreamHtml(streamServiceName, entry.appLoc, entry.streamLogo)
|
singleAppStreamHtml(
|
||||||
)
|
streamServiceName,
|
||||||
.join('')}
|
entry.appLoc,
|
||||||
|
entry.streamLogo
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.join('')}
|
||||||
|
|
||||||
<a class="app" title="Upload build.json">
|
<a class="app" title="Upload build.json">
|
||||||
<input id="fileId" type="file" hidden />
|
<input id="fileId" type="file" hidden />
|
||||||
<button id="uploadButton" style="margin-bottom: 5px; cursor: pointer">
|
<button id="uploadButton" style="margin-bottom: 5px; cursor: pointer">
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import express from 'express'
|
import express, { Request } from 'express'
|
||||||
import { folderExists } from '@sasjs/utils'
|
import { folderExists } from '@sasjs/utils'
|
||||||
|
|
||||||
import { addEntryToAppStreamConfig, getFilesFolder } from '../../utils'
|
import { addEntryToAppStreamConfig, getFilesFolder } from '../../utils'
|
||||||
import { appStreamHtml } from './appStreamHtml'
|
import { appStreamHtml } from './appStreamHtml'
|
||||||
|
|
||||||
|
const appStreams: { [key: string]: string } = {}
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
|
|
||||||
router.get('/', async (req, res) => {
|
router.get('/', async (req, res) => {
|
||||||
@@ -44,7 +46,7 @@ export const publishAppStream = async (
|
|||||||
streamServiceName = `AppStreamName${appCount + 1}`
|
streamServiceName = `AppStreamName${appCount + 1}`
|
||||||
}
|
}
|
||||||
|
|
||||||
router.use(`/${streamServiceName}`, express.static(pathToDeployment))
|
appStreams[streamServiceName] = pathToDeployment
|
||||||
|
|
||||||
addEntryToAppStreamConfig(
|
addEntryToAppStreamConfig(
|
||||||
streamServiceName,
|
streamServiceName,
|
||||||
@@ -64,4 +66,26 @@ export const publishAppStream = async (
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
router.get(`/*`, function (req: Request, res, next) {
|
||||||
|
const reqPath = req.path.replace(/^\//, '')
|
||||||
|
|
||||||
|
// Redirecting to url with trailing slash for appStream base URL only
|
||||||
|
if (reqPath.split('/').length === 1 && !reqPath.endsWith('/'))
|
||||||
|
// navigating to same url with slash at start
|
||||||
|
return res.redirect(301, `${reqPath}/`)
|
||||||
|
|
||||||
|
const appStream = reqPath.split('/')[0]
|
||||||
|
const appStreamFilesPath = appStreams[appStream]
|
||||||
|
if (appStreamFilesPath) {
|
||||||
|
// resourcePath is without appStream base path
|
||||||
|
const resourcePath = reqPath.split('/').slice(1).join('/') || 'index.html'
|
||||||
|
|
||||||
|
req.url = resourcePath
|
||||||
|
|
||||||
|
return express.static(appStreamFilesPath)(req, res, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.send("There's no App Stream available here.")
|
||||||
|
})
|
||||||
|
|
||||||
export default router
|
export default router
|
||||||
|
|||||||
@@ -5,18 +5,71 @@ export const style = `<style>
|
|||||||
.app-container {
|
.app-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: baseline;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
padding-top: 50px;
|
||||||
}
|
}
|
||||||
.app-container .app {
|
.app-container .app {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
|
height: 180px;
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
|
||||||
|
background: #efefef;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 7px;
|
||||||
|
border: 1px solid #d7d7d7;
|
||||||
}
|
}
|
||||||
.app-container .app img{
|
.app-container .app img{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
#uploadButton {
|
||||||
|
border: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#uploadButton:focus {
|
||||||
|
outline: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#uploadMessage {
|
||||||
|
position: relative;
|
||||||
|
bottom: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
transition: box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
|
||||||
|
box-shadow: rgb(0 0 0 / 20%) 0px 2px 4px -1px, rgb(0 0 0 / 14%) 0px 4px 5px 0px, rgb(0 0 0 / 12%) 0px 1px 10px 0px;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: auto;
|
||||||
|
right: 0px;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
z-index: 1201;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
margin: 13px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header a {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
header .logo {
|
||||||
|
width: 35px;
|
||||||
|
margin-left: 10px;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
</style>`
|
</style>`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { WebController } from '../../controllers/web'
|
import { WebController } from '../../controllers/web'
|
||||||
import { authenticateAccessToken } from '../../middlewares'
|
import { authenticateAccessToken, desktopRestrict } from '../../middlewares'
|
||||||
import { authorizeValidation, loginWebValidation } from '../../utils'
|
import { authorizeValidation, loginWebValidation } from '../../utils'
|
||||||
|
|
||||||
const webRouter = express.Router()
|
const webRouter = express.Router()
|
||||||
@@ -19,7 +19,7 @@ webRouter.get('/', async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
webRouter.post('/SASLogon/login', async (req, res) => {
|
webRouter.post('/SASLogon/login', desktopRestrict, async (req, res) => {
|
||||||
const { error, value: body } = loginWebValidation(req.body)
|
const { error, value: body } = loginWebValidation(req.body)
|
||||||
if (error) return res.status(400).send(error.details[0].message)
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
@@ -33,6 +33,7 @@ webRouter.post('/SASLogon/login', async (req, res) => {
|
|||||||
|
|
||||||
webRouter.post(
|
webRouter.post(
|
||||||
'/SASLogon/authorize',
|
'/SASLogon/authorize',
|
||||||
|
desktopRestrict,
|
||||||
authenticateAccessToken,
|
authenticateAccessToken,
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { error, value: body } = authorizeValidation(req.body)
|
const { error, value: body } = authorizeValidation(req.body)
|
||||||
@@ -47,7 +48,7 @@ webRouter.post(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
webRouter.get('/logout', async (req, res) => {
|
webRouter.get('/logout', desktopRestrict, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
await controller.logout(req)
|
await controller.logout(req)
|
||||||
res.status(200).send('OK!')
|
res.status(200).send('OK!')
|
||||||
|
|||||||
8
api/src/utils/desktopAutoExec.ts
Normal file
8
api/src/utils/desktopAutoExec.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { createFile, readFile } from '@sasjs/utils'
|
||||||
|
import { getDesktopUserAutoExecPath } from './file'
|
||||||
|
|
||||||
|
export const getUserAutoExec = async (): Promise<string> =>
|
||||||
|
readFile(getDesktopUserAutoExecPath())
|
||||||
|
|
||||||
|
export const updateUserAutoExec = async (autoExecContent: string) =>
|
||||||
|
createFile(getDesktopUserAutoExecPath(), autoExecContent)
|
||||||
6
api/src/utils/extractName.ts
Normal file
6
api/src/utils/extractName.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
export const extractName = (filePath: string) => {
|
||||||
|
const extension = path.extname(filePath)
|
||||||
|
return path.basename(filePath, extension)
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { homedir } from 'os'
|
import { homedir } from 'os'
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
export const apiRoot = path.join(__dirname, '..', '..')
|
export const apiRoot = path.join(__dirname, '..', '..')
|
||||||
export const codebaseRoot = path.join(apiRoot, '..')
|
export const codebaseRoot = path.join(apiRoot, '..')
|
||||||
@@ -47,3 +48,6 @@ export const generateUniqueFileName = (fileName: string, extension = '') =>
|
|||||||
new Date().getTime(),
|
new Date().getTime(),
|
||||||
extension
|
extension
|
||||||
].join('')
|
].join('')
|
||||||
|
|
||||||
|
export const createReadStream = async (filePath: string) =>
|
||||||
|
fs.createReadStream(filePath)
|
||||||
|
|||||||
15
api/src/utils/getServerUrl.ts
Normal file
15
api/src/utils/getServerUrl.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import express from 'express'
|
||||||
|
import url from 'url'
|
||||||
|
|
||||||
|
export const getFullUrl = (req: express.Request) =>
|
||||||
|
url.format({
|
||||||
|
protocol: req.protocol,
|
||||||
|
host: req.get('host'),
|
||||||
|
pathname: req.originalUrl
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getServerUrl = (req: express.Request) =>
|
||||||
|
url.format({
|
||||||
|
protocol: req.protocol,
|
||||||
|
host: req.get('x-forwarded-host') || req.get('host')
|
||||||
|
})
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
export * from './appStreamConfig'
|
export * from './appStreamConfig'
|
||||||
export * from './connectDB'
|
export * from './connectDB'
|
||||||
export * from './copySASjsCore'
|
export * from './copySASjsCore'
|
||||||
|
export * from './desktopAutoExec'
|
||||||
export * from './extractHeaders'
|
export * from './extractHeaders'
|
||||||
|
export * from './extractName'
|
||||||
export * from './file'
|
export * from './file'
|
||||||
export * from './generateAccessToken'
|
export * from './generateAccessToken'
|
||||||
export * from './generateAuthCode'
|
export * from './generateAuthCode'
|
||||||
@@ -9,8 +11,10 @@ export * from './generateRefreshToken'
|
|||||||
export * from './getCertificates'
|
export * from './getCertificates'
|
||||||
export * from './getDesktopFields'
|
export * from './getDesktopFields'
|
||||||
export * from './getPreProgramVariables'
|
export * from './getPreProgramVariables'
|
||||||
|
export * from './getServerUrl'
|
||||||
export * from './instantiateLogger'
|
export * from './instantiateLogger'
|
||||||
export * from './isDebugOn'
|
export * from './isDebugOn'
|
||||||
|
export * from './zipped'
|
||||||
export * from './parseLogToArray'
|
export * from './parseLogToArray'
|
||||||
export * from './removeTokensInDB'
|
export * from './removeTokensInDB'
|
||||||
export * from './saveTokensInDB'
|
export * from './saveTokensInDB'
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import Joi from 'joi'
|
import Joi from 'joi'
|
||||||
|
|
||||||
const usernameSchema = Joi.string().alphanum().min(3).max(16)
|
const usernameSchema = Joi.string().lowercase().alphanum().min(3).max(16)
|
||||||
const passwordSchema = Joi.string().min(6).max(1024)
|
const passwordSchema = Joi.string().min(6).max(1024)
|
||||||
|
|
||||||
export const blockFileRegex = /\.(exe|sh|htaccess)$/i
|
export const blockFileRegex = /\.(exe|sh|htaccess)$/i
|
||||||
|
|
||||||
|
export const getUserValidation = (data: any): Joi.ValidationResult =>
|
||||||
|
Joi.object({
|
||||||
|
username: usernameSchema.required()
|
||||||
|
}).validate(data)
|
||||||
|
|
||||||
export const loginWebValidation = (data: any): Joi.ValidationResult =>
|
export const loginWebValidation = (data: any): Joi.ValidationResult =>
|
||||||
Joi.object({
|
Joi.object({
|
||||||
username: usernameSchema.required(),
|
username: usernameSchema.required(),
|
||||||
|
|||||||
40
api/src/utils/zipped.ts
Normal file
40
api/src/utils/zipped.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import unZipper from 'unzipper'
|
||||||
|
import { extractName } from './extractName'
|
||||||
|
import { createReadStream } from './file'
|
||||||
|
|
||||||
|
export const isZipFile = (
|
||||||
|
file: Express.Multer.File
|
||||||
|
): { error?: string; value?: Express.Multer.File } => {
|
||||||
|
const fileExtension = path.extname(file.originalname)
|
||||||
|
if (fileExtension.toUpperCase() !== '.ZIP')
|
||||||
|
return { error: `"file" has invalid extension ${fileExtension}` }
|
||||||
|
|
||||||
|
const allowedMimetypes = ['application/zip', 'application/x-zip-compressed']
|
||||||
|
|
||||||
|
if (!allowedMimetypes.includes(file.mimetype))
|
||||||
|
return { error: `"file" has invalid type ${file.mimetype}` }
|
||||||
|
|
||||||
|
return { value: file }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const extractJSONFromZip = async (zipFile: Express.Multer.File) => {
|
||||||
|
let fileContent: string = ''
|
||||||
|
|
||||||
|
const fileInZip = extractName(zipFile.originalname)
|
||||||
|
const zip = (await createReadStream(zipFile.path)).pipe(
|
||||||
|
unZipper.Parse({ forceStream: true })
|
||||||
|
)
|
||||||
|
|
||||||
|
for await (const entry of zip) {
|
||||||
|
const fileName = entry.path as string
|
||||||
|
if (fileName.toUpperCase().endsWith('.JSON') && fileName === fileInZip) {
|
||||||
|
fileContent = await entry.buffer()
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
entry.autodrain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileContent
|
||||||
|
}
|
||||||
122
package-lock.json
generated
122
package-lock.json
generated
@@ -2770,9 +2770,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm": {
|
"node_modules/npm": {
|
||||||
"version": "8.10.0",
|
"version": "8.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/npm/-/npm-8.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/npm/-/npm-8.12.2.tgz",
|
||||||
"integrity": "sha512-6oo65q9Quv9mRPGZJufmSH+C/UFdgelwzRXiglT/2mDB50zdy/lZK5dFY0TJ9fJ/8gHqnxcX1NM206KLjTBMlQ==",
|
"integrity": "sha512-TArexqro9wpl/6wz6t6YdYhOoiy/UArqiSsSsqI7fieEhQEswDQSJcgt/LuCDjl6mfCDi0So7S2UZ979qLYRPg==",
|
||||||
"bundleDependencies": [
|
"bundleDependencies": [
|
||||||
"@isaacs/string-locale-compare",
|
"@isaacs/string-locale-compare",
|
||||||
"@npmcli/arborist",
|
"@npmcli/arborist",
|
||||||
@@ -2858,7 +2858,7 @@
|
|||||||
"@npmcli/run-script": "^3.0.1",
|
"@npmcli/run-script": "^3.0.1",
|
||||||
"abbrev": "~1.1.1",
|
"abbrev": "~1.1.1",
|
||||||
"archy": "~1.0.0",
|
"archy": "~1.0.0",
|
||||||
"cacache": "^16.0.7",
|
"cacache": "^16.1.1",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"chownr": "^2.0.0",
|
"chownr": "^2.0.0",
|
||||||
"cli-columns": "^4.0.0",
|
"cli-columns": "^4.0.0",
|
||||||
@@ -2883,7 +2883,7 @@
|
|||||||
"libnpmsearch": "^5.0.2",
|
"libnpmsearch": "^5.0.2",
|
||||||
"libnpmteam": "^4.0.2",
|
"libnpmteam": "^4.0.2",
|
||||||
"libnpmversion": "^3.0.1",
|
"libnpmversion": "^3.0.1",
|
||||||
"make-fetch-happen": "^10.1.3",
|
"make-fetch-happen": "^10.1.7",
|
||||||
"minipass": "^3.1.6",
|
"minipass": "^3.1.6",
|
||||||
"minipass-pipeline": "^1.2.4",
|
"minipass-pipeline": "^1.2.4",
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
@@ -2900,7 +2900,7 @@
|
|||||||
"npm-user-validate": "^1.0.1",
|
"npm-user-validate": "^1.0.1",
|
||||||
"npmlog": "^6.0.2",
|
"npmlog": "^6.0.2",
|
||||||
"opener": "^1.5.2",
|
"opener": "^1.5.2",
|
||||||
"pacote": "^13.3.0",
|
"pacote": "^13.6.0",
|
||||||
"parse-conflict-json": "^2.0.2",
|
"parse-conflict-json": "^2.0.2",
|
||||||
"proc-log": "^2.0.1",
|
"proc-log": "^2.0.1",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
@@ -2910,7 +2910,7 @@
|
|||||||
"readdir-scoped-modules": "^1.1.0",
|
"readdir-scoped-modules": "^1.1.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.3.7",
|
||||||
"ssri": "^9.0.0",
|
"ssri": "^9.0.1",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
"text-table": "~0.2.0",
|
"text-table": "~0.2.0",
|
||||||
"tiny-relative-date": "^1.3.0",
|
"tiny-relative-date": "^1.3.0",
|
||||||
@@ -2965,7 +2965,7 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/@npmcli/arborist": {
|
"node_modules/npm/node_modules/@npmcli/arborist": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -3389,7 +3389,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/cacache": {
|
"node_modules/npm/node_modules/cacache": {
|
||||||
"version": "16.0.7",
|
"version": "16.1.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -3759,7 +3759,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/glob": {
|
"node_modules/npm/node_modules/glob": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -3769,8 +3769,7 @@
|
|||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^5.0.1",
|
"minimatch": "^5.0.1",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0"
|
||||||
"path-is-absolute": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -4121,7 +4120,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/libnpmexec": {
|
"node_modules/npm/node_modules/libnpmexec": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -4186,7 +4185,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/libnpmpack": {
|
"node_modules/npm/node_modules/libnpmpack": {
|
||||||
"version": "4.0.3",
|
"version": "4.1.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -4194,7 +4193,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@npmcli/run-script": "^3.0.0",
|
"@npmcli/run-script": "^3.0.0",
|
||||||
"npm-package-arg": "^9.0.1",
|
"npm-package-arg": "^9.0.1",
|
||||||
"pacote": "^13.0.5"
|
"pacote": "^13.5.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||||
@@ -4272,14 +4271,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/make-fetch-happen": {
|
"node_modules/npm/node_modules/make-fetch-happen": {
|
||||||
"version": "10.1.3",
|
"version": "10.1.7",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"agentkeepalive": "^4.2.1",
|
"agentkeepalive": "^4.2.1",
|
||||||
"cacache": "^16.0.2",
|
"cacache": "^16.1.0",
|
||||||
"http-cache-semantics": "^4.1.0",
|
"http-cache-semantics": "^4.1.0",
|
||||||
"http-proxy-agent": "^5.0.0",
|
"http-proxy-agent": "^5.0.0",
|
||||||
"https-proxy-agent": "^5.0.0",
|
"https-proxy-agent": "^5.0.0",
|
||||||
@@ -4292,7 +4291,7 @@
|
|||||||
"minipass-pipeline": "^1.2.4",
|
"minipass-pipeline": "^1.2.4",
|
||||||
"negotiator": "^0.6.3",
|
"negotiator": "^0.6.3",
|
||||||
"promise-retry": "^2.0.1",
|
"promise-retry": "^2.0.1",
|
||||||
"socks-proxy-agent": "^6.1.1",
|
"socks-proxy-agent": "^7.0.0",
|
||||||
"ssri": "^9.0.0"
|
"ssri": "^9.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4300,7 +4299,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/minimatch": {
|
"node_modules/npm/node_modules/minimatch": {
|
||||||
"version": "5.0.1",
|
"version": "5.1.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -4509,7 +4508,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/node-gyp/node_modules/glob": {
|
"node_modules/npm/node_modules/node-gyp/node_modules/glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -4518,7 +4517,7 @@
|
|||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.1.1",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"path-is-absolute": "^1.0.0"
|
"path-is-absolute": "^1.0.0"
|
||||||
},
|
},
|
||||||
@@ -4633,7 +4632,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/npm-packlist": {
|
"node_modules/npm/node_modules/npm-packlist": {
|
||||||
"version": "5.0.3",
|
"version": "5.1.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -4760,7 +4759,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/pacote": {
|
"node_modules/npm/node_modules/pacote": {
|
||||||
"version": "13.3.0",
|
"version": "13.6.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -4777,7 +4776,7 @@
|
|||||||
"minipass": "^3.1.6",
|
"minipass": "^3.1.6",
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
"npm-package-arg": "^9.0.0",
|
"npm-package-arg": "^9.0.0",
|
||||||
"npm-packlist": "^5.0.0",
|
"npm-packlist": "^5.1.0",
|
||||||
"npm-pick-manifest": "^7.0.0",
|
"npm-pick-manifest": "^7.0.0",
|
||||||
"npm-registry-fetch": "^13.0.1",
|
"npm-registry-fetch": "^13.0.1",
|
||||||
"proc-log": "^2.0.0",
|
"proc-log": "^2.0.0",
|
||||||
@@ -5009,7 +5008,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/rimraf/node_modules/glob": {
|
"node_modules/npm/node_modules/rimraf/node_modules/glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -5018,7 +5017,7 @@
|
|||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.1.1",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"path-is-absolute": "^1.0.0"
|
"path-is-absolute": "^1.0.0"
|
||||||
},
|
},
|
||||||
@@ -5141,7 +5140,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/socks-proxy-agent": {
|
"node_modules/npm/node_modules/socks-proxy-agent": {
|
||||||
"version": "6.2.0",
|
"version": "7.0.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -5192,7 +5191,7 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/npm/node_modules/ssri": {
|
"node_modules/npm/node_modules/ssri": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"inBundle": true,
|
"inBundle": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@@ -5911,9 +5910,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/semantic-release": {
|
"node_modules/semantic-release": {
|
||||||
"version": "19.0.2",
|
"version": "19.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.3.tgz",
|
||||||
"integrity": "sha512-7tPonjZxukKECmClhsfyMKDt0GR38feIC2HxgyYaBi+9tDySBLjK/zYDLhh+m6yjnHIJa9eBTKYE7k63ZQcYbw==",
|
"integrity": "sha512-HaFbydST1cDKZHuFZxB8DTrBLJVK/AnDExpK0s3EqLIAAUAHUgnd+VSJCUtTYQKkAkauL8G9CucODrVCc7BuAA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9019,9 +9018,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"npm": {
|
"npm": {
|
||||||
"version": "8.10.0",
|
"version": "8.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/npm/-/npm-8.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/npm/-/npm-8.12.2.tgz",
|
||||||
"integrity": "sha512-6oo65q9Quv9mRPGZJufmSH+C/UFdgelwzRXiglT/2mDB50zdy/lZK5dFY0TJ9fJ/8gHqnxcX1NM206KLjTBMlQ==",
|
"integrity": "sha512-TArexqro9wpl/6wz6t6YdYhOoiy/UArqiSsSsqI7fieEhQEswDQSJcgt/LuCDjl6mfCDi0So7S2UZ979qLYRPg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
@@ -9035,7 +9034,7 @@
|
|||||||
"@npmcli/run-script": "^3.0.1",
|
"@npmcli/run-script": "^3.0.1",
|
||||||
"abbrev": "~1.1.1",
|
"abbrev": "~1.1.1",
|
||||||
"archy": "~1.0.0",
|
"archy": "~1.0.0",
|
||||||
"cacache": "^16.0.7",
|
"cacache": "^16.1.1",
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
"chownr": "^2.0.0",
|
"chownr": "^2.0.0",
|
||||||
"cli-columns": "^4.0.0",
|
"cli-columns": "^4.0.0",
|
||||||
@@ -9060,7 +9059,7 @@
|
|||||||
"libnpmsearch": "^5.0.2",
|
"libnpmsearch": "^5.0.2",
|
||||||
"libnpmteam": "^4.0.2",
|
"libnpmteam": "^4.0.2",
|
||||||
"libnpmversion": "^3.0.1",
|
"libnpmversion": "^3.0.1",
|
||||||
"make-fetch-happen": "^10.1.3",
|
"make-fetch-happen": "^10.1.7",
|
||||||
"minipass": "^3.1.6",
|
"minipass": "^3.1.6",
|
||||||
"minipass-pipeline": "^1.2.4",
|
"minipass-pipeline": "^1.2.4",
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
@@ -9077,7 +9076,7 @@
|
|||||||
"npm-user-validate": "^1.0.1",
|
"npm-user-validate": "^1.0.1",
|
||||||
"npmlog": "^6.0.2",
|
"npmlog": "^6.0.2",
|
||||||
"opener": "^1.5.2",
|
"opener": "^1.5.2",
|
||||||
"pacote": "^13.3.0",
|
"pacote": "^13.6.0",
|
||||||
"parse-conflict-json": "^2.0.2",
|
"parse-conflict-json": "^2.0.2",
|
||||||
"proc-log": "^2.0.1",
|
"proc-log": "^2.0.1",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
@@ -9087,7 +9086,7 @@
|
|||||||
"readdir-scoped-modules": "^1.1.0",
|
"readdir-scoped-modules": "^1.1.0",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.3.7",
|
||||||
"ssri": "^9.0.0",
|
"ssri": "^9.0.1",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
"text-table": "~0.2.0",
|
"text-table": "~0.2.0",
|
||||||
"tiny-relative-date": "^1.3.0",
|
"tiny-relative-date": "^1.3.0",
|
||||||
@@ -9117,7 +9116,7 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"@npmcli/arborist": {
|
"@npmcli/arborist": {
|
||||||
"version": "5.2.0",
|
"version": "5.2.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -9432,7 +9431,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cacache": {
|
"cacache": {
|
||||||
"version": "16.0.7",
|
"version": "16.1.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -9704,7 +9703,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -9713,8 +9712,7 @@
|
|||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^5.0.1",
|
"minimatch": "^5.0.1",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0"
|
||||||
"path-is-absolute": "^1.0.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
@@ -9970,7 +9968,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libnpmexec": {
|
"libnpmexec": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.6",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10019,14 +10017,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libnpmpack": {
|
"libnpmpack": {
|
||||||
"version": "4.0.3",
|
"version": "4.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@npmcli/run-script": "^3.0.0",
|
"@npmcli/run-script": "^3.0.0",
|
||||||
"npm-package-arg": "^9.0.1",
|
"npm-package-arg": "^9.0.1",
|
||||||
"pacote": "^13.0.5"
|
"pacote": "^13.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"libnpmpublish": {
|
"libnpmpublish": {
|
||||||
@@ -10081,13 +10079,13 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"make-fetch-happen": {
|
"make-fetch-happen": {
|
||||||
"version": "10.1.3",
|
"version": "10.1.7",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"agentkeepalive": "^4.2.1",
|
"agentkeepalive": "^4.2.1",
|
||||||
"cacache": "^16.0.2",
|
"cacache": "^16.1.0",
|
||||||
"http-cache-semantics": "^4.1.0",
|
"http-cache-semantics": "^4.1.0",
|
||||||
"http-proxy-agent": "^5.0.0",
|
"http-proxy-agent": "^5.0.0",
|
||||||
"https-proxy-agent": "^5.0.0",
|
"https-proxy-agent": "^5.0.0",
|
||||||
@@ -10100,12 +10098,12 @@
|
|||||||
"minipass-pipeline": "^1.2.4",
|
"minipass-pipeline": "^1.2.4",
|
||||||
"negotiator": "^0.6.3",
|
"negotiator": "^0.6.3",
|
||||||
"promise-retry": "^2.0.1",
|
"promise-retry": "^2.0.1",
|
||||||
"socks-proxy-agent": "^6.1.1",
|
"socks-proxy-agent": "^7.0.0",
|
||||||
"ssri": "^9.0.0"
|
"ssri": "^9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "5.0.1",
|
"version": "5.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10254,7 +10252,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10262,7 +10260,7 @@
|
|||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.1.1",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"path-is-absolute": "^1.0.0"
|
"path-is-absolute": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -10344,7 +10342,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npm-packlist": {
|
"npm-packlist": {
|
||||||
"version": "5.0.3",
|
"version": "5.1.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10435,7 +10433,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pacote": {
|
"pacote": {
|
||||||
"version": "13.3.0",
|
"version": "13.6.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10451,7 +10449,7 @@
|
|||||||
"minipass": "^3.1.6",
|
"minipass": "^3.1.6",
|
||||||
"mkdirp": "^1.0.4",
|
"mkdirp": "^1.0.4",
|
||||||
"npm-package-arg": "^9.0.0",
|
"npm-package-arg": "^9.0.0",
|
||||||
"npm-packlist": "^5.0.0",
|
"npm-packlist": "^5.1.0",
|
||||||
"npm-pick-manifest": "^7.0.0",
|
"npm-pick-manifest": "^7.0.0",
|
||||||
"npm-registry-fetch": "^13.0.1",
|
"npm-registry-fetch": "^13.0.1",
|
||||||
"proc-log": "^2.0.0",
|
"proc-log": "^2.0.0",
|
||||||
@@ -10615,7 +10613,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"glob": {
|
"glob": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.3",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10623,7 +10621,7 @@
|
|||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
"inherits": "2",
|
"inherits": "2",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.1.1",
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"path-is-absolute": "^1.0.0"
|
"path-is-absolute": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -10701,7 +10699,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"socks-proxy-agent": {
|
"socks-proxy-agent": {
|
||||||
"version": "6.2.0",
|
"version": "7.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -10744,7 +10742,7 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"ssri": {
|
"ssri": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
@@ -11270,9 +11268,9 @@
|
|||||||
"peer": true
|
"peer": true
|
||||||
},
|
},
|
||||||
"semantic-release": {
|
"semantic-release": {
|
||||||
"version": "19.0.2",
|
"version": "19.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-19.0.3.tgz",
|
||||||
"integrity": "sha512-7tPonjZxukKECmClhsfyMKDt0GR38feIC2HxgyYaBi+9tDySBLjK/zYDLhh+m6yjnHIJa9eBTKYE7k63ZQcYbw==",
|
"integrity": "sha512-HaFbydST1cDKZHuFZxB8DTrBLJVK/AnDExpK0s3EqLIAAUAHUgnd+VSJCUtTYQKkAkauL8G9CucODrVCc7BuAA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ const Header = (props: any) => {
|
|||||||
color="primary"
|
color="primary"
|
||||||
startIcon={<SettingsIcon />}
|
startIcon={<SettingsIcon />}
|
||||||
>
|
>
|
||||||
Setting
|
Settings
|
||||||
</Button>
|
</Button>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem onClick={handleLogout} sx={{ justifyContent: 'center' }}>
|
<MenuItem onClick={handleLogout} sx={{ justifyContent: 'center' }}>
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ import {
|
|||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Checkbox
|
Checkbox
|
||||||
} from '@mui/material'
|
} from '@mui/material'
|
||||||
|
|
||||||
import { AppContext } from '../../context/appContext'
|
|
||||||
import { toast } from 'react-toastify'
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
|
import { AppContext, ModeType } from '../../context/appContext'
|
||||||
|
|
||||||
const Profile = () => {
|
const Profile = () => {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
const appContext = useContext(AppContext)
|
const appContext = useContext(AppContext)
|
||||||
@@ -89,6 +89,7 @@ const Profile = () => {
|
|||||||
required
|
required
|
||||||
value={user.displayName}
|
value={user.displayName}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
disabled={appContext.mode === ModeType.Desktop}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@@ -103,6 +104,20 @@ const Profile = () => {
|
|||||||
required
|
required
|
||||||
value={user.username}
|
value={user.username}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
disabled={appContext.mode === ModeType.Desktop}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item lg={6} md={8} sm={12} xs={12}>
|
||||||
|
<TextField
|
||||||
|
fullWidth
|
||||||
|
label="autoExec"
|
||||||
|
name="autoExec"
|
||||||
|
onChange={handleChange}
|
||||||
|
multiline
|
||||||
|
rows="10"
|
||||||
|
value={user.autoExec}
|
||||||
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@@ -120,19 +135,6 @@ const Profile = () => {
|
|||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<TextField
|
|
||||||
fullWidth
|
|
||||||
label="autoExec"
|
|
||||||
name="autoExec"
|
|
||||||
onChange={handleChange}
|
|
||||||
multiline
|
|
||||||
rows="4"
|
|
||||||
value={user.autoExec}
|
|
||||||
variant="outlined"
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ import React, {
|
|||||||
} from 'react'
|
} from 'react'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export enum ModeType {
|
||||||
|
Server = 'server',
|
||||||
|
Desktop = 'desktop'
|
||||||
|
}
|
||||||
|
|
||||||
interface AppContextProps {
|
interface AppContextProps {
|
||||||
checkingSession: boolean
|
checkingSession: boolean
|
||||||
loggedIn: boolean
|
loggedIn: boolean
|
||||||
@@ -19,6 +24,7 @@ interface AppContextProps {
|
|||||||
setUsername: Dispatch<SetStateAction<string>> | null
|
setUsername: Dispatch<SetStateAction<string>> | null
|
||||||
displayName: string
|
displayName: string
|
||||||
setDisplayName: Dispatch<SetStateAction<string>> | null
|
setDisplayName: Dispatch<SetStateAction<string>> | null
|
||||||
|
mode: ModeType
|
||||||
logout: (() => void) | null
|
logout: (() => void) | null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,6 +38,7 @@ export const AppContext = createContext<AppContextProps>({
|
|||||||
setUsername: null,
|
setUsername: null,
|
||||||
displayName: '',
|
displayName: '',
|
||||||
setDisplayName: null,
|
setDisplayName: null,
|
||||||
|
mode: ModeType.Server,
|
||||||
logout: null
|
logout: null
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -42,6 +49,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
|
|||||||
const [userId, setUserId] = useState(0)
|
const [userId, setUserId] = useState(0)
|
||||||
const [username, setUsername] = useState('')
|
const [username, setUsername] = useState('')
|
||||||
const [displayName, setDisplayName] = useState('')
|
const [displayName, setDisplayName] = useState('')
|
||||||
|
const [mode, setMode] = useState(ModeType.Server)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCheckingSession(true)
|
setCheckingSession(true)
|
||||||
@@ -60,6 +68,14 @@ const AppContextProvider = (props: { children: ReactNode }) => {
|
|||||||
setLoggedIn(false)
|
setLoggedIn(false)
|
||||||
axios.get('/') // get CSRF TOKEN
|
axios.get('/') // get CSRF TOKEN
|
||||||
})
|
})
|
||||||
|
|
||||||
|
axios
|
||||||
|
.get('/SASjsApi/info')
|
||||||
|
.then((res) => res.data)
|
||||||
|
.then((data: any) => {
|
||||||
|
setMode(data.mode)
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const logout = useCallback(() => {
|
const logout = useCallback(() => {
|
||||||
@@ -82,6 +98,7 @@ const AppContextProvider = (props: { children: ReactNode }) => {
|
|||||||
setUsername,
|
setUsername,
|
||||||
displayName,
|
displayName,
|
||||||
setDisplayName,
|
setDisplayName,
|
||||||
|
mode,
|
||||||
logout
|
logout
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user