|
|
@@ -0,0 +1,181 @@
|
|
|
+const fs = require('fs');
|
|
|
+const NodeRSA = require('node-rsa');
|
|
|
+const { config } = require('process');
|
|
|
+const logger = require('../logger').global;
|
|
|
+
|
|
|
+const keysFile = '/data/keys.json';
|
|
|
+
|
|
|
+let instance = null;
|
|
|
+
|
|
|
+// 1. Load from config file first (not recommended anymore)
|
|
|
+// 2. Use config env variables next
|
|
|
+const configure = () => {
|
|
|
+ const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json';
|
|
|
+ if (fs.existsSync(filename)) {
|
|
|
+ let configData;
|
|
|
+ try {
|
|
|
+ configData = require(filename);
|
|
|
+ } catch (err) {
|
|
|
+ // do nothing
|
|
|
+ }
|
|
|
+ if (configData?.database && configData?.database?.engine) {
|
|
|
+ logger.info(`Using configuration from file: ${filename}`);
|
|
|
+ instance = configData;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const envMysqlHost = process.env.DB_MYSQL_HOST || null;
|
|
|
+ const envMysqlUser = process.env.DB_MYSQL_USER || null;
|
|
|
+ const envMysqlName = process.env.DB_MYSQL_NAME || null;
|
|
|
+ if (envMysqlHost && envMysqlUser && envMysqlName) {
|
|
|
+ // we have enough mysql creds to go with mysql
|
|
|
+ logger.info('Using MySQL configuration');
|
|
|
+ instance = {
|
|
|
+ database: {
|
|
|
+ engine: 'mysql',
|
|
|
+ host: envMysqlHost,
|
|
|
+ port: process.env.DB_MYSQL_PORT || 3306,
|
|
|
+ user: envMysqlUser,
|
|
|
+ password: process.env.DB_MYSQL_PASSWORD,
|
|
|
+ name: envMysqlName,
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite';
|
|
|
+ logger.info(`Using Sqlite: ${envSqliteFile}`);
|
|
|
+ instance = {
|
|
|
+ database: {
|
|
|
+ engine: 'knex-native',
|
|
|
+ knex: {
|
|
|
+ client: 'sqlite3',
|
|
|
+ connection: {
|
|
|
+ filename: envSqliteFile
|
|
|
+ },
|
|
|
+ useNullAsDefault: true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Get keys from file
|
|
|
+ if (!fs.existsSync(keysFile)) {
|
|
|
+ generateKeys();
|
|
|
+ } else if (!!process.env.DEBUG) {
|
|
|
+ logger.info('Keys file exists OK');
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ instance.keys = require(keysFile);
|
|
|
+ } catch (err) {
|
|
|
+ logger.error('Could not read JWT key pair from config file: ' + keysFile, err);
|
|
|
+ process.exit(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.debug('Configuration: ' + JSON.stringify(instance, null, 2));
|
|
|
+};
|
|
|
+
|
|
|
+const generateKeys = () => {
|
|
|
+ logger.info('Creating a new JWT key pair...');
|
|
|
+ // Now create the keys and save them in the config.
|
|
|
+ const key = new NodeRSA({ b: 2048 });
|
|
|
+ key.generateKeyPair();
|
|
|
+
|
|
|
+ const keys = {
|
|
|
+ key: key.exportKey('private').toString(),
|
|
|
+ pub: key.exportKey('public').toString(),
|
|
|
+ };
|
|
|
+
|
|
|
+ // Write keys config
|
|
|
+ try {
|
|
|
+ fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
|
|
|
+ } catch (err) {
|
|
|
+ logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' . err.message);
|
|
|
+ process.exit(1);
|
|
|
+ }
|
|
|
+ logger.info('Wrote JWT key pair to config file: ' + keysFile);
|
|
|
+};
|
|
|
+
|
|
|
+module.exports = {
|
|
|
+
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ * @param {string} key ie: 'database' or 'database.engine'
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ has: function(key) {
|
|
|
+ instance === null && configure();
|
|
|
+ const keys = key.split('.');
|
|
|
+ let level = instance;
|
|
|
+ let has = true;
|
|
|
+ keys.forEach((keyItem) =>{
|
|
|
+ if (typeof level[keyItem] === 'undefined') {
|
|
|
+ has = false;
|
|
|
+ } else {
|
|
|
+ level = level[keyItem];
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return has;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Gets a specific key from the top level
|
|
|
+ *
|
|
|
+ * @param {string} key
|
|
|
+ * @returns {*}
|
|
|
+ */
|
|
|
+ get: function (key) {
|
|
|
+ instance === null && configure();
|
|
|
+ if (key && typeof instance[key] !== 'undefined') {
|
|
|
+ return instance[key];
|
|
|
+ }
|
|
|
+ return instance;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Is this a sqlite configuration?
|
|
|
+ *
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ isSqlite: function () {
|
|
|
+ instance === null && configure();
|
|
|
+ return instance.database?.knex && instance.database?.knex?.client === 'sqlite3';
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Are we running in debug mdoe?
|
|
|
+ *
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ debug: function () {
|
|
|
+ return !!process.env.DEBUG;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a public key
|
|
|
+ *
|
|
|
+ * @returns {string}
|
|
|
+ */
|
|
|
+ getPublicKey: function () {
|
|
|
+ instance === null && configure();
|
|
|
+ return instance?.keys?.pub
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns a private key
|
|
|
+ *
|
|
|
+ * @returns {string}
|
|
|
+ */
|
|
|
+ getPrivateKey: function () {
|
|
|
+ instance === null && configure();
|
|
|
+ return instance?.keys?.key;
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @returns {boolean}
|
|
|
+ */
|
|
|
+ useLetsencryptStaging: function () {
|
|
|
+ return !!process.env.LE_STAGING;
|
|
|
+ }
|
|
|
+};
|