UNPKG

@smartdcc/dccboxed-keystore

Version:
210 lines 8.39 kB
"use strict"; /* * Created on Thu Aug 04 2022 * * Copyright (c) 2022 Smart DCC Limited * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.KeyStoreDB = void 0; exports.queryOptionsHasEUI = queryOptionsHasEUI; const node_json_db_1 = require("node-json-db"); const JsonDBConfig_1 = require("node-json-db/dist/lib/JsonDBConfig"); const node_crypto_1 = require("node:crypto"); const certificateMetadata_1 = require("./certificateMetadata"); function pushOptionsHasCertificate(p) { return 'certificate' in p; } function queryOptionsHasEUI(q) { return 'eui' in q; } class KeyStoreDB { constructor(filename) { this.db = new node_json_db_1.JsonDB(new JsonDBConfig_1.Config(filename, true, true)); } /** * Wrap constructor for async operations. * * @param filename * @returns */ static async new(filename) { const instance = new KeyStoreDB(filename); await instance.db.load(); return instance; } async query(options) { if (queryOptionsHasEUI(options)) { let tree; try { tree = (await this.db.getData(`/${(0, certificateMetadata_1.normaliseEUI)(options.eui)}/${certificateMetadata_1.KeyUsage[options.keyUsage]}`)); } catch { return null; } /* accumulate matches */ const results = []; for (const serial in tree) { const e = tree[serial]; /* skip any entries without the correct role */ if (typeof options.role === 'number' && e.role !== options.role) { continue; } /* skip any entries without the request cert/key */ if (!(options.lookup in e) || typeof e[options.lookup] !== 'string') { continue; } let material; if (options.lookup === 'certificate') { material = { certificate: new node_crypto_1.X509Certificate(e.certificate), }; } else { material = { privateKey: (0, node_crypto_1.createPrivateKey)({ key: e.privateKey, type: 'pkcs8', format: 'pem', }), }; } const role = {}; if (typeof e.role === 'number') { role.role = e.role; } const name = {}; if (typeof e.name === 'string') { name.name = e.name; } results.push({ eui: options.eui instanceof certificateMetadata_1.EUI ? options.eui : new certificateMetadata_1.EUI(options.eui), keyUsage: [options.keyUsage], serial: BigInt(serial), ...role, ...material, ...name, }); } if (results.length >= 1) { return results; } } else { /* search by serial */ const tree = (await this.db.getData('/')); for (const id in tree) { for (const usage in tree[id]) { for (const serial in tree[id][usage]) { if (serial === options.serial.toString()) { const e = tree[id][usage][serial]; if (options.lookup in e && typeof e[options.lookup] === 'string') { let material; if (options.lookup === 'certificate') { material = { certificate: new node_crypto_1.X509Certificate(e.certificate), }; } else { material = { privateKey: (0, node_crypto_1.createPrivateKey)({ key: e.privateKey, type: 'pkcs8', format: 'pem', }), }; } const role = {}; if (typeof e.role === 'number') { role.role = e.role; } const name = {}; if (typeof e.name === 'string') { name.name = e.name; } return { eui: new certificateMetadata_1.EUI(id), keyUsage: [certificateMetadata_1.KeyUsage[usage]], serial: options.serial, ...role, ...material, ...name, }; } } } } } } return null; } async push(options) { let meta; const certificate = {}; const privateKey = {}; const name = {}; if (typeof options.name === 'string') { name.name = options.name; } if (pushOptionsHasCertificate(options)) { certificate.certificate = options.certificate.toJSON(); try { meta = (0, certificateMetadata_1.buildOrgCertificateMetadata)(options.certificate); } catch { try { meta = (0, certificateMetadata_1.buildDeviceCertificateMetadata)(options.certificate); } catch { throw new Error('unable to extract metadata from certificate'); } } if (options.private) { privateKey.privateKey = options.private?.export({ format: 'pem', type: 'pkcs8', }); if (!options.certificate.checkPrivateKey(options.private)) { throw new Error('invalid key pair'); } } } else { meta = { ...options.meta, eui: new certificateMetadata_1.EUI((0, certificateMetadata_1.normaliseEUI)(options.meta.eui)) }; privateKey.privateKey = options.private?.export({ format: 'pem', type: 'pkcs8', }); } const entry = { ...certificate, ...privateKey, ...name, }; if (typeof meta.role === 'number') { entry.role = meta.role; } if (meta.keyUsage.length !== 1 && meta.keyUsage[0] !== certificateMetadata_1.KeyUsage.digitalSignature && meta.keyUsage[0] !== certificateMetadata_1.KeyUsage.keyAgreement) { throw new Error('unsupported keyUsage'); } await this.db.push(`/${(0, certificateMetadata_1.normaliseEUI)(meta.eui)}/${certificateMetadata_1.KeyUsage[meta.keyUsage[0]]}/${meta.serial}`, entry, false); return meta; } } exports.KeyStoreDB = KeyStoreDB; //# sourceMappingURL=db.js.map