diff --git a/config/sample.json b/config/sample.json index 8c8c9dc..f0f5c92 100644 --- a/config/sample.json +++ b/config/sample.json @@ -1,10 +1,26 @@ { - adminPass: "default", - adminSessionSecret: "default", - env: "dev", - port: 8080, - sandboxToken: "a8654152-74c0-41dd-a954-bcab50ff99d4", - sandboxServer: "https://pg-api.sensorup.com", - sandboxPath: "/st-playground/proxy/v1.0", - version: "1.0" + "adminPass": "default", + "adminSessionSecret": "default", + "env": "dev", + "port": 8080, + "sensorthings": { + "remote": { + "server": "https://pg-api.sensorup.com", + "path": "/st-playground/proxy/v1.0", + "credentials": { + "header": "St-P-Access-Token", + "value": "a8654152-74c0-41dd-a954-bcab50ff99d4" + } + }, + "local": { + "db": { + "host": "localhost", + "port": "5432", + "name": "default", + "user": "default", + "password": "default" + } + } + }, + "version": "1.0" } diff --git a/config/test.json b/config/test.json index a12a24a..6fcf750 100644 --- a/config/test.json +++ b/config/test.json @@ -1,10 +1,18 @@ + { - adminPass: "1.TestPassword.1", - adminSessionSecret: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", - env: "test", - port: 8080, - sandboxToken: "a8654152-74c0-41dd-a954-bcab50ff99d4", - sandboxServer: "https://pg-api.sensorup.com", - sandboxPath: "/st-playground/proxy/v1.0", - version: "1.0" + "adminPass": "1.TestPassword.1", + "adminSessionSecret": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", + "env": "test", + "port": 8080, + "sensorthings": { + "remote": { + "server": "https://pg-api.sensorup.com", + "path": "/st-playground/proxy/v1.0", + "credentials": { + "header": "St-P-Access-Token", + "value": "a8654152-74c0-41dd-a954-bcab50ff99d4" + } + } + }, + "version": "1.0" } diff --git a/package.json b/package.json index 4ca16ee..e9c8bc6 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,8 @@ "morgan-body": "^0.9.1", "pg": "^6.1.0", "on-headers": "^1.0.1", - "owasp-password-strength-test": "^1.3.0" + "owasp-password-strength-test": "^1.3.0", + "sensorthings": "" }, "config": { "blanket": { diff --git a/src/config.js b/src/config.js index 85522f1..de32e49 100644 --- a/src/config.js +++ b/src/config.js @@ -12,16 +12,71 @@ const avoidDefault = value => { } }; -const conf = convict({ +const password = value => { + const adminPass = owasp.test(value); + if (!adminPass.strong) { + adminPass.errors.forEach(error => console.error(error)); + throw new Error('Admin pass is default or not strong enough.'); + } +}; + +const remoteSTConfig = { + server: { + doc: 'SensorThings remote API server', + format: 'url', + default: 'https://pg-api.sensorup.com' + }, + path: { + doc: 'SensorThings remote API path', + default: '/st-playground/proxy/v1.0' + }, + credentials: { + header: { + doc: 'SensorThings auth header name', + format: avoidDefault, + default: defaultValue + }, + value: { + doc: 'SensorThings auth header value', + format: avoidDefault, + default: defaultValue + } + } +}; + +const localSTConfig = { + db: { + host: { + doc: 'SensorThings DB host', + default: 'localhost' + }, + port: { + doc: 'SensorThings DB port', + format: 'port', + default: 5432 + }, + name: { + doc: 'SensorThings DB name', + format: avoidDefault, + default: 'postgres' + }, + user: { + doc: 'SensorThings DB user', + format: avoidDefault, + default: defaultValue + }, + password: { + doc: 'SensorThings DB password', + format: password, + default: defaultValue + } + } +}; + +let commonConf = { adminPass: { doc: 'The password for the admin user. Follow OWASP guidelines for passwords', - format: value => { - const adminPass = owasp.test(value); - if (!adminPass.strong) { - adminPass.errors.forEach(error => console.error(error)); - throw new Error('Admin pass is default or not strong enough.'); - } - }, + format: password, default: 'invalid' }, adminSessionSecret: { @@ -41,20 +96,7 @@ const conf = convict({ default: 8080, env: 'PORT' }, - sandboxPath: { - doc: 'SensorThings sandbox API path', - default: '/st-playground/proxy/v1.0' - }, - sandboxServer: { - doc: 'SensorThings sandbox API server', - format: 'url', - default: 'https://pg-api.sensorup.com' - }, - sandboxToken: { - doc: 'SensorThings sandbox API credentials', - format: avoidDefault, - default: defaultValue - }, + sensorthings: {}, version: { doc: 'API version. We follow SensorThing\'s versioning format as described at http://docs.opengeospatial.org/is/15-078r6/15-078r6.html#34', format: value => { @@ -66,7 +108,9 @@ const conf = convict({ }, default: '1.0' } -}); +}; + +let conf = convict(commonConf); // Handle configuration files. You can specify a CSV list of configuration // files to process, which will be overlayed in order, in the CONFIG_FILES @@ -76,6 +120,20 @@ let files = (envConfig + ',' + process.env.CONFIG_FILES) .split(',') .filter(fs.existsSync); +conf.loadFile(files); + +const currentSTConfig = conf.get('sensorthings'); + +if (currentSTConfig.local) { + commonConf.sensorthings.local = localSTConfig; + conf = convict(commonConf); +} else if (currentSTConfig.remote) { + commonConf.sensorthings.remote = remoteSTConfig; + conf = convict(commonConf); +} else { + throw new Error('SensorThings needs at least a local or remote configuration'); +} + conf.loadFile(files); conf.validate(); diff --git a/src/routes/sensorthings.js b/src/routes/sensorthings.js new file mode 100644 index 0000000..fbb814b --- /dev/null +++ b/src/routes/sensorthings.js @@ -0,0 +1,59 @@ +/** + * + * This module decides, based on configuration, if we mount our own + * Sensorthings API (through sensortings module) or proxy to an external + * implementation. + * + */ + +import proxy from 'express-http-proxy'; + +import config from '../config'; +import { resourceEndpoints } from '../routes/base'; +import sensorthings from 'sensorthings' + +const localAPI = config.has('sensorthings.local'); +let sensorthingsAPI; + +if (localAPI) { + //Init DB + sensorthingsAPI = sensorthings; +} else { + /** + * + * At the moment, we are using Sensorup as our remote implementation + * of the Sensorthings API, but we should be able to proxy to any + * other remote server. + * + * You will need to get an access token by creating an account at + * https://pg.sensorup.com/playground.html + * + * Add the access token to your 'sensorthings.remote.credentials.token' + * config file entry. + */ + sensorthingsAPI = proxy(config.get('sensorthings.remote.server'), { + filter: (req, res) => { + const matches = resourceEndpoints.filter(endpoint => { + const regexp = new RegExp('^((?!' + endpoint + ').)*$'); + return req.path.match(regexp) == null; + }); + + // Only the paths listed in the resourcesEndpoints array are handled + // by the proxy. + if (matches.length) { + return true; + } + }, + decorateRequest: (proxyReq, originalReq) => { + // Add auth header. + const header = config.get('sensorthings.remote.credentials.header'); + proxyReq.headers[header] = config.get('sensorthings.remote.credentials.value'); + + proxyReq.path = config.get('sensorthings.remote.path') + proxyReq.path; + + return proxyReq; + } + }); +} + +export default sensorthingsAPI diff --git a/src/server.js b/src/server.js index 657f3d0..907f338 100644 --- a/src/server.js +++ b/src/server.js @@ -13,7 +13,7 @@ import base from './routes/base'; import clients from './routes/clients'; import users from './routes/users'; -import sensorup from './utils/sensorup'; +import sensorthings from './routes/sensorthings'; let app = express(); @@ -29,10 +29,7 @@ app.use(cors()); const endpointPrefix = '/api/v' + config.get('version'); -// SensorUp's sandbox. -// We use this sandbox until we have our own implementation of the -// SensorThings API in place. -app.use(endpointPrefix + '/', sensorup); +app.use(endpointPrefix + '/', sensorthings); app.use(endpointPrefix + '/clients', auth(['admin']), clients); app.use(endpointPrefix + '/users', users); diff --git a/src/utils/sensorup.js b/src/utils/sensorup.js deleted file mode 100644 index 0395c6c..0000000 --- a/src/utils/sensorup.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This is just a temporary utility. - * - * This proxy allows us to quickly expose a SensorThings API while we work on - * our own open source implementation of this API. We will be using SensorUp's - * sandbox. - * - * You will need to get an access token by creating an account at - * https://pg.sensorup.com/playground.html - * - * Add the access token to your 'sandboxToken' config file entry. - */ - -import proxy from 'express-http-proxy'; - -import config from '../config'; -import { resourceEndpoints } from '../routes/base'; - -export default proxy(config.get('sandboxServer'), { - filter: (req, res) => { - const matches = resourceEndpoints.filter(endpoint => { - const regexp = new RegExp('^((?!' + endpoint + ').)*$'); - return req.path.match(regexp) == null; - }); - - // Only the paths listed in the resourcesEndpoints array are handled - // by the proxy. - if (matches.length) { - return true; - } - }, - decorateRequest: (proxyReq, originalReq) => { - // Add SensorUp auth header. - proxyReq.headers['St-P-Access-Token'] = config.get('sandboxToken'); - - proxyReq.path = config.get('sandboxPath') + proxyReq.path; - - return proxyReq; - } -});