mirror of
https://github.com/sasjs/server.git
synced 2026-01-20 20:30:06 +00:00
chore: merge main into issue-198
This commit is contained in:
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [sasjs]
|
||||
48
CHANGELOG.md
48
CHANGELOG.md
@@ -1,3 +1,51 @@
|
||||
## [0.11.5](https://github.com/sasjs/server/compare/v0.11.4...v0.11.5) (2022-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Revert "fix(security): missing cookie flags are added" ([ce5218a](https://github.com/sasjs/server/commit/ce5218a2278cc750f2b1032024685dc6cd72f796))
|
||||
|
||||
## [0.11.4](https://github.com/sasjs/server/compare/v0.11.3...v0.11.4) (2022-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **security:** missing cookie flags are added ([526402f](https://github.com/sasjs/server/commit/526402fd73407ee4fa2d31092111a7e6a1741487))
|
||||
|
||||
## [0.11.3](https://github.com/sasjs/server/compare/v0.11.2...v0.11.3) (2022-07-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* filePath fix in code.js file for windows ([2995121](https://github.com/sasjs/server/commit/299512135d77c2ac9e34853cf35aee6f2e1d4da4))
|
||||
|
||||
## [0.11.2](https://github.com/sasjs/server/compare/v0.11.1...v0.11.2) (2022-07-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* apply icon option only for sas.exe ([d2ddd8a](https://github.com/sasjs/server/commit/d2ddd8aacadfdd143026881f2c6ae8c6b277610a))
|
||||
|
||||
## [0.11.1](https://github.com/sasjs/server/compare/v0.11.0...v0.11.1) (2022-07-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bank operator ([aa02741](https://github.com/sasjs/server/commit/aa027414ed3ce51f1014ef36c4191e064b2e963d))
|
||||
* ensuring nosplash option only applies for sas.exe ([65e6de9](https://github.com/sasjs/server/commit/65e6de966383fe49a919b1f901d77c7f1e402c9b)), closes [#229](https://github.com/sasjs/server/issues/229)
|
||||
|
||||
# [0.11.0](https://github.com/sasjs/server/compare/v0.10.0...v0.11.0) (2022-07-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **logs:** logs location is configurable ([e024a92](https://github.com/sasjs/server/commit/e024a92f165990e08db8aa26ee326dbcb30e2e46))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **logs:** logs to file with rotating + code split into files ([92fda18](https://github.com/sasjs/server/commit/92fda183f3f0f3956b7c791669eb8dd52c389d1b))
|
||||
|
||||
# [0.10.0](https://github.com/sasjs/server/compare/v0.9.0...v0.10.0) (2022-07-06)
|
||||
|
||||
|
||||
|
||||
@@ -136,6 +136,9 @@ HELMET_CSP_CONFIG_PATH=./csp.config.json
|
||||
# Docs: https://www.npmjs.com/package/morgan#predefined-formats
|
||||
LOG_FORMAT_MORGAN=
|
||||
|
||||
# This location is for server logs with classical UNIX logrotate behavior
|
||||
LOG_LOCATION=./sasjs_root/logs
|
||||
|
||||
# A comma separated string that defines the available runTimes.
|
||||
# Priority is given to the runtime that comes first in the string.
|
||||
# Possible options at the moment are sas and js
|
||||
|
||||
@@ -21,3 +21,4 @@ NODE_PATH=~/.nvm/versions/node/v16.14.0/bin/node
|
||||
SASJS_ROOT=./sasjs_root
|
||||
|
||||
LOG_FORMAT_MORGAN=common
|
||||
LOG_LOCATION=./sasjs_root/logs
|
||||
1252
api/package-lock.json
generated
1252
api/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
||||
"initial": "npm run swagger && npm run compileSysInit && npm run copySASjsCore",
|
||||
"prestart": "npm run initial",
|
||||
"prebuild": "npm run initial",
|
||||
"start": "nodemon ./src/server.ts",
|
||||
"start": "NODE_ENV=development nodemon ./src/server.ts",
|
||||
"start:prod": "node ./build/src/server.js",
|
||||
"build": "rimraf build && tsc",
|
||||
"postbuild": "npm run copy:files",
|
||||
@@ -63,6 +63,7 @@
|
||||
"mongoose-sequence": "^5.3.1",
|
||||
"morgan": "^1.10.0",
|
||||
"multer": "^1.4.3",
|
||||
"rotating-file-stream": "^3.0.4",
|
||||
"swagger-ui-express": "4.3.0",
|
||||
"unzipper": "^0.10.11",
|
||||
"url": "^0.10.3"
|
||||
|
||||
@@ -85,10 +85,8 @@ components:
|
||||
type: string
|
||||
_webout:
|
||||
anyOf:
|
||||
-
|
||||
type: string
|
||||
-
|
||||
$ref: '#/components/schemas/IRecordOfAny'
|
||||
- type: string
|
||||
- $ref: '#/components/schemas/IRecordOfAny'
|
||||
log:
|
||||
items:
|
||||
$ref: '#/components/schemas/LogLine'
|
||||
@@ -137,12 +135,9 @@ components:
|
||||
members:
|
||||
items:
|
||||
anyOf:
|
||||
-
|
||||
$ref: '#/components/schemas/FolderMember'
|
||||
-
|
||||
$ref: '#/components/schemas/ServiceMember'
|
||||
-
|
||||
$ref: '#/components/schemas/FileMember'
|
||||
- $ref: '#/components/schemas/FolderMember'
|
||||
- $ref: '#/components/schemas/ServiceMember'
|
||||
- $ref: '#/components/schemas/FileMember'
|
||||
type: array
|
||||
required:
|
||||
- name
|
||||
@@ -191,12 +186,9 @@ components:
|
||||
members:
|
||||
items:
|
||||
anyOf:
|
||||
-
|
||||
$ref: '#/components/schemas/FolderMember'
|
||||
-
|
||||
$ref: '#/components/schemas/ServiceMember'
|
||||
-
|
||||
$ref: '#/components/schemas/FileMember'
|
||||
- $ref: '#/components/schemas/FolderMember'
|
||||
- $ref: '#/components/schemas/ServiceMember'
|
||||
- $ref: '#/components/schemas/FileMember'
|
||||
type: array
|
||||
required:
|
||||
- members
|
||||
@@ -382,7 +374,7 @@ components:
|
||||
autoExec:
|
||||
type: string
|
||||
description: 'User-specific auto-exec code'
|
||||
example: ""
|
||||
example: ''
|
||||
required:
|
||||
- displayName
|
||||
- username
|
||||
@@ -619,7 +611,11 @@ paths:
|
||||
$ref: '#/components/schemas/TokenResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {accessToken: someRandomCryptoString, refreshToken: someRandomCryptoString}
|
||||
value:
|
||||
{
|
||||
accessToken: someRandomCryptoString,
|
||||
refreshToken: someRandomCryptoString
|
||||
}
|
||||
summary: 'Accepts client/auth code and returns access/refresh tokens'
|
||||
tags:
|
||||
- Auth
|
||||
@@ -643,13 +639,16 @@ paths:
|
||||
$ref: '#/components/schemas/TokenResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {accessToken: someRandomCryptoString, refreshToken: someRandomCryptoString}
|
||||
value:
|
||||
{
|
||||
accessToken: someRandomCryptoString,
|
||||
refreshToken: someRandomCryptoString
|
||||
}
|
||||
summary: 'Returns new access/refresh tokens'
|
||||
tags:
|
||||
- Auth
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
/SASjsApi/auth/logout:
|
||||
post:
|
||||
@@ -661,8 +660,7 @@ paths:
|
||||
tags:
|
||||
- Auth
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
/SASjsApi/client:
|
||||
post:
|
||||
@@ -676,13 +674,16 @@ paths:
|
||||
$ref: '#/components/schemas/ClientPayload'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString}
|
||||
value:
|
||||
{
|
||||
clientId: someFormattedClientID1234,
|
||||
clientSecret: someRandomCryptoString
|
||||
}
|
||||
summary: 'Create client with the following attributes: ClientId, ClientSecret. Admin only task.'
|
||||
tags:
|
||||
- Client
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -705,8 +706,7 @@ paths:
|
||||
tags:
|
||||
- CODE
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -726,7 +726,11 @@ paths:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: success, message: 'Files deployed successfully to @sasjs/server.'}
|
||||
value:
|
||||
{
|
||||
status: success,
|
||||
message: 'Files deployed successfully to @sasjs/server.'
|
||||
}
|
||||
'400':
|
||||
description: 'Invalid Format'
|
||||
content:
|
||||
@@ -735,7 +739,11 @@ paths:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: failure, message: 'Provided not supported data format.'}
|
||||
value:
|
||||
{
|
||||
status: failure,
|
||||
message: 'Provided not supported data format.'
|
||||
}
|
||||
'500':
|
||||
description: 'Execution Error'
|
||||
content:
|
||||
@@ -749,8 +757,7 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -770,7 +777,11 @@ paths:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: success, message: 'Files deployed successfully to @sasjs/server.'}
|
||||
value:
|
||||
{
|
||||
status: success,
|
||||
message: 'Files deployed successfully to @sasjs/server.'
|
||||
}
|
||||
'400':
|
||||
description: 'Invalid Format'
|
||||
content:
|
||||
@@ -779,7 +790,11 @@ paths:
|
||||
$ref: '#/components/schemas/DeployResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: failure, message: 'Provided not supported data format.'}
|
||||
value:
|
||||
{
|
||||
status: failure,
|
||||
message: 'Provided not supported data format.'
|
||||
}
|
||||
'500':
|
||||
description: 'Execution Error'
|
||||
content:
|
||||
@@ -794,8 +809,7 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -819,11 +833,9 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
in: query
|
||||
- in: query
|
||||
name: _filePath
|
||||
required: true
|
||||
schema:
|
||||
@@ -846,11 +858,9 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
in: query
|
||||
- in: query
|
||||
name: _filePath
|
||||
required: true
|
||||
schema:
|
||||
@@ -882,11 +892,9 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'Location of file'
|
||||
- description: 'Location of file'
|
||||
in: query
|
||||
name: _filePath
|
||||
required: false
|
||||
@@ -920,7 +928,7 @@ paths:
|
||||
'Example 1':
|
||||
value: { status: success }
|
||||
'403':
|
||||
description: ""
|
||||
description: ''
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -933,11 +941,9 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'Location of SAS program'
|
||||
- description: 'Location of SAS program'
|
||||
in: query
|
||||
name: _filePath
|
||||
required: false
|
||||
@@ -978,11 +984,9 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
in: query
|
||||
- in: query
|
||||
name: _folderPath
|
||||
required: false
|
||||
schema:
|
||||
@@ -1005,11 +1009,9 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
in: query
|
||||
- in: query
|
||||
name: _folderPath
|
||||
required: true
|
||||
schema:
|
||||
@@ -1035,13 +1037,13 @@ paths:
|
||||
$ref: '#/components/schemas/FileFolderResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: failure, message: 'Add folder request failed.'}
|
||||
value:
|
||||
{ status: failure, message: 'Add folder request failed.' }
|
||||
summary: 'Create an empty folder in SASjs Drive'
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -1075,8 +1077,7 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -1098,8 +1099,7 @@ paths:
|
||||
tags:
|
||||
- Drive
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
/SASjsApi/user:
|
||||
get:
|
||||
@@ -1115,13 +1115,26 @@ paths:
|
||||
type: array
|
||||
examples:
|
||||
'Example 1':
|
||||
value: [{id: 123, username: johnusername, displayName: John, isAdmin: false}, {id: 456, username: starkusername, displayName: Stark, isAdmin: true}]
|
||||
value:
|
||||
[
|
||||
{
|
||||
id: 123,
|
||||
username: johnusername,
|
||||
displayName: John,
|
||||
isAdmin: false
|
||||
},
|
||||
{
|
||||
id: 456,
|
||||
username: starkusername,
|
||||
displayName: Stark,
|
||||
isAdmin: true
|
||||
}
|
||||
]
|
||||
summary: 'Get list of all users (username, displayname). All users can request this.'
|
||||
tags:
|
||||
- User
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
post:
|
||||
operationId: CreateUser
|
||||
@@ -1134,13 +1147,19 @@ paths:
|
||||
$ref: '#/components/schemas/UserDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
|
||||
value:
|
||||
{
|
||||
id: 1234,
|
||||
displayName: 'John Snow',
|
||||
username: johnSnow01,
|
||||
isAdmin: false,
|
||||
isActive: true
|
||||
}
|
||||
summary: 'Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.'
|
||||
tags:
|
||||
- User
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -1163,11 +1182,9 @@ paths:
|
||||
tags:
|
||||
- User
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The User''s username'
|
||||
- description: "The User's username"
|
||||
in: path
|
||||
name: username
|
||||
required: true
|
||||
@@ -1185,16 +1202,21 @@ paths:
|
||||
$ref: '#/components/schemas/UserDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
|
||||
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: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The User''s username'
|
||||
- description: "The User's username"
|
||||
in: path
|
||||
name: username
|
||||
required: true
|
||||
@@ -1216,11 +1238,9 @@ paths:
|
||||
tags:
|
||||
- User
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The User''s username'
|
||||
- description: "The User's username"
|
||||
in: path
|
||||
name: username
|
||||
required: true
|
||||
@@ -1251,11 +1271,9 @@ paths:
|
||||
tags:
|
||||
- User
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The user''s identifier'
|
||||
- description: "The user's identifier"
|
||||
in: path
|
||||
name: userId
|
||||
required: true
|
||||
@@ -1274,16 +1292,21 @@ paths:
|
||||
$ref: '#/components/schemas/UserDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {id: 1234, displayName: 'John Snow', username: johnSnow01, isAdmin: false, isActive: true}
|
||||
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: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The user''s identifier'
|
||||
- description: "The user's identifier"
|
||||
in: path
|
||||
name: userId
|
||||
required: true
|
||||
@@ -1306,11 +1329,9 @@ paths:
|
||||
tags:
|
||||
- User
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The user''s identifier'
|
||||
- description: "The user's identifier"
|
||||
in: path
|
||||
name: userId
|
||||
required: true
|
||||
@@ -1341,13 +1362,19 @@ paths:
|
||||
type: array
|
||||
examples:
|
||||
'Example 1':
|
||||
value: [{groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users'}]
|
||||
value:
|
||||
[
|
||||
{
|
||||
groupId: 123,
|
||||
name: DCGroup,
|
||||
description: 'This group represents Data Controller Users'
|
||||
}
|
||||
]
|
||||
summary: 'Get list of all groups (groupName and groupDescription). All users can request this.'
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
post:
|
||||
operationId: CreateGroup
|
||||
@@ -1360,13 +1387,19 @@ paths:
|
||||
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
|
||||
value:
|
||||
{
|
||||
groupId: 123,
|
||||
name: DCGroup,
|
||||
description: 'This group represents Data Controller Users',
|
||||
isActive: true,
|
||||
users: []
|
||||
}
|
||||
summary: 'Create a new group. Admin only.'
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -1388,11 +1421,9 @@ paths:
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The group''s name'
|
||||
- description: "The group's name"
|
||||
in: path
|
||||
name: name
|
||||
required: true
|
||||
@@ -1412,11 +1443,9 @@ paths:
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The group''s identifier'
|
||||
- description: "The group's identifier"
|
||||
in: path
|
||||
name: groupId
|
||||
required: true
|
||||
@@ -1439,11 +1468,9 @@ paths:
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The group''s identifier'
|
||||
- description: "The group's identifier"
|
||||
in: path
|
||||
name: groupId
|
||||
required: true
|
||||
@@ -1463,16 +1490,21 @@ paths:
|
||||
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
|
||||
value:
|
||||
{
|
||||
groupId: 123,
|
||||
name: DCGroup,
|
||||
description: 'This group represents Data Controller Users',
|
||||
isActive: true,
|
||||
users: []
|
||||
}
|
||||
summary: 'Add a user to a group. Admin task only.'
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The group''s identifier'
|
||||
- description: "The group's identifier"
|
||||
in: path
|
||||
name: groupId
|
||||
required: true
|
||||
@@ -1480,8 +1512,7 @@ paths:
|
||||
format: double
|
||||
type: number
|
||||
example: '1234'
|
||||
-
|
||||
description: 'The user''s identifier'
|
||||
- description: "The user's identifier"
|
||||
in: path
|
||||
name: userId
|
||||
required: true
|
||||
@@ -1500,16 +1531,21 @@ paths:
|
||||
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {groupId: 123, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}
|
||||
value:
|
||||
{
|
||||
groupId: 123,
|
||||
name: DCGroup,
|
||||
description: 'This group represents Data Controller Users',
|
||||
isActive: true,
|
||||
users: []
|
||||
}
|
||||
summary: 'Remove a user to a group. Admin task only.'
|
||||
tags:
|
||||
- Group
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The group''s identifier'
|
||||
- description: "The group's identifier"
|
||||
in: path
|
||||
name: groupId
|
||||
required: true
|
||||
@@ -1517,8 +1553,7 @@ paths:
|
||||
format: double
|
||||
type: number
|
||||
example: '1234'
|
||||
-
|
||||
description: 'The user''s identifier'
|
||||
- description: "The user's identifier"
|
||||
in: path
|
||||
name: userId
|
||||
required: true
|
||||
@@ -1538,7 +1573,14 @@ paths:
|
||||
$ref: '#/components/schemas/InfoResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {mode: desktop, cors: enable, whiteList: ['http://example.com', 'http://example2.com'], protocol: http, runTimes: [sas, js]}
|
||||
value:
|
||||
{
|
||||
mode: desktop,
|
||||
cors: enable,
|
||||
whiteList: ['http://example.com', 'http://example2.com'],
|
||||
protocol: http,
|
||||
runTimes: [sas, js]
|
||||
}
|
||||
summary: 'Get server info (mode, cors, whiteList, protocol).'
|
||||
tags:
|
||||
- Info
|
||||
@@ -1574,13 +1616,18 @@ paths:
|
||||
$ref: '#/components/schemas/UserResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {id: 123, username: johnusername, displayName: John, isAdmin: false}
|
||||
value:
|
||||
{
|
||||
id: 123,
|
||||
username: johnusername,
|
||||
displayName: John,
|
||||
isAdmin: false
|
||||
}
|
||||
summary: 'Get session info (username).'
|
||||
tags:
|
||||
- Session
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
/SASjsApi/stp/execute:
|
||||
get:
|
||||
@@ -1599,11 +1646,9 @@ paths:
|
||||
tags:
|
||||
- STP
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'Location of SAS or JS code'
|
||||
- description: 'Location of SAS or JS code'
|
||||
in: query
|
||||
name: _program
|
||||
required: true
|
||||
@@ -1621,17 +1666,25 @@ paths:
|
||||
$ref: '#/components/schemas/ExecuteReturnJsonResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {status: success, _webout: 'webout content', log: [], httpHeaders: {Content-type: application/zip, Cache-Control: 'public, max-age=1000'}}
|
||||
value:
|
||||
{
|
||||
status: success,
|
||||
_webout: 'webout content',
|
||||
log: [],
|
||||
httpHeaders:
|
||||
{
|
||||
Content-type: application/zip,
|
||||
Cache-Control: 'public, max-age=1000'
|
||||
}
|
||||
}
|
||||
description: "Trigger a SAS or JS program using the _program URL parameter.\n\nAccepts URL parameters and file uploads. For more details, see docs:\n\nhttps://server.sasjs.io/storedprograms\n\nThe response will be a JSON object with the following root attributes:\nlog, webout, headers.\n\nThe webout attribute will be nested JSON ONLY if the response-header\ncontains a content-type of application/json AND it is valid JSON.\nOtherwise it will be a stringified version of the webout content."
|
||||
summary: 'Execute a Stored Program, return a JSON object'
|
||||
tags:
|
||||
- STP
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'Location of SAS or JS code'
|
||||
- description: 'Location of SAS or JS code'
|
||||
in: query
|
||||
name: _program
|
||||
required: false
|
||||
@@ -1669,7 +1722,18 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
user: {properties: {isAdmin: {type: boolean}, displayName: {type: string}, username: {type: string}, id: {type: number, format: double}}, required: [isAdmin, displayName, username, id], type: object}
|
||||
user:
|
||||
{
|
||||
properties:
|
||||
{
|
||||
isAdmin: { type: boolean },
|
||||
displayName: { type: string },
|
||||
username: { type: string },
|
||||
id: { type: number, format: double }
|
||||
},
|
||||
required: [isAdmin, displayName, username, id],
|
||||
type: object
|
||||
}
|
||||
loggedIn: { type: boolean }
|
||||
required:
|
||||
- user
|
||||
@@ -1738,13 +1802,39 @@ paths:
|
||||
type: array
|
||||
examples:
|
||||
'Example 1':
|
||||
value: [{permissionId: 123, uri: /SASjsApi/code/execute, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}, {permissionId: 124, uri: /SASjsApi/code/execute, setting: Grant, group: {groupId: 1, name: DCGroup, description: 'This group represents Data Controller Users', isActive: true, users: []}}]
|
||||
value:
|
||||
[
|
||||
{
|
||||
permissionId: 123,
|
||||
uri: /SASjsApi/code/execute,
|
||||
setting: Grant,
|
||||
user:
|
||||
{
|
||||
id: 1,
|
||||
username: johnSnow01,
|
||||
displayName: 'John Snow',
|
||||
isAdmin: false
|
||||
}
|
||||
},
|
||||
{
|
||||
permissionId: 124,
|
||||
uri: /SASjsApi/code/execute,
|
||||
setting: Grant,
|
||||
group:
|
||||
{
|
||||
groupId: 1,
|
||||
name: DCGroup,
|
||||
description: 'This group represents Data Controller Users',
|
||||
isActive: true,
|
||||
users: []
|
||||
}
|
||||
}
|
||||
]
|
||||
summary: 'Get list of all permissions (uri, setting and userDetail).'
|
||||
tags:
|
||||
- Permission
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
post:
|
||||
operationId: CreatePermission
|
||||
@@ -1757,13 +1847,24 @@ paths:
|
||||
$ref: '#/components/schemas/PermissionDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {permissionId: 123, uri: /SASjsApi/code/execute, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}
|
||||
value:
|
||||
{
|
||||
permissionId: 123,
|
||||
uri: /SASjsApi/code/execute,
|
||||
setting: Grant,
|
||||
user:
|
||||
{
|
||||
id: 1,
|
||||
username: johnSnow01,
|
||||
displayName: 'John Snow',
|
||||
isAdmin: false
|
||||
}
|
||||
}
|
||||
summary: 'Create a new permission. Admin only.'
|
||||
tags:
|
||||
- Permission
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters: []
|
||||
requestBody:
|
||||
required: true
|
||||
@@ -1783,16 +1884,26 @@ paths:
|
||||
$ref: '#/components/schemas/PermissionDetailsResponse'
|
||||
examples:
|
||||
'Example 1':
|
||||
value: {permissionId: 123, uri: /SASjsApi/code/execute, setting: Grant, user: {id: 1, username: johnSnow01, displayName: 'John Snow', isAdmin: false}}
|
||||
value:
|
||||
{
|
||||
permissionId: 123,
|
||||
uri: /SASjsApi/code/execute,
|
||||
setting: Grant,
|
||||
user:
|
||||
{
|
||||
id: 1,
|
||||
username: johnSnow01,
|
||||
displayName: 'John Snow',
|
||||
isAdmin: false
|
||||
}
|
||||
}
|
||||
summary: 'Update permission setting. Admin only'
|
||||
tags:
|
||||
- Permission
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The permission''s identifier'
|
||||
- description: "The permission's identifier"
|
||||
in: path
|
||||
name: permissionId
|
||||
required: true
|
||||
@@ -1815,11 +1926,9 @@ paths:
|
||||
tags:
|
||||
- Permission
|
||||
security:
|
||||
-
|
||||
bearerAuth: []
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
-
|
||||
description: 'The user''s identifier'
|
||||
- description: "The user's identifier"
|
||||
in: path
|
||||
name: permissionId
|
||||
required: true
|
||||
@@ -1828,39 +1937,27 @@ paths:
|
||||
type: number
|
||||
example: 1234
|
||||
servers:
|
||||
-
|
||||
url: /
|
||||
- url: /
|
||||
tags:
|
||||
-
|
||||
name: Auth
|
||||
- name: Auth
|
||||
description: 'Operations about auth'
|
||||
-
|
||||
name: Client
|
||||
- name: Client
|
||||
description: 'Operations about clients'
|
||||
-
|
||||
name: CODE
|
||||
- name: CODE
|
||||
description: 'Execution of code (various runtimes are supported)'
|
||||
-
|
||||
name: Drive
|
||||
- name: Drive
|
||||
description: 'Operations on SASjs Drive'
|
||||
-
|
||||
name: Group
|
||||
- name: Group
|
||||
description: 'Operations on groups and group memberships'
|
||||
-
|
||||
name: Info
|
||||
- name: Info
|
||||
description: 'Get Server Information'
|
||||
-
|
||||
name: Permission
|
||||
- name: Permission
|
||||
description: 'Operations about permissions'
|
||||
-
|
||||
name: Session
|
||||
- name: Session
|
||||
description: 'Get Session information'
|
||||
-
|
||||
name: STP
|
||||
- name: STP
|
||||
description: 'Execution of Stored Programs'
|
||||
-
|
||||
name: User
|
||||
- name: User
|
||||
description: 'Operations with users'
|
||||
-
|
||||
name: Web
|
||||
- name: Web
|
||||
description: 'Operations on Web'
|
||||
|
||||
21
api/src/app-modules/configureCors.ts
Normal file
21
api/src/app-modules/configureCors.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Express } from 'express'
|
||||
import cors from 'cors'
|
||||
import { CorsType } from '../utils'
|
||||
|
||||
export const configureCors = (app: Express) => {
|
||||
const { CORS, WHITELIST } = process.env
|
||||
|
||||
if (CORS === CorsType.ENABLED) {
|
||||
const whiteList: string[] = []
|
||||
WHITELIST?.split(' ')
|
||||
?.filter((url) => !!url)
|
||||
.forEach((url) => {
|
||||
if (url.startsWith('http'))
|
||||
// removing trailing slash of URLs listing for CORS
|
||||
whiteList.push(url.replace(/\/$/, ''))
|
||||
})
|
||||
|
||||
console.log('All CORS Requests are enabled for:', whiteList)
|
||||
app.use(cors({ credentials: true, origin: whiteList }))
|
||||
}
|
||||
}
|
||||
32
api/src/app-modules/configureExpressSession.ts
Normal file
32
api/src/app-modules/configureExpressSession.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Express } from 'express'
|
||||
import mongoose from 'mongoose'
|
||||
import session from 'express-session'
|
||||
import MongoStore from 'connect-mongo'
|
||||
|
||||
import { ModeType } from '../utils'
|
||||
import { cookieOptions } from '../app'
|
||||
|
||||
export const configureExpressSession = (app: Express) => {
|
||||
const { MODE } = process.env
|
||||
|
||||
if (MODE === ModeType.Server) {
|
||||
let store: MongoStore | undefined
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
store = MongoStore.create({
|
||||
client: mongoose.connection!.getClient() as any,
|
||||
collectionName: 'sessions'
|
||||
})
|
||||
}
|
||||
|
||||
app.use(
|
||||
session({
|
||||
secret: process.secrets.SESSION_SECRET,
|
||||
saveUninitialized: false, // don't create session until something stored
|
||||
resave: false, //don't save session if unmodified
|
||||
store,
|
||||
cookie: cookieOptions
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
33
api/src/app-modules/configureLogger.ts
Normal file
33
api/src/app-modules/configureLogger.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import path from 'path'
|
||||
import { Express } from 'express'
|
||||
import morgan from 'morgan'
|
||||
import { createStream } from 'rotating-file-stream'
|
||||
import { generateTimestamp } from '@sasjs/utils'
|
||||
import { getLogFolder } from '../utils'
|
||||
|
||||
export const configureLogger = (app: Express) => {
|
||||
const { LOG_FORMAT_MORGAN } = process.env
|
||||
|
||||
let options
|
||||
if (
|
||||
process.env.NODE_ENV !== 'development' &&
|
||||
process.env.NODE_ENV !== 'test'
|
||||
) {
|
||||
const timestamp = generateTimestamp()
|
||||
const filename = `${timestamp}.log`
|
||||
const logsFolder = getLogFolder()
|
||||
|
||||
// create a rotating write stream
|
||||
var accessLogStream = createStream(filename, {
|
||||
interval: '1d', // rotate daily
|
||||
path: logsFolder
|
||||
})
|
||||
|
||||
console.log('Writing Logs to :', path.join(logsFolder, filename))
|
||||
|
||||
options = { stream: accessLogStream }
|
||||
}
|
||||
|
||||
// setup the logger
|
||||
app.use(morgan(LOG_FORMAT_MORGAN as string, options))
|
||||
}
|
||||
26
api/src/app-modules/configureSecurity.ts
Normal file
26
api/src/app-modules/configureSecurity.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Express } from 'express'
|
||||
import { getEnvCSPDirectives } from '../utils/parseHelmetConfig'
|
||||
import { HelmetCoepType, ProtocolType } from '../utils'
|
||||
import helmet from 'helmet'
|
||||
|
||||
export const configureSecurity = (app: Express) => {
|
||||
const { PROTOCOL, HELMET_CSP_CONFIG_PATH, HELMET_COEP } = process.env
|
||||
|
||||
const cspConfigJson: { [key: string]: string[] | null } = getEnvCSPDirectives(
|
||||
HELMET_CSP_CONFIG_PATH
|
||||
)
|
||||
if (PROTOCOL === ProtocolType.HTTP)
|
||||
cspConfigJson['upgrade-insecure-requests'] = null
|
||||
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
...helmet.contentSecurityPolicy.getDefaultDirectives(),
|
||||
...cspConfigJson
|
||||
}
|
||||
},
|
||||
crossOriginEmbedderPolicy: HELMET_COEP === HelmetCoepType.TRUE
|
||||
})
|
||||
)
|
||||
}
|
||||
4
api/src/app-modules/index.ts
Normal file
4
api/src/app-modules/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './configureCors'
|
||||
export * from './configureExpressSession'
|
||||
export * from './configureLogger'
|
||||
export * from './configureSecurity'
|
||||
123
api/src/app.ts
123
api/src/app.ts
@@ -1,30 +1,26 @@
|
||||
import path from 'path'
|
||||
import express, { ErrorRequestHandler } from 'express'
|
||||
import mongoose from 'mongoose'
|
||||
import csrf from 'csurf'
|
||||
import session from 'express-session'
|
||||
import MongoStore from 'connect-mongo'
|
||||
import morgan from 'morgan'
|
||||
import cookieParser from 'cookie-parser'
|
||||
import dotenv from 'dotenv'
|
||||
import cors from 'cors'
|
||||
import helmet from 'helmet'
|
||||
|
||||
import {
|
||||
copySASjsCore,
|
||||
CorsType,
|
||||
getWebBuildFolder,
|
||||
HelmetCoepType,
|
||||
instantiateLogger,
|
||||
loadAppStreamConfig,
|
||||
ModeType,
|
||||
ProtocolType,
|
||||
ReturnCode,
|
||||
setProcessVariables,
|
||||
setupFolders,
|
||||
verifyEnvVariables
|
||||
} from './utils'
|
||||
import { getEnvCSPDirectives } from './utils/parseHelmetConfig'
|
||||
import {
|
||||
configureCors,
|
||||
configureExpressSession,
|
||||
configureLogger,
|
||||
configureSecurity
|
||||
} from './app-modules'
|
||||
|
||||
dotenv.config()
|
||||
|
||||
@@ -34,19 +30,7 @@ if (verifyEnvVariables()) process.exit(ReturnCode.InvalidEnv)
|
||||
|
||||
const app = express()
|
||||
|
||||
app.use(cookieParser())
|
||||
|
||||
const {
|
||||
MODE,
|
||||
CORS,
|
||||
WHITELIST,
|
||||
PROTOCOL,
|
||||
HELMET_CSP_CONFIG_PATH,
|
||||
HELMET_COEP,
|
||||
LOG_FORMAT_MORGAN
|
||||
} = process.env
|
||||
|
||||
app.use(morgan(LOG_FORMAT_MORGAN as string))
|
||||
const { PROTOCOL } = process.env
|
||||
|
||||
export const cookieOptions = {
|
||||
secure: PROTOCOL === ProtocolType.HTTPS,
|
||||
@@ -54,79 +38,11 @@ export const cookieOptions = {
|
||||
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
||||
}
|
||||
|
||||
const cspConfigJson: { [key: string]: string[] | null } = getEnvCSPDirectives(
|
||||
HELMET_CSP_CONFIG_PATH
|
||||
)
|
||||
if (PROTOCOL === ProtocolType.HTTP)
|
||||
cspConfigJson['upgrade-insecure-requests'] = null
|
||||
|
||||
/***********************************
|
||||
* CSRF Protection *
|
||||
***********************************/
|
||||
export const csrfProtection = csrf({ cookie: cookieOptions })
|
||||
|
||||
/***********************************
|
||||
* Handle security and origin *
|
||||
***********************************/
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
...helmet.contentSecurityPolicy.getDefaultDirectives(),
|
||||
...cspConfigJson
|
||||
}
|
||||
},
|
||||
crossOriginEmbedderPolicy: HELMET_COEP === HelmetCoepType.TRUE
|
||||
})
|
||||
)
|
||||
|
||||
/***********************************
|
||||
* Enabling CORS *
|
||||
***********************************/
|
||||
if (CORS === CorsType.ENABLED) {
|
||||
const whiteList: string[] = []
|
||||
WHITELIST?.split(' ')
|
||||
?.filter((url) => !!url)
|
||||
.forEach((url) => {
|
||||
if (url.startsWith('http'))
|
||||
// removing trailing slash of URLs listing for CORS
|
||||
whiteList.push(url.replace(/\/$/, ''))
|
||||
})
|
||||
|
||||
console.log('All CORS Requests are enabled for:', whiteList)
|
||||
app.use(cors({ credentials: true, origin: whiteList }))
|
||||
}
|
||||
|
||||
export default setProcessVariables().then(async () => {
|
||||
/***********************************
|
||||
* DB Connection & *
|
||||
* Express Sessions *
|
||||
* With Mongo Store *
|
||||
***********************************/
|
||||
if (MODE === ModeType.Server) {
|
||||
let store: MongoStore | undefined
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
store = MongoStore.create({
|
||||
client: mongoose.connection!.getClient() as any,
|
||||
collectionName: 'sessions'
|
||||
})
|
||||
}
|
||||
|
||||
app.use(
|
||||
session({
|
||||
secret: process.secrets.SESSION_SECRET,
|
||||
saveUninitialized: false, // don't create session until something stored
|
||||
resave: false, //don't save session if unmodified
|
||||
store,
|
||||
cookie: cookieOptions
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
app.use(express.json({ limit: '100mb' }))
|
||||
app.use(express.static(path.join(__dirname, '../public')))
|
||||
|
||||
const onError: ErrorRequestHandler = (err, req, res, next) => {
|
||||
if (err.code === 'EBADCSRFTOKEN')
|
||||
return res.status(400).send('Invalid CSRF token!')
|
||||
@@ -135,6 +51,31 @@ export default setProcessVariables().then(async () => {
|
||||
res.status(500).send('Something broke!')
|
||||
}
|
||||
|
||||
export default setProcessVariables().then(async () => {
|
||||
app.use(cookieParser())
|
||||
|
||||
configureLogger(app)
|
||||
|
||||
/***********************************
|
||||
* Handle security and origin *
|
||||
***********************************/
|
||||
configureSecurity(app)
|
||||
|
||||
/***********************************
|
||||
* Enabling CORS *
|
||||
***********************************/
|
||||
configureCors(app)
|
||||
|
||||
/***********************************
|
||||
* DB Connection & *
|
||||
* Express Sessions *
|
||||
* With Mongo Store *
|
||||
***********************************/
|
||||
configureExpressSession(app)
|
||||
|
||||
app.use(express.json({ limit: '100mb' }))
|
||||
app.use(express.static(path.join(__dirname, '../public')))
|
||||
|
||||
await setupFolders()
|
||||
await copySASjsCore()
|
||||
|
||||
|
||||
@@ -101,8 +101,8 @@ ${autoExecContent}`
|
||||
session.path,
|
||||
'-AUTOEXEC',
|
||||
autoExecPath,
|
||||
isWindows() ? '-nosplash' : '',
|
||||
isWindows() ? '-icon' : '',
|
||||
process.sasLoc!.endsWith('sas.exe') ? '-nosplash' : '',
|
||||
process.sasLoc!.endsWith('sas.exe') ? '-icon' : '',
|
||||
isWindows() ? '-nologo' : ''
|
||||
])
|
||||
.then(() => {
|
||||
|
||||
@@ -23,7 +23,9 @@ let _webout = '';
|
||||
const weboutPath = '${
|
||||
isWindows() ? weboutPath.replace(/\\/g, '\\\\') : weboutPath
|
||||
}';
|
||||
const _sasjs_tokenfile = '${tokenFile}';
|
||||
const _sasjs_tokenfile = '${
|
||||
isWindows() ? tokenFile.replace(/\\/g, '\\\\') : tokenFile
|
||||
}';
|
||||
const _sasjs_username = '${preProgramVariables?.username}';
|
||||
const _sasjs_userid = '${preProgramVariables?.userId}';
|
||||
const _sasjs_displayname = '${preProgramVariables?.displayName}';
|
||||
|
||||
1
api/src/types/system/process.d.ts
vendored
1
api/src/types/system/process.d.ts
vendored
@@ -3,6 +3,7 @@ declare namespace NodeJS {
|
||||
sasLoc?: string
|
||||
nodeLoc?: string
|
||||
driveLoc: string
|
||||
logsLoc: string
|
||||
sasSessionController?: import('../../controllers/internal').SASSessionController
|
||||
jsSessionController?: import('../../controllers/internal').JSSessionController
|
||||
appStreamConfig: import('../').AppStreamConfig
|
||||
|
||||
@@ -22,6 +22,8 @@ export const getDesktopUserAutoExecPath = () =>
|
||||
|
||||
export const getSasjsRootFolder = () => process.driveLoc
|
||||
|
||||
export const getLogFolder = () => process.logsLoc
|
||||
|
||||
export const getAppStreamConfigPath = () =>
|
||||
path.join(getSasjsRootFolder(), 'appStreamConfig.json')
|
||||
|
||||
@@ -32,8 +34,6 @@ export const getUploadsFolder = () => path.join(getSasjsRootFolder(), 'uploads')
|
||||
|
||||
export const getFilesFolder = () => path.join(getSasjsRootFolder(), 'files')
|
||||
|
||||
export const getLogFolder = () => path.join(getSasjsRootFolder(), 'logs')
|
||||
|
||||
export const getWeboutFolder = () => path.join(getSasjsRootFolder(), 'webouts')
|
||||
|
||||
export const getSessionsFolder = () =>
|
||||
|
||||
@@ -40,7 +40,16 @@ export const setProcessVariables = async () => {
|
||||
await createFolder(absPath)
|
||||
process.driveLoc = getRealPath(absPath)
|
||||
|
||||
const { LOG_LOCATION } = process.env
|
||||
const absLogsPath = getAbsolutePath(
|
||||
LOG_LOCATION ?? `sasjs_root${path.sep}logs`,
|
||||
process.cwd()
|
||||
)
|
||||
await createFolder(absLogsPath)
|
||||
process.logsLoc = getRealPath(absLogsPath)
|
||||
|
||||
console.log('sasLoc: ', process.sasLoc)
|
||||
console.log('sasDrive: ', process.driveLoc)
|
||||
console.log('sasLogs: ', process.logsLoc)
|
||||
console.log('runTimes: ', process.runTimes)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path'
|
||||
import { MulterFile } from '../types/Upload'
|
||||
import { listFilesInFolder, readFileBinary } from '@sasjs/utils'
|
||||
import { listFilesInFolder, readFileBinary, isWindows } from '@sasjs/utils'
|
||||
|
||||
interface FilenameMapSingle {
|
||||
fieldName: string
|
||||
@@ -118,7 +118,9 @@ export const generateFileUploadJSCode = async (
|
||||
if (fileName.includes('req_file')) {
|
||||
fileCount++
|
||||
const filePath = path.join(sessionFolder, fileName)
|
||||
uploadCode += `\nconst _WEBIN_FILEREF${fileCount} = fs.readFileSync('${filePath}')`
|
||||
uploadCode += `\nconst _WEBIN_FILEREF${fileCount} = fs.readFileSync('${
|
||||
isWindows() ? filePath.replace(/\\/g, '\\\\') : filePath
|
||||
}')`
|
||||
uploadCode += `\nconst _WEBIN_FILENAME${fileCount} = '${filesNamesMap[fileName].originalName}'`
|
||||
uploadCode += `\nconst _WEBIN_NAME${fileCount} = '${filesNamesMap[fileName].fieldName}'`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user