From f43982d5413a7903cb6166d7712912ba2a9783d1 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Mon, 22 Feb 2021 15:37:20 -0400 Subject: [PATCH] content reveal order --- services/gunDB/contact-api/jobs/onOrders.js | 90 ++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/jobs/onOrders.js b/services/gunDB/contact-api/jobs/onOrders.js index 8d7a717e..ae048abe 100644 --- a/services/gunDB/contact-api/jobs/onOrders.js +++ b/services/gunDB/contact-api/jobs/onOrders.js @@ -21,6 +21,7 @@ const { const { writeCoordinate } = require('../../../coordinates') const Key = require('../key') const Utils = require('../utils') +const { gunUUID } = require('../../../../utils') const getUser = () => require('../../Mediator').getUser() @@ -220,7 +221,7 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => { /** * @param {Common.InvoiceWhenListed} invoice */ - const onData = invoice => { + const onData = async invoice => { if (invoice.settled) { writeCoordinate(invoice.r_hash.toString(), coord) @@ -231,7 +232,92 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => { .get(/** @type {string} */ (order.ackInfo)) .set(null) // each item in the set is a tip } else if (order.targetType === 'contentReveal') { - // TODO + // ----------------------------------------- + logger.debug('Content Reveal') + + //assuming digital product that only requires to be unlocked + const postID = order.ackInfo + + if (!Common.isPopulatedString(postID)) { + logger.error(`Invalid post ID`) + logger.error(postID) + return + } + + // TODO: do this reactively + const selectedPost = await new Promise(res => { + getUser() + .get(Key.POSTS_NEW) + .get(postID) + .load(res) + }) + + logger.debug(selectedPost) + + if (Common.isPost(selectedPost)) { + logger.error('Post id provided does not correspond to a valid post') + return + } + + /** + * @type {Record} + */ + const contentsToSend = {} + const mySecret = require('../../Mediator').getMySecret() + logger.debug('SECRET OK') + let privateFound = false + await Common.Utils.asyncForEach( + Object.entries(selectedPost.contentItems), + async ([contentID, item]) => { + if ( + item.type !== 'image/embedded' && + item.type !== 'video/embedded' + ) { + return //only visual content can be private + } + if (!item.isPrivate) { + return + } + privateFound = true + const decrypted = await SEA.decrypt(item.magnetURI, mySecret) + contentsToSend[contentID] = decrypted + } + ) + if (!privateFound) { + logger.error(`Post provided does not contain private content`) + return + } + const ackData = { unlockedContents: contentsToSend } + const toSend = JSON.stringify(ackData) + const encrypted = await SEA.encrypt(toSend, secret) + const ordResponse = { + type: 'orderAck', + response: encrypted + } + logger.debug('RES READY') + + const uuid = gunUUID() + orderResponse.ackNode = uuid + + await /** @type {Promise} */ (new Promise((res, rej) => { + getUser() + .get(Key.ORDER_TO_RESPONSE) + .get(uuid) + .put(ordResponse, ack => { + if (ack.err && typeof ack.err !== 'number') { + rej( + new Error( + `Error saving encrypted orderAck to order to response usergraph: ${ack}` + ) + ) + } else { + res() + } + }) + })) + logger.debug('RES SENT CONTENT') + + // ---------------------------------------------------------------------------------- } else if (order.targetType === 'spontaneousPayment') { // no action required } else if (order.targetType === 'torrentSeed') {