mirror of
https://github.com/sasjs/server.git
synced 2026-01-17 19:00:05 +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)
|
# [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
|
# Docs: https://www.npmjs.com/package/morgan#predefined-formats
|
||||||
LOG_FORMAT_MORGAN=
|
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.
|
# A comma separated string that defines the available runTimes.
|
||||||
# Priority is given to the runtime that comes first in the string.
|
# Priority is given to the runtime that comes first in the string.
|
||||||
# Possible options at the moment are sas and js
|
# 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
|
SASJS_ROOT=./sasjs_root
|
||||||
|
|
||||||
LOG_FORMAT_MORGAN=common
|
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",
|
"initial": "npm run swagger && npm run compileSysInit && npm run copySASjsCore",
|
||||||
"prestart": "npm run initial",
|
"prestart": "npm run initial",
|
||||||
"prebuild": "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",
|
"start:prod": "node ./build/src/server.js",
|
||||||
"build": "rimraf build && tsc",
|
"build": "rimraf build && tsc",
|
||||||
"postbuild": "npm run copy:files",
|
"postbuild": "npm run copy:files",
|
||||||
@@ -63,6 +63,7 @@
|
|||||||
"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",
|
||||||
|
"rotating-file-stream": "^3.0.4",
|
||||||
"swagger-ui-express": "4.3.0",
|
"swagger-ui-express": "4.3.0",
|
||||||
"unzipper": "^0.10.11",
|
"unzipper": "^0.10.11",
|
||||||
"url": "^0.10.3"
|
"url": "^0.10.3"
|
||||||
|
|||||||
@@ -85,10 +85,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
_webout:
|
_webout:
|
||||||
anyOf:
|
anyOf:
|
||||||
-
|
- type: string
|
||||||
type: string
|
- $ref: '#/components/schemas/IRecordOfAny'
|
||||||
-
|
|
||||||
$ref: '#/components/schemas/IRecordOfAny'
|
|
||||||
log:
|
log:
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/LogLine'
|
$ref: '#/components/schemas/LogLine'
|
||||||
@@ -137,12 +135,9 @@ components:
|
|||||||
members:
|
members:
|
||||||
items:
|
items:
|
||||||
anyOf:
|
anyOf:
|
||||||
-
|
- $ref: '#/components/schemas/FolderMember'
|
||||||
$ref: '#/components/schemas/FolderMember'
|
- $ref: '#/components/schemas/ServiceMember'
|
||||||
-
|
- $ref: '#/components/schemas/FileMember'
|
||||||
$ref: '#/components/schemas/ServiceMember'
|
|
||||||
-
|
|
||||||
$ref: '#/components/schemas/FileMember'
|
|
||||||
type: array
|
type: array
|
||||||
required:
|
required:
|
||||||
- name
|
- name
|
||||||
@@ -191,12 +186,9 @@ components:
|
|||||||
members:
|
members:
|
||||||
items:
|
items:
|
||||||
anyOf:
|
anyOf:
|
||||||
-
|
- $ref: '#/components/schemas/FolderMember'
|
||||||
$ref: '#/components/schemas/FolderMember'
|
- $ref: '#/components/schemas/ServiceMember'
|
||||||
-
|
- $ref: '#/components/schemas/FileMember'
|
||||||
$ref: '#/components/schemas/ServiceMember'
|
|
||||||
-
|
|
||||||
$ref: '#/components/schemas/FileMember'
|
|
||||||
type: array
|
type: array
|
||||||
required:
|
required:
|
||||||
- members
|
- members
|
||||||
@@ -382,7 +374,7 @@ components:
|
|||||||
autoExec:
|
autoExec:
|
||||||
type: string
|
type: string
|
||||||
description: 'User-specific auto-exec code'
|
description: 'User-specific auto-exec code'
|
||||||
example: ""
|
example: ''
|
||||||
required:
|
required:
|
||||||
- displayName
|
- displayName
|
||||||
- username
|
- username
|
||||||
@@ -619,7 +611,11 @@ paths:
|
|||||||
$ref: '#/components/schemas/TokenResponse'
|
$ref: '#/components/schemas/TokenResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {accessToken: someRandomCryptoString, refreshToken: someRandomCryptoString}
|
value:
|
||||||
|
{
|
||||||
|
accessToken: someRandomCryptoString,
|
||||||
|
refreshToken: someRandomCryptoString
|
||||||
|
}
|
||||||
summary: 'Accepts client/auth code and returns access/refresh tokens'
|
summary: 'Accepts client/auth code and returns access/refresh tokens'
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- Auth
|
||||||
@@ -643,13 +639,16 @@ paths:
|
|||||||
$ref: '#/components/schemas/TokenResponse'
|
$ref: '#/components/schemas/TokenResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {accessToken: someRandomCryptoString, refreshToken: someRandomCryptoString}
|
value:
|
||||||
|
{
|
||||||
|
accessToken: someRandomCryptoString,
|
||||||
|
refreshToken: someRandomCryptoString
|
||||||
|
}
|
||||||
summary: 'Returns new access/refresh tokens'
|
summary: 'Returns new access/refresh tokens'
|
||||||
tags:
|
tags:
|
||||||
- Auth
|
- Auth
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
/SASjsApi/auth/logout:
|
/SASjsApi/auth/logout:
|
||||||
post:
|
post:
|
||||||
@@ -661,8 +660,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Auth
|
- Auth
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
/SASjsApi/client:
|
/SASjsApi/client:
|
||||||
post:
|
post:
|
||||||
@@ -676,13 +674,16 @@ paths:
|
|||||||
$ref: '#/components/schemas/ClientPayload'
|
$ref: '#/components/schemas/ClientPayload'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {clientId: someFormattedClientID1234, clientSecret: someRandomCryptoString}
|
value:
|
||||||
|
{
|
||||||
|
clientId: someFormattedClientID1234,
|
||||||
|
clientSecret: someRandomCryptoString
|
||||||
|
}
|
||||||
summary: 'Create client with the following attributes: ClientId, ClientSecret. Admin only task.'
|
summary: 'Create client with the following attributes: ClientId, ClientSecret. Admin only task.'
|
||||||
tags:
|
tags:
|
||||||
- Client
|
- Client
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -705,8 +706,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- CODE
|
- CODE
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -726,7 +726,11 @@ paths:
|
|||||||
$ref: '#/components/schemas/DeployResponse'
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {status: success, message: 'Files deployed successfully to @sasjs/server.'}
|
value:
|
||||||
|
{
|
||||||
|
status: success,
|
||||||
|
message: 'Files deployed successfully to @sasjs/server.'
|
||||||
|
}
|
||||||
'400':
|
'400':
|
||||||
description: 'Invalid Format'
|
description: 'Invalid Format'
|
||||||
content:
|
content:
|
||||||
@@ -735,7 +739,11 @@ paths:
|
|||||||
$ref: '#/components/schemas/DeployResponse'
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {status: failure, message: 'Provided not supported data format.'}
|
value:
|
||||||
|
{
|
||||||
|
status: failure,
|
||||||
|
message: 'Provided not supported data format.'
|
||||||
|
}
|
||||||
'500':
|
'500':
|
||||||
description: 'Execution Error'
|
description: 'Execution Error'
|
||||||
content:
|
content:
|
||||||
@@ -749,8 +757,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -770,7 +777,11 @@ paths:
|
|||||||
$ref: '#/components/schemas/DeployResponse'
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {status: success, message: 'Files deployed successfully to @sasjs/server.'}
|
value:
|
||||||
|
{
|
||||||
|
status: success,
|
||||||
|
message: 'Files deployed successfully to @sasjs/server.'
|
||||||
|
}
|
||||||
'400':
|
'400':
|
||||||
description: 'Invalid Format'
|
description: 'Invalid Format'
|
||||||
content:
|
content:
|
||||||
@@ -779,7 +790,11 @@ paths:
|
|||||||
$ref: '#/components/schemas/DeployResponse'
|
$ref: '#/components/schemas/DeployResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'Example 1':
|
||||||
value: {status: failure, message: 'Provided not supported data format.'}
|
value:
|
||||||
|
{
|
||||||
|
status: failure,
|
||||||
|
message: 'Provided not supported data format.'
|
||||||
|
}
|
||||||
'500':
|
'500':
|
||||||
description: 'Execution Error'
|
description: 'Execution Error'
|
||||||
content:
|
content:
|
||||||
@@ -794,8 +809,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -819,11 +833,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- in: query
|
||||||
in: query
|
|
||||||
name: _filePath
|
name: _filePath
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
@@ -846,11 +858,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- in: query
|
||||||
in: query
|
|
||||||
name: _filePath
|
name: _filePath
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
@@ -882,11 +892,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: 'Location of file'
|
||||||
description: 'Location of file'
|
|
||||||
in: query
|
in: query
|
||||||
name: _filePath
|
name: _filePath
|
||||||
required: false
|
required: false
|
||||||
@@ -920,7 +928,7 @@ paths:
|
|||||||
'Example 1':
|
'Example 1':
|
||||||
value: { status: success }
|
value: { status: success }
|
||||||
'403':
|
'403':
|
||||||
description: ""
|
description: ''
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
@@ -933,11 +941,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: 'Location of SAS program'
|
||||||
description: 'Location of SAS program'
|
|
||||||
in: query
|
in: query
|
||||||
name: _filePath
|
name: _filePath
|
||||||
required: false
|
required: false
|
||||||
@@ -978,11 +984,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- in: query
|
||||||
in: query
|
|
||||||
name: _folderPath
|
name: _folderPath
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
@@ -1005,11 +1009,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- in: query
|
||||||
in: query
|
|
||||||
name: _folderPath
|
name: _folderPath
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
@@ -1035,13 +1037,13 @@ paths:
|
|||||||
$ref: '#/components/schemas/FileFolderResponse'
|
$ref: '#/components/schemas/FileFolderResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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'
|
summary: 'Create an empty folder in SASjs Drive'
|
||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -1075,8 +1077,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -1098,8 +1099,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Drive
|
- Drive
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
/SASjsApi/user:
|
/SASjsApi/user:
|
||||||
get:
|
get:
|
||||||
@@ -1115,13 +1115,26 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Get list of all users (username, displayname). All users can request this.'
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
post:
|
post:
|
||||||
operationId: CreateUser
|
operationId: CreateUser
|
||||||
@@ -1134,13 +1147,19 @@ paths:
|
|||||||
$ref: '#/components/schemas/UserDetailsResponse'
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Create user with the following attributes: UserId, UserName, Password, isAdmin, isActive. Admin only task.'
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -1163,11 +1182,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The User's username"
|
||||||
description: 'The User''s username'
|
|
||||||
in: path
|
in: path
|
||||||
name: username
|
name: username
|
||||||
required: true
|
required: true
|
||||||
@@ -1185,16 +1202,21 @@ paths:
|
|||||||
$ref: '#/components/schemas/UserDetailsResponse'
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Update user properties - such as displayName. Can be performed either by admins, or the user in question.'
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The User's username"
|
||||||
description: 'The User''s username'
|
|
||||||
in: path
|
in: path
|
||||||
name: username
|
name: username
|
||||||
required: true
|
required: true
|
||||||
@@ -1216,11 +1238,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The User's username"
|
||||||
description: 'The User''s username'
|
|
||||||
in: path
|
in: path
|
||||||
name: username
|
name: username
|
||||||
required: true
|
required: true
|
||||||
@@ -1251,11 +1271,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The user's identifier"
|
||||||
description: 'The user''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
@@ -1274,16 +1292,21 @@ paths:
|
|||||||
$ref: '#/components/schemas/UserDetailsResponse'
|
$ref: '#/components/schemas/UserDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Update user properties - such as displayName. Can be performed either by admins, or the user in question.'
|
||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The user's identifier"
|
||||||
description: 'The user''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
@@ -1306,11 +1329,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- User
|
- User
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The user's identifier"
|
||||||
description: 'The user''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
@@ -1341,13 +1362,19 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Get list of all groups (groupName and groupDescription). All users can request this.'
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
post:
|
post:
|
||||||
operationId: CreateGroup
|
operationId: CreateGroup
|
||||||
@@ -1360,13 +1387,19 @@ paths:
|
|||||||
$ref: '#/components/schemas/GroupDetailsResponse'
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Create a new group. Admin only.'
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -1388,11 +1421,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The group's name"
|
||||||
description: 'The group''s name'
|
|
||||||
in: path
|
in: path
|
||||||
name: name
|
name: name
|
||||||
required: true
|
required: true
|
||||||
@@ -1412,11 +1443,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The group's identifier"
|
||||||
description: 'The group''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: groupId
|
name: groupId
|
||||||
required: true
|
required: true
|
||||||
@@ -1439,11 +1468,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The group's identifier"
|
||||||
description: 'The group''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: groupId
|
name: groupId
|
||||||
required: true
|
required: true
|
||||||
@@ -1463,16 +1490,21 @@ paths:
|
|||||||
$ref: '#/components/schemas/GroupDetailsResponse'
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Add a user to a group. Admin task only.'
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The group's identifier"
|
||||||
description: 'The group''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: groupId
|
name: groupId
|
||||||
required: true
|
required: true
|
||||||
@@ -1480,8 +1512,7 @@ paths:
|
|||||||
format: double
|
format: double
|
||||||
type: number
|
type: number
|
||||||
example: '1234'
|
example: '1234'
|
||||||
-
|
- description: "The user's identifier"
|
||||||
description: 'The user''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
@@ -1500,16 +1531,21 @@ paths:
|
|||||||
$ref: '#/components/schemas/GroupDetailsResponse'
|
$ref: '#/components/schemas/GroupDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Remove a user to a group. Admin task only.'
|
||||||
tags:
|
tags:
|
||||||
- Group
|
- Group
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The group's identifier"
|
||||||
description: 'The group''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: groupId
|
name: groupId
|
||||||
required: true
|
required: true
|
||||||
@@ -1517,8 +1553,7 @@ paths:
|
|||||||
format: double
|
format: double
|
||||||
type: number
|
type: number
|
||||||
example: '1234'
|
example: '1234'
|
||||||
-
|
- description: "The user's identifier"
|
||||||
description: 'The user''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: userId
|
name: userId
|
||||||
required: true
|
required: true
|
||||||
@@ -1538,7 +1573,14 @@ paths:
|
|||||||
$ref: '#/components/schemas/InfoResponse'
|
$ref: '#/components/schemas/InfoResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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).'
|
summary: 'Get server info (mode, cors, whiteList, protocol).'
|
||||||
tags:
|
tags:
|
||||||
- Info
|
- Info
|
||||||
@@ -1574,13 +1616,18 @@ paths:
|
|||||||
$ref: '#/components/schemas/UserResponse'
|
$ref: '#/components/schemas/UserResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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).'
|
summary: 'Get session info (username).'
|
||||||
tags:
|
tags:
|
||||||
- Session
|
- Session
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
/SASjsApi/stp/execute:
|
/SASjsApi/stp/execute:
|
||||||
get:
|
get:
|
||||||
@@ -1599,11 +1646,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- STP
|
- STP
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: 'Location of SAS or JS code'
|
||||||
description: 'Location of SAS or JS code'
|
|
||||||
in: query
|
in: query
|
||||||
name: _program
|
name: _program
|
||||||
required: true
|
required: true
|
||||||
@@ -1621,17 +1666,25 @@ paths:
|
|||||||
$ref: '#/components/schemas/ExecuteReturnJsonResponse'
|
$ref: '#/components/schemas/ExecuteReturnJsonResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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."
|
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'
|
summary: 'Execute a Stored Program, return a JSON object'
|
||||||
tags:
|
tags:
|
||||||
- STP
|
- STP
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: 'Location of SAS or JS code'
|
||||||
description: 'Location of SAS or JS code'
|
|
||||||
in: query
|
in: query
|
||||||
name: _program
|
name: _program
|
||||||
required: false
|
required: false
|
||||||
@@ -1669,7 +1722,18 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
properties:
|
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 }
|
loggedIn: { type: boolean }
|
||||||
required:
|
required:
|
||||||
- user
|
- user
|
||||||
@@ -1738,13 +1802,39 @@ paths:
|
|||||||
type: array
|
type: array
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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).'
|
summary: 'Get list of all permissions (uri, setting and userDetail).'
|
||||||
tags:
|
tags:
|
||||||
- Permission
|
- Permission
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
post:
|
post:
|
||||||
operationId: CreatePermission
|
operationId: CreatePermission
|
||||||
@@ -1757,13 +1847,24 @@ paths:
|
|||||||
$ref: '#/components/schemas/PermissionDetailsResponse'
|
$ref: '#/components/schemas/PermissionDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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.'
|
summary: 'Create a new permission. Admin only.'
|
||||||
tags:
|
tags:
|
||||||
- Permission
|
- Permission
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters: []
|
parameters: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
@@ -1783,16 +1884,26 @@ paths:
|
|||||||
$ref: '#/components/schemas/PermissionDetailsResponse'
|
$ref: '#/components/schemas/PermissionDetailsResponse'
|
||||||
examples:
|
examples:
|
||||||
'Example 1':
|
'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'
|
summary: 'Update permission setting. Admin only'
|
||||||
tags:
|
tags:
|
||||||
- Permission
|
- Permission
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The permission's identifier"
|
||||||
description: 'The permission''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: permissionId
|
name: permissionId
|
||||||
required: true
|
required: true
|
||||||
@@ -1815,11 +1926,9 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Permission
|
- Permission
|
||||||
security:
|
security:
|
||||||
-
|
- bearerAuth: []
|
||||||
bearerAuth: []
|
|
||||||
parameters:
|
parameters:
|
||||||
-
|
- description: "The user's identifier"
|
||||||
description: 'The user''s identifier'
|
|
||||||
in: path
|
in: path
|
||||||
name: permissionId
|
name: permissionId
|
||||||
required: true
|
required: true
|
||||||
@@ -1828,39 +1937,27 @@ paths:
|
|||||||
type: number
|
type: number
|
||||||
example: 1234
|
example: 1234
|
||||||
servers:
|
servers:
|
||||||
-
|
- url: /
|
||||||
url: /
|
|
||||||
tags:
|
tags:
|
||||||
-
|
- name: Auth
|
||||||
name: Auth
|
|
||||||
description: 'Operations about auth'
|
description: 'Operations about auth'
|
||||||
-
|
- name: Client
|
||||||
name: Client
|
|
||||||
description: 'Operations about clients'
|
description: 'Operations about clients'
|
||||||
-
|
- name: CODE
|
||||||
name: CODE
|
|
||||||
description: 'Execution of code (various runtimes are supported)'
|
description: 'Execution of code (various runtimes are supported)'
|
||||||
-
|
- name: Drive
|
||||||
name: Drive
|
|
||||||
description: 'Operations on SASjs Drive'
|
description: 'Operations on SASjs Drive'
|
||||||
-
|
- name: Group
|
||||||
name: Group
|
|
||||||
description: 'Operations on groups and group memberships'
|
description: 'Operations on groups and group memberships'
|
||||||
-
|
- name: Info
|
||||||
name: Info
|
|
||||||
description: 'Get Server Information'
|
description: 'Get Server Information'
|
||||||
-
|
- name: Permission
|
||||||
name: Permission
|
|
||||||
description: 'Operations about permissions'
|
description: 'Operations about permissions'
|
||||||
-
|
- name: Session
|
||||||
name: Session
|
|
||||||
description: 'Get Session information'
|
description: 'Get Session information'
|
||||||
-
|
- name: STP
|
||||||
name: STP
|
|
||||||
description: 'Execution of Stored Programs'
|
description: 'Execution of Stored Programs'
|
||||||
-
|
- name: User
|
||||||
name: User
|
|
||||||
description: 'Operations with users'
|
description: 'Operations with users'
|
||||||
-
|
- name: Web
|
||||||
name: Web
|
|
||||||
description: 'Operations on 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 path from 'path'
|
||||||
import express, { ErrorRequestHandler } from 'express'
|
import express, { ErrorRequestHandler } from 'express'
|
||||||
import mongoose from 'mongoose'
|
|
||||||
import csrf from 'csurf'
|
import csrf from 'csurf'
|
||||||
import session from 'express-session'
|
|
||||||
import MongoStore from 'connect-mongo'
|
|
||||||
import morgan from 'morgan'
|
|
||||||
import cookieParser from 'cookie-parser'
|
import cookieParser from 'cookie-parser'
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
import cors from 'cors'
|
|
||||||
import helmet from 'helmet'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
copySASjsCore,
|
copySASjsCore,
|
||||||
CorsType,
|
|
||||||
getWebBuildFolder,
|
getWebBuildFolder,
|
||||||
HelmetCoepType,
|
|
||||||
instantiateLogger,
|
instantiateLogger,
|
||||||
loadAppStreamConfig,
|
loadAppStreamConfig,
|
||||||
ModeType,
|
|
||||||
ProtocolType,
|
ProtocolType,
|
||||||
ReturnCode,
|
ReturnCode,
|
||||||
setProcessVariables,
|
setProcessVariables,
|
||||||
setupFolders,
|
setupFolders,
|
||||||
verifyEnvVariables
|
verifyEnvVariables
|
||||||
} from './utils'
|
} from './utils'
|
||||||
import { getEnvCSPDirectives } from './utils/parseHelmetConfig'
|
import {
|
||||||
|
configureCors,
|
||||||
|
configureExpressSession,
|
||||||
|
configureLogger,
|
||||||
|
configureSecurity
|
||||||
|
} from './app-modules'
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
@@ -34,19 +30,7 @@ if (verifyEnvVariables()) process.exit(ReturnCode.InvalidEnv)
|
|||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
app.use(cookieParser())
|
const { PROTOCOL } = process.env
|
||||||
|
|
||||||
const {
|
|
||||||
MODE,
|
|
||||||
CORS,
|
|
||||||
WHITELIST,
|
|
||||||
PROTOCOL,
|
|
||||||
HELMET_CSP_CONFIG_PATH,
|
|
||||||
HELMET_COEP,
|
|
||||||
LOG_FORMAT_MORGAN
|
|
||||||
} = process.env
|
|
||||||
|
|
||||||
app.use(morgan(LOG_FORMAT_MORGAN as string))
|
|
||||||
|
|
||||||
export const cookieOptions = {
|
export const cookieOptions = {
|
||||||
secure: PROTOCOL === ProtocolType.HTTPS,
|
secure: PROTOCOL === ProtocolType.HTTPS,
|
||||||
@@ -54,79 +38,11 @@ export const cookieOptions = {
|
|||||||
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
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 *
|
* CSRF Protection *
|
||||||
***********************************/
|
***********************************/
|
||||||
export const csrfProtection = csrf({ cookie: cookieOptions })
|
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) => {
|
const onError: ErrorRequestHandler = (err, req, res, next) => {
|
||||||
if (err.code === 'EBADCSRFTOKEN')
|
if (err.code === 'EBADCSRFTOKEN')
|
||||||
return res.status(400).send('Invalid CSRF token!')
|
return res.status(400).send('Invalid CSRF token!')
|
||||||
@@ -135,6 +51,31 @@ export default setProcessVariables().then(async () => {
|
|||||||
res.status(500).send('Something broke!')
|
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 setupFolders()
|
||||||
await copySASjsCore()
|
await copySASjsCore()
|
||||||
|
|
||||||
|
|||||||
@@ -101,8 +101,8 @@ ${autoExecContent}`
|
|||||||
session.path,
|
session.path,
|
||||||
'-AUTOEXEC',
|
'-AUTOEXEC',
|
||||||
autoExecPath,
|
autoExecPath,
|
||||||
isWindows() ? '-nosplash' : '',
|
process.sasLoc!.endsWith('sas.exe') ? '-nosplash' : '',
|
||||||
isWindows() ? '-icon' : '',
|
process.sasLoc!.endsWith('sas.exe') ? '-icon' : '',
|
||||||
isWindows() ? '-nologo' : ''
|
isWindows() ? '-nologo' : ''
|
||||||
])
|
])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ let _webout = '';
|
|||||||
const weboutPath = '${
|
const weboutPath = '${
|
||||||
isWindows() ? weboutPath.replace(/\\/g, '\\\\') : 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_username = '${preProgramVariables?.username}';
|
||||||
const _sasjs_userid = '${preProgramVariables?.userId}';
|
const _sasjs_userid = '${preProgramVariables?.userId}';
|
||||||
const _sasjs_displayname = '${preProgramVariables?.displayName}';
|
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
|
sasLoc?: string
|
||||||
nodeLoc?: string
|
nodeLoc?: string
|
||||||
driveLoc: string
|
driveLoc: string
|
||||||
|
logsLoc: string
|
||||||
sasSessionController?: import('../../controllers/internal').SASSessionController
|
sasSessionController?: import('../../controllers/internal').SASSessionController
|
||||||
jsSessionController?: import('../../controllers/internal').JSSessionController
|
jsSessionController?: import('../../controllers/internal').JSSessionController
|
||||||
appStreamConfig: import('../').AppStreamConfig
|
appStreamConfig: import('../').AppStreamConfig
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export const getDesktopUserAutoExecPath = () =>
|
|||||||
|
|
||||||
export const getSasjsRootFolder = () => process.driveLoc
|
export const getSasjsRootFolder = () => process.driveLoc
|
||||||
|
|
||||||
|
export const getLogFolder = () => process.logsLoc
|
||||||
|
|
||||||
export const getAppStreamConfigPath = () =>
|
export const getAppStreamConfigPath = () =>
|
||||||
path.join(getSasjsRootFolder(), 'appStreamConfig.json')
|
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 getFilesFolder = () => path.join(getSasjsRootFolder(), 'files')
|
||||||
|
|
||||||
export const getLogFolder = () => path.join(getSasjsRootFolder(), 'logs')
|
|
||||||
|
|
||||||
export const getWeboutFolder = () => path.join(getSasjsRootFolder(), 'webouts')
|
export const getWeboutFolder = () => path.join(getSasjsRootFolder(), 'webouts')
|
||||||
|
|
||||||
export const getSessionsFolder = () =>
|
export const getSessionsFolder = () =>
|
||||||
|
|||||||
@@ -40,7 +40,16 @@ export const setProcessVariables = async () => {
|
|||||||
await createFolder(absPath)
|
await createFolder(absPath)
|
||||||
process.driveLoc = getRealPath(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('sasLoc: ', process.sasLoc)
|
||||||
console.log('sasDrive: ', process.driveLoc)
|
console.log('sasDrive: ', process.driveLoc)
|
||||||
|
console.log('sasLogs: ', process.logsLoc)
|
||||||
console.log('runTimes: ', process.runTimes)
|
console.log('runTimes: ', process.runTimes)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { MulterFile } from '../types/Upload'
|
import { MulterFile } from '../types/Upload'
|
||||||
import { listFilesInFolder, readFileBinary } from '@sasjs/utils'
|
import { listFilesInFolder, readFileBinary, isWindows } from '@sasjs/utils'
|
||||||
|
|
||||||
interface FilenameMapSingle {
|
interface FilenameMapSingle {
|
||||||
fieldName: string
|
fieldName: string
|
||||||
@@ -118,7 +118,9 @@ export const generateFileUploadJSCode = async (
|
|||||||
if (fileName.includes('req_file')) {
|
if (fileName.includes('req_file')) {
|
||||||
fileCount++
|
fileCount++
|
||||||
const filePath = path.join(sessionFolder, fileName)
|
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_FILENAME${fileCount} = '${filesNamesMap[fileName].originalName}'`
|
||||||
uploadCode += `\nconst _WEBIN_NAME${fileCount} = '${filesNamesMap[fileName].fieldName}'`
|
uploadCode += `\nconst _WEBIN_NAME${fileCount} = '${filesNamesMap[fileName].fieldName}'`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user