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

Compare commits

..

9 Commits

Author SHA1 Message Date
semantic-release-bot
5c0eff5197 chore(release): 0.21.1 [skip ci]
## [0.21.1](https://github.com/sasjs/server/compare/v0.21.0...v0.21.1) (2022-09-19)

### Bug Fixes

* SASJS_WEBOUT_HEADERS path for windows ([0749d65](0749d65173))
2022-09-19 18:58:46 +00:00
Allan Bowe
3bda991a58 Merge pull request #282 from sasjs/issue-281
fix: SASJS_WEBOUT_HEADERS path for windows
2022-09-19 19:54:13 +01:00
0327f7c6ec chore: no need to escapeWinSlash in _sasjs_webout_headers 2022-09-19 23:51:18 +05:00
92549402eb chore: use utility function escapeWinSlashes 2022-09-19 23:36:04 +05:00
semantic-release-bot
b88c911527 chore(release): 0.21.0 [skip ci]
# [0.21.0](https://github.com/sasjs/server/compare/v0.20.0...v0.21.0) (2022-09-19)

### Features

* sas9 mocker improved - public access denied scenario ([06d3b17](06d3b17154))
2022-09-19 12:54:27 +00:00
Saad Jutt
8b12f31060 Merge pull request #276 from sasjs/sas9-mock
SAS9 mocker improved - public access denied scenario
2022-09-19 17:50:45 +05:00
Saad Jutt
e65cba9af0 chore: removed deprecated body-parser 2022-09-19 17:47:29 +05:00
0749d65173 fix: SASJS_WEBOUT_HEADERS path for windows 2022-09-19 15:53:51 +05:00
06d3b17154 feat: sas9 mocker improved - public access denied scenario 2022-09-07 18:48:56 +02:00
12 changed files with 129 additions and 42 deletions

View File

@@ -1,3 +1,17 @@
## [0.21.1](https://github.com/sasjs/server/compare/v0.21.0...v0.21.1) (2022-09-19)
### Bug Fixes
* SASJS_WEBOUT_HEADERS path for windows ([0749d65](https://github.com/sasjs/server/commit/0749d65173e8cfe9a93464711b7be1e123c289ff))
# [0.21.0](https://github.com/sasjs/server/compare/v0.20.0...v0.21.0) (2022-09-19)
### Features
* sas9 mocker improved - public access denied scenario ([06d3b17](https://github.com/sasjs/server/commit/06d3b1715432ea245ee755ae1dfd0579d3eb30e9))
# [0.20.0](https://github.com/sasjs/server/compare/v0.19.0...v0.20.0) (2022-09-16) # [0.20.0](https://github.com/sasjs/server/compare/v0.19.0...v0.20.0) (2022-09-16)

View File

@@ -0,0 +1 @@
Public access has been denied.

14
api/package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "0.0.2", "version": "0.0.2",
"dependencies": { "dependencies": {
"@sasjs/core": "^4.31.3", "@sasjs/core": "^4.31.3",
"@sasjs/utils": "2.42.1", "@sasjs/utils": "2.48.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"connect-mongo": "^4.6.0", "connect-mongo": "^4.6.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
@@ -1396,9 +1396,9 @@
"integrity": "sha512-TpVqWl5bqp3JTQjIg0r4WiQg7Ima5f17eAJILJbdYDdXsnLXlA/Csbb95G7eDPhzWpM3C0NrzKek3yvCMGzXIA==" "integrity": "sha512-TpVqWl5bqp3JTQjIg0r4WiQg7Ima5f17eAJILJbdYDdXsnLXlA/Csbb95G7eDPhzWpM3C0NrzKek3yvCMGzXIA=="
}, },
"node_modules/@sasjs/utils": { "node_modules/@sasjs/utils": {
"version": "2.42.1", "version": "2.48.1",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.1.tgz", "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.48.1.tgz",
"integrity": "sha512-DzHNYjeoj2eUkwV7Sa4eHCKRoTrYaQ6eyv6c1U5qOYXwVdZpMoYA3HFsHj55UcMOn2U3CXI5nrR7PZlUmVwVbQ==", "integrity": "sha512-Eu9p66JKLeTj0KK3kfY7YLQYq+MDMS1Q1/FOFfRe9hV23mFsuzierVMrnEYGK0JaHOogdHLmwzg6iVLDT8Jssg==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
@@ -10974,9 +10974,9 @@
"integrity": "sha512-TpVqWl5bqp3JTQjIg0r4WiQg7Ima5f17eAJILJbdYDdXsnLXlA/Csbb95G7eDPhzWpM3C0NrzKek3yvCMGzXIA==" "integrity": "sha512-TpVqWl5bqp3JTQjIg0r4WiQg7Ima5f17eAJILJbdYDdXsnLXlA/Csbb95G7eDPhzWpM3C0NrzKek3yvCMGzXIA=="
}, },
"@sasjs/utils": { "@sasjs/utils": {
"version": "2.42.1", "version": "2.48.1",
"resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.42.1.tgz", "resolved": "https://registry.npmjs.org/@sasjs/utils/-/utils-2.48.1.tgz",
"integrity": "sha512-DzHNYjeoj2eUkwV7Sa4eHCKRoTrYaQ6eyv6c1U5qOYXwVdZpMoYA3HFsHj55UcMOn2U3CXI5nrR7PZlUmVwVbQ==", "integrity": "sha512-Eu9p66JKLeTj0KK3kfY7YLQYq+MDMS1Q1/FOFfRe9hV23mFsuzierVMrnEYGK0JaHOogdHLmwzg6iVLDT8Jssg==",
"requires": { "requires": {
"@types/fs-extra": "9.0.13", "@types/fs-extra": "9.0.13",
"@types/prompts": "2.0.13", "@types/prompts": "2.0.13",

View File

@@ -48,7 +48,7 @@
"author": "4GL Ltd", "author": "4GL Ltd",
"dependencies": { "dependencies": {
"@sasjs/core": "^4.31.3", "@sasjs/core": "^4.31.3",
"@sasjs/utils": "2.42.1", "@sasjs/utils": "2.48.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"connect-mongo": "^4.6.0", "connect-mongo": "^4.6.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",

View File

@@ -77,6 +77,10 @@ export default setProcessVariables().then(async () => {
app.use(express.json({ limit: '100mb' })) app.use(express.json({ limit: '100mb' }))
app.use(express.static(path.join(__dirname, '../public'))) app.use(express.static(path.join(__dirname, '../public')))
// Body parser is used for decoding the formdata on POST request.
// Currently only place we use it is SAS9 Mock - POST /SASLogon/login
app.use(express.urlencoded({ extended: true }))
await setupFolders() await setupFolders()
await copySASjsCore() await copySASjsCore()

View File

@@ -1,4 +1,4 @@
import { isWindows } from '@sasjs/utils' import { escapeWinSlashes } 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 './'
@@ -21,13 +21,9 @@ export const createJSProgram = async (
const preProgramVarStatments = ` const preProgramVarStatments = `
let _webout = ''; let _webout = '';
const weboutPath = '${ const weboutPath = '${escapeWinSlashes(weboutPath)}';
isWindows() ? weboutPath.replace(/\\/g, '\\\\') : weboutPath const _SASJS_TOKENFILE = '${escapeWinSlashes(tokenFile)}';
}'; const _SASJS_WEBOUT_HEADERS = '${escapeWinSlashes(headersPath)}';
const _SASJS_TOKENFILE = '${
isWindows() ? tokenFile.replace(/\\/g, '\\\\') : tokenFile
}';
const _SASJS_WEBOUT_HEADERS = '${headersPath}';
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}';

View File

@@ -1,4 +1,4 @@
import { isWindows } from '@sasjs/utils' import { escapeWinSlashes } from '@sasjs/utils'
import { PreProgramVars, Session } from '../../types' import { PreProgramVars, Session } from '../../types'
import { generateFileUploadPythonCode } from '../../utils' import { generateFileUploadPythonCode } from '../../utils'
import { ExecutionVars } from './' import { ExecutionVars } from './'
@@ -19,14 +19,10 @@ export const createPythonProgram = async (
) )
const preProgramVarStatments = ` const preProgramVarStatments = `
_SASJS_SESSION_PATH = '${ _SASJS_SESSION_PATH = '${escapeWinSlashes(session.path)}';
isWindows() ? session.path.replace(/\\/g, '\\\\') : session.path _WEBOUT = '${escapeWinSlashes(weboutPath)}';
}'; _SASJS_WEBOUT_HEADERS = '${escapeWinSlashes(headersPath)}';
_WEBOUT = '${isWindows() ? weboutPath.replace(/\\/g, '\\\\') : weboutPath}'; _SASJS_TOKENFILE = '${escapeWinSlashes(tokenFile)}';
_SASJS_WEBOUT_HEADERS = '${headersPath}';
_SASJS_TOKENFILE = '${
isWindows() ? tokenFile.replace(/\\/g, '\\\\') : tokenFile
}';
_SASJS_USERNAME = '${preProgramVariables?.username}'; _SASJS_USERNAME = '${preProgramVariables?.username}';
_SASJS_USERID = '${preProgramVariables?.userId}'; _SASJS_USERID = '${preProgramVariables?.userId}';
_SASJS_DISPLAYNAME = '${preProgramVariables?.displayName}'; _SASJS_DISPLAYNAME = '${preProgramVariables?.displayName}';

View File

@@ -1,4 +1,4 @@
import { isWindows } from '@sasjs/utils' import { escapeWinSlashes } from '@sasjs/utils'
import { PreProgramVars, Session } from '../../types' import { PreProgramVars, Session } from '../../types'
import { generateFileUploadRCode } from '../../utils' import { generateFileUploadRCode } from '../../utils'
import { ExecutionVars } from '.' import { ExecutionVars } from '.'
@@ -19,14 +19,10 @@ export const createRProgram = async (
) )
const preProgramVarStatments = ` const preProgramVarStatments = `
._SASJS_SESSION_PATH <- '${ ._SASJS_SESSION_PATH <- '${escapeWinSlashes(session.path)}';
isWindows() ? session.path.replace(/\\/g, '\\\\') : session.path ._WEBOUT <- '${escapeWinSlashes(weboutPath)}';
}'; ._SASJS_WEBOUT_HEADERS <- '${escapeWinSlashes(headersPath)}';
._WEBOUT <- '${isWindows() ? weboutPath.replace(/\\/g, '\\\\') : weboutPath}'; ._SASJS_TOKENFILE <- '${escapeWinSlashes(tokenFile)}';
._SASJS_WEBOUT_HEADERS <- '${headersPath}';
._SASJS_TOKENFILE <- '${
isWindows() ? tokenFile.replace(/\\/g, '\\\\') : tokenFile
}';
._SASJS_USERNAME <- '${preProgramVariables?.username}'; ._SASJS_USERNAME <- '${preProgramVariables?.username}';
._SASJS_USERID <- '${preProgramVariables?.userId}'; ._SASJS_USERID <- '${preProgramVariables?.userId}';
._SASJS_DISPLAYNAME <- '${preProgramVariables?.displayName}'; ._SASJS_DISPLAYNAME <- '${preProgramVariables?.displayName}';

View File

@@ -8,6 +8,7 @@ export const createSASProgram = async (
vars: ExecutionVars, vars: ExecutionVars,
session: Session, session: Session,
weboutPath: string, weboutPath: string,
headersPath: string,
tokenFile: string, tokenFile: string,
otherArgs?: any otherArgs?: any
) => { ) => {
@@ -23,7 +24,7 @@ export const createSASProgram = async (
%let _sasjs_displayname=${preProgramVariables?.displayName}; %let _sasjs_displayname=${preProgramVariables?.displayName};
%let _sasjs_apiserverurl=${preProgramVariables?.serverUrl}; %let _sasjs_apiserverurl=${preProgramVariables?.serverUrl};
%let _sasjs_apipath=/SASjsApi/stp/execute; %let _sasjs_apipath=/SASjsApi/stp/execute;
%let _sasjs_webout_headers=%sysfunc(pathname(work))/../stpsrv_header.txt; %let _sasjs_webout_headers=${headersPath};
%let _metaperson=&_sasjs_displayname; %let _metaperson=&_sasjs_displayname;
%let _metauser=&_sasjs_username; %let _metauser=&_sasjs_username;

View File

@@ -32,6 +32,7 @@ export const processProgram = async (
vars, vars,
session, session,
weboutPath, weboutPath,
headersPath,
tokenFile, tokenFile,
otherArgs otherArgs
) )

View File

@@ -15,7 +15,7 @@ export interface MockFileRead {
} }
export class MockSas9Controller { export class MockSas9Controller {
private loggedIn: boolean = false private loggedIn: string | undefined
@Get('/SASStoredProcess') @Get('/SASStoredProcess')
public async sasStoredProcess(): Promise<Sas9Response> { public async sasStoredProcess(): Promise<Sas9Response> {
@@ -46,6 +46,13 @@ export class MockSas9Controller {
} }
} }
if (this.isPublicAccount()) {
return {
content: '',
redirect: '/SASLogon/Login'
}
}
let program = req.query._program?.toString() || '' let program = req.query._program?.toString() || ''
program = program.replace('/', '') program = program.replace('/', '')
@@ -68,6 +75,23 @@ export class MockSas9Controller {
@Get('/SASLogon/login') @Get('/SASLogon/login')
public async loginGet(): Promise<Sas9Response> { public async loginGet(): Promise<Sas9Response> {
if (this.loggedIn) {
if (this.isPublicAccount()) {
return {
content: '',
redirect: '/SASStoredProcess/Logoff?publicDenied=true'
}
} else {
return await getMockResponseFromFile([
process.cwd(),
'mocks',
'generic',
'sas9',
'logged-in'
])
}
}
return await getMockResponseFromFile([ return await getMockResponseFromFile([
process.cwd(), process.cwd(),
'mocks', 'mocks',
@@ -78,8 +102,8 @@ export class MockSas9Controller {
} }
@Post('/SASLogon/login') @Post('/SASLogon/login')
public async loginPost(): Promise<Sas9Response> { public async loginPost(req: express.Request): Promise<Sas9Response> {
this.loggedIn = true this.loggedIn = req.body.username
return await getMockResponseFromFile([ return await getMockResponseFromFile([
process.cwd(), process.cwd(),
@@ -91,8 +115,18 @@ export class MockSas9Controller {
} }
@Get('/SASLogon/logout') @Get('/SASLogon/logout')
public async logout(): Promise<Sas9Response> { public async logout(req: express.Request): Promise<Sas9Response> {
this.loggedIn = false this.loggedIn = undefined
if (req.query.publicDenied === 'true') {
return await getMockResponseFromFile([
process.cwd(),
'mocks',
'generic',
'sas9',
'public-access-denied'
])
}
return await getMockResponseFromFile([ return await getMockResponseFromFile([
process.cwd(), process.cwd(),
@@ -102,6 +136,20 @@ export class MockSas9Controller {
'logged-out' 'logged-out'
]) ])
} }
@Get('/SASStoredProcess/Logoff') //publicDenied=true
public async logoff(req: express.Request): Promise<Sas9Response> {
const params = req.query.publicDenied
? `?publicDenied=${req.query.publicDenied}`
: ''
return {
content: '',
redirect: '/SASLogon/logout' + params
}
}
private isPublicAccount = () => this.loggedIn?.toLowerCase() === 'public'
} }
/** /**

View File

@@ -58,6 +58,11 @@ sas9WebRouter.post('/SASStoredProcess/do/', async (req, res) => {
sas9WebRouter.get('/SASLogon/login', async (req, res) => { sas9WebRouter.get('/SASLogon/login', async (req, res) => {
const response = await controller.loginGet() const response = await controller.loginGet()
if (response.redirect) {
res.redirect(response.redirect)
return
}
try { try {
res.send(response.content) res.send(response.content)
} catch (err: any) { } catch (err: any) {
@@ -66,7 +71,12 @@ sas9WebRouter.get('/SASLogon/login', async (req, res) => {
}) })
sas9WebRouter.post('/SASLogon/login', async (req, res) => { sas9WebRouter.post('/SASLogon/login', async (req, res) => {
const response = await controller.loginPost() const response = await controller.loginPost(req)
if (response.redirect) {
res.redirect(response.redirect)
return
}
try { try {
res.send(response.content) res.send(response.content)
@@ -76,7 +86,27 @@ sas9WebRouter.post('/SASLogon/login', async (req, res) => {
}) })
sas9WebRouter.get('/SASLogon/logout', async (req, res) => { sas9WebRouter.get('/SASLogon/logout', async (req, res) => {
const response = await controller.logout() const response = await controller.logout(req)
if (response.redirect) {
res.redirect(response.redirect)
return
}
try {
res.send(response.content)
} catch (err: any) {
res.status(403).send(err.toString())
}
})
sas9WebRouter.get('/SASStoredProcess/Logoff', async (req, res) => {
const response = await controller.logoff(req)
if (response.redirect) {
res.redirect(response.redirect)
return
}
try { try {
res.send(response.content) res.send(response.content)