UNPKG

signalk-server

Version:

An implementation of a [Signal K](http://signalk.org) server for boats.

184 lines (183 loc) 7.19 kB
"use strict"; /* eslint-disable @typescript-eslint/no-explicit-any */ /* * Copyright 2017 Teppo Kurki <teppo.kurki@iki.fi> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.InvalidTokenError = void 0; exports.startSecurity = startSecurity; exports.getSecurityConfig = getSecurityConfig; exports.pathForSecurityConfig = pathForSecurityConfig; exports.saveSecurityConfig = saveSecurityConfig; exports.getCertificateOptions = getCertificateOptions; exports.getCAChainArray = getCAChainArray; exports.createCertificateOptions = createCertificateOptions; exports.requestAccess = requestAccess; const fs_1 = require("fs"); const lodash_1 = __importDefault(require("lodash")); const path_1 = __importDefault(require("path")); const selfsigned_1 = require("selfsigned"); const stat_mode_1 = require("stat-mode"); const debug_1 = require("./debug"); const dummysecurity_1 = __importDefault(require("./dummysecurity")); const debug = (0, debug_1.createDebug)('signalk-server:security'); class InvalidTokenError extends Error { constructor(...args) { super(...args); Error.captureStackTrace(this, InvalidTokenError); } } exports.InvalidTokenError = InvalidTokenError; function startSecurity(app, securityConfig) { let securityStrategyModuleName = process.env.SECURITYSTRATEGY || lodash_1.default.get(app, 'config.settings.security.strategy'); if (securityStrategyModuleName) { if (securityStrategyModuleName === 'sk-simple-token-security') { console.log('The sk-simple-token-security security strategy is depricated, please update to @signalk/sk-simple-token-security'); process.exit(1); } else if (securityStrategyModuleName === '@signalk/sk-simple-token-security') { securityStrategyModuleName = './tokensecurity'; } const config = securityConfig || getSecurityConfig(app, true); // eslint-disable-next-line @typescript-eslint/no-require-imports app.securityStrategy = require(securityStrategyModuleName)(app, config); if (securityConfig) { app.securityStrategy.configFromArguments = true; app.securityStrategy.securityConfig = securityConfig; } } else { app.securityStrategy = (0, dummysecurity_1.default)(); } } function getSecurityConfig(app, forceRead = false) { if (!forceRead && app.securityStrategy?.configFromArguments) { return app.securityStrategy.securityConfig; } else { try { const optionsAsString = (0, fs_1.readFileSync)(pathForSecurityConfig(app), 'utf8'); return JSON.parse(optionsAsString); } catch (e) { console.error('Could not parse security config'); console.error(e.message); return {}; } } } function pathForSecurityConfig(app) { return path_1.default.join(app.config.configPath, 'security.json'); } function saveSecurityConfig(app, data, callback) { if (app.securityStrategy.configFromArguments) { app.securityStrategy.securityConfig = data; if (callback) { callback(null); } } else { //const config = JSON.parse(JSON.stringify(data)) const configPath = pathForSecurityConfig(app); (0, fs_1.writeFile)(configPath, JSON.stringify(data, null, 2), (err) => { if (!err) { (0, fs_1.chmodSync)(configPath, '600'); } if (callback) { callback(err); } }); } } function getCertificateOptions(app, cb) { let certLocation; if (!app.config.configPath || (0, fs_1.existsSync)('./settings/ssl-cert.pem')) { certLocation = './settings'; } else { certLocation = app.config.configPath; } const certFile = path_1.default.join(certLocation, 'ssl-cert.pem'); const keyFile = path_1.default.join(certLocation, 'ssl-key.pem'); const chainFile = path_1.default.join(certLocation, 'ssl-chain.pem'); if ((0, fs_1.existsSync)(certFile) && (0, fs_1.existsSync)(keyFile)) { if (!hasStrictPermissions((0, fs_1.statSync)(keyFile))) { cb(new Error(`${keyFile} must be accessible only by the user that is running the server, refusing to start`)); return; } if (!hasStrictPermissions((0, fs_1.statSync)(certFile))) { cb(new Error(`${certFile} must be accessible only by the user that is running the server, refusing to start`)); return; } let ca; if ((0, fs_1.existsSync)(chainFile)) { debug('Found ssl-chain.pem'); ca = getCAChainArray(chainFile); debug(JSON.stringify(ca, null, 2)); } debug(`Using certificate ssl-key.pem and ssl-cert.pem in ${certLocation}`); cb(null, { key: (0, fs_1.readFileSync)(keyFile), cert: (0, fs_1.readFileSync)(certFile), ca }); } else { createCertificateOptions(app, certFile, keyFile, cb); } } function hasStrictPermissions(stat) { if (process.platform === 'win32') { return true; } else { return /^-r[-w][-x]------$/.test(new stat_mode_1.Mode(stat).toString()); } } function getCAChainArray(filename) { let chainCert = new Array(); return (0, fs_1.readFileSync)(filename, 'utf8') .split('\n') .reduce((ca, line) => { chainCert.push(line); if (line.match(/-END CERTIFICATE-/)) { ca.push(chainCert.join('\n')); chainCert = []; } return ca; }, new Array()); } function createCertificateOptions(app, certFile, keyFile, cb) { const location = app.config.configPath ? app.config.configPath : './settings'; debug(`Creating certificate files in ${location}`); (0, selfsigned_1.generate)([{ name: 'commonName', value: 'localhost' }], { days: 3650 }, function (err, pems) { (0, fs_1.writeFileSync)(keyFile, pems.private); (0, fs_1.chmodSync)(keyFile, '600'); (0, fs_1.writeFileSync)(certFile, pems.cert); (0, fs_1.chmodSync)(certFile, '600'); cb(null, { key: pems.private, cert: pems.cert }); }); } function requestAccess(app, request, ip, updateCb) { const config = getSecurityConfig(app); return app.securityStrategy.requestAccess(config, request, ip, updateCb); } //# sourceMappingURL=security.js.map