import * as path from 'path' import * as fetch from 'node-fetch' import {parseLDAT} from '../utils/ldat' import * as rsa from '../crypto/rsa' import * as crypto from 'crypto' import * as meme from '../utils/meme' import * as FormData from 'form-data' import { models } from '../models' import * as RNCryptor from 'jscryptor' import {sendMessage} from './send' const constants = require(path.join(__dirname,'../../config/constants.json')) const msgtypes = constants.message_types export async function modifyPayloadAndSaveMediaKey(payload, chat, sender) { if(payload.type!==msgtypes.attachment) return payload try{ const ret = await downloadAndUploadAndSaveReturningTermsAndKey(payload,chat,sender) return fillmsg(payload, ret) // key is re-encrypted later } catch(e) { console.log("[modify] error", e) return payload } } // "purchase" type export async function purchaseFromOriginalSender(payload, chat, purchaser){ if(payload.type!==msgtypes.purchase) return const mt = payload.message && payload.message.mediaToken const amount = payload.message.amount const muid = mt && mt.split('.').length && mt.split('.')[1] if(!muid) return const mediaKey = await models.MediaKey.findOne({where:{originalMuid:muid}}) const terms = parseLDAT(mt) let price = terms.meta && terms.meta.amt if(amount{}, failure: ()=>{} }) } else { console.log("NO MEDIA KEY EXISTS YET") const ogmsg = await models.Message.findOne({where:{chatId:chat.id,mediaToken:mt}}) // purchase it from creator (send "purchase") const msg={amount, mediaToken:mt} console.log("GO AHEARD AND BUY!!! from:",ogmsg.sender,{ chat: {...chat.dataValues, contactIds:[ogmsg.sender]}, sender: { ...owner.dataValues, ...purchaser&&purchaser.alias && {alias:purchaser.alias} }, type: constants.message_types.purchase, message: msg, amount: amount, success: ()=>{}, failure: ()=>{} }) sendMessage({ chat: {...chat.dataValues, contactIds:[ogmsg.sender]}, sender: { ...owner.dataValues, ...purchaser&&purchaser.alias && {alias:purchaser.alias} }, type: constants.message_types.purchase, message: msg, amount: amount, success: ()=>{}, failure: ()=>{} }) } } export async function sendFinalMemeIfFirstPurchaser(payload, chat, sender){ if(payload.type!==msgtypes.purchase_accept) return console.log("PURCHASE ACCEPT!!!!!") const mt = payload.message && payload.message.mediaToken const typ = payload.message && payload.message.mediaType if(!mt) return const muid = mt && mt.split('.').length && mt.split('.')[1] if(!muid) return const existingMediaKey = await models.MediaKey.findOne({where:{muid}}) if(existingMediaKey) return // no need, its already been sent console.log("DOWNLOAD AND REIP:OAD",mt) const termsAndKey = await downloadAndUploadAndSaveReturningTermsAndKey(payload,chat,sender) const msg = await models.Message.findOne({where:{mediaToken:mt,type:msgtypes.attachment}}) console.log("OG MSG",msg.dataValues) // not found const ogSender = await models.Contact.findOne({where:{id:msg.sender}}) console.log("OG SENDER",ogSender.dataValues) // find "purchase" Message with the OG muid // send it to the purchaser const owner = await models.Contact.findOne({where: {isOwner:true}}) console.log("SEND firST PURHCASE ACCEPT MSG!") sendMessage({ sender: { ...owner.dataValues, ...ogSender&&ogSender.alias && {alias:ogSender.alias} }, chat:{ ...chat.dataValues, contactIds:[sender.id], }, type:msgtypes.purchase_accept, message:{ ...termsAndKey, mediaType: typ, }, success: ()=>{}, receive: ()=>{} }) } function fillmsg(full, props){ return { ...full, message: { ...full.message, ...props, } } } async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)) } export async function downloadAndUploadAndSaveReturningTermsAndKey(payload, chat, sender){ const mt = payload.message && payload.message.mediaToken const key = payload.message && payload.message.mediaKey const typ = payload.message && payload.message.mediaType if(!mt || !key) return payload // save anyway?????????? const ogmuid = mt && mt.split('.').length && mt.split('.')[1] const terms = parseLDAT(mt) if(!terms.host) return payload try { const r = await fetch(`https://${terms.host}/file/${mt}`, { headers: {'Authorization': `Bearer ${meme.mediaToken}`} }) const buf = await r.buffer() const decMediaKey = rsa.decrypt(chat.groupPrivateKey, key) const imgBuf = RNCryptor.Decrypt(buf.toString('base64'), decMediaKey) const newKey = crypto.randomBytes(20).toString('hex') const encImgBase64 = RNCryptor.Encrypt(imgBuf, newKey) var encImgBuffer = Buffer.from(encImgBase64,'base64'); const form = new FormData() form.append('file', encImgBuffer, { contentType: typ||'image/jpg', filename: 'Image.jpg', knownLength:encImgBuffer.length, }) const formHeaders = form.getHeaders() const resp = await fetch(`https://${terms.host}/file`, { method: 'POST', headers: { ...formHeaders, // THIS IS REQUIRED!!! 'Authorization': `Bearer ${meme.mediaToken}`, }, body:form }) let json = await resp.json() if(!json.muid) throw new Error('no muid') // PUT NEW TERMS, to finish in personalizeMessage const amt = terms.meta&&terms.meta.amt const ttl = terms.meta&&terms.meta.ttl const mediaTerms: {[k:string]:any} = { muid:json.muid, ttl:ttl||31536000, host:'', meta:{...amt && {amt}}, skipSigning: amt ? true : false // only sign if its free } const encKey = rsa.encrypt(chat.groupKey, newKey.slice()) var date = new Date() date.setMilliseconds(0) console.log('[modify] save media key!',{ muid:json.muid, chatId:chat.id, key: encKey, messageId: (payload.message&&payload.message.id)||0, receiver: 0, sender: sender.id, // the og sender createdAt: date, }) await sleep(1) await models.MediaKey.create({ muid:json.muid, chatId:chat.id, key:encKey, messageId: (payload.message&&payload.message.id)||0, receiver: 0, sender: sender.id, // the og sender createdAt: date, originalMuid: ogmuid, }) return {mediaTerms,mediaKey:encKey} } catch(e) { throw e } }