From 835f4506861ca96e4e44c5f2d4e9962a7ca49af0 Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 26 May 2020 14:12:12 +0200 Subject: [PATCH] PoC for code sandboxing --- ext/.eslintrc | 24 +++++++++++++++++++++++ ext/.gitignore | 30 +++++++++++++++++++++++++++++ ext/db/schema.cds | 6 ++++++ ext/package.json | 19 +++++++++++++++++++ ext/server.js | 40 +++++++++++++++++++++++++++++++++++++++ ext/srv/AdminService.js | 10 ++++++++++ ext/srv/CatalogService.js | 9 +++++++++ 7 files changed, 138 insertions(+) create mode 100644 ext/.eslintrc create mode 100644 ext/.gitignore create mode 100644 ext/db/schema.cds create mode 100644 ext/package.json create mode 100644 ext/server.js create mode 100644 ext/srv/AdminService.js create mode 100644 ext/srv/CatalogService.js diff --git a/ext/.eslintrc b/ext/.eslintrc new file mode 100644 index 00000000..639d13a0 --- /dev/null +++ b/ext/.eslintrc @@ -0,0 +1,24 @@ +{ + "extends": "eslint:recommended", + "env": { + "node": true, + "es6": true, + "jest": true + }, + "parserOptions": { + "ecmaVersion": 2017 + }, + "globals": { + "SELECT": true, + "INSERT": true, + "UPDATE": true, + "DELETE": true, + "CREATE": true, + "DROP": true, + "cds": true + }, + "rules": { + "no-console": "off", + "require-atomic-updates": "off" + } +} diff --git a/ext/.gitignore b/ext/.gitignore new file mode 100644 index 00000000..739359e0 --- /dev/null +++ b/ext/.gitignore @@ -0,0 +1,30 @@ +# CAP ext +_out +*.db +connection.properties +default-*.json +gen/ +node_modules/ +package-lock.json +target/ + +# Web IDE, App Studio +.che/ +.gen/ + +# MTA +*_mta_build_tmp +*.mtar +mta_archives/ + +# Other +.DS_Store +*.orig +*.log + +*.iml +*.flattened-pom.xml + +# IDEs +.vscode +.idea diff --git a/ext/db/schema.cds b/ext/db/schema.cds new file mode 100644 index 00000000..051a067b --- /dev/null +++ b/ext/db/schema.cds @@ -0,0 +1,6 @@ +using { sap.capire.bookshop.Books } from '@capire/bookshop'; + +extend Books with { + ISBN : String; + discount : Decimal @assert.range:[0,1]; +} diff --git a/ext/package.json b/ext/package.json new file mode 100644 index 00000000..6dadcb88 --- /dev/null +++ b/ext/package.json @@ -0,0 +1,19 @@ +{ + "name": "ext", + "version": "1.0.0", + "description": "A simple CAP project.", + "repository": "", + "license": "UNLICENSED", + "private": true, + "dependencies": { + "@capire/bookshop": "../bookshop", + "@sap/cds": "^4", + "express": "^4" + }, + "devDependencies": { + "sqlite3": "^4" + }, + "scripts": { + "start": "npx cds run" + } +} diff --git a/ext/server.js b/ext/server.js new file mode 100644 index 00000000..648fa70f --- /dev/null +++ b/ext/server.js @@ -0,0 +1,40 @@ +const cds = require ('@sap/cds') +const path = require ('path') +const fs = require ('fs') +const protected = {db:1,messaging:1,auth:1} +const { isfile } = cds.utils + +cds.on('served', ()=>{ + for (let each of cds.services) { + if (each.name in protected) continue + // search for local srv/.js files and if exist + // activate them in a service extension sandbox + const impl = isfile (path.resolve('srv/'+each.name+'.js')) + if (impl) activate_sandboxed (each,impl) + } +}) + +function activate_sandboxed (srv,impl) { + console.log (`[cds] - extending ${srv.name} with sandboxed:`, {impl:path.relative(process.cwd(),impl)}) + const src = fs.readFileSync (impl) + const sandbox = Object.keys(global).filter(name => name !== 'cds') + const fn = new Function ( + 'module','cds','global','process', ...sandbox, + src + ) + // restricted sandboxed variant of 'module' and 'cds' + const module = {} + const cds = { + service: { + impl: fn=>fn + } + } + fn (module,cds,undefined,undefined, ...sandbox.map((()=>(undefined)))) + if (typeof module.exports === 'function') try { + module.exports.call (srv,srv) + } catch (e) { + console.log (e) + } +} + +module.exports = cds.server diff --git a/ext/srv/AdminService.js b/ext/srv/AdminService.js new file mode 100644 index 00000000..4053df46 --- /dev/null +++ b/ext/srv/AdminService.js @@ -0,0 +1,10 @@ +module.exports = cds.service.impl(function(){ + + this.before(['CREATE','UPDATE'],'Books', req => { //> .... + const book = req.data + if (book.stock < 10 && book.discount > 0.5) { + req.error('Hey, da sind so wenig übrig, die wollen wir nicht zu billig verticken') + } + }) + +}) diff --git a/ext/srv/CatalogService.js b/ext/srv/CatalogService.js new file mode 100644 index 00000000..329857b5 --- /dev/null +++ b/ext/srv/CatalogService.js @@ -0,0 +1,9 @@ +console.log ('Böses Zeug', global, process, cds) +// process.exit() +// const fs = require('fs') +// cds.run('Böses Zeugs') +// SELECT.from ('Foo') + +module.exports = cds.service.impl(function(){ + this.after('READ','Books', each => each.title += ' (served through sandbox)') +})