mirror of
https://github.com/sasjs/server.git
synced 2025-12-11 03:34:35 +00:00
fix: issue174 + issue175 + issue146
This commit is contained in:
@@ -63,7 +63,7 @@ SAS_PATH=/path/to/sas/executable.exe
|
|||||||
|
|
||||||
# Path to working directory
|
# Path to working directory
|
||||||
# This location is for SAS WORK, staged files, DRIVE, configuration etc
|
# This location is for SAS WORK, staged files, DRIVE, configuration etc
|
||||||
DRIVE_PATH=/tmp
|
SASJS_ROOT=./sasjs_root
|
||||||
|
|
||||||
# options: [http|https] default: http
|
# options: [http|https] default: http
|
||||||
PROTOCOL=
|
PROTOCOL=
|
||||||
@@ -147,7 +147,7 @@ Install the npm package [pm2](https://www.npmjs.com/package/pm2) (`npm install p
|
|||||||
```bash
|
```bash
|
||||||
export SAS_PATH=/opt/sas9/SASHome/SASFoundation/9.4/sasexe/sas
|
export SAS_PATH=/opt/sas9/SASHome/SASFoundation/9.4/sasexe/sas
|
||||||
export PORT=5001
|
export PORT=5001
|
||||||
export DRIVE_PATH=./tmp
|
export SASJS_ROOT=./sasjs_root
|
||||||
|
|
||||||
pm2 start api-linux
|
pm2 start api-linux
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -18,4 +18,4 @@ SESSION_SECRET=<secret>
|
|||||||
DB_CONNECT=mongodb+srv://<DB_USERNAME>:<DB_PASSWORD>@<CLUSTER>/<DB_NAME>?retryWrites=true&w=majority
|
DB_CONNECT=mongodb+srv://<DB_USERNAME>:<DB_PASSWORD>@<CLUSTER>/<DB_NAME>?retryWrites=true&w=majority
|
||||||
|
|
||||||
SAS_PATH=/opt/sas/sas9/SASHome/SASFoundation/9.4/sas
|
SAS_PATH=/opt/sas/sas9/SASHome/SASFoundation/9.4/sas
|
||||||
DRIVE_PATH=./tmp
|
SASJS_ROOT=./sasjs_root
|
||||||
|
|||||||
@@ -94,9 +94,6 @@
|
|||||||
"tsoa": "3.14.1",
|
"tsoa": "3.14.1",
|
||||||
"typescript": "^4.3.2"
|
"typescript": "^4.3.2"
|
||||||
},
|
},
|
||||||
"configuration": {
|
|
||||||
"sasPath": "/opt/sas/sas9/SASHome/SASFoundation/9.4/sas"
|
|
||||||
},
|
|
||||||
"nodemonConfig": {
|
"nodemonConfig": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"tmp/**/*"
|
"tmp/**/*"
|
||||||
|
|||||||
@@ -12,15 +12,28 @@ import helmet from 'helmet'
|
|||||||
import {
|
import {
|
||||||
connectDB,
|
connectDB,
|
||||||
copySASjsCore,
|
copySASjsCore,
|
||||||
getWebBuildFolderPath,
|
CorsType,
|
||||||
|
getWebBuildFolder,
|
||||||
|
HelmetCoepType,
|
||||||
|
instantiateLogger,
|
||||||
loadAppStreamConfig,
|
loadAppStreamConfig,
|
||||||
|
ModeType,
|
||||||
|
ProtocolType,
|
||||||
|
ReturnCode,
|
||||||
setProcessVariables,
|
setProcessVariables,
|
||||||
setupFolders
|
setupFolders,
|
||||||
|
verifyEnvVariables
|
||||||
} from './utils'
|
} from './utils'
|
||||||
import { getEnvCSPDirectives } from './utils/parseHelmetConfig'
|
import { getEnvCSPDirectives } from './utils/parseHelmetConfig'
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config()
|
||||||
|
|
||||||
|
instantiateLogger()
|
||||||
|
|
||||||
|
if (verifyEnvVariables()) {
|
||||||
|
process.exit(ReturnCode.InvalidEnv)
|
||||||
|
}
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
app.use(cookieParser())
|
app.use(cookieParser())
|
||||||
@@ -30,7 +43,7 @@ const { MODE, CORS, WHITELIST, PROTOCOL, HELMET_CSP_CONFIG_PATH, HELMET_COEP } =
|
|||||||
process.env
|
process.env
|
||||||
|
|
||||||
export const cookieOptions = {
|
export const cookieOptions = {
|
||||||
secure: PROTOCOL === 'https',
|
secure: PROTOCOL === ProtocolType.HTTPS,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
||||||
}
|
}
|
||||||
@@ -38,9 +51,8 @@ export const cookieOptions = {
|
|||||||
const cspConfigJson: { [key: string]: string[] | null } = getEnvCSPDirectives(
|
const cspConfigJson: { [key: string]: string[] | null } = getEnvCSPDirectives(
|
||||||
HELMET_CSP_CONFIG_PATH
|
HELMET_CSP_CONFIG_PATH
|
||||||
)
|
)
|
||||||
const coepFlag =
|
if (PROTOCOL === ProtocolType.HTTP)
|
||||||
HELMET_COEP === 'true' || HELMET_COEP === undefined ? true : false
|
cspConfigJson['upgrade-insecure-requests'] = null
|
||||||
if (PROTOCOL === 'http') cspConfigJson['upgrade-insecure-requests'] = null
|
|
||||||
|
|
||||||
/***********************************
|
/***********************************
|
||||||
* CSRF Protection *
|
* CSRF Protection *
|
||||||
@@ -58,14 +70,14 @@ app.use(
|
|||||||
...cspConfigJson
|
...cspConfigJson
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
crossOriginEmbedderPolicy: coepFlag
|
crossOriginEmbedderPolicy: HELMET_COEP === HelmetCoepType.TRUE
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
/***********************************
|
/***********************************
|
||||||
* Enabling CORS *
|
* Enabling CORS *
|
||||||
***********************************/
|
***********************************/
|
||||||
if (MODE?.trim() !== 'server' || CORS?.trim() === 'enable') {
|
if (MODE === ModeType.Server || CORS === CorsType.ENABLED) {
|
||||||
const whiteList: string[] = []
|
const whiteList: string[] = []
|
||||||
WHITELIST?.split(' ')
|
WHITELIST?.split(' ')
|
||||||
?.filter((url) => !!url)
|
?.filter((url) => !!url)
|
||||||
@@ -84,7 +96,7 @@ if (MODE?.trim() !== 'server' || CORS?.trim() === 'enable') {
|
|||||||
* Express Sessions *
|
* Express Sessions *
|
||||||
* With Mongo Store *
|
* With Mongo Store *
|
||||||
***********************************/
|
***********************************/
|
||||||
if (MODE?.trim() === 'server') {
|
if (MODE === ModeType.Server) {
|
||||||
let store: MongoStore | undefined
|
let store: MongoStore | undefined
|
||||||
|
|
||||||
// NOTE: when exporting app.js as agent for supertest
|
// NOTE: when exporting app.js as agent for supertest
|
||||||
@@ -129,7 +141,7 @@ export default setProcessVariables().then(async () => {
|
|||||||
|
|
||||||
// should be served after setting up web route
|
// should be served after setting up web route
|
||||||
// index.html needs to be injected with some js script.
|
// index.html needs to be injected with some js script.
|
||||||
app.use(express.static(getWebBuildFolderPath()))
|
app.use(express.static(getWebBuildFolder()))
|
||||||
|
|
||||||
app.use(onError)
|
app.use(onError)
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import {
|
|||||||
import { createFileTree, ExecutionController, getTreeExample } from './internal'
|
import { createFileTree, ExecutionController, getTreeExample } from './internal'
|
||||||
|
|
||||||
import { TreeNode } from '../types'
|
import { TreeNode } from '../types'
|
||||||
import { getTmpFilesFolderPath } from '../utils'
|
import { getFilesFolder } from '../utils'
|
||||||
|
|
||||||
interface DeployPayload {
|
interface DeployPayload {
|
||||||
appLoc: string
|
appLoc: string
|
||||||
@@ -214,12 +214,12 @@ const getFileTree = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deploy = async (data: DeployPayload) => {
|
const deploy = async (data: DeployPayload) => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
const appLocParts = data.appLoc.replace(/^\//, '').split('/')
|
const appLocParts = data.appLoc.replace(/^\//, '').split('/')
|
||||||
|
|
||||||
const appLocPath = path
|
const appLocPath = path
|
||||||
.join(getTmpFilesFolderPath(), ...appLocParts)
|
.join(getFilesFolder(), ...appLocParts)
|
||||||
.replace(new RegExp('/', 'g'), path.sep)
|
.replace(new RegExp('/', 'g'), path.sep)
|
||||||
|
|
||||||
if (!appLocPath.includes(driveFilesPath)) {
|
if (!appLocPath.includes(driveFilesPath)) {
|
||||||
@@ -238,10 +238,10 @@ const deploy = async (data: DeployPayload) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getFile = async (req: express.Request, filePath: string) => {
|
const getFile = async (req: express.Request, filePath: string) => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
const filePathFull = path
|
const filePathFull = path
|
||||||
.join(getTmpFilesFolderPath(), filePath)
|
.join(getFilesFolder(), filePath)
|
||||||
.replace(new RegExp('/', 'g'), path.sep)
|
.replace(new RegExp('/', 'g'), path.sep)
|
||||||
|
|
||||||
if (!filePathFull.includes(driveFilesPath)) {
|
if (!filePathFull.includes(driveFilesPath)) {
|
||||||
@@ -261,11 +261,11 @@ const getFile = async (req: express.Request, filePath: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getFolder = async (folderPath?: string) => {
|
const getFolder = async (folderPath?: string) => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
if (folderPath) {
|
if (folderPath) {
|
||||||
const folderPathFull = path
|
const folderPathFull = path
|
||||||
.join(getTmpFilesFolderPath(), folderPath)
|
.join(getFilesFolder(), folderPath)
|
||||||
.replace(new RegExp('/', 'g'), path.sep)
|
.replace(new RegExp('/', 'g'), path.sep)
|
||||||
|
|
||||||
if (!folderPathFull.includes(driveFilesPath)) {
|
if (!folderPathFull.includes(driveFilesPath)) {
|
||||||
@@ -291,10 +291,10 @@ const getFolder = async (folderPath?: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const deleteFile = async (filePath: string) => {
|
const deleteFile = async (filePath: string) => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
const filePathFull = path
|
const filePathFull = path
|
||||||
.join(getTmpFilesFolderPath(), filePath)
|
.join(getFilesFolder(), filePath)
|
||||||
.replace(new RegExp('/', 'g'), path.sep)
|
.replace(new RegExp('/', 'g'), path.sep)
|
||||||
|
|
||||||
if (!filePathFull.includes(driveFilesPath)) {
|
if (!filePathFull.includes(driveFilesPath)) {
|
||||||
@@ -314,7 +314,7 @@ const saveFile = async (
|
|||||||
filePath: string,
|
filePath: string,
|
||||||
multerFile: Express.Multer.File
|
multerFile: Express.Multer.File
|
||||||
): Promise<GetFileResponse> => {
|
): Promise<GetFileResponse> => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
const filePathFull = path
|
const filePathFull = path
|
||||||
.join(driveFilesPath, filePath)
|
.join(driveFilesPath, filePath)
|
||||||
@@ -339,7 +339,7 @@ const updateFile = async (
|
|||||||
filePath: string,
|
filePath: string,
|
||||||
multerFile: Express.Multer.File
|
multerFile: Express.Multer.File
|
||||||
): Promise<GetFileResponse> => {
|
): Promise<GetFileResponse> => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
const filePathFull = path
|
const filePathFull = path
|
||||||
.join(driveFilesPath, filePath)
|
.join(driveFilesPath, filePath)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ import { PreProgramVars, Session, TreeNode } from '../../types'
|
|||||||
import {
|
import {
|
||||||
extractHeaders,
|
extractHeaders,
|
||||||
generateFileUploadSasCode,
|
generateFileUploadSasCode,
|
||||||
getTmpFilesFolderPath,
|
getFilesFolder,
|
||||||
getTmpMacrosPath,
|
getMacrosFolder,
|
||||||
HTTPHeaders,
|
HTTPHeaders,
|
||||||
isDebugOn
|
isDebugOn
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
@@ -110,7 +110,7 @@ export class ExecutionController {
|
|||||||
`
|
`
|
||||||
|
|
||||||
program = `
|
program = `
|
||||||
options insert=(SASAUTOS="${getTmpMacrosPath()}");
|
options insert=(SASAUTOS="${getMacrosFolder()}");
|
||||||
|
|
||||||
/* runtime vars */
|
/* runtime vars */
|
||||||
${varStatments}
|
${varStatments}
|
||||||
@@ -191,7 +191,7 @@ ${program}`
|
|||||||
const root: TreeNode = {
|
const root: TreeNode = {
|
||||||
name: 'files',
|
name: 'files',
|
||||||
relativePath: '',
|
relativePath: '',
|
||||||
absolutePath: getTmpFilesFolderPath(),
|
absolutePath: getFilesFolder(),
|
||||||
children: []
|
children: []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Session } from '../../types'
|
|||||||
import { promisify } from 'util'
|
import { promisify } from 'util'
|
||||||
import { execFile } from 'child_process'
|
import { execFile } from 'child_process'
|
||||||
import {
|
import {
|
||||||
getTmpSessionsFolderPath,
|
getSessionsFolder,
|
||||||
generateUniqueFileName,
|
generateUniqueFileName,
|
||||||
sysInitCompiledPath
|
sysInitCompiledPath
|
||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
@@ -37,7 +37,7 @@ export class SessionController {
|
|||||||
|
|
||||||
private async createSession(): Promise<Session> {
|
private async createSession(): Promise<Session> {
|
||||||
const sessionId = generateUniqueFileName(generateTimestamp())
|
const sessionId = generateUniqueFileName(generateTimestamp())
|
||||||
const sessionFolder = path.join(getTmpSessionsFolderPath(), sessionId)
|
const sessionFolder = path.join(getSessionsFolder(), sessionId)
|
||||||
|
|
||||||
const creationTimeStamp = sessionId.split('-').pop() as string
|
const creationTimeStamp = sessionId.split('-').pop() as string
|
||||||
// death time of session is 15 mins from creation
|
// death time of session is 15 mins from creation
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { getTmpFilesFolderPath } from '../../utils/file'
|
import { getFilesFolder } from '../../utils/file'
|
||||||
import {
|
import {
|
||||||
createFolder,
|
createFolder,
|
||||||
createFile,
|
createFile,
|
||||||
@@ -17,7 +17,7 @@ export const createFileTree = async (
|
|||||||
parentFolders: string[] = []
|
parentFolders: string[] = []
|
||||||
) => {
|
) => {
|
||||||
const destinationPath = path.join(
|
const destinationPath = path.join(
|
||||||
getTmpFilesFolderPath(),
|
getFilesFolder(),
|
||||||
path.join(...parentFolders)
|
path.join(...parentFolders)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
} from './internal'
|
} from './internal'
|
||||||
import {
|
import {
|
||||||
getPreProgramVariables,
|
getPreProgramVariables,
|
||||||
getTmpFilesFolderPath,
|
getFilesFolder,
|
||||||
HTTPHeaders,
|
HTTPHeaders,
|
||||||
isDebugOn,
|
isDebugOn,
|
||||||
LogLine,
|
LogLine,
|
||||||
@@ -132,7 +132,7 @@ const executeReturnRaw = async (
|
|||||||
const query = req.query as ExecutionVars
|
const query = req.query as ExecutionVars
|
||||||
const sasCodePath =
|
const sasCodePath =
|
||||||
path
|
path
|
||||||
.join(getTmpFilesFolderPath(), _program)
|
.join(getFilesFolder(), _program)
|
||||||
.replace(new RegExp('/', 'g'), path.sep) + '.sas'
|
.replace(new RegExp('/', 'g'), path.sep) + '.sas'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -172,7 +172,7 @@ const executeReturnJson = async (
|
|||||||
): Promise<ExecuteReturnJsonResponse> => {
|
): Promise<ExecuteReturnJsonResponse> => {
|
||||||
const sasCodePath =
|
const sasCodePath =
|
||||||
path
|
path
|
||||||
.join(getTmpFilesFolderPath(), _program)
|
.join(getFilesFolder(), _program)
|
||||||
.replace(new RegExp('/', 'g'), path.sep) + '.sas'
|
.replace(new RegExp('/', 'g'), path.sep) + '.sas'
|
||||||
|
|
||||||
const filesNamesMap = req.files?.length ? makeFilesNamesMap(req.files) : null
|
const filesNamesMap = req.files?.length ? makeFilesNamesMap(req.files) : null
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { readFile } from '@sasjs/utils'
|
|||||||
|
|
||||||
import User from '../model/User'
|
import User from '../model/User'
|
||||||
import Client from '../model/Client'
|
import Client from '../model/Client'
|
||||||
import { getWebBuildFolderPath, generateAuthCode } from '../utils'
|
import { getWebBuildFolder, generateAuthCode } from '../utils'
|
||||||
import { InfoJWT } from '../types'
|
import { InfoJWT } from '../types'
|
||||||
import { AuthController } from './auth'
|
import { AuthController } from './auth'
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ export class WebController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const home = async () => {
|
const home = async () => {
|
||||||
const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html')
|
const indexHtmlPath = path.join(getWebBuildFolder(), 'index.html')
|
||||||
|
|
||||||
// Attention! Cannot use fileExists here,
|
// Attention! Cannot use fileExists here,
|
||||||
// due to limitation after building executable
|
// due to limitation after building executable
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { Request } from 'express'
|
import { Request } from 'express'
|
||||||
import multer, { FileFilterCallback, Options } from 'multer'
|
import multer, { FileFilterCallback, Options } from 'multer'
|
||||||
import { blockFileRegex, getTmpUploadsPath } from '../utils'
|
import { blockFileRegex, getUploadsFolder } from '../utils'
|
||||||
|
|
||||||
const fieldNameSize = 300
|
const fieldNameSize = 300
|
||||||
const fileSize = 104857600 // 100 MB
|
const fileSize = 104857600 // 100 MB
|
||||||
|
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination: getTmpUploadsPath(),
|
destination: getUploadsFolder(),
|
||||||
filename: function (
|
filename: function (
|
||||||
_req: Request,
|
_req: Request,
|
||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
|
|||||||
@@ -21,17 +21,17 @@ import * as fileUtilModules from '../../../utils/file'
|
|||||||
const timestamp = generateTimestamp()
|
const timestamp = generateTimestamp()
|
||||||
const tmpFolder = path.join(process.cwd(), `tmp-${timestamp}`)
|
const tmpFolder = path.join(process.cwd(), `tmp-${timestamp}`)
|
||||||
jest
|
jest
|
||||||
.spyOn(fileUtilModules, 'getTmpFolderPath')
|
.spyOn(fileUtilModules, 'getSasjsRootFolder')
|
||||||
.mockImplementation(() => tmpFolder)
|
.mockImplementation(() => tmpFolder)
|
||||||
jest
|
jest
|
||||||
.spyOn(fileUtilModules, 'getTmpUploadsPath')
|
.spyOn(fileUtilModules, 'getUploadsFolder')
|
||||||
.mockImplementation(() => path.join(tmpFolder, 'uploads'))
|
.mockImplementation(() => path.join(tmpFolder, 'uploads'))
|
||||||
|
|
||||||
import appPromise from '../../../app'
|
import appPromise from '../../../app'
|
||||||
import { UserController } from '../../../controllers/'
|
import { UserController } from '../../../controllers/'
|
||||||
import { getTreeExample } from '../../../controllers/internal'
|
import { getTreeExample } from '../../../controllers/internal'
|
||||||
import { generateAccessToken, saveTokensInDB } from '../../../utils/'
|
import { generateAccessToken, saveTokensInDB } from '../../../utils/'
|
||||||
const { getTmpFilesFolderPath } = fileUtilModules
|
const { getFilesFolder } = fileUtilModules
|
||||||
|
|
||||||
const clientId = 'someclientID'
|
const clientId = 'someclientID'
|
||||||
const user = {
|
const user = {
|
||||||
@@ -157,10 +157,10 @@ describe('drive', () => {
|
|||||||
expect(res.text).toEqual(
|
expect(res.text).toEqual(
|
||||||
'{"status":"success","message":"Files deployed successfully to @sasjs/server."}'
|
'{"status":"success","message":"Files deployed successfully to @sasjs/server."}'
|
||||||
)
|
)
|
||||||
await expect(folderExists(getTmpFilesFolderPath())).resolves.toEqual(true)
|
await expect(folderExists(getFilesFolder())).resolves.toEqual(true)
|
||||||
|
|
||||||
const testJobFolder = path.join(
|
const testJobFolder = path.join(
|
||||||
getTmpFilesFolderPath(),
|
getFilesFolder(),
|
||||||
'public',
|
'public',
|
||||||
'jobs',
|
'jobs',
|
||||||
'extract'
|
'extract'
|
||||||
@@ -174,7 +174,7 @@ describe('drive', () => {
|
|||||||
|
|
||||||
await expect(readFile(testJobFile)).resolves.toEqual(exampleService.code)
|
await expect(readFile(testJobFile)).resolves.toEqual(exampleService.code)
|
||||||
|
|
||||||
await deleteFolder(path.join(getTmpFilesFolderPath(), 'public'))
|
await deleteFolder(path.join(getFilesFolder(), 'public'))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ describe('drive', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should get a SAS folder on drive having _folderPath as query param', async () => {
|
it('should get a SAS folder on drive having _folderPath as query param', async () => {
|
||||||
const pathToDrive = fileUtilModules.getTmpFilesFolderPath()
|
const pathToDrive = fileUtilModules.getFilesFolder()
|
||||||
|
|
||||||
const dirLevel1 = 'level1'
|
const dirLevel1 = 'level1'
|
||||||
const dirLevel2 = 'level2'
|
const dirLevel2 = 'level2'
|
||||||
@@ -267,10 +267,7 @@ describe('drive', () => {
|
|||||||
const fileToCopyPath = path.join(__dirname, 'files', 'sample.sas')
|
const fileToCopyPath = path.join(__dirname, 'files', 'sample.sas')
|
||||||
const filePath = '/my/path/code.sas'
|
const filePath = '/my/path/code.sas'
|
||||||
|
|
||||||
const pathToCopy = path.join(
|
const pathToCopy = path.join(fileUtilModules.getFilesFolder(), filePath)
|
||||||
fileUtilModules.getTmpFilesFolderPath(),
|
|
||||||
filePath
|
|
||||||
)
|
|
||||||
await copy(fileToCopyPath, pathToCopy)
|
await copy(fileToCopyPath, pathToCopy)
|
||||||
|
|
||||||
const res = await request(app)
|
const res = await request(app)
|
||||||
@@ -333,7 +330,7 @@ describe('drive', () => {
|
|||||||
const pathToUpload = `/my/path/code-${generateTimestamp()}.sas`
|
const pathToUpload = `/my/path/code-${generateTimestamp()}.sas`
|
||||||
|
|
||||||
const pathToCopy = path.join(
|
const pathToCopy = path.join(
|
||||||
fileUtilModules.getTmpFilesFolderPath(),
|
fileUtilModules.getFilesFolder(),
|
||||||
pathToUpload
|
pathToUpload
|
||||||
)
|
)
|
||||||
await copy(fileToAttachPath, pathToCopy)
|
await copy(fileToAttachPath, pathToCopy)
|
||||||
@@ -445,7 +442,7 @@ describe('drive', () => {
|
|||||||
const pathToUpload = '/my/path/code.sas'
|
const pathToUpload = '/my/path/code.sas'
|
||||||
|
|
||||||
const pathToCopy = path.join(
|
const pathToCopy = path.join(
|
||||||
fileUtilModules.getTmpFilesFolderPath(),
|
fileUtilModules.getFilesFolder(),
|
||||||
pathToUpload
|
pathToUpload
|
||||||
)
|
)
|
||||||
await copy(fileToAttachPath, pathToCopy)
|
await copy(fileToAttachPath, pathToCopy)
|
||||||
@@ -467,7 +464,7 @@ describe('drive', () => {
|
|||||||
const pathToUpload = '/my/path/code.sas'
|
const pathToUpload = '/my/path/code.sas'
|
||||||
|
|
||||||
const pathToCopy = path.join(
|
const pathToCopy = path.join(
|
||||||
fileUtilModules.getTmpFilesFolderPath(),
|
fileUtilModules.getFilesFolder(),
|
||||||
pathToUpload
|
pathToUpload
|
||||||
)
|
)
|
||||||
await copy(fileToAttachPath, pathToCopy)
|
await copy(fileToAttachPath, pathToCopy)
|
||||||
@@ -603,10 +600,7 @@ describe('drive', () => {
|
|||||||
const fileToCopyContent = await readFile(fileToCopyPath)
|
const fileToCopyContent = await readFile(fileToCopyPath)
|
||||||
const filePath = '/my/path/code.sas'
|
const filePath = '/my/path/code.sas'
|
||||||
|
|
||||||
const pathToCopy = path.join(
|
const pathToCopy = path.join(fileUtilModules.getFilesFolder(), filePath)
|
||||||
fileUtilModules.getTmpFilesFolderPath(),
|
|
||||||
filePath
|
|
||||||
)
|
|
||||||
await copy(fileToCopyPath, pathToCopy)
|
await copy(fileToCopyPath, pathToCopy)
|
||||||
|
|
||||||
const res = await request(app)
|
const res = await request(app)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import path from 'path'
|
|||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { folderExists } from '@sasjs/utils'
|
import { folderExists } from '@sasjs/utils'
|
||||||
|
|
||||||
import { addEntryToAppStreamConfig, getTmpFilesFolderPath } from '../../utils'
|
import { addEntryToAppStreamConfig, getFilesFolder } from '../../utils'
|
||||||
import { appStreamHtml } from './appStreamHtml'
|
import { appStreamHtml } from './appStreamHtml'
|
||||||
|
|
||||||
const router = express.Router()
|
const router = express.Router()
|
||||||
@@ -22,7 +22,7 @@ export const publishAppStream = async (
|
|||||||
streamLogo?: string,
|
streamLogo?: string,
|
||||||
addEntryToFile: boolean = true
|
addEntryToFile: boolean = true
|
||||||
) => {
|
) => {
|
||||||
const driveFilesPath = getTmpFilesFolderPath()
|
const driveFilesPath = getFilesFolder()
|
||||||
|
|
||||||
const appLocParts = appLoc.replace(/^\//, '')?.split('/')
|
const appLocParts = appLoc.replace(/^\//, '')?.split('/')
|
||||||
const appLocPath = path.join(driveFilesPath, ...appLocParts)
|
const appLocPath = path.join(driveFilesPath, ...appLocParts)
|
||||||
|
|||||||
1
api/src/types/system/process.d.ts
vendored
1
api/src/types/system/process.d.ts
vendored
@@ -4,5 +4,6 @@ declare namespace NodeJS {
|
|||||||
driveLoc: string
|
driveLoc: string
|
||||||
sessionController?: import('../../controllers/internal').SessionController
|
sessionController?: import('../../controllers/internal').SessionController
|
||||||
appStreamConfig: import('../').AppStreamConfig
|
appStreamConfig: import('../').AppStreamConfig
|
||||||
|
logger: import('@sasjs/utils/logger').Logger
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import { createFile, fileExists, readFile } from '@sasjs/utils'
|
|||||||
import { publishAppStream } from '../routes/appStream'
|
import { publishAppStream } from '../routes/appStream'
|
||||||
import { AppStreamConfig } from '../types'
|
import { AppStreamConfig } from '../types'
|
||||||
|
|
||||||
import { getTmpAppStreamConfigPath } from './file'
|
import { getAppStreamConfigPath } from './file'
|
||||||
|
|
||||||
export const loadAppStreamConfig = async () => {
|
export const loadAppStreamConfig = async () => {
|
||||||
if (process.env.NODE_ENV === 'test') return
|
if (process.env.NODE_ENV === 'test') return
|
||||||
|
|
||||||
const appStreamConfigPath = getTmpAppStreamConfigPath()
|
const appStreamConfigPath = getAppStreamConfigPath()
|
||||||
|
|
||||||
const content = (await fileExists(appStreamConfigPath))
|
const content = (await fileExists(appStreamConfigPath))
|
||||||
? await readFile(appStreamConfigPath)
|
? await readFile(appStreamConfigPath)
|
||||||
@@ -63,7 +63,7 @@ export const removeEntryFromAppStreamConfig = (streamServiceName: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const saveAppStreamConfig = async () => {
|
const saveAppStreamConfig = async () => {
|
||||||
const appStreamConfigPath = getTmpAppStreamConfigPath()
|
const appStreamConfigPath = getAppStreamConfigPath()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await createFile(
|
await createFile(
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import {
|
|||||||
readFile
|
readFile
|
||||||
} from '@sasjs/utils'
|
} from '@sasjs/utils'
|
||||||
|
|
||||||
import { getTmpMacrosPath, sasJSCoreMacros, sasJSCoreMacrosInfo } from '.'
|
import { getMacrosFolder, sasJSCoreMacros, sasJSCoreMacrosInfo } from '.'
|
||||||
|
|
||||||
export const copySASjsCore = async () => {
|
export const copySASjsCore = async () => {
|
||||||
if (process.env.NODE_ENV === 'test') return
|
if (process.env.NODE_ENV === 'test') return
|
||||||
|
|
||||||
console.log('Copying Macros from container to drive(tmp).')
|
console.log('Copying Macros from container to drive(tmp).')
|
||||||
|
|
||||||
const macrosDrivePath = getTmpMacrosPath()
|
const macrosDrivePath = getMacrosFolder()
|
||||||
|
|
||||||
await deleteFolder(macrosDrivePath)
|
await deleteFolder(macrosDrivePath)
|
||||||
await createFolder(macrosDrivePath)
|
await createFolder(macrosDrivePath)
|
||||||
|
|||||||
@@ -11,28 +11,26 @@ export const sysInitCompiledPath = path.join(
|
|||||||
export const sasJSCoreMacros = path.join(apiRoot, 'sasjscore')
|
export const sasJSCoreMacros = path.join(apiRoot, 'sasjscore')
|
||||||
export const sasJSCoreMacrosInfo = path.join(sasJSCoreMacros, '.macrolist')
|
export const sasJSCoreMacrosInfo = path.join(sasJSCoreMacros, '.macrolist')
|
||||||
|
|
||||||
export const getWebBuildFolderPath = () =>
|
export const getWebBuildFolder = () => path.join(codebaseRoot, 'web', 'build')
|
||||||
path.join(codebaseRoot, 'web', 'build')
|
|
||||||
|
|
||||||
export const getTmpFolderPath = () => process.driveLoc
|
export const getSasjsRootFolder = () => process.driveLoc
|
||||||
|
|
||||||
export const getTmpAppStreamConfigPath = () =>
|
export const getAppStreamConfigPath = () =>
|
||||||
path.join(getTmpFolderPath(), 'appStreamConfig.json')
|
path.join(getSasjsRootFolder(), 'appStreamConfig.json')
|
||||||
|
|
||||||
export const getTmpMacrosPath = () => path.join(getTmpFolderPath(), 'sasjscore')
|
export const getMacrosFolder = () =>
|
||||||
|
path.join(getSasjsRootFolder(), 'sasjscore')
|
||||||
|
|
||||||
export const getTmpUploadsPath = () => path.join(getTmpFolderPath(), 'uploads')
|
export const getUploadsFolder = () => path.join(getSasjsRootFolder(), 'uploads')
|
||||||
|
|
||||||
export const getTmpFilesFolderPath = () =>
|
export const getFilesFolder = () => path.join(getSasjsRootFolder(), 'files')
|
||||||
path.join(getTmpFolderPath(), 'files')
|
|
||||||
|
|
||||||
export const getTmpLogFolderPath = () => path.join(getTmpFolderPath(), 'logs')
|
export const getLogFolder = () => path.join(getSasjsRootFolder(), 'logs')
|
||||||
|
|
||||||
export const getTmpWeboutFolderPath = () =>
|
export const getWeboutFolder = () => path.join(getSasjsRootFolder(), 'webouts')
|
||||||
path.join(getTmpFolderPath(), 'webouts')
|
|
||||||
|
|
||||||
export const getTmpSessionsFolderPath = () =>
|
export const getSessionsFolder = () =>
|
||||||
path.join(getTmpFolderPath(), 'sessions')
|
path.join(getSasjsRootFolder(), 'sessions')
|
||||||
|
|
||||||
export const generateUniqueFileName = (fileName: string, extension = '') =>
|
export const generateUniqueFileName = (fileName: string, extension = '') =>
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import { createFolder, fileExists, folderExists } from '@sasjs/utils'
|
|||||||
const isWindows = () => process.platform === 'win32'
|
const isWindows = () => process.platform === 'win32'
|
||||||
|
|
||||||
export const getDesktopFields = async () => {
|
export const getDesktopFields = async () => {
|
||||||
const { SAS_PATH, DRIVE_PATH } = process.env
|
const { SAS_PATH } = process.env
|
||||||
|
|
||||||
const sasLoc = SAS_PATH ?? (await getSASLocation())
|
const sasLoc = SAS_PATH ?? (await getSASLocation())
|
||||||
const driveLoc = DRIVE_PATH ?? (await getDriveLocation())
|
// const driveLoc = DRIVE_PATH ?? (await getDriveLocation())
|
||||||
|
|
||||||
return { sasLoc, driveLoc }
|
return { sasLoc }
|
||||||
}
|
}
|
||||||
|
|
||||||
const getDriveLocation = async (): Promise<string> => {
|
const getDriveLocation = async (): Promise<string> => {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export * from './generateRefreshToken'
|
|||||||
export * from './getCertificates'
|
export * from './getCertificates'
|
||||||
export * from './getDesktopFields'
|
export * from './getDesktopFields'
|
||||||
export * from './getPreProgramVariables'
|
export * from './getPreProgramVariables'
|
||||||
|
export * from './instantiateLogger'
|
||||||
export * from './isDebugOn'
|
export * from './isDebugOn'
|
||||||
export * from './parseLogToArray'
|
export * from './parseLogToArray'
|
||||||
export * from './removeTokensInDB'
|
export * from './removeTokensInDB'
|
||||||
@@ -18,4 +19,5 @@ export * from './setProcessVariables'
|
|||||||
export * from './setupFolders'
|
export * from './setupFolders'
|
||||||
export * from './upload'
|
export * from './upload'
|
||||||
export * from './validation'
|
export * from './validation'
|
||||||
|
export * from './verifyEnvVariables'
|
||||||
export * from './verifyTokenInDB'
|
export * from './verifyTokenInDB'
|
||||||
|
|||||||
7
api/src/utils/instantiateLogger.ts
Normal file
7
api/src/utils/instantiateLogger.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { LogLevel, Logger } from '@sasjs/utils/logger'
|
||||||
|
|
||||||
|
export const instantiateLogger = () => {
|
||||||
|
const logLevel = (process.env.LOG_LEVEL || LogLevel.Info) as LogLevel
|
||||||
|
const logger = new Logger(logLevel)
|
||||||
|
process.logger = logger
|
||||||
|
}
|
||||||
@@ -1,30 +1,29 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import { getAbsolutePath, getRealPath } from '@sasjs/utils'
|
import { createFolder, getAbsolutePath, getRealPath } from '@sasjs/utils'
|
||||||
|
|
||||||
import { configuration } from '../../package.json'
|
import { getDesktopFields, ModeType } from '.'
|
||||||
import { getDesktopFields } from '.'
|
|
||||||
|
|
||||||
export const setProcessVariables = async () => {
|
export const setProcessVariables = async () => {
|
||||||
if (process.env.NODE_ENV === 'test') {
|
if (process.env.NODE_ENV === 'test') {
|
||||||
process.driveLoc = path.join(process.cwd(), 'tmp')
|
process.driveLoc = path.join(process.cwd(), 'sasjs_root')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { MODE } = process.env
|
const { MODE } = process.env
|
||||||
|
|
||||||
if (MODE?.trim() === 'server') {
|
if (MODE === ModeType.Server) {
|
||||||
const { SAS_PATH, DRIVE_PATH } = process.env
|
process.sasLoc = process.env.SAS_PATH as string
|
||||||
|
|
||||||
process.sasLoc = SAS_PATH ?? configuration.sasPath
|
|
||||||
const absPath = getAbsolutePath(DRIVE_PATH ?? 'tmp', process.cwd())
|
|
||||||
process.driveLoc = getRealPath(absPath)
|
|
||||||
} else {
|
} else {
|
||||||
const { sasLoc, driveLoc } = await getDesktopFields()
|
const { sasLoc } = await getDesktopFields()
|
||||||
|
|
||||||
process.sasLoc = sasLoc
|
process.sasLoc = sasLoc
|
||||||
process.driveLoc = driveLoc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { SASJS_ROOT } = process.env
|
||||||
|
const absPath = getAbsolutePath(SASJS_ROOT ?? 'sasjs_root', process.cwd())
|
||||||
|
await createFolder(absPath)
|
||||||
|
process.driveLoc = getRealPath(absPath)
|
||||||
|
|
||||||
console.log('sasLoc: ', process.sasLoc)
|
console.log('sasLoc: ', process.sasLoc)
|
||||||
console.log('sasDrive: ', process.driveLoc)
|
console.log('sasDrive: ', process.driveLoc)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { createFolder } from '@sasjs/utils'
|
import { createFolder } from '@sasjs/utils'
|
||||||
import { getTmpFilesFolderPath } from './file'
|
import { getFilesFolder } from './file'
|
||||||
|
|
||||||
export const setupFolders = async () => {
|
export const setupFolders = async () => {
|
||||||
const drivePath = getTmpFilesFolderPath()
|
const drivePath = getFilesFolder()
|
||||||
await createFolder(drivePath)
|
await createFolder(drivePath)
|
||||||
}
|
}
|
||||||
|
|||||||
181
api/src/utils/verifyEnvVariables.ts
Normal file
181
api/src/utils/verifyEnvVariables.ts
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
export enum ModeType {
|
||||||
|
Server = 'server',
|
||||||
|
Desktop = 'desktop'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProtocolType {
|
||||||
|
HTTP = 'http',
|
||||||
|
HTTPS = 'https'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CorsType {
|
||||||
|
ENABLED = 'enable',
|
||||||
|
DISABLED = 'disable'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum HelmetCoepType {
|
||||||
|
TRUE = 'true',
|
||||||
|
FALSE = 'false'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ReturnCode {
|
||||||
|
Success,
|
||||||
|
InvalidEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
export const verifyEnvVariables = (): ReturnCode => {
|
||||||
|
const errors: string[] = []
|
||||||
|
|
||||||
|
errors.push(...verifyMODE())
|
||||||
|
|
||||||
|
errors.push(...verifyPROTOCOL())
|
||||||
|
|
||||||
|
errors.push(...verifyPORT())
|
||||||
|
|
||||||
|
errors.push(...verifyCORS())
|
||||||
|
|
||||||
|
errors.push(...verifyHELMET_COEP())
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
process.logger?.error(
|
||||||
|
`Invalid environment variable(s) provided: \n${errors.join('\n')}`
|
||||||
|
)
|
||||||
|
return ReturnCode.InvalidEnv
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReturnCode.Success
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyMODE = (): string[] => {
|
||||||
|
const errors: string[] = []
|
||||||
|
const { MODE } = process.env
|
||||||
|
|
||||||
|
if (MODE) {
|
||||||
|
const modeTypes = Object.values(ModeType)
|
||||||
|
if (!modeTypes.includes(MODE as ModeType))
|
||||||
|
errors.push(`- MODE '${MODE}'\n - valid options ${modeTypes}`)
|
||||||
|
} else {
|
||||||
|
process.env.MODE = DEFAULTS.MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.MODE === ModeType.Server) {
|
||||||
|
const {
|
||||||
|
ACCESS_TOKEN_SECRET,
|
||||||
|
REFRESH_TOKEN_SECRET,
|
||||||
|
AUTH_CODE_SECRET,
|
||||||
|
SESSION_SECRET,
|
||||||
|
DB_CONNECT
|
||||||
|
} = process.env
|
||||||
|
|
||||||
|
if (!ACCESS_TOKEN_SECRET)
|
||||||
|
errors.push(
|
||||||
|
`- ACCESS_TOKEN_SECRET is required for PROTOCOL '${ModeType.Server}'`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!REFRESH_TOKEN_SECRET)
|
||||||
|
errors.push(
|
||||||
|
`- REFRESH_TOKEN_SECRET is required for PROTOCOL '${ModeType.Server}'`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!AUTH_CODE_SECRET)
|
||||||
|
errors.push(
|
||||||
|
`- AUTH_CODE_SECRET is required for PROTOCOL '${ModeType.Server}'`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!SESSION_SECRET)
|
||||||
|
errors.push(
|
||||||
|
`- SESSION_SECRET is required for PROTOCOL '${ModeType.Server}'`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'test')
|
||||||
|
if (!DB_CONNECT)
|
||||||
|
errors.push(
|
||||||
|
`- DB_CONNECT is required for PROTOCOL '${ModeType.Server}'`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyPROTOCOL = (): string[] => {
|
||||||
|
const errors: string[] = []
|
||||||
|
const { PROTOCOL } = process.env
|
||||||
|
|
||||||
|
if (PROTOCOL) {
|
||||||
|
const protocolTypes = Object.values(ProtocolType)
|
||||||
|
if (!protocolTypes.includes(PROTOCOL as ProtocolType))
|
||||||
|
errors.push(`- PROTOCOL '${PROTOCOL}'\n - valid options ${protocolTypes}`)
|
||||||
|
} else {
|
||||||
|
process.env.PROTOCOL = DEFAULTS.PROTOCOL
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.PROTOCOL === ProtocolType.HTTPS) {
|
||||||
|
const { PRIVATE_KEY, FULL_CHAIN } = process.env
|
||||||
|
|
||||||
|
if (!PRIVATE_KEY)
|
||||||
|
errors.push(
|
||||||
|
`- PRIVATE_KEY is required for PROTOCOL '${ProtocolType.HTTPS}'`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!FULL_CHAIN)
|
||||||
|
errors.push(
|
||||||
|
`- FULL_CHAIN is required for PROTOCOL '${ProtocolType.HTTPS}'`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyCORS = (): string[] => {
|
||||||
|
const errors: string[] = []
|
||||||
|
const { CORS } = process.env
|
||||||
|
|
||||||
|
if (CORS) {
|
||||||
|
const corsTypes = Object.values(CorsType)
|
||||||
|
if (!corsTypes.includes(CORS as CorsType))
|
||||||
|
errors.push(`- CORS '${CORS}'\n - valid options ${corsTypes}`)
|
||||||
|
} else {
|
||||||
|
const { MODE } = process.env
|
||||||
|
process.env.CORS =
|
||||||
|
MODE === ModeType.Server ? CorsType.DISABLED : CorsType.ENABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyPORT = (): string[] => {
|
||||||
|
const errors: string[] = []
|
||||||
|
const { PORT } = process.env
|
||||||
|
|
||||||
|
if (PORT) {
|
||||||
|
if (Number.isNaN(parseInt(PORT)))
|
||||||
|
errors.push(`- PORT '${PORT}'\n - should be a valid number`)
|
||||||
|
} else {
|
||||||
|
process.env.PORT = DEFAULTS.PORT
|
||||||
|
}
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const verifyHELMET_COEP = (): string[] => {
|
||||||
|
const errors: string[] = []
|
||||||
|
const { HELMET_COEP } = process.env
|
||||||
|
|
||||||
|
if (HELMET_COEP) {
|
||||||
|
const helmetCoepTypes = Object.values(HelmetCoepType)
|
||||||
|
if (!helmetCoepTypes.includes(HELMET_COEP as HelmetCoepType))
|
||||||
|
errors.push(
|
||||||
|
`- HELMET_COEP '${HELMET_COEP}'\n - valid options ${helmetCoepTypes}`
|
||||||
|
)
|
||||||
|
HELMET_COEP
|
||||||
|
} else {
|
||||||
|
process.env.HELMET_COEP = DEFAULTS.HELMET_COEP
|
||||||
|
}
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULTS = {
|
||||||
|
MODE: 'desktop',
|
||||||
|
PROTOCOL: 'http',
|
||||||
|
PORT: '5000',
|
||||||
|
HELMET_COEP: 'true'
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user