Merge pull request #47 from shocknet/feature/api-caching
Feature/api caching
This commit is contained in:
commit
40365122f2
7 changed files with 90 additions and 16 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,5 +5,6 @@ services/auth/secrets.json
|
||||||
.directory
|
.directory
|
||||||
|
|
||||||
radata/
|
radata/
|
||||||
|
radata-*.tmp
|
||||||
*.cert
|
*.cert
|
||||||
*.key
|
*.key
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,8 @@
|
||||||
"main": "src/server.js",
|
"main": "src/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --experimental-modules src/server.js",
|
"start": "node --experimental-modules src/server.js",
|
||||||
"dev": "node --trace-warnings main.js -h 0.0.0.0",
|
"dev": "node --trace-warnings --max-old-space-size=4096 main.js -h 0.0.0.0",
|
||||||
|
"dev": "node main.js -h 0.0.0.0",
|
||||||
"dev:watch": "nodemon main.js -- -h 0.0.0.0",
|
"dev:watch": "nodemon main.js -- -h 0.0.0.0",
|
||||||
"test": "jest --no-cache",
|
"test": "jest --no-cache",
|
||||||
"test:watch": "jest --no-cache --watch",
|
"test:watch": "jest --no-cache --watch",
|
||||||
|
|
@ -30,6 +31,7 @@
|
||||||
"colors": "^1.3.0",
|
"colors": "^1.3.0",
|
||||||
"command-exists": "^1.2.6",
|
"command-exists": "^1.2.6",
|
||||||
"commander": "^2.9.0",
|
"commander": "^2.9.0",
|
||||||
|
"compression": "^1.7.4",
|
||||||
"cors": "^2.8.4",
|
"cors": "^2.8.4",
|
||||||
"debug": "^3.1.0",
|
"debug": "^3.1.0",
|
||||||
"dotenv": "^8.1.0",
|
"dotenv": "^8.1.0",
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
{}
|
{}
|
||||||
|
|
|
||||||
|
|
@ -212,6 +212,7 @@ module.exports = async (
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
app.use((req, res, next) => {
|
||||||
const deviceId = req.headers["x-shockwallet-device-id"];
|
const deviceId = req.headers["x-shockwallet-device-id"];
|
||||||
|
console.log("Decrypting route...")
|
||||||
try {
|
try {
|
||||||
if (nonEncryptedRoutes.includes(req.path)) {
|
if (nonEncryptedRoutes.includes(req.path)) {
|
||||||
return next();
|
return next();
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ const server = program => {
|
||||||
const Https = require('https')
|
const Https = require('https')
|
||||||
const Http = require('http')
|
const Http = require('http')
|
||||||
const Express = require('express')
|
const Express = require('express')
|
||||||
|
const Crypto = require('crypto')
|
||||||
const LightningServices = require('../utils/lightningServices')
|
const LightningServices = require('../utils/lightningServices')
|
||||||
const Encryption = require('../utils/encryptionStore')
|
const Encryption = require('../utils/encryptionStore')
|
||||||
const app = Express()
|
const app = Express()
|
||||||
|
|
||||||
const FS = require('../utils/fs')
|
const FS = require('../utils/fs')
|
||||||
|
const compression = require('compression')
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
const session = require('express-session')
|
const session = require('express-session')
|
||||||
const methodOverride = require('method-override')
|
const methodOverride = require('method-override')
|
||||||
|
|
@ -41,6 +43,25 @@ const server = program => {
|
||||||
|
|
||||||
logger.info('Mainnet Mode:', !!program.mainnet)
|
logger.info('Mainnet Mode:', !!program.mainnet)
|
||||||
|
|
||||||
|
const stringifyData = data => {
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
const stringifiedData = JSON.stringify(data)
|
||||||
|
return stringifiedData
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.toString) {
|
||||||
|
return data.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashData = data => {
|
||||||
|
return Crypto.createHash('SHA256')
|
||||||
|
.update(Buffer.from(stringifyData(data)))
|
||||||
|
.digest('hex')
|
||||||
|
}
|
||||||
|
|
||||||
const modifyResponseBody = (req, res, next) => {
|
const modifyResponseBody = (req, res, next) => {
|
||||||
const deviceId = req.headers['x-shockwallet-device-id']
|
const deviceId = req.headers['x-shockwallet-device-id']
|
||||||
const oldSend = res.send
|
const oldSend = res.send
|
||||||
|
|
@ -50,18 +71,35 @@ const server = program => {
|
||||||
if (args[0] && args[0].encryptedData && args[0].encryptionKey) {
|
if (args[0] && args[0].encryptedData && args[0].encryptionKey) {
|
||||||
logger.warn('Response loop detected!')
|
logger.warn('Response loop detected!')
|
||||||
oldSend.apply(res, args)
|
oldSend.apply(res, args)
|
||||||
} else {
|
return
|
||||||
// arguments[0] (or `data`) contains the response body
|
|
||||||
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
|
||||||
const encryptedMessage = authorized
|
|
||||||
? Encryption.encryptMessage({
|
|
||||||
message: args[0],
|
|
||||||
deviceId
|
|
||||||
})
|
|
||||||
: args[0]
|
|
||||||
args[0] = JSON.stringify(encryptedMessage)
|
|
||||||
oldSend.apply(res, args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const dataHash = hashData(args[0]).slice(-8)
|
||||||
|
res.set('ETag', dataHash)
|
||||||
|
|
||||||
|
console.log('ETag:', req.headers.etag)
|
||||||
|
console.log('Data Hash:', dataHash)
|
||||||
|
if (req.headers.etag === dataHash) {
|
||||||
|
console.log('Same Hash Detected!')
|
||||||
|
args[0] = null
|
||||||
|
res.status(304)
|
||||||
|
oldSend.apply(res, args)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// arguments[0] (or `data`) contains the response body
|
||||||
|
const authorized = Encryption.isAuthorizedDevice({ deviceId })
|
||||||
|
const encryptedMessage = authorized
|
||||||
|
? Encryption.encryptMessage({
|
||||||
|
message: args[0],
|
||||||
|
deviceId,
|
||||||
|
metadata: {
|
||||||
|
hash: dataHash
|
||||||
|
}
|
||||||
|
})
|
||||||
|
: args[0]
|
||||||
|
args[0] = JSON.stringify(encryptedMessage)
|
||||||
|
oldSend.apply(res, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next()
|
next()
|
||||||
|
|
@ -84,6 +122,8 @@ const server = program => {
|
||||||
)
|
)
|
||||||
const auth = require('../services/auth/auth')
|
const auth = require('../services/auth/auth')
|
||||||
|
|
||||||
|
app.use(compression())
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
logger.info('Route:', req.path)
|
logger.info('Route:', req.path)
|
||||||
if (unprotectedRoutes[req.method][req.path]) {
|
if (unprotectedRoutes[req.method][req.path]) {
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ const Encryption = {
|
||||||
|
|
||||||
return encryptedData.toString()
|
return encryptedData.toString()
|
||||||
},
|
},
|
||||||
encryptMessage: ({ deviceId, message }) => {
|
encryptMessage: ({ deviceId, message, metadata }) => {
|
||||||
const parsedMessage =
|
const parsedMessage =
|
||||||
typeof message === 'object' ? JSON.stringify(message) : message
|
typeof message === 'object' ? JSON.stringify(message) : message
|
||||||
const data = Buffer.from(parsedMessage)
|
const data = Buffer.from(parsedMessage)
|
||||||
|
|
@ -66,7 +66,7 @@ const Encryption = {
|
||||||
Buffer.from(cipher.final())
|
Buffer.from(cipher.final())
|
||||||
])
|
])
|
||||||
const encryptedData = encryptedBuffer.toString('base64')
|
const encryptedData = encryptedBuffer.toString('base64')
|
||||||
return { encryptedData, encryptedKey, iv: iv.toString('hex') }
|
return { encryptedData, encryptedKey, iv: iv.toString('hex'), metadata }
|
||||||
},
|
},
|
||||||
decryptMessage: ({ message, key, iv }) => {
|
decryptMessage: ({ message, key, iv }) => {
|
||||||
const data = Buffer.from(message, 'base64')
|
const data = Buffer.from(message, 'base64')
|
||||||
|
|
|
||||||
32
yarn.lock
32
yarn.lock
|
|
@ -703,7 +703,7 @@ abbrev@1:
|
||||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||||
|
|
||||||
accepts@~1.3.4, accepts@~1.3.7:
|
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
|
||||||
version "1.3.7"
|
version "1.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
|
||||||
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
|
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
|
||||||
|
|
@ -1332,6 +1332,11 @@ bytebuffer@~5:
|
||||||
dependencies:
|
dependencies:
|
||||||
long "~3"
|
long "~3"
|
||||||
|
|
||||||
|
bytes@3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||||
|
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
|
||||||
|
|
||||||
bytes@3.1.0:
|
bytes@3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
|
||||||
|
|
@ -1614,6 +1619,26 @@ component-inherit@0.0.3:
|
||||||
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
|
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
|
||||||
integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
|
integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
|
||||||
|
|
||||||
|
compressible@~2.0.16:
|
||||||
|
version "2.0.18"
|
||||||
|
resolved "https://registry.npm.taobao.org/compressible/download/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
|
||||||
|
integrity sha1-r1PMprBw1MPAdQ+9dyhqbXzEb7o=
|
||||||
|
dependencies:
|
||||||
|
mime-db ">= 1.43.0 < 2"
|
||||||
|
|
||||||
|
compression@^1.7.4:
|
||||||
|
version "1.7.4"
|
||||||
|
resolved "https://registry.npm.taobao.org/compression/download/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
|
||||||
|
integrity sha1-lVI+/xcMpXwpoMpB5v4TH0Hlu48=
|
||||||
|
dependencies:
|
||||||
|
accepts "~1.3.5"
|
||||||
|
bytes "3.0.0"
|
||||||
|
compressible "~2.0.16"
|
||||||
|
debug "2.6.9"
|
||||||
|
on-headers "~1.0.2"
|
||||||
|
safe-buffer "5.1.2"
|
||||||
|
vary "~1.1.2"
|
||||||
|
|
||||||
concat-map@0.0.1:
|
concat-map@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||||
|
|
@ -4195,6 +4220,11 @@ mime-db@1.40.0:
|
||||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
|
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
|
||||||
integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
|
integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
|
||||||
|
|
||||||
|
"mime-db@>= 1.43.0 < 2":
|
||||||
|
version "1.43.0"
|
||||||
|
resolved "https://registry.npm.taobao.org/mime-db/download/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
|
||||||
|
integrity sha1-ChLgUCZQ5HPXNVNQUOfI9OtPrlg=
|
||||||
|
|
||||||
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
|
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
|
||||||
version "2.1.24"
|
version "2.1.24"
|
||||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
|
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue