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

feat(certs): ENV variables updated and set CA Root for HTTPS server

This commit is contained in:
Saad Jutt
2022-06-21 03:17:14 +05:00
parent 87dbab98f6
commit 2119e9de9a
12 changed files with 81 additions and 43 deletions

View File

@@ -101,7 +101,8 @@ SASV9_OPTIONS= -NOXCMD
# ENV variables required for PROTOCOL: `https` # ENV variables required for PROTOCOL: `https`
PRIVATE_KEY=privkey.pem PRIVATE_KEY=privkey.pem
FULL_CHAIN=fullchain.pem CERT_CHAIN=certificate.pem
CA_ROOT=fullchain.pem
# ENV variables required for MODE: `server` # ENV variables required for MODE: `server`
ACCESS_TOKEN_SECRET=<secret> ACCESS_TOKEN_SECRET=<secret>

View File

@@ -1,6 +1,8 @@
import path from 'path' import path from 'path'
import fs from 'fs' import fs from 'fs'
import { import {
SASSessionController,
JSSessionController,
getSASSessionController, getSASSessionController,
getJSSessionController, getJSSessionController,
processProgram processProgram
@@ -76,10 +78,19 @@ export class ExecutionController {
session: sessionByFileUpload, session: sessionByFileUpload,
runTime runTime
}: ExecuteProgramParams): Promise<ExecuteReturnRaw | ExecuteReturnJson> { }: ExecuteProgramParams): Promise<ExecuteReturnRaw | ExecuteReturnJson> {
const sessionController = let sessionController: SASSessionController | JSSessionController
runTime === RunTimeType.SAS
? getSASSessionController() switch (runTime) {
: getJSSessionController() case RunTimeType.SAS:
sessionController = getSASSessionController()
break
case RunTimeType.JS:
sessionController = getJSSessionController()
break
default:
throw new Error('No Runtime is configured1')
}
const session = const session =
sessionByFileUpload ?? (await sessionController.getSession()) sessionByFileUpload ?? (await sessionController.getSession())

View File

@@ -1,7 +1,12 @@
import { Request, RequestHandler } from 'express' import { Request, RequestHandler } from 'express'
import multer from 'multer' import multer from 'multer'
import { uuidv4 } from '@sasjs/utils' import { uuidv4 } from '@sasjs/utils'
import { getSASSessionController, getJSSessionController } from '.' import {
SASSessionController,
JSSessionController,
getSASSessionController,
getJSSessionController
} from '.'
import { import {
executeProgramRawValidation, executeProgramRawValidation,
getRunTimeAndFilePath, getRunTimeAndFilePath,
@@ -44,10 +49,19 @@ export class FileUploadController {
}) })
} }
const sessionController = let sessionController: SASSessionController | JSSessionController
runTime === RunTimeType.SAS
? getSASSessionController() switch (runTime) {
: getJSSessionController() case RunTimeType.SAS:
sessionController = getSASSessionController()
break
case RunTimeType.JS:
sessionController = getJSSessionController()
break
default:
return res.status(400).send('No Runtime is configured1')
}
const session = await sessionController.getSession() const session = await sessionController.getSession()
// marking consumed true, so that it's not available // marking consumed true, so that it's not available

View File

@@ -12,7 +12,8 @@ import {
createFile, createFile,
fileExists, fileExists,
generateTimestamp, generateTimestamp,
readFile readFile,
isWindows
} from '@sasjs/utils' } from '@sasjs/utils'
const execFilePromise = promisify(execFile) const execFilePromise = promisify(execFile)
@@ -88,7 +89,7 @@ ${autoExecContent}`
// Additional windows specific options to avoid the desktop popups. // Additional windows specific options to avoid the desktop popups.
execFilePromise(process.sasLoc, [ execFilePromise(process.sasLoc!, [
'-SYSIN', '-SYSIN',
codePath, codePath,
'-LOG', '-LOG',
@@ -99,9 +100,9 @@ ${autoExecContent}`
session.path, session.path,
'-AUTOEXEC', '-AUTOEXEC',
autoExecPath, autoExecPath,
process.platform === 'win32' ? '-nosplash' : '', isWindows() ? '-nosplash' : '',
process.platform === 'win32' ? '-icon' : '', isWindows() ? '-icon' : '',
process.platform === 'win32' ? '-nologo' : '' isWindows() ? '-nologo' : ''
]) ])
.then(() => { .then(() => {
session.completed = true session.completed = true

View File

@@ -1,3 +1,4 @@
import { isWindows } from '@sasjs/utils'
import { PreProgramVars, Session } from '../../types' import { PreProgramVars, Session } from '../../types'
import { generateFileUploadJSCode } from '../../utils' import { generateFileUploadJSCode } from '../../utils'
import { ExecutionVars } from './' import { ExecutionVars } from './'
@@ -20,9 +21,7 @@ export const createJSProgram = async (
const preProgramVarStatments = ` const preProgramVarStatments = `
let _webout = ''; let _webout = '';
const weboutPath = '${ const weboutPath = '${
process.platform === 'win32' isWindows() ? weboutPath.replace(/\\/g, '\\\\') : weboutPath
? weboutPath.replace(/\\/g, '\\\\')
: weboutPath
}'; }';
const _sasjs_tokenfile = '${tokenFile}'; const _sasjs_tokenfile = '${tokenFile}';
const _sasjs_username = '${preProgramVariables?.username}'; const _sasjs_username = '${preProgramVariables?.username}';

View File

@@ -40,7 +40,7 @@ export const processProgram = async (
// waiting for the open event so that we can have underlying file descriptor // waiting for the open event so that we can have underlying file descriptor
await once(writeStream, 'open') await once(writeStream, 'open')
execFileSync(process.nodeLoc, [codePath], { execFileSync(process.nodeLoc!, [codePath], {
stdio: ['ignore', writeStream, writeStream] stdio: ['ignore', writeStream, writeStream]
}) })

View File

@@ -16,9 +16,9 @@ appPromise.then(async (app) => {
) )
}) })
} else { } else {
const { key, cert } = await getCertificates() const { key, cert, ca } = await getCertificates()
const httpsServer = createServer({ key, cert }, app) const httpsServer = createServer({ key, cert, ca }, app)
httpsServer.listen(sasJsPort, () => { httpsServer.listen(sasJsPort, () => {
console.log( console.log(
`⚡️[server]: Server is running at https://localhost:${sasJsPort}` `⚡️[server]: Server is running at https://localhost:${sasJsPort}`

View File

@@ -1,7 +1,7 @@
declare namespace NodeJS { declare namespace NodeJS {
export interface Process { export interface Process {
sasLoc: string sasLoc?: string
nodeLoc: string nodeLoc?: string
driveLoc: string driveLoc: string
sasSessionController?: import('../../controllers/internal').SASSessionController sasSessionController?: import('../../controllers/internal').SASSessionController
jsSessionController?: import('../../controllers/internal').JSSessionController jsSessionController?: import('../../controllers/internal').JSSessionController

View File

@@ -2,22 +2,30 @@ import path from 'path'
import { fileExists, getString, readFile } from '@sasjs/utils' import { fileExists, getString, readFile } from '@sasjs/utils'
export const getCertificates = async () => { export const getCertificates = async () => {
const { PRIVATE_KEY, FULL_CHAIN } = process.env const { PRIVATE_KEY, CERT_CHAIN, CA_ROOT } = process.env
const keyPath = PRIVATE_KEY ?? (await getFileInput('Private Key (PEM)')) const keyPath = PRIVATE_KEY ?? (await getFileInput('Private Key (PEM)'))
const certPath = FULL_CHAIN ?? (await getFileInput('Full Chain (PEM)')) const certPath = CERT_CHAIN ?? (await getFileInput('Certificate Chain (PEM)'))
const caPath = CA_ROOT ?? (await getFileInput('CA ROOT (PEM)'))
console.log('keyPath: ', keyPath) console.log('keyPath: ', keyPath)
console.log('certPath: ', certPath) console.log('certPath: ', certPath)
console.log('caPath: ', caPath)
const key = await readFile(keyPath) const key = await readFile(keyPath)
const cert = await readFile(certPath) const cert = await readFile(certPath)
const ca = await readFile(caPath)
return { key, cert } return { key, cert, ca }
} }
const getFileInput = async (filename: string): Promise<string> => { const getFileInput = async (
filename: string,
required: boolean = true
): Promise<string> => {
const validator = async (filePath: string) => { const validator = async (filePath: string) => {
if (!required) return true
if (!filePath) return `Path to ${filename} is required.` if (!filePath) return `Path to ${filename} is required.`
if (!(await fileExists(path.join(process.cwd(), filePath)))) { if (!(await fileExists(path.join(process.cwd(), filePath)))) {

View File

@@ -1,15 +1,20 @@
import path from 'path' import path from 'path'
import { getString } from '@sasjs/utils/input' import { getString } from '@sasjs/utils/input'
import { createFolder, fileExists, folderExists } from '@sasjs/utils' import { createFolder, fileExists, folderExists, isWindows } from '@sasjs/utils'
import { RunTimeType } from './verifyEnvVariables'
const isWindows = () => process.platform === 'win32'
export const getDesktopFields = async () => { export const getDesktopFields = async () => {
const { SAS_PATH, NODE_PATH } = process.env const { SAS_PATH, NODE_PATH } = process.env
const sasLoc = SAS_PATH ?? (await getSASLocation()) let sasLoc, nodeLoc
const nodeLoc = NODE_PATH ?? (await getNodeLocation())
// const driveLoc = DRIVE_PATH ?? (await getDriveLocation()) if (process.runTimes.includes(RunTimeType.SAS)) {
sasLoc = SAS_PATH ?? (await getSASLocation())
}
if (process.runTimes.includes(RunTimeType.JS)) {
nodeLoc = NODE_PATH ?? (await getNodeLocation())
}
return { sasLoc, nodeLoc } return { sasLoc, nodeLoc }
} }

View File

@@ -9,11 +9,13 @@ export const setProcessVariables = async () => {
return return
} }
const { MODE } = process.env const { MODE, RUN_TIMES } = process.env
process.runTimes = (RUN_TIMES?.split(',') as RunTimeType[]) ?? []
if (MODE === ModeType.Server) { if (MODE === ModeType.Server) {
process.sasLoc = process.env.SAS_PATH as string process.sasLoc = process.env.SAS_PATH
process.nodeLoc = process.env.NODE_PATH as string process.nodeLoc = process.env.NODE_PATH
} else { } else {
const { sasLoc, nodeLoc } = await getDesktopFields() const { sasLoc, nodeLoc } = await getDesktopFields()
@@ -26,9 +28,6 @@ export const setProcessVariables = async () => {
await createFolder(absPath) await createFolder(absPath)
process.driveLoc = getRealPath(absPath) process.driveLoc = getRealPath(absPath)
const { RUN_TIMES } = process.env
process.runTimes = (RUN_TIMES as string).split(',') as RunTimeType[]
console.log('sasLoc: ', process.sasLoc) console.log('sasLoc: ', process.sasLoc)
console.log('sasDrive: ', process.driveLoc) console.log('sasDrive: ', process.driveLoc)
console.log('runTimes: ', process.runTimes) console.log('runTimes: ', process.runTimes)

View File

@@ -129,16 +129,16 @@ const verifyPROTOCOL = (): string[] => {
} }
if (process.env.PROTOCOL === ProtocolType.HTTPS) { if (process.env.PROTOCOL === ProtocolType.HTTPS) {
const { PRIVATE_KEY, FULL_CHAIN } = process.env const { PRIVATE_KEY, CERT_CHAIN } = process.env
if (!PRIVATE_KEY) if (!PRIVATE_KEY)
errors.push( errors.push(
`- PRIVATE_KEY is required for PROTOCOL '${ProtocolType.HTTPS}'` `- PRIVATE_KEY is required for PROTOCOL '${ProtocolType.HTTPS}'`
) )
if (!FULL_CHAIN) if (!CERT_CHAIN)
errors.push( errors.push(
`- FULL_CHAIN is required for PROTOCOL '${ProtocolType.HTTPS}'` `- CERT_CHAIN is required for PROTOCOL '${ProtocolType.HTTPS}'`
) )
} }
@@ -258,5 +258,5 @@ const DEFAULTS = {
PORT: '5000', PORT: '5000',
HELMET_COEP: HelmetCoepType.TRUE, HELMET_COEP: HelmetCoepType.TRUE,
LOG_FORMAT_MORGAN: LOG_FORMAT_MORGANType.Common, LOG_FORMAT_MORGAN: LOG_FORMAT_MORGANType.Common,
RUN_TIMES: `${RunTimeType.SAS}` RUN_TIMES: RunTimeType.SAS
} }