From 7532bc486e170f79d210f3930c87d3c2fe13edbc Mon Sep 17 00:00:00 2001 From: brennanjl Date: Tue, 15 Feb 2022 12:52:25 -0800 Subject: [PATCH] Query sig --- .gitignore | 1 + index.js | 5 +-- package-lock.json | 69 +++++++++++++++++++++++++++++--- package.json | 2 + src/create.js | 8 ++-- src/createDataWrite.js | 25 ++++++++++++ src/createMoat.js | 10 +++-- src/main.js | 14 +++---- src/utils/generateAPIKey.js | 5 ++- src/utils/generateKeyPair.js | 67 +++++++++++++++++++++++++++++++ src/utils/generateKeyPairNode.js | 24 +++++++++++ src/utils/sign.js | 12 ++++++ t.js | 21 +++++----- 13 files changed, 225 insertions(+), 38 deletions(-) create mode 100644 src/createDataWrite.js create mode 100644 src/utils/generateKeyPair.js create mode 100644 src/utils/generateKeyPairNode.js create mode 100644 src/utils/sign.js diff --git a/.gitignore b/.gitignore index 8c3b677..21798e2 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,4 @@ cloud_config/ # Test Files testFiles/ +devKey.js \ No newline at end of file diff --git a/index.js b/index.js index 7b19a81..0f7f6ec 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,6 @@ const createConnector = require('./src/main.js') const createConnectorRegistry = require('./src/mainRegistry.js') const createMoat = require('./src/createMoat.js') -const KwilDB = {createConnector, createMoat} -const KwilDB2 = {createConnectorRegistry} +const KwilDB = {createConnector, createMoat, createConnectorRegistry} -module.exports = {KwilDB,KwilDB2} \ No newline at end of file +module.exports = KwilDB \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7563a91..b961a26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,22 @@ { "name": "kwildb", - "version": "1.0.14", + "version": "1.0.17", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "kwildb", - "version": "1.0.14", + "version": "1.0.17", "license": "ISC", "dependencies": { "axios": "^0.25.0", "base64url": "^3.0.1", "buffer": "^6.0.3", "ethers": "^5.5.4", + "jsrsasign": "^10.5.4", "jssha": "^3.2.0", "knex": "^1.0.1", + "pem-jwk": "^2.0.0", "pg": "^8.7.1", "react-native-crypto-js": "^1.0.0", "scrypt-js": "^3.0.1", @@ -1799,6 +1801,17 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -3769,6 +3782,14 @@ "node": ">=6" } }, + "node_modules/jsrsasign": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.4.tgz", + "integrity": "sha512-ohUbCLLurDCk0+91U5Z91tWP5NLvuxRFzmBo7oqyt7mLTbiPWXHrjeoLv6AoyycJOLSFbNv6azwOr+AoWZ0fqQ==", + "funding": { + "url": "https://github.com/kjur/jsrsasign#donations" + } + }, "node_modules/jssha": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz", @@ -4160,6 +4181,20 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/pem-jwk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pem-jwk/-/pem-jwk-2.0.0.tgz", + "integrity": "sha512-rFxu7rVoHgQ5H9YsP50dDWf0rHjreVA2z0yPiWr5WdH/UHb29hKtF7h6l8vNd1cbYR1t0QL+JKhW55a2ZV4KtA==", + "dependencies": { + "asn1.js": "^5.0.1" + }, + "bin": { + "pem-jwk": "bin/pem-jwk.js" + }, + "engines": { + "node": ">=5.10.0" + } + }, "node_modules/pg": { "version": "8.7.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", @@ -4471,8 +4506,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/saxes": { "version": "5.0.1", @@ -6311,6 +6345,17 @@ "sprintf-js": "~1.0.2" } }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -7790,6 +7835,11 @@ "minimist": "^1.2.5" } }, + "jsrsasign": { + "version": "10.5.4", + "resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.5.4.tgz", + "integrity": "sha512-ohUbCLLurDCk0+91U5Z91tWP5NLvuxRFzmBo7oqyt7mLTbiPWXHrjeoLv6AoyycJOLSFbNv6azwOr+AoWZ0fqQ==" + }, "jssha": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz", @@ -8074,6 +8124,14 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "pem-jwk": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pem-jwk/-/pem-jwk-2.0.0.tgz", + "integrity": "sha512-rFxu7rVoHgQ5H9YsP50dDWf0rHjreVA2z0yPiWr5WdH/UHb29hKtF7h6l8vNd1cbYR1t0QL+JKhW55a2ZV4KtA==", + "requires": { + "asn1.js": "^5.0.1" + } + }, "pg": { "version": "8.7.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", @@ -8299,8 +8357,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "saxes": { "version": "5.0.1", diff --git a/package.json b/package.json index b00eb6a..505ccaa 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,10 @@ "base64url": "^3.0.1", "buffer": "^6.0.3", "ethers": "^5.5.4", + "jsrsasign": "^10.5.4", "jssha": "^3.2.0", "knex": "^1.0.1", + "pem-jwk": "^2.0.0", "pg": "^8.7.1", "react-native-crypto-js": "^1.0.0", "scrypt-js": "^3.0.1", diff --git a/src/create.js b/src/create.js index d7651b0..ef01a91 100644 --- a/src/create.js +++ b/src/create.js @@ -4,9 +4,8 @@ const create = (_credentials) => { //Cleaning inputs and giving warnings //Trying to make this idiot-proof - if (_credentials.protocol == null || _credentials.host == null || _credentials.apiKey == null || _credentials.moat == null) { - throw new Error('Missing a credential. Mandatory are protocol, host, apiKey, and moat') - console.log('Input cleaning for connection is disabled, but I can tell you right now the rest of this shit isnt gonna work') + if (_credentials.protocol == null || _credentials.host == null || _credentials.moat == null) { + throw new Error('Missing a credential. Mandatory are protocol, host, privateKey, and moat') } if (_credentials.protocol == 'http' && _credentials.host != 'localhost') { @@ -27,8 +26,7 @@ const create = (_credentials) => { method: 'post', timeout: 20000, data: { - moat: _credentials.moat, - apiKey: _credentials.apiKey + moat: _credentials.moat } }; return params diff --git a/src/createDataWrite.js b/src/createDataWrite.js new file mode 100644 index 0000000..5ed3d51 --- /dev/null +++ b/src/createDataWrite.js @@ -0,0 +1,25 @@ +const { generateAPIKey } = require("./utils/generateAPIKey") +const { sha384 } = require("./utils/sha384") +const { sign } = require('./utils/sign.js') + +function createDataWrite(_data, _store, _secret, _moat, _privateJWK) { + const timestamp = Date.now() + const hash = sha384(_data+timestamp.toString()+_secret) + const queryID = generateAPIKey(64) + const signature = sign({data : _data, + timestamp: timestamp, + hash: hash, + queryID: queryID, + }, _privateJWK) + return { + data : _data, + timestamp: timestamp, + hash: hash, + queryID: queryID, + signature: signature, + store: _store, + moat: _moat + } +} + +module.exports = {createDataWrite} \ No newline at end of file diff --git a/src/createMoat.js b/src/createMoat.js index fef0324..723aaff 100644 --- a/src/createMoat.js +++ b/src/createMoat.js @@ -1,12 +1,14 @@ const axios = require('axios') const {generateAPIKey} = require('./utils/generateAPIKey.js') const {encryptKey} = require('./utils/encryptKey.js') +const {generateKeyPair} = require('./utils/generateKeyPair.js') const createMoat = async (_registry, _moat, _signature, _walletAddr) => { - const apiKey = generateAPIKey() + const keys = await generateKeyPair() + const privateKey = keys.privateKey const secret = generateAPIKey() - const encryptedKey = await encryptKey(_signature, _walletAddr, apiKey) + const encryptedKey = await encryptKey(_signature, _walletAddr, JSON.stringify(privateKey)) const encryptedSecret = await encryptKey(_signature, _walletAddr, secret) const params = { @@ -15,14 +17,14 @@ const createMoat = async (_registry, _moat, _signature, _walletAddr) => { timeout: 20000, data: { encryptedKey: encryptedKey, - key: apiKey, + publicKey: keys.publicKey.n, moat: _moat, address: _walletAddr, secret: encryptedSecret } }; let response = await axios(params) - response.data.apiKey = apiKey + response.data.apiKey = privateKey response.data.secret = secret return response.data } diff --git a/src/main.js b/src/main.js index 33c9f28..37d40a5 100644 --- a/src/main.js +++ b/src/main.js @@ -3,22 +3,18 @@ const create = require('./create.js') const Transaction = require('./transactions.js') const {createWebSocket} = require('./websocket.js') const table = require('./createTable.js') //Importing like this because I want the function to be called createTable -const { sha384 } = require('./utils/sha384.js') +const { createDataWrite } = require('./createDataWrite.js') const createConnector = (_credentials, _secret) => { const secret = _secret.slice() + const privateKey = _credentials.privateKey const params = create(_credentials) class KwilDB { - connectionParams = params - query = async (_query, _store = false) => { let _params = JSON.parse(JSON.stringify(params)) //we must copy the params since we will be writing to them - const timestamp = Date.now() - _params.data.query = _query - _params.data.store = _store - _params.data.timestamp = timestamp - _params.data.hash = sha384(_query+timestamp.toString()+secret) - _params.url = params.url + '/raw' //use .slice to copy + const dataWrite = createDataWrite(_query, _store, secret, _params.data.moat, privateKey) + _params.data = dataWrite + _params.url = params.url + '/raw' const response = await axios(_params) return response.data } diff --git a/src/utils/generateAPIKey.js b/src/utils/generateAPIKey.js index 6966762..3e8faf9 100644 --- a/src/utils/generateAPIKey.js +++ b/src/utils/generateAPIKey.js @@ -1,11 +1,12 @@ -const generateAPIKey = () => { +const generateAPIKey = (_length=32) => { const validChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890,.<>/?;:[]{}|+=_-)(*&^%$#@!~'; let salt = ''; - for (let i = 0; i < 32; i++) { + for (let i = 0; i < _length; i++) { const randomElement = Math.floor(Math.random() * validChars.length); salt = salt + validChars[randomElement]; } return salt; }; + module.exports = {generateAPIKey} diff --git a/src/utils/generateKeyPair.js b/src/utils/generateKeyPair.js new file mode 100644 index 0000000..70c7fe6 --- /dev/null +++ b/src/utils/generateKeyPair.js @@ -0,0 +1,67 @@ +const rs = require('jsrsasign') +const crypto = require('crypto') +const generateKeyPairNode = require('./generateKeyPairNode') + +const getPublicJWKFromPrivateJWK = (_privateJWK) => { + //This function takes a private key and returns a public JWK + let pubJWK = { + kty: _privateJWK.kty, + n: _privateJWK.n, + e: _privateJWK.e, + }; + return pubJWK; +}; + + + +const generateKeyPair = async () => { + + if (typeof crypto.generateKeyPair == "function") { + const keys = await generateKeyPairNode() + return keys + } + + async function WrapperFunction() { + if (typeof window === 'object') { + if (typeof window.crypto === 'object') { + try { + let keyPair = await window.crypto.subtle.generateKey( + { + name: 'RSA-PSS', + modulusLength: 4096, //can be 1024, 2048, or 4096 + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { name: 'SHA-256' }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512" + }, + true, //whether the key is extractable (i.e. can be used in exportKey) + ['sign', 'verify'] //can be any combination of "sign" and "verify" + ); + let jwk = await window.crypto.subtle.exportKey('jwk', keyPair.privateKey); + let privateKey = rs.KEYUTIL.getKey(jwk); + const rsaJWK = rs.KEYUTIL.getJWKFromKey(privateKey); + return { pubKey: getPublicJWKFromPrivateJWK(rsaJWK), privateKey: rsaJWK }; + } + catch ({ message } ) { + return { + status: 400, + message + }; + } + //return keyPair; + } + } //Test for node + else { + console.log('window.crypto not available. Key generation may take a while...'); + try { + let keyPair = await rs.KEYUTIL.generateKeypair('RSA', 4096); + const rsaJWK = await rs.KEYUTIL.getJWKFromKey(keyPair.prvKeyObj); + return { pubKey: getPublicJWKFromPrivateJWK(rsaJWK), privateKey: rsaJWK }; + } catch (e) { + console.log(e); + } + } + } + const retVal = await WrapperFunction() + return retVal +} + +module.exports = {generateKeyPair} \ No newline at end of file diff --git a/src/utils/generateKeyPairNode.js b/src/utils/generateKeyPairNode.js new file mode 100644 index 0000000..742b4cc --- /dev/null +++ b/src/utils/generateKeyPairNode.js @@ -0,0 +1,24 @@ +const crypto = require('crypto') +const pem2jwk = require('pem-jwk').pem2jwk + +async function generateKeyPairNode() { +if (typeof crypto.generateKeyPair == "function") { + //running in nodejs + const keys = crypto.generateKeyPairSync('rsa', { + modulusLength: 4096, // options + publicExponent: 0x10001, + publicKeyEncoding: { + type: 'pkcs1', + format: 'pem' + }, + privateKeyEncoding: { + type: 'pkcs1', + format: 'pem' + } + } + ) + return {publicKey: pem2jwk(keys.publicKey), privateKey: pem2jwk(keys.privateKey)} +} else {throw new Error('Not in nodejs')} +} + +module.exports = generateKeyPairNode \ No newline at end of file diff --git a/src/utils/sign.js b/src/utils/sign.js new file mode 100644 index 0000000..2ab5e86 --- /dev/null +++ b/src/utils/sign.js @@ -0,0 +1,12 @@ +const rs = require('jsrsasign') + +const sign = (_data, _privateJWK) => { + const privateKey = rs.KEYUTIL.getKey(_privateJWK); + var sig = new rs.crypto.Signature({ alg: 'SHA384withRSA' }); + sig.init(privateKey); + sig.updateString(_data); + let signature = sig.sign(); + return signature; +}; + +module.exports = {sign} \ No newline at end of file diff --git a/t.js b/t.js index 0afeb9d..dabb7cd 100644 --- a/t.js +++ b/t.js @@ -1,24 +1,27 @@ const KwilDB = require('./index.js') -const { decryptKey } = require('./src/utils/decryptKey.js') -const b64String = require('./testFiles/testFile') +const fs = require('fs') +let devKey +if (fs.existsSync('./devKey.js')) { + devKey = require('./devKey.js') +} const kwilDB = KwilDB.createConnector({ host: 'localhost', protocol: 'http', port: 1984, - moat: 'test7', - apiKey: '9ydoed[GGu,KJhalS(K>UJ]ET1[Gh?Uo-#rr3Dp[=>') + moat: 'test10', + privateKey: devKey, +}, 'ko#k^lKa=j|UN8!B8j.:g(gNrbD8]UTm') const testF = async () => { //console.log(await kwilDB.query(`SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'test';`)) - //console.log(await kwilDB.query('CREATE TABLE IF NOT EXISTS yuh;')) - //console.log(await KwilDB.createMoat('http://localhost:1984', 'test7', 'kwilSIG', '0xEF94BD30AA33de1677D7614D17aA39D493a485F1')) + console.log(await kwilDB.query('CREATE TABLE IF NOT EXISTS yuh (test_col varchar(10))', true)) + //console.log(await KwilDB.createMoat('http://localhost:1984', 'test10', 'kwilSIG', '0xEF94BD30AA33de1677D7614D17aA39D493a485F1')) //console.log(await decryptKey('kwilSIG', '0xEF94BD30AA33de1677D7614D17aA39D493a485F1', 'U2FsdGVkX1+154CCJHU2FUrV7DOd1INDyidhHpf+ciebVG/s3R/uWVPh5PRy6A64L+o/n2Z19L/YUKixGRpl6A==')) //console.log(await kwilDB.createTable('table2' , {test: {}, username: 'varchar(100)'})) - kwilDB.query(`INSERT INTO testtabl3 (test_col) VALUES ('hi')`, true) + //kwilDB.query(`INSERT INTO testtabl3 (test_col) VALUES ('hi')`, true) } -//testF() \ No newline at end of file +testF() \ No newline at end of file