Merge pull request #41 from shocknet/gun-issues

Gun issues
This commit is contained in:
Daniel Lugo 2020-02-26 17:39:40 -04:00 committed by GitHub
commit 266c43c9a4
6 changed files with 375 additions and 239 deletions

View file

@ -77,7 +77,9 @@
"line-comment-position": "off", "line-comment-position": "off",
// if someone does this it's probably intentional // if someone does this it's probably intentional
"no-useless-concat": "off" "no-useless-concat": "off",
"no-plusplus": "off"
}, },
"parser": "babel-eslint", "parser": "babel-eslint",
"env": { "env": {

View file

@ -2,6 +2,7 @@
* @format * @format
*/ */
const Gun = require('gun') const Gun = require('gun')
// @ts-ignore
Gun.log = () => {} Gun.log = () => {}
// @ts-ignore // @ts-ignore
require('gun/lib/open') require('gun/lib/open')
@ -12,6 +13,8 @@ const logger = require('winston')
/** @type {import('../contact-api/SimpleGUN').ISEA} */ /** @type {import('../contact-api/SimpleGUN').ISEA} */
// @ts-ignore // @ts-ignore
const SEAx = require('gun/sea') const SEAx = require('gun/sea')
// @ts-ignore
SEAx.throw = true
/** @type {import('../contact-api/SimpleGUN').ISEA} */ /** @type {import('../contact-api/SimpleGUN').ISEA} */
const mySEA = {} const mySEA = {}
@ -36,6 +39,20 @@ mySEA.encrypt = (msg, secret) => {
) )
} }
if (typeof secret !== 'string') {
throw new TypeError(
`mySEA.encrypt() -> expected secret to be a an string, args: |msg| -- ${JSON.stringify(
secret
)}`
)
}
if (secret.length < 1) {
throw new TypeError(
`mySEA.encrypt() -> expected secret to be a populated string`
)
}
// Avoid this: https://github.com/amark/gun/issues/804 and any other issues // Avoid this: https://github.com/amark/gun/issues/804 and any other issues
const sanitizedMsg = $$__SHOCKWALLET__MSG__ + msg const sanitizedMsg = $$__SHOCKWALLET__MSG__ + msg
@ -87,23 +104,69 @@ mySEA.decrypt = (encMsg, secret) => {
}) })
} }
mySEA.secret = (recipientOrSenderEpub, recipientOrSenderSEA) => { mySEA.secret = async (recipientOrSenderEpub, recipientOrSenderSEA) => {
if (typeof recipientOrSenderEpub !== 'string') { if (typeof recipientOrSenderEpub !== 'string') {
throw new TypeError('epub has to be an string') throw new TypeError(
'epub has to be an string, args:' +
`${JSON.stringify(recipientOrSenderEpub)} -- ${JSON.stringify(
recipientOrSenderSEA
)}`
)
}
if (recipientOrSenderEpub.length === 0) {
throw new TypeError(
'epub has to be populated string, args: ' +
`${JSON.stringify(recipientOrSenderEpub)} -- ${JSON.stringify(
recipientOrSenderSEA
)}`
)
} }
if (typeof recipientOrSenderSEA !== 'object') { if (typeof recipientOrSenderSEA !== 'object') {
throw new TypeError('sea has to be an object') throw new TypeError(
'sea has to be an object, args: ' +
`${JSON.stringify(recipientOrSenderEpub)} -- ${JSON.stringify(
recipientOrSenderSEA
)}`
)
} }
if (recipientOrSenderEpub === recipientOrSenderSEA.pub) {
throw new Error('Do not use pub for mysecret')
}
return SEAx.secret(recipientOrSenderEpub, recipientOrSenderSEA).then(sec => {
if (typeof sec !== 'string') {
throw new TypeError('Could not generate secret')
}
return sec if (recipientOrSenderSEA === null) {
}) throw new TypeError(
'sea has to be nont null, args: ' +
`${JSON.stringify(recipientOrSenderEpub)} -- ${JSON.stringify(
recipientOrSenderSEA
)}`
)
}
if (recipientOrSenderEpub === recipientOrSenderSEA.pub) {
throw new Error(
'Do not use pub for mysecret, args: ' +
`${JSON.stringify(recipientOrSenderEpub)} -- ${JSON.stringify(
recipientOrSenderSEA
)}`
)
}
const sec = await SEAx.secret(recipientOrSenderEpub, recipientOrSenderSEA)
if (typeof sec !== 'string') {
throw new TypeError(
`Could not generate secret, args: ${JSON.stringify(
recipientOrSenderEpub
)} -- ${JSON.stringify(recipientOrSenderSEA)}`
)
}
if (sec.length === 0) {
throw new TypeError(
`SEA.secret returned an empty string!, args: ${JSON.stringify(
recipientOrSenderEpub
)} -- ${JSON.stringify(recipientOrSenderSEA)}`
)
}
return sec
} }
const auth = require('../../auth/auth') const auth = require('../../auth/auth')
@ -127,10 +190,17 @@ const Event = require('../event-constants')
* @prop {Record<string, any>} origBody * @prop {Record<string, any>} origBody
*/ */
/**
* @typedef {object} EncryptedEmission
* @prop {string} encryptedData
* @prop {string} encryptedKey
* @prop {string} iv
*/
// TO DO: move to common repo // TO DO: move to common repo
/** /**
* @typedef {object} SimpleSocket * @typedef {object} SimpleSocket
* @prop {(eventName: string, data: Emission) => void} emit * @prop {(eventName: string, data: Emission|EncryptedEmission) => void} emit
* @prop {(eventName: string, handler: (data: any) => void) => void} on * @prop {(eventName: string, handler: (data: any) => void) => void} on
* @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake * @prop {{ query: { 'x-shockwallet-device-id': string }}} handshake
*/ */
@ -146,13 +216,16 @@ let user
/* eslint-enable init-declarations */ /* eslint-enable init-declarations */
let _currentAlias = '' /** @type {string|null} */
let _currentPass = '' let _currentAlias = null
/** @type {string|null} */
let _currentPass = null
let mySec = '' /** @type {string|null} */
let mySec = null
/** @returns {string} */ /** @returns {string} */
const getMySecret = () => mySec const getMySecret = () => /** @type {string} */ (mySec)
let _isAuthenticating = false let _isAuthenticating = false
let _isRegistering = false let _isRegistering = false
@ -161,18 +234,43 @@ const isAuthenticated = () => typeof user.is === 'object' && user.is !== null
const isAuthenticating = () => _isAuthenticating const isAuthenticating = () => _isAuthenticating
const isRegistering = () => _isRegistering const isRegistering = () => _isRegistering
const getGun = () => {
return gun
}
const getUser = () => {
return user
}
/** /**
* Returns a promise containing the public key of the newly created user. * Returns a promise containing the public key of the newly created user.
* @param {string} alias * @param {string} alias
* @param {string} pass * @param {string} pass
* @param {UserGUNNode=} user
* @returns {Promise<string>} * @returns {Promise<string>}
*/ */
const authenticate = async (alias, pass) => { const authenticate = async (alias, pass, user = getUser()) => {
const isFreshGun = user !== getUser()
if (isFreshGun) {
const ack = await new Promise(res => {
user.auth(alias, pass, _ack => {
res(_ack)
})
})
if (typeof ack.err === 'string') {
throw new Error(ack.err)
} else if (typeof ack.sea === 'object') {
return ack.sea.pub
} else {
throw new Error('Unknown error.')
}
}
if (isAuthenticated()) { if (isAuthenticated()) {
const currAlias = user.is && user.is.alias if (alias !== _currentAlias) {
if (alias !== currAlias) {
throw new Error( throw new Error(
`Tried to re-authenticate with an alias different to that of stored one, tried: ${alias} - stored: ${currAlias}, logoff first if need to change aliases.` `Tried to re-authenticate with an alias different to that of stored one, tried: ${alias} - stored: ${_currentAlias}, logoff first if need to change aliases.`
) )
} }
// move this to a subscription; implement off() ? todo // move this to a subscription; implement off() ? todo
@ -202,7 +300,7 @@ const authenticate = async (alias, pass) => {
} else if (typeof ack.sea === 'object') { } else if (typeof ack.sea === 'object') {
mySec = await mySEA.secret(user._.sea.epub, user._.sea) mySec = await mySEA.secret(user._.sea.epub, user._.sea)
_currentAlias = user.is ? user.is.alias : '' _currentAlias = alias
_currentPass = await mySEA.encrypt(pass, mySec) _currentPass = await mySEA.encrypt(pass, mySec)
await new Promise(res => setTimeout(res, 5000)) await new Promise(res => setTimeout(res, 5000))
@ -220,47 +318,44 @@ const logoff = () => {
user.leave() user.leave()
} }
const instantiateGun = async () => { const instantiateGun = () => {
let mySecret = '' const _gun = /** @type {unknown} */ (new Gun({
if (user && user.is) {
mySecret = /** @type {string} */ (await mySEA.secret(
user._.sea.epub,
user._.sea
))
}
if (typeof mySecret !== 'string') {
throw new TypeError("typeof mySec !== 'string'")
}
const _gun = new Gun({
axe: false, axe: false,
peers: Config.PEERS peers: Config.PEERS
}) }))
// please typescript gun = /** @type {GUNNode} */ (_gun)
const __gun = /** @type {unknown} */ (_gun)
gun = /** @type {GUNNode} */ (__gun)
// eslint-disable-next-line require-atomic-updates
user = gun.user() user = gun.user()
if (_currentAlias && _currentPass) {
const pass = await mySEA.decrypt(_currentPass, mySecret)
if (typeof pass !== 'string') {
throw new Error('could not decrypt stored in memory current pass')
}
user.leave()
await authenticate(_currentAlias, pass)
}
} }
instantiateGun() instantiateGun()
const freshGun = async () => {
const _gun = /** @type {unknown} */ (new Gun({
axe: false,
peers: Config.PEERS
}))
const gun = /** @type {GUNNode} */ (_gun)
const user = gun.user()
if (!_currentAlias || !_currentPass || !mySec) {
throw new Error('Called freshGun() without alias, pass and secret cached')
}
const pass = await mySEA.decrypt(_currentPass, mySec)
if (typeof pass !== 'string') {
throw new Error('could not decrypt stored in memory current pass')
}
await authenticate(_currentAlias, pass, user)
return { gun, user }
}
/** /**
* @param {string} token * @param {string} token
* @returns {Promise<boolean>} * @returns {Promise<boolean>}
@ -296,14 +391,6 @@ const throwOnInvalidToken = async token => {
} }
} }
const getGun = () => {
return gun
}
const getUser = () => {
return user
}
class Mediator { class Mediator {
/** /**
* @param {Readonly<SimpleSocket>} socket * @param {Readonly<SimpleSocket>} socket
@ -1144,9 +1231,7 @@ const register = async (alias, pass) => {
// restart instances so write to user graph work, there's an issue with gun // restart instances so write to user graph work, there's an issue with gun
// (at least on node) where after initial user creation, writes to user graph // (at least on node) where after initial user creation, writes to user graph
// don't work // don't work
await instantiateGun() instantiateGun()
user.leave()
return authenticate(alias, pass).then(async pub => { return authenticate(alias, pass).then(async pub => {
await API.Actions.setDisplayName('anon' + pub.slice(0, 8), user) await API.Actions.setDisplayName('anon' + pub.slice(0, 8), user)
@ -1179,9 +1264,9 @@ module.exports = {
isAuthenticating, isAuthenticating,
isRegistering, isRegistering,
register, register,
instantiateGun,
getGun, getGun,
getUser, getUser,
mySEA, mySEA,
getMySecret getMySecret,
freshGun
} }

View file

@ -57,22 +57,12 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => {
user._.sea user._.sea
) )
const maybeEncryptedForMeOutgoingFeedID = await Utils.tryAndWait( const maybeOutgoingID = await Utils.recipientToOutgoingID(withPublicKey)
(_, user) =>
new Promise(res => {
user
.get(Key.RECIPIENT_TO_OUTGOING)
.get(withPublicKey)
.once(data => {
res(data)
})
})
)
let outgoingFeedID = '' let outgoingFeedID = ''
// if there was no stored outgoing, create an outgoing feed // if there was no stored outgoing, create an outgoing feed
if (typeof maybeEncryptedForMeOutgoingFeedID !== 'string') { if (typeof maybeOutgoingID !== 'string') {
/** @type {PartialOutgoing} */ /** @type {PartialOutgoing} */
const newPartialOutgoingFeed = { const newPartialOutgoingFeed = {
with: encryptedForMeRecipientPub with: encryptedForMeRecipientPub
@ -138,18 +128,7 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => {
// otherwise decrypt stored outgoing // otherwise decrypt stored outgoing
else { else {
const decryptedOID = await SEA.decrypt( outgoingFeedID = maybeOutgoingID
maybeEncryptedForMeOutgoingFeedID,
mySecret
)
if (typeof decryptedOID !== 'string') {
throw new TypeError(
"__createOutgoingFeed() -> typeof decryptedOID !== 'string'"
)
}
outgoingFeedID = decryptedOID
} }
if (typeof outgoingFeedID === 'undefined') { if (typeof outgoingFeedID === 'undefined') {
@ -539,8 +518,8 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
const lastRequestIDSentToUser = maybeLastRequestIDSentToUser const lastRequestIDSentToUser = maybeLastRequestIDSentToUser
console.log('sendHR() -> before alreadyContactedOnCurrHandshakeNode') console.log('sendHR() -> before alreadyContactedOnCurrHandshakeNode')
/** @type {boolean} */
const alreadyContactedOnCurrHandshakeNode = await Utils.tryAndWait( const hrInHandshakeNode = await Utils.tryAndWait(
gun => gun =>
new Promise(res => { new Promise(res => {
gun gun
@ -548,11 +527,16 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
.get(currentHandshakeAddress) .get(currentHandshakeAddress)
.get(lastRequestIDSentToUser) .get(lastRequestIDSentToUser)
.once(data => { .once(data => {
res(typeof data !== 'undefined') res(data)
}) })
}) }),
// force retry on undefined in case the undefined was a false negative
v => typeof v === 'undefined'
) )
const alreadyContactedOnCurrHandshakeNode =
typeof hrInHandshakeNode !== 'undefined'
if (alreadyContactedOnCurrHandshakeNode) { if (alreadyContactedOnCurrHandshakeNode) {
throw new Error(ErrorCode.ALREADY_REQUESTED_HANDSHAKE) throw new Error(ErrorCode.ALREADY_REQUESTED_HANDSHAKE)
} }

View file

@ -1,6 +1,8 @@
/** /**
* @format * @format
*/ */
const logger = require('winston')
const ErrorCode = require('../errorCode') const ErrorCode = require('../errorCode')
const Key = require('../key') const Key = require('../key')
const Schema = require('../schema') const Schema = require('../schema')
@ -12,6 +14,8 @@ const Utils = require('../utils')
* @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode * @typedef {import('../SimpleGUN').UserGUNNode} UserGUNNode
*/ */
let procid = 0
/** /**
* @throws {Error} NOT_AUTH * @throws {Error} NOT_AUTH
* @param {UserGUNNode} user * @param {UserGUNNode} user
@ -23,17 +27,16 @@ const onAcceptedRequests = (user, SEA) => {
throw new Error(ErrorCode.NOT_AUTH) throw new Error(ErrorCode.NOT_AUTH)
} }
const mySecret = require('../../Mediator').getMySecret() procid++
if (typeof mySecret !== 'string') {
console.log("Jobs.onAcceptedRequests() -> typeof mySecret !== 'string'")
return
}
user user
.get(Key.STORED_REQS) .get(Key.STORED_REQS)
.map() .map()
.once(async (storedReq, id) => { .once(async (storedReq, id) => {
logger.info(
`------------------------------------\nPROCID:${procid}\n---------------------------------------`
)
const mySecret = require('../../Mediator').getMySecret()
try { try {
if (!Schema.isStoredRequest(storedReq)) { if (!Schema.isStoredRequest(storedReq)) {
throw new TypeError( throw new TypeError(
@ -70,93 +73,101 @@ const onAcceptedRequests = (user, SEA) => {
return return
} }
const gun = require('../../Mediator').getGun()
const user = require('../../Mediator').getUser()
const recipientEpub = await Utils.pubToEpub(recipientPub) const recipientEpub = await Utils.pubToEpub(recipientPub)
const ourSecret = await SEA.secret(recipientEpub, user._.sea) const ourSecret = await SEA.secret(recipientEpub, user._.sea)
if (typeof ourSecret !== 'string') { await new Promise((res, rej) => {
throw new TypeError("typeof ourSecret !== 'string'") gun
} .get(Key.HANDSHAKE_NODES)
.get(requestAddress)
await Utils.tryAndWait( .get(sentReqID)
(gun, user) => .on(async sentReq => {
new Promise((res, rej) => { if (!Schema.isHandshakeRequest(sentReq)) {
gun rej(
.get(Key.HANDSHAKE_NODES) new Error(
.get(requestAddress) 'sent request found in handshake node not a handshake request'
.get(sentReqID)
.on(async sentReq => {
if (!Schema.isHandshakeRequest(sentReq)) {
rej(
new Error(
'sent request found in handshake node not a handshake request'
)
)
return
}
// The response can be decrypted with the same secret regardless of who
// wrote to it last (see HandshakeRequest definition).
// This could be our feed ID for the recipient, or the recipient's feed
// id if he accepted the request.
const feedID = await SEA.decrypt(sentReq.response, ourSecret)
if (typeof feedID !== 'string') {
throw new TypeError("typeof feedID !== 'string'")
}
const feedIDExistsOnRecipientsOutgoings = await Utils.tryAndWait(
gun =>
new Promise(res => {
gun
.user(recipientPub)
.get(Key.OUTGOINGS)
.get(feedID)
.once(feed => {
res(typeof feed !== 'undefined')
})
})
) )
)
return
}
if (!feedIDExistsOnRecipientsOutgoings) { // The response can be decrypted with the same secret regardless of who
return // wrote to it last (see HandshakeRequest definition).
} // This could be our feed ID for the recipient, or the recipient's feed
// id if he accepted the request.
const feedID = await SEA.decrypt(sentReq.response, ourSecret)
const encryptedForMeIncomingID = await SEA.encrypt( if (typeof feedID !== 'string') {
feedID, throw new TypeError("typeof feedID !== 'string'")
mySecret }
)
await new Promise((res, rej) => { logger.info(`onAcceptedRequests -> decrypted feed ID: ${feedID}`)
user
.get(Key.USER_TO_INCOMING) logger.info(
.get(recipientPub) 'Will now try to access the other users outgoing feed'
.put(encryptedForMeIncomingID, ack => { )
if (ack.err) {
rej(new Error(ack.err)) const maybeFeedOnRecipientsOutgoings = await Utils.tryAndWait(
} else { gun =>
res() new Promise(res => {
} gun
.user(recipientPub)
.get(Key.OUTGOINGS)
.get(feedID)
.once(feed => {
res(feed)
}) })
}) }),
// retry on undefined, might be a false negative
v => typeof v === 'undefined'
)
await new Promise((res, rej) => { const feedIDExistsOnRecipientsOutgoings =
user typeof maybeFeedOnRecipientsOutgoings === 'object' &&
.get(Key.STORED_REQS) maybeFeedOnRecipientsOutgoings !== null
.get(id)
.put(null, ack => {
if (ack.err) {
rej(new Error(ack.err))
} else {
res()
}
})
})
// ensure this listeners gets called at least once if (!feedIDExistsOnRecipientsOutgoings) {
res() return
}) }
const encryptedForMeIncomingID = await SEA.encrypt(
feedID,
mySecret
)
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()
}) })
) })
} catch (err) { } catch (err) {
console.warn(`Jobs.onAcceptedRequests() -> ${err.message}`) console.warn(`Jobs.onAcceptedRequests() -> ${err.message}`)
console.log(err) console.log(err)

View file

@ -1,6 +1,8 @@
/** /**
* @format * @format
*/ */
const logger = require('winston')
const ErrorCode = require('../errorCode') const ErrorCode = require('../errorCode')
const Key = require('../key') const Key = require('../key')
@ -39,18 +41,96 @@ const timeout10 = promise => {
/** /**
* @template T * @template T
* @param {(gun: GUNNode, user: UserGUNNode) => Promise<T>} promGen The function * @param {Promise<T>} promise
* receives the most recent gun and user instances.
* @returns {Promise<T>} * @returns {Promise<T>}
*/ */
const tryAndWait = promGen => const timeout5 = promise => {
timeout10( return Promise.race([
promGen( promise,
require('../../Mediator/index').getGun(), new Promise((_, rej) => {
require('../../Mediator/index').getUser() setTimeout(() => {
rej(new Error(ErrorCode.TIMEOUT_ERR))
}, 5000)
})
])
}
/**
* @template T
* @param {(gun: GUNNode, user: UserGUNNode) => Promise<T>} promGen The function
* receives the most recent gun and user instances.
* @param {((resolvedValue: unknown) => boolean)=} shouldRetry
* @returns {Promise<T>}
*/
const tryAndWait = async (promGen, shouldRetry = () => false) => {
/* eslint-disable no-empty */
/* eslint-disable init-declarations */
// If hang stop at 10, wait 3, retry, if hang stop at 5, reinstate, warm for
// 5, retry, stop at 10, err
/** @type {T} */
let resolvedValue
try {
resolvedValue = await timeout10(
promGen(
require('../../Mediator/index').getGun(),
require('../../Mediator/index').getUser()
)
) )
if (shouldRetry(resolvedValue)) {
logger.info(
'force retrying' +
` args: ${promGen.toString()} -- ${shouldRetry.toString()}`
)
} else {
return resolvedValue
}
} catch (e) {
logger.error(e)
}
logger.info(
`\n retrying \n` +
` args: ${promGen.toString()} -- ${shouldRetry.toString()}`
) )
await delay(3000)
try {
resolvedValue = await timeout5(
promGen(
require('../../Mediator/index').getGun(),
require('../../Mediator/index').getUser()
)
)
if (shouldRetry(resolvedValue)) {
logger.info(
'force retrying' +
` args: ${promGen.toString()} -- ${shouldRetry.toString()}`
)
} else {
return resolvedValue
}
} catch (e) {
logger.error(e)
}
logger.info(
`\n recreating a fresh gun and retrying one last time \n` +
` args: ${promGen.toString()} -- ${shouldRetry.toString()}`
)
const { gun, user } = await require('../../Mediator/index').freshGun()
return timeout10(promGen(gun, user))
/* eslint-enable no-empty */
/* eslint-enable init-declarations */
}
/** /**
* @param {string} pub * @param {string} pub
* @returns {Promise<string>} * @returns {Promise<string>}
@ -74,7 +154,7 @@ const pubToEpub = async pub => {
return epub return epub
} catch (err) { } catch (err) {
console.log(err) logger.error(err)
throw new Error(`pubToEpub() -> ${err.message}`) throw new Error(`pubToEpub() -> ${err.message}`)
} }
} }
@ -86,18 +166,20 @@ const pubToEpub = async pub => {
* @returns {Promise<string|null>} * @returns {Promise<string|null>}
*/ */
const recipientPubToLastReqSentID = async recipientPub => { const recipientPubToLastReqSentID = async recipientPub => {
const lastReqSentID = await tryAndWait(async (_, user) => { const maybeLastReqSentID = await tryAndWait(
const userToLastReqSent = user.get(Key.USER_TO_LAST_REQUEST_SENT) (_, user) => {
const data = await userToLastReqSent.get(recipientPub).then() const userToLastReqSent = user.get(Key.USER_TO_LAST_REQUEST_SENT)
return userToLastReqSent.get(recipientPub).then()
},
// retry on undefined, in case it is a false negative
v => typeof v === 'undefined'
)
if (typeof data !== 'string') { if (typeof maybeLastReqSentID !== 'string') {
return null return null
} }
return data return maybeLastReqSentID
})
return lastReqSentID
} }
/** /**
@ -127,11 +209,15 @@ const successfulHandshakeAlreadyExists = async recipientPub => {
* @returns {Promise<string|null>} * @returns {Promise<string|null>}
*/ */
const recipientToOutgoingID = async recipientPub => { const recipientToOutgoingID = async recipientPub => {
const maybeEncryptedOutgoingID = await require('../../Mediator/index') const maybeEncryptedOutgoingID = await tryAndWait(
.getUser() (_, user) =>
.get(Key.RECIPIENT_TO_OUTGOING) user
.get(recipientPub) .get(Key.RECIPIENT_TO_OUTGOING)
.then() .get(recipientPub)
.then(),
// force retry in case undefined is a false negative
v => typeof v === 'undefined'
)
if (typeof maybeEncryptedOutgoingID === 'string') { if (typeof maybeEncryptedOutgoingID === 'string') {
const outgoingID = await require('../../Mediator/index').mySEA.decrypt( const outgoingID = await require('../../Mediator/index').mySEA.decrypt(
@ -145,22 +231,6 @@ const recipientToOutgoingID = async recipientPub => {
return null return null
} }
/**
*
* @param {string} userPub
* @returns {Promise<string|null>}
*/
const currHandshakeAddress = async userPub => {
const maybeAddr = await tryAndWait(gun =>
gun
.user(userPub)
.get(Key.CURRENT_HANDSHAKE_ADDRESS)
.then()
)
return typeof maybeAddr === 'string' ? maybeAddr : null
}
/** /**
* @template T * @template T
* @param {T[]} arr * @param {T[]} arr
@ -223,22 +293,6 @@ const dataHasSoul = listenerData =>
*/ */
const defaultName = pub => 'anon' + pub.slice(0, 8) const defaultName = pub => 'anon' + pub.slice(0, 8)
/**
* @param {string} pub
* @param {string} incomingID
* @returns {Promise<boolean>}
*/
const didDisconnect = async (pub, incomingID) => {
const feed = await require('../../Mediator/index')
.getGun()
.user(pub)
.get(Key.OUTGOINGS)
.get(incomingID)
.then()
return feed === null
}
module.exports = { module.exports = {
asyncMap, asyncMap,
asyncFilter, asyncFilter,
@ -249,10 +303,9 @@ module.exports = {
recipientPubToLastReqSentID, recipientPubToLastReqSentID,
successfulHandshakeAlreadyExists, successfulHandshakeAlreadyExists,
recipientToOutgoingID, recipientToOutgoingID,
currHandshakeAddress,
tryAndWait, tryAndWait,
mySecret, mySecret,
promisifyGunNode: require('./promisifygun'), promisifyGunNode: require('./promisifygun'),
didDisconnect, asyncForEach,
asyncForEach timeout5
} }

View file

@ -1570,6 +1570,7 @@ module.exports = async (
const Events = require('../services/gunDB/contact-api/events') const Events = require('../services/gunDB/contact-api/events')
const user = require('../services/gunDB/Mediator').getUser() const user = require('../services/gunDB/Mediator').getUser()
const Key = require('../services/gunDB/contact-api/key') const Key = require('../services/gunDB/contact-api/key')
const {timeout5} = require('../services/gunDB/contact-api/utils')
app.get(`/api/gun/${GunEvent.ON_RECEIVED_REQUESTS}`, (_, res) => { app.get(`/api/gun/${GunEvent.ON_RECEIVED_REQUESTS}`, (_, res) => {
try { try {
@ -1619,7 +1620,7 @@ module.exports = async (
app.get(`/api/gun/${GunEvent.ON_AVATAR}`, async (_, res) => { app.get(`/api/gun/${GunEvent.ON_AVATAR}`, async (_, res) => {
try { try {
res.json({ res.json({
data: await user.get(Key.PROFILE).get(Key.AVATAR).then() data: await timeout5(user.get(Key.PROFILE).get(Key.AVATAR).then())
}) })
} catch (err) { } catch (err) {
res.status(500).json({ res.status(500).json({
@ -1631,7 +1632,7 @@ module.exports = async (
app.get(`/api/gun/${GunEvent.ON_DISPLAY_NAME}`, async (_, res) => { app.get(`/api/gun/${GunEvent.ON_DISPLAY_NAME}`, async (_, res) => {
try { try {
res.json({ res.json({
data: await user.get(Key.PROFILE).get(Key.DISPLAY_NAME).then() data: await timeout5(user.get(Key.PROFILE).get(Key.DISPLAY_NAME).then())
}) })
} catch (err) { } catch (err) {
res.status(500).json({ res.status(500).json({
@ -1643,7 +1644,7 @@ module.exports = async (
app.get(`/api/gun/${GunEvent.ON_HANDSHAKE_ADDRESS}`, async (_, res) => { app.get(`/api/gun/${GunEvent.ON_HANDSHAKE_ADDRESS}`, async (_, res) => {
try { try {
res.json({ res.json({
data: await user.get(Key.CURRENT_HANDSHAKE_ADDRESS).then() data: await timeout5(user.get(Key.CURRENT_HANDSHAKE_ADDRESS).then())
}) })
} catch (err) { } catch (err) {
res.status(500).json({ res.status(500).json({