Skip to content

Commit

Permalink
Remove config dep in updateContentBlacklist by extracting api signing (
Browse files Browse the repository at this point in the history
…#903)

* remove config dep in updateContentBlacklist by extracting api signing logic

* update imports to use apiSigning

* update imports to use apiSigning again

* remove blacklist env vars

* add WAIT_HOSTS back
  • Loading branch information
vicky-g committed Oct 8, 2020
1 parent 971a3bb commit 418e25b
Show file tree
Hide file tree
Showing 13 changed files with 56 additions and 75 deletions.
2 changes: 1 addition & 1 deletion creator-node/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
An Audius Creator Node maintains the availability of creators' content on IPFS. The information stored includes audius user metadata, images, and audio content. The content is backed by either aws S3 or a local directory.

To blacklist content on an already running node:
1. export the keys `delegatePrivateKey` and `creatorNodeEndpoint` in your terminal
1. Export the keys `delegatePrivateKey` and `creatorNodeEndpoint` in your terminal
```
$ export delegatePrivateKey='your_private_key'
$ export creatorNodeEndpoint='http://the_creator_node_endpoint'
Expand Down
5 changes: 1 addition & 4 deletions creator-node/compose/env/base.env
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,4 @@ debounceTime=5000
# Can be overriden.
creatorNodeIsDebug=true

# content blacklist
userBlacklist=
trackBlacklist=
WAIT_HOSTS=
WAIT_HOSTS=
2 changes: 0 additions & 2 deletions creator-node/default-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
"debounceTime": 30000,
"discoveryProviderWhitelist": "http://audius-disc-prov_web-server_1:5000",
"identityService": "http://audius-identity-service_identity-service_1:7000",
"userBlacklist": "",
"trackBlacklist": "",
"dataRegistryAddress": "",
"dataProviderUrl": "http://docker.for.mac.localhost:8545",
"dataNetworkId": "",
Expand Down
6 changes: 1 addition & 5 deletions creator-node/docker-compose/development.env
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,4 @@ isUserMetadataNode=false
debounceTime=5000

# not part of the config itself, but required for docker to know when ports are available
WAIT_HOSTS=docker.for.mac.localhost:4379,docker.for.mac.localhost:4432

# content blacklist
userBlacklist=
trackBlacklist=
WAIT_HOSTS=docker.for.mac.localhost:4379,docker.for.mac.localhost:4432
5 changes: 2 additions & 3 deletions creator-node/scripts/updateContentBlacklist.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
const axios = require('axios')

const models = require('../src/models')
const { generateTimestampAndSignature } = require('../src/apiHelpers')
const { generateTimestampAndSignature } = require('../src/apiSigning')

const PRIVATE_KEY = process.env.delegatePrivateKey
const CREATOR_NODE_ENDPOINT = process.env.creatorNodeEndpoint

// Available action types
const ACTION_ARR = ['ADD', 'DELETE']
const ACTION_SET = new Set(ACTION_ARR)
const TYPES_ARR = models.ContentBlacklist.Types
const TYPES_ARR = ['USER', 'TRACK']
const TYPES_SET = new Set(TYPES_ARR)

// Script usage:
Expand Down
42 changes: 1 addition & 41 deletions creator-node/src/apiHelpers.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
const config = require('./config')
const Web3 = require('web3')
const web3 = new Web3()

const { requestNotExcludedFromLogging } = require('./logging')
const versionInfo = require('../.version.json')
const { generateTimestampAndSignature } = require('./apiSigning')

module.exports.handleResponse = (func) => {
return async function (req, res, next) {
Expand Down Expand Up @@ -83,45 +82,6 @@ module.exports.successResponse = (obj = {}) => {
}
}

/**
* Generate the timestamp and signature for api signing
* @param {object} data
* @param {string} privateKey
*/
const generateTimestampAndSignature = (data, privateKey) => {
const timestamp = new Date().toISOString()
const toSignObj = { ...data, timestamp }
// JSON stringify automatically removes white space given 1 param
const toSignStr = JSON.stringify(sortKeys(toSignObj))
const toSignHash = web3.utils.keccak256(toSignStr)
const signedResponse = web3.eth.accounts.sign(toSignHash, privateKey)

return { timestamp, signature: signedResponse.signature }
}
module.exports.generateTimestampAndSignature = generateTimestampAndSignature

/**
* Recover the public wallet address
* @param {*} data obj with structure {...data, timestamp}
* @param {*} signature signature generated with signed data
*/
// eslint-disable-next-line no-unused-vars
const recoverWallet = (data, signature) => {
let structuredData = JSON.stringify(sortKeys(data))
const hashedData = web3.utils.keccak256(structuredData)
const recoveredWallet = web3.eth.accounts.recover(hashedData, signature)

return recoveredWallet
}
module.exports.recoverWallet = recoverWallet

const sortKeys = x => {
if (typeof x !== 'object' || !x) { return x }
if (Array.isArray(x)) { return x.map(sortKeys) }
return Object.keys(x).sort().reduce((o, k) => ({ ...o, [k]: sortKeys(x[k]) }), {})
}
module.exports.sortKeys = sortKeys

const errorResponse = module.exports.errorResponse = (statusCode, message) => {
return {
statusCode: statusCode,
Expand Down
44 changes: 44 additions & 0 deletions creator-node/src/apiSigning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const Web3 = require('web3')
const web3 = new Web3()

/**
* Generate the timestamp and signature for api signing
* @param {object} data
* @param {string} privateKey
*/
const generateTimestampAndSignature = (data, privateKey) => {
const timestamp = new Date().toISOString()
const toSignObj = { ...data, timestamp }
// JSON stringify automatically removes white space given 1 param
const toSignStr = JSON.stringify(sortKeys(toSignObj))
const toSignHash = web3.utils.keccak256(toSignStr)
const signedResponse = web3.eth.accounts.sign(toSignHash, privateKey)

return { timestamp, signature: signedResponse.signature }
}

/**
* Recover the public wallet address
* @param {*} data obj with structure {...data, timestamp}
* @param {*} signature signature generated with signed data
*/
// eslint-disable-next-line no-unused-vars
const recoverWallet = (data, signature) => {
let structuredData = JSON.stringify(sortKeys(data))
const hashedData = web3.utils.keccak256(structuredData)
const recoveredWallet = web3.eth.accounts.recover(hashedData, signature)

return recoveredWallet
}

const sortKeys = x => {
if (typeof x !== 'object' || !x) { return x }
if (Array.isArray(x)) { return x.map(sortKeys) }
return Object.keys(x).sort().reduce((o, k) => ({ ...o, [k]: sortKeys(x[k]) }), {})
}

module.exports = {
generateTimestampAndSignature,
recoverWallet,
sortKeys
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const {
successResponse,
errorResponseBadRequest,
errorResponseUnauthorized,
errorResponseServerError,
recoverWallet
errorResponseServerError
} = require('../../apiHelpers')
const { recoverWallet } = require('../../apiSigning')
const models = require('../../../src/models')
const config = require('../../config')

Expand Down
13 changes: 0 additions & 13 deletions creator-node/src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,19 +354,6 @@ const config = convict({
env: 'identityService',
default: ''
},
/** Manual content blacklists */
userBlacklist: {
doc: 'Comma-separated list of user blockchain IDs that creator node should avoid serving / storing',
format: String,
env: 'userBlacklist',
default: ''
},
trackBlacklist: {
doc: 'Comma-separated list of track blockchain IDs that creator node should avoid serving / storing',
format: String,
env: 'trackBlacklist',
default: ''
},
creatorNodeIsDebug: {
doc: 'Whether the creatornode is in debug mode.',
format: Boolean,
Expand Down
2 changes: 1 addition & 1 deletion creator-node/test/audiusUsers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const { getApp } = require('./lib/app')
const { createStarterCNodeUser } = require('./lib/dataSeeds')
const { getIPFSMock } = require('./lib/ipfsMock')
const { getLibsMock } = require('./lib/libsMock')
const { sortKeys } = require('../src/apiHelpers')
const { sortKeys } = require('../src/apiSigning')

describe('test AudiusUsers with mocked IPFS', function () {
let app, server, session, ipfsMock, libsMock
Expand Down
2 changes: 1 addition & 1 deletion creator-node/test/contentBlacklist.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const BlacklistManager = require('../src/blacklistManager')
const models = require('../src/models')
const ipfsClient = require('../src/ipfsClient')
const redis = require('../src/redis')
const { generateTimestampAndSignature } = require('../src/apiHelpers')
const { generateTimestampAndSignature } = require('../src/apiSigning')

const { getApp } = require('./lib/app')
const { getLibsMock } = require('./lib/libsMock')
Expand Down
2 changes: 1 addition & 1 deletion creator-node/test/fileManager.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { saveFileToIPFSFromFS, removeTrackFolder, saveFileFromBufferToIPFSAndDisk
const config = require('../src/config')
const models = require('../src/models')

const { sortKeys } = require('../src/apiHelpers')
const { sortKeys } = require('../src/apiSigning')

let storagePath = config.get('storagePath')
storagePath = storagePath.charAt(0) === '/' ? storagePath.slice(1) : storagePath
Expand Down
2 changes: 1 addition & 1 deletion creator-node/test/tracks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const { getApp } = require('./lib/app')
const { createStarterCNodeUser } = require('./lib/dataSeeds')
const { getIPFSMock } = require('./lib/ipfsMock')
const { getLibsMock } = require('./lib/libsMock')
const { sortKeys } = require('../src/apiHelpers')
const { sortKeys } = require('../src/apiSigning')

const testAudioFilePath = path.resolve(__dirname, 'testTrack.mp3')
const testAudioFileWrongFormatPath = path.resolve(__dirname, 'testTrackWrongFormat.jpg')
Expand Down

0 comments on commit 418e25b

Please sign in to comment.