From 95843fa4c711aa695ee63ad265b8def4ba56360d Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sun, 6 Mar 2022 01:57:14 +0500 Subject: [PATCH 1/2] fix: macros are available Sessions with SASAUTOS --- .gitignore | 1 + api/package.json | 8 +++++--- api/scripts/compileSysInit.ts | 1 - api/scripts/copySASjsCore.ts | 25 +++++++++++++++++++++++ api/src/controllers/internal/Execution.ts | 5 ++++- api/src/controllers/internal/Session.ts | 5 ++++- api/src/utils/file.ts | 2 ++ 7 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 api/scripts/copySASjsCore.ts diff --git a/.gitignore b/.gitignore index 3d08c5d..00a8877 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ sas/ tmp/ build/ sasjsbuild/ +sasjscore/ certificates/ executables/ .env diff --git a/api/package.json b/api/package.json index 02ba0b2..b08c4f5 100644 --- a/api/package.json +++ b/api/package.json @@ -4,7 +4,7 @@ "description": "Api of SASjs server", "main": "./src/server.ts", "scripts": { - "initial": "npm run swagger && npm run compileSysInit", + "initial": "npm run swagger && npm run compileSysInit && npm run copySASjsCore", "prestart": "npm run initial", "prebuild": "npm run initial", "start": "nodemon ./src/server.ts", @@ -16,11 +16,13 @@ "lint": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"", "package:lib": "npm run build && cp ./package.json build && cp README.md build && cd build && npm version \"5.0.0\" && npm pack", "exe": "npm run build && npm run exe:copy && pkg .", - "exe:copy": "npm run public:copy && npm run sasjsbuild:copy && npm run web:copy", + "exe:copy": "npm run public:copy && npm run sasjsbuild:copy && npm run sasjscore:copy && npm run web:copy", "public:copy": "cp -r ./public/ ./build/public/", "sasjsbuild:copy": "cp -r ./sasjsbuild/ ./build/sasjsbuild/", + "sasjscore:copy": "cp -r ./sasjscore/ ./build/sasjscore/", "web:copy": "rimraf web && mkdir web && cp -r ../web/build/ ./web/build/", - "compileSysInit": "ts-node ./scripts/compileSysInit.ts" + "compileSysInit": "ts-node ./scripts/compileSysInit.ts", + "copySASjsCore": "ts-node ./scripts/copySASjsCore.ts" }, "bin": "./build/src/server.js", "pkg": { diff --git a/api/scripts/compileSysInit.ts b/api/scripts/compileSysInit.ts index 2aa5443..58438e7 100644 --- a/api/scripts/compileSysInit.ts +++ b/api/scripts/compileSysInit.ts @@ -21,7 +21,6 @@ const compiledSystemInit = async (systemInit: string) => })) const createSysInitFile = async () => { - console.log('macroCorePath', macroCorePath) const systemInitContent = await readFile( path.join(__dirname, 'systemInit.sas') ) diff --git a/api/scripts/copySASjsCore.ts b/api/scripts/copySASjsCore.ts new file mode 100644 index 0000000..a6f5d70 --- /dev/null +++ b/api/scripts/copySASjsCore.ts @@ -0,0 +1,25 @@ +import path from 'path' +import { asyncForEach, copy, createFolder, deleteFolder } from '@sasjs/utils' + +import { apiRoot, sasJSCoreMacros } from '../src/utils' + +const macroCorePath = path.join(apiRoot, 'node_modules', '@sasjs', 'core') + +export const copySASjsCore = async () => { + await deleteFolder(sasJSCoreMacros) + await createFolder(sasJSCoreMacros) + + console.log('Copying SASjs Core Macros...') + + const foldersToCopy = ['base', 'ddl', 'fcmp', 'lua', 'server'] + + await asyncForEach(foldersToCopy, async (coreSubFolder) => { + const coreSubFolderPath = path.join(macroCorePath, coreSubFolder) + + await copy(coreSubFolderPath, sasJSCoreMacros) + }) + + console.log('Macros available at: ', sasJSCoreMacros) +} + +copySASjsCore() diff --git a/api/src/controllers/internal/Execution.ts b/api/src/controllers/internal/Execution.ts index f3eebf1..3e60a9d 100644 --- a/api/src/controllers/internal/Execution.ts +++ b/api/src/controllers/internal/Execution.ts @@ -13,7 +13,8 @@ import { extractHeaders, generateFileUploadSasCode, getTmpFilesFolderPath, - HTTPHeaders + HTTPHeaders, + sasJSCoreMacros } from '../../utils' export interface ExecutionVars { @@ -104,6 +105,8 @@ export class ExecutionController { ` program = ` +options insert=(SASAUTOS="${sasJSCoreMacros}"); + /* runtime vars */ ${varStatments} filename _webout "${weboutPath}" mod; diff --git a/api/src/controllers/internal/Session.ts b/api/src/controllers/internal/Session.ts index 5921a25..5fe8f2d 100644 --- a/api/src/controllers/internal/Session.ts +++ b/api/src/controllers/internal/Session.ts @@ -67,7 +67,10 @@ export class SessionController { // the autoexec file is executed on SAS startup const autoExecPath = path.join(sessionFolder, 'autoexec.sas') - const contentForAutoExec = `/* compiled systemInit */\n${compiledSystemInitContent}\n/* autoexec */\n${autoExecContent}` + const contentForAutoExec = `/* compiled systemInit */ +${compiledSystemInitContent} +/* autoexec */ +${autoExecContent}` await createFile(autoExecPath, contentForAutoExec) // create empty code.sas as SAS will not start without a SYSIN diff --git a/api/src/utils/file.ts b/api/src/utils/file.ts index 5072bb9..7907959 100644 --- a/api/src/utils/file.ts +++ b/api/src/utils/file.ts @@ -8,6 +8,8 @@ export const sysInitCompiledPath = path.join( 'systemInitCompiled.sas' ) +export const sasJSCoreMacros = path.join(apiRoot, 'sasjscore') + export const getWebBuildFolderPath = () => path.join(codebaseRoot, 'web', 'build') From efaf38d3039391392ce0e14a3accddd8f34ea7d6 Mon Sep 17 00:00:00 2001 From: Saad Jutt Date: Sun, 6 Mar 2022 02:33:56 +0500 Subject: [PATCH 2/2] fix: get file instead of it's content --- api/public/swagger.yaml | 32 ++------------------- api/src/controllers/drive.ts | 55 ++++++++++++++---------------------- api/src/routes/api/drive.ts | 9 ++---- 3 files changed, 25 insertions(+), 71 deletions(-) diff --git a/api/public/swagger.yaml b/api/public/swagger.yaml index 6adc771..e22f671 100644 --- a/api/public/swagger.yaml +++ b/api/public/swagger.yaml @@ -223,18 +223,6 @@ components: - fileTree type: object additionalProperties: false - GetFileResponse: - properties: - status: - type: string - fileContent: - type: string - message: - type: string - required: - - status - type: object - additionalProperties: false UpdateFileResponse: properties: status: @@ -610,24 +598,8 @@ paths: get: operationId: GetFile responses: - '200': - description: Ok - content: - application/json: - schema: - $ref: '#/components/schemas/GetFileResponse' - examples: - 'Example 1': - value: {status: success, fileContent: 'Contents of the File'} - '400': - description: 'Unable to get File' - content: - application/json: - schema: - $ref: '#/components/schemas/GetFileResponse' - examples: - 'Example 1': - value: {status: failure, message: 'File request failed.'} + '204': + description: 'No content' summary: 'Get file from SASjs Drive' tags: - Drive diff --git a/api/src/controllers/drive.ts b/api/src/controllers/drive.ts index 6bbb813..e799599 100644 --- a/api/src/controllers/drive.ts +++ b/api/src/controllers/drive.ts @@ -1,7 +1,8 @@ import path from 'path' -import { Express } from 'express' +import express, { Express } from 'express' import { Security, + Request, Route, Tags, Example, @@ -14,14 +15,7 @@ import { UploadedFile, FormField } from 'tsoa' -import { - fileExists, - readFile, - createFile, - moveFile, - createFolder, - deleteFile -} from '@sasjs/utils' +import { fileExists, createFile, moveFile, createFolder } from '@sasjs/utils' import { createFileTree, ExecutionController, getTreeExample } from './internal' import { FileTree, isFileTree, TreeNode } from '../types' @@ -103,17 +97,12 @@ export class DriveController { * @query filePath Location of SAS program * @example filePath "/Public/somefolder/some.file" */ - @Example({ - status: 'success', - fileContent: 'Contents of the File' - }) - @Response(400, 'Unable to get File', { - status: 'failure', - message: 'File request failed.' - }) @Get('/file') - public async getFile(@Query() filePath: string): Promise { - return getFile(filePath) + public async getFile( + @Request() request: express.Request, + @Query() filePath: string + ) { + return getFile(request, filePath) } /** @@ -190,24 +179,22 @@ const deploy = async (data: DeployPayload) => { return successDeployResponse } -const getFile = async (filePath: string): Promise => { - try { - const filePathFull = path - .join(getTmpFilesFolderPath(), filePath) - .replace(new RegExp('/', 'g'), path.sep) +const getFile = async (req: express.Request, filePath: string) => { + const driveFilesPath = getTmpFilesFolderPath() - await validateFilePath(filePathFull) - const fileContent = await readFile(filePathFull) + const filePathFull = path + .join(getTmpFilesFolderPath(), filePath) + .replace(new RegExp('/', 'g'), path.sep) - return { status: 'success', fileContent: fileContent } - } catch (err: any) { - throw { - code: 400, - status: 'failure', - message: 'File request failed.', - error: typeof err === 'object' ? err.toString() : err - } + if (!filePathFull.includes(driveFilesPath)) { + throw new Error('Cannot get file outside drive.') } + + if (!(await fileExists(filePathFull))) { + throw new Error('File does not exist.') + } + + req.res?.download(filePathFull) } const saveFile = async ( diff --git a/api/src/routes/api/drive.ts b/api/src/routes/api/drive.ts index 2a533f9..bee9375 100644 --- a/api/src/routes/api/drive.ts +++ b/api/src/routes/api/drive.ts @@ -32,14 +32,9 @@ driveRouter.get('/file', async (req, res) => { if (error) return res.status(400).send(error.details[0].message) try { - const response = await controller.getFile(query.filePath) - res.send(response) + await controller.getFile(req, query.filePath) } catch (err: any) { - const statusCode = err.code - - delete err.code - - res.status(statusCode).send(err) + res.status(403).send(err.toString()) } })