1
0
mirror of https://github.com/sasjs/server.git synced 2025-12-10 19:34:34 +00:00

Compare commits

...

44 Commits

Author SHA1 Message Date
semantic-release-bot
6a44cd69d9 chore(release): 0.30.3 [skip ci]
## [0.30.3](https://github.com/sasjs/server/compare/v0.30.2...v0.30.3) (2023-03-07)

### Bug Fixes

* add location.pathname to location.origin conditionally ([edab51c](edab51c519))
2023-03-07 10:45:49 +00:00
Allan Bowe
e607115995 Merge pull request #343 from sasjs/quick-fix
fix: add location.pathname to location.origin conditionally
2023-03-07 10:42:07 +00:00
edab51c519 fix: add location.pathname to location.origin conditionally 2023-03-07 15:37:22 +05:00
semantic-release-bot
081cc3102c chore(release): 0.30.2 [skip ci]
## [0.30.2](https://github.com/sasjs/server/compare/v0.30.1...v0.30.2) (2023-03-07)

### Bug Fixes

* **web:** add path to base in launch program url ([2c31922](2c31922f58))
2023-03-07 09:40:13 +00:00
Allan Bowe
b19aa1eba4 Merge pull request #342 from sasjs/quick-fix
fix(web): add path to base in launch program url
2023-03-07 09:35:09 +00:00
2c31922f58 fix(web): add path to base in launch program url 2023-03-07 09:05:29 +05:00
semantic-release-bot
4d7a571a6e chore(release): 0.30.1 [skip ci]
## [0.30.1](https://github.com/sasjs/server/compare/v0.30.0...v0.30.1) (2023-03-01)

### Bug Fixes

* **web:** add proper base url in axios.defaults ([5e3ce8a](5e3ce8a98f))
2023-03-01 18:38:43 +00:00
Allan Bowe
a373a4eb5f Merge pull request #341 from sasjs/base-url
fix(web): add proper base url in axios.defaults
2023-03-01 18:34:55 +00:00
5e3ce8a98f fix(web): add proper base url in axios.defaults 2023-03-01 21:45:18 +05:00
semantic-release-bot
737b34567e chore(release): 0.30.0 [skip ci]
# [0.30.0](https://github.com/sasjs/server/compare/v0.29.0...v0.30.0) (2023-02-28)

### Bug Fixes

* lint + remove default settings ([3de59ac](3de59ac4f8))

### Features

* add new env config DB_TYPE ([158f044](158f044363))
2023-02-28 21:08:30 +00:00
Allan Bowe
6373442f83 Merge pull request #340 from sasjs/issue-339
feat: add new env config DB_TYPE
2023-02-28 21:04:25 +00:00
munja
3de59ac4f8 fix: lint + remove default settings 2023-02-28 21:01:39 +00:00
Allan Bowe
941988cd7c chore(docs): linking to official docs 2023-02-28 20:55:32 +00:00
158f044363 feat: add new env config DB_TYPE 2023-03-01 01:41:08 +05:00
semantic-release-bot
02ae041a81 chore(release): 0.29.0 [skip ci]
# [0.29.0](https://github.com/sasjs/server/compare/v0.28.7...v0.29.0) (2023-02-06)

### Features

* Add /SASjsApi endpoint in permissions ([b3402ea](b3402ea80a))
2023-02-06 13:07:06 +00:00
Allan Bowe
c4c84b1537 Merge pull request #338 from sasjs/issue-224
feat: Add /SASjsApi endpoint in permissions
2023-02-06 13:02:49 +00:00
b3402ea80a feat: Add /SASjsApi endpoint in permissions 2023-02-06 15:29:24 +05:00
semantic-release-bot
abe942e697 chore(release): 0.28.7 [skip ci]
## [0.28.7](https://github.com/sasjs/server/compare/v0.28.6...v0.28.7) (2023-02-03)

### Bug Fixes

* add user to all users group on user creation ([2bae52e](2bae52e307))
2023-02-03 13:48:40 +00:00
Allan Bowe
faf2edb111 Merge pull request #337 from sasjs/issue-336
fix: add user to all users group on user creation
2023-02-03 13:44:46 +00:00
5bec453e89 chore: quick fix 2023-02-03 18:39:35 +05:00
7f2174dd2c chore: quick fix 2023-02-03 16:48:18 +05:00
2bae52e307 fix: add user to all users group on user creation 2023-02-03 16:47:18 +05:00
semantic-release-bot
b243e62ece chore(release): 0.28.6 [skip ci]
## [0.28.6](https://github.com/sasjs/server/compare/v0.28.5...v0.28.6) (2023-01-26)

### Bug Fixes

* show loading spinner on login screen while request is in process ([69f2576](69f2576ee6))
2023-01-26 18:20:28 +00:00
Sabir Hassan
88c3056e97 Merge pull request #335 from sasjs/issue-330
fix: show loading spinner on login screen while request is in process
2023-01-26 23:16:25 +05:00
203303b659 chore: bump the version of mongodb-memory-server 2023-01-26 23:12:46 +05:00
835709bd36 chore: npm audit fix 2023-01-26 23:10:20 +05:00
69f2576ee6 fix: show loading spinner on login screen while request is in process 2023-01-26 22:27:43 +05:00
semantic-release-bot
305077f36e chore(release): 0.28.5 [skip ci]
## [0.28.5](https://github.com/sasjs/server/compare/v0.28.4...v0.28.5) (2023-01-01)

### Bug Fixes

* adding NOPRNGETLIST system option for faster startup ([96eca3a](96eca3a35d))
2023-01-01 16:55:09 +00:00
Allan Bowe
96eca3a35d fix: adding NOPRNGETLIST system option for faster startup 2023-01-01 16:49:48 +00:00
semantic-release-bot
0f5c815c25 chore(release): 0.28.4 [skip ci]
## [0.28.4](https://github.com/sasjs/server/compare/v0.28.3...v0.28.4) (2022-12-07)

### Bug Fixes

* replace main class with container class ([71c429b](71c429b093))
2022-12-07 16:08:32 +00:00
Allan Bowe
acccef1e99 Merge pull request #334 from sasjs/issue-332
fix: Studio Editor autocomplete invisible
2022-12-07 16:04:42 +00:00
abc34ea047 chore: npm audit fix 2022-12-07 20:26:31 +05:00
71c429b093 fix: replace main class with container class 2022-12-07 20:25:06 +05:00
semantic-release-bot
c126f2d5d9 chore(release): 0.28.3 [skip ci]
## [0.28.3](https://github.com/sasjs/server/compare/v0.28.2...v0.28.3) (2022-12-06)

### Bug Fixes

* stringify json file ([1192583](1192583843))
2022-12-06 14:17:01 +00:00
Allan Bowe
34dd95d16e Merge pull request #333 from sasjs/issue-331
fix: stringify json file
2022-12-06 14:11:37 +00:00
1192583843 fix: stringify json file 2022-12-06 18:55:01 +05:00
semantic-release-bot
518815acf1 chore(release): 0.28.2 [skip ci]
## [0.28.2](https://github.com/sasjs/server/compare/v0.28.1...v0.28.2) (2022-12-05)

### Bug Fixes

* execute child process asyncronously ([23c997b](23c997b3be))
* JS / Python / R session folders should be NEW folders, not existing SAS folders ([39ba995](39ba995355))
2022-12-05 16:25:38 +00:00
Allan Bowe
80b7e14ed5 Merge pull request #329 from sasjs/issue-326
fix: non sas programs shouldn't use sas session folder
2022-12-05 16:21:58 +00:00
23c997b3be fix: execute child process asyncronously 2022-12-01 23:27:40 +05:00
39ba995355 fix: JS / Python / R session folders should be NEW folders, not existing SAS folders 2022-12-01 23:26:30 +05:00
semantic-release-bot
0e081e024b chore(release): 0.28.1 [skip ci]
## [0.28.1](https://github.com/sasjs/server/compare/v0.28.0...v0.28.1) (2022-11-28)

### Bug Fixes

* update the content type header after the program has been executed ([4dcee4b](4dcee4b3c3))
2022-11-28 23:25:10 +00:00
Allan Bowe
6a84bd0387 Merge pull request #327 from sasjs/issue-325
fix: default response header fixed when debug is ON
2022-11-28 23:20:30 +00:00
98d177a691 chore: audit fix 2022-11-28 23:55:21 +05:00
4dcee4b3c3 fix: update the content type header after the program has been executed 2022-11-28 23:53:36 +05:00
25 changed files with 3515 additions and 787 deletions

View File

@@ -1,3 +1,93 @@
## [0.30.3](https://github.com/sasjs/server/compare/v0.30.2...v0.30.3) (2023-03-07)
### Bug Fixes
* add location.pathname to location.origin conditionally ([edab51c](https://github.com/sasjs/server/commit/edab51c51997f17553e037dc7c2b5e5fa6ea8ffe))
## [0.30.2](https://github.com/sasjs/server/compare/v0.30.1...v0.30.2) (2023-03-07)
### Bug Fixes
* **web:** add path to base in launch program url ([2c31922](https://github.com/sasjs/server/commit/2c31922f58a8aa20d7fa6bfc95b53a350f90c798))
## [0.30.1](https://github.com/sasjs/server/compare/v0.30.0...v0.30.1) (2023-03-01)
### Bug Fixes
* **web:** add proper base url in axios.defaults ([5e3ce8a](https://github.com/sasjs/server/commit/5e3ce8a98f1825e14c1d26d8da0c9821beeff7b3))
# [0.30.0](https://github.com/sasjs/server/compare/v0.29.0...v0.30.0) (2023-02-28)
### Bug Fixes
* lint + remove default settings ([3de59ac](https://github.com/sasjs/server/commit/3de59ac4f8e3d95cad31f09e6963bd04c4811f26))
### Features
* add new env config DB_TYPE ([158f044](https://github.com/sasjs/server/commit/158f044363abf2576c8248f0ca9da4bc9cb7e9d8))
# [0.29.0](https://github.com/sasjs/server/compare/v0.28.7...v0.29.0) (2023-02-06)
### Features
* Add /SASjsApi endpoint in permissions ([b3402ea](https://github.com/sasjs/server/commit/b3402ea80afb8802eee8b8b6cbbbcc29903424bc))
## [0.28.7](https://github.com/sasjs/server/compare/v0.28.6...v0.28.7) (2023-02-03)
### Bug Fixes
* add user to all users group on user creation ([2bae52e](https://github.com/sasjs/server/commit/2bae52e307327d7ee4a94b19d843abdc0ccec9d1))
## [0.28.6](https://github.com/sasjs/server/compare/v0.28.5...v0.28.6) (2023-01-26)
### Bug Fixes
* show loading spinner on login screen while request is in process ([69f2576](https://github.com/sasjs/server/commit/69f2576ee6d3d7b7f3325922a88656d511e3ac88))
## [0.28.5](https://github.com/sasjs/server/compare/v0.28.4...v0.28.5) (2023-01-01)
### Bug Fixes
* adding NOPRNGETLIST system option for faster startup ([96eca3a](https://github.com/sasjs/server/commit/96eca3a35dce4521150257ee019beb4488c8a08f))
## [0.28.4](https://github.com/sasjs/server/compare/v0.28.3...v0.28.4) (2022-12-07)
### Bug Fixes
* replace main class with container class ([71c429b](https://github.com/sasjs/server/commit/71c429b093b91e2444ae75d946579dccc2e48636))
## [0.28.3](https://github.com/sasjs/server/compare/v0.28.2...v0.28.3) (2022-12-06)
### Bug Fixes
* stringify json file ([1192583](https://github.com/sasjs/server/commit/1192583843d7efd1a6ab6943207f394c3ae966be))
## [0.28.2](https://github.com/sasjs/server/compare/v0.28.1...v0.28.2) (2022-12-05)
### Bug Fixes
* execute child process asyncronously ([23c997b](https://github.com/sasjs/server/commit/23c997b3beabeb6b733ae893031d2f1a48f28ad2))
* JS / Python / R session folders should be NEW folders, not existing SAS folders ([39ba995](https://github.com/sasjs/server/commit/39ba995355daa24bb7ab22720f8fc57d2dc85f40))
## [0.28.1](https://github.com/sasjs/server/compare/v0.28.0...v0.28.1) (2022-11-28)
### Bug Fixes
* update the content type header after the program has been executed ([4dcee4b](https://github.com/sasjs/server/commit/4dcee4b3c3950d402220b8f451c50ad98a317d83))
# [0.28.0](https://github.com/sasjs/server/compare/v0.27.0...v0.28.0) (2022-11-28)

View File

@@ -137,6 +137,9 @@ CA_ROOT=fullchain.pem (optional)
## ENV variables required for MODE: `server`
DB_CONNECT=mongodb+srv://<DB_USERNAME>:<DB_PASSWORD>@<CLUSTER>/<DB_NAME>?retryWrites=true&w=majority
# options: [mongodb|cosmos_mongodb] default: mongodb
DB_TYPE=
# AUTH_PROVIDERS options: [ldap] default: ``
AUTH_PROVIDERS=

View File

@@ -14,6 +14,7 @@ HELMET_CSP_CONFIG_PATH=./csp.config.json if omitted HELMET default will be used
HELMET_COEP=[true|false] if omitted HELMET default will be used
DB_CONNECT=mongodb+srv://<DB_USERNAME>:<DB_PASSWORD>@<CLUSTER>/<DB_NAME>?retryWrites=true&w=majority
DB_TYPE=[mongodb|cosmos_mongodb] default considered as mongodb
AUTH_PROVIDERS=[ldap]

3187
api/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -92,7 +92,7 @@
"dotenv": "^10.0.0",
"http-headers-validation": "^0.0.1",
"jest": "^27.0.6",
"mongodb-memory-server": "^8.0.0",
"mongodb-memory-server": "8.11.4",
"nodejs-file-downloader": "4.10.2",
"nodemon": "^2.0.7",
"pkg": "5.6.0",

View File

@@ -3,19 +3,27 @@ import mongoose from 'mongoose'
import session from 'express-session'
import MongoStore from 'connect-mongo'
import { ModeType, ProtocolType } from '../utils'
import { DatabaseType, ModeType, ProtocolType } from '../utils'
export const configureExpressSession = (app: Express) => {
const { MODE } = process.env
const { MODE, DB_TYPE } = 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'
})
if (DB_TYPE === DatabaseType.COSMOS_MONGODB) {
// COSMOS DB requires specific connection options (compatibility mode)
// See: https://www.npmjs.com/package/connect-mongo#set-the-compatibility-mode
store = MongoStore.create({
client: mongoose.connection!.getClient() as any,
autoRemove: 'interval'
})
} else {
store = MongoStore.create({
client: mongoose.connection!.getClient() as any
})
}
}
const { PROTOCOL, ALLOWED_DOMAIN } = process.env

View File

@@ -159,7 +159,7 @@ const updatePassword = async (
) => {
const { currentPassword, newPassword } = data
const userId = req.user?.userId
const dbUser = await User.findOne({ userId })
const dbUser = await User.findOne({ id: userId })
if (!dbUser)
throw {

View File

@@ -79,10 +79,6 @@ export class ExecutionController {
const logPath = path.join(session.path, 'log.log')
const headersPath = path.join(session.path, 'stpsrv_header.txt')
if (isDebugOn(vars)) {
await createFile(headersPath, 'content-type: text/plain')
}
const weboutPath = path.join(session.path, 'webout.txt')
const tokenFile = path.join(session.path, 'reqHeaders.txt')
@@ -110,6 +106,11 @@ export class ExecutionController {
? await readFile(headersPath)
: ''
const httpHeaders: HTTPHeaders = extractHeaders(headersContent)
if (isDebugOn(vars)) {
httpHeaders['content-type'] = 'text/plain'
}
const fileResponse: boolean = httpHeaders.hasOwnProperty('content-type')
const webout = (await fileExists(weboutPath))

View File

@@ -94,7 +94,7 @@ export class SASSessionController extends SessionController {
}
const headersPath = path.join(session.path, 'stpsrv_header.txt')
await createFile(headersPath, 'content-type: text/html; charset=utf-8')
await createFile(headersPath, 'content-type: text/html; charset=utf-8\n')
// we do not want to leave sessions running forever
// we clean them up after a predefined period, if unused
@@ -140,6 +140,7 @@ ${autoExecContent}`
process.sasLoc!.endsWith('sas.exe') ? '-nodms' : '',
process.sasLoc!.endsWith('sas.exe') ? '-noterminal' : '',
process.sasLoc!.endsWith('sas.exe') ? '-nostatuswin' : '',
process.sasLoc!.endsWith('sas.exe') ? '-NOPRNGETLIST' : '',
process.sasLoc!.endsWith('sas.exe') ? '-SASINITIALFOLDER' : '',
process.sasLoc!.endsWith('sas.exe') ? session.path : ''
])
@@ -206,12 +207,15 @@ ${autoExecContent}`
export const getSessionController = (
runTime: RunTimeType
): SessionController => {
if (process.sessionController) return process.sessionController
if (runTime === RunTimeType.SAS) {
process.sasSessionController =
process.sasSessionController || new SASSessionController()
return process.sasSessionController
}
process.sessionController =
runTime === RunTimeType.SAS
? new SASSessionController()
: new SessionController()
process.sessionController || new SessionController()
return process.sessionController
}

View File

@@ -1,6 +1,6 @@
import path from 'path'
import fs from 'fs'
import { execFileSync } from 'child_process'
import { WriteStream, createWriteStream } from 'fs'
import { execFile } from 'child_process'
import { once } from 'stream'
import { createFile, moveFile } from '@sasjs/utils'
import { PreProgramVars, Session } from '../../types'
@@ -105,26 +105,58 @@ export const processProgram = async (
throw new Error('Invalid runtime!')
}
try {
await createFile(codePath, program)
await createFile(codePath, program)
// create a stream that will write to console outputs to log file
const writeStream = fs.createWriteStream(logPath)
// waiting for the open event so that we can have underlying file descriptor
await once(writeStream, 'open')
execFileSync(executablePath, [codePath], {
stdio: ['ignore', writeStream, writeStream]
// create a stream that will write to console outputs to log file
const writeStream = createWriteStream(logPath)
// waiting for the open event so that we can have underlying file descriptor
await once(writeStream, 'open')
await execFilePromise(executablePath, [codePath], writeStream)
.then(() => {
session.completed = true
process.logger.info('session completed', session)
})
// copy the code file to log and end write stream
writeStream.end(program)
session.completed = true
process.logger.info('session completed', session)
} catch (err: any) {
session.completed = true
session.crashed = err.toString()
process.logger.error('session crashed', session.id, session.crashed)
}
.catch((err) => {
session.completed = true
session.crashed = err.toString()
process.logger.error('session crashed', session.id, session.crashed)
})
// copy the code file to log and end write stream
writeStream.end(program)
}
}
/**
* Promisified child_process.execFile
*
* @param file - The name or path of the executable file to run.
* @param args - List of string arguments.
* @param writeStream - Child process stdout and stderr will be piped to it.
*
* @returns {Promise<{ stdout: string, stderr: string }>}
*/
const execFilePromise = (
file: string,
args: string[],
writeStream: WriteStream
): Promise<{ stdout: string; stderr: string }> => {
return new Promise((resolve, reject) => {
const child = execFile(file, args, (err, stdout, stderr) => {
if (err) reject(err)
resolve({ stdout, stderr })
})
child.stdout?.on('data', (data) => {
writeStream.write(data)
})
child.stderr?.on('data', (data) => {
writeStream.write(data)
})
})
}
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

View File

@@ -21,9 +21,9 @@ import {
getUserAutoExec,
updateUserAutoExec,
ModeType,
AuthProviderType
ALL_USERS_GROUP
} from '../utils'
import { GroupResponse } from './group'
import { GroupController, GroupResponse } from './group'
export interface UserResponse {
id: number
@@ -237,6 +237,15 @@ const createUser = async (data: UserPayload): Promise<UserDetailsResponse> => {
const savedUser = await user.save()
const groupController = new GroupController()
const allUsersGroup = await groupController
.getGroupByGroupName(ALL_USERS_GROUP.name)
.catch(() => {})
if (allUsersGroup) {
await groupController.addUserToGroup(allUsersGroup.groupId, savedUser.id)
}
return {
id: savedUser.id,
displayName: savedUser.displayName,

View File

@@ -5,7 +5,7 @@ import {
PermissionSettingForRoute,
PermissionType
} from '../controllers/permission'
import { getPath, isPublicRoute } from '../utils'
import { getPath, isPublicRoute, TopLevelRoutes } from '../utils'
export const authorize: RequestHandler = async (req, res, next) => {
const { user } = req
@@ -22,6 +22,9 @@ export const authorize: RequestHandler = async (req, res, next) => {
if (!dbUser) return res.sendStatus(401)
const path = getPath(req)
const { baseUrl } = req
const topLevelRoute =
TopLevelRoutes.find((route) => baseUrl.startsWith(route)) || baseUrl
// find permission w.r.t user
const permission = await Permission.findOne({
@@ -35,6 +38,21 @@ export const authorize: RequestHandler = async (req, res, next) => {
else return res.sendStatus(401)
}
// find permission w.r.t user on top level
const topLevelPermission = await Permission.findOne({
path: topLevelRoute,
type: PermissionType.route,
user: dbUser._id
})
if (topLevelPermission) {
if (topLevelPermission.setting === PermissionSettingForRoute.grant)
return next()
else return res.sendStatus(401)
}
let isPermissionDenied = false
// find permission w.r.t user's groups
for (const group of dbUser.groups) {
const groupPermission = await Permission.findOne({
@@ -42,8 +60,28 @@ export const authorize: RequestHandler = async (req, res, next) => {
type: PermissionType.route,
group
})
if (groupPermission?.setting === PermissionSettingForRoute.grant)
return next()
if (groupPermission) {
if (groupPermission.setting === PermissionSettingForRoute.grant) {
return next()
} else {
isPermissionDenied = true
}
}
}
if (!isPermissionDenied) {
// find permission w.r.t user's groups on top level
for (const group of dbUser.groups) {
const groupPermission = await Permission.findOne({
path: topLevelRoute,
type: PermissionType.route,
group
})
if (groupPermission?.setting === PermissionSettingForRoute.grant)
return next()
}
}
return res.sendStatus(401)
}

View File

@@ -9,6 +9,7 @@ declare namespace NodeJS {
logsLoc: string
logsUUID: string
sessionController?: import('../../controllers/internal').SessionController
sasSessionController?: import('../../controllers/internal').SASSessionController
appStreamConfig: import('../').AppStreamConfig
logger: import('@sasjs/utils/logger').Logger
runTimes: import('../../utils').RunTimeType[]

View File

@@ -1,7 +1,8 @@
import { Request } from 'express'
export const TopLevelRoutes = ['/AppStream', '/SASjsApi']
const StaticAuthorizedRoutes = [
'/AppStream',
'/SASjsApi/code/execute',
'/SASjsApi/stp/execute',
'/SASjsApi/drive/deploy',
@@ -15,7 +16,7 @@ const StaticAuthorizedRoutes = [
export const getAuthorizedRoutes = () => {
const streamingApps = Object.keys(process.appStreamConfig)
const streamingAppsRoutes = streamingApps.map((app) => `/AppStream/${app}`)
return [...StaticAuthorizedRoutes, ...streamingAppsRoutes]
return [...TopLevelRoutes, ...StaticAuthorizedRoutes, ...streamingAppsRoutes]
}
export const getPath = (req: Request) => {

View File

@@ -23,12 +23,12 @@ export const seedDB = async (): Promise<ConfigurationType> => {
}
// Checking if 'AllUsers' Group is already in the database
let groupExist = await Group.findOne({ name: GROUP.name })
let groupExist = await Group.findOne({ name: ALL_USERS_GROUP.name })
if (!groupExist) {
const group = new Group(GROUP)
const group = new Group(ALL_USERS_GROUP)
groupExist = await group.save()
process.logger.success(`DB Seed - Group created: ${GROUP.name}`)
process.logger.success(`DB Seed - Group created: ${ALL_USERS_GROUP.name}`)
}
// Checking if 'Public' Group is already in the database
@@ -54,7 +54,7 @@ export const seedDB = async (): Promise<ConfigurationType> => {
if (!groupExist.hasUser(usernameExist)) {
groupExist.addUser(usernameExist)
process.logger.success(
`DB Seed - admin account '${ADMIN_USER.username}' added to Group '${GROUP.name}'`
`DB Seed - admin account '${ADMIN_USER.username}' added to Group '${ALL_USERS_GROUP.name}'`
)
}
@@ -75,7 +75,7 @@ export const seedDB = async (): Promise<ConfigurationType> => {
}
}
const GROUP = {
export const ALL_USERS_GROUP = {
name: 'AllUsers',
description: 'Group contains all users'
}

View File

@@ -47,6 +47,11 @@ export enum ReturnCode {
InvalidEnv
}
export enum DatabaseType {
MONGO = 'mongodb',
COSMOS_MONGODB = 'cosmos_mongodb'
}
export const verifyEnvVariables = (): ReturnCode => {
const errors: string[] = []
@@ -70,6 +75,8 @@ export const verifyEnvVariables = (): ReturnCode => {
errors.push(...verifyLDAPVariables())
errors.push(...verifyDbType())
if (errors.length) {
process.logger?.error(
`Invalid environment variable(s) provided: \n${errors.join('\n')}`
@@ -342,11 +349,30 @@ const verifyLDAPVariables = () => {
return errors
}
const verifyDbType = () => {
const errors: string[] = []
const { MODE, DB_TYPE } = process.env
if (MODE === ModeType.Server) {
if (DB_TYPE) {
const dbTypes = Object.values(DatabaseType)
if (!dbTypes.includes(DB_TYPE as DatabaseType))
errors.push(`- DB_TYPE '${DB_TYPE}'\n - valid options ${dbTypes}`)
} else {
process.env.DB_TYPE = DEFAULTS.DB_TYPE
}
}
return errors
}
const DEFAULTS = {
MODE: ModeType.Desktop,
PROTOCOL: ProtocolType.HTTP,
PORT: '5000',
HELMET_COEP: HelmetCoepType.TRUE,
LOG_FORMAT_MORGAN: LOG_FORMAT_MORGANType.Common,
RUN_TIMES: RunTimeType.SAS
RUN_TIMES: RunTimeType.SAS,
DB_TYPE: DatabaseType.MONGO
}

680
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ import Box from '@mui/material/Box'
const Home = () => {
return (
<Box className="main">
<Box className="container">
<CssBaseline />
<h2>Welcome to SASjs Server!</h2>
<p>

View File

@@ -2,7 +2,14 @@ import axios from 'axios'
import React, { useState, useContext } from 'react'
import PropTypes from 'prop-types'
import { CssBaseline, Box, TextField, Button } from '@mui/material'
import {
Backdrop,
CircularProgress,
CssBaseline,
Box,
TextField,
Button
} from '@mui/material'
import { AppContext } from '../context/appContext'
const login = async (payload: { username: string; password: string }) =>
@@ -10,21 +17,27 @@ const login = async (payload: { username: string; password: string }) =>
const Login = () => {
const appContext = useContext(AppContext)
const [isLoading, setIsLoading] = useState(false)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [errorMessage, setErrorMessage] = useState('')
const handleSubmit = async (e: any) => {
setIsLoading(true)
setErrorMessage('')
e.preventDefault()
const { loggedIn, user } = await login({
username,
password
}).catch((err: any) => {
setErrorMessage(err.response?.data || err.toString())
return {}
})
.catch((err: any) => {
setErrorMessage(err.response?.data || err.toString())
return {}
})
.finally(() => {
setIsLoading(false)
})
if (loggedIn) {
appContext.setUserId?.(user.id)
@@ -37,42 +50,51 @@ const Login = () => {
}
return (
<Box
className="main"
component="form"
onSubmit={handleSubmit}
sx={{
'& > :not(style)': { m: 1, width: '25ch' }
}}
>
<CssBaseline />
<br />
<h2 style={{ width: 'auto' }}>Welcome to SASjs Server!</h2>
<TextField
id="username"
label="Username"
type="text"
variant="outlined"
onChange={(e: any) => setUsername(e.target.value)}
required
/>
<TextField
id="password"
label="Password"
type="password"
variant="outlined"
onChange={(e: any) => setPassword(e.target.value)}
required
/>
{errorMessage && <span>{errorMessage}</span>}
<Button
type="submit"
variant="outlined"
disabled={!appContext.setLoggedIn}
<>
<Backdrop
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={isLoading}
>
Submit
</Button>
</Box>
<CircularProgress color="inherit" />
</Backdrop>
<Box
className="container"
component="form"
onSubmit={handleSubmit}
sx={{
'& > :not(style)': { m: 1, width: '25ch' }
}}
>
<CssBaseline />
<br />
<h2 style={{ width: 'auto' }}>Welcome to SASjs Server!</h2>
<TextField
id="username"
label="Username"
type="text"
variant="outlined"
onChange={(e: any) => setUsername(e.target.value)}
required
/>
<TextField
id="password"
label="Password"
type="password"
variant="outlined"
onChange={(e: any) => setPassword(e.target.value)}
required
/>
{errorMessage && <span>{errorMessage}</span>}
<Button
type="submit"
variant="outlined"
disabled={!appContext.setLoggedIn}
>
Submit
</Button>
</Box>
</>
)
}

View File

@@ -69,7 +69,7 @@ const UpdatePassword = () => {
/>
) : (
<Box
className="main"
className="container"
component="form"
onSubmit={handleSubmit}
sx={{

View File

@@ -47,7 +47,7 @@ const AuthCode = () => {
}
return (
<Box className="main">
<Box className="container">
<CssBaseline />
<br />
<h2>Authorization Code</h2>

View File

@@ -31,7 +31,10 @@ const RunMenu = ({
handleRunBtnClick
}: RunMenuProps) => {
const launchProgram = () => {
const baseUrl = window.location.origin
const pathName =
window.location.pathname === '/' ? '' : window.location.pathname
const baseUrl = window.location.origin + pathName
window.open(`${baseUrl}/SASjsApi/stp/execute?_program=${selectedFilePath}`)
}

View File

@@ -261,8 +261,10 @@ const useEditor = ({
axios
.get(`/SASjsApi/drive/file?_filePath=${selectedFilePath}`)
.then((res: any) => {
setPrevFileContent(res.data)
setFileContent(res.data)
const content =
typeof res.data === 'object' ? JSON.stringify(res.data) : res.data
setPrevFileContent(content)
setFileContent(content)
})
.catch((err) => {
setModalTitle('Abort')

View File

@@ -12,7 +12,7 @@ code {
monospace;
}
.main {
.container {
margin: 50px 10px 0 10px;
display: flex;
flex-direction: column;

View File

@@ -9,7 +9,9 @@ import axios from 'axios'
const NODE_ENV = process.env.NODE_ENV
const PORT_API = process.env.PORT_API
const baseUrl =
NODE_ENV === 'development' ? `http://localhost:${PORT_API ?? 5000}` : ''
NODE_ENV === 'development'
? `http://localhost:${PORT_API ?? 5000}`
: window.location.origin + window.location.pathname
axios.defaults = Object.assign(axios.defaults, {
withCredentials: true,