Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support signing all responses using the storage node VDA private key. #42

Merged
merged 2 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
"cors": "^2.8.5",
"did-resolver": "^3.1.0",
"dotenv": "^8.2.0",
"ethers": "^4.0.42",
"express": "^4.17.1",
"express-basic-auth": "git+https://github.com/Mozzler/express-basic-auth.git",
"jsonwebtoken": "^8.5.1",
Expand All @@ -77,6 +76,7 @@
"@verida/client-ts": "^2.0.0-rc1",
"axios": "^0.27.2",
"claudia": "^5.14.1",
"ethers": "^5.7.2",
"mocha": "^7.0.0",
"nodemon": "^2.0.14",
"pouchdb": "^7.2.2",
Expand Down
2 changes: 2 additions & 0 deletions sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ DB_REFRESH_TOKENS="verida_refresh_tokens"
DB_DB_INFO="verida_db_info"
# How often garbage collection runs (1=100%, 0.5 = 50%)
GC_PERCENT=0.1
# Verida Private Key as hex string (used to sign responses). Including leading 0x.
VDA_PRIVATE_KEY=

// alpha numeric only
DB_PUBLIC_USER=784c2n780c9cn0789
Expand Down
13 changes: 13 additions & 0 deletions src/components/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ class Utils {
return dids ? dids.map(did => this.generateUsername(did, contextName)) : []
}

signResponse(response, privateKey) {
privateKey = new Uint8Array(Buffer.from(privateKey.substring(2),'hex'))
return EncryptionUtils.signData(response, privateKey)
}

signedResponse(data, response) {
const signature = this.signResponse(data, process.env.VDA_PRIVATE_KEY)
return response.status(200).send({
...data,
signature
});
}

}

let utils = new Utils();
Expand Down
8 changes: 4 additions & 4 deletions src/controllers/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ class AuthController {
const contextName = req.body.contextName;
const authJwt = AuthManager.generateAuthJwt(did, contextName)

return res.status(200).send({
return Utils.signedResponse({
status: "success",
authJwt
});
}, res);
}

/**
Expand Down Expand Up @@ -176,10 +176,10 @@ class AuthController {
const isValid = await AuthManager.verifyRefreshToken(refreshToken, contextName)

if (isValid) {
return res.status(200).send({
return Utils.signedResponse({
status: "success",
expires: isValid.exp
})
}, res)
} else {
return res.status(401).send({
status: "fail"
Expand Down
29 changes: 15 additions & 14 deletions src/controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import Db from '../components/db.js'
class UserController {

async getPublic(req, res) {
return res.status(200).send({
return Utils.signedResponse({
status: "success",
user: {
username: process.env.DB_PUBLIC_USER,
password: process.env.DB_PUBLIC_PASS,
dsn: Db.buildDsn(process.env.DB_PUBLIC_USER, process.env.DB_PUBLIC_PASS)
}
});
}, res);
}

// Grant a user access to a user's database
Expand Down Expand Up @@ -45,9 +45,9 @@ class UserController {
if (success) {
await DbManager.saveUserDatabase(did, contextName, databaseName, databaseHash, options.permissions)

return res.status(200).send({
return Utils.signedResponse({
status: "success"
});
}, res);
}
} catch (err) {
return res.status(400).send({
Expand Down Expand Up @@ -85,9 +85,9 @@ class UserController {
if (success) {
await DbManager.deleteUserDatabase(did, contextName, databaseName, databaseHash)

return res.status(200).send({
return Utils.signedResponse({
status: "success"
});
}, res);
}
} catch (err) {
return res.status(500).send({
Expand Down Expand Up @@ -130,10 +130,10 @@ class UserController {
}
};

return res.status(200).send({
return Utils.signedResponse({
status: "success",
results
});
}, res);
}

// Update permissions on a user's database
Expand All @@ -152,9 +152,9 @@ class UserController {
if (success) {
await DbManager.saveUserDatabase(did, contextName, databaseName, databaseHash, options.permissions)

return res.status(200).send({
return Utils.signedResponse({
status: "success"
});
}, res);
}
} catch (err) {
return res.status(500).send({
Expand All @@ -178,11 +178,12 @@ class UserController {

try {
const result = await DbManager.getUserDatabases(did, contextName)

if (result) {
return res.status(200).send({
return Utils.signedResponse({
status: "success",
result
});
}, res)
}
} catch (err) {
return res.status(500).send({
Expand Down Expand Up @@ -215,10 +216,10 @@ class UserController {
const result = await DbManager.getUserDatabase(did, contextName, databaseName)

if (result) {
return res.status(200).send({
return Utils.signedResponse({
status: "success",
result
});
}, res)
} else {
return res.status(404).send({
status: "fail",
Expand Down
2 changes: 1 addition & 1 deletion test/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default {
},
},
ENVIRONMENT: EnvironmentType.TESTNET,
SERVER_URL: `https://sn-acacia1.tn.verida.tech`,
SERVER_URL: `http://localhost:5000`,
VDA_PRIVATE_KEY: '0x19d3b996ec98a9a536efdffbae41e5eaaf117765a587483c69195c9460165c34',
CONTEXT_NAME: 'Verida Storage Node Test: Test Application 1',
DATABASE_SERVER: 'https://sn-acacia1.tn.verida.tech/', // http://localhost:5000/ for local testing when running local @verida/storage-node
Expand Down
17 changes: 13 additions & 4 deletions test/server.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import assert from 'assert';
import dotenv from 'dotenv';

import Axios from 'axios'

import AuthManager from "../src/components/authManager";
import TestUtils from "./utils"

import CONFIG from './config'

import dotenv from 'dotenv';
dotenv.config();

const { CONTEXT_NAME, SERVER_URL, TEST_DEVICE_ID } = CONFIG
Expand Down Expand Up @@ -150,7 +151,6 @@ describe("Server tests", function() {
// Valid response, which is unexpected
resolve(false)
}).catch((err) => {
console.log('b')
if (err.response.data.status == 'fail') {
resolve(true)
}
Expand All @@ -174,11 +174,12 @@ describe("Server tests", function() {
it("Creates database", async () => {
const response = await TestUtils.createDatabase(databaseName, accountInfo.did, CONTEXT_NAME, accessToken)
assert.equal(response.data.status, "success", "Successful create response")
assert.ok(TestUtils.verifySignature(response), 'Have a valid signature in response')
})

it("Gets active databases for a user", async () => {
// create a second database
await Axios.post(`${SERVER_URL}/user/createDatabase`, {
const createResponse = await Axios.post(`${SERVER_URL}/user/createDatabase`, {
databaseName: databaseName2,
did: accountInfo.did,
contextName: CONTEXT_NAME
Expand All @@ -188,6 +189,8 @@ describe("Server tests", function() {
}
});

assert.ok(TestUtils.verifySignature(createResponse), 'Have a valid signature in create response')

const response = await Axios.post(`${SERVER_URL}/user/databases`, {
databaseName,
did: accountInfo.did,
Expand All @@ -200,6 +203,7 @@ describe("Server tests", function() {

assert.equal(response.data.status, "success", "Successful databases response")
assert.ok(response.data.result.length > 1, 'At least two database returned')
assert.ok(TestUtils.verifySignature(response), 'Have a valid signature in databases response')

let found1 = false
let found2 = false
Expand Down Expand Up @@ -228,6 +232,8 @@ describe("Server tests", function() {
}
});

assert.ok(TestUtils.verifySignature(response), 'Have a valid signature in response')

assert.equal(response.data.status, "success", "Successful database info response")

const result = response.data.result
Expand All @@ -249,6 +255,8 @@ describe("Server tests", function() {
}
});

assert.ok(TestUtils.verifySignature(response), 'Have a valid signature in response')

assert.equal(response.data.status, "success", "Successful delete response")

const response2 = await Axios.post(`${SERVER_URL}/user/deleteDatabase`, {
Expand Down Expand Up @@ -284,7 +292,8 @@ describe("Server tests", function() {
assert.equal(response.data.results.length, 3, "Deleted three databases")
assert.ok(response.data.results.indexOf('DeleteAll_1') >= 0, 'Deleted correct databases (DeleteAll_1)')
assert.ok(response.data.results.indexOf('DeleteAll_2') >= 0, 'Deleted correct databases (DeleteAll_2)')
assert.ok(response.data.results.indexOf('DeleteAll_3') >= 0, 'Deleted correct databases (DeleteAll_3)')
assert.ok(response.data.results.indexOf('DeleteAll_3') >= 0, 'Deleted correct databases (DeleteAll_3)')
assert.ok(TestUtils.verifySignature(response), 'Have a valid signature in response')
})


Expand Down
19 changes: 19 additions & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ import Axios from 'axios'
import PouchDb from 'pouchdb'
import { AutoAccount } from "@verida/account-node"
import { Network } from "@verida/client-ts"
import EncryptionUtils from '@verida/encryption-utils';
import { ethers } from 'ethers'

import CONFIG from './config.js'

import dotenv from 'dotenv';
dotenv.config();

const VDA_PRIVATE_KEY = process.env.VDA_PRIVATE_KEY
const wallet = new ethers.Wallet(VDA_PRIVATE_KEY)
const VDA_PUBLIC_KEY = wallet.publicKey

class Utils {

async ensureVeridaAccount(privateKey) {
Expand Down Expand Up @@ -66,6 +75,16 @@ class Utils {
return response
}

verifySignature(response) {
if (!response.data.signature) {
return false
}

const signature = response.data.signature
delete response.data['signature']
return EncryptionUtils.verifySig(response.data, signature, VDA_PUBLIC_KEY)
}

}

const utils = new Utils()
Expand Down
52 changes: 9 additions & 43 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3117,21 +3117,6 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==

ethers@^4.0.42:
version "4.0.49"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894"
integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==
dependencies:
aes-js "3.0.0"
bn.js "^4.11.9"
elliptic "6.5.4"
hash.js "1.1.3"
js-sha3 "0.5.7"
scrypt-js "2.0.4"
setimmediate "1.0.4"
uuid "2.0.1"
xmlhttprequest "1.8.0"

ethers@^5.5.1:
version "5.7.0"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.0.tgz#0055da174b9e076b242b8282638bc94e04b39835"
Expand Down Expand Up @@ -3608,14 +3593,6 @@ hash-base@^3.0.0:
readable-stream "^3.6.0"
safe-buffer "^5.2.0"

hash.js@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846"
integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==
dependencies:
inherits "^2.0.3"
minimalistic-assert "^1.0.0"

hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3:
version "1.1.7"
resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
Expand Down Expand Up @@ -3921,11 +3898,6 @@ jmespath@0.16.0:
resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076"
integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==

js-sha3@0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7"
integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==

js-sha3@0.8.0, js-sha3@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
Expand Down Expand Up @@ -5088,6 +5060,15 @@ sax@>=0.6.0:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==

schema-utils@^2.6.5:
version "2.7.1"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==
dependencies:
"@types/json-schema" "^7.0.5"
ajv "^6.12.4"
ajv-keywords "^3.5.2"

scrypt-js@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16"
Expand Down Expand Up @@ -5152,11 +5133,6 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==

setimmediate@1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f"
integrity sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==

setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
Expand Down Expand Up @@ -5585,11 +5561,6 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==

uuid@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac"
integrity sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==

uuid@8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c"
Expand Down Expand Up @@ -5732,11 +5703,6 @@ xmlbuilder@~9.0.1:
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d"
integrity sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==

xmlhttprequest@1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==

xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
Expand Down