Remove outdated gun actions

This commit is contained in:
Daniel Lugo 2021-06-13 12:41:44 -04:00
parent 0681464817
commit 45eeb2d672

View file

@ -26,262 +26,10 @@ const LNDHealthMananger = require('../../../utils/lightningServices/errors')
const { enrollContentTokens, selfContentToken } = require('../../seed')
/**
* @typedef {import('./SimpleGUN').GUNNode} GUNNode
* @typedef {import('./SimpleGUN').ISEA} ISEA
* @typedef {import('./SimpleGUN').UserGUNNode} UserGUNNode
* @typedef {import('shock-common').Schema.HandshakeRequest} HandshakeRequest
* @typedef {import('shock-common').Schema.StoredRequest} StoredReq
* @typedef {import('shock-common').Schema.Message} Message
* @typedef {import('shock-common').Schema.Outgoing} Outgoing
* @typedef {import('shock-common').Schema.PartialOutgoing} PartialOutgoing
* @typedef {import('shock-common').Schema.Order} Order
* @typedef {import('./SimpleGUN').Ack} Ack
*/
/**
* 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
* outgoing feed.
*
* If an outgoing feed is already created for the recipient, then returns the id
* of that one.
* @param {string} withPublicKey Public key of the intended recipient of the
* outgoing feed that will be created.
* @throws {Error} If the outgoing feed cannot be created or if the initial
* message for it also cannot be created. These errors aren't coded as they are
* not meant to be caught outside of this module.
* @param {UserGUNNode} user
* @param {ISEA} SEA
* @returns {Promise<string>}
*/
const __createOutgoingFeed = async (withPublicKey, user, SEA) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
const mySecret = require('../Mediator').getMySecret()
const encryptedForMeRecipientPub = await SEA.encrypt(withPublicKey, mySecret)
const ourSecret = await SEA.secret(
await Utils.pubToEpub(withPublicKey),
user._.sea
)
const maybeOutgoingID = await Utils.recipientToOutgoingID(withPublicKey)
let outgoingFeedID = ''
// if there was no stored outgoing, create an outgoing feed
if (typeof maybeOutgoingID !== 'string') {
/** @type {PartialOutgoing} */
const newPartialOutgoingFeed = {
with: encryptedForMeRecipientPub
}
/** @type {string} */
const newOutgoingFeedID = await new Promise((res, rej) => {
const _outFeedNode = user
.get(Key.OUTGOINGS)
//@ts-ignore
.set(newPartialOutgoingFeed, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res(_outFeedNode._.get)
}
})
})
if (typeof newOutgoingFeedID !== 'string') {
throw new TypeError('typeof newOutgoingFeedID !== "string"')
}
/** @type {Message} */
const initialMsg = {
body: await SEA.encrypt(Constants.Misc.INITIAL_MSG, ourSecret),
timestamp: Date.now()
}
await /** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.OUTGOINGS)
.get(newOutgoingFeedID)
.get(Key.MESSAGES)
//@ts-ignore
.set(initialMsg, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
const encryptedForMeNewOutgoingFeedID = await SEA.encrypt(
newOutgoingFeedID,
mySecret
)
await /** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.RECIPIENT_TO_OUTGOING)
.get(withPublicKey)
.put(encryptedForMeNewOutgoingFeedID, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(Error(ack.err))
} else {
res()
}
})
}))
outgoingFeedID = newOutgoingFeedID
}
// otherwise decrypt stored outgoing
else {
outgoingFeedID = maybeOutgoingID
}
if (typeof outgoingFeedID === 'undefined') {
throw new TypeError(
'__createOutgoingFeed() -> typeof outgoingFeedID === "undefined"'
)
}
if (typeof outgoingFeedID !== 'string') {
throw new TypeError(
'__createOutgoingFeed() -> expected outgoingFeedID to be an string'
)
}
if (outgoingFeedID.length === 0) {
throw new TypeError(
'__createOutgoingFeed() -> expected outgoingFeedID to be a populated string.'
)
}
return outgoingFeedID
}
/**
* Given a request's ID, that should be found on the user's current handshake
* node, accept the request by creating an outgoing feed intended for the
* requestor, then encrypting and putting the id of this newly created outgoing
* feed on the response prop of the request.
* @param {string} requestID The id for the request to accept.
* @param {GUNNode} gun
* @param {UserGUNNode} user Pass only for testing purposes.
* @param {ISEA} SEA
* @param {typeof __createOutgoingFeed} outgoingFeedCreator Pass only
* for testing. purposes.
* @throws {Error} Throws if trying to accept an invalid request, or an error on
* gun's part.
* @returns {Promise<void>}
*/
const acceptRequest = async (
requestID,
gun,
user,
SEA,
outgoingFeedCreator = __createOutgoingFeed
) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
const handshakeAddress = await Utils.tryAndWait(async (_, user) => {
const addr = await user.get(Key.CURRENT_HANDSHAKE_ADDRESS).then()
if (typeof addr !== 'string') {
throw new TypeError("typeof addr !== 'string'")
}
return addr
})
const {
response: encryptedForUsIncomingID,
from: senderPublicKey
} = await Utils.tryAndWait(async gun => {
const hr = await gun
.get(Key.HANDSHAKE_NODES)
.get(handshakeAddress)
.get(requestID)
.then()
if (!Schema.isHandshakeRequest(hr)) {
throw new Error(ErrorCode.TRIED_TO_ACCEPT_AN_INVALID_REQUEST)
}
return hr
})
/** @type {string} */
const requestorEpub = await Utils.pubToEpub(senderPublicKey)
const ourSecret = await SEA.secret(requestorEpub, user._.sea)
if (typeof ourSecret !== 'string') {
throw new TypeError("typeof ourSecret !== 'string'")
}
const incomingID = await SEA.decrypt(encryptedForUsIncomingID, ourSecret)
if (typeof incomingID !== 'string') {
throw new TypeError("typeof incomingID !== 'string'")
}
const newlyCreatedOutgoingFeedID = await outgoingFeedCreator(
senderPublicKey,
user,
SEA
)
const mySecret = require('../Mediator').getMySecret()
const encryptedForMeIncomingID = await SEA.encrypt(incomingID, mySecret)
await /** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_INCOMING)
.get(senderPublicKey)
.put(encryptedForMeIncomingID, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
////////////////////////////////////////////////////////////////////////////
// NOTE: perform non-reversable actions before destructive actions
// In case any of the non-reversable actions reject.
// In this case, writing to the response is the non-revesarble op.
////////////////////////////////////////////////////////////////////////////
const encryptedForUsOutgoingID = await SEA.encrypt(
newlyCreatedOutgoingFeedID,
ourSecret
)
//why await if you dont need the response?
await /** @type {Promise<void>} */ (new Promise((res, rej) => {
gun
.get(Key.HANDSHAKE_NODES)
.get(handshakeAddress)
.get(requestID)
.put(
{
response: encryptedForUsOutgoingID
},
ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
}
)
}))
}
/**
* @param {string} user
* @param {string} pass
@ -374,438 +122,6 @@ const generateHandshakeAddress = async () => {
}))
}
/**
*
* @param {string} pub
* @throws {Error}
* @returns {Promise<void>}
*/
const cleanup = async pub => {
const user = require('../Mediator').getUser()
const outGoingID = await Utils.recipientToOutgoingID(pub)
const promises = []
promises.push(
/** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_INCOMING)
.get(pub)
.put(null, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
)
promises.push(
/** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.RECIPIENT_TO_OUTGOING)
.get(pub)
.put(null, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
)
promises.push(
/** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_LAST_REQUEST_SENT)
.get(pub)
.put(null, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
)
if (outGoingID) {
promises.push(
/** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.OUTGOINGS)
.get(outGoingID)
.put(null, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
)
}
await Promise.all(promises)
}
/**
* @param {string} recipientPublicKey
* @param {GUNNode} gun
* @param {UserGUNNode} user
* @param {ISEA} SEA
* @throws {Error|TypeError}
* @returns {Promise<void>}
*/
const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
await cleanup(recipientPublicKey)
if (typeof recipientPublicKey !== 'string') {
throw new TypeError(
`recipientPublicKey is not string, got: ${typeof recipientPublicKey}`
)
}
if (recipientPublicKey.length === 0) {
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')
}
logger.info('sendHR() -> before recipientEpub')
/** @type {string} */
const recipientEpub = await Utils.pubToEpub(recipientPublicKey)
logger.info('sendHR() -> before mySecret')
const mySecret = require('../Mediator').getMySecret()
logger.info('sendHR() -> before ourSecret')
const ourSecret = await SEA.secret(recipientEpub, user._.sea)
// check if successful handshake is present
logger.info('sendHR() -> before alreadyHandshaked')
/** @type {boolean} */
const alreadyHandshaked = await Utils.successfulHandshakeAlreadyExists(
recipientPublicKey
)
if (alreadyHandshaked) {
throw new Error(ErrorCode.ALREADY_HANDSHAKED)
}
logger.info('sendHR() -> before maybeLastRequestIDSentToUser')
// check that we have already sent a request to this user, on his current
// handshake node
const maybeLastRequestIDSentToUser = await Utils.tryAndWait((_, user) =>
user
.get(Key.USER_TO_LAST_REQUEST_SENT)
.get(recipientPublicKey)
.then()
)
logger.info('sendHR() -> before currentHandshakeAddress')
const currentHandshakeAddress = await Utils.tryAndWait(
gun =>
Common.Utils.makePromise(res => {
gun
.user(recipientPublicKey)
.get(Key.CURRENT_HANDSHAKE_ADDRESS)
.once(
data => {
res(data)
},
{ wait: 1000 }
)
}),
data => typeof data !== 'string'
)
if (typeof currentHandshakeAddress !== 'string') {
throw new TypeError(
'expected current handshake address found on recipients user node to be an string'
)
}
if (typeof maybeLastRequestIDSentToUser === 'string') {
if (maybeLastRequestIDSentToUser.length < 5) {
throw new TypeError(
'sendHandshakeRequest() -> maybeLastRequestIDSentToUser.length < 5'
)
}
const lastRequestIDSentToUser = maybeLastRequestIDSentToUser
logger.info('sendHR() -> before alreadyContactedOnCurrHandshakeNode')
const hrInHandshakeNode = await Utils.tryAndWait(
gun =>
new Promise(res => {
gun
.get(Key.HANDSHAKE_NODES)
.get(currentHandshakeAddress)
.get(lastRequestIDSentToUser)
.once(data => {
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) {
throw new Error(ErrorCode.ALREADY_REQUESTED_HANDSHAKE)
}
}
logger.info('sendHR() -> before __createOutgoingFeed')
const outgoingFeedID = await __createOutgoingFeed(
recipientPublicKey,
user,
SEA
)
logger.info('sendHR() -> before encryptedForUsOutgoingFeedID')
const encryptedForUsOutgoingFeedID = await SEA.encrypt(
outgoingFeedID,
ourSecret
)
const timestamp = Date.now()
/** @type {HandshakeRequest} */
const handshakeRequestData = {
from: user.is.pub,
response: encryptedForUsOutgoingFeedID,
timestamp
}
const encryptedForMeRecipientPublicKey = await SEA.encrypt(
recipientPublicKey,
mySecret
)
logger.info('sendHR() -> before newHandshakeRequestID')
/** @type {string} */
const newHandshakeRequestID = await new Promise((res, rej) => {
const hr = gun
.get(Key.HANDSHAKE_NODES)
.get(currentHandshakeAddress)
//@ts-ignore
.set(handshakeRequestData, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(`Error trying to create request: ${ack.err}`))
} else {
res(hr._.get)
}
})
})
await /** @type {Promise<void>} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_LAST_REQUEST_SENT)
.get(recipientPublicKey)
.put(newHandshakeRequestID, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
}))
// 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
/**
* @type {StoredReq}
*/
const storedReq = {
sentReqID: await SEA.encrypt(newHandshakeRequestID, mySecret),
recipientPub: encryptedForMeRecipientPublicKey,
handshakeAddress: await SEA.encrypt(currentHandshakeAddress, mySecret),
timestamp
}
//why await if you dont need the response?
await /** @type {Promise<void>} */ (new Promise((res, rej) => {
//@ts-ignore
user.get(Key.STORED_REQS).set(storedReq, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(
new Error(
`Error saving newly created request to sent requests: ${ack.err}`
)
)
} else {
res()
}
})
}))
}
/**
* Returns the message id.
* @param {string} recipientPublicKey
* @param {string} body
* @param {UserGUNNode} user
* @param {ISEA} SEA
* @returns {Promise<import('shock-common').Schema.ChatMessage>} The message id.
*/
const sendMessageNew = async (recipientPublicKey, body, user, SEA) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
if (typeof recipientPublicKey !== 'string') {
throw new TypeError(
`expected recipientPublicKey to be an string, but instead got: ${typeof recipientPublicKey}`
)
}
if (recipientPublicKey.length === 0) {
throw new TypeError(
'expected recipientPublicKey to be an string of length greater than zero'
)
}
if (typeof body !== 'string') {
throw new TypeError(
`expected message to be an string, instead got: ${typeof body}`
)
}
if (body.length === 0) {
throw new TypeError(
'expected message to be an string of length greater than zero'
)
}
const outgoingID = await Utils.recipientToOutgoingID(recipientPublicKey)
if (outgoingID === null) {
throw new Error(
`Could not fetch an outgoing id for user: ${recipientPublicKey}`
)
}
const recipientEpub = await Utils.pubToEpub(recipientPublicKey)
const ourSecret = await SEA.secret(recipientEpub, user._.sea)
if (typeof ourSecret !== 'string') {
throw new TypeError("sendMessage() -> typeof ourSecret !== 'string'")
}
const encryptedBody = await SEA.encrypt(body, ourSecret)
const newMessage = {
body: encryptedBody,
timestamp: Date.now()
}
return new Promise((res, rej) => {
const msgNode = user
.get(Key.OUTGOINGS)
.get(outgoingID)
.get(Key.MESSAGES)
.set(newMessage, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res({
body,
id: msgNode._.get,
outgoing: true,
timestamp: newMessage.timestamp
})
}
})
})
}
/**
* Returns the message id.
* @param {string} recipientPublicKey
* @param {string} body
* @param {UserGUNNode} user
* @param {ISEA} SEA
* @returns {Promise<string>} The message id.
*/
const sendMessage = async (recipientPublicKey, body, user, SEA) =>
(await sendMessageNew(recipientPublicKey, body, user, SEA)).id
/**
* @param {string} recipientPub
* @param {string} msgID
* @param {UserGUNNode} user
* @returns {Promise<void>}
*/
const deleteMessage = async (recipientPub, msgID, user) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
if (typeof recipientPub !== 'string') {
throw new TypeError(
`expected recipientPublicKey to be an string, but instead got: ${typeof recipientPub}`
)
}
if (recipientPub.length === 0) {
throw new TypeError(
'expected recipientPublicKey to be an string of length greater than zero'
)
}
if (typeof msgID !== 'string') {
throw new TypeError(
`expected msgID to be an string, instead got: ${typeof msgID}`
)
}
if (msgID.length === 0) {
throw new TypeError(
'expected msgID to be an string of length greater than zero'
)
}
const outgoingID = await Utils.recipientToOutgoingID(recipientPub)
if (outgoingID === null) {
throw new Error(`Could not fetch an outgoing id for user: ${recipientPub}`)
}
return new Promise((res, rej) => {
user
.get(Key.OUTGOINGS)
.get(outgoingID)
.get(Key.MESSAGES)
.get(msgID)
.put(null, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
} else {
res()
}
})
})
}
/**
* @param {string|null} avatar
* @param {UserGUNNode} user
@ -924,52 +240,6 @@ const setSeedServiceData = (encryptedSeedServiceData, user) =>
})
})
/**
* @param {string} initialMsg
* @param {string} recipientPublicKey
* @param {GUNNode} gun
* @param {UserGUNNode} user
* @param {ISEA} SEA
* @throws {Error|TypeError}
* @returns {Promise<void>}
*/
const sendHRWithInitialMsg = async (
initialMsg,
recipientPublicKey,
gun,
user,
SEA
) => {
/** @type {boolean} */
const alreadyHandshaked = await Utils.tryAndWait(
(_, user) =>
new Promise((res, rej) => {
user
.get(Key.USER_TO_INCOMING)
.get(recipientPublicKey)
.once(inc => {
if (typeof inc !== 'string') {
res(false)
} else if (inc.length === 0) {
rej(
new Error(
`sendHRWithInitialMsg()-> obtained encryptedIncomingId from user-to-incoming an string but of length 0`
)
)
} else {
res(true)
}
})
})
)
if (!alreadyHandshaked) {
await sendHandshakeRequest(recipientPublicKey, gun, user, SEA)
}
await sendMessage(recipientPublicKey, initialMsg, user, SEA)
}
/**
* @typedef {object} SpontPaymentOptions
* @prop {Common.Schema.OrderTargetType} type
@ -1035,7 +305,7 @@ const sendSpontaneousPayment = async (
logger.info('sendPayment() -> will now create order:')
/** @type {Order} */
/** @type {import('shock-common').Schema.Order} */
const order = {
amount: amount.toString(),
from: getUser()._.sea.pub,
@ -1395,18 +665,6 @@ const saveChannelsBackup = async (backups, user, SEA) => {
})
}
/**
* @param {string} pub
* @returns {Promise<void>}
*/
const disconnect = async pub => {
if (!(await Utils.successfulHandshakeAlreadyExists(pub))) {
throw new Error('No handshake exists for this pub')
}
await Promise.all([cleanup(pub), generateHandshakeAddress()])
}
/**
* @returns {Promise<void>}
*/
@ -1789,15 +1047,9 @@ const initWall = async () => {
}
module.exports = {
__createOutgoingFeed,
acceptRequest,
authenticate,
blacklist,
generateHandshakeAddress,
sendHandshakeRequest,
deleteMessage,
sendMessage,
sendHRWithInitialMsg,
setAvatar,
setDisplayName,
sendPayment,
@ -1805,14 +1057,12 @@ module.exports = {
setBio,
saveSeedBackup,
saveChannelsBackup,
disconnect,
setLastSeenApp,
createPost,
deletePost,
follow,
unfollow,
initWall,
sendMessageNew,
sendSpontaneousPayment,
createPostNew,
setDefaultSeedProvider,