mirror of
https://github.com/sasjs/server.git
synced 2025-12-10 19:34:34 +00:00
Compare commits
3 Commits
v0.33.1
...
domain-che
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ed10109c1 | ||
|
|
ef9cca575f | ||
|
|
efbfd3f392 |
@@ -1,5 +1,6 @@
|
|||||||
MODE=[desktop|server] default considered as desktop
|
MODE=[desktop|server] default considered as desktop
|
||||||
CORS=[disable|enable] default considered as disable for server MODE & enable for desktop MODE
|
CORS=[disable|enable] default considered as disable for server MODE & enable for desktop MODE
|
||||||
|
ALLOWED_DOMAINS=<space separated urls, each starting with protocol `http` or `https`>
|
||||||
WHITELIST=<space separated urls, each starting with protocol `http` or `https`>
|
WHITELIST=<space separated urls, each starting with protocol `http` or `https`>
|
||||||
|
|
||||||
PROTOCOL=[http|https] default considered as http
|
PROTOCOL=[http|https] default considered as http
|
||||||
|
|||||||
@@ -3,10 +3,21 @@ import cors from 'cors'
|
|||||||
import { CorsType } from '../utils'
|
import { CorsType } from '../utils'
|
||||||
|
|
||||||
export const configureCors = (app: Express) => {
|
export const configureCors = (app: Express) => {
|
||||||
|
const { CORS } = process.env
|
||||||
|
|
||||||
|
if (CORS === CorsType.ENABLED) {
|
||||||
|
const whiteList = getWhiteListed()
|
||||||
|
|
||||||
|
console.log('All CORS Requests are enabled for:', whiteList)
|
||||||
|
app.use(cors({ credentials: true, origin: whiteList }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getWhiteListed = (): string[] => {
|
||||||
|
const whiteList: string[] = []
|
||||||
const { CORS, WHITELIST } = process.env
|
const { CORS, WHITELIST } = process.env
|
||||||
|
|
||||||
if (CORS === CorsType.ENABLED) {
|
if (CORS === CorsType.ENABLED) {
|
||||||
const whiteList: string[] = []
|
|
||||||
WHITELIST?.split(' ')
|
WHITELIST?.split(' ')
|
||||||
?.filter((url) => !!url)
|
?.filter((url) => !!url)
|
||||||
.forEach((url) => {
|
.forEach((url) => {
|
||||||
@@ -14,8 +25,6 @@ export const configureCors = (app: Express) => {
|
|||||||
// removing trailing slash of URLs listing for CORS
|
// removing trailing slash of URLs listing for CORS
|
||||||
whiteList.push(url.replace(/\/$/, ''))
|
whiteList.push(url.replace(/\/$/, ''))
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('All CORS Requests are enabled for:', whiteList)
|
|
||||||
app.use(cors({ credentials: true, origin: whiteList }))
|
|
||||||
}
|
}
|
||||||
|
return whiteList
|
||||||
}
|
}
|
||||||
|
|||||||
29
api/src/app-modules/configureDomains.ts
Normal file
29
api/src/app-modules/configureDomains.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { Express } from 'express'
|
||||||
|
import { checkDomain } from '../middlewares'
|
||||||
|
import { getWhiteListed } from './configureCors'
|
||||||
|
|
||||||
|
export const configureDomains = (app: Express) => {
|
||||||
|
// const domains: string[] = []
|
||||||
|
const domains = new Set<string>()
|
||||||
|
const { ALLOWED_DOMAINS } = process.env
|
||||||
|
|
||||||
|
const allowedDomains = ALLOWED_DOMAINS?.trim().split(' ') ?? []
|
||||||
|
|
||||||
|
const whiteListed = getWhiteListed()
|
||||||
|
|
||||||
|
const combinedUrls = [...allowedDomains, ...whiteListed]
|
||||||
|
combinedUrls
|
||||||
|
.filter((domainName) => !!domainName)
|
||||||
|
.forEach((url) => {
|
||||||
|
try {
|
||||||
|
const domain = new URL(url)
|
||||||
|
domains.add(domain.hostname)
|
||||||
|
} catch (_) {}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (domains.size) {
|
||||||
|
process.allowedDomains = [...domains]
|
||||||
|
console.log('Allowed Domain(s):', process.allowedDomains)
|
||||||
|
app.use(checkDomain)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Express } from 'express'
|
import { Express, CookieOptions } from 'express'
|
||||||
import mongoose from 'mongoose'
|
import mongoose from 'mongoose'
|
||||||
import session from 'express-session'
|
import session from 'express-session'
|
||||||
import MongoStore from 'connect-mongo'
|
import MongoStore from 'connect-mongo'
|
||||||
|
|
||||||
import { ModeType } from '../utils'
|
import { ModeType, ProtocolType } from '../utils'
|
||||||
import { cookieOptions } from '../app'
|
|
||||||
|
|
||||||
export const configureExpressSession = (app: Express) => {
|
export const configureExpressSession = (app: Express) => {
|
||||||
const { MODE } = process.env
|
const { MODE } = process.env
|
||||||
@@ -19,6 +18,15 @@ export const configureExpressSession = (app: Express) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { PROTOCOL } = process.env
|
||||||
|
const cookieOptions: CookieOptions = {
|
||||||
|
secure: PROTOCOL === ProtocolType.HTTPS,
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: PROTOCOL === ProtocolType.HTTPS ? 'none' : undefined,
|
||||||
|
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
|
domain: 'sas.4gl.io'
|
||||||
|
}
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
session({
|
session({
|
||||||
secret: process.secrets.SESSION_SECRET,
|
secret: process.secrets.SESSION_SECRET,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './configureCors'
|
export * from './configureCors'
|
||||||
|
export * from './configureDomains'
|
||||||
export * from './configureExpressSession'
|
export * from './configureExpressSession'
|
||||||
export * from './configureLogger'
|
export * from './configureLogger'
|
||||||
export * from './configureSecurity'
|
export * from './configureSecurity'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import express, { ErrorRequestHandler, CookieOptions } from 'express'
|
import express, { ErrorRequestHandler } from 'express'
|
||||||
import cookieParser from 'cookie-parser'
|
import cookieParser from 'cookie-parser'
|
||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
|
|
||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
getWebBuildFolder,
|
getWebBuildFolder,
|
||||||
instantiateLogger,
|
instantiateLogger,
|
||||||
loadAppStreamConfig,
|
loadAppStreamConfig,
|
||||||
ProtocolType,
|
|
||||||
ReturnCode,
|
ReturnCode,
|
||||||
setProcessVariables,
|
setProcessVariables,
|
||||||
setupFolders,
|
setupFolders,
|
||||||
@@ -16,6 +15,7 @@ import {
|
|||||||
} from './utils'
|
} from './utils'
|
||||||
import {
|
import {
|
||||||
configureCors,
|
configureCors,
|
||||||
|
configureDomains,
|
||||||
configureExpressSession,
|
configureExpressSession,
|
||||||
configureLogger,
|
configureLogger,
|
||||||
configureSecurity
|
configureSecurity
|
||||||
@@ -29,15 +29,6 @@ if (verifyEnvVariables()) process.exit(ReturnCode.InvalidEnv)
|
|||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
const { PROTOCOL } = process.env
|
|
||||||
|
|
||||||
export const cookieOptions: CookieOptions = {
|
|
||||||
secure: PROTOCOL === ProtocolType.HTTPS,
|
|
||||||
httpOnly: true,
|
|
||||||
sameSite: PROTOCOL === ProtocolType.HTTPS ? 'none' : undefined,
|
|
||||||
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
|
||||||
}
|
|
||||||
|
|
||||||
const onError: ErrorRequestHandler = (err, req, res, next) => {
|
const onError: ErrorRequestHandler = (err, req, res, next) => {
|
||||||
console.error(err.stack)
|
console.error(err.stack)
|
||||||
res.status(500).send('Something broke!')
|
res.status(500).send('Something broke!')
|
||||||
@@ -58,6 +49,11 @@ export default setProcessVariables().then(async () => {
|
|||||||
***********************************/
|
***********************************/
|
||||||
configureCors(app)
|
configureCors(app)
|
||||||
|
|
||||||
|
/***********************************
|
||||||
|
* Allowed Domains *
|
||||||
|
***********************************/
|
||||||
|
configureDomains(app)
|
||||||
|
|
||||||
/***********************************
|
/***********************************
|
||||||
* DB Connection & *
|
* DB Connection & *
|
||||||
* Express Sessions *
|
* Express Sessions *
|
||||||
|
|||||||
17
api/src/middlewares/checkDomain.ts
Normal file
17
api/src/middlewares/checkDomain.ts
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { RequestHandler } from 'express'
|
||||||
|
|
||||||
|
export const checkDomain: RequestHandler = (req, res, next) => {
|
||||||
|
const { allowedDomains } = process
|
||||||
|
|
||||||
|
// pass if no allowed domain is specified
|
||||||
|
if (!allowedDomains.length) return next()
|
||||||
|
|
||||||
|
if (allowedDomains.includes(req.hostname)) return next()
|
||||||
|
|
||||||
|
console.log('allowedDomains', allowedDomains)
|
||||||
|
console.log('hostname not allowed', req.hostname)
|
||||||
|
res.writeHead(404, {
|
||||||
|
'Content-Type': 'text/plain'
|
||||||
|
})
|
||||||
|
return res.end('Not found')
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export * from './authenticateToken'
|
export * from './authenticateToken'
|
||||||
export * from './authorize'
|
export * from './authorize'
|
||||||
|
export * from './checkDomain'
|
||||||
export * from './csrfProtection'
|
export * from './csrfProtection'
|
||||||
export * from './desktop'
|
export * from './desktop'
|
||||||
export * from './verifyAdmin'
|
export * from './verifyAdmin'
|
||||||
|
|||||||
1
api/src/types/system/process.d.ts
vendored
1
api/src/types/system/process.d.ts
vendored
@@ -12,5 +12,6 @@ declare namespace NodeJS {
|
|||||||
logger: import('@sasjs/utils/logger').Logger
|
logger: import('@sasjs/utils/logger').Logger
|
||||||
runTimes: import('../../utils').RunTimeType[]
|
runTimes: import('../../utils').RunTimeType[]
|
||||||
secrets: import('../../model/Configuration').ConfigurationType
|
secrets: import('../../model/Configuration').ConfigurationType
|
||||||
|
allowedDomains: string[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ const verifyRUN_TIMES = (): string[] => {
|
|||||||
return errors
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
const verifyExecutablePaths = () => {
|
const verifyExecutablePaths = (): string[] => {
|
||||||
const errors: string[] = []
|
const errors: string[] = []
|
||||||
const { RUN_TIMES, SAS_PATH, NODE_PATH, PYTHON_PATH, R_PATH, MODE } =
|
const { RUN_TIMES, SAS_PATH, NODE_PATH, PYTHON_PATH, R_PATH, MODE } =
|
||||||
process.env
|
process.env
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "ES6",
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"rootDir": "./",
|
"rootDir": "./",
|
||||||
"outDir": "./build",
|
"outDir": "./build",
|
||||||
|
|||||||
8105
web/package-lock.json
generated
8105
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,8 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --config webpack.dev.ts --hot",
|
"start": "vite serve --port 3000",
|
||||||
"build": "webpack --config webpack.prod.ts"
|
"build": "vite build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.4.1",
|
"@emotion/react": "^11.4.1",
|
||||||
@@ -30,38 +30,21 @@
|
|||||||
"react-toastify": "^9.0.1"
|
"react-toastify": "^9.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.16.0",
|
|
||||||
"@babel/node": "^7.16.0",
|
|
||||||
"@babel/plugin-proposal-class-properties": "^7.16.0",
|
|
||||||
"@babel/preset-env": "^7.16.4",
|
|
||||||
"@babel/preset-react": "^7.16.0",
|
|
||||||
"@babel/preset-typescript": "^7.16.0",
|
|
||||||
"@types/dotenv-webpack": "^7.0.3",
|
|
||||||
"@types/prismjs": "^1.16.6",
|
|
||||||
"@types/react": "^17.0.37",
|
"@types/react": "^17.0.37",
|
||||||
"@types/react-copy-to-clipboard": "^5.0.2",
|
"@types/react-copy-to-clipboard": "^5.0.2",
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.11",
|
||||||
"@types/react-router-dom": "^5.3.1",
|
"@types/react-router-dom": "^5.3.1",
|
||||||
"babel-loader": "^8.2.3",
|
"@vitejs/plugin-react": "^2.1.0",
|
||||||
"babel-plugin-prismjs": "^2.1.0",
|
|
||||||
"copy-webpack-plugin": "^10.0.0",
|
|
||||||
"css-loader": "^6.5.1",
|
|
||||||
"dotenv-webpack": "^7.1.0",
|
|
||||||
"eslint": "^8.5.0",
|
"eslint": "^8.5.0",
|
||||||
"eslint-config-react-app": "^7.0.0",
|
"eslint-config-react-app": "^7.0.0",
|
||||||
"eslint-webpack-plugin": "^3.1.1",
|
|
||||||
"file-loader": "^6.2.0",
|
|
||||||
"html-webpack-plugin": "5.5.0",
|
|
||||||
"path": "0.12.7",
|
"path": "0.12.7",
|
||||||
"prettier": "^2.4.1",
|
"prettier": "^2.4.1",
|
||||||
"sass": "^1.44.0",
|
"sass": "^1.44.0",
|
||||||
"sass-loader": "^12.3.0",
|
|
||||||
"style-loader": "^3.3.1",
|
|
||||||
"ts-loader": "^9.2.6",
|
|
||||||
"typescript": "^4.5.2",
|
"typescript": "^4.5.2",
|
||||||
"webpack": "5.64.3",
|
"vite": "^3.1.4",
|
||||||
"webpack-cli": "^4.9.2",
|
"vite-plugin-env-compatible": "^1.1.1",
|
||||||
"webpack-dev-server": "4.7.4"
|
"vite-plugin-html": "^3.2.0",
|
||||||
|
"vite-plugin-monaco-editor": "^1.1.0"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|||||||
@@ -35,5 +35,6 @@
|
|||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
17
web/vite.config.js
Normal file
17
web/vite.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
import { createHtmlPlugin } from 'vite-plugin-html'
|
||||||
|
import envCompatible from 'vite-plugin-env-compatible'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
build: {
|
||||||
|
outDir: './build'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
react(),
|
||||||
|
createHtmlPlugin({
|
||||||
|
template: './src/index.html'
|
||||||
|
}),
|
||||||
|
envCompatible({ prefix: '' })
|
||||||
|
]
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user