From 267373a7877ee0cc52a7cf7a1ead5fc3acb6ab56 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 12:51:27 -0400 Subject: [PATCH 001/137] folder for utils --- .../contact-api/{utils.js => utils/index.js} | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) rename services/gunDB/contact-api/{utils.js => utils/index.js} (93%) diff --git a/services/gunDB/contact-api/utils.js b/services/gunDB/contact-api/utils/index.js similarity index 93% rename from services/gunDB/contact-api/utils.js rename to services/gunDB/contact-api/utils/index.js index d24173c0..9993f137 100644 --- a/services/gunDB/contact-api/utils.js +++ b/services/gunDB/contact-api/utils/index.js @@ -1,13 +1,13 @@ /** * @format */ -const ErrorCode = require('./errorCode') -const Key = require('./key') +const ErrorCode = require('../errorCode') +const Key = require('../key') /** - * @typedef {import('./SimpleGUN').GUNNode} GUNNode - * @typedef {import('./SimpleGUN').ISEA} ISEA - * @typedef {import('./SimpleGUN').UserGUNNode} UserGUNNode + * @typedef {import('../SimpleGUN').GUNNode} GUNNode + * @typedef {import('../SimpleGUN').ISEA} ISEA + * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode */ /** @@ -41,8 +41,8 @@ const timeout10 = promise => { const tryAndWait = promGen => timeout10( promGen( - require('../Mediator/index').getGun(), - require('../Mediator/index').getUser() + require('../../Mediator/index').getGun(), + require('../../Mediator/index').getUser() ) ) @@ -266,8 +266,8 @@ const asyncFilter = async (arr, cb) => { } /** - * @param {import('./SimpleGUN').ListenerData} listenerData - * @returns {listenerData is import('./SimpleGUN').ListenerObj} + * @param {import('../SimpleGUN').ListenerData} listenerData + * @returns {listenerData is import('../SimpleGUN').ListenerObj} */ const dataHasSoul = listenerData => typeof listenerData === 'object' && listenerData !== null From 5f2ef409c2b4e04f692893a2063f687369fb51b6 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 14:59:32 -0400 Subject: [PATCH 002/137] promisify gun --- services/gunDB/contact-api/SimpleGUN.ts | 14 ++++-- services/gunDB/contact-api/utils/PGUNNode.ts | 8 ++++ services/gunDB/contact-api/utils/index.js | 3 +- .../gunDB/contact-api/utils/promisifygun.js | 47 +++++++++++++++++++ 4 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 services/gunDB/contact-api/utils/PGUNNode.ts create mode 100644 services/gunDB/contact-api/utils/promisifygun.js diff --git a/services/gunDB/contact-api/SimpleGUN.ts b/services/gunDB/contact-api/SimpleGUN.ts index d9270915..3c98b025 100644 --- a/services/gunDB/contact-api/SimpleGUN.ts +++ b/services/gunDB/contact-api/SimpleGUN.ts @@ -31,14 +31,14 @@ export interface Soul { put: Primitive | null | object | undefined } -export interface GUNNode { +export interface GUNNodeBase { _: Soul - get(key: string): GUNNode + map(): GUNNode - put(data: ValidDataValue | GUNNode, cb?: Callback): GUNNode + on(this: GUNNode, cb: Listener): void once(this: GUNNode, cb?: Listener): GUNNode - set(data: ValidDataValue | GUNNode, cb?: Callback): GUNNode + off(): void user(): UserGUNNode user(epub: string): GUNNode @@ -47,6 +47,12 @@ export interface GUNNode { then(cb: (v: ListenerData) => T): Promise } +export interface GUNNode extends GUNNodeBase { + get(key: string): GUNNode + put(data: ValidDataValue | GUNNode, cb?: Callback): GUNNode + set(data: ValidDataValue | GUNNode, cb?: Callback): GUNNode +} + export interface CreateAck { pub: string | undefined err: string | undefined diff --git a/services/gunDB/contact-api/utils/PGUNNode.ts b/services/gunDB/contact-api/utils/PGUNNode.ts new file mode 100644 index 00000000..5c74b0e1 --- /dev/null +++ b/services/gunDB/contact-api/utils/PGUNNode.ts @@ -0,0 +1,8 @@ +/** @format */ +import { GUNNode, GUNNodeBase, ValidDataValue } from '../SimpleGUN' + +export interface PGUNNode extends GUNNodeBase { + get(key: string): PGUNNode + put(data: ValidDataValue | GUNNode): Promise + set(data: ValidDataValue | GUNNode): Promise +} diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 9993f137..b9121093 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -291,5 +291,6 @@ module.exports = { recipientToOutgoingID, reqWasAccepted, currHandshakeAddress, - tryAndWait + tryAndWait, + promisifyGunNode: require('./promisifygun') } diff --git a/services/gunDB/contact-api/utils/promisifygun.js b/services/gunDB/contact-api/utils/promisifygun.js new file mode 100644 index 00000000..cc045f9d --- /dev/null +++ b/services/gunDB/contact-api/utils/promisifygun.js @@ -0,0 +1,47 @@ +/** + * @format + * @typedef {import("../SimpleGUN").ValidDataValue} ValidDataValue + * @typedef {import('../SimpleGUN').GUNNode} GUNNode + * @typedef {import('./PGUNNode').PGUNNode} PGUNNode + */ + +/** + * @param {GUNNode} node + * @returns {PGUNNode} + */ +const promisify = node => { + const oldPut = node.put.bind(node) + const oldSet = node.set.bind(node) + const oldGet = node.get.bind(node) + + const _pnode = /** @type {unknown} */ (node) + const pnode = /** @type {PGUNNode} */ (_pnode) + + pnode.put = data => + new Promise((res, rej) => { + oldPut(data, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + + pnode.set = data => + new Promise((res, rej) => { + oldSet(data, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + + pnode.get = key => promisify(oldGet(key)) + + return pnode +} + +module.exports = promisify From 1b0202c9503e2511a466a63dd1d801adabc67c7c Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 15:00:34 -0400 Subject: [PATCH 003/137] mySecret() util --- services/gunDB/contact-api/utils/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index b9121093..5ce3bd4f 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -1,6 +1,7 @@ /** * @format */ +const { getUser, mySEA: SEA } = require('../../Mediator') const ErrorCode = require('../errorCode') const Key = require('../key') @@ -16,6 +17,14 @@ const Key = require('../key') */ const delay = ms => new Promise(res => setTimeout(res, ms)) +/** + * @returns {Promise} + */ +const mySecret = () => { + const user = getUser() + return SEA.secret(user._.sea.epub, user._.sea) +} + /** * @template T * @param {Promise} promise @@ -292,5 +301,6 @@ module.exports = { reqWasAccepted, currHandshakeAddress, tryAndWait, + mySecret, promisifyGunNode: require('./promisifygun') } From f26612c0d683bd45fac2ea79de18cd528818739f Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 15:04:50 -0400 Subject: [PATCH 004/137] use mysecret util and avoid dep inj --- services/gunDB/contact-api/utils/index.js | 37 ++++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 5ce3bd4f..9e4d10e6 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -143,31 +143,32 @@ const successfulHandshakeAlreadyExists = async recipientPub => { return userToIncoming.get(recipientPub).then() }) - return typeof maybeIncomingID === 'string' + const maybeOutgoingID = await tryAndWait((_, user) => { + const recipientToOutgoing = user.get(Key.RECIPIENT_TO_OUTGOING) + + return recipientToOutgoing.get(recipientPub).then() + }) + + return ( + typeof maybeIncomingID === 'string' && typeof maybeOutgoingID === 'string' + ) } /** * @param {string} recipientPub - * @param {UserGUNNode} user - * @param {ISEA} SEA * @returns {Promise} */ -const recipientToOutgoingID = async (recipientPub, user, SEA) => { - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - - if (typeof mySecret !== 'string') { - throw new TypeError('could not get mySecret') - } - - const maybeEncryptedOutgoingID = await tryAndWait((_, user) => - user - .get(Key.RECIPIENT_TO_OUTGOING) - .get(recipientPub) - .then() - ) +const recipientToOutgoingID = async recipientPub => { + const maybeEncryptedOutgoingID = await getUser() + .get(Key.RECIPIENT_TO_OUTGOING) + .get(recipientPub) + .then() if (typeof maybeEncryptedOutgoingID === 'string') { - const outgoingID = await SEA.decrypt(maybeEncryptedOutgoingID, mySecret) + const outgoingID = await SEA.decrypt( + maybeEncryptedOutgoingID, + await mySecret() + ) return outgoingID || null } @@ -196,7 +197,7 @@ const reqWasAccepted = async (reqResponse, recipientPub, user, SEA) => { throw new TypeError('typeof decryptedResponse !== "string"') } - const myFeedID = await recipientToOutgoingID(recipientPub, user, SEA) + const myFeedID = await recipientToOutgoingID(recipientPub) if (typeof myFeedID === 'string' && decryptedResponse === myFeedID) { return false From 9769d85d768765337a758e47419b994224153703 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 15:05:49 -0400 Subject: [PATCH 005/137] avoid dep injection --- services/gunDB/contact-api/actions.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 1bb3d347..e8c42a51 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -4,6 +4,7 @@ const uuidv1 = require('uuid/v1') const LightningServices = require('../../../utils/lightningServices') +const { getUser } = require('../Mediator') const ErrorCode = require('./errorCode') const Getters = require('./getters') @@ -625,11 +626,7 @@ const sendMessage = async (recipientPublicKey, body, user, SEA) => { ) } - const outgoingID = await Utils.recipientToOutgoingID( - recipientPublicKey, - user, - SEA - ) + const outgoingID = await Utils.recipientToOutgoingID(recipientPublicKey) if (outgoingID === null) { throw new Error( @@ -668,10 +665,9 @@ const sendMessage = async (recipientPublicKey, body, user, SEA) => { * @param {string} recipientPub * @param {string} msgID * @param {UserGUNNode} user - * @param {ISEA} SEA * @returns {Promise} */ -const deleteMessage = async (recipientPub, msgID, user, SEA) => { +const deleteMessage = async (recipientPub, msgID, user) => { if (!user.is) { throw new Error(ErrorCode.NOT_AUTH) } @@ -700,7 +696,7 @@ const deleteMessage = async (recipientPub, msgID, user, SEA) => { ) } - const outgoingID = await Utils.recipientToOutgoingID(recipientPub, user, SEA) + const outgoingID = await Utils.recipientToOutgoingID(recipientPub) if (outgoingID === null) { throw new Error(`Could not fetch an outgoing id for user: ${recipientPub}`) From 45d6bd109902f9c960a24edd2fb5db052e7ad5f3 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 15:07:42 -0400 Subject: [PATCH 006/137] disconnect action --- services/gunDB/contact-api/actions.js | 53 ++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index e8c42a51..6ee5d514 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -10,6 +10,7 @@ const ErrorCode = require('./errorCode') const Getters = require('./getters') const Key = require('./key') const Utils = require('./utils') +const { promisifyGunNode: p } = Utils const { isHandshakeRequest } = require('./schema') /** * @typedef {import('./SimpleGUN').GUNNode} GUNNode @@ -1047,6 +1048,55 @@ const saveSeedBackup = async (mnemonicPhrase, user, SEA) => { }) } +/** + * @param {string} pub + * @returns {Promise} + */ +const disconnect = async pub => { + const user = p(getUser()) + if (!(await Utils.successfulHandshakeAlreadyExists(pub))) { + throw new Error('No handshake exists for this pub') + } + + const outGoingID = /** @type {string} */ (await Utils.recipientToOutgoingID( + pub + )) + + await user + .get(Key.USER_TO_INCOMING) + .get(pub) + .put(null) + + await user + .get(Key.RECIPIENT_TO_OUTGOING) + .get(pub) + .put(null) + + await user + .get(Key.USER_TO_LAST_REQUEST_SENT) + .get(pub) + .put(null) + + const msgs = getUser() + .get(Key.OUTGOINGS) + .get(outGoingID) + .get(Key.MESSAGES) + + msgs + .once() + .map() + .once((_, key) => { + msgs.get(key).put(null) + }) + + // give it a bit of time so it can delete the messages + return new Promise(res => { + setTimeout(() => { + res() + }, 500) + }) +} + module.exports = { INITIAL_MSG, __createOutgoingFeed, @@ -1063,5 +1113,6 @@ module.exports = { sendPayment, generateOrderAddress, setBio, - saveSeedBackup + saveSeedBackup, + disconnect } From e7610ebc24f9beb2f3283a6177cd3bdba840bf8e Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 16:22:22 -0400 Subject: [PATCH 007/137] disconnect action in mediator --- services/gunDB/Mediator/index.js | 28 ++++++++++++++++++++++++++++ services/gunDB/action-constants.js | 3 ++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 3bd236a3..d267500d 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -305,6 +305,7 @@ class Mediator { this.socket.on(Action.SET_DISPLAY_NAME, this.setDisplayName) this.socket.on(Action.SEND_PAYMENT, this.sendPayment) this.socket.on(Action.SET_BIO, this.setBio) + this.socket.on(Action.DISCONNECT, this.disconnect) this.socket.on(Event.ON_AVATAR, this.onAvatar) this.socket.on(Event.ON_BLACKLIST, this.onBlacklist) @@ -319,8 +320,12 @@ class Mediator { this.socket.on(IS_GUN_AUTH, this.isGunAuth) } + /** @param {SimpleSocket} socket */ encryptSocketInstance = socket => { return { + /** + * @type {SimpleSocket['on']} + */ on: (eventName, cb) => { const deviceId = socket.handshake.query['x-shockwallet-device-id'] socket.on(eventName, data => { @@ -1063,6 +1068,29 @@ class Mediator { }) } } + + /** @param {Readonly<{ pub: string, token: string }>} body */ + disconnect = async body => { + try { + const { pub, token } = body + + await throwOnInvalidToken(token) + + await API.Actions.disconnect(pub) + + this.socket.emit(Action.DISCONNECT, { + ok: true, + msg: null, + origBody: body + }) + } catch (err) { + this.socket.emit(Action.DISCONNECT, { + ok: true, + msg: null, + origBody: body + }) + } + } } /** diff --git a/services/gunDB/action-constants.js b/services/gunDB/action-constants.js index 546bd5b7..bcb52aed 100644 --- a/services/gunDB/action-constants.js +++ b/services/gunDB/action-constants.js @@ -8,7 +8,8 @@ const Actions = { SEND_PAYMENT: "SEND_PAYMENT", SET_AVATAR: "SET_AVATAR", SET_DISPLAY_NAME: "SET_DISPLAY_NAME", - SET_BIO: "SET_BIO" + SET_BIO: "SET_BIO", + DISCONNECT: "DISCONNECT" }; module.exports = Actions; From db884955fe99a11702249e978ad6366a26943868 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 16:46:02 -0400 Subject: [PATCH 008/137] didDisconnect util --- services/gunDB/contact-api/utils/index.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 9e4d10e6..6a393f8a 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -1,7 +1,7 @@ /** * @format */ -const { getUser, mySEA: SEA } = require('../../Mediator') +const { getUser, mySEA: SEA, getGun } = require('../../Mediator') const ErrorCode = require('../errorCode') const Key = require('../key') @@ -288,6 +288,21 @@ const dataHasSoul = listenerData => */ const defaultName = pub => 'anon' + pub.slice(0, 8) +/** + * @param {string} pub + * @param {string} incomingID + * @returns {Promise} + */ +const didDisconnect = async (pub, incomingID) => { + const feed = await getGun() + .user(pub) + .get(Key.OUTGOINGS) + .get(incomingID) + .then() + + return feed === null +} + module.exports = { asyncMap, asyncFilter, @@ -303,5 +318,6 @@ module.exports = { currHandshakeAddress, tryAndWait, mySecret, - promisifyGunNode: require('./promisifygun') + promisifyGunNode: require('./promisifygun'), + didDisconnect } From 1b44fe1fd07250e6a8450a97ca03f76409f9685d Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 16:46:10 -0400 Subject: [PATCH 009/137] userToIncomingID getter --- services/gunDB/contact-api/getters.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/services/gunDB/contact-api/getters.js b/services/gunDB/contact-api/getters.js index fa704e37..d0cc8baa 100644 --- a/services/gunDB/contact-api/getters.js +++ b/services/gunDB/contact-api/getters.js @@ -1,3 +1,5 @@ +const {getUser} = require('../Mediator') + const Key = require('./key') const Utils = require('./utils') @@ -13,4 +15,17 @@ exports.currentOrderAddress = async (pub) => { } return currAddr +} + +/** + * @param {string} pub + * @returns {Promise} + */ +exports.userToIncomingID = async (pub) => { + const incomingID = await getUser().get(Key.USER_TO_INCOMING).get(pub).then() + + if (typeof incomingID === 'string') return incomingID + + return null + } \ No newline at end of file From d2a461b904a9c0d44bb8cbaf39b7bb53b9680420 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 16:47:27 -0400 Subject: [PATCH 010/137] signal disconnect by nulling out outgoing feed --- services/gunDB/contact-api/actions.js | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 6ee5d514..f8b38adf 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -1077,24 +1077,10 @@ const disconnect = async pub => { .get(pub) .put(null) - const msgs = getUser() + await user .get(Key.OUTGOINGS) .get(outGoingID) - .get(Key.MESSAGES) - - msgs - .once() - .map() - .once((_, key) => { - msgs.get(key).put(null) - }) - - // give it a bit of time so it can delete the messages - return new Promise(res => { - setTimeout(() => { - res() - }, 500) - }) + .put(null) } module.exports = { From f2c1fa5f128826c2a96c57f4f44eb629bcf6a8a3 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 18:19:45 -0400 Subject: [PATCH 011/137] async forEach --- services/gunDB/contact-api/utils/index.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 6a393f8a..8c749f12 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -238,6 +238,18 @@ const currHandshakeAddress = async userPub => { return typeof maybeAddr === 'string' ? maybeAddr : null } +/** + * @template T + * @param {T[]} arr + * @param {(item: T) => void} cb + * @returns {Promise} + */ +const asyncForEach = async (arr, cb) => { + const promises = arr.map(item => cb(item)) + + await Promise.all(promises) +} + /** * @template T * @template U @@ -319,5 +331,6 @@ module.exports = { tryAndWait, mySecret, promisifyGunNode: require('./promisifygun'), - didDisconnect + didDisconnect, + asyncForEach } From ebff8f458123495a2c7b1c973170ab0150ad272f Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 18:46:00 -0400 Subject: [PATCH 012/137] propagate disconnect --- services/gunDB/contact-api/events.js | 218 +++++++++++++++++---------- services/gunDB/contact-api/schema.js | 5 + 2 files changed, 143 insertions(+), 80 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index a0c14d9f..58d30224 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -3,8 +3,11 @@ */ const debounce = require('lodash/debounce') +const { getGun } = require('../Mediator/index') + const Actions = require('./actions') const ErrorCode = require('./errorCode') +const Getters = require('./getters') const Key = require('./key') const Schema = require('./schema') const Utils = require('./utils') @@ -175,7 +178,7 @@ const __onSentRequestToUser = async (cb, user, SEA) => { } /** - * @param {(userToOutgoing: Record) => void} cb + * @param {(userToIncoming: Record) => void} cb * @param {UserGUNNode} user Pass only for testing purposes. * @param {ISEA} SEA * @returns {Promise} @@ -188,7 +191,7 @@ const __onUserToIncoming = async (cb, user, SEA) => { const callb = debounce(cb, DEBOUNCE_WAIT_TIME) /** @type {Record} */ - const userToOutgoing = {} + const userToIncoming = {} const mySecret = await SEA.secret(user._.sea.epub, user._.sea) if (typeof mySecret !== 'string') { @@ -200,7 +203,14 @@ const __onUserToIncoming = async (cb, user, SEA) => { .map() .on(async (encryptedIncomingID, userPub) => { if (typeof encryptedIncomingID !== 'string') { - console.error('got a non string value') + if (encryptedIncomingID === null) { + // on disconnect + delete userToIncoming[userPub] + } else { + console.error( + 'got a non string non null value inside user to incoming' + ) + } return } @@ -216,9 +226,9 @@ const __onUserToIncoming = async (cb, user, SEA) => { return } - userToOutgoing[userPub] = incomingID + userToIncoming[userPub] = incomingID - callb(userToOutgoing) + callb(userToIncoming) }) } @@ -434,13 +444,25 @@ const onOutgoing = async ( */ const outgoingsWithMessageListeners = [] + /** @type {Set} */ + const outgoingsDisconnected = new Set() + user .get(Key.OUTGOINGS) .map() .on(async (data, key) => { if (!Schema.isPartialOutgoing(data)) { - console.warn('not partial outgoing') - console.warn(JSON.stringify(data)) + // if user disconnected + if (data === null) { + delete outgoings[key] + outgoingsDisconnected.add(key) + } else { + console.warn('not partial outgoing') + console.warn(JSON.stringify(data)) + } + + callb(outgoings) + return } @@ -464,6 +486,10 @@ const onOutgoing = async ( onOutgoingMessage( key, (msg, msgKey) => { + if (outgoingsDisconnected.has(key)) { + return + } + outgoings[key].messages = { ...outgoings[key].messages, [msgKey]: msg @@ -517,6 +543,9 @@ const onChats = (cb, gun, user, SEA) => { */ const usersWithIncomingListeners = [] + /** @type {Set} */ + const userWithDisconnectionListeners = new Set() + const _callCB = () => { // Only provide chats that have incoming listeners which would be contacts // that were actually accepted / are going on @@ -544,16 +573,21 @@ const onChats = (cb, gun, user, SEA) => { callCB() onOutgoing( - outgoings => { - for (const outgoing of Object.values(outgoings)) { + async outgoings => { + await Utils.asyncForEach(Object.values(outgoings), async outgoing => { const recipientPK = outgoing.with + const incomingID = await Getters.userToIncomingID(recipientPK) if (!recipientPKToChat[recipientPK]) { + // eslint-disable-next-line require-atomic-updates recipientPKToChat[recipientPK] = { messages: [], recipientAvatar: '', recipientDisplayName: Utils.defaultName(recipientPK), - recipientPublicKey: recipientPK + recipientPublicKey: recipientPK, + didDisconnect: + !!incomingID && + (await Utils.didDisconnect(recipientPK, incomingID)) } } @@ -569,7 +603,7 @@ const onChats = (cb, gun, user, SEA) => { }) } } - } + }) callCB() }, @@ -578,77 +612,101 @@ const onChats = (cb, gun, user, SEA) => { ) __onUserToIncoming( - uti => { - for (const [recipientPK, incomingFeedID] of Object.entries(uti)) { - if (!recipientPKToChat[recipientPK]) { - recipientPKToChat[recipientPK] = { - messages: [], - recipientAvatar: '', - recipientDisplayName: Utils.defaultName(recipientPK), - recipientPublicKey: recipientPK + async uti => { + await Utils.asyncForEach( + Object.entries(uti), + async ([recipientPK, incomingFeedID]) => { + if (!recipientPKToChat[recipientPK]) { + // eslint-disable-next-line require-atomic-updates + recipientPKToChat[recipientPK] = { + messages: [], + recipientAvatar: '', + recipientDisplayName: Utils.defaultName(recipientPK), + recipientPublicKey: recipientPK, + didDisconnect: await Utils.didDisconnect( + recipientPK, + incomingFeedID + ) + } + } + + const chat = recipientPKToChat[recipientPK] + + if (!userWithDisconnectionListeners.has(recipientPK)) { + userWithDisconnectionListeners.add(recipientPK) + + getGun() + .user(recipientPK) + .get(Key.OUTGOINGS) + .get(incomingFeedID) + .on(data => { + if (data === null) { + chat.didDisconnect = true + + callCB() + } + }) + } + + if (!usersWithIncomingListeners.includes(recipientPK)) { + usersWithIncomingListeners.push(recipientPK) + + onIncomingMessages( + msgs => { + for (const [msgK, msg] of Object.entries(msgs)) { + const { messages } = chat + + if (!messages.find(_msg => _msg.id === msgK)) { + messages.push({ + body: msg.body, + id: msgK, + outgoing: false, + timestamp: msg.timestamp + }) + } + } + + callCB() + }, + recipientPK, + incomingFeedID, + gun, + user, + SEA + ) + } + + if (!usersWithAvatarListeners.includes(recipientPK)) { + usersWithAvatarListeners.push(recipientPK) + + gun + .user(recipientPK) + .get(Key.PROFILE) + .get(Key.AVATAR) + .on(avatar => { + if (typeof avatar === 'string') { + chat.recipientAvatar = avatar + callCB() + } + }) + } + + if (!usersWithDisplayNameListeners.includes(recipientPK)) { + usersWithDisplayNameListeners.push(recipientPK) + + gun + .user(recipientPK) + .get(Key.PROFILE) + .get(Key.DISPLAY_NAME) + .on(displayName => { + if (typeof displayName === 'string') { + chat.recipientDisplayName = displayName + callCB() + } + }) } } - - const chat = recipientPKToChat[recipientPK] - - if (!usersWithIncomingListeners.includes(recipientPK)) { - usersWithIncomingListeners.push(recipientPK) - - onIncomingMessages( - msgs => { - for (const [msgK, msg] of Object.entries(msgs)) { - const { messages } = chat - - if (!messages.find(_msg => _msg.id === msgK)) { - messages.push({ - body: msg.body, - id: msgK, - outgoing: false, - timestamp: msg.timestamp - }) - } - } - - callCB() - }, - recipientPK, - incomingFeedID, - gun, - user, - SEA - ) - } - - if (!usersWithAvatarListeners.includes(recipientPK)) { - usersWithAvatarListeners.push(recipientPK) - - gun - .user(recipientPK) - .get(Key.PROFILE) - .get(Key.AVATAR) - .on(avatar => { - if (typeof avatar === 'string') { - chat.recipientAvatar = avatar - callCB() - } - }) - } - - if (!usersWithDisplayNameListeners.includes(recipientPK)) { - usersWithDisplayNameListeners.push(recipientPK) - - gun - .user(recipientPK) - .get(Key.PROFILE) - .get(Key.DISPLAY_NAME) - .on(displayName => { - if (typeof displayName === 'string') { - chat.recipientDisplayName = displayName - callCB() - } - }) - } - } + ) }, user, SEA diff --git a/services/gunDB/contact-api/schema.js b/services/gunDB/contact-api/schema.js index 9a7d57bf..fceb2d11 100644 --- a/services/gunDB/contact-api/schema.js +++ b/services/gunDB/contact-api/schema.js @@ -69,6 +69,7 @@ exports.isChatMessage = item => { * @prop {string} recipientPublicKey A way to uniquely identify each chat. * @prop {ChatMessage[]} messages Sorted from most recent to least recent. * @prop {string|null} recipientDisplayName + * @prop {boolean} didDisconnect True if the recipient performed a disconnect. */ /** @@ -102,6 +103,10 @@ exports.isChat = item => { return false } + if (typeof obj.didDisconnect !== 'boolean') { + return false + } + return obj.messages.every(msg => exports.isChatMessage(msg)) } From e4ab314e7f0789d76a44398e5af58b076877edce Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 19:32:56 -0400 Subject: [PATCH 013/137] update eslint rules --- .eslintrc.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index bfcdeedb..c08e850c 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -65,7 +65,9 @@ "no-throw-literal": "off", // lightning has sync methods and this rule bans them - "no-sync": "off" + "no-sync": "off", + + "id-length": "off" }, "parser": "babel-eslint", "env": { From d0bef5ea2cbc65b04fd2abaa3c6d222a85eff271 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 25 Jan 2020 19:50:54 -0400 Subject: [PATCH 014/137] instantly reflect changes in messages --- services/gunDB/contact-api/events.js | 1 + 1 file changed, 1 insertion(+) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 58d30224..864c9c02 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -642,6 +642,7 @@ const onChats = (cb, gun, user, SEA) => { .on(data => { if (data === null) { chat.didDisconnect = true + chat.messages = chat.messages.filter(m => m.outgoing) callCB() } From 33d13439749cbfa0a9016be7e75b6be00d071dd2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Mon, 27 Jan 2020 14:48:05 -0400 Subject: [PATCH 015/137] prevent race condition --- services/gunDB/contact-api/events.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 864c9c02..0513e195 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -577,17 +577,16 @@ const onChats = (cb, gun, user, SEA) => { await Utils.asyncForEach(Object.values(outgoings), async outgoing => { const recipientPK = outgoing.with const incomingID = await Getters.userToIncomingID(recipientPK) + const didDisconnect = + !!incomingID && (await Utils.didDisconnect(recipientPK, incomingID)) if (!recipientPKToChat[recipientPK]) { - // eslint-disable-next-line require-atomic-updates recipientPKToChat[recipientPK] = { messages: [], recipientAvatar: '', recipientDisplayName: Utils.defaultName(recipientPK), recipientPublicKey: recipientPK, - didDisconnect: - !!incomingID && - (await Utils.didDisconnect(recipientPK, incomingID)) + didDisconnect } } @@ -616,17 +615,17 @@ const onChats = (cb, gun, user, SEA) => { await Utils.asyncForEach( Object.entries(uti), async ([recipientPK, incomingFeedID]) => { + const didDisconnect = await Utils.didDisconnect( + recipientPK, + incomingFeedID + ) if (!recipientPKToChat[recipientPK]) { - // eslint-disable-next-line require-atomic-updates recipientPKToChat[recipientPK] = { messages: [], recipientAvatar: '', recipientDisplayName: Utils.defaultName(recipientPK), recipientPublicKey: recipientPK, - didDisconnect: await Utils.didDisconnect( - recipientPK, - incomingFeedID - ) + didDisconnect } } From 9a9185f56053815c6fa6684f939958eaef3a9b31 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Mon, 27 Jan 2020 15:04:01 -0400 Subject: [PATCH 016/137] typings for jsonwebtoken --- package.json | 1 + yarn.lock | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/package.json b/package.json index 5edf3bd1..7803eb99 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@types/express": "^4.17.1", "@types/gun": "^0.9.1", "@types/jest": "^24.0.18", + "@types/jsonwebtoken": "^8.3.7", "@types/lodash": "^4.14.141", "@types/socket.io": "^2.1.3", "@types/socket.io-client": "^1.4.32", diff --git a/yarn.lock b/yarn.lock index 7abb87b8..9ae14013 100644 --- a/yarn.lock +++ b/yarn.lock @@ -579,6 +579,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== +"@types/jsonwebtoken@^8.3.7": + version "8.3.7" + resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.3.7.tgz#ab79ad55b9435834d24cca3112f42c08eedb1a54" + integrity sha512-B5SSifLkjB0ns7VXpOOtOUlynE78/hKcY8G8pOAhkLJZinwofIBYqz555nRj2W9iDWZqFhK5R+7NZDaRmKWAoQ== + dependencies: + "@types/node" "*" + "@types/lodash@^4.14.141": version "4.14.141" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.141.tgz#d81f4d0c562abe28713406b571ffb27692a82ae6" From e0fe2e96bafcb503f08fc883ea98873345c589ad Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 16:57:02 -0400 Subject: [PATCH 017/137] chats now have ids --- services/gunDB/contact-api/events.js | 6 ++++-- services/gunDB/contact-api/schema.js | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 0513e195..c50ad89d 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -586,7 +586,8 @@ const onChats = (cb, gun, user, SEA) => { recipientAvatar: '', recipientDisplayName: Utils.defaultName(recipientPK), recipientPublicKey: recipientPK, - didDisconnect + didDisconnect, + id: recipientPK + incomingID } } @@ -625,7 +626,8 @@ const onChats = (cb, gun, user, SEA) => { recipientAvatar: '', recipientDisplayName: Utils.defaultName(recipientPK), recipientPublicKey: recipientPK, - didDisconnect + didDisconnect, + id: recipientPK + incomingFeedID } } diff --git a/services/gunDB/contact-api/schema.js b/services/gunDB/contact-api/schema.js index fceb2d11..e7dc0b5b 100644 --- a/services/gunDB/contact-api/schema.js +++ b/services/gunDB/contact-api/schema.js @@ -65,6 +65,8 @@ exports.isChatMessage = item => { * outgoing/incoming feed paradigm. It combines both the outgoing and incoming * messages into one data structure plus metada about the chat. * @typedef {object} Chat + * @prop {string} id Chats now have IDs because of disconnect. + * RecipientPublicKey will no longer be unique. * @prop {string|null} recipientAvatar Base64 encoded image. * @prop {string} recipientPublicKey A way to uniquely identify each chat. * @prop {ChatMessage[]} messages Sorted from most recent to least recent. @@ -107,6 +109,10 @@ exports.isChat = item => { return false } + if (typeof obj.id !== 'string') { + return false + } + return obj.messages.every(msg => exports.isChatMessage(msg)) } From 29680618ffc0b72c36a57e74008e5ff1abbc9dfa Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 17:28:23 -0400 Subject: [PATCH 018/137] avoid commonjs require race conditions --- services/gunDB/contact-api/actions.js | 2 +- services/gunDB/contact-api/events.js | 5 ++--- services/gunDB/contact-api/getters.js | 2 +- services/gunDB/contact-api/utils/index.js | 16 ++++++++++------ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index f8b38adf..50716dee 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -1053,7 +1053,7 @@ const saveSeedBackup = async (mnemonicPhrase, user, SEA) => { * @returns {Promise} */ const disconnect = async pub => { - const user = p(getUser()) + const user = p(require('../Mediator').getUser()) if (!(await Utils.successfulHandshakeAlreadyExists(pub))) { throw new Error('No handshake exists for this pub') } diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index c50ad89d..4dd845bf 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -3,8 +3,6 @@ */ const debounce = require('lodash/debounce') -const { getGun } = require('../Mediator/index') - const Actions = require('./actions') const ErrorCode = require('./errorCode') const Getters = require('./getters') @@ -636,7 +634,8 @@ const onChats = (cb, gun, user, SEA) => { if (!userWithDisconnectionListeners.has(recipientPK)) { userWithDisconnectionListeners.add(recipientPK) - getGun() + require('../Mediator') + .getGun() .user(recipientPK) .get(Key.OUTGOINGS) .get(incomingFeedID) diff --git a/services/gunDB/contact-api/getters.js b/services/gunDB/contact-api/getters.js index d0cc8baa..d5ace3c1 100644 --- a/services/gunDB/contact-api/getters.js +++ b/services/gunDB/contact-api/getters.js @@ -22,7 +22,7 @@ exports.currentOrderAddress = async (pub) => { * @returns {Promise} */ exports.userToIncomingID = async (pub) => { - const incomingID = await getUser().get(Key.USER_TO_INCOMING).get(pub).then() + const incomingID = await require('../Mediator').getUser().get(Key.USER_TO_INCOMING).get(pub).then() if (typeof incomingID === 'string') return incomingID diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 8c749f12..4d523907 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -1,7 +1,6 @@ /** * @format */ -const { getUser, mySEA: SEA, getGun } = require('../../Mediator') const ErrorCode = require('../errorCode') const Key = require('../key') @@ -21,8 +20,11 @@ const delay = ms => new Promise(res => setTimeout(res, ms)) * @returns {Promise} */ const mySecret = () => { - const user = getUser() - return SEA.secret(user._.sea.epub, user._.sea) + const user = require('../../Mediator/index').getUser() + return require('../../Mediator/index').mySEA.secret( + user._.sea.epub, + user._.sea + ) } /** @@ -159,13 +161,14 @@ const successfulHandshakeAlreadyExists = async recipientPub => { * @returns {Promise} */ const recipientToOutgoingID = async recipientPub => { - const maybeEncryptedOutgoingID = await getUser() + const maybeEncryptedOutgoingID = await require('../../Mediator/index') + .getUser() .get(Key.RECIPIENT_TO_OUTGOING) .get(recipientPub) .then() if (typeof maybeEncryptedOutgoingID === 'string') { - const outgoingID = await SEA.decrypt( + const outgoingID = await require('../../Mediator/index').mySEA.decrypt( maybeEncryptedOutgoingID, await mySecret() ) @@ -306,7 +309,8 @@ const defaultName = pub => 'anon' + pub.slice(0, 8) * @returns {Promise} */ const didDisconnect = async (pub, incomingID) => { - const feed = await getGun() + const feed = await require('../../Mediator/index') + .getGun() .user(pub) .get(Key.OUTGOINGS) .get(incomingID) From 438b6f138355c307b8ad62bafd429a947c06f2bd Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 17:29:00 -0400 Subject: [PATCH 019/137] unused vars --- services/gunDB/contact-api/actions.js | 1 - services/gunDB/contact-api/getters.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 50716dee..aefa3a07 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -4,7 +4,6 @@ const uuidv1 = require('uuid/v1') const LightningServices = require('../../../utils/lightningServices') -const { getUser } = require('../Mediator') const ErrorCode = require('./errorCode') const Getters = require('./getters') diff --git a/services/gunDB/contact-api/getters.js b/services/gunDB/contact-api/getters.js index d5ace3c1..cc1104f7 100644 --- a/services/gunDB/contact-api/getters.js +++ b/services/gunDB/contact-api/getters.js @@ -1,5 +1,3 @@ -const {getUser} = require('../Mediator') - const Key = require('./key') const Utils = require('./utils') From a43ff12cc5e9fe5d1812c7d762dc44c421aa791c Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 17:49:41 -0400 Subject: [PATCH 020/137] promisify is broken --- services/gunDB/contact-api/actions.js | 68 ++++++++++++++++++++------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index aefa3a07..b9c21c09 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -9,7 +9,7 @@ const ErrorCode = require('./errorCode') const Getters = require('./getters') const Key = require('./key') const Utils = require('./utils') -const { promisifyGunNode: p } = Utils +// const { promisifyGunNode: p } = Utils const { isHandshakeRequest } = require('./schema') /** * @typedef {import('./SimpleGUN').GUNNode} GUNNode @@ -1052,7 +1052,7 @@ const saveSeedBackup = async (mnemonicPhrase, user, SEA) => { * @returns {Promise} */ const disconnect = async pub => { - const user = p(require('../Mediator').getUser()) + const user = require('../Mediator').getUser() if (!(await Utils.successfulHandshakeAlreadyExists(pub))) { throw new Error('No handshake exists for this pub') } @@ -1061,25 +1061,57 @@ const disconnect = async pub => { pub )) - await user - .get(Key.USER_TO_INCOMING) - .get(pub) - .put(null) + await new Promise((res, rej) => { + user + .get(Key.USER_TO_INCOMING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - await user - .get(Key.RECIPIENT_TO_OUTGOING) - .get(pub) - .put(null) + await new Promise((res, rej) => { + user + .get(Key.RECIPIENT_TO_OUTGOING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - await user - .get(Key.USER_TO_LAST_REQUEST_SENT) - .get(pub) - .put(null) + await new Promise((res, rej) => { + user + .get(Key.USER_TO_LAST_REQUEST_SENT) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - await user - .get(Key.OUTGOINGS) - .get(outGoingID) - .put(null) + await new Promise((res, rej) => { + user + .get(Key.OUTGOINGS) + .get(outGoingID) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) } module.exports = { From aa80f58cbe152f5e9548936eb94aafc77bd49cd6 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 18:58:56 -0400 Subject: [PATCH 021/137] typo --- services/gunDB/Mediator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index d267500d..c085a71b 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -1085,7 +1085,7 @@ class Mediator { }) } catch (err) { this.socket.emit(Action.DISCONNECT, { - ok: true, + ok: false, msg: null, origBody: body }) From d58b9cc78b02ac433d2466d63a3e0d6951024b13 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 20:51:57 -0400 Subject: [PATCH 022/137] avatar null initial state --- services/gunDB/contact-api/events.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 4dd845bf..e12f95c1 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -581,7 +581,7 @@ const onChats = (cb, gun, user, SEA) => { if (!recipientPKToChat[recipientPK]) { recipientPKToChat[recipientPK] = { messages: [], - recipientAvatar: '', + recipientAvatar: null, recipientDisplayName: Utils.defaultName(recipientPK), recipientPublicKey: recipientPK, didDisconnect, @@ -621,7 +621,7 @@ const onChats = (cb, gun, user, SEA) => { if (!recipientPKToChat[recipientPK]) { recipientPKToChat[recipientPK] = { messages: [], - recipientAvatar: '', + recipientAvatar: null, recipientDisplayName: Utils.defaultName(recipientPK), recipientPublicKey: recipientPK, didDisconnect, From 61ece2905a50b72a71e3bc7e33a9e20e560356b2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 21:00:47 -0400 Subject: [PATCH 023/137] disconnect deletes last req sent id --- services/gunDB/contact-api/utils/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 4d523907..c67eee1a 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -116,8 +116,9 @@ const reqToRecipientPub = async (reqID, SEA, mySecret) => { /** * Should only be called with a recipient pub that has already been contacted. + * If returns null, a disconnect happened. * @param {string} recipientPub - * @returns {Promise} + * @returns {Promise} */ const recipientPubToLastReqSentID = async recipientPub => { const lastReqSentID = await tryAndWait(async (_, user) => { @@ -125,7 +126,7 @@ const recipientPubToLastReqSentID = async recipientPub => { const data = await userToLastReqSent.get(recipientPub).then() if (typeof data !== 'string') { - throw new TypeError("typeof latestReqSentID !== 'string'") + return null } return data From 6458bf739863f4c87175808882644592b0ff1870 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 21:50:54 -0400 Subject: [PATCH 024/137] take disconnect into account --- services/gunDB/contact-api/events.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index e12f95c1..332a00a5 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -918,8 +918,13 @@ const onSimplerReceivedRequests = (cb, gun, user, SEA) => { user .get(Key.USER_TO_INCOMING) .map() - .on((_, userPK) => { - requestorsAlreadyAccepted.add(userPK) + .on((incomingID, userPK) => { + const disconnected = incomingID === null + if (disconnected) { + requestorsAlreadyAccepted.delete(userPK) + } else { + requestorsAlreadyAccepted.add(userPK) + } callCB() }) From 0f208f094807f6ec0f5b96f68be9782a16f975a8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 21:59:25 -0400 Subject: [PATCH 025/137] generate new handshake addr on disconnect --- services/gunDB/contact-api/actions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index b9c21c09..4ecdfe7f 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -1112,6 +1112,8 @@ const disconnect = async pub => { } }) }) + + await generateHandshakeAddress(require('../Mediator').getUser()) } module.exports = { From b72604075f4bd164bb5c778e04df7b9fe3ed31b2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 22:13:03 -0400 Subject: [PATCH 026/137] pass error through --- services/gunDB/Mediator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index c085a71b..6945ad83 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -1086,7 +1086,7 @@ class Mediator { } catch (err) { this.socket.emit(Action.DISCONNECT, { ok: false, - msg: null, + msg: err.message, origBody: body }) } From 2eac1eaaf78a4ebed6170b0991161a983fb16c86 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 22:16:47 -0400 Subject: [PATCH 027/137] parallel --- services/gunDB/contact-api/actions.js | 100 +++++++++++++------------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 4ecdfe7f..0bee456b 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -1061,59 +1061,61 @@ const disconnect = async pub => { pub )) - await new Promise((res, rej) => { - user - .get(Key.USER_TO_INCOMING) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) + await Promise.all([ + new Promise((res, rej) => { + user + .get(Key.USER_TO_INCOMING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }), - await new Promise((res, rej) => { - user - .get(Key.RECIPIENT_TO_OUTGOING) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) + new Promise((res, rej) => { + user + .get(Key.RECIPIENT_TO_OUTGOING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }), - await new Promise((res, rej) => { - user - .get(Key.USER_TO_LAST_REQUEST_SENT) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) + new Promise((res, rej) => { + user + .get(Key.USER_TO_LAST_REQUEST_SENT) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }), - await new Promise((res, rej) => { - user - .get(Key.OUTGOINGS) - .get(outGoingID) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) + new Promise((res, rej) => { + user + .get(Key.OUTGOINGS) + .get(outGoingID) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }), - await generateHandshakeAddress(require('../Mediator').getUser()) + await generateHandshakeAddress(require('../Mediator').getUser()) + ]) } module.exports = { From 3a169db2f913f3a30b6f52cccedd9f10c85101a8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 28 Jan 2020 22:17:14 -0400 Subject: [PATCH 028/137] Revert "parallel" This reverts commit aa6d487ef884bdb0df6e0a9135fb9dbc663bd50f. --- services/gunDB/contact-api/actions.js | 100 +++++++++++++------------- 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 0bee456b..4ecdfe7f 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -1061,61 +1061,59 @@ const disconnect = async pub => { pub )) - await Promise.all([ - new Promise((res, rej) => { - user - .get(Key.USER_TO_INCOMING) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }), + await new Promise((res, rej) => { + user + .get(Key.USER_TO_INCOMING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - new Promise((res, rej) => { - user - .get(Key.RECIPIENT_TO_OUTGOING) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }), + await new Promise((res, rej) => { + user + .get(Key.RECIPIENT_TO_OUTGOING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - new Promise((res, rej) => { - user - .get(Key.USER_TO_LAST_REQUEST_SENT) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }), + await new Promise((res, rej) => { + user + .get(Key.USER_TO_LAST_REQUEST_SENT) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - new Promise((res, rej) => { - user - .get(Key.OUTGOINGS) - .get(outGoingID) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }), + await new Promise((res, rej) => { + user + .get(Key.OUTGOINGS) + .get(outGoingID) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) - await generateHandshakeAddress(require('../Mediator').getUser()) - ]) + await generateHandshakeAddress(require('../Mediator').getUser()) } module.exports = { From ba99c7e4000c8bbcc198ea91b7fe24de517947e4 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:32:25 -0400 Subject: [PATCH 029/137] use gun.open --- services/gunDB/contact-api/SimpleGUN.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/gunDB/contact-api/SimpleGUN.ts b/services/gunDB/contact-api/SimpleGUN.ts index 3c98b025..25f9e8ba 100644 --- a/services/gunDB/contact-api/SimpleGUN.ts +++ b/services/gunDB/contact-api/SimpleGUN.ts @@ -23,6 +23,10 @@ export type ListenerObj = Record & { export type ListenerData = Primitive | null | ListenerObj | undefined +interface OpenListenerDataObj { + [k: string]: OpenListenerData +} + export type Listener = (data: ListenerData, key: string) => void export type Callback = (ack: Ack) => void @@ -31,6 +35,9 @@ export interface Soul { put: Primitive | null | object | undefined } +export type OpenListenerData = Primitive | null | OpenListenerDataObj +export type OpenListener = (data: OpenListenerData, key: string) => void + export interface GUNNodeBase { _: Soul @@ -39,6 +46,8 @@ export interface GUNNodeBase { on(this: GUNNode, cb: Listener): void once(this: GUNNode, cb?: Listener): GUNNode + open(this: GUNNode, cb?: OpenListener): GUNNode + off(): void user(): UserGUNNode user(epub: string): GUNNode From 527072f538f480e8819893cd964a8ba2fc7bbf81 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:34:14 -0400 Subject: [PATCH 030/137] new onoutgoing --- services/gunDB/contact-api/events.js | 328 ++++++++++----------------- 1 file changed, 116 insertions(+), 212 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 332a00a5..70c222ca 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -27,105 +27,6 @@ const Config = require('../config') const DEBOUNCE_WAIT_TIME = 500 -/** - * @param {string} outgoingKey - * @param {(message: Message, key: string) => void} cb - * @param {UserGUNNode} user - * @param {ISEA} SEA - * @returns {Promise} - */ -const __onOutgoingMessage = async (outgoingKey, cb, user, SEA) => { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } - - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new TypeError("typeof mySecret !== 'string'") - } - - const callb = debounce(cb, DEBOUNCE_WAIT_TIME) - /** @type {string} */ - const encryptedForMeRecipientPublicKey = await Utils.tryAndWait( - (_, user) => - new Promise((res, rej) => { - user - .get(Key.OUTGOINGS) - .get(outgoingKey) - .get('with') - .once(erpk => { - if (typeof erpk !== 'string') { - rej( - new TypeError("Expected outgoing.get('with') to be an string.") - ) - } else if (erpk.length === 0) { - rej( - new TypeError( - "Expected outgoing.get('with') to be a populated." - ) - ) - } else { - res(erpk) - } - }) - }) - ) - - const recipientPublicKey = await SEA.decrypt( - encryptedForMeRecipientPublicKey, - mySecret - ) - - if (typeof recipientPublicKey !== 'string') { - throw new TypeError( - "__onOutgoingMessage() -> typeof recipientPublicKey !== 'string'" - ) - } - - /** @type {string} */ - const recipientEpub = await Utils.pubToEpub(recipientPublicKey) - - const ourSecret = await SEA.secret(recipientEpub, user._.sea) - - if (typeof ourSecret !== 'string') { - throw new TypeError( - "__onOutgoingMessage() -> typeof ourSecret !== 'string'" - ) - } - - user - .get(Key.OUTGOINGS) - .get(outgoingKey) - .get(Key.MESSAGES) - .map() - .on(async (msg, key) => { - if (!Schema.isMessage(msg)) { - console.warn('non message received: ' + JSON.stringify(msg)) - return - } - - let { body } = msg - - if (body !== Actions.INITIAL_MSG) { - const decrypted = await SEA.decrypt(body, ourSecret) - - if (typeof decrypted !== 'string') { - console.log("__onOutgoingMessage() -> typeof decrypted !== 'string'") - } else { - body = decrypted - } - } - - callb( - { - body, - timestamp: msg.timestamp - }, - key - ) - }) -} - /** * Maps a sent request ID to the public key of the user it was sent to. * @param {(requestToUser: Record) => void} cb @@ -407,101 +308,105 @@ const onIncomingMessages = (cb, userPK, incomingFeedID, gun, user, SEA) => { } /** - * - * @param {(outgoings: Record) => void} cb - * @param {UserGUNNode} user - * @param {ISEA} SEA - * @param {typeof __onOutgoingMessage} onOutgoingMessage + * @typedef {Record} Outgoings + * @typedef {(outgoings: Outgoings) => void} OutgoingsListener */ -const onOutgoing = async ( - cb, - user, - SEA, - onOutgoingMessage = __onOutgoingMessage -) => { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } - const callb = debounce(cb, DEBOUNCE_WAIT_TIME) +/** + * @type {Outgoings} + */ +export let currentOutgoings = {} - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new TypeError("onOutgoing() -> typeof mySecret !== 'string'") - } +/** + * @type {Outgoings} + */ +export let encryptedOutgoings = {} - /** - * @type {Record} - */ - const outgoings = {} +/** @type {Set} */ +const outgoingsListeners = new Set() - callb(outgoings) +export const notifyOutgoingsListeners = () => { + outgoingsListeners.forEach(l => l(currentOutgoings)) +} - /** - * @type {string[]} - */ - const outgoingsWithMessageListeners = [] +/** @type {UserGUNNode|null} */ +let lastUserWithListener = null - /** @type {Set} */ - const outgoingsDisconnected = new Set() +const processOutgoings = async () => { + const outs = encryptedOutgoings + encryptedOutgoings = {} + const mySecret = await Utils.mySecret() + const SEA = require('../Mediator').mySEA + await Utils.asyncForEach(Object.entries(outs), async ([id, out]) => { + if (out === null) { + currentOutgoings[id] = null + return + } - user - .get(Key.OUTGOINGS) - .map() - .on(async (data, key) => { - if (!Schema.isPartialOutgoing(data)) { - // if user disconnected - if (data === null) { - delete outgoings[key] - outgoingsDisconnected.add(key) - } else { - console.warn('not partial outgoing') - console.warn(JSON.stringify(data)) + if (typeof currentOutgoings[id] === 'undefined') { + // We disable this rule because we are awaiting the result of the whole + // for each AND each callback looks only at one single ID + // eslint-disable-next-line require-atomic-updates + currentOutgoings[id] = { + messages: {}, + with: await SEA.decrypt(out.with, mySecret) + } + } + + const currentOut = currentOutgoings[id] + if (currentOut === null) { + return + } + + // on each open() only "messages" should change, not "with" + // also messages are non-nullable and non-editable + + await Utils.asyncForEach( + Object.entries(out.messages), + async ([msgID, msg]) => { + if (!currentOut.messages[msgID]) { + // each callback only looks at one particular msgID + // eslint-disable-next-line require-atomic-updates + currentOut.messages[msgID] = { + body: await SEA.decrypt(msg.body, mySecret), + timestamp: msg.timestamp + } } + } + ) + }) + notifyOutgoingsListeners() +} - callb(outgoings) +/** + * @param {OutgoingsListener} cb + * @returns {() => void} + */ +const onOutgoing = cb => { + cb(currentOutgoings) + const currentUser = require('../Mediator').getUser() + + if (lastUserWithListener !== currentUser) { + // in case user changed gun alias + currentOutgoings = {} + encryptedOutgoings = {} + lastUserWithListener = currentUser + + currentUser.get(Key.OUTGOINGS).open(data => { + // deactivate this listener when user changes + if (lastUserWithListener !== require('../Mediator').getUser()) { return } - - const decryptedRecipientPublicKey = await SEA.decrypt(data.with, mySecret) - - if (typeof decryptedRecipientPublicKey !== 'string') { - console.log( - "onOutgoing() -> typeof decryptedRecipientPublicKey !== 'string'" - ) - return - } - - outgoings[key] = { - messages: outgoings[key] ? outgoings[key].messages : {}, - with: decryptedRecipientPublicKey - } - - if (!outgoingsWithMessageListeners.includes(key)) { - outgoingsWithMessageListeners.push(key) - - onOutgoingMessage( - key, - (msg, msgKey) => { - if (outgoingsDisconnected.has(key)) { - return - } - - outgoings[key].messages = { - ...outgoings[key].messages, - [msgKey]: msg - } - - callb(outgoings) - }, - user, - SEA - ) - } - - callb(outgoings) + // @ts-ignore Let's skip schema checks for perf reasons + encryptedOutgoings = data + processOutgoings() }) + } + + return () => { + outgoingsListeners.delete(cb) + } } /** @@ -570,44 +475,43 @@ const onChats = (cb, gun, user, SEA) => { callCB() - onOutgoing( - async outgoings => { - await Utils.asyncForEach(Object.values(outgoings), async outgoing => { - const recipientPK = outgoing.with - const incomingID = await Getters.userToIncomingID(recipientPK) - const didDisconnect = - !!incomingID && (await Utils.didDisconnect(recipientPK, incomingID)) + onOutgoing(async outgoings => { + await Utils.asyncForEach(Object.values(outgoings), async outgoing => { + if (outgoing === null) { + return + } + const recipientPK = outgoing.with + const incomingID = await Getters.userToIncomingID(recipientPK) + const didDisconnect = + !!incomingID && (await Utils.didDisconnect(recipientPK, incomingID)) - if (!recipientPKToChat[recipientPK]) { - recipientPKToChat[recipientPK] = { - messages: [], - recipientAvatar: null, - recipientDisplayName: Utils.defaultName(recipientPK), - recipientPublicKey: recipientPK, - didDisconnect, - id: recipientPK + incomingID - } + if (!recipientPKToChat[recipientPK]) { + recipientPKToChat[recipientPK] = { + messages: [], + recipientAvatar: null, + recipientDisplayName: Utils.defaultName(recipientPK), + recipientPublicKey: recipientPK, + didDisconnect, + id: recipientPK + incomingID } + } - const { messages } = recipientPKToChat[recipientPK] + const { messages } = recipientPKToChat[recipientPK] - for (const [msgK, msg] of Object.entries(outgoing.messages)) { - if (!messages.find(_msg => _msg.id === msgK)) { - messages.push({ - body: msg.body, - id: msgK, - outgoing: true, - timestamp: msg.timestamp - }) - } + for (const [msgK, msg] of Object.entries(outgoing.messages)) { + if (!messages.find(_msg => _msg.id === msgK)) { + messages.push({ + body: msg.body, + id: msgK, + outgoing: true, + timestamp: msg.timestamp + }) } - }) + } + }) - callCB() - }, - user, - SEA - ) + callCB() + }) __onUserToIncoming( async uti => { From d40f53fa853b080fd94a949ef1e658b6ab3a0ec8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:35:23 -0400 Subject: [PATCH 031/137] remove invalid keywords --- services/gunDB/contact-api/events.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 70c222ca..9510a531 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -315,17 +315,17 @@ const onIncomingMessages = (cb, userPK, incomingFeedID, gun, user, SEA) => { /** * @type {Outgoings} */ -export let currentOutgoings = {} +let currentOutgoings = {} /** * @type {Outgoings} */ -export let encryptedOutgoings = {} +let encryptedOutgoings = {} /** @type {Set} */ const outgoingsListeners = new Set() -export const notifyOutgoingsListeners = () => { +const notifyOutgoingsListeners = () => { outgoingsListeners.forEach(l => l(currentOutgoings)) } From 1e8148641ae50ff42dc3118326409e09d6227d79 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:41:59 -0400 Subject: [PATCH 032/137] actually import open lib --- services/gunDB/Mediator/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 6945ad83..c34776ed 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -2,6 +2,8 @@ * @format */ const Gun = require('gun') +// @ts-ignore +require('gun/lib/open') const debounce = require('lodash/debounce') const once = require('lodash/once') const Encryption = require('../../../utils/encryptionStore') From f97a11039243f06a8b28d5b329d504bb649f328e Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:44:43 -0400 Subject: [PATCH 033/137] dont unencrypt initial msg --- services/gunDB/contact-api/events.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 9510a531..b99d9e7f 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -365,10 +365,16 @@ const processOutgoings = async () => { Object.entries(out.messages), async ([msgID, msg]) => { if (!currentOut.messages[msgID]) { + let decryptedBody = '' + if (msg.body === Actions.INITIAL_MSG) { + decryptedBody = Actions.INITIAL_MSG + } else { + decryptedBody = await SEA.decrypt(msg.body, mySecret) + } // each callback only looks at one particular msgID // eslint-disable-next-line require-atomic-updates currentOut.messages[msgID] = { - body: await SEA.decrypt(msg.body, mySecret), + body: decryptedBody, timestamp: msg.timestamp } } From d1b6b238bfa7a0938da56676e0d46d2fdb9aeef4 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:55:33 -0400 Subject: [PATCH 034/137] schema check for incomplete data --- services/gunDB/contact-api/events.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index b99d9e7f..42991976 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -343,6 +343,11 @@ const processOutgoings = async () => { return } + if (!Schema.isPartialOutgoing(out)) { + // incomplete data + return + } + if (typeof currentOutgoings[id] === 'undefined') { // We disable this rule because we are awaiting the result of the whole // for each AND each callback looks only at one single ID @@ -364,6 +369,10 @@ const processOutgoings = async () => { await Utils.asyncForEach( Object.entries(out.messages), async ([msgID, msg]) => { + if (!Schema.isMessage(msg)) { + // incomplete data + return + } if (!currentOut.messages[msgID]) { let decryptedBody = '' if (msg.body === Actions.INITIAL_MSG) { From 72ff9eb21a269eac2643810b36c4388a8dc4317a Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 11:58:25 -0400 Subject: [PATCH 035/137] better err msg --- services/gunDB/Mediator/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index c34776ed..4b22e1f8 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -23,7 +23,10 @@ const IS_GUN_AUTH = 'IS_GUN_AUTH' mySEA.encrypt = (msg, secret) => { if (typeof msg !== 'string') { - throw new TypeError('mySEA.encrypt() -> expected msg to be an string') + throw new TypeError( + 'mySEA.encrypt() -> expected msg to be an string instead got: ' + + typeof msg + ) } if (msg.length === 0) { @@ -42,7 +45,10 @@ mySEA.encrypt = (msg, secret) => { mySEA.decrypt = (encMsg, secret) => { if (typeof encMsg !== 'string') { - throw new TypeError('mySEA.encrypt() -> expected encMsg to be an string') + throw new TypeError( + 'mySEA.encrypt() -> expected encMsg to be an string instead got: ' + + typeof encMsg + ) } if (encMsg.length === 0) { From 03fe61f2e4b1d7e26b9844e394bbf2336134137b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 12:04:41 -0400 Subject: [PATCH 036/137] actually store listener --- services/gunDB/contact-api/events.js | 1 + 1 file changed, 1 insertion(+) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 42991976..383dbac4 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -398,6 +398,7 @@ const processOutgoings = async () => { * @returns {() => void} */ const onOutgoing = cb => { + outgoingsListeners.add(cb) cb(currentOutgoings) const currentUser = require('../Mediator').getUser() From 44de364ae439ca801a93c8f15f69d3e5b3ee0ddc Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 12:36:16 -0400 Subject: [PATCH 037/137] better error checking --- services/gunDB/Mediator/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 4b22e1f8..03bd2a39 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -87,6 +87,12 @@ mySEA.decrypt = (encMsg, secret) => { } mySEA.secret = (recipientOrSenderEpub, recipientOrSenderSEA) => { + if (typeof recipientOrSenderEpub !== 'string') { + throw new TypeError('epub has to be an string') + } + if (typeof recipientOrSenderSEA !== 'object') { + throw new TypeError('sea has to be an object') + } if (recipientOrSenderEpub === recipientOrSenderSEA.pub) { throw new Error('Do not use pub for mysecret') } From 58cf841bdc87d728cdd9c1d22e47f7a5affdfd30 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 12:43:24 -0400 Subject: [PATCH 038/137] correct decrpyt --- services/gunDB/contact-api/events.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 383dbac4..b75e054b 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -337,6 +337,7 @@ const processOutgoings = async () => { encryptedOutgoings = {} const mySecret = await Utils.mySecret() const SEA = require('../Mediator').mySEA + const user = require('../Mediator').getUser() await Utils.asyncForEach(Object.entries(outs), async ([id, out]) => { if (out === null) { currentOutgoings[id] = null @@ -366,6 +367,11 @@ const processOutgoings = async () => { // on each open() only "messages" should change, not "with" // also messages are non-nullable and non-editable + const ourSecret = await SEA.secret( + await Utils.pubToEpub(currentOut.with), + user._.sea + ) + await Utils.asyncForEach( Object.entries(out.messages), async ([msgID, msg]) => { @@ -378,7 +384,7 @@ const processOutgoings = async () => { if (msg.body === Actions.INITIAL_MSG) { decryptedBody = Actions.INITIAL_MSG } else { - decryptedBody = await SEA.decrypt(msg.body, mySecret) + decryptedBody = await SEA.decrypt(msg.body, ourSecret) } // each callback only looks at one particular msgID // eslint-disable-next-line require-atomic-updates From 857b9ba1312b05d20b806d88f237f4b700397f01 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:26:03 -0400 Subject: [PATCH 039/137] rules --- .eslintrc.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index c08e850c..31d777cc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,6 @@ "rules": { "prettier/prettier": "error", "strict": "off", - "id-length": ["error", { "exceptions": ["_"] }], "no-console": "off", @@ -67,7 +66,10 @@ // lightning has sync methods and this rule bans them "no-sync": "off", - "id-length": "off" + "id-length": "off", + + // typescript does this + "no-unused-vars": "off" }, "parser": "babel-eslint", "env": { From 3fdd932e636d45db833b04ccc68f767629030041 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:26:13 -0400 Subject: [PATCH 040/137] streams --- services/gunDB/contact-api/streams.js | 192 ++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 services/gunDB/contact-api/streams.js diff --git a/services/gunDB/contact-api/streams.js b/services/gunDB/contact-api/streams.js new file mode 100644 index 00000000..00e7e206 --- /dev/null +++ b/services/gunDB/contact-api/streams.js @@ -0,0 +1,192 @@ +/** @format */ +const { INITIAL_MSG } = require('./actions') +const Key = require('./key') +const Schema = require('./schema') +const Utils = require('./utils') +/** + * @typedef {Record} Avatars + * @typedef {(avatars: Avatars) => void} AvatarListener + */ + +/** @type {Avatars} */ +const pubToAvatar = {} + +/** @type {Set} */ +const avatarListeners = new Set() + +const notifyAvatarListeners = () => { + avatarListeners.forEach(l => l(pubToAvatar)) +} + +/** @type {Set} */ +const pubsWithAvatarListeners = new Set() + +/** + * @param {AvatarListener} cb + * @param {string=} pub + */ +const onAvatar = (cb, pub) => { + avatarListeners.add(cb) + cb(pubToAvatar) + if (pub && pubsWithAvatarListeners.add(pub)) { + require('../Mediator') + .getGun() + .user(pub) + .get(Key.PROFILE) + .get(Key.AVATAR) + .on(av => { + if (typeof av === 'string' || av === null) { + pubToAvatar[pub] = av || null + notifyAvatarListeners() + } + }) + } + return () => { + avatarListeners.delete(cb) + } +} + +/** + * @typedef {Record} DisplayNames + * @typedef {(avatars: Avatars) => void} DisplayNameListener + */ + +/** @type {DisplayNames} */ +const pubToDisplayName = {} + +/** @type {Set} */ +const displayNameListeners = new Set() + +const notifyDisplayNameListeners = () => { + displayNameListeners.forEach(l => l(pubToDisplayName)) +} + +/** @type {Set} */ +const pubsWithDisplayNameListeners = new Set() + +/** + * @param {DisplayNameListener} cb + * @param {string=} pub + */ +const onDisplayName = (cb, pub) => { + displayNameListeners.add(cb) + cb(pubToDisplayName) + if (pub && pubsWithDisplayNameListeners.add(pub)) { + require('../Mediator') + .getGun() + .user(pub) + .get(Key.PROFILE) + .get(Key.DISPLAY_NAME) + .on(dn => { + if (typeof dn === 'string' || dn === null) { + pubToDisplayName[pub] = dn || null + notifyDisplayNameListeners() + } + }) + } + return () => { + displayNameListeners.delete(cb) + } +} + +/** + * @typedef {import('./schema').ChatMessage[]} Message + * @typedef {Record} Incomings + * @typedef {(incomings: Incomings) => void} IncomingsListener + */ + +/** + * @type {Incomings} + */ +const pubToIncoming = {} + +/** @type {Set} */ +const incomingsListeners = new Set() + +const notifyIncomingsListeners = () => { + incomingsListeners.forEach(l => l(pubToIncoming)) +} + +/** @type {Set} */ +const pubFeedPairsWithIncomingListeners = new Set() + +/** + * @param {IncomingsListener} cb + */ +const onIncoming = cb => { + incomingsListeners.add(cb) + + const user = require('../Mediator').getUser() + const SEA = require('../Mediator').mySEA + + user.get(Key.USER_TO_INCOMING).open(uti => { + if (typeof uti !== 'object' || uti === null) { + return + } + + Object.entries(uti).forEach(async ([pub, feed]) => { + if (typeof feed !== 'string') { + return + } + + if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { + const ourSecret = await SEA.secret( + await Utils.pubToEpub(pub), + user._.sea + ) + + require('../Mediator') + .getGun() + .user(pub) + .get(Key.OUTGOINGS) + .get(feed) + .open(async data => { + if (data === null) { + pubToIncoming[pub] = null + return + } + + if (!Schema.isOutgoing(data)) { + return + } + + // eslint-disable-next-line require-atomic-updates + pubToIncoming[pub] = await Utils.asyncMap( + Object.entries(data.messages), + async ([msgid, msg]) => { + let decryptedBody = '' + + if (msg.body === INITIAL_MSG) { + decryptedBody = INITIAL_MSG + } else { + decryptedBody = await SEA.decrypt(msg.body, ourSecret) + } + + /** @type {Schema.ChatMessage} */ + const finalMsg = { + body: decryptedBody, + id: msgid, + outgoing: false, + timestamp: msg.timestamp + } + + return finalMsg + } + ) + + notifyIncomingsListeners() + }) + } + }) + }) + + return () => { + incomingsListeners.delete(cb) + } +} + +module.exports = { + onAvatar, + onDisplayName, + onIncoming +} From 018978d7cec71887aa538db79c701ad9455eb488 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:26:35 -0400 Subject: [PATCH 041/137] faster chats --- services/gunDB/contact-api/events.js | 294 +++++++++------------------ 1 file changed, 94 insertions(+), 200 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index b75e054b..96faaddb 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -5,9 +5,9 @@ const debounce = require('lodash/debounce') const Actions = require('./actions') const ErrorCode = require('./errorCode') -const Getters = require('./getters') const Key = require('./key') const Schema = require('./schema') +const Streams = require('./streams') const Utils = require('./utils') const Config = require('../config') /** @@ -430,214 +430,108 @@ const onOutgoing = cb => { outgoingsListeners.delete(cb) } } +//////////////////////////////////////////////////////////////////////////////// +/** @type {Outgoings} */ +let outgoings = {} + +/** @type {Streams.Avatars} */ +let pubToAvatar = {} + +/** @type {Streams.DisplayNames} */ +let pubToDn = {} + +/** @type {Streams.Incomings} */ +let pubToIncoming = {} +/** + * @typedef {(chats: Chat[]) => void} ChatsListener + */ + +/** @type {Chat[]} */ +let currentChats = [] + +/** @type {Set} */ +const chatsListeners = new Set() + +const notifyChatsListeners = () => { + chatsListeners.forEach(l => l(currentChats)) +} + +const processChats = () => { + const existingOutgoings = /** @type {[string, Outgoing][]} */ (Object.entries( + outgoings + ).filter(([_, o]) => o !== null)) + + /** @type {Chat[]} */ + const chats = [] + + for (const [outID, out] of existingOutgoings) { + /** @type {ChatMessage[]} */ + let msgs = Object.entries(out.messages).map(([mid, m]) => ({ + id: mid, + outgoing: true, + body: m.body, + timestamp: m.timestamp + })) + + const incoming = pubToIncoming[out.with] + + if (Array.isArray(incoming)) { + msgs = [...msgs, ...incoming] + } + + /** @type {Chat} */ + const chat = { + recipientPublicKey: out.with, + didDisconnect: incoming === null, + id: out.with + outID, + messages: msgs, + recipientAvatar: pubToAvatar[out.with] || null, + recipientDisplayName: pubToDn[out.with] || null + } + + chats.push(chat) + + // eslint-disable-next-line no-empty-function + Streams.onAvatar(() => {}, out.with) + // eslint-disable-next-line no-empty-function + Streams.onDisplayName(() => {}, out.with) + } + + currentChats = chats + notifyChatsListeners() +} /** * Massages all of the more primitive data structures into a more manageable * 'Chat' paradigm. - * @param {(chats: Chat[]) => void} cb - * @param {GUNNode} gun - * @param {UserGUNNode} user - * @param {ISEA} SEA - * @returns {void} + * @param {ChatsListener} cb + * @returns {() => void} */ -const onChats = (cb, gun, user, SEA) => { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } +const onChats = cb => { + chatsListeners.add(cb) + cb(currentChats) - /** - * @type {Record} - */ - const recipientPKToChat = {} - - /** - * Keep track of the users for which we already set up avatar listeners. - * @type {string[]} - */ - const usersWithAvatarListeners = [] - - /** - * Keep track of the users for which we already set up display name listeners. - * @type {string[]} - */ - const usersWithDisplayNameListeners = [] - - /** - * Keep track of the user for which we already set up incoming feed listeners. - * @type {string[]} - */ - const usersWithIncomingListeners = [] - - /** @type {Set} */ - const userWithDisconnectionListeners = new Set() - - const _callCB = () => { - // Only provide chats that have incoming listeners which would be contacts - // that were actually accepted / are going on - // Only provide chats that have received at least 1 message from gun - const chats = Object.values(recipientPKToChat) - .filter(chat => - usersWithIncomingListeners.includes(chat.recipientPublicKey) - ) - .filter(chat => Schema.isChat(chat)) - .filter(chat => chat.messages.length > 0) - - // in case someone else elsewhere forgets about sorting - chats.forEach(chat => { - chat.messages = chat.messages - .slice(0) - .sort((msgA, msgB) => msgA.timestamp - msgB.timestamp) - }) - - cb(chats) - } - - // chats seem to require a bit more of debounce time - const callCB = debounce(_callCB, DEBOUNCE_WAIT_TIME + 200) - - callCB() - - onOutgoing(async outgoings => { - await Utils.asyncForEach(Object.values(outgoings), async outgoing => { - if (outgoing === null) { - return - } - const recipientPK = outgoing.with - const incomingID = await Getters.userToIncomingID(recipientPK) - const didDisconnect = - !!incomingID && (await Utils.didDisconnect(recipientPK, incomingID)) - - if (!recipientPKToChat[recipientPK]) { - recipientPKToChat[recipientPK] = { - messages: [], - recipientAvatar: null, - recipientDisplayName: Utils.defaultName(recipientPK), - recipientPublicKey: recipientPK, - didDisconnect, - id: recipientPK + incomingID - } - } - - const { messages } = recipientPKToChat[recipientPK] - - for (const [msgK, msg] of Object.entries(outgoing.messages)) { - if (!messages.find(_msg => _msg.id === msgK)) { - messages.push({ - body: msg.body, - id: msgK, - outgoing: true, - timestamp: msg.timestamp - }) - } - } - }) - - callCB() + onOutgoing(outs => { + outgoings = outs + processChats() }) - __onUserToIncoming( - async uti => { - await Utils.asyncForEach( - Object.entries(uti), - async ([recipientPK, incomingFeedID]) => { - const didDisconnect = await Utils.didDisconnect( - recipientPK, - incomingFeedID - ) - if (!recipientPKToChat[recipientPK]) { - recipientPKToChat[recipientPK] = { - messages: [], - recipientAvatar: null, - recipientDisplayName: Utils.defaultName(recipientPK), - recipientPublicKey: recipientPK, - didDisconnect, - id: recipientPK + incomingFeedID - } - } + Streams.onAvatar(pta => { + pubToAvatar = pta + processChats() + }) + Streams.onDisplayName(ptd => { + pubToDn = ptd + processChats() + }) + Streams.onIncoming(pti => { + pubToIncoming = pti + processChats() + }) - const chat = recipientPKToChat[recipientPK] - - if (!userWithDisconnectionListeners.has(recipientPK)) { - userWithDisconnectionListeners.add(recipientPK) - - require('../Mediator') - .getGun() - .user(recipientPK) - .get(Key.OUTGOINGS) - .get(incomingFeedID) - .on(data => { - if (data === null) { - chat.didDisconnect = true - chat.messages = chat.messages.filter(m => m.outgoing) - - callCB() - } - }) - } - - if (!usersWithIncomingListeners.includes(recipientPK)) { - usersWithIncomingListeners.push(recipientPK) - - onIncomingMessages( - msgs => { - for (const [msgK, msg] of Object.entries(msgs)) { - const { messages } = chat - - if (!messages.find(_msg => _msg.id === msgK)) { - messages.push({ - body: msg.body, - id: msgK, - outgoing: false, - timestamp: msg.timestamp - }) - } - } - - callCB() - }, - recipientPK, - incomingFeedID, - gun, - user, - SEA - ) - } - - if (!usersWithAvatarListeners.includes(recipientPK)) { - usersWithAvatarListeners.push(recipientPK) - - gun - .user(recipientPK) - .get(Key.PROFILE) - .get(Key.AVATAR) - .on(avatar => { - if (typeof avatar === 'string') { - chat.recipientAvatar = avatar - callCB() - } - }) - } - - if (!usersWithDisplayNameListeners.includes(recipientPK)) { - usersWithDisplayNameListeners.push(recipientPK) - - gun - .user(recipientPK) - .get(Key.PROFILE) - .get(Key.DISPLAY_NAME) - .on(displayName => { - if (typeof displayName === 'string') { - chat.recipientDisplayName = displayName - callCB() - } - }) - } - } - ) - }, - user, - SEA - ) + return () => { + chatsListeners.delete(cb) + } } /** From 0713d5500b32d817423b8c14730bb83ba791b415 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:33:51 -0400 Subject: [PATCH 042/137] no empty chats --- services/gunDB/contact-api/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 96faaddb..37fc10bb 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -497,7 +497,7 @@ const processChats = () => { Streams.onDisplayName(() => {}, out.with) } - currentChats = chats + currentChats = chats.filter(c => c.messages.length > 0) notifyChatsListeners() } From f6dd79c1593c8ff5590d4570a61053f1dc77f661 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:43:55 -0400 Subject: [PATCH 043/137] avoid stack overflow --- services/gunDB/contact-api/events.js | 12 ++++++++---- services/gunDB/contact-api/streams.js | 8 ++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 37fc10bb..4429e34b 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -491,10 +491,14 @@ const processChats = () => { chats.push(chat) - // eslint-disable-next-line no-empty-function - Streams.onAvatar(() => {}, out.with) - // eslint-disable-next-line no-empty-function - Streams.onDisplayName(() => {}, out.with) + if (typeof pubToAvatar[out.with] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onAvatar(() => {}, out.with) + } + if (typeof pubToDn[out.with] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onDisplayName(() => {}, out.with) + } } currentChats = chats.filter(c => c.messages.length > 0) diff --git a/services/gunDB/contact-api/streams.js b/services/gunDB/contact-api/streams.js index 00e7e206..de370a26 100644 --- a/services/gunDB/contact-api/streams.js +++ b/services/gunDB/contact-api/streams.js @@ -37,8 +37,10 @@ const onAvatar = (cb, pub) => { .on(av => { if (typeof av === 'string' || av === null) { pubToAvatar[pub] = av || null - notifyAvatarListeners() + } else { + pubToAvatar[pub] = null } + notifyAvatarListeners() }) } return () => { @@ -80,8 +82,10 @@ const onDisplayName = (cb, pub) => { .on(dn => { if (typeof dn === 'string' || dn === null) { pubToDisplayName[pub] = dn || null - notifyDisplayNameListeners() + } else { + pubToDisplayName } + notifyDisplayNameListeners() }) } return () => { From 11fd3733011c5af8fffce5b06d9949780abb98a4 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:45:14 -0400 Subject: [PATCH 044/137] typo --- services/gunDB/contact-api/streams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams.js b/services/gunDB/contact-api/streams.js index de370a26..4a5ea059 100644 --- a/services/gunDB/contact-api/streams.js +++ b/services/gunDB/contact-api/streams.js @@ -83,7 +83,7 @@ const onDisplayName = (cb, pub) => { if (typeof dn === 'string' || dn === null) { pubToDisplayName[pub] = dn || null } else { - pubToDisplayName + pubToDisplayName[pub] = null } notifyDisplayNameListeners() }) From d898506a2819eaca0eca8d88729d70ce5c2cc217 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 14:54:14 -0400 Subject: [PATCH 045/137] fine grained validation --- services/gunDB/contact-api/streams.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/streams.js b/services/gunDB/contact-api/streams.js index 4a5ea059..ba7457a8 100644 --- a/services/gunDB/contact-api/streams.js +++ b/services/gunDB/contact-api/streams.js @@ -150,13 +150,29 @@ const onIncoming = cb => { return } - if (!Schema.isOutgoing(data)) { + if (typeof data !== 'object') { return } + if (typeof data.with !== 'string') { + return + } + + if (typeof data.messages !== 'object') { + return + } + + if (data.messages === null) { + return + } + + const msgs = /** @type {[string, Schema.Message][]} */ (Object.entries( + data.messages + ).filter(([_, msg]) => Schema.isMessage(msg))) + // eslint-disable-next-line require-atomic-updates pubToIncoming[pub] = await Utils.asyncMap( - Object.entries(data.messages), + msgs, async ([msgid, msg]) => { let decryptedBody = '' From 64cff4b64b9333c69a873f0a81e5cd59396465af Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 15:09:54 -0400 Subject: [PATCH 046/137] filter chats for which we don't know the request status --- services/gunDB/contact-api/events.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events.js index 4429e34b..aac6c600 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events.js @@ -501,7 +501,9 @@ const processChats = () => { } } - currentChats = chats.filter(c => c.messages.length > 0) + currentChats = chats + .filter(c => c.messages.length > 0) + .filter(c => typeof pubToIncoming[c.recipientPublicKey] !== 'undefined') notifyChatsListeners() } From 851349317669660a4608c711e5eb41be42f09b5b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 16:34:40 -0400 Subject: [PATCH 047/137] better received reqs --- .../{events.js => events/index.js} | 351 ++---------------- .../contact-api/events/onReceivedReqs.js | 144 +++++++ 2 files changed, 167 insertions(+), 328 deletions(-) rename services/gunDB/contact-api/{events.js => events/index.js} (67%) create mode 100644 services/gunDB/contact-api/events/onReceivedReqs.js diff --git a/services/gunDB/contact-api/events.js b/services/gunDB/contact-api/events/index.js similarity index 67% rename from services/gunDB/contact-api/events.js rename to services/gunDB/contact-api/events/index.js index aac6c600..9ebcaeb5 100644 --- a/services/gunDB/contact-api/events.js +++ b/services/gunDB/contact-api/events/index.js @@ -3,26 +3,25 @@ */ const debounce = require('lodash/debounce') -const Actions = require('./actions') -const ErrorCode = require('./errorCode') -const Key = require('./key') -const Schema = require('./schema') -const Streams = require('./streams') -const Utils = require('./utils') -const Config = require('../config') +const Actions = require('../actions') +const ErrorCode = require('../errorCode') +const Key = require('../key') +const Schema = require('../schema') +const Streams = require('../streams') +const Utils = require('../utils') /** - * @typedef {import('./SimpleGUN').UserGUNNode} UserGUNNode - * @typedef {import('./SimpleGUN').GUNNode} GUNNode - * @typedef {import('./SimpleGUN').ISEA} ISEA - * @typedef {import('./SimpleGUN').ListenerData} ListenerData - * @typedef {import('./schema').HandshakeRequest} HandshakeRequest - * @typedef {import('./schema').Message} Message - * @typedef {import('./schema').Outgoing} Outgoing - * @typedef {import('./schema').PartialOutgoing} PartialOutgoing - * @typedef {import('./schema').Chat} Chat - * @typedef {import('./schema').ChatMessage} ChatMessage - * @typedef {import('./schema').SimpleSentRequest} SimpleSentRequest - * @typedef {import('./schema').SimpleReceivedRequest} SimpleReceivedRequest + * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode + * @typedef {import('../SimpleGUN').GUNNode} GUNNode + * @typedef {import('../SimpleGUN').ISEA} ISEA + * @typedef {import('../SimpleGUN').ListenerData} ListenerData + * @typedef {import('../schema').HandshakeRequest} HandshakeRequest + * @typedef {import('../schema').Message} Message + * @typedef {import('../schema').Outgoing} Outgoing + * @typedef {import('../schema').PartialOutgoing} PartialOutgoing + * @typedef {import('../schema').Chat} Chat + * @typedef {import('../schema').ChatMessage} ChatMessage + * @typedef {import('../schema').SimpleSentRequest} SimpleSentRequest + * @typedef {import('../schema').SimpleReceivedRequest} SimpleReceivedRequest */ const DEBOUNCE_WAIT_TIME = 500 @@ -336,8 +335,8 @@ const processOutgoings = async () => { const outs = encryptedOutgoings encryptedOutgoings = {} const mySecret = await Utils.mySecret() - const SEA = require('../Mediator').mySEA - const user = require('../Mediator').getUser() + const SEA = require('../../Mediator').mySEA + const user = require('../../Mediator').getUser() await Utils.asyncForEach(Object.entries(outs), async ([id, out]) => { if (out === null) { currentOutgoings[id] = null @@ -407,7 +406,7 @@ const onOutgoing = cb => { outgoingsListeners.add(cb) cb(currentOutgoings) - const currentUser = require('../Mediator').getUser() + const currentUser = require('../../Mediator').getUser() if (lastUserWithListener !== currentUser) { // in case user changed gun alias @@ -417,7 +416,7 @@ const onOutgoing = cb => { currentUser.get(Key.OUTGOINGS).open(data => { // deactivate this listener when user changes - if (lastUserWithListener !== require('../Mediator').getUser()) { + if (lastUserWithListener !== require('../../Mediator').getUser()) { return } // @ts-ignore Let's skip schema checks for perf reasons @@ -540,310 +539,6 @@ const onChats = cb => { } } -/** - * - * @param {(simpleReceivedRequests: SimpleReceivedRequest[]) => void} cb - * @param {GUNNode} gun - * @param {UserGUNNode} user - * @param {ISEA} SEA - * @returns {void} - */ -const onSimplerReceivedRequests = (cb, gun, user, SEA) => { - try { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } - - /** @type {Record} */ - const idToRequest = {} - - /** @type {string[]} */ - const requestorsWithAvatarListeners = [] - - /** @type {string[]} */ - const requestorsWithDisplayNameListeners = [] - - /** - * @type {Partial>} - */ - const requestorToAvatar = {} - - /** - * @type {Partial>} - */ - const requestorToDisplayName = {} - - /** @type {Set} */ - const requestorsAlreadyAccepted = new Set() - - /** - * We cannot call gun.off(), so keep track of the current handshake addres. - * And only run the listeners for the handshake nodes if they are for the - * current handshake address node. - */ - let currentHandshakeAddress = '' - - //////////////////////////////////////////////////////////////////////////// - - const _callCB = async () => { - try { - const requestEntries = Object.entries(idToRequest) - - if (Config.SHOW_LOG) { - console.log('requestorsAlreadyAccepted') - console.log(requestorsAlreadyAccepted) - console.log('/requestorsAlreadyAccepted') - } - - if (Config.SHOW_LOG) { - console.log('raw requests:') - console.log(idToRequest) - console.log('/raw requests') - } - - // avoid race conditions due to gun's reactive nature. - const onlyInCurrentHandshakeNode = await Utils.asyncFilter( - requestEntries, - async ([id]) => { - try { - const HNAddr = await Utils.tryAndWait(async (_, user) => { - const data = await user - .get(Key.CURRENT_HANDSHAKE_ADDRESS) - .then() - - if (typeof data !== 'string') { - throw new Error('handshake address not an string') - } - - return data - }) - - const maybeHreq = await Utils.tryAndWait(gun => - gun - .get(Key.HANDSHAKE_NODES) - .get(HNAddr) - .get(id) - .then() - ) - - return Schema.isHandshakeRequest(maybeHreq) - } catch (err) { - console.log(`error for request ID: ${id}`) - throw err - } - } - ) - - if (Config.SHOW_LOG) { - console.log('onlyInCurrentHandshakeNode') - console.log(onlyInCurrentHandshakeNode) - console.log('/onlyInCurrentHandshakeNode') - } - - // USER-TO-INCOMING (which indicates acceptance of this request) write - // might not be in there by the time we are looking at these requests. - // Let's account for this. - const notAccepted = await Utils.asyncFilter( - onlyInCurrentHandshakeNode, - async ([reqID, req]) => { - try { - if (requestorsAlreadyAccepted.has(req.from)) { - return false - } - - const requestorEpub = await Utils.pubToEpub(req.from) - - const ourSecret = await SEA.secret(requestorEpub, user._.sea) - if (typeof ourSecret !== 'string') { - throw new TypeError('typeof ourSecret !== "string"') - } - - const decryptedResponse = await SEA.decrypt( - req.response, - ourSecret - ) - - if (typeof decryptedResponse !== 'string') { - throw new TypeError('typeof decryptedResponse !== "string"') - } - - const outfeedID = decryptedResponse - - if (Config.SHOW_LOG) { - console.log('\n') - console.log('--------outfeedID----------') - console.log(outfeedID) - console.log('------------------') - console.log('\n') - } - - const maybeOutfeed = await Utils.tryAndWait(gun => - gun - .user(req.from) - .get(Key.OUTGOINGS) - .get(outfeedID) - .then() - ) - - if (Config.SHOW_LOG) { - console.log('\n') - console.log('--------maybeOutfeed----------') - console.log(maybeOutfeed) - console.log('------------------') - console.log('\n') - } - - const wasAccepted = Schema.isHandshakeRequest(maybeOutfeed) - - return !wasAccepted - } catch (err) { - console.log(`error for request ID: ${reqID}`) - throw err - } - } - ) - - if (Config.SHOW_LOG) { - console.log('notAccepted') - console.log(notAccepted) - console.log('/notAccepted') - } - - const simpleReceivedReqs = notAccepted.map(([reqID, req]) => { - try { - const { from: requestorPub } = req - - /** @type {SimpleReceivedRequest} */ - const simpleReceivedReq = { - id: reqID, - requestorAvatar: requestorToAvatar[requestorPub] || null, - requestorDisplayName: - requestorToDisplayName[requestorPub] || - Utils.defaultName(requestorPub), - requestorPK: requestorPub, - response: req.response, - timestamp: req.timestamp - } - - return simpleReceivedReq - } catch (err) { - console.log(`error for request ID: ${reqID}`) - throw err - } - }) - - cb(simpleReceivedReqs) - } catch (err) { - console.error(err) - } - } - - const callCB = debounce(_callCB, DEBOUNCE_WAIT_TIME) - callCB() - - user - .get(Key.USER_TO_INCOMING) - .map() - .on((incomingID, userPK) => { - const disconnected = incomingID === null - if (disconnected) { - requestorsAlreadyAccepted.delete(userPK) - } else { - requestorsAlreadyAccepted.add(userPK) - } - - callCB() - }) - - //////////////////////////////////////////////////////////////////////////// - /** - * @param {string} addr - * @returns {(req: ListenerData, reqID: string) => void} - */ - const listenerForAddr = addr => (req, reqID) => { - try { - if (addr !== currentHandshakeAddress) { - console.log( - 'onSimplerReceivedRequests() -> listenerForAddr() -> stale handshake address, quitting' - ) - return - } - - if (!Schema.isHandshakeRequest(req)) { - console.log( - 'onSimplerReceivedRequests() -> listenerForAddr() -> bad handshake request, quitting' - ) - console.log(req) - return - } - - idToRequest[reqID] = req - callCB() - - if (!requestorsWithAvatarListeners.includes(req.from)) { - requestorsWithAvatarListeners.push(req.from) - - gun - .user(req.from) - .get(Key.PROFILE) - .get(Key.AVATAR) - .on(avatar => { - if (typeof avatar === 'string' || avatar === null) { - // || handles empty strings - requestorToAvatar[req.from] = avatar || null - - callCB() - } - }) - } - - if (!requestorsWithDisplayNameListeners.includes(req.from)) { - requestorsWithDisplayNameListeners.push(req.from) - - gun - .user(req.from) - .get(Key.PROFILE) - .get(Key.DISPLAY_NAME) - .on(displayName => { - if (typeof displayName === 'string' || displayName === null) { - // || handles empty strings - requestorToDisplayName[req.from] = displayName || null - - callCB() - } - }) - } - } catch (err) { - console.log('onSimplerReceivedRequests() -> listenerForAddr() ->') - console.log(err) - } - - callCB() - } - //////////////////////////////////////////////////////////////////////////// - user.get(Key.CURRENT_HANDSHAKE_ADDRESS).on(addr => { - if (typeof addr !== 'string') { - throw new TypeError('current handshake address not an string') - } - - console.log( - `onSimplerReceivedRequests() -> setting current address to ${addr}` - ) - currentHandshakeAddress = addr - - gun - .get(Key.HANDSHAKE_NODES) - .get(addr) - .map() - .on(listenerForAddr(addr)) - - callCB() - }) - } catch (err) { - console.log(`onSimplerReceivedRequests() -> ${err.message}`) - } -} - /** * @param {(sentRequests: SimpleSentRequest[]) => void} cb * @param {GUNNode} gun @@ -1158,7 +853,7 @@ module.exports = { onIncomingMessages, onOutgoing, onChats, - onSimplerReceivedRequests, + onSimplerReceivedRequests: require('./onReceivedReqs'), onSimplerSentRequests, onBio, onSeedBackup diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js new file mode 100644 index 00000000..849a3ec9 --- /dev/null +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -0,0 +1,144 @@ +/** @format */ +const Events = require('./index') +const Key = require('../key') +const Schema = require('../schema') +const Streams = require('../streams') +/** + * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode + * @typedef {import('../SimpleGUN').GUNNode} GUNNode + * @typedef {import('../SimpleGUN').ISEA} ISEA + * @typedef {import('../SimpleGUN').ListenerData} ListenerData + * @typedef {import('../schema').HandshakeRequest} HandshakeRequest + * @typedef {import('../schema').Message} Message + * @typedef {import('../schema').Outgoing} Outgoing + * @typedef {import('../schema').PartialOutgoing} PartialOutgoing + * @typedef {import('../schema').Chat} Chat + * @typedef {import('../schema').ChatMessage} ChatMessage + * @typedef {import('../schema').SimpleSentRequest} SimpleSentRequest + * @typedef {import('../schema').SimpleReceivedRequest} SimpleReceivedRequest + */ + +/** + * @typedef {(chats: SimpleReceivedRequest[]) => void} Listener + */ + +const listeners = new Set() + +/** @type {Streams.Avatars} */ +let pubToAvatar = {} + +/** @type {Streams.DisplayNames} */ +let pubToDn = {} + +/** @type {Streams.Incomings} */ +let pubToIncoming = {} + +/** @type {SimpleReceivedRequest[]} */ +let currentReqs = [] + +/** @type {string|null} */ +let currentAddress = null + +/** @type {Record} */ +let currentNode = {} + +const react = () => { + /** @type {SimpleReceivedRequest[]} */ + const finalReqs = [] + + for (const [id, req] of Object.entries(currentNode)) { + const notAccepted = typeof pubToIncoming[req.from] === 'undefined' + + if (notAccepted) { + finalReqs.push({ + id, + requestorAvatar: pubToAvatar[req.from] || null, + requestorDisplayName: pubToDn[req.from] || null, + requestorPK: req.from, + response: req.response, + timestamp: req.timestamp + }) + } + } + + currentReqs = finalReqs + + listeners.forEach(l => l(currentReqs)) +} + +/** + * + * @param {string} addr + * @returns {(data: import('../SimpleGUN').OpenListenerData) => void} + */ +const listenerForAddr = addr => data => { + if (addr !== currentAddress) { + return + } + + if (typeof data === 'object' && data !== null) { + for (const [id, req] of Object.entries(data)) { + if (!Schema.isHandshakeRequest(req)) { + return + } + + currentNode[id] = req + } + + react() + } +} + +let subbed = false + +/** + * Massages all of the more primitive data structures into a more manageable + * 'Chat' paradigm. + * @param {Listener} cb + * @returns {() => void} + */ +const onReceivedReqs = cb => { + listeners.add(cb) + + if (!subbed) { + Events.onCurrentHandshakeAddress(addr => { + if (currentAddress !== addr) { + currentAddress = addr + currentNode = {} + + if (typeof addr === 'string') { + require('../../Mediator') + .getGun() + .get(Key.HANDSHAKE_NODES) + .get(addr) + .open(listenerForAddr(addr)) + } + + react() + } + }, require('../../Mediator').getUser()) + + Streams.onAvatar(pta => { + pubToAvatar = pta + react() + }) + Streams.onDisplayName(ptd => { + pubToDn = ptd + react() + }) + Streams.onIncoming(pti => { + pubToIncoming = pti + react() + }) + + subbed = true + } + + cb(currentReqs) + + return () => { + listeners.delete(cb) + } +} + +module.exports = onReceivedReqs From 29ef6eceba869622d00ae12a9752be8b28ddf467 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 17:21:57 -0400 Subject: [PATCH 048/137] correct schema --- services/gunDB/contact-api/schema.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/gunDB/contact-api/schema.js b/services/gunDB/contact-api/schema.js index e7dc0b5b..41adf321 100644 --- a/services/gunDB/contact-api/schema.js +++ b/services/gunDB/contact-api/schema.js @@ -146,6 +146,8 @@ exports.isStoredRequest = item => { const obj = /** @type {StoredRequest} */ (item) if (typeof obj.recipientPub !== 'string') return false if (typeof obj.handshakeAddress !== 'string') return false + if (typeof obj.handshakeAddress !== 'string') return false + if (typeof obj.timestamp !== 'number') return false return true } From 8d28395e777e5db3ebbc96ce137698531ddc4254 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 17:22:30 -0400 Subject: [PATCH 049/137] storedreqs stream --- services/gunDB/contact-api/streams.js | 77 ++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams.js b/services/gunDB/contact-api/streams.js index ba7457a8..8bedcf3f 100644 --- a/services/gunDB/contact-api/streams.js +++ b/services/gunDB/contact-api/streams.js @@ -205,8 +205,83 @@ const onIncoming = cb => { } } +/** + * @typedef {import('./schema').StoredRequest} StoredRequest + * @typedef {(reqs: StoredRequest[]) => void} StoredRequestsListener + */ + +/** @type {Set} */ +const storedRequestsListeners = new Set() + +/** + * @type {StoredRequest[]} + */ +let encryptedStoredReqs = [] + +/** + * @type {StoredRequest[]} + */ +let currentStoredReqs = [] + +const getStoredReqs = () => currentStoredReqs + +const processStoredReqs = async () => { + const ereqs = encryptedStoredReqs + encryptedStoredReqs = [] + const mySecret = await Utils.mySecret() + const SEA = require('../Mediator').mySEA + const finalReqs = await Utils.asyncMap(ereqs, async er => { + /** @type {StoredRequest} */ + const r = { + handshakeAddress: await SEA.decrypt(er.handshakeAddress, mySecret), + recipientPub: await SEA.decrypt(er.recipientPub, mySecret), + sentReqID: await SEA.decrypt(er.sentReqID, mySecret), + timestamp: er.timestamp + } + + return r + }) + currentStoredReqs = finalReqs + storedRequestsListeners.forEach(l => l(currentStoredReqs)) +} + +let subbed = false + +/** + * + * @param {StoredRequestsListener} cb + */ +const onStoredReqs = cb => { + storedRequestsListeners.add(cb) + + if (!subbed) { + require('../Mediator') + .getUser() + .get(Key.STORED_REQS) + .open(d => { + if (typeof d === 'object' && d !== null) { + encryptedStoredReqs = /** @type {StoredRequest[]} */ (Object.values( + d + ).filter(i => Schema.isStoredRequest(i))) + } + + processStoredReqs() + }) + + subbed = true + } + + cb(currentStoredReqs) + + return () => { + storedRequestsListeners.delete(cb) + } +} + module.exports = { onAvatar, onDisplayName, - onIncoming + onIncoming, + onStoredReqs, + getStoredReqs } From c2c63f957659a5d43ac239540cfe25acc08bfd73 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 18:29:21 -0400 Subject: [PATCH 050/137] new events and streams --- services/gunDB/Mediator/index.js | 97 +++---- services/gunDB/contact-api/events/index.js | 254 +----------------- .../gunDB/contact-api/events/onSentReqs.js | 103 +++++++ .../gunDB/contact-api/streams/addresses.js | 48 ++++ .../{streams.js => streams/index.js} | 42 +-- .../contact-api/streams/lastSentReqID.js | 50 ++++ 6 files changed, 269 insertions(+), 325 deletions(-) create mode 100644 services/gunDB/contact-api/events/onSentReqs.js create mode 100644 services/gunDB/contact-api/streams/addresses.js rename services/gunDB/contact-api/{streams.js => streams/index.js} (86%) create mode 100644 services/gunDB/contact-api/streams/lastSentReqID.js diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 03bd2a39..d01b9ea7 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -474,10 +474,7 @@ class Mediator { }) }), 300 - ), - gun, - user, - mySEA + ) ) } catch (err) { console.log(err) @@ -593,10 +590,7 @@ class Mediator { }) }), 350 - ), - gun, - user, - mySEA + ) ) } catch (err) { if (Config.SHOW_LOG) { @@ -835,24 +829,19 @@ class Mediator { await throwOnInvalidToken(token) - API.Events.onChats( - chats => { - if (Config.SHOW_LOG) { - console.log('---chats---') - console.log(chats) - console.log('-----------------------') - } + API.Events.onChats(chats => { + if (Config.SHOW_LOG) { + console.log('---chats---') + console.log(chats) + console.log('-----------------------') + } - this.socket.emit(Event.ON_CHATS, { - msg: chats, - ok: true, - origBody: body - }) - }, - gun, - user, - mySEA - ) + this.socket.emit(Event.ON_CHATS, { + msg: chats, + ok: true, + origBody: body + }) + }) } catch (err) { console.log(err) this.socket.emit(Event.ON_CHATS, { @@ -936,24 +925,19 @@ class Mediator { await throwOnInvalidToken(token) - API.Events.onSimplerReceivedRequests( - receivedRequests => { - if (Config.SHOW_LOG) { - console.log('---receivedRequests---') - console.log(receivedRequests) - console.log('-----------------------') - } + API.Events.onSimplerReceivedRequests(receivedRequests => { + if (Config.SHOW_LOG) { + console.log('---receivedRequests---') + console.log(receivedRequests) + console.log('-----------------------') + } - this.socket.emit(Event.ON_RECEIVED_REQUESTS, { - msg: receivedRequests, - ok: true, - origBody: body - }) - }, - gun, - user, - mySEA - ) + this.socket.emit(Event.ON_RECEIVED_REQUESTS, { + msg: receivedRequests, + ok: true, + origBody: body + }) + }) } catch (err) { console.log(err) this.socket.emit(Event.ON_RECEIVED_REQUESTS, { @@ -973,24 +957,19 @@ class Mediator { await throwOnInvalidToken(token) - await API.Events.onSimplerSentRequests( - sentRequests => { - if (Config.SHOW_LOG) { - console.log('---sentRequests---') - console.log(sentRequests) - console.log('-----------------------') - } + await API.Events.onSimplerSentRequests(sentRequests => { + if (Config.SHOW_LOG) { + console.log('---sentRequests---') + console.log(sentRequests) + console.log('-----------------------') + } - this.socket.emit(Event.ON_SENT_REQUESTS, { - msg: sentRequests, - ok: true, - origBody: body - }) - }, - gun, - user, - mySEA - ) + this.socket.emit(Event.ON_SENT_REQUESTS, { + msg: sentRequests, + ok: true, + origBody: body + }) + }) } catch (err) { console.log(err) this.socket.emit(Event.ON_SENT_REQUESTS, { diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 9ebcaeb5..18ab7f01 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -441,6 +441,7 @@ let pubToDn = {} /** @type {Streams.Incomings} */ let pubToIncoming = {} + /** * @typedef {(chats: Chat[]) => void} ChatsListener */ @@ -539,256 +540,6 @@ const onChats = cb => { } } -/** - * @param {(sentRequests: SimpleSentRequest[]) => void} cb - * @param {GUNNode} gun - * @param {UserGUNNode} user - * @param {ISEA} SEA - * @returns {Promise} - */ -const onSimplerSentRequests = async (cb, gun, user, SEA) => { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } - /** - * @type {Record} - */ - const storedReqs = {} - /** - * @type {Partial>} - */ - const recipientToAvatar = {} - /** - * @type {Partial>} - */ - const recipientToDisplayName = {} - /** - * @type {Partial>} - */ - const recipientToCurrentHandshakeAddress = {} - /** - * @type {Record} - */ - const simpleSentRequests = {} - /** - * Keep track of recipients that already have listeners for their avatars. - * @type {string[]} - */ - const recipientsWithAvatarListener = [] - /** - * Keep track of recipients that already have listeners for their display - * name. - * @type {string[]} - */ - const recipientsWithDisplayNameListener = [] - /** - * Keep track of recipients that already have listeners for their current - * handshake node. - * @type {string[]} - */ - const recipientsWithCurrentHandshakeAddressListener = [] - - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - - if (typeof mySecret !== 'string') { - throw new TypeError("typeof mySecret !== 'string'") - } - - const callCB = debounce(async () => { - try { - console.log('\n') - console.log('------simplerSentRequests: rawRequests ------') - console.log(storedReqs) - console.log('\n') - - const entries = Object.entries(storedReqs) - - /** @type {Promise[]} */ - const promises = entries.map(([, storedReq]) => - (async () => { - const recipientPub = await SEA.decrypt( - storedReq.recipientPub, - mySecret - ) - if (typeof recipientPub !== 'string') { - throw new TypeError() - } - const requestAddress = await SEA.decrypt( - storedReq.handshakeAddress, - mySecret - ) - if (typeof requestAddress !== 'string') { - throw new TypeError() - } - const sentReqID = await SEA.decrypt(storedReq.sentReqID, mySecret) - if (typeof sentReqID !== 'string') { - throw new TypeError() - } - - /** @type {Schema.HandshakeRequest} */ - const sentReq = await Utils.tryAndWait(async gun => { - const data = await gun - .get(Key.HANDSHAKE_NODES) - .get(requestAddress) - .get(sentReqID) - .then() - - if (Schema.isHandshakeRequest(data)) { - return data - } - - throw new TypeError('sent req not a handshake request') - }) - - const latestReqIDForRecipient = await Utils.recipientPubToLastReqSentID( - recipientPub - ) - - if ( - await Utils.reqWasAccepted( - sentReq.response, - recipientPub, - user, - SEA - ) - ) { - return null - } - - if ( - !recipientsWithCurrentHandshakeAddressListener.includes( - recipientPub - ) - ) { - recipientsWithCurrentHandshakeAddressListener.push(recipientPub) - - gun - .user(recipientPub) - .get(Key.CURRENT_HANDSHAKE_ADDRESS) - .on(addr => { - if (typeof addr !== 'string') { - console.log( - "onSimplerSentRequests() -> typeof addr !== 'string'" - ) - - return - } - - recipientToCurrentHandshakeAddress[recipientPub] = addr - - callCB() - }) - } - - if (!recipientsWithAvatarListener.includes(recipientPub)) { - recipientsWithAvatarListener.push(recipientPub) - - gun - .user(recipientPub) - .get(Key.PROFILE) - .get(Key.AVATAR) - .on(avatar => { - if (typeof avatar === 'string' || avatar === null) { - recipientToAvatar[recipientPub] = avatar - callCB() - } - }) - } - - if (!recipientsWithDisplayNameListener.includes(recipientPub)) { - recipientsWithDisplayNameListener.push(recipientPub) - - gun - .user(recipientPub) - .get(Key.PROFILE) - .get(Key.DISPLAY_NAME) - .on(displayName => { - if (typeof displayName === 'string' || displayName === null) { - recipientToDisplayName[recipientPub] = displayName - callCB() - } - }) - } - - const isStaleRequest = latestReqIDForRecipient !== sentReqID - - if (isStaleRequest) { - return null - } - - /** - * @type {SimpleSentRequest} - */ - const res = { - id: sentReqID, - recipientAvatar: recipientToAvatar[recipientPub] || null, - recipientChangedRequestAddress: false, - recipientDisplayName: - recipientToDisplayName[recipientPub] || - Utils.defaultName(recipientPub), - recipientPublicKey: recipientPub, - timestamp: sentReq.timestamp - } - - return res - })() - ) - - const reqsOrNulls = await Promise.all(promises) - - console.log('\n') - console.log('------simplerSentRequests: reqsOrNulls ------') - console.log(reqsOrNulls) - console.log('\n') - - /** @type {SimpleSentRequest[]} */ - // @ts-ignore - const reqs = reqsOrNulls.filter(item => item !== null) - - for (const req of reqs) { - simpleSentRequests[req.id] = req - } - } catch (err) { - console.log(`onSimplerSentRequests() -> callCB() -> ${err.message}`) - } finally { - cb(Object.values(simpleSentRequests)) - } - }, DEBOUNCE_WAIT_TIME) - - callCB() - - // force a refresh when a request is accepted - user.get(Key.USER_TO_INCOMING).on(() => { - callCB() - }) - - user - .get(Key.STORED_REQS) - .map() - .on((sentRequest, sentRequestID) => { - try { - if (!Schema.isStoredRequest(sentRequest)) { - console.log('\n') - console.log( - '------simplerSentRequests: !Schema.isHandshakeRequest(sentRequest) ------' - ) - console.log(sentRequest) - console.log('\n') - - return - } - - storedReqs[sentRequestID] = sentRequest - - callCB() - } catch (err) { - console.log( - `onSimplerSentRequests() -> sentRequestID: ${sentRequestID} -> ${err.message}` - ) - } - }) -} - /** @type {string|null} */ let currentBio = null @@ -854,7 +605,8 @@ module.exports = { onOutgoing, onChats, onSimplerReceivedRequests: require('./onReceivedReqs'), - onSimplerSentRequests, + onSimplerSentRequests: require('./onSentReqs').onSentReqs, + getCurrentSentReqs: require('./onSentReqs').getCurrentSentReqs, onBio, onSeedBackup } diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js new file mode 100644 index 00000000..09057ef3 --- /dev/null +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -0,0 +1,103 @@ +/** @format */ +const Streams = require('../streams') +/** + * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode + * @typedef {import('../SimpleGUN').GUNNode} GUNNode + * @typedef {import('../SimpleGUN').ISEA} ISEA + * @typedef {import('../SimpleGUN').ListenerData} ListenerData + * @typedef {import('../schema').HandshakeRequest} HandshakeRequest + * @typedef {import('../schema').Message} Message + * @typedef {import('../schema').Outgoing} Outgoing + * @typedef {import('../schema').PartialOutgoing} PartialOutgoing + * @typedef {import('../schema').Chat} Chat + * @typedef {import('../schema').ChatMessage} ChatMessage + * @typedef {import('../schema').SimpleSentRequest} SimpleSentRequest + * @typedef {import('../schema').SimpleReceivedRequest} SimpleReceivedRequest + */ + +/** + * @typedef {(chats: SimpleSentRequest[]) => void} Listener + */ + +/** @type {Set} */ +const listeners = new Set() + +/** @type {SimpleSentRequest[]} */ +let currentReqs = [] + +const getCurrentSentReqs = () => currentReqs + +const react = () => { + /** @type {SimpleSentRequest[]} */ + const finalSentReqs = [] + + const pubToHAddr = Streams.getAddresses() + const storedReqs = Streams.getStoredReqs() + const pubToLastSentReqID = Streams.getSentReqIDs() + const pubToIncoming = Streams.getPubToIncoming() + const pubToAvatar = Streams.getPubToAvatar() + const pubToDN = Streams.getPubToDn() + + for (const storedReq of storedReqs) { + const { handshakeAddress, recipientPub, sentReqID, timestamp } = storedReq + const currAddress = pubToHAddr[recipientPub] + + const lastReqID = pubToLastSentReqID[recipientPub] + const isStale = typeof lastReqID !== 'undefined' && lastReqID !== sentReqID + const aHandshakeWasEstablishedAtSomePoint = + typeof pubToIncoming[recipientPub] !== 'undefined' + + if (isStale && aHandshakeWasEstablishedAtSomePoint) { + // eslint-disable-next-line no-continue + continue + } + + finalSentReqs.push({ + id: sentReqID, + recipientAvatar: pubToAvatar[recipientPub] || null, + recipientChangedRequestAddress: + typeof currAddress && handshakeAddress !== currAddress, + recipientDisplayName: pubToDN[recipientPub] || null, + recipientPublicKey: recipientPub, + timestamp + }) + } + + currentReqs = finalSentReqs + + listeners.forEach(l => l(currentReqs)) +} + +let subbed = false + +/** + * Massages all of the more primitive data structures into a more manageable + * 'Chat' paradigm. + * @param {Listener} cb + * @returns {() => void} + */ +const onSentReqs = cb => { + listeners.add(cb) + + if (!subbed) { + Streams.onAddresses(react) + Streams.onStoredReqs(react) + Streams.onLastSentReqIDs(react) + Streams.onIncoming(react) + Streams.onAvatar(react) + Streams.onDisplayName(react) + + subbed = true + } + + cb(currentReqs) + + return () => { + listeners.delete(cb) + } +} + +module.exports = { + onSentReqs, + getCurrentSentReqs +} diff --git a/services/gunDB/contact-api/streams/addresses.js b/services/gunDB/contact-api/streams/addresses.js new file mode 100644 index 00000000..cc6d9343 --- /dev/null +++ b/services/gunDB/contact-api/streams/addresses.js @@ -0,0 +1,48 @@ +/** @format */ +const Key = require('../key') +/** + * @typedef {Record} Addresses + */ + +/** @type {Addresses} */ +const pubToAddress = {} + +/** @type {Set<() => void>} */ +const listeners = new Set() +const notify = () => listeners.forEach(l => l()) + +/** @type {Set} */ +const subbedPublicKeys = new Set() + +/** + * @param {() => void} cb + * @param {string=} pub + */ +const onAddresses = (cb, pub) => { + listeners.add(cb) + cb() + if (pub && subbedPublicKeys.add(pub)) { + require('../../Mediator') + .getGun() + .user(pub) + .get(Key.CURRENT_HANDSHAKE_ADDRESS) + .on(addr => { + if (typeof addr === 'string' || addr === null) { + pubToAddress[pub] = addr + } else { + pubToAddress[pub] = null + } + notify() + }) + } + return () => { + listeners.delete(cb) + } +} + +const getAddresses = () => pubToAddress + +module.exports = { + onAddresses, + getAddresses +} diff --git a/services/gunDB/contact-api/streams.js b/services/gunDB/contact-api/streams/index.js similarity index 86% rename from services/gunDB/contact-api/streams.js rename to services/gunDB/contact-api/streams/index.js index 8bedcf3f..248da93d 100644 --- a/services/gunDB/contact-api/streams.js +++ b/services/gunDB/contact-api/streams/index.js @@ -1,8 +1,8 @@ /** @format */ -const { INITIAL_MSG } = require('./actions') -const Key = require('./key') -const Schema = require('./schema') -const Utils = require('./utils') +const { INITIAL_MSG } = require('../actions') +const Key = require('../key') +const Schema = require('../schema') +const Utils = require('../utils') /** * @typedef {Record} Avatars * @typedef {(avatars: Avatars) => void} AvatarListener @@ -11,6 +11,8 @@ const Utils = require('./utils') /** @type {Avatars} */ const pubToAvatar = {} +const getPubToAvatar = () => pubToAvatar + /** @type {Set} */ const avatarListeners = new Set() @@ -29,7 +31,7 @@ const onAvatar = (cb, pub) => { avatarListeners.add(cb) cb(pubToAvatar) if (pub && pubsWithAvatarListeners.add(pub)) { - require('../Mediator') + require('../../Mediator') .getGun() .user(pub) .get(Key.PROFILE) @@ -56,6 +58,8 @@ const onAvatar = (cb, pub) => { /** @type {DisplayNames} */ const pubToDisplayName = {} +const getPubToDn = () => pubToDisplayName + /** @type {Set} */ const displayNameListeners = new Set() @@ -74,7 +78,7 @@ const onDisplayName = (cb, pub) => { displayNameListeners.add(cb) cb(pubToDisplayName) if (pub && pubsWithDisplayNameListeners.add(pub)) { - require('../Mediator') + require('../../Mediator') .getGun() .user(pub) .get(Key.PROFILE) @@ -94,7 +98,7 @@ const onDisplayName = (cb, pub) => { } /** - * @typedef {import('./schema').ChatMessage[]} Message + * @typedef {import('../schema').ChatMessage[]} Message * @typedef {Record} Incomings * @typedef {(incomings: Incomings) => void} IncomingsListener */ @@ -104,6 +108,8 @@ const onDisplayName = (cb, pub) => { */ const pubToIncoming = {} +const getPubToIncoming = () => pubToIncoming + /** @type {Set} */ const incomingsListeners = new Set() @@ -120,8 +126,8 @@ const pubFeedPairsWithIncomingListeners = new Set() const onIncoming = cb => { incomingsListeners.add(cb) - const user = require('../Mediator').getUser() - const SEA = require('../Mediator').mySEA + const user = require('../../Mediator').getUser() + const SEA = require('../../Mediator').mySEA user.get(Key.USER_TO_INCOMING).open(uti => { if (typeof uti !== 'object' || uti === null) { @@ -139,7 +145,7 @@ const onIncoming = cb => { user._.sea ) - require('../Mediator') + require('../../Mediator') .getGun() .user(pub) .get(Key.OUTGOINGS) @@ -206,7 +212,7 @@ const onIncoming = cb => { } /** - * @typedef {import('./schema').StoredRequest} StoredRequest + * @typedef {import('../schema').StoredRequest} StoredRequest * @typedef {(reqs: StoredRequest[]) => void} StoredRequestsListener */ @@ -229,7 +235,7 @@ const processStoredReqs = async () => { const ereqs = encryptedStoredReqs encryptedStoredReqs = [] const mySecret = await Utils.mySecret() - const SEA = require('../Mediator').mySEA + const SEA = require('../../Mediator').mySEA const finalReqs = await Utils.asyncMap(ereqs, async er => { /** @type {StoredRequest} */ const r = { @@ -248,14 +254,13 @@ const processStoredReqs = async () => { let subbed = false /** - * * @param {StoredRequestsListener} cb */ const onStoredReqs = cb => { storedRequestsListeners.add(cb) if (!subbed) { - require('../Mediator') + require('../../Mediator') .getUser() .get(Key.STORED_REQS) .open(d => { @@ -280,8 +285,15 @@ const onStoredReqs = cb => { module.exports = { onAvatar, + getPubToAvatar, onDisplayName, + getPubToDn, onIncoming, + getPubToIncoming, onStoredReqs, - getStoredReqs + getStoredReqs, + onAddresses: require('./addresses').onAddresses, + getAddresses: require('./addresses').getAddresses, + onLastSentReqIDs: require('./lastSentReqID').onLastSentReqIDs, + getSentReqIDs: require('./lastSentReqID').getSentReqIDs } diff --git a/services/gunDB/contact-api/streams/lastSentReqID.js b/services/gunDB/contact-api/streams/lastSentReqID.js new file mode 100644 index 00000000..0c552922 --- /dev/null +++ b/services/gunDB/contact-api/streams/lastSentReqID.js @@ -0,0 +1,50 @@ +/** @format */ +const Key = require('../key') + +/** @type {Record} */ +let pubToLastSentReqID = {} + +/** @type {Set<() => void>} */ +const listeners = new Set() +const notify = () => listeners.forEach(l => l()) + +let subbed = false + +/** + * @param {() => void} cb + */ +const onLastSentReqIDs = cb => { + listeners.add(cb) + cb() + + if (!subbed) { + require('../../Mediator') + .getUser() + .get(Key.USER_TO_LAST_REQUEST_SENT) + .open(data => { + if (typeof data === 'object' && data !== null) { + for (const [pub, id] of Object.entries(data)) { + if (typeof id === 'string' || id === null) { + pubToLastSentReqID[pub] = id + } + } + } else { + pubToLastSentReqID = {} + } + + notify() + }) + subbed = true + } + + return () => { + listeners.delete(cb) + } +} + +const getSentReqIDs = () => pubToLastSentReqID + +module.exports = { + onLastSentReqIDs, + getSentReqIDs +} From 81907545b08379fe2c75ad2ae8383fea740bc246 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 18:34:21 -0400 Subject: [PATCH 051/137] circular dependency node bug --- services/gunDB/contact-api/events/onReceivedReqs.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 849a3ec9..1136b19d 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -1,5 +1,4 @@ /** @format */ -const Events = require('./index') const Key = require('../key') const Schema = require('../schema') const Streams = require('../streams') @@ -101,7 +100,7 @@ const onReceivedReqs = cb => { listeners.add(cb) if (!subbed) { - Events.onCurrentHandshakeAddress(addr => { + require('./index').onCurrentHandshakeAddress(addr => { if (currentAddress !== addr) { currentAddress = addr currentNode = {} From 21c9b7f57780678c58261eb8e7cc1332eec741db Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 18:47:57 -0400 Subject: [PATCH 052/137] typo --- services/gunDB/contact-api/events/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 18ab7f01..45c03a0f 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -372,7 +372,7 @@ const processOutgoings = async () => { ) await Utils.asyncForEach( - Object.entries(out.messages), + Object.entries(currentOut.messages), async ([msgID, msg]) => { if (!Schema.isMessage(msg)) { // incomplete data From b0c615d4831d498bf81935b8c3f849ac68ab7402 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 18:51:04 -0400 Subject: [PATCH 053/137] typo --- services/gunDB/contact-api/events/onSentReqs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index 09057ef3..ad6decf1 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -56,7 +56,7 @@ const react = () => { id: sentReqID, recipientAvatar: pubToAvatar[recipientPub] || null, recipientChangedRequestAddress: - typeof currAddress && handshakeAddress !== currAddress, + typeof currAddress !== 'undefined' && handshakeAddress !== currAddress, recipientDisplayName: pubToDN[recipientPub] || null, recipientPublicKey: recipientPub, timestamp From 7306a52f8ee8de35862473bad4e8a9e6862bbbca Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 19:09:34 -0400 Subject: [PATCH 054/137] unencrypt incoming feed --- services/gunDB/contact-api/streams/index.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index 248da93d..85c7834d 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -134,17 +134,15 @@ const onIncoming = cb => { return } - Object.entries(uti).forEach(async ([pub, feed]) => { - if (typeof feed !== 'string') { + Object.entries(uti).forEach(async ([pub, encFeed]) => { + if (typeof encFeed !== 'string') { return } + const ourSecret = await SEA.secret(await Utils.pubToEpub(pub), user._.sea) + + const feed = await SEA.decrypt(encFeed, ourSecret) if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { - const ourSecret = await SEA.secret( - await Utils.pubToEpub(pub), - user._.sea - ) - require('../../Mediator') .getGun() .user(pub) From f96114b7fcd648f25fb0350ade1334dd11ce58ac Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 19:11:50 -0400 Subject: [PATCH 055/137] decrypt with correct secret --- services/gunDB/contact-api/streams/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index 85c7834d..ce5502d3 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -139,8 +139,9 @@ const onIncoming = cb => { return } const ourSecret = await SEA.secret(await Utils.pubToEpub(pub), user._.sea) + const mySecret = await Utils.mySecret() - const feed = await SEA.decrypt(encFeed, ourSecret) + const feed = await SEA.decrypt(encFeed, mySecret) if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { require('../../Mediator') From 3d685eb7142d633d1306bc036891e6eec8a74f93 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 19:19:02 -0400 Subject: [PATCH 056/137] log --- services/gunDB/contact-api/streams/index.js | 147 +++++++++++--------- 1 file changed, 80 insertions(+), 67 deletions(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index ce5502d3..65fdbe5a 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -120,6 +120,8 @@ const notifyIncomingsListeners = () => { /** @type {Set} */ const pubFeedPairsWithIncomingListeners = new Set() +let subbed = false + /** * @param {IncomingsListener} cb */ @@ -129,81 +131,92 @@ const onIncoming = cb => { const user = require('../../Mediator').getUser() const SEA = require('../../Mediator').mySEA - user.get(Key.USER_TO_INCOMING).open(uti => { - if (typeof uti !== 'object' || uti === null) { - return - } - - Object.entries(uti).forEach(async ([pub, encFeed]) => { - if (typeof encFeed !== 'string') { + if (!subbed) { + user.get(Key.USER_TO_INCOMING).open(uti => { + if (typeof uti !== 'object' || uti === null) { return } - const ourSecret = await SEA.secret(await Utils.pubToEpub(pub), user._.sea) - const mySecret = await Utils.mySecret() - const feed = await SEA.decrypt(encFeed, mySecret) + Object.entries(uti).forEach(async ([pub, encFeed]) => { + if (typeof encFeed !== 'string') { + return + } + const ourSecret = await SEA.secret( + await Utils.pubToEpub(pub), + user._.sea + ) + const mySecret = await Utils.mySecret() - if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { - require('../../Mediator') - .getGun() - .user(pub) - .get(Key.OUTGOINGS) - .get(feed) - .open(async data => { - if (data === null) { - pubToIncoming[pub] = null - return - } + const feed = await SEA.decrypt(encFeed, mySecret) - if (typeof data !== 'object') { - return - } - - if (typeof data.with !== 'string') { - return - } - - if (typeof data.messages !== 'object') { - return - } - - if (data.messages === null) { - return - } - - const msgs = /** @type {[string, Schema.Message][]} */ (Object.entries( - data.messages - ).filter(([_, msg]) => Schema.isMessage(msg))) - - // eslint-disable-next-line require-atomic-updates - pubToIncoming[pub] = await Utils.asyncMap( - msgs, - async ([msgid, msg]) => { - let decryptedBody = '' - - if (msg.body === INITIAL_MSG) { - decryptedBody = INITIAL_MSG - } else { - decryptedBody = await SEA.decrypt(msg.body, ourSecret) - } - - /** @type {Schema.ChatMessage} */ - const finalMsg = { - body: decryptedBody, - id: msgid, - outgoing: false, - timestamp: msg.timestamp - } - - return finalMsg + if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { + require('../../Mediator') + .getGun() + .user(pub) + .get(Key.OUTGOINGS) + .get(feed) + .open(async data => { + if (data === null) { + pubToIncoming[pub] = null + return } - ) - notifyIncomingsListeners() - }) - } + if (typeof data !== 'object') { + return + } + + if (typeof data.with !== 'string') { + return + } + + if (typeof data.messages !== 'object') { + return + } + + if (data.messages === null) { + return + } + + const msgs = /** @type {[string, Schema.Message][]} */ (Object.entries( + data.messages + ).filter(([_, msg]) => Schema.isMessage(msg))) + + // eslint-disable-next-line require-atomic-updates + pubToIncoming[pub] = await Utils.asyncMap( + msgs, + async ([msgid, msg]) => { + let decryptedBody = '' + + if (msg.body === INITIAL_MSG) { + decryptedBody = INITIAL_MSG + } else { + decryptedBody = await SEA.decrypt(msg.body, ourSecret) + } + + /** @type {Schema.ChatMessage} */ + const finalMsg = { + body: decryptedBody, + id: msgid, + outgoing: false, + timestamp: msg.timestamp + } + + return finalMsg + } + ) + + console.log('--------------------------------') + console.log(`msgs: ${JSON.stringify(msgs)}`) + console.log('--------------------------------') + + notifyIncomingsListeners() + }) + } + }) }) - }) + + subbed = true + } return () => { incomingsListeners.delete(cb) From 5e6142fd1b64e2ffcc8bbafb39a55b1d91c3f034 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 19:21:32 -0400 Subject: [PATCH 057/137] typos --- services/gunDB/contact-api/streams/index.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index 65fdbe5a..08d0d120 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -205,10 +205,6 @@ const onIncoming = cb => { } ) - console.log('--------------------------------') - console.log(`msgs: ${JSON.stringify(msgs)}`) - console.log('--------------------------------') - notifyIncomingsListeners() }) } @@ -263,7 +259,7 @@ const processStoredReqs = async () => { storedRequestsListeners.forEach(l => l(currentStoredReqs)) } -let subbed = false +let storedReqsSubbed = false /** * @param {StoredRequestsListener} cb @@ -271,7 +267,7 @@ let subbed = false const onStoredReqs = cb => { storedRequestsListeners.add(cb) - if (!subbed) { + if (!storedReqsSubbed) { require('../../Mediator') .getUser() .get(Key.STORED_REQS) @@ -285,7 +281,7 @@ const onStoredReqs = cb => { processStoredReqs() }) - subbed = true + storedReqsSubbed = true } cb(currentStoredReqs) From 676853351594ba83fb5eaaefce434eba25be5a4f Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 19:38:19 -0400 Subject: [PATCH 058/137] pubtoincoming fixes --- services/gunDB/contact-api/streams/index.js | 126 +-------------- .../contact-api/streams/pubToIncoming.js | 144 ++++++++++++++++++ 2 files changed, 146 insertions(+), 124 deletions(-) create mode 100644 services/gunDB/contact-api/streams/pubToIncoming.js diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index 08d0d120..b620cd10 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -97,128 +97,6 @@ const onDisplayName = (cb, pub) => { } } -/** - * @typedef {import('../schema').ChatMessage[]} Message - * @typedef {Record} Incomings - * @typedef {(incomings: Incomings) => void} IncomingsListener - */ - -/** - * @type {Incomings} - */ -const pubToIncoming = {} - -const getPubToIncoming = () => pubToIncoming - -/** @type {Set} */ -const incomingsListeners = new Set() - -const notifyIncomingsListeners = () => { - incomingsListeners.forEach(l => l(pubToIncoming)) -} - -/** @type {Set} */ -const pubFeedPairsWithIncomingListeners = new Set() - -let subbed = false - -/** - * @param {IncomingsListener} cb - */ -const onIncoming = cb => { - incomingsListeners.add(cb) - - const user = require('../../Mediator').getUser() - const SEA = require('../../Mediator').mySEA - - if (!subbed) { - user.get(Key.USER_TO_INCOMING).open(uti => { - if (typeof uti !== 'object' || uti === null) { - return - } - - Object.entries(uti).forEach(async ([pub, encFeed]) => { - if (typeof encFeed !== 'string') { - return - } - const ourSecret = await SEA.secret( - await Utils.pubToEpub(pub), - user._.sea - ) - const mySecret = await Utils.mySecret() - - const feed = await SEA.decrypt(encFeed, mySecret) - - if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { - require('../../Mediator') - .getGun() - .user(pub) - .get(Key.OUTGOINGS) - .get(feed) - .open(async data => { - if (data === null) { - pubToIncoming[pub] = null - return - } - - if (typeof data !== 'object') { - return - } - - if (typeof data.with !== 'string') { - return - } - - if (typeof data.messages !== 'object') { - return - } - - if (data.messages === null) { - return - } - - const msgs = /** @type {[string, Schema.Message][]} */ (Object.entries( - data.messages - ).filter(([_, msg]) => Schema.isMessage(msg))) - - // eslint-disable-next-line require-atomic-updates - pubToIncoming[pub] = await Utils.asyncMap( - msgs, - async ([msgid, msg]) => { - let decryptedBody = '' - - if (msg.body === INITIAL_MSG) { - decryptedBody = INITIAL_MSG - } else { - decryptedBody = await SEA.decrypt(msg.body, ourSecret) - } - - /** @type {Schema.ChatMessage} */ - const finalMsg = { - body: decryptedBody, - id: msgid, - outgoing: false, - timestamp: msg.timestamp - } - - return finalMsg - } - ) - - notifyIncomingsListeners() - }) - } - }) - }) - - subbed = true - } - - return () => { - incomingsListeners.delete(cb) - } -} - /** * @typedef {import('../schema').StoredRequest} StoredRequest * @typedef {(reqs: StoredRequest[]) => void} StoredRequestsListener @@ -296,8 +174,8 @@ module.exports = { getPubToAvatar, onDisplayName, getPubToDn, - onIncoming, - getPubToIncoming, + onIncoming: require('./pubToIncoming').onIncoming, + getPubToIncoming: require('./pubToIncoming').getPubToIncoming, onStoredReqs, getStoredReqs, onAddresses: require('./addresses').onAddresses, diff --git a/services/gunDB/contact-api/streams/pubToIncoming.js b/services/gunDB/contact-api/streams/pubToIncoming.js new file mode 100644 index 00000000..36eb3dff --- /dev/null +++ b/services/gunDB/contact-api/streams/pubToIncoming.js @@ -0,0 +1,144 @@ +/** @format */ +const { INITIAL_MSG } = require('../actions') +const Schema = require('../schema') +const Key = require('../key') +const Utils = require('../utils') + +/** + * @typedef {import('../schema').ChatMessage} Message + * @typedef {Record} Incomings + * @typedef {(incomings: Incomings) => void} IncomingsListener + */ + +/** + * @type {Incomings} + */ +const currentPubToIncoming = {} + +const getPubToIncoming = () => currentPubToIncoming + +/** @type {Set} */ +const incomingsListeners = new Set() + +const notifyIncomingsListeners = () => { + incomingsListeners.forEach(l => l(currentPubToIncoming)) +} + +/** @type {Set} */ +const pubFeedPairsWithIncomingListeners = new Set() + +let subbed = false + +/** + * @param {IncomingsListener} cb + */ +const onIncoming = cb => { + incomingsListeners.add(cb) + + const user = require('../../Mediator').getUser() + const SEA = require('../../Mediator').mySEA + + if (!subbed) { + user.get(Key.USER_TO_INCOMING).open(uti => { + if (typeof uti !== 'object' || uti === null) { + return + } + + Object.entries(uti).forEach(async ([pub, encFeed]) => { + if (typeof encFeed !== 'string') { + return + } + const ourSecret = await SEA.secret( + await Utils.pubToEpub(pub), + user._.sea + ) + const mySecret = await Utils.mySecret() + + const feed = await SEA.decrypt(encFeed, mySecret) + + if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { + require('../../Mediator') + .getGun() + .user(pub) + .get(Key.OUTGOINGS) + .get(feed) + .open(async data => { + if (data === null) { + currentPubToIncoming[pub] = null + return + } + + if (typeof data !== 'object') { + return + } + + if (typeof data.with !== 'string') { + return + } + + if (typeof data.messages !== 'object') { + return + } + + if (data.messages === null) { + return + } + + if (!Array.isArray(currentPubToIncoming[pub])) { + currentPubToIncoming[pub] = [ + { + body: INITIAL_MSG, + // hack one year + timestamp: Date.now() - 31556952, + id: Math.random().toString(), + outgoing: false + } + ] + } + + const msgs = /** @type {[string, Schema.Message][]} */ (Object.entries( + data.messages + ).filter(([_, msg]) => Schema.isMessage(msg))) + + // eslint-disable-next-line require-atomic-updates + currentPubToIncoming[pub] = await Utils.asyncMap( + msgs, + async ([msgid, msg]) => { + let decryptedBody = '' + + if (msg.body === INITIAL_MSG) { + decryptedBody = INITIAL_MSG + } else { + decryptedBody = await SEA.decrypt(msg.body, ourSecret) + } + + /** @type {Schema.ChatMessage} */ + const finalMsg = { + body: decryptedBody, + id: msgid, + outgoing: false, + timestamp: msg.timestamp + } + + return finalMsg + } + ) + + notifyIncomingsListeners() + }) + } + }) + }) + + subbed = true + } + + return () => { + incomingsListeners.delete(cb) + } +} + +module.exports = { + onIncoming, + getPubToIncoming +} From d4ed5e03556e197d0c7a70713b506815065728d0 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 19:42:11 -0400 Subject: [PATCH 059/137] use getter --- services/gunDB/contact-api/events/onReceivedReqs.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 1136b19d..152f272b 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -29,9 +29,6 @@ let pubToAvatar = {} /** @type {Streams.DisplayNames} */ let pubToDn = {} -/** @type {Streams.Incomings} */ -let pubToIncoming = {} - /** @type {SimpleReceivedRequest[]} */ let currentReqs = [] @@ -44,6 +41,7 @@ let currentNode = {} const react = () => { /** @type {SimpleReceivedRequest[]} */ const finalReqs = [] + const pubToIncoming = Streams.getPubToIncoming() for (const [id, req] of Object.entries(currentNode)) { const notAccepted = typeof pubToIncoming[req.from] === 'undefined' From 6b298763afc2ec8418bb717548340cbafdeee7c1 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 20:16:07 -0400 Subject: [PATCH 060/137] notify on sub --- services/gunDB/contact-api/streams/pubToIncoming.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/gunDB/contact-api/streams/pubToIncoming.js b/services/gunDB/contact-api/streams/pubToIncoming.js index 36eb3dff..3d531a32 100644 --- a/services/gunDB/contact-api/streams/pubToIncoming.js +++ b/services/gunDB/contact-api/streams/pubToIncoming.js @@ -133,6 +133,8 @@ const onIncoming = cb => { subbed = true } + cb(getPubToIncoming()) + return () => { incomingsListeners.delete(cb) } From 2d1e328cfb234091a5ee96c3c3070ee9fa113a51 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 20:17:28 -0400 Subject: [PATCH 061/137] unused var --- services/gunDB/contact-api/streams/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index b620cd10..b3df5683 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -1,5 +1,4 @@ /** @format */ -const { INITIAL_MSG } = require('../actions') const Key = require('../key') const Schema = require('../schema') const Utils = require('../utils') From 4a03cde744986577e20e5c026c3dc561b4186c3c Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 21:00:08 -0400 Subject: [PATCH 062/137] dont delete encrypted outgoings --- services/gunDB/contact-api/events/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 45c03a0f..a8d24881 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -333,7 +333,6 @@ let lastUserWithListener = null const processOutgoings = async () => { const outs = encryptedOutgoings - encryptedOutgoings = {} const mySecret = await Utils.mySecret() const SEA = require('../../Mediator').mySEA const user = require('../../Mediator').getUser() From 905cdd6f003cdc28374ce22d4a30d99f37cc294f Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 21:09:15 -0400 Subject: [PATCH 063/137] better handling of outgoings --- services/gunDB/contact-api/events/index.js | 50 +++++++++------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index a8d24881..296a98b1 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -342,18 +342,21 @@ const processOutgoings = async () => { return } + const withPub = await SEA.decrypt(out.with, mySecret) + const ourSecret = await SEA.secret( + await Utils.pubToEpub(withPub), + user._.sea + ) + if (!Schema.isPartialOutgoing(out)) { // incomplete data return } if (typeof currentOutgoings[id] === 'undefined') { - // We disable this rule because we are awaiting the result of the whole - // for each AND each callback looks only at one single ID - // eslint-disable-next-line require-atomic-updates currentOutgoings[id] = { messages: {}, - with: await SEA.decrypt(out.with, mySecret) + with: withPub } } @@ -362,30 +365,22 @@ const processOutgoings = async () => { return } - // on each open() only "messages" should change, not "with" - // also messages are non-nullable and non-editable - - const ourSecret = await SEA.secret( - await Utils.pubToEpub(currentOut.with), - user._.sea - ) - await Utils.asyncForEach( - Object.entries(currentOut.messages), + Object.entries(currentOut.messages || {}), async ([msgID, msg]) => { if (!Schema.isMessage(msg)) { // incomplete data return } + let decryptedBody = '' + if (msg.body === Actions.INITIAL_MSG) { + decryptedBody = Actions.INITIAL_MSG + } else { + decryptedBody = await SEA.decrypt(msg.body, ourSecret) + } + if (!currentOut.messages[msgID]) { - let decryptedBody = '' - if (msg.body === Actions.INITIAL_MSG) { - decryptedBody = Actions.INITIAL_MSG - } else { - decryptedBody = await SEA.decrypt(msg.body, ourSecret) - } // each callback only looks at one particular msgID - // eslint-disable-next-line require-atomic-updates currentOut.messages[msgID] = { body: decryptedBody, timestamp: msg.timestamp @@ -438,9 +433,6 @@ let pubToAvatar = {} /** @type {Streams.DisplayNames} */ let pubToDn = {} -/** @type {Streams.Incomings} */ -let pubToIncoming = {} - /** * @typedef {(chats: Chat[]) => void} ChatsListener */ @@ -472,7 +464,7 @@ const processChats = () => { timestamp: m.timestamp })) - const incoming = pubToIncoming[out.with] + const incoming = Streams.getPubToIncoming()[out.with] if (Array.isArray(incoming)) { msgs = [...msgs, ...incoming] @@ -502,7 +494,10 @@ const processChats = () => { currentChats = chats .filter(c => c.messages.length > 0) - .filter(c => typeof pubToIncoming[c.recipientPublicKey] !== 'undefined') + .filter( + c => + typeof Streams.getPubToIncoming()[c.recipientPublicKey] !== 'undefined' + ) notifyChatsListeners() } @@ -529,10 +524,7 @@ const onChats = cb => { pubToDn = ptd processChats() }) - Streams.onIncoming(pti => { - pubToIncoming = pti - processChats() - }) + Streams.onIncoming(processChats) return () => { chatsListeners.delete(cb) From eea9b0dac828badf785e63646b6714ce78c7ccb5 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 21:38:34 -0400 Subject: [PATCH 064/137] different handling of outgoings --- services/gunDB/contact-api/events/index.js | 132 +++++++++++---------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 296a98b1..2d792616 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -331,67 +331,6 @@ const notifyOutgoingsListeners = () => { /** @type {UserGUNNode|null} */ let lastUserWithListener = null -const processOutgoings = async () => { - const outs = encryptedOutgoings - const mySecret = await Utils.mySecret() - const SEA = require('../../Mediator').mySEA - const user = require('../../Mediator').getUser() - await Utils.asyncForEach(Object.entries(outs), async ([id, out]) => { - if (out === null) { - currentOutgoings[id] = null - return - } - - const withPub = await SEA.decrypt(out.with, mySecret) - const ourSecret = await SEA.secret( - await Utils.pubToEpub(withPub), - user._.sea - ) - - if (!Schema.isPartialOutgoing(out)) { - // incomplete data - return - } - - if (typeof currentOutgoings[id] === 'undefined') { - currentOutgoings[id] = { - messages: {}, - with: withPub - } - } - - const currentOut = currentOutgoings[id] - if (currentOut === null) { - return - } - - await Utils.asyncForEach( - Object.entries(currentOut.messages || {}), - async ([msgID, msg]) => { - if (!Schema.isMessage(msg)) { - // incomplete data - return - } - let decryptedBody = '' - if (msg.body === Actions.INITIAL_MSG) { - decryptedBody = Actions.INITIAL_MSG - } else { - decryptedBody = await SEA.decrypt(msg.body, ourSecret) - } - - if (!currentOut.messages[msgID]) { - // each callback only looks at one particular msgID - currentOut.messages[msgID] = { - body: decryptedBody, - timestamp: msg.timestamp - } - } - } - ) - }) - notifyOutgoingsListeners() -} - /** * @param {OutgoingsListener} cb * @returns {() => void} @@ -408,14 +347,77 @@ const onOutgoing = cb => { encryptedOutgoings = {} lastUserWithListener = currentUser - currentUser.get(Key.OUTGOINGS).open(data => { + currentUser.get(Key.OUTGOINGS).open(async data => { // deactivate this listener when user changes if (lastUserWithListener !== require('../../Mediator').getUser()) { return } - // @ts-ignore Let's skip schema checks for perf reasons - encryptedOutgoings = data - processOutgoings() + + if (typeof data !== 'object' || data === null) { + currentOutgoings = {} + notifyOutgoingsListeners() + return + } + + /** @type {Record} */ + const newOuts = {} + + const SEA = require('../../Mediator').mySEA + const mySecret = await Utils.mySecret() + + await Utils.asyncForEach(Object.entries(data), async ([id, out]) => { + if (typeof out !== 'object') { + return + } + + if (out === null) { + // @ts-ignore + newOuts[id] = null + return + } + + const { with: encPub, messages } = out + + if (typeof encPub !== 'string') { + return + } + + const pub = await SEA.decrypt(encPub, mySecret) + + if (!newOuts[id]) { + newOuts[id] = { + with: pub, + messages: {} + } + } + + const ourSec = await SEA.secret( + await Utils.pubToEpub(pub), + require('../../Mediator').getUser()._.sea + ) + + if (typeof messages === 'object' && messages !== null) { + await Utils.asyncForEach( + Object.entries(messages), + async ([mid, msg]) => { + if (typeof msg === 'object' && msg !== null) { + if ( + typeof msg.body === 'string' && + typeof msg.timestamp === 'number' + ) { + newOuts[id].messages[mid] = { + body: await SEA.decrypt(msg.body, ourSec), + timestamp: msg.timestamp + } + } + } + } + ) + } + }) + + currentOutgoings = newOuts + notifyOutgoingsListeners() }) } From 89e07ac19f67b1a733f2959f39f419658fd978bb Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 22:32:09 -0400 Subject: [PATCH 065/137] use getters --- .../contact-api/events/onReceivedReqs.js | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 152f272b..659a8300 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -23,12 +23,6 @@ const Streams = require('../streams') const listeners = new Set() -/** @type {Streams.Avatars} */ -let pubToAvatar = {} - -/** @type {Streams.DisplayNames} */ -let pubToDn = {} - /** @type {SimpleReceivedRequest[]} */ let currentReqs = [] @@ -42,6 +36,8 @@ const react = () => { /** @type {SimpleReceivedRequest[]} */ const finalReqs = [] const pubToIncoming = Streams.getPubToIncoming() + const pubToAvatar = Streams.getPubToAvatar() + const pubToDn = Streams.getPubToDn() for (const [id, req] of Object.entries(currentNode)) { const notAccepted = typeof pubToIncoming[req.from] === 'undefined' @@ -115,18 +111,9 @@ const onReceivedReqs = cb => { } }, require('../../Mediator').getUser()) - Streams.onAvatar(pta => { - pubToAvatar = pta - react() - }) - Streams.onDisplayName(ptd => { - pubToDn = ptd - react() - }) - Streams.onIncoming(pti => { - pubToIncoming = pti - react() - }) + Streams.onAvatar(react) + Streams.onDisplayName(react) + Streams.onIncoming(react) subbed = true } From a12e31f72a1a62a26e2db9905f452db6d3c1aad2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 22:47:38 -0400 Subject: [PATCH 066/137] t --- services/gunDB/Mediator/index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index d01b9ea7..d7580ed2 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -4,6 +4,8 @@ const Gun = require('gun') // @ts-ignore require('gun/lib/open') +// @ts-ignore +require('gun/lib/load') const debounce = require('lodash/debounce') const once = require('lodash/once') const Encryption = require('../../../utils/encryptionStore') @@ -196,6 +198,12 @@ const authenticate = async (alias, pass) => { API.Jobs.onAcceptedRequests(user, mySEA) API.Jobs.onOrders(user, gun, mySEA) + setInterval(() => { + user.get('outgoings').load(data => { + console.log(JSON.stringify(data, null, 4)) + }) + }, 1000) + const mySec = await mySEA.secret(user._.sea.epub, user._.sea) if (typeof mySec !== 'string') { throw new TypeError('mySec not an string') From d6df459070fd6e4f51b0e819fe428ffc6266cef2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 23:27:36 -0400 Subject: [PATCH 067/137] remove debug code --- services/gunDB/Mediator/index.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index d7580ed2..d01b9ea7 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -4,8 +4,6 @@ const Gun = require('gun') // @ts-ignore require('gun/lib/open') -// @ts-ignore -require('gun/lib/load') const debounce = require('lodash/debounce') const once = require('lodash/once') const Encryption = require('../../../utils/encryptionStore') @@ -198,12 +196,6 @@ const authenticate = async (alias, pass) => { API.Jobs.onAcceptedRequests(user, mySEA) API.Jobs.onOrders(user, gun, mySEA) - setInterval(() => { - user.get('outgoings').load(data => { - console.log(JSON.stringify(data, null, 4)) - }) - }, 1000) - const mySec = await mySEA.secret(user._.sea.epub, user._.sea) if (typeof mySec !== 'string') { throw new TypeError('mySec not an string') From bdf23e78e4877f4170c5c220bbfda7b60fdfb093 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 23:29:56 -0400 Subject: [PATCH 068/137] logging --- services/gunDB/contact-api/events/onSentReqs.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index ad6decf1..78c9abdf 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -63,6 +63,13 @@ const react = () => { }) } + if (finalSentReqs.length > 0) { + console.log('-------------------------') + console.log('pub to incoming') + console.log(pubToIncoming) + console.log('-------------------------') + } + currentReqs = finalSentReqs listeners.forEach(l => l(currentReqs)) From b108027ba5578ba5905e28be6abf0dcac75a4422 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 29 Jan 2020 23:34:25 -0400 Subject: [PATCH 069/137] dont decrypt initial msg --- services/gunDB/contact-api/events/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 2d792616..cec931f4 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -406,7 +406,10 @@ const onOutgoing = cb => { typeof msg.timestamp === 'number' ) { newOuts[id].messages[mid] = { - body: await SEA.decrypt(msg.body, ourSec), + body: + msg.body === Actions.INITIAL_MSG + ? Actions.INITIAL_MSG + : await SEA.decrypt(msg.body, ourSec), timestamp: msg.timestamp } } From 806ff0bab7a2159dcb3afe13b7c82932dfb418c8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 07:22:01 -0400 Subject: [PATCH 070/137] delete stored req on successful connect --- .../contact-api/jobs/onAcceptedRequests.js | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/services/gunDB/contact-api/jobs/onAcceptedRequests.js b/services/gunDB/contact-api/jobs/onAcceptedRequests.js index 34888ca9..3f6efff4 100644 --- a/services/gunDB/contact-api/jobs/onAcceptedRequests.js +++ b/services/gunDB/contact-api/jobs/onAcceptedRequests.js @@ -33,7 +33,7 @@ const onAcceptedRequests = async (user, SEA) => { user .get(Key.STORED_REQS) .map() - .once(async storedReq => { + .once(async (storedReq, id) => { try { if (!Schema.isStoredRequest(storedReq)) { throw new TypeError('Stored request not an StoredRequest') @@ -123,10 +123,31 @@ const onAcceptedRequests = async (user, SEA) => { mySecret ) - user - .get(Key.USER_TO_INCOMING) - .get(recipientPub) - .put(encryptedForMeIncomingID) + await new Promise((res, rej) => { + user + .get(Key.USER_TO_INCOMING) + .get(recipientPub) + .put(encryptedForMeIncomingID, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + + await new Promise((res, rej) => { + user + .get(Key.STORED_REQS) + .get(id) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) // ensure this listeners gets called at least once res() From e90c3b20668e3bbfb9d9acdbd062f68a9a5a3e04 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 07:22:11 -0400 Subject: [PATCH 071/137] better filtering --- services/gunDB/contact-api/events/onSentReqs.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index 78c9abdf..272bddcf 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -44,10 +44,9 @@ const react = () => { const lastReqID = pubToLastSentReqID[recipientPub] const isStale = typeof lastReqID !== 'undefined' && lastReqID !== sentReqID - const aHandshakeWasEstablishedAtSomePoint = - typeof pubToIncoming[recipientPub] !== 'undefined' + const isConnected = typeof pubToIncoming[recipientPub] !== 'undefined' - if (isStale && aHandshakeWasEstablishedAtSomePoint) { + if (isStale || isConnected) { // eslint-disable-next-line no-continue continue } From 98bb44042ef035fa8526ec5799c8bcf5fcf20eb5 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 07:28:13 -0400 Subject: [PATCH 072/137] log --- services/gunDB/contact-api/events/onSentReqs.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index 272bddcf..cba5b1b2 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -38,6 +38,10 @@ const react = () => { const pubToAvatar = Streams.getPubToAvatar() const pubToDN = Streams.getPubToDn() + console.log( + `pubToLastSentREqID: ${JSON.stringify(pubToLastSentReqID, null, 4)}` + ) + for (const storedReq of storedReqs) { const { handshakeAddress, recipientPub, sentReqID, timestamp } = storedReq const currAddress = pubToHAddr[recipientPub] From 59a238b3c79b10422ee78e8bbf0c8024a70a7660 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 07:48:13 -0400 Subject: [PATCH 073/137] use getters --- services/gunDB/contact-api/events/index.js | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index cec931f4..1330f0af 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -432,12 +432,6 @@ const onOutgoing = cb => { /** @type {Outgoings} */ let outgoings = {} -/** @type {Streams.Avatars} */ -let pubToAvatar = {} - -/** @type {Streams.DisplayNames} */ -let pubToDn = {} - /** * @typedef {(chats: Chat[]) => void} ChatsListener */ @@ -453,6 +447,8 @@ const notifyChatsListeners = () => { } const processChats = () => { + const pubToAvatar = Streams.getPubToAvatar() + const pubToDn = Streams.getPubToDn() const existingOutgoings = /** @type {[string, Outgoing][]} */ (Object.entries( outgoings ).filter(([_, o]) => o !== null)) @@ -521,14 +517,8 @@ const onChats = cb => { processChats() }) - Streams.onAvatar(pta => { - pubToAvatar = pta - processChats() - }) - Streams.onDisplayName(ptd => { - pubToDn = ptd - processChats() - }) + Streams.onAvatar(processChats) + Streams.onDisplayName(processChats) Streams.onIncoming(processChats) return () => { From 012264d3ba005bae6695b191362aabc0abdec692 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 07:55:01 -0400 Subject: [PATCH 074/137] unused code --- services/gunDB/contact-api/events/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 1330f0af..a9fc0774 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -316,11 +316,6 @@ const onIncomingMessages = (cb, userPK, incomingFeedID, gun, user, SEA) => { */ let currentOutgoings = {} -/** - * @type {Outgoings} - */ -let encryptedOutgoings = {} - /** @type {Set} */ const outgoingsListeners = new Set() @@ -344,7 +339,6 @@ const onOutgoing = cb => { if (lastUserWithListener !== currentUser) { // in case user changed gun alias currentOutgoings = {} - encryptedOutgoings = {} lastUserWithListener = currentUser currentUser.get(Key.OUTGOINGS).open(async data => { From e2a1b85de955c87795a5479b10d31565f1714112 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 07:59:03 -0400 Subject: [PATCH 075/137] logging --- services/gunDB/contact-api/events/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index a9fc0774..b0ea1927 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -465,6 +465,11 @@ const processChats = () => { msgs = [...msgs, ...incoming] } + console.log('-------------------------------------------------') + console.log(`msgs before filtering`) + console.log(msgs) + console.log('-------------------------------------------------') + /** @type {Chat} */ const chat = { recipientPublicKey: out.with, From a188639ff0a68c4527730fda6000574ff97f908b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 08:32:13 -0400 Subject: [PATCH 076/137] refresh avatar/display names --- services/gunDB/contact-api/events/onReceivedReqs.js | 9 +++++++++ services/gunDB/contact-api/events/onSentReqs.js | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 659a8300..7f7b1f8f 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -43,6 +43,15 @@ const react = () => { const notAccepted = typeof pubToIncoming[req.from] === 'undefined' if (notAccepted) { + if (typeof pubToAvatar[req.from] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onAvatar(() => {}, req.from) + } + if (typeof pubToDn[req.from] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onDisplayName(() => {}, req.from) + } + finalReqs.push({ id, requestorAvatar: pubToAvatar[req.from] || null, diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index cba5b1b2..947fa12b 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -55,6 +55,15 @@ const react = () => { continue } + if (typeof pubToAvatar[recipientPub] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onAvatar(() => {}, recipientPub) + } + if (typeof pubToDN[recipientPub] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onDisplayName(() => {}, recipientPub) + } + finalSentReqs.push({ id: sentReqID, recipientAvatar: pubToAvatar[recipientPub] || null, From c577880aace496f1a6381d0bbd7016e4492a6368 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 30 Jan 2020 08:42:54 -0400 Subject: [PATCH 077/137] no auto send --- services/gunDB/contact-api/actions.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 4ecdfe7f..bcf416bc 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -407,6 +407,10 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { throw new TypeError('recipientPublicKey is an string of length 0') } + if (recipientPublicKey === user.is.pub) { + throw new Error('Do not send a request to yourself') + } + console.log('sendHR() -> before recipientEpub') /** @type {string} */ From 6e2101c74cdf17310bcecf8ce3ad52f2b8455a47 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 1 Feb 2020 15:22:23 -0400 Subject: [PATCH 078/137] typings --- services/gunDB/Mediator/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index d01b9ea7..1cf4a74e 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -131,6 +131,7 @@ const Event = require('../event-constants') * @typedef {object} SimpleSocket * @prop {(eventName: string, data: Emission) => void} emit * @prop {(eventName: string, handler: (data: any) => void) => void} on + * @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake */ /* eslint-disable init-declarations */ @@ -342,16 +343,18 @@ class Mediator { */ on: (eventName, cb) => { const deviceId = socket.handshake.query['x-shockwallet-device-id'] - socket.on(eventName, data => { + socket.on(eventName, _data => { try { if (Encryption.isNonEncrypted(eventName)) { return cb(data) } - if (!data) { - return cb(data) + if (!_data) { + return cb(_data) } + let data = _data + if (!deviceId) { const error = { field: 'deviceId', @@ -396,6 +399,7 @@ class Mediator { } }) }, + /** @type {SimpleSocket['emit']} */ emit: (eventName, data) => { try { if (Encryption.isNonEncrypted(eventName)) { From 6213ebdd2baa7390ad9f592f914223bfc7d60062 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 1 Feb 2020 15:49:29 -0400 Subject: [PATCH 079/137] yarn.lock --- yarn.lock | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9ae14013..62854ae0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -880,7 +880,7 @@ ascli@~1: colour "~0.7.1" optjs "~3.2.2" -asn1@^0.2.4, asn1@~0.2.3: +asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== @@ -4348,13 +4348,6 @@ node-pre-gyp@^0.13.0: semver "^5.3.0" tar "^4" -node-rsa@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.0.7.tgz#85b7a6d6fa8ee624be6402a6b41be49272d58055" - integrity sha512-idwRXma6scFufZmbaKkHpJoLL93yynRefP6yur13wZ5i9FR35ex451KCoF2OORDeJanyRVahmjjiwmUlCnTqJA== - dependencies: - asn1 "^0.2.4" - nodemon@^1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.19.3.tgz#db71b3e62aef2a8e1283a9fa00164237356102c0" From 1f0ca74779a2fc1d3852e836ffca0be553a77afa Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Mon, 3 Feb 2020 22:19:15 -0400 Subject: [PATCH 080/137] reference eror --- services/gunDB/Mediator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 1cf4a74e..7e598a2f 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -346,7 +346,7 @@ class Mediator { socket.on(eventName, _data => { try { if (Encryption.isNonEncrypted(eventName)) { - return cb(data) + return cb(_data) } if (!_data) { From 92a7ef089425f87fa6d3fae507318de2784698c7 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 00:09:09 -0400 Subject: [PATCH 081/137] refined outgoing handling --- services/gunDB/contact-api/events/index.js | 159 +++++++++++---------- 1 file changed, 81 insertions(+), 78 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index b0ea1927..f7aeebb5 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -323,8 +323,7 @@ const notifyOutgoingsListeners = () => { outgoingsListeners.forEach(l => l(currentOutgoings)) } -/** @type {UserGUNNode|null} */ -let lastUserWithListener = null +let outSubbed = false /** * @param {OutgoingsListener} cb @@ -334,88 +333,92 @@ const onOutgoing = cb => { outgoingsListeners.add(cb) cb(currentOutgoings) - const currentUser = require('../../Mediator').getUser() - - if (lastUserWithListener !== currentUser) { - // in case user changed gun alias - currentOutgoings = {} - lastUserWithListener = currentUser - - currentUser.get(Key.OUTGOINGS).open(async data => { - // deactivate this listener when user changes - if (lastUserWithListener !== require('../../Mediator').getUser()) { - return - } - - if (typeof data !== 'object' || data === null) { - currentOutgoings = {} - notifyOutgoingsListeners() - return - } - - /** @type {Record} */ - const newOuts = {} - - const SEA = require('../../Mediator').mySEA - const mySecret = await Utils.mySecret() - - await Utils.asyncForEach(Object.entries(data), async ([id, out]) => { - if (typeof out !== 'object') { - return - } - - if (out === null) { - // @ts-ignore - newOuts[id] = null - return - } - - const { with: encPub, messages } = out - - if (typeof encPub !== 'string') { - return - } - - const pub = await SEA.decrypt(encPub, mySecret) - - if (!newOuts[id]) { - newOuts[id] = { - with: pub, - messages: {} + if (!outSubbed) { + const user = require('../../Mediator').getUser() + user.get(Key.OUTGOINGS).open( + debounce(async data => { + try { + if (typeof data !== 'object' || data === null) { + currentOutgoings = {} + notifyOutgoingsListeners() + return } - } - const ourSec = await SEA.secret( - await Utils.pubToEpub(pub), - require('../../Mediator').getUser()._.sea - ) + /** @type {Record} */ + const newOuts = {} - if (typeof messages === 'object' && messages !== null) { - await Utils.asyncForEach( - Object.entries(messages), - async ([mid, msg]) => { - if (typeof msg === 'object' && msg !== null) { - if ( - typeof msg.body === 'string' && - typeof msg.timestamp === 'number' - ) { - newOuts[id].messages[mid] = { - body: - msg.body === Actions.INITIAL_MSG - ? Actions.INITIAL_MSG - : await SEA.decrypt(msg.body, ourSec), - timestamp: msg.timestamp - } - } + const SEA = require('../../Mediator').mySEA + const mySecret = await Utils.mySecret() + + await Utils.asyncForEach(Object.entries(data), async ([id, out]) => { + if (typeof out !== 'object') { + return + } + + if (out === null) { + newOuts[id] = null + return + } + + const { with: encPub, messages } = out + + if (typeof encPub !== 'string') { + return + } + + const pub = await SEA.decrypt(encPub, mySecret) + + if (!newOuts[id]) { + newOuts[id] = { + with: pub, + messages: {} } } - ) - } - }) - currentOutgoings = newOuts - notifyOutgoingsListeners() - }) + const ourSec = await SEA.secret( + await Utils.pubToEpub(pub), + user._.sea + ) + + if (typeof messages === 'object' && messages !== null) { + await Utils.asyncForEach( + Object.entries(messages), + async ([mid, msg]) => { + if (typeof msg === 'object' && msg !== null) { + if ( + typeof msg.body === 'string' && + typeof msg.timestamp === 'number' + ) { + const newOut = newOuts[id] + if (!newOut) { + return + } + newOut.messages[mid] = { + body: + msg.body === Actions.INITIAL_MSG + ? Actions.INITIAL_MSG + : await SEA.decrypt(msg.body, ourSec), + timestamp: msg.timestamp + } + } + } + } + ) + } + }) + + currentOutgoings = newOuts + notifyOutgoingsListeners() + } catch (e) { + console.log('--------------------------') + console.log('Events -> onOutgoing') + console.log(e) + console.log('--------------------------') + } + }, 400) + ) + + outSubbed = true } return () => { From 5762a2aaf8bb9b063c065dac2412fa0b6b4d0512 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 10:04:44 -0400 Subject: [PATCH 082/137] unused graph/code --- services/gunDB/contact-api/actions.js | 18 -------- services/gunDB/contact-api/events/index.js | 50 ---------------------- services/gunDB/contact-api/key.js | 1 - services/gunDB/contact-api/utils/index.js | 30 ------------- 4 files changed, 99 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index bcf416bc..c5643b8a 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -542,8 +542,6 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { }) }) - // save request id to REQUEST_TO_USER - const encryptedForMeRecipientPublicKey = await SEA.encrypt( recipientPublicKey, mySecret @@ -552,22 +550,6 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { // This needs to come before the write to sent requests. Because that write // triggers Jobs.onAcceptedRequests and it in turn reads from request-to-user // This also triggers Events.onSimplerSentRequests - await new Promise((res, rej) => { - user - .get(Key.REQUEST_TO_USER) - .get(newHandshakeRequestID) - .put(encryptedForMeRecipientPublicKey, ack => { - if (ack.err) { - rej( - new Error( - `Error saving recipient public key to request to user: ${ack.err}` - ) - ) - } else { - res() - } - }) - }) /** * @type {StoredReq} diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index f7aeebb5..1890a7f2 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -26,55 +26,6 @@ const Utils = require('../utils') const DEBOUNCE_WAIT_TIME = 500 -/** - * Maps a sent request ID to the public key of the user it was sent to. - * @param {(requestToUser: Record) => void} cb - * @param {UserGUNNode} user Pass only for testing purposes. - * @param {ISEA} SEA - * @returns {Promise} - */ -const __onSentRequestToUser = async (cb, user, SEA) => { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } - - const callb = debounce(cb, DEBOUNCE_WAIT_TIME) - - /** @type {Record} */ - const requestToUser = {} - callb(requestToUser) - - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new TypeError( - "__onSentRequestToUser() -> typeof mySecret !== 'string'" - ) - } - - user - .get(Key.REQUEST_TO_USER) - .map() - .on(async (encryptedUserPub, requestID) => { - if (typeof encryptedUserPub !== 'string') { - console.error('got a non string value') - return - } - if (encryptedUserPub.length === 0) { - console.error('got an empty string value') - return - } - - const userPub = await SEA.decrypt(encryptedUserPub, mySecret) - if (typeof userPub !== 'string') { - console.log(`__onSentRequestToUser() -> typeof userPub !== 'string'`) - return - } - - requestToUser[requestID] = userPub - callb(requestToUser) - }) -} - /** * @param {(userToIncoming: Record) => void} cb * @param {UserGUNNode} user Pass only for testing purposes. @@ -583,7 +534,6 @@ const onSeedBackup = async (cb, user, SEA) => { } module.exports = { - __onSentRequestToUser, __onUserToIncoming, onAvatar, onBlacklist, diff --git a/services/gunDB/contact-api/key.js b/services/gunDB/contact-api/key.js index 0902a454..22f83dc6 100644 --- a/services/gunDB/contact-api/key.js +++ b/services/gunDB/contact-api/key.js @@ -12,7 +12,6 @@ exports.RECIPIENT_TO_OUTGOING = 'recipientToOutgoing' exports.USER_TO_INCOMING = 'userToIncoming' exports.STORED_REQS = 'storedReqs' -exports.REQUEST_TO_USER = 'requestToUser' exports.BLACKLIST = 'blacklist' diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index c67eee1a..092b7742 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -85,35 +85,6 @@ const pubToEpub = async pub => { } } -/** - * @param {string} reqID - * @param {ISEA} SEA - * @param {string} mySecret - * @returns {Promise} - */ -const reqToRecipientPub = async (reqID, SEA, mySecret) => { - const maybeEncryptedForMeRecipientPub = await tryAndWait(async (_, user) => { - const reqToUser = user.get(Key.REQUEST_TO_USER) - const data = await reqToUser.get(reqID).then() - - if (typeof data !== 'string') { - throw new TypeError("typeof maybeEncryptedForMeRecipientPub !== 'string'") - } - - return data - }) - - const encryptedForMeRecipientPub = maybeEncryptedForMeRecipientPub - - const recipientPub = await SEA.decrypt(encryptedForMeRecipientPub, mySecret) - - if (typeof recipientPub !== 'string') { - throw new TypeError("typeof recipientPub !== 'string'") - } - - return recipientPub -} - /** * Should only be called with a recipient pub that has already been contacted. * If returns null, a disconnect happened. @@ -327,7 +298,6 @@ module.exports = { defaultName, delay, pubToEpub, - reqToRecipientPub, recipientPubToLastReqSentID, successfulHandshakeAlreadyExists, recipientToOutgoingID, From 6263b153148ee999963dfa1ab9d046df01ab2127 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 10:15:47 -0400 Subject: [PATCH 083/137] unused code --- services/gunDB/contact-api/utils/index.js | 47 ----------------------- 1 file changed, 47 deletions(-) diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 092b7742..1fc6d00d 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -151,52 +151,6 @@ const recipientToOutgoingID = async recipientPub => { return null } -/** - * @param {string} reqResponse - * @param {string} recipientPub - * @param {UserGUNNode} user - * @param {ISEA} SEA - * @returns {Promise} - */ -const reqWasAccepted = async (reqResponse, recipientPub, user, SEA) => { - try { - const recipientEpub = await pubToEpub(recipientPub) - const ourSecret = await SEA.secret(recipientEpub, user._.sea) - if (typeof ourSecret !== 'string') { - throw new TypeError('typeof ourSecret !== "string"') - } - - const decryptedResponse = await SEA.decrypt(reqResponse, ourSecret) - - if (typeof decryptedResponse !== 'string') { - throw new TypeError('typeof decryptedResponse !== "string"') - } - - const myFeedID = await recipientToOutgoingID(recipientPub) - - if (typeof myFeedID === 'string' && decryptedResponse === myFeedID) { - return false - } - - const recipientFeedID = decryptedResponse - - const maybeFeed = await tryAndWait(gun => - gun - .user(recipientPub) - .get(Key.OUTGOINGS) - .get(recipientFeedID) - .then() - ) - - const feedExistsOnRecipient = - typeof maybeFeed === 'object' && maybeFeed !== null - - return feedExistsOnRecipient - } catch (err) { - throw new Error(`reqWasAccepted() -> ${err.message}`) - } -} - /** * * @param {string} userPub @@ -301,7 +255,6 @@ module.exports = { recipientPubToLastReqSentID, successfulHandshakeAlreadyExists, recipientToOutgoingID, - reqWasAccepted, currHandshakeAddress, tryAndWait, mySecret, From 7c6849c9cbe8f02ef0f756842c643c9f56e91943 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 15:14:06 -0400 Subject: [PATCH 084/137] remove unused imports --- services/gunDB/contact-api/events/onReceivedReqs.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 7f7b1f8f..66755408 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -3,17 +3,7 @@ const Key = require('../key') const Schema = require('../schema') const Streams = require('../streams') /** - * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode - * @typedef {import('../SimpleGUN').GUNNode} GUNNode - * @typedef {import('../SimpleGUN').ISEA} ISEA - * @typedef {import('../SimpleGUN').ListenerData} ListenerData * @typedef {import('../schema').HandshakeRequest} HandshakeRequest - * @typedef {import('../schema').Message} Message - * @typedef {import('../schema').Outgoing} Outgoing - * @typedef {import('../schema').PartialOutgoing} PartialOutgoing - * @typedef {import('../schema').Chat} Chat - * @typedef {import('../schema').ChatMessage} ChatMessage - * @typedef {import('../schema').SimpleSentRequest} SimpleSentRequest * @typedef {import('../schema').SimpleReceivedRequest} SimpleReceivedRequest */ From 092dc71b91108e759aa9786d6c5217cd78625485 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 15:46:22 -0400 Subject: [PATCH 085/137] naming --- services/gunDB/contact-api/events/onReceivedReqs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 66755408..972073aa 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -8,7 +8,7 @@ const Streams = require('../streams') */ /** - * @typedef {(chats: SimpleReceivedRequest[]) => void} Listener + * @typedef {(reqs: SimpleReceivedRequest[]) => void} Listener */ const listeners = new Set() From d47aa691ba81dc3820c70e4e8a278544c1cc842f Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 16:56:23 -0400 Subject: [PATCH 086/137] typings --- services/gunDB/contact-api/streams/pubToIncoming.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/pubToIncoming.js b/services/gunDB/contact-api/streams/pubToIncoming.js index 3d531a32..a8d54621 100644 --- a/services/gunDB/contact-api/streams/pubToIncoming.js +++ b/services/gunDB/contact-api/streams/pubToIncoming.js @@ -6,7 +6,7 @@ const Utils = require('../utils') /** * @typedef {import('../schema').ChatMessage} Message - * @typedef {Record} Incomings + * @typedef {Record} Incomings * @typedef {(incomings: Incomings) => void} IncomingsListener */ From 32c087e69f4d4040fe75fc698c4fce1fa51c3281 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 16:56:28 -0400 Subject: [PATCH 087/137] refresh missing data --- services/gunDB/contact-api/events/onSentReqs.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index 947fa12b..171d6835 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -55,13 +55,18 @@ const react = () => { continue } + if (typeof currAddress === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onAddresses(() => {}, recipientPub)() + } + if (typeof pubToAvatar[recipientPub] === 'undefined') { // eslint-disable-next-line no-empty-function - Streams.onAvatar(() => {}, recipientPub) + Streams.onAvatar(() => {}, recipientPub)() } if (typeof pubToDN[recipientPub] === 'undefined') { // eslint-disable-next-line no-empty-function - Streams.onDisplayName(() => {}, recipientPub) + Streams.onDisplayName(() => {}, recipientPub)() } finalSentReqs.push({ @@ -74,14 +79,6 @@ const react = () => { timestamp }) } - - if (finalSentReqs.length > 0) { - console.log('-------------------------') - console.log('pub to incoming') - console.log(pubToIncoming) - console.log('-------------------------') - } - currentReqs = finalSentReqs listeners.forEach(l => l(currentReqs)) From 80c5cbc6b84d4b456eb8ea6b95cfd0a24ff9aa60 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 17:36:12 -0400 Subject: [PATCH 088/137] dont force refresh --- services/gunDB/Mediator/index.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 7e598a2f..35708691 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -583,19 +583,6 @@ class Mediator { msg: null, origBody: body }) - - API.Events.onSimplerSentRequests( - debounce( - once(srs => { - this.socket.emit(Event.ON_SENT_REQUESTS, { - ok: true, - msg: srs, - origBody: body - }) - }), - 350 - ) - ) } catch (err) { if (Config.SHOW_LOG) { console.log('\n') From 7bc7ad35ef677e8872fa565653fe7f95486a0c23 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 17:50:19 -0400 Subject: [PATCH 089/137] do not force refresh --- services/gunDB/Mediator/index.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 35708691..5ad2c8bc 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -460,26 +460,6 @@ class Mediator { msg: null, origBody: body }) - - // refresh received requests - API.Events.onSimplerReceivedRequests( - debounce( - once(receivedRequests => { - if (Config.SHOW_LOG) { - console.log('---received requests---') - console.log(receivedRequests) - console.log('-----------------------') - } - - this.socket.emit(Event.ON_RECEIVED_REQUESTS, { - msg: receivedRequests, - ok: true, - origBody: body - }) - }), - 300 - ) - ) } catch (err) { console.log(err) this.socket.emit(Action.ACCEPT_REQUEST, { From a4f476998948a78ceae86934d6f4de4df4be029b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 18:08:47 -0400 Subject: [PATCH 090/137] debounce, remove console logs --- services/gunDB/Mediator/index.js | 35 ++++++++++++--------------- services/gunDB/contact-api/actions.js | 11 ++++----- 2 files changed, 20 insertions(+), 26 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 5ad2c8bc..938dbaa7 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -372,16 +372,9 @@ class Mediator { console.error('Unknown Device', error) return false } - console.log('Emitting Data...', data) if (typeof data === 'string') { data = JSON.parse(data) } - console.log('Event:', eventName) - console.log('Data:', data) - console.log('Decrypt params:', { - deviceId, - message: data.encryptedKey - }) const decryptedKey = Encryption.decryptKey({ deviceId, message: data.encryptedKey @@ -415,7 +408,7 @@ class Mediator { deviceId }) : data - console.log('Sending Message...', eventName, data, encryptedMessage) + socket.emit(eventName, encryptedMessage) } catch (err) { console.error(err) @@ -928,19 +921,21 @@ class Mediator { await throwOnInvalidToken(token) - await API.Events.onSimplerSentRequests(sentRequests => { - if (Config.SHOW_LOG) { - console.log('---sentRequests---') - console.log(sentRequests) - console.log('-----------------------') - } + await API.Events.onSimplerSentRequests( + debounce(sentRequests => { + if (Config.SHOW_LOG) { + console.log('---sentRequests---') + console.log(sentRequests) + console.log('-----------------------') + } - this.socket.emit(Event.ON_SENT_REQUESTS, { - msg: sentRequests, - ok: true, - origBody: body - }) - }) + this.socket.emit(Event.ON_SENT_REQUESTS, { + msg: sentRequests, + ok: true, + origBody: body + }) + }, 200) + ) } catch (err) { console.log(err) this.socket.emit(Event.ON_SENT_REQUESTS, { diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index c5643b8a..d74f33fa 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -514,6 +514,11 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { timestamp } + const encryptedForMeRecipientPublicKey = await SEA.encrypt( + recipientPublicKey, + mySecret + ) + console.log('sendHR() -> before newHandshakeRequestID') /** @type {string} */ const newHandshakeRequestID = await new Promise((res, rej) => { @@ -542,14 +547,8 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { }) }) - const encryptedForMeRecipientPublicKey = await SEA.encrypt( - recipientPublicKey, - mySecret - ) - // This needs to come before the write to sent requests. Because that write // triggers Jobs.onAcceptedRequests and it in turn reads from request-to-user - // This also triggers Events.onSimplerSentRequests /** * @type {StoredReq} From fab6e66439011a0d5587dc0e93142fd940358416 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Tue, 4 Feb 2020 18:26:07 -0400 Subject: [PATCH 091/137] tweak debounce time --- services/gunDB/Mediator/index.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 938dbaa7..183a921d 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -921,20 +921,14 @@ class Mediator { await throwOnInvalidToken(token) - await API.Events.onSimplerSentRequests( + API.Events.onSimplerSentRequests( debounce(sentRequests => { - if (Config.SHOW_LOG) { - console.log('---sentRequests---') - console.log(sentRequests) - console.log('-----------------------') - } - this.socket.emit(Event.ON_SENT_REQUESTS, { msg: sentRequests, ok: true, origBody: body }) - }, 200) + }, 1000) ) } catch (err) { console.log(err) From 4c19336fcfc9b9ccedfa876cc16bfa9bbeb2aa71 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 6 Feb 2020 13:02:24 -0400 Subject: [PATCH 092/137] improved generateHandshakeAddress() --- services/gunDB/Mediator/index.js | 4 ++-- services/gunDB/contact-api/actions.js | 28 +++++++++++++++++++-------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 183a921d..1c17c0ef 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -502,7 +502,7 @@ class Mediator { await throwOnInvalidToken(token) - await API.Actions.generateHandshakeAddress(user) + await API.Actions.generateHandshakeAddress() this.socket.emit(Action.GENERATE_NEW_HANDSHAKE_NODE, { ok: true, @@ -1105,7 +1105,7 @@ const register = async (alias, pass) => { return authenticate(alias, pass).then(async pub => { await API.Actions.setDisplayName('anon' + pub.slice(0, 8), user) - await API.Actions.generateHandshakeAddress(user) + await API.Actions.generateHandshakeAddress() await API.Actions.generateOrderAddress(user) return pub }) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index d74f33fa..6e81fd47 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -364,17 +364,15 @@ const blacklist = (publicKey, user) => }) /** - * @param {UserGUNNode} user * @returns {Promise} */ -const generateHandshakeAddress = user => - new Promise((res, rej) => { - if (!user.is) { - throw new Error(ErrorCode.NOT_AUTH) - } +const generateHandshakeAddress = async () => { + const gun = require('../Mediator').getGun() + const user = require('../Mediator').getUser() - const address = uuidv1() + const address = uuidv1() + await new Promise((res, rej) => { user.get(Key.CURRENT_HANDSHAKE_ADDRESS).put(address, ack => { if (ack.err) { rej(new Error(ack.err)) @@ -384,6 +382,20 @@ const generateHandshakeAddress = user => }) }) + await new Promise((res, rej) => { + gun + .get(Key.HANDSHAKE_NODES) + .get(address) + .put({ unused: 0 }, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) +} + /** * @param {string} recipientPublicKey * @param {GUNNode} gun @@ -1098,7 +1110,7 @@ const disconnect = async pub => { }) }) - await generateHandshakeAddress(require('../Mediator').getUser()) + await generateHandshakeAddress() } module.exports = { From b8aae30f67f75ba06c396c3ed6c7f4fdf2f47d44 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 6 Feb 2020 16:08:36 -0400 Subject: [PATCH 093/137] memoize mySecret --- services/gunDB/Mediator/index.js | 16 ++++++++-------- services/gunDB/contact-api/utils/index.js | 8 +------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 1c17c0ef..ea4899e4 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -148,6 +148,11 @@ let user let _currentAlias = '' let _currentPass = '' +let mySec = '' + +/** @returns {string} */ +const getMySecret = () => mySec + let _isAuthenticating = false let _isRegistering = false @@ -197,10 +202,7 @@ const authenticate = async (alias, pass) => { API.Jobs.onAcceptedRequests(user, mySEA) API.Jobs.onOrders(user, gun, mySEA) - const mySec = await mySEA.secret(user._.sea.epub, user._.sea) - if (typeof mySec !== 'string') { - throw new TypeError('mySec not an string') - } + mySec = await mySEA.secret(user._.sea.epub, user._.sea) _currentAlias = user.is ? user.is.alias : '' _currentPass = await mySEA.encrypt(pass, mySec) @@ -1083,9 +1085,6 @@ const register = async (alias, pass) => { _isRegistering = false const mySecret = await mySEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new Error('Could not generate secret for user.') - } if (typeof ack.err === 'string') { throw new Error(ack.err) @@ -1145,5 +1144,6 @@ module.exports = { instantiateGun, getGun, getUser, - mySEA + mySEA, + getMySecret } diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js index 1fc6d00d..1294f1c5 100644 --- a/services/gunDB/contact-api/utils/index.js +++ b/services/gunDB/contact-api/utils/index.js @@ -19,13 +19,7 @@ const delay = ms => new Promise(res => setTimeout(res, ms)) /** * @returns {Promise} */ -const mySecret = () => { - const user = require('../../Mediator/index').getUser() - return require('../../Mediator/index').mySEA.secret( - user._.sea.epub, - user._.sea - ) -} +const mySecret = () => Promise.resolve(require('../../Mediator').getMySecret()) /** * @template T From 6774278e77fc5cf94e248ee23c779e9246646b39 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 9 Feb 2020 13:41:04 -0400 Subject: [PATCH 094/137] use memoized secret --- services/gunDB/contact-api/actions.js | 16 ++++------------ services/gunDB/contact-api/events/index.js | 7 ++----- .../gunDB/contact-api/jobs/onAcceptedRequests.js | 2 +- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 6e81fd47..4df52296 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -58,12 +58,7 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => { throw new Error(ErrorCode.NOT_AUTH) } - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new TypeError( - "__createOutgoingFeed() -> typeof mySecret !== 'string'" - ) - } + const mySecret = require('../Mediator').getMySecret() const encryptedForMeRecipientPub = await SEA.encrypt(withPublicKey, mySecret) const maybeEncryptedForMeOutgoingFeedID = await Utils.tryAndWait( @@ -254,10 +249,7 @@ const acceptRequest = async ( SEA ) - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new TypeError("acceptRequest() -> typeof mySecret !== 'string'") - } + const mySecret = require('../Mediator').getMySecret() const encryptedForMeIncomingID = await SEA.encrypt(incomingID, mySecret) await new Promise((res, rej) => { @@ -430,7 +422,7 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { console.log('sendHR() -> before mySecret') - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) + const mySecret = require('../Mediator').getMySecret() console.log('sendHR() -> before ourSecret') const ourSecret = await SEA.secret(recipientEpub, user._.sea) @@ -1030,7 +1022,7 @@ const saveSeedBackup = async (mnemonicPhrase, user, SEA) => { throw new TypeError('expected mnemonicPhrase to be an string array') } - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) + const mySecret = require('../Mediator').getMySecret() const encryptedSeed = await SEA.encrypt(mnemonicPhrase.join(' '), mySecret) return new Promise((res, rej) => { diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 1890a7f2..2e4c98c2 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -42,10 +42,7 @@ const __onUserToIncoming = async (cb, user, SEA) => { /** @type {Record} */ const userToIncoming = {} - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) - if (typeof mySecret !== 'string') { - throw new TypeError("__onUserToIncoming() -> typeof mySecret !== 'string'") - } + const mySecret = require('../../Mediator').getMySecret() user .get(Key.USER_TO_INCOMING) @@ -520,7 +517,7 @@ const onSeedBackup = async (cb, user, SEA) => { throw new Error(ErrorCode.NOT_AUTH) } - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) + const mySecret = require('../../Mediator').getMySecret() const callb = debounce(cb, DEBOUNCE_WAIT_TIME) callb(currentSeedBackup) diff --git a/services/gunDB/contact-api/jobs/onAcceptedRequests.js b/services/gunDB/contact-api/jobs/onAcceptedRequests.js index 3f6efff4..33c32a12 100644 --- a/services/gunDB/contact-api/jobs/onAcceptedRequests.js +++ b/services/gunDB/contact-api/jobs/onAcceptedRequests.js @@ -23,7 +23,7 @@ const onAcceptedRequests = async (user, SEA) => { throw new Error(ErrorCode.NOT_AUTH) } - const mySecret = await SEA.secret(user._.sea.epub, user._.sea) + const mySecret = require('../../Mediator').getMySecret() if (typeof mySecret !== 'string') { console.log("Jobs.onAcceptedRequests() -> typeof mySecret !== 'string'") From 12887a78b4a76ee1f48da966fd35aa1f610f1ebe Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sun, 9 Feb 2020 18:05:45 -0400 Subject: [PATCH 095/137] pubToIncoming stream --- services/gunDB/contact-api/streams/index.js | 3 +- .../contact-api/streams/pubToIncoming.js | 187 +++++++----------- 2 files changed, 69 insertions(+), 121 deletions(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index b3df5683..63201275 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -180,5 +180,6 @@ module.exports = { onAddresses: require('./addresses').onAddresses, getAddresses: require('./addresses').getAddresses, onLastSentReqIDs: require('./lastSentReqID').onLastSentReqIDs, - getSentReqIDs: require('./lastSentReqID').getSentReqIDs + getSentReqIDs: require('./lastSentReqID').getSentReqIDs, + PubToIncoming: require('./pubToIncoming') } diff --git a/services/gunDB/contact-api/streams/pubToIncoming.js b/services/gunDB/contact-api/streams/pubToIncoming.js index a8d54621..ba2b156e 100644 --- a/services/gunDB/contact-api/streams/pubToIncoming.js +++ b/services/gunDB/contact-api/streams/pubToIncoming.js @@ -1,146 +1,93 @@ /** @format */ -const { INITIAL_MSG } = require('../actions') -const Schema = require('../schema') -const Key = require('../key') -const Utils = require('../utils') +const uuidv1 = require('uuid/v1') +const debounce = require('lodash/debounce') + +const { USER_TO_INCOMING } = require('../key') +const { asyncForEach } = require('../utils') +/** @typedef {import('../SimpleGUN').OpenListenerData} OpenListenerData */ /** - * @typedef {import('../schema').ChatMessage} Message - * @typedef {Record} Incomings - * @typedef {(incomings: Incomings) => void} IncomingsListener + * @typedef {Record} PubToIncoming */ +/** @type {Set<() => void>} */ +const listeners = new Set() + +/** @type {PubToIncoming} */ +let pubToIncoming = {} + +const getPubToIncoming = () => pubToIncoming /** - * @type {Incomings} + * @param {PubToIncoming} pti + * @returns {void} */ -const currentPubToIncoming = {} - -const getPubToIncoming = () => currentPubToIncoming - -/** @type {Set} */ -const incomingsListeners = new Set() - -const notifyIncomingsListeners = () => { - incomingsListeners.forEach(l => l(currentPubToIncoming)) +const setPubToIncoming = pti => { + pubToIncoming = pti + listeners.forEach(l => l()) } -/** @type {Set} */ -const pubFeedPairsWithIncomingListeners = new Set() +let latestUpdate = uuidv1() + +const onOpen = debounce(async uti => { + const SEA = require('../../Mediator').mySEA + const mySec = require('../../Mediator').getMySecret() + const thisUpdate = uuidv1() + latestUpdate = thisUpdate + + if (typeof uti !== 'object' || uti === null) { + setPubToIncoming({}) + return + } + + /** @type {PubToIncoming} */ + const newPubToIncoming = {} + + await asyncForEach(Object.entries(uti), async ([pub, encFeedID]) => { + if (encFeedID === null) { + newPubToIncoming[pub] = null + return + } + + if (typeof encFeedID === 'string') { + newPubToIncoming[pub] = await SEA.decrypt(encFeedID, mySec) + } + }) + + // avoid old data from overwriting new data if decrypting took longer to + // process for the older open() call than for the newer open() call + if (latestUpdate === thisUpdate) { + setPubToIncoming(newPubToIncoming) + } +}, 750) let subbed = false /** - * @param {IncomingsListener} cb + * @param {() => void} cb + * @returns {() => void} */ -const onIncoming = cb => { - incomingsListeners.add(cb) +const onPubToIncoming = cb => { + if (!listeners.add(cb)) { + throw new Error('Tried to subscribe twice') + } - const user = require('../../Mediator').getUser() - const SEA = require('../../Mediator').mySEA + cb() if (!subbed) { - user.get(Key.USER_TO_INCOMING).open(uti => { - if (typeof uti !== 'object' || uti === null) { - return - } - - Object.entries(uti).forEach(async ([pub, encFeed]) => { - if (typeof encFeed !== 'string') { - return - } - const ourSecret = await SEA.secret( - await Utils.pubToEpub(pub), - user._.sea - ) - const mySecret = await Utils.mySecret() - - const feed = await SEA.decrypt(encFeed, mySecret) - - if (pubFeedPairsWithIncomingListeners.add(pub + '--' + feed)) { - require('../../Mediator') - .getGun() - .user(pub) - .get(Key.OUTGOINGS) - .get(feed) - .open(async data => { - if (data === null) { - currentPubToIncoming[pub] = null - return - } - - if (typeof data !== 'object') { - return - } - - if (typeof data.with !== 'string') { - return - } - - if (typeof data.messages !== 'object') { - return - } - - if (data.messages === null) { - return - } - - if (!Array.isArray(currentPubToIncoming[pub])) { - currentPubToIncoming[pub] = [ - { - body: INITIAL_MSG, - // hack one year - timestamp: Date.now() - 31556952, - id: Math.random().toString(), - outgoing: false - } - ] - } - - const msgs = /** @type {[string, Schema.Message][]} */ (Object.entries( - data.messages - ).filter(([_, msg]) => Schema.isMessage(msg))) - - // eslint-disable-next-line require-atomic-updates - currentPubToIncoming[pub] = await Utils.asyncMap( - msgs, - async ([msgid, msg]) => { - let decryptedBody = '' - - if (msg.body === INITIAL_MSG) { - decryptedBody = INITIAL_MSG - } else { - decryptedBody = await SEA.decrypt(msg.body, ourSecret) - } - - /** @type {Schema.ChatMessage} */ - const finalMsg = { - body: decryptedBody, - id: msgid, - outgoing: false, - timestamp: msg.timestamp - } - - return finalMsg - } - ) - - notifyIncomingsListeners() - }) - } - }) - }) - + const user = require('../../Mediator').getUser() + user.get(USER_TO_INCOMING).open(onOpen) subbed = true } - cb(getPubToIncoming()) - return () => { - incomingsListeners.delete(cb) + if (!listeners.delete(cb)) { + throw new Error('Tried to unsubscribe twice') + } } } module.exports = { - onIncoming, - getPubToIncoming + getPubToIncoming, + setPubToIncoming, + onPubToIncoming } From f118beac16b1308c4158b8f22220c72dd3c12109 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 12 Feb 2020 14:20:53 -0400 Subject: [PATCH 096/137] rules --- .eslintrc.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 31d777cc..6f4fbc0d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -69,7 +69,13 @@ "id-length": "off", // typescript does this - "no-unused-vars": "off" + "no-unused-vars": "off", + + // https://github.com/prettier/eslint-config-prettier/issues/132 + "line-comment-position": "off", + + // if someone does this it's probably intentional + "no-useless-concat": "off" }, "parser": "babel-eslint", "env": { From 70ac41edfad71cbe06505774803ebe3dff48ad0b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 12 Feb 2020 14:36:01 -0400 Subject: [PATCH 097/137] encrypt initial msg --- services/gunDB/contact-api/actions.js | 27 +++++++++------------- services/gunDB/contact-api/events/index.js | 21 ++++------------- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index 4df52296..b9a11a54 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -29,14 +29,6 @@ const { isHandshakeRequest } = require('./schema') */ const INITIAL_MSG = '$$__SHOCKWALLET__INITIAL__MESSAGE' -/** - * @returns {Message} - */ -const __createInitialMessage = () => ({ - body: INITIAL_MSG, - timestamp: Date.now() -}) - /** * Create a an outgoing feed. The feed will have an initial special acceptance * message. Returns a promise that resolves to the id of the newly-created @@ -60,6 +52,10 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => { const mySecret = require('../Mediator').getMySecret() const encryptedForMeRecipientPub = await SEA.encrypt(withPublicKey, mySecret) + const ourSecret = await SEA.secret( + await Utils.pubToEpub(withPublicKey), + user._.sea + ) const maybeEncryptedForMeOutgoingFeedID = await Utils.tryAndWait( (_, user) => @@ -99,12 +95,18 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => { throw new TypeError('typeof newOutgoingFeedID !== "string"') } + /** @type {Message} */ + const initialMsg = { + body: await SEA.encrypt(INITIAL_MSG, ourSecret), + timestamp: Date.now() + } + await new Promise((res, rej) => { user .get(Key.OUTGOINGS) .get(newOutgoingFeedID) .get(Key.MESSAGES) - .set(__createInitialMessage(), ack => { + .set(initialMsg, ack => { if (ack.err) { rej(new Error(ack.err)) } else { @@ -118,12 +120,6 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => { mySecret ) - if (typeof encryptedForMeNewOutgoingFeedID === 'undefined') { - throw new TypeError( - "typeof encryptedForMeNewOutgoingFeedID === 'undefined'" - ) - } - await new Promise((res, rej) => { user .get(Key.RECIPIENT_TO_OUTGOING) @@ -1106,7 +1102,6 @@ const disconnect = async pub => { } module.exports = { - INITIAL_MSG, __createOutgoingFeed, acceptRequest, authenticate, diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 2e4c98c2..83648c2e 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -30,9 +30,9 @@ const DEBOUNCE_WAIT_TIME = 500 * @param {(userToIncoming: Record) => void} cb * @param {UserGUNNode} user Pass only for testing purposes. * @param {ISEA} SEA - * @returns {Promise} + * @returns {void} */ -const __onUserToIncoming = async (cb, user, SEA) => { +const __onUserToIncoming = (cb, user, SEA) => { if (!user.is) { throw new Error(ErrorCode.NOT_AUTH) } @@ -233,17 +233,7 @@ const onIncomingMessages = (cb, userPK, incomingFeedID, gun, user, SEA) => { const secret = await SEA.secret(recipientEpub, user._.sea) let { body } = data - - if (body !== Actions.INITIAL_MSG) { - const decrypted = await SEA.decrypt(body, secret) - - if (typeof decrypted !== 'string') { - console.log("onIncommingMessages() -> typeof decrypted !== 'string'") - return - } - - body = decrypted - } + body = await SEA.decrypt(body, secret) messages[key] = { body, @@ -342,10 +332,7 @@ const onOutgoing = cb => { return } newOut.messages[mid] = { - body: - msg.body === Actions.INITIAL_MSG - ? Actions.INITIAL_MSG - : await SEA.decrypt(msg.body, ourSec), + body: await SEA.decrypt(msg.body, ourSec), timestamp: msg.timestamp } } From 4614ed599d996a29f7d0ec79d3dd7a400cedd8e2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 12 Feb 2020 15:10:52 -0400 Subject: [PATCH 098/137] pubToFeed stream --- .../gunDB/contact-api/streams/pubToFeed.js | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 services/gunDB/contact-api/streams/pubToFeed.js diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js new file mode 100644 index 00000000..9dd4733c --- /dev/null +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -0,0 +1,230 @@ +/** @format */ +const uuidv1 = require('uuid/v1') +const logger = require('winston') +const debounce = require('lodash/debounce') + +const Schema = require('../schema') +const Key = require('../key') +const Utils = require('../utils') +/** + * @typedef {import('../schema').ChatMessage} Message + * @typedef {import('../SimpleGUN').OpenListenerData} OpenListenerData + */ + +const PubToIncoming = require('./pubToIncoming') + +/** + * @typedef {Record} Feeds + * @typedef {(feeds: Feeds) => void} FeedsListener + */ + +/** @type {Set} */ +const feedsListeners = new Set() + +/** + * @type {Feeds} + */ +let pubToFeed = {} + +const getPubToFeed = () => pubToFeed + +/** @param {Feeds} ptf */ +const setPubToFeed = ptf => { + pubToFeed = ptf + feedsListeners.forEach(l => { + l(pubToFeed) + }) +} + +/** + * If at one point we subscribed to a feed, record it here. Keeps track of it + * for unsubbing. + * + * Since we can't really unsub in GUN, what we do is that each listener created + * checks the last incoming feed, if it was created for other feed that is not + * the latest, it becomes inactive. + * @type {Record} + */ +const pubToLastIncoming = {} + +/** + * Any pub-feed pair listener will write its update id here when fired up. Avoid + * race conditions between different listeners and between different invocations + * of the same listener. + * @type {Record} + */ +const pubToLastUpdate = {} + +/** + * Performs a sub to a pub feed pair that will only emit if it is the last + * subbed feed for that pub, according to `pubToLastIncoming`. This listener is + * not in charge of writing to the cache. + * @param {[ string , string ]} param0 + * @returns {(data: OpenListenerData) => void} + */ +const onOpenForPubFeedPair = ([pub, feed]) => + debounce(async data => { + // did invalidate + if (pubToLastIncoming[pub] !== feed) { + return + } + + if ( + // did disconnect + data === null || + // interpret as disconnect + typeof data !== 'object' + ) { + // invalidate this listener. If a reconnection happens it will be for a + // different pub-feed pair. + pubToLastIncoming[pub] = null + setImmediate(() => { + logger.info( + `onOpenForPubFeedPair -> didDisconnect -> pub: ${pub} - feed: ${feed}` + ) + }) + return + } + + const incoming = /** @type {Schema.Outgoing} */ (data) + + // incomplete data + if ( + typeof incoming.with !== 'string' || + typeof incoming.messages !== 'object' + ) { + return + } + + /** @type {Schema.ChatMessage[]} */ + const newMsgs = Object.entries(incoming.messages) + // filter out messages with incomplete data + .filter(([_, msg]) => Schema.isMessage(msg)) + .map(([id, msg]) => { + /** @type {Schema.ChatMessage} */ + const m = { + // we'll decrypt later + body: msg.body, + id, + outgoing: false, + timestamp: msg.timestamp + } + + return m + }) + + if (newMsgs.length === 0) { + setPubToFeed({ + ...getPubToFeed(), + [pub]: [] + }) + return + } + + const thisUpdate = uuidv1() + pubToLastUpdate[pub] = thisUpdate + + const user = require('../../Mediator').getUser() + const SEA = require('../../Mediator').mySEA + + const ourSecret = await SEA.secret(await Utils.pubToEpub(pub), user._.sea) + + const decryptedMsgs = await Utils.asyncMap(newMsgs, async m => { + /** @type {Schema.ChatMessage} */ + const decryptedMsg = { + ...m, + body: await SEA.decrypt(m.body, ourSecret) + } + + return decryptedMsg + }) + + // this listener got invalidated while we were awaiting the async operations + // above. + if (pubToLastUpdate[pub] !== thisUpdate) { + return + } + + setPubToFeed({ + ...getPubToFeed(), + [pub]: decryptedMsgs + }) + }, 750) + +const react = () => { + const pubToIncoming = PubToIncoming.getPubToIncoming() + + const gun = require('../../Mediator').getGun() + + const newPubToFeed = { + ...getPubToFeed() + } + + for (const [pub, inc] of Object.entries(pubToIncoming)) { + /** + * empty string -> null + * @type {string|null} + */ + const newIncoming = inc || null + + if (newIncoming === pubToLastIncoming[pub]) { + // eslint-disable-next-line no-continue + continue + } + + // will invalidate stale listeners (a listener for an outdated incoming feed + // id) + pubToLastIncoming[pub] = newIncoming + // Invalidate pending writes from stale listener(s) for the old incoming + // address. + pubToLastUpdate[pub] = uuidv1() + newPubToFeed[pub] = newIncoming ? [] : null + + // sub to this incoming feed + if (typeof newIncoming === 'string') { + // perform sub to pub-incoming_feed pair + // leave all of the sideffects from this for the next tick + setImmediate(() => { + gun + .user(pub) + .get(Key.OUTGOINGS) + .get(newIncoming) + .open(onOpenForPubFeedPair([pub, newIncoming])) + }) + } + } + + if (Object.keys(newPubToFeed).length > 0) { + setPubToFeed(newPubToFeed) + } +} + +let subbed = false + +/** + * Array.isArray(pubToFeed[pub]) means a Handshake is in place, look for + * incoming messages here. + * pubToIncoming[pub] === null means a disconnection took place. + * typeof pubToIncoming[pub] === 'undefined' means none of the above. + * @param {FeedsListener} cb + * @returns {() => void} + */ +const onPubToFeed = cb => { + feedsListeners.add(cb) + cb(getPubToFeed()) + + if (!subbed) { + PubToIncoming.onPubToIncoming(react) + subbed = true + } + + return () => { + feedsListeners.delete(cb) + } +} + +module.exports = { + getPubToFeed, + setPubToFeed, + onPubToFeed +} From aafdcc37dad300167b683d66f071125bdef36b7e Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 12 Feb 2020 15:13:38 -0400 Subject: [PATCH 099/137] tweaks --- services/gunDB/contact-api/events/onReceivedReqs.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 972073aa..c97c84ba 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -11,6 +11,7 @@ const Streams = require('../streams') * @typedef {(reqs: SimpleReceivedRequest[]) => void} Listener */ +/** @type {Set} */ const listeners = new Set() /** @type {SimpleReceivedRequest[]} */ @@ -30,16 +31,17 @@ const react = () => { const pubToDn = Streams.getPubToDn() for (const [id, req] of Object.entries(currentNode)) { + // HERE const notAccepted = typeof pubToIncoming[req.from] === 'undefined' if (notAccepted) { if (typeof pubToAvatar[req.from] === 'undefined') { // eslint-disable-next-line no-empty-function - Streams.onAvatar(() => {}, req.from) + Streams.onAvatar(() => {}, req.from)() } if (typeof pubToDn[req.from] === 'undefined') { // eslint-disable-next-line no-empty-function - Streams.onDisplayName(() => {}, req.from) + Streams.onDisplayName(() => {}, req.from)() } finalReqs.push({ @@ -59,7 +61,6 @@ const react = () => { } /** - * * @param {string} addr * @returns {(data: import('../SimpleGUN').OpenListenerData) => void} */ From b43d45e9e10ea315d10a85d491082b399aa2e86d Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Wed, 12 Feb 2020 15:18:40 -0400 Subject: [PATCH 100/137] current outgoings getter --- services/gunDB/contact-api/events/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 83648c2e..9f186c78 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -254,6 +254,8 @@ const onIncomingMessages = (cb, userPK, incomingFeedID, gun, user, SEA) => { */ let currentOutgoings = {} +const getCurrentOutgoings = () => currentOutgoings + /** @type {Set} */ const outgoingsListeners = new Set() @@ -497,9 +499,9 @@ let currentSeedBackup = null * @param {UserGUNNode} user * @param {ISEA} SEA * @throws {Error} If user hasn't been auth. - * @returns {Promise} + * @returns {void} */ -const onSeedBackup = async (cb, user, SEA) => { +const onSeedBackup = (cb, user, SEA) => { if (!user.is) { throw new Error(ErrorCode.NOT_AUTH) } @@ -525,7 +527,7 @@ module.exports = { onDisplayName, onIncomingMessages, onOutgoing, - onChats, + getCurrentOutgoings, onSimplerReceivedRequests: require('./onReceivedReqs'), onSimplerSentRequests: require('./onSentReqs').onSentReqs, getCurrentSentReqs: require('./onSentReqs').getCurrentSentReqs, From e05991b171d4122a6a2397689bcacb0254b1f975 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 14:21:07 -0400 Subject: [PATCH 101/137] tweak --- services/gunDB/contact-api/streams/pubToFeed.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index 9dd4733c..f94d8caf 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -156,9 +156,8 @@ const react = () => { const gun = require('../../Mediator').getGun() - const newPubToFeed = { - ...getPubToFeed() - } + /** @type {Feeds} */ + const newPubToFeed = {} for (const [pub, inc] of Object.entries(pubToIncoming)) { /** @@ -195,7 +194,10 @@ const react = () => { } if (Object.keys(newPubToFeed).length > 0) { - setPubToFeed(newPubToFeed) + setPubToFeed({ + ...getPubToFeed(), + ...newPubToFeed + }) } } From 955a77e5e8f310cd8890b43d97526a8c9f7cbeba Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 14:31:00 -0400 Subject: [PATCH 102/137] signal remote disconnect --- services/gunDB/contact-api/streams/pubToFeed.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index f94d8caf..ca6ae0fa 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -83,6 +83,13 @@ const onOpenForPubFeedPair = ([pub, feed]) => `onOpenForPubFeedPair -> didDisconnect -> pub: ${pub} - feed: ${feed}` ) }) + // signal disconnect to listeners listeners should rely on pubToFeed for + // disconnect status instead of pub-to-incoming. Only the latter will + // detect remote disconnection + setPubToFeed({ + ...getPubToFeed(), + [pub]: null + }) return } From 45aa0831e40271674941659f9aec80adb9eafd56 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 14:31:41 -0400 Subject: [PATCH 103/137] export pubToFeed --- services/gunDB/contact-api/streams/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/index.js b/services/gunDB/contact-api/streams/index.js index 63201275..b1eb872f 100644 --- a/services/gunDB/contact-api/streams/index.js +++ b/services/gunDB/contact-api/streams/index.js @@ -173,8 +173,14 @@ module.exports = { getPubToAvatar, onDisplayName, getPubToDn, - onIncoming: require('./pubToIncoming').onIncoming, + + onPubToIncoming: require('./pubToIncoming').onPubToIncoming, getPubToIncoming: require('./pubToIncoming').getPubToIncoming, + setPubToIncoming: require('./pubToIncoming').setPubToIncoming, + + onPubToFeed: require('./pubToFeed').onPubToFeed, + getPubToFeed: require('./pubToFeed').getPubToFeed, + onStoredReqs, getStoredReqs, onAddresses: require('./addresses').onAddresses, From 21210694d56cdb2bf4529002aeb5e48058701975 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 16:11:43 -0400 Subject: [PATCH 104/137] improved received requests --- .../contact-api/events/onReceivedReqs.js | 124 ++++++++++-------- services/gunDB/contact-api/schema.js | 5 - 2 files changed, 67 insertions(+), 62 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index c97c84ba..904640cd 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -1,128 +1,138 @@ /** @format */ +const debounce = require('lodash/debounce') + const Key = require('../key') const Schema = require('../schema') const Streams = require('../streams') -/** - * @typedef {import('../schema').HandshakeRequest} HandshakeRequest - * @typedef {import('../schema').SimpleReceivedRequest} SimpleReceivedRequest - */ /** - * @typedef {(reqs: SimpleReceivedRequest[]) => void} Listener + * @typedef {Readonly} SimpleReceivedRequest + * @typedef {(reqs: ReadonlyArray) => void} Listener */ /** @type {Set} */ const listeners = new Set() -/** @type {SimpleReceivedRequest[]} */ -let currentReqs = [] - /** @type {string|null} */ let currentAddress = null -/** @type {Record} */ -let currentNode = {} +/** @type {Record} */ +let currReceivedReqsMap = {} -const react = () => { - /** @type {SimpleReceivedRequest[]} */ - const finalReqs = [] - const pubToIncoming = Streams.getPubToIncoming() +/** + * Unprocessed requests in current handshake node. + * @type {Record} + */ +let currAddressData = {} + +/** @returns {SimpleReceivedRequest[]} */ +const getReceivedReqs = () => Object.values(currReceivedReqsMap) +/** @param {Record} reqs */ +const setReceivedReqsMap = reqs => { + currReceivedReqsMap = reqs + listeners.forEach(l => l(getReceivedReqs())) +} + +const react = debounce(() => { + /** @type {Record} */ + const newReceivedReqsMap = {} + + const pubToFeed = Streams.getPubToFeed() const pubToAvatar = Streams.getPubToAvatar() const pubToDn = Streams.getPubToDn() - for (const [id, req] of Object.entries(currentNode)) { - // HERE - const notAccepted = typeof pubToIncoming[req.from] === 'undefined' + for (const [id, req] of Object.entries(currAddressData)) { + const inContact = Array.isArray(pubToFeed[req.from]) - if (notAccepted) { - if (typeof pubToAvatar[req.from] === 'undefined') { - // eslint-disable-next-line no-empty-function - Streams.onAvatar(() => {}, req.from)() - } - if (typeof pubToDn[req.from] === 'undefined') { - // eslint-disable-next-line no-empty-function - Streams.onDisplayName(() => {}, req.from)() - } + if (typeof pubToAvatar[req.from] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onAvatar(() => {}, req.from)() + } + if (typeof pubToDn[req.from] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onDisplayName(() => {}, req.from)() + } - finalReqs.push({ + if (!inContact) { + newReceivedReqsMap[req.from] = { id, requestorAvatar: pubToAvatar[req.from] || null, requestorDisplayName: pubToDn[req.from] || null, requestorPK: req.from, - response: req.response, timestamp: req.timestamp - }) + } } } - currentReqs = finalReqs - - listeners.forEach(l => l(currentReqs)) -} + setReceivedReqsMap(newReceivedReqsMap) +}, 750) /** * @param {string} addr * @returns {(data: import('../SimpleGUN').OpenListenerData) => void} */ const listenerForAddr = addr => data => { + // did invalidate if (addr !== currentAddress) { return } - if (typeof data === 'object' && data !== null) { + if (typeof data !== 'object' || data === null) { + currAddressData = {} + } else { for (const [id, req] of Object.entries(data)) { - if (!Schema.isHandshakeRequest(req)) { - return + // no need to update them just write them once + if (Schema.isHandshakeRequest(req) && !currAddressData[id]) { + currAddressData[id] = req } - - currentNode[id] = req } - - react() } + + react() } let subbed = false /** - * Massages all of the more primitive data structures into a more manageable - * 'Chat' paradigm. * @param {Listener} cb * @returns {() => void} */ const onReceivedReqs = cb => { listeners.add(cb) + cb(getReceivedReqs()) if (!subbed) { require('./index').onCurrentHandshakeAddress(addr => { - if (currentAddress !== addr) { - currentAddress = addr - currentNode = {} + if (currentAddress === addr) { + return + } - if (typeof addr === 'string') { - require('../../Mediator') - .getGun() - .get(Key.HANDSHAKE_NODES) - .get(addr) - .open(listenerForAddr(addr)) - } + currentAddress = addr + currAddressData = {} + setReceivedReqsMap({}) - react() + if (typeof addr === 'string') { + require('../../Mediator') + .getGun() + .get(Key.HANDSHAKE_NODES) + .get(addr) + .open(listenerForAddr(addr)) } }, require('../../Mediator').getUser()) Streams.onAvatar(react) Streams.onDisplayName(react) - Streams.onIncoming(react) + Streams.onPubToFeed(react) subbed = true } - cb(currentReqs) - return () => { listeners.delete(cb) } } -module.exports = onReceivedReqs +module.exports = { + getReceivedReqs, + onReceivedReqs +} diff --git a/services/gunDB/contact-api/schema.js b/services/gunDB/contact-api/schema.js index 41adf321..d4281ee6 100644 --- a/services/gunDB/contact-api/schema.js +++ b/services/gunDB/contact-api/schema.js @@ -213,7 +213,6 @@ exports.isSimpleSentRequest = item => { * @prop {string|null} requestorAvatar * @prop {string|null} requestorDisplayName * @prop {string} requestorPK - * @prop {string} response * @prop {number} timestamp */ @@ -251,10 +250,6 @@ exports.isSimpleReceivedRequest = item => { return false } - if (typeof obj.response !== 'string') { - return false - } - if (typeof obj.timestamp !== 'number') { return false } From b9abcb06cc51d6a9b9ede608d86ff12d4e9c5917 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 16:25:13 -0400 Subject: [PATCH 105/137] improved sent requests --- .../gunDB/contact-api/events/onSentReqs.js | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index 171d6835..cd00bd37 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -1,4 +1,6 @@ /** @format */ +const debounce = require('lodash/debounce') + const Streams = require('../streams') /** * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode @@ -27,14 +29,14 @@ let currentReqs = [] const getCurrentSentReqs = () => currentReqs -const react = () => { +const react = debounce(() => { /** @type {SimpleSentRequest[]} */ - const finalSentReqs = [] + const newReqs = [] const pubToHAddr = Streams.getAddresses() const storedReqs = Streams.getStoredReqs() const pubToLastSentReqID = Streams.getSentReqIDs() - const pubToIncoming = Streams.getPubToIncoming() + const pubToFeed = Streams.getPubToFeed() const pubToAvatar = Streams.getPubToAvatar() const pubToDN = Streams.getPubToDn() @@ -48,7 +50,7 @@ const react = () => { const lastReqID = pubToLastSentReqID[recipientPub] const isStale = typeof lastReqID !== 'undefined' && lastReqID !== sentReqID - const isConnected = typeof pubToIncoming[recipientPub] !== 'undefined' + const isConnected = Array.isArray(pubToFeed[recipientPub]) if (isStale || isConnected) { // eslint-disable-next-line no-continue @@ -59,7 +61,6 @@ const react = () => { // eslint-disable-next-line no-empty-function Streams.onAddresses(() => {}, recipientPub)() } - if (typeof pubToAvatar[recipientPub] === 'undefined') { // eslint-disable-next-line no-empty-function Streams.onAvatar(() => {}, recipientPub)() @@ -69,7 +70,7 @@ const react = () => { Streams.onDisplayName(() => {}, recipientPub)() } - finalSentReqs.push({ + newReqs.push({ id: sentReqID, recipientAvatar: pubToAvatar[recipientPub] || null, recipientChangedRequestAddress: @@ -79,10 +80,11 @@ const react = () => { timestamp }) } - currentReqs = finalSentReqs + + currentReqs = newReqs listeners.forEach(l => l(currentReqs)) -} +}, 750) let subbed = false @@ -94,20 +96,19 @@ let subbed = false */ const onSentReqs = cb => { listeners.add(cb) + cb(currentReqs) if (!subbed) { Streams.onAddresses(react) Streams.onStoredReqs(react) Streams.onLastSentReqIDs(react) - Streams.onIncoming(react) + Streams.onPubToFeed(react) Streams.onAvatar(react) Streams.onDisplayName(react) subbed = true } - cb(currentReqs) - return () => { listeners.delete(cb) } From 180c485bb874034885914b37c5a65e75358ad752 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 17:58:06 -0400 Subject: [PATCH 106/137] tweak chats --- services/gunDB/contact-api/events/index.js | 75 ++++++++++------------ 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 9f186c78..d83191b7 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -3,7 +3,6 @@ */ const debounce = require('lodash/debounce') -const Actions = require('../actions') const ErrorCode = require('../errorCode') const Key = require('../key') const Schema = require('../schema') @@ -363,9 +362,6 @@ const onOutgoing = cb => { } } //////////////////////////////////////////////////////////////////////////////// -/** @type {Outgoings} */ -let outgoings = {} - /** * @typedef {(chats: Chat[]) => void} ChatsListener */ @@ -380,17 +376,27 @@ const notifyChatsListeners = () => { chatsListeners.forEach(l => l(currentChats)) } -const processChats = () => { +const processChats = debounce(() => { const pubToAvatar = Streams.getPubToAvatar() const pubToDn = Streams.getPubToDn() const existingOutgoings = /** @type {[string, Outgoing][]} */ (Object.entries( - outgoings + getCurrentOutgoings() ).filter(([_, o]) => o !== null)) + const pubToFeed = Streams.getPubToFeed() /** @type {Chat[]} */ - const chats = [] + const newChats = [] for (const [outID, out] of existingOutgoings) { + if (typeof pubToAvatar[out.with] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onAvatar(() => {}, out.with) + } + if (typeof pubToDn[out.with] === 'undefined') { + // eslint-disable-next-line no-empty-function + Streams.onDisplayName(() => {}, out.with) + } + /** @type {ChatMessage[]} */ let msgs = Object.entries(out.messages).map(([mid, m]) => ({ id: mid, @@ -399,17 +405,12 @@ const processChats = () => { timestamp: m.timestamp })) - const incoming = Streams.getPubToIncoming()[out.with] + const incoming = pubToFeed[out.with] if (Array.isArray(incoming)) { msgs = [...msgs, ...incoming] } - console.log('-------------------------------------------------') - console.log(`msgs before filtering`) - console.log(msgs) - console.log('-------------------------------------------------') - /** @type {Chat} */ const chat = { recipientPublicKey: out.with, @@ -420,26 +421,15 @@ const processChats = () => { recipientDisplayName: pubToDn[out.with] || null } - chats.push(chat) - - if (typeof pubToAvatar[out.with] === 'undefined') { - // eslint-disable-next-line no-empty-function - Streams.onAvatar(() => {}, out.with) - } - if (typeof pubToDn[out.with] === 'undefined') { - // eslint-disable-next-line no-empty-function - Streams.onDisplayName(() => {}, out.with) - } + newChats.push(chat) } - currentChats = chats - .filter(c => c.messages.length > 0) - .filter( - c => - typeof Streams.getPubToIncoming()[c.recipientPublicKey] !== 'undefined' - ) + currentChats = newChats + notifyChatsListeners() -} +}, 750) + +let onChatsSubbed = false /** * Massages all of the more primitive data structures into a more manageable @@ -448,20 +438,24 @@ const processChats = () => { * @returns {() => void} */ const onChats = cb => { - chatsListeners.add(cb) + if (!chatsListeners.add(cb)) { + throw new Error('Tried to subscribe twice') + } cb(currentChats) - onOutgoing(outs => { - outgoings = outs - processChats() - }) + if (!onChatsSubbed) { + onOutgoing(processChats) + Streams.onAvatar(processChats) + Streams.onDisplayName(processChats) + Streams.onPubToFeed(processChats) - Streams.onAvatar(processChats) - Streams.onDisplayName(processChats) - Streams.onIncoming(processChats) + onChatsSubbed = true + } return () => { - chatsListeners.delete(cb) + if (!chatsListeners.delete(cb)) { + throw new Error('Tried to unsubscribe twice') + } } } @@ -532,5 +526,6 @@ module.exports = { onSimplerSentRequests: require('./onSentReqs').onSentReqs, getCurrentSentReqs: require('./onSentReqs').getCurrentSentReqs, onBio, - onSeedBackup + onSeedBackup, + onChats } From 5f1ac80553196086b94dfc46ef64ffdcaa7257b4 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 17:59:07 -0400 Subject: [PATCH 107/137] not async --- services/gunDB/contact-api/jobs/onAcceptedRequests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/jobs/onAcceptedRequests.js b/services/gunDB/contact-api/jobs/onAcceptedRequests.js index 33c32a12..b8d3b54c 100644 --- a/services/gunDB/contact-api/jobs/onAcceptedRequests.js +++ b/services/gunDB/contact-api/jobs/onAcceptedRequests.js @@ -16,9 +16,9 @@ const Utils = require('../utils') * @throws {Error} NOT_AUTH * @param {UserGUNNode} user * @param {ISEA} SEA - * @returns {Promise} + * @returns {void} */ -const onAcceptedRequests = async (user, SEA) => { +const onAcceptedRequests = (user, SEA) => { if (!user.is) { throw new Error(ErrorCode.NOT_AUTH) } From f5625b6b59e4ba4f2604c1c08b1b844bf2089ef5 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 17:59:48 -0400 Subject: [PATCH 108/137] remove unused var --- services/gunDB/Mediator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index ea4899e4..d1d4bb25 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -5,7 +5,6 @@ const Gun = require('gun') // @ts-ignore require('gun/lib/open') const debounce = require('lodash/debounce') -const once = require('lodash/once') const Encryption = require('../../../utils/encryptionStore') /** @type {import('../contact-api/SimpleGUN').ISEA} */ @@ -414,6 +413,7 @@ class Mediator { socket.emit(eventName, encryptedMessage) } catch (err) { console.error(err) + } } } From c8675f5cfef5dff0d90d1bcf078db29d45c1bf92 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 18:08:56 -0400 Subject: [PATCH 109/137] fix import/export --- services/gunDB/contact-api/events/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index d83191b7..c420862b 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -522,7 +522,7 @@ module.exports = { onIncomingMessages, onOutgoing, getCurrentOutgoings, - onSimplerReceivedRequests: require('./onReceivedReqs'), + onSimplerReceivedRequests: require('./onReceivedReqs').onReceivedReqs, onSimplerSentRequests: require('./onSentReqs').onSentReqs, getCurrentSentReqs: require('./onSentReqs').getCurrentSentReqs, onBio, From 80481f77fe0589000af5343eabbc6f27db353954 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 18:45:37 -0400 Subject: [PATCH 110/137] logging --- services/gunDB/contact-api/events/onReceivedReqs.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 904640cd..0b739d2d 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -77,6 +77,9 @@ const listenerForAddr = addr => data => { return } + console.log('data') + console.log(data) + if (typeof data !== 'object' || data === null) { currAddressData = {} } else { From 74fa91c1b0502e624668a3605e5a1a53acfcf3e1 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 18:55:23 -0400 Subject: [PATCH 111/137] filter unconnected on first contact request --- services/gunDB/contact-api/events/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index c420862b..9c85b218 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -424,7 +424,11 @@ const processChats = debounce(() => { newChats.push(chat) } - currentChats = newChats + currentChats = newChats.filter( + c => + // initial state, means non connected + typeof pubToFeed[c.recipientPublicKey] !== 'undefined' + ) notifyChatsListeners() }, 750) From 40f53c6994513c8c8300029efa9176e98db1a355 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 19:10:39 -0400 Subject: [PATCH 112/137] logging --- services/gunDB/contact-api/streams/addresses.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/gunDB/contact-api/streams/addresses.js b/services/gunDB/contact-api/streams/addresses.js index cc6d9343..9a6aeea3 100644 --- a/services/gunDB/contact-api/streams/addresses.js +++ b/services/gunDB/contact-api/streams/addresses.js @@ -9,6 +9,9 @@ const pubToAddress = {} /** @type {Set<() => void>} */ const listeners = new Set() + +listeners.add(() => `pubToAddress: ${JSON.stringify(pubToAddress, null, 4)}`) + const notify = () => listeners.forEach(l => l()) /** @type {Set} */ From 199617210778be96565981e95ae5913377848e86 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 19:23:04 -0400 Subject: [PATCH 113/137] actual logging --- services/gunDB/contact-api/streams/addresses.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/addresses.js b/services/gunDB/contact-api/streams/addresses.js index 9a6aeea3..1a599066 100644 --- a/services/gunDB/contact-api/streams/addresses.js +++ b/services/gunDB/contact-api/streams/addresses.js @@ -10,7 +10,9 @@ const pubToAddress = {} /** @type {Set<() => void>} */ const listeners = new Set() -listeners.add(() => `pubToAddress: ${JSON.stringify(pubToAddress, null, 4)}`) +listeners.add(() => { + console.log(`pubToAddress: ${JSON.stringify(pubToAddress, null, 4)}`) +}) const notify = () => listeners.forEach(l => l()) From 1d5211783ad7dda63d6065876e3d9d2fdafd5dd8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 19:33:50 -0400 Subject: [PATCH 114/137] better logging --- services/gunDB/contact-api/events/onReceivedReqs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 0b739d2d..088764f8 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -77,7 +77,7 @@ const listenerForAddr = addr => data => { return } - console.log('data') + console.log('data for address: ' + addr) console.log(data) if (typeof data !== 'object' || data === null) { From a7fb6dd50829838c970fae17f53087248d3305cb Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 19:54:48 -0400 Subject: [PATCH 115/137] better logging --- services/gunDB/contact-api/events/onReceivedReqs.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 088764f8..5f12a132 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -77,9 +77,6 @@ const listenerForAddr = addr => data => { return } - console.log('data for address: ' + addr) - console.log(data) - if (typeof data !== 'object' || data === null) { currAddressData = {} } else { @@ -91,6 +88,9 @@ const listenerForAddr = addr => data => { } } + console.log('data for address: ' + addr) + console.log(currAddressData) + react() } From b533d884c643fe8ce403759d845a5d0cc44ce1ea Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 21:43:07 -0400 Subject: [PATCH 116/137] more logging --- services/gunDB/contact-api/events/onSentReqs.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index cd00bd37..d6a3773b 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -27,6 +27,10 @@ const listeners = new Set() /** @type {SimpleSentRequest[]} */ let currentReqs = [] +listeners.add(() => { + console.log(`new reqs: ${JSON.stringify(currentReqs)}`) +}) + const getCurrentSentReqs = () => currentReqs const react = debounce(() => { From 3d0537670a3a32b2c2908e33e9fa333dcbb44944 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Thu, 13 Feb 2020 21:57:39 -0400 Subject: [PATCH 117/137] received reqs log --- services/gunDB/contact-api/events/onReceivedReqs.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 5f12a132..2404e2d9 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -33,6 +33,10 @@ const setReceivedReqsMap = reqs => { listeners.forEach(l => l(getReceivedReqs())) } +listeners.add(() => { + console.log(`new received reqs: ${getReceivedReqs()}`) +}) + const react = debounce(() => { /** @type {Record} */ const newReceivedReqsMap = {} From 8346962ed2f7cf7e4f7e00512f881bbf855d20e6 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 12:22:39 -0400 Subject: [PATCH 118/137] better log --- services/gunDB/contact-api/events/onReceivedReqs.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index 2404e2d9..d73f1ce2 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -34,7 +34,9 @@ const setReceivedReqsMap = reqs => { } listeners.add(() => { - console.log(`new received reqs: ${getReceivedReqs()}`) + console.log( + `new received reqs: ${JSON.stringify(getReceivedReqs(), null, 4)}` + ) }) const react = debounce(() => { From 5093f910f8c811b8fee0ca2d940a152124824059 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 13:35:09 -0400 Subject: [PATCH 119/137] exact log --- services/gunDB/contact-api/events/onReceivedReqs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/onReceivedReqs.js b/services/gunDB/contact-api/events/onReceivedReqs.js index d73f1ce2..3a174069 100644 --- a/services/gunDB/contact-api/events/onReceivedReqs.js +++ b/services/gunDB/contact-api/events/onReceivedReqs.js @@ -95,7 +95,7 @@ const listenerForAddr = addr => data => { } console.log('data for address: ' + addr) - console.log(currAddressData) + console.log(JSON.stringify(data, null, 4)) react() } From 3c41d435fdb56424eae2a5ca296e0e9e5c90c0de Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 13:57:02 -0400 Subject: [PATCH 120/137] re-enable axe --- services/gunDB/Mediator/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index d1d4bb25..2f44d5d7 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -232,7 +232,7 @@ const instantiateGun = async () => { } const _gun = new Gun({ - axe: false, + axe: true, peers: Config.PEERS }) @@ -413,7 +413,6 @@ class Mediator { socket.emit(eventName, encryptedMessage) } catch (err) { console.error(err) - } } } From 207936a9fd39cadf88bbfcee3c38073f97bd8d6b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 14:21:46 -0400 Subject: [PATCH 121/137] disable axe, lock gun version --- package.json | 2 +- services/gunDB/Mediator/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7803eb99..4ad5aea8 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "google-proto-files": "^1.0.3", "graphviz": "0.0.8", "grpc": "^1.21.1", - "gun": "^0.2019.1211", + "gun": "0.2019.1211", "husky": "^3.0.9", "jsonfile": "^4.0.0", "jsonwebtoken": "^8.3.0", diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 2f44d5d7..ea0e373f 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -232,7 +232,7 @@ const instantiateGun = async () => { } const _gun = new Gun({ - axe: true, + axe: false, peers: Config.PEERS }) From bed7e5d4d00c33ee9b4491d090cd69ef3a1c5f5e Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 14:31:13 -0400 Subject: [PATCH 122/137] lock gun version --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 62854ae0..d458a403 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2718,7 +2718,7 @@ grpc@^1.21.1: node-pre-gyp "^0.13.0" protobufjs "^5.0.3" -gun@^0.2019.1211: +gun@0.2019.1211: version "0.2019.1211" resolved "https://registry.yarnpkg.com/gun/-/gun-0.2019.1211.tgz#37aa58217f86256b5d6f126450c8860f7bca384e" integrity sha512-wueemUJBtNfVcZDeXK7wYbth+eu7tNFo5T54gAbA3N0VAN3zoPNE12saeekzrkVeMiKVxG8/kiR35BhykQ+CJg== From 2d5e950090f2ed65bf5ed80e2fa42efc232feb32 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 14:44:16 -0400 Subject: [PATCH 123/137] sync gun to super peer --- package.json | 2 +- yarn.lock | 204 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 161 insertions(+), 45 deletions(-) diff --git a/package.json b/package.json index 4ad5aea8..7867869d 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "google-proto-files": "^1.0.3", "graphviz": "0.0.8", "grpc": "^1.21.1", - "gun": "0.2019.1211", + "gun": "git://github.com/amark/gun#c59e0e95f92779ce6bb3aab823d318bc16b20c33", "husky": "^3.0.9", "jsonfile": "^4.0.0", "jsonwebtoken": "^8.3.0", diff --git a/yarn.lock b/yarn.lock index d458a403..349712f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -385,24 +385,24 @@ asn1js "^2.0.22" tslib "^1.9.3" -"@peculiar/json-schema@^1.1.5": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.5.tgz#376e0e978d2bd7132487a5679ab375a34313e73f" - integrity sha512-y5XYA3pf9+c+YKVpWnPtQbNmlNCs2ehNHyMLJvq4K5Fjwc1N64YGy7MNecKW3uYLga+sqbGTQSUdOdlnaRRbpA== +"@peculiar/json-schema@^1.1.6": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.9.tgz#b746e046b787607a1b2804f64437fda2527b3e62" + integrity sha512-F2ST2y/IQPgY+1QMw1Q33sqJbGDCeO3lGqI69SL3Hgo0++7iHqprUB1QyxB/A7bN3tuM65MBxoM2JLbwh42lsQ== dependencies: - tslib "^1.9.3" + tslib "^1.10.0" -"@peculiar/webcrypto@^1.0.19": - version "1.0.19" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.0.19.tgz#45dd199c57ee655f9efd0332aca6fd53801d89f7" - integrity sha512-+lF69A18LJBLp0/gJIQatCARLah6cTUmLwY0Cdab0zsk+Z53BcpjKQyyP4LIN8oW601ZXv28mWEQ4Cm7MllF6w== +"@peculiar/webcrypto@^1.0.22": + version "1.0.22" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.0.22.tgz#9dae652fce6bacd9df15bc91965797cee33adf67" + integrity sha512-NP6H6ZGXUvJnQJCWzUgnRcQv+9nMCNwLUDhTwOxRUwPFvtHauMOl0oPTKUjbhInCMaE55gJqB4yc0YKbde6Exw== dependencies: "@peculiar/asn1-schema" "^1.0.3" - "@peculiar/json-schema" "^1.1.5" + "@peculiar/json-schema" "^1.1.6" asn1js "^2.0.26" - pvtsutils "^1.0.6" + pvtsutils "^1.0.9" tslib "^1.10.0" - webcrypto-core "^1.0.14" + webcrypto-core "^1.0.17" "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" @@ -611,11 +611,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.17.tgz#b96d4dd3e427382482848948041d3754d40fd5ce" integrity sha512-p/sGgiPaathCfOtqu2fx5Mu1bcjuP8ALFg4xpGgNkcin7LwRyzUKniEHBKdcE1RPsenq5JVPIpMTJSygLboygQ== -"@types/node@^10.14.17": - version "10.14.19" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.19.tgz#f52742c7834a815dedf66edfc8a51547e2a67342" - integrity sha512-j6Sqt38ssdMKutXBUuAcmWF8QtHW1Fwz/mz4Y+Wd9mzpBiVFirjpNQf363hG5itkG+yGaD+oiLyb50HxJ36l9Q== - "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -687,6 +682,22 @@ lodash.unescape "4.0.1" semver "5.5.0" +"@unimodules/core@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@unimodules/core/-/core-5.0.0.tgz#e1e3ca3f91f3d27dbc93c6eebc03a40c711da755" + integrity sha512-PswccfzFIviX61Lm8h6/QyC94bWe+6cARwhzgzTCKa6aR6azmi4732ExhX4VxfQjJNHB0szYVXGXVEDsFkj+tQ== + dependencies: + compare-versions "^3.4.0" + +"@unimodules/react-native-adapter@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@unimodules/react-native-adapter/-/react-native-adapter-5.0.0.tgz#af9835821a2bf38390b9f09f3231c0b7546ee510" + integrity sha512-qb5p5wUQoi3TRa/33aLLHSnS7sewV99oBxIo9gnzNI3VFzbOm3rsbTjOJNcR2hx0raUolTtnQT75VbgagVQx4w== + dependencies: + invariant "^2.2.4" + lodash "^4.5.0" + prop-types "^15.6.1" + abab@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.2.tgz#a2fba1b122c69a85caa02d10f9270c7219709a9d" @@ -880,6 +891,11 @@ ascli@~1: colour "~0.7.1" optjs "~3.2.2" +asmcrypto.js@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/asmcrypto.js/-/asmcrypto.js-0.22.0.tgz#38fc1440884d802c7bd37d1d23c2b26a5cd5d2d2" + integrity sha512-usgMoyXjMbx/ZPdzTSXExhMPur2FTdz/Vo5PVx2gIaBcdAAJNOFlsdgqveM8Cff7W0v+xrf9BwjOV26JSAF9qA== + asn1@~0.2.3: version "0.2.4" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" @@ -914,7 +930,7 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-limiter@^1.0.0, async-limiter@~1.0.0: +async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== @@ -952,6 +968,20 @@ axios@0.19.0, axios@^0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" +b64-lite@^1.3.1, b64-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/b64-lite/-/b64-lite-1.4.0.tgz#e62442de11f1f21c60e38b74f111ac0242283d3d" + integrity sha512-aHe97M7DXt+dkpa8fHlCcm1CnskAHrJqEfMI0KN7dwqlzml/aUe1AGt6lk51HzrSfVD67xOso84sOpr+0wIe2w== + dependencies: + base-64 "^0.1.0" + +b64u-lite@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/b64u-lite/-/b64u-lite-1.1.0.tgz#a581b7df94cbd4bed7cbb19feae816654f0b1bf0" + integrity sha512-929qWGDVCRph7gQVTC6koHqQIpF4vtVaSbwLltFQo44B1bYUquALswZdBKFfrJCPEnsCOvWkJsPdQYZ/Ukhw8A== + dependencies: + b64-lite "^1.4.0" + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1095,6 +1125,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base-64@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" + integrity sha1-eAqZyE59YAJgNhURxId2E78k9rs= + base-x@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.7.tgz#1c5a7fafe8f66b4114063e8da102799d4e7c408f" @@ -1107,6 +1142,11 @@ base64-arraybuffer@0.1.5: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= +base64-js@*, base64-js@^1.0.2, base64-js@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" @@ -1282,6 +1322,14 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer@^5.4.3: + version "5.4.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" + integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + bytebuffer@~5: version "5.0.1" resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd" @@ -1546,6 +1594,11 @@ commander@~2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.1.tgz#3863ce3ca92d0831dcf2a102f5fb4b5926afd0f9" integrity sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg== +compare-versions@^3.4.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" + integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== + component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -2280,6 +2333,13 @@ expect@^24.9.0: jest-message-util "^24.9.0" jest-regex-util "^24.9.0" +expo-random@*: + version "8.0.0" + resolved "https://registry.yarnpkg.com/expo-random/-/expo-random-8.0.0.tgz#bbcc7a189d29ae9b709b36a6cf84256c22cc16f6" + integrity sha512-ukDC3eGSEliBsnobX1bQRAwti9GE8ZEW53AHFf1fVy+JuAhhZm+M5HW7T0ptdbLjm46VpTDGIO4vq+qxeXAl7g== + dependencies: + base64-js "^1.3.0" + express-session@^1.15.1: version "1.16.2" resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.16.2.tgz#59f36d7770e94872d19b163b6708a2d16aa6848c" @@ -2718,15 +2778,15 @@ grpc@^1.21.1: node-pre-gyp "^0.13.0" protobufjs "^5.0.3" -gun@0.2019.1211: - version "0.2019.1211" - resolved "https://registry.yarnpkg.com/gun/-/gun-0.2019.1211.tgz#37aa58217f86256b5d6f126450c8860f7bca384e" - integrity sha512-wueemUJBtNfVcZDeXK7wYbth+eu7tNFo5T54gAbA3N0VAN3zoPNE12saeekzrkVeMiKVxG8/kiR35BhykQ+CJg== +"gun@git://github.com/amark/gun#c59e0e95f92779ce6bb3aab823d318bc16b20c33": + version "0.2020.116" + resolved "git://github.com/amark/gun#c59e0e95f92779ce6bb3aab823d318bc16b20c33" dependencies: - ws "~>7.1.0" + buffer "^5.4.3" + ws "^7.1.2" optionalDependencies: - "@peculiar/webcrypto" "^1.0.19" emailjs "^2.2.0" + isomorphic-webcrypto "^2.3.2" text-encoding "^0.7.0" handlebars@^4.1.2: @@ -2909,6 +2969,11 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -3304,6 +3369,24 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isomorphic-webcrypto@^2.3.2: + version "2.3.4" + resolved "https://registry.yarnpkg.com/isomorphic-webcrypto/-/isomorphic-webcrypto-2.3.4.tgz#6d18ee7f795ab2f5e9fd7a5b489abaf9ee2e6af5" + integrity sha512-SnOCsm0Vls8jeWP4c26ItHFajzfDlRPcKK4YRUv6jukYGzJwl2tKNwSIAiCh1INdoRttaKhJrLc3HBer1om4HA== + dependencies: + "@peculiar/webcrypto" "^1.0.22" + asmcrypto.js "^0.22.0" + b64-lite "^1.3.1" + b64u-lite "^1.0.1" + msrcrypto "^1.5.6" + str2buf "^1.3.0" + webcrypto-shim "^0.1.4" + optionalDependencies: + "@unimodules/core" "*" + "@unimodules/react-native-adapter" "*" + expo-random "*" + react-native-securerandom "^0.1.1" + isstream@0.1.x, isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -4022,7 +4105,7 @@ lodash@=4.17.4: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= -lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5: +lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -4037,7 +4120,7 @@ long@~3: resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -4239,6 +4322,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +msrcrypto@^1.5.6: + version "1.5.8" + resolved "https://registry.yarnpkg.com/msrcrypto/-/msrcrypto-1.5.8.tgz#be419be4945bf134d8af52e9d43be7fa261f4a1c" + integrity sha512-ujZ0TRuozHKKm6eGbKHfXef7f+esIhEckmThVnz7RNyiOJd7a6MXj2JGBoL9cnPDW+JMG16MoTUh5X+XXjI66Q== + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -4446,7 +4534,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4, object-assign@^4.1.0: +object-assign@^4, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4887,6 +4975,15 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.3" +prop-types@^15.6.1: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + protobufjs@^5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17" @@ -4957,12 +5054,11 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -pvtsutils@^1.0.4, pvtsutils@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.0.6.tgz#e3883fd77abdd4c124131f6a49f3914cd9f21290" - integrity sha512-0yNrOdJyLE7FZzmeEHTKanwBr5XbmDAd020cKa4ZiTYuGMBYBZmq7vHOhcOqhVllh6gghDBbaz1lnVdOqiB7cw== +pvtsutils@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.0.9.tgz#0eb6106f27878ccaa55e7dfbf6bd2c75af461dee" + integrity sha512-/kDsuCKPqJuIzn37w6+iN+TiSrN+zrwPEd7FjT61oNbRvceGdsS94fMEWZ4/h6QZU5EZhBMiV+79IYedroP/Yw== dependencies: - "@types/node" "^10.14.17" tslib "^1.10.0" pvutils@latest: @@ -5015,11 +5111,23 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-is@^16.8.1: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" + integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== + react-is@^16.8.4: version "16.10.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.1.tgz#0612786bf19df406502d935494f0450b40b8294f" integrity sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw== +react-native-securerandom@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/react-native-securerandom/-/react-native-securerandom-0.1.1.tgz#f130623a412c338b0afadedbc204c5cbb8bf2070" + integrity sha1-8TBiOkEsM4sK+t7bwgTFy7i/IHA= + dependencies: + base64-js "*" + read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -5697,6 +5805,11 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +str2buf@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/str2buf/-/str2buf-1.3.0.tgz#a4172afff4310e67235178e738a2dbb573abead0" + integrity sha512-xIBmHIUHYZDP4HyoXGHYNVmxlXLXDrtFHYT0eV6IOdEj3VO9ccaF1Ejl9Oq8iFjITllpT8FhaXb4KsNmw+3EuA== + string-length@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" @@ -6221,14 +6334,19 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" -webcrypto-core@^1.0.14: - version "1.0.14" - resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.0.14.tgz#c015088fbc9c235ebd8b35047a131c5ff58f7152" - integrity sha512-iGZQcH/o3Jv6mpvCbzan6uAcUcLTTnUCil6RVYakcNh5/QXIKRRC06EFxHru9lHgVKucZy3gG4OBiup0IsOr0g== +webcrypto-core@^1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.0.17.tgz#a9354bc0b1ba6735e882f4137ede2c4366e6ad9b" + integrity sha512-7jxTLgtM+TahBPErx/Dd2XvxFDfWJrHxjVeTSvIa4LSgiYrmCPlC2INiAMAfb8MbtHiwJKKqF5sPS0AWNjBbXw== dependencies: - pvtsutils "^1.0.4" + pvtsutils "^1.0.9" tslib "^1.10.0" +webcrypto-shim@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/webcrypto-shim/-/webcrypto-shim-0.1.5.tgz#13e34a010ccc544edecfe8a2642204502841bcf0" + integrity sha512-mE+E00gulvbLjHaAwl0kph60oOLQRsKyivEFgV9DMM/3Y05F1vZvGq12hAcNzHRnYxyEOABBT/XMtwGSg5xA7A== + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -6383,6 +6501,11 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" +ws@^7.1.2: + version "7.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e" + integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A== + ws@~6.1.0: version "6.1.4" resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" @@ -6390,13 +6513,6 @@ ws@~6.1.0: dependencies: async-limiter "~1.0.0" -ws@~>7.1.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.1.2.tgz#c672d1629de8bb27a9699eb599be47aeeedd8f73" - integrity sha512-gftXq3XI81cJCgkUiAVixA0raD9IVmXqsylCrjRygw4+UOOGzPoxnQ6r/CnVL9i+mDncJo94tSkyrtuuQVBmrg== - dependencies: - async-limiter "^1.0.0" - xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" From a6ab80ac1eb7a1395c9d627cbf3ab487cb714add Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Fri, 14 Feb 2020 16:22:58 -0400 Subject: [PATCH 124/137] spin up jobs after setup --- services/gunDB/Mediator/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index ea0e373f..3a063988 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -198,9 +198,6 @@ const authenticate = async (alias, pass) => { if (typeof ack.err === 'string') { throw new Error(ack.err) } else if (typeof ack.sea === 'object') { - API.Jobs.onAcceptedRequests(user, mySEA) - API.Jobs.onOrders(user, gun, mySEA) - mySec = await mySEA.secret(user._.sea.epub, user._.sea) _currentAlias = user.is ? user.is.alias : '' @@ -208,6 +205,9 @@ const authenticate = async (alias, pass) => { await new Promise(res => setTimeout(res, 5000)) + API.Jobs.onAcceptedRequests(user, mySEA) + API.Jobs.onOrders(user, gun, mySEA) + return ack.sea.pub } else { throw new Error('Unknown error.') From cf0100d1055b36d6bc226cecd9c74448674a6078 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 11:52:56 -0400 Subject: [PATCH 125/137] better handling of remote disconnection --- services/gunDB/contact-api/events/index.js | 12 ++++++------ services/gunDB/contact-api/streams/pubToFeed.js | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 9c85b218..6036a8d2 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -414,7 +414,7 @@ const processChats = debounce(() => { /** @type {Chat} */ const chat = { recipientPublicKey: out.with, - didDisconnect: incoming === null, + didDisconnect: pubToFeed[out.with] === 'disconnected', id: out.with + outID, messages: msgs, recipientAvatar: pubToAvatar[out.with] || null, @@ -424,11 +424,11 @@ const processChats = debounce(() => { newChats.push(chat) } - currentChats = newChats.filter( - c => - // initial state, means non connected - typeof pubToFeed[c.recipientPublicKey] !== 'undefined' - ) + currentChats = newChats + // initial state, means non connected + .filter(c => typeof pubToFeed[c.recipientPublicKey] !== 'undefined') + // disconnected from this side + .filter(c => pubToFeed[c.recipientPublicKey] !== null) notifyChatsListeners() }, 750) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index ca6ae0fa..7c06c080 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -14,7 +14,7 @@ const Utils = require('../utils') const PubToIncoming = require('./pubToIncoming') /** - * @typedef {Record} Feeds + * @typedef {Record} Feeds * @typedef {(feeds: Feeds) => void} FeedsListener */ @@ -88,14 +88,14 @@ const onOpenForPubFeedPair = ([pub, feed]) => // detect remote disconnection setPubToFeed({ ...getPubToFeed(), - [pub]: null + [pub]: /** @type {'disconnected'} */ ('disconnected') }) return } const incoming = /** @type {Schema.Outgoing} */ (data) - // incomplete data + // incomplete data, let's not assume anything if ( typeof incoming.with !== 'string' || typeof incoming.messages !== 'object' From c59a2e4fb60fe174f0f230e185ae37c91cc8164a Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 12:08:55 -0400 Subject: [PATCH 126/137] better log --- services/gunDB/contact-api/events/onSentReqs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/events/onSentReqs.js b/services/gunDB/contact-api/events/onSentReqs.js index d6a3773b..f30bb9d2 100644 --- a/services/gunDB/contact-api/events/onSentReqs.js +++ b/services/gunDB/contact-api/events/onSentReqs.js @@ -28,7 +28,7 @@ const listeners = new Set() let currentReqs = [] listeners.add(() => { - console.log(`new reqs: ${JSON.stringify(currentReqs)}`) + console.log(`new sent reqs: ${JSON.stringify(currentReqs)}`) }) const getCurrentSentReqs = () => currentReqs From aa16d4e949ac8309a0993d4d0345d74ff91091a8 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 12:12:17 -0400 Subject: [PATCH 127/137] more logging --- services/gunDB/Mediator/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 3a063988..5401dec6 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -924,6 +924,7 @@ class Mediator { API.Events.onSimplerSentRequests( debounce(sentRequests => { + console.log(`new Reqss in mediator: ${sentRequests}`) this.socket.emit(Event.ON_SENT_REQUESTS, { msg: sentRequests, ok: true, From b2f89db1296e5e061f0adc2df440b99aa5ddaef2 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 12:14:15 -0400 Subject: [PATCH 128/137] better log --- services/gunDB/Mediator/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 5401dec6..f14129c1 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -924,7 +924,7 @@ class Mediator { API.Events.onSimplerSentRequests( debounce(sentRequests => { - console.log(`new Reqss in mediator: ${sentRequests}`) + console.log(`new Reqss in mediator: ${JSON.stringify(sentRequests)}`) this.socket.emit(Event.ON_SENT_REQUESTS, { msg: sentRequests, ok: true, From 327f5ee9fe6a256030c038530e2b6899a11173f5 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 14:20:38 -0400 Subject: [PATCH 129/137] don't debounce, only sub once --- services/gunDB/Mediator/index.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index f14129c1..633eb900 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -913,6 +913,8 @@ class Mediator { } } + onSentRequestsSubbed = false + /** * @param {Readonly<{ token: string }>} body */ @@ -922,16 +924,18 @@ class Mediator { await throwOnInvalidToken(token) - API.Events.onSimplerSentRequests( - debounce(sentRequests => { + if (!this.onSentRequestsSubbed) { + this.onSentRequestsSubbed = true + + API.Events.onSimplerSentRequests(sentRequests => { console.log(`new Reqss in mediator: ${JSON.stringify(sentRequests)}`) this.socket.emit(Event.ON_SENT_REQUESTS, { msg: sentRequests, ok: true, origBody: body }) - }, 1000) - ) + }) + } } catch (err) { console.log(err) this.socket.emit(Event.ON_SENT_REQUESTS, { From 3b663f81369121842294db8ac81c305e14f528ac Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 14:28:17 -0400 Subject: [PATCH 130/137] log --- services/gunDB/contact-api/streams/pubToFeed.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index 7c06c080..e03bb1ae 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -28,6 +28,10 @@ let pubToFeed = {} const getPubToFeed = () => pubToFeed +feedsListeners.add(() => { + console.log(`new pubToFeed: ${getPubToFeed()}`) +}) + /** @param {Feeds} ptf */ const setPubToFeed = ptf => { pubToFeed = ptf From bc55e59c73f037e4082bf379b9fc7d7b7f7b39ba Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 15:11:07 -0400 Subject: [PATCH 131/137] pubToFeed handles disconnect better --- services/gunDB/contact-api/streams/pubToFeed.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index e03bb1ae..20a2f54b 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -177,7 +177,15 @@ const react = () => { */ const newIncoming = inc || null - if (newIncoming === pubToLastIncoming[pub]) { + if ( + newIncoming === pubToLastIncoming[pub] || + // if disconnected, the same incoming feed will try to overwrite the + // nulled out pubToLastIncoming[pub] entry. Making the listener for that + // pub feed pair fire up again, etc. Now. When the user disconnects from + // this side of things. He will overwrite the pub to incoming with null. + // Let's allow that. + (pubToFeed[pub] === 'disconnected' && newIncoming !== null) + ) { // eslint-disable-next-line no-continue continue } From 56a9caf8c17d9ce815c9549e1d9994eff51a84b0 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 15:33:16 -0400 Subject: [PATCH 132/137] fix pubToFeed --- services/gunDB/contact-api/streams/pubToFeed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index 20a2f54b..9995f5bf 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -178,12 +178,12 @@ const react = () => { const newIncoming = inc || null if ( - newIncoming === pubToLastIncoming[pub] || // if disconnected, the same incoming feed will try to overwrite the // nulled out pubToLastIncoming[pub] entry. Making the listener for that // pub feed pair fire up again, etc. Now. When the user disconnects from // this side of things. He will overwrite the pub to incoming with null. // Let's allow that. + newIncoming === pubToLastIncoming[pub] || (pubToFeed[pub] === 'disconnected' && newIncoming !== null) ) { // eslint-disable-next-line no-continue From 8f7792f27583eb0c8a9d1f477d2ad63ec4d78b0a Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 15:39:12 -0400 Subject: [PATCH 133/137] cleanup() --- services/gunDB/contact-api/actions.js | 125 ++++++++++++++------------ 1 file changed, 69 insertions(+), 56 deletions(-) diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js index b9a11a54..0235b296 100644 --- a/services/gunDB/contact-api/actions.js +++ b/services/gunDB/contact-api/actions.js @@ -384,6 +384,72 @@ const generateHandshakeAddress = async () => { }) } +/** + * + * @param {string} pub + * @throws {Error} + * @returns {Promise} + */ +const cleanup = async pub => { + const user = require('../Mediator').getUser() + + const outGoingID = await Utils.recipientToOutgoingID(pub) + + await new Promise((res, rej) => { + user + .get(Key.USER_TO_INCOMING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + + await new Promise((res, rej) => { + user + .get(Key.RECIPIENT_TO_OUTGOING) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + + await new Promise((res, rej) => { + user + .get(Key.USER_TO_LAST_REQUEST_SENT) + .get(pub) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + + if (outGoingID) { + await new Promise((res, rej) => { + user + .get(Key.OUTGOINGS) + .get(outGoingID) + .put(null, ack => { + if (ack.err) { + rej(new Error(ack.err)) + } else { + res() + } + }) + }) + } +} + /** * @param {string} recipientPublicKey * @param {GUNNode} gun @@ -397,6 +463,8 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => { throw new Error(ErrorCode.NOT_AUTH) } + await cleanup(recipientPublicKey) + if (typeof recipientPublicKey !== 'string') { throw new TypeError( `recipientPublicKey is not string, got: ${typeof recipientPublicKey}` @@ -1037,66 +1105,11 @@ const saveSeedBackup = async (mnemonicPhrase, user, SEA) => { * @returns {Promise} */ const disconnect = async pub => { - const user = require('../Mediator').getUser() if (!(await Utils.successfulHandshakeAlreadyExists(pub))) { throw new Error('No handshake exists for this pub') } - const outGoingID = /** @type {string} */ (await Utils.recipientToOutgoingID( - pub - )) - - await new Promise((res, rej) => { - user - .get(Key.USER_TO_INCOMING) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) - - await new Promise((res, rej) => { - user - .get(Key.RECIPIENT_TO_OUTGOING) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) - - await new Promise((res, rej) => { - user - .get(Key.USER_TO_LAST_REQUEST_SENT) - .get(pub) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) - - await new Promise((res, rej) => { - user - .get(Key.OUTGOINGS) - .get(outGoingID) - .put(null, ack => { - if (ack.err) { - rej(new Error(ack.err)) - } else { - res() - } - }) - }) + await cleanup(pub) await generateHandshakeAddress() } From fa8c184b6bd9f3f52c4cfdcf6ec3ada4df895671 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 15:39:19 -0400 Subject: [PATCH 134/137] correct chats --- services/gunDB/contact-api/events/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/gunDB/contact-api/events/index.js b/services/gunDB/contact-api/events/index.js index 6036a8d2..6421d2ec 100644 --- a/services/gunDB/contact-api/events/index.js +++ b/services/gunDB/contact-api/events/index.js @@ -424,11 +424,11 @@ const processChats = debounce(() => { newChats.push(chat) } - currentChats = newChats - // initial state, means non connected - .filter(c => typeof pubToFeed[c.recipientPublicKey] !== 'undefined') - // disconnected from this side - .filter(c => pubToFeed[c.recipientPublicKey] !== null) + currentChats = newChats.filter( + c => + Array.isArray(pubToFeed[c.recipientPublicKey]) || + pubToFeed[c.recipientPublicKey] === 'disconnected' + ) notifyChatsListeners() }, 750) From f1f65fe074c5a4b8ccbd40e0fb22fe611ae8b17b Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 16:09:46 -0400 Subject: [PATCH 135/137] log --- services/gunDB/Mediator/index.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js index 633eb900..31c8d2ae 100644 --- a/services/gunDB/Mediator/index.js +++ b/services/gunDB/Mediator/index.js @@ -6,6 +6,7 @@ const Gun = require('gun') require('gun/lib/open') const debounce = require('lodash/debounce') const Encryption = require('../../../utils/encryptionStore') +const logger = require('winston') /** @type {import('../contact-api/SimpleGUN').ISEA} */ // @ts-ignore @@ -412,6 +413,7 @@ class Mediator { socket.emit(eventName, encryptedMessage) } catch (err) { + logger.error(err.message) console.error(err) } } @@ -927,14 +929,18 @@ class Mediator { if (!this.onSentRequestsSubbed) { this.onSentRequestsSubbed = true - API.Events.onSimplerSentRequests(sentRequests => { - console.log(`new Reqss in mediator: ${JSON.stringify(sentRequests)}`) - this.socket.emit(Event.ON_SENT_REQUESTS, { - msg: sentRequests, - ok: true, - origBody: body - }) - }) + API.Events.onSimplerSentRequests( + debounce(sentRequests => { + console.log( + `new Reqss in mediator: ${JSON.stringify(sentRequests)}` + ) + this.socket.emit(Event.ON_SENT_REQUESTS, { + msg: sentRequests, + ok: true, + origBody: body + }) + }, 1000) + ) } } catch (err) { console.log(err) From 04ed91f7e4cf51e13c0057491d64e233a26b0030 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 16:30:18 -0400 Subject: [PATCH 136/137] fix pubtofeed --- services/gunDB/contact-api/streams/pubToFeed.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index 9995f5bf..463b87ff 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -183,8 +183,8 @@ const react = () => { // pub feed pair fire up again, etc. Now. When the user disconnects from // this side of things. He will overwrite the pub to incoming with null. // Let's allow that. - newIncoming === pubToLastIncoming[pub] || - (pubToFeed[pub] === 'disconnected' && newIncoming !== null) + newIncoming === pubToLastIncoming[pub] && + !(pubToFeed[pub] === 'disconnected' && newIncoming === null) ) { // eslint-disable-next-line no-continue continue From a853e6515dec7ec54281cccef9ac68154ebb7dc6 Mon Sep 17 00:00:00 2001 From: Daniel Lugo Date: Sat, 15 Feb 2020 16:33:29 -0400 Subject: [PATCH 137/137] actual log --- services/gunDB/contact-api/streams/pubToFeed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/gunDB/contact-api/streams/pubToFeed.js b/services/gunDB/contact-api/streams/pubToFeed.js index 463b87ff..d8b5a933 100644 --- a/services/gunDB/contact-api/streams/pubToFeed.js +++ b/services/gunDB/contact-api/streams/pubToFeed.js @@ -29,7 +29,7 @@ let pubToFeed = {} const getPubToFeed = () => pubToFeed feedsListeners.add(() => { - console.log(`new pubToFeed: ${getPubToFeed()}`) + console.log(`new pubToFeed: ${JSON.stringify(getPubToFeed())}`) }) /** @param {Feeds} ptf */