Merge branch 'master' into feature/random-secrets

This commit is contained in:
Emad-salah 2020-07-27 22:41:40 +01:00 committed by GitHub
commit 77e8fa696c
15 changed files with 647 additions and 208 deletions

21
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: Update Wizard
on:
push:
branches: [ 'feature/synchronized-wizard-builds' ]
pull_request:
branches: [ 'feature/synchronized-wizard-builds' ]
jobs:
dispatch:
strategy:
matrix:
repo: ['shocknet/Wizard']
runs-on: ubuntu-latest
steps:
- name: Repository Dispatch
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.REPO_ACCESS_TOKEN }}
repository: ${{ matrix.repo }}
event-type: api-update

View file

@ -324,6 +324,18 @@ const authenticate = async (alias, pass, __user) => {
API.Jobs.onAcceptedRequests(_user, mySEA) API.Jobs.onAcceptedRequests(_user, mySEA)
API.Jobs.onOrders(_user, gun, mySEA) API.Jobs.onOrders(_user, gun, mySEA)
API.Jobs.lastSeenNode(_user) API.Jobs.lastSeenNode(_user)
API.Events.onAvatar(() => {}, user)()
API.Events.onBio(() => {}, user)
API.Events.onBlacklist(() => {}, user)
API.Events.onChats(() => {})()
API.Events.onCurrentHandshakeAddress(() => {}, user)()
API.Events.onDisplayName(() => {}, user)()
API.Events.onOutgoing(() => {})()
API.Events.onSeedBackup(() => {}, user, mySEA)
API.Events.onSimplerReceivedRequests(() => {})()
API.Events.onSimplerSentRequests(() => {})()
return _user._.sea.pub return _user._.sea.pub
} }
@ -372,6 +384,17 @@ const authenticate = async (alias, pass, __user) => {
API.Jobs.onOrders(_user, gun, mySEA) API.Jobs.onOrders(_user, gun, mySEA)
API.Jobs.lastSeenNode(_user) API.Jobs.lastSeenNode(_user)
API.Events.onAvatar(() => {}, user)()
API.Events.onBio(() => {}, user)
API.Events.onBlacklist(() => {}, user)
API.Events.onChats(() => {})()
API.Events.onCurrentHandshakeAddress(() => {}, user)()
API.Events.onDisplayName(() => {}, user)()
API.Events.onOutgoing(() => {})()
API.Events.onSeedBackup(() => {}, user, mySEA)
API.Events.onSimplerReceivedRequests(() => {})()
API.Events.onSimplerSentRequests(() => {})()
return ack.sea.pub return ack.sea.pub
} else { } else {
logger.error( logger.error(

View file

@ -372,50 +372,13 @@ const cleanup = async pub => {
const outGoingID = await Utils.recipientToOutgoingID(pub) const outGoingID = await Utils.recipientToOutgoingID(pub)
await new Promise((res, rej) => { const promises = []
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) => { promises.push(
user new Promise((res, rej) => {
.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 user
.get(Key.OUTGOINGS) .get(Key.USER_TO_INCOMING)
.get(outGoingID) .get(pub)
.put(null, ack => { .put(null, ack => {
if (ack.err) { if (ack.err) {
rej(new Error(ack.err)) rej(new Error(ack.err))
@ -424,7 +387,56 @@ const cleanup = async pub => {
} }
}) })
}) })
)
promises.push(
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()
}
})
})
)
promises.push(
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) {
promises.push(
new Promise((res, rej) => {
user
.get(Key.OUTGOINGS)
.get(outGoingID)
.put(null, ack => {
if (ack.err) {
rej(new Error(ack.err))
} else {
res()
}
})
})
)
} }
await Promise.all(promises)
} }
/** /**
@ -631,9 +643,9 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
* @param {string} body * @param {string} body
* @param {UserGUNNode} user * @param {UserGUNNode} user
* @param {ISEA} SEA * @param {ISEA} SEA
* @returns {Promise<string>} The message id. * @returns {Promise<import('shock-common').Schema.ChatMessage>} The message id.
*/ */
const sendMessage = async (recipientPublicKey, body, user, SEA) => { const sendMessageNew = async (recipientPublicKey, body, user, SEA) => {
if (!user.is) { if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH) throw new Error(ErrorCode.NOT_AUTH)
} }
@ -691,12 +703,28 @@ const sendMessage = async (recipientPublicKey, body, user, SEA) => {
if (ack.err) { if (ack.err) {
rej(new Error(ack.err)) rej(new Error(ack.err))
} else { } else {
res(msgNode._.get) 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} recipientPub
* @param {string} msgID * @param {string} msgID
@ -1211,9 +1239,7 @@ const disconnect = async pub => {
throw new Error('No handshake exists for this pub') throw new Error('No handshake exists for this pub')
} }
await cleanup(pub) await Promise.all([cleanup(pub), generateHandshakeAddress()])
await generateHandshakeAddress()
} }
/** /**
@ -1589,5 +1615,6 @@ module.exports = {
deletePost, deletePost,
follow, follow,
unfollow, unfollow,
initWall initWall,
sendMessageNew
} }

View file

@ -329,7 +329,11 @@ const getCurrentOutgoings = () => currentOutgoings
const outgoingsListeners = new Set() const outgoingsListeners = new Set()
outgoingsListeners.add(o => { outgoingsListeners.add(o => {
logger.info(`new outgoings: ${JSON.stringify(o, null, 4)}`) const values = Object.values(o)
const nulls = values.filter(x => x === null).length
const nonNulls = values.length - nulls
logger.info(`new outgoings, ${nulls} nulls and ${nonNulls} nonNulls`)
}) })
const notifyOutgoingsListeners = () => { const notifyOutgoingsListeners = () => {
@ -452,7 +456,7 @@ const getChats = () => currentChats
const chatsListeners = new Set() const chatsListeners = new Set()
chatsListeners.add(c => { chatsListeners.add(c => {
logger.info(`new Chats: ${JSON.stringify(c, null, 4)}`) logger.info(`Chats: ${c.length}`)
}) })
const notifyChatsListeners = () => { const notifyChatsListeners = () => {

View file

@ -2,6 +2,7 @@
const debounce = require('lodash/debounce') const debounce = require('lodash/debounce')
const logger = require('winston') const logger = require('winston')
const { Schema } = require('shock-common') const { Schema } = require('shock-common')
const size = require('lodash/size')
const Key = require('../key') const Key = require('../key')
const Streams = require('../streams') const Streams = require('../streams')
@ -50,6 +51,7 @@ const react = debounce(() => {
for (const [id, req] of Object.entries(currAddressData)) { for (const [id, req] of Object.entries(currAddressData)) {
const inContact = Array.isArray(pubToFeed[req.from]) const inContact = Array.isArray(pubToFeed[req.from])
const isDisconnected = pubToFeed[req.from] === 'disconnected'
if (typeof pubToAvatar[req.from] === 'undefined') { if (typeof pubToAvatar[req.from] === 'undefined') {
// eslint-disable-next-line no-empty-function // eslint-disable-next-line no-empty-function
@ -60,7 +62,7 @@ const react = debounce(() => {
Streams.onDisplayName(() => {}, req.from)() Streams.onDisplayName(() => {}, req.from)()
} }
if (!inContact) { if (!inContact && !isDisconnected) {
newReceivedReqsMap[req.from] = { newReceivedReqsMap[req.from] = {
id, id,
requestorAvatar: pubToAvatar[req.from] || null, requestorAvatar: pubToAvatar[req.from] || null,
@ -95,8 +97,7 @@ const listenerForAddr = addr => data => {
} }
} }
logger.info('data for address: ' + addr) logger.info('data for address length: ' + size(addr))
logger.info(JSON.stringify(data, null, 4))
react() react()
} }

View file

@ -1,6 +1,7 @@
/** @format */ /** @format */
const debounce = require('lodash/debounce') const debounce = require('lodash/debounce')
const logger = require('winston') const logger = require('winston')
const size = require('lodash/size')
const Streams = require('../streams') const Streams = require('../streams')
/** /**
@ -29,7 +30,7 @@ const listeners = new Set()
let currentReqs = [] let currentReqs = []
listeners.add(() => { listeners.add(() => {
logger.info(`new sent reqs: ${JSON.stringify(currentReqs)}`) logger.info(`new sent reqs length: ${size(currentReqs)}`)
}) })
const getCurrentSentReqs = () => currentReqs const getCurrentSentReqs = () => currentReqs
@ -55,9 +56,7 @@ const react = debounce(() => {
// pk to display name // pk to display name
const pubToDN = Streams.getPubToDn() const pubToDN = Streams.getPubToDn()
logger.info( logger.info(`pubToLastSentREqID length: ${size(pubToLastSentReqID)}`)
`pubToLastSentREqID: ${JSON.stringify(pubToLastSentReqID, null, 4)}`
)
for (const storedReq of storedReqs) { for (const storedReq of storedReqs) {
const { handshakeAddress, recipientPub, sentReqID, timestamp } = storedReq const { handshakeAddress, recipientPub, sentReqID, timestamp } = storedReq

View file

@ -28,6 +28,7 @@ exports.currentFollows = async () => {
return true return true
} }
// load sometimes returns an empty set on the first try
if (size(v) === 0) { if (size(v) === 0) {
return true return true
} }

View file

@ -9,6 +9,7 @@ const Utils = require('../utils')
const Wall = require('./wall') const Wall = require('./wall')
const Feed = require('./feed') const Feed = require('./feed')
const User = require('./user') const User = require('./user')
const { size } = require('lodash')
/** /**
* @param {string} pub * @param {string} pub
@ -51,7 +52,18 @@ exports.userToIncomingID = async pub => {
const getMyUser = async () => { const getMyUser = async () => {
const oldProfile = await Utils.tryAndWait( const oldProfile = await Utils.tryAndWait(
(_, user) => new Promise(res => user.get(Key.PROFILE).load(res)), (_, user) => new Promise(res => user.get(Key.PROFILE).load(res)),
v => typeof v !== 'object' v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
}
) )
const bio = await Utils.tryAndWait( const bio = await Utils.tryAndWait(

View file

@ -2,6 +2,7 @@
* @format * @format
*/ */
const Common = require('shock-common') const Common = require('shock-common')
const size = require('lodash/size')
const Key = require('../key') const Key = require('../key')
const Utils = require('../utils') const Utils = require('../utils')
@ -72,7 +73,18 @@ module.exports.getAnUser = getAnUser
const getMyUser = async () => { const getMyUser = async () => {
const oldProfile = await Utils.tryAndWait( const oldProfile = await Utils.tryAndWait(
(_, user) => new Promise(res => user.get(Key.PROFILE).load(res)), (_, user) => new Promise(res => user.get(Key.PROFILE).load(res)),
v => typeof v !== 'object' v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
}
) )
const bio = await Utils.tryAndWait( const bio = await Utils.tryAndWait(

View file

@ -6,6 +6,7 @@ const {
Constants: { ErrorCode }, Constants: { ErrorCode },
Schema Schema
} = require('shock-common') } = require('shock-common')
const size = require('lodash/size')
const Key = require('../key') const Key = require('../key')
const Utils = require('../utils') const Utils = require('../utils')
@ -39,24 +40,31 @@ const onAcceptedRequests = (user, SEA) => {
logger.info( logger.info(
`------------------------------------\nPROCID:${procid} (used for debugging memory leaks in jobs)\n---------------------------------------` `------------------------------------\nPROCID:${procid} (used for debugging memory leaks in jobs)\n---------------------------------------`
) )
const mySecret = require('../../Mediator').getMySecret() const mySecret = require('../../Mediator').getMySecret()
try { try {
if (!Schema.isStoredRequest(storedReq)) { if (!Schema.isStoredRequest(storedReq)) {
logger.warn( throw new Error(
'Stored request not an StoredRequest, instead got: ' + 'Stored request not an StoredRequest, instead got: ' +
JSON.stringify(storedReq) + JSON.stringify(storedReq) +
' this can be due to nulling out an old request (if null) or something else happened (please look at the output)' ' this can be due to nulling out an old request (if null) or something else happened (please look at the output)'
) )
return
} }
// get the recipient pub from the stored request to avoid an attacker
// overwriting the handshake request in the root graph
const recipientPub = await SEA.decrypt(storedReq.recipientPub, mySecret) const recipientPub = await SEA.decrypt(storedReq.recipientPub, mySecret)
if (typeof recipientPub !== 'string') { if (typeof recipientPub !== 'string') {
throw new TypeError() throw new TypeError(
`Expected storedReq.recipientPub to be an string, instead got: ${recipientPub}`
)
} }
if (await Utils.successfulHandshakeAlreadyExists(recipientPub)) { if (await Utils.successfulHandshakeAlreadyExists(recipientPub)) {
return return
} }
const requestAddress = await SEA.decrypt( const requestAddress = await SEA.decrypt(
storedReq.handshakeAddress, storedReq.handshakeAddress,
mySecret mySecret
@ -99,9 +107,9 @@ const onAcceptedRequests = (user, SEA) => {
return return
} }
// The response can be decrypted with the same secret regardless of who // The response can be decrypted with the same secret regardless
// wrote to it last (see HandshakeRequest definition). // of who wrote to it last (see HandshakeRequest definition). This
// This could be our feed ID for the recipient, or the recipient's feed // could be our feed ID for the recipient, or the recipient's feed
// id if he accepted the request. // id if he accepted the request.
const feedID = await SEA.decrypt(sentReq.response, ourSecret) const feedID = await SEA.decrypt(sentReq.response, ourSecret)
@ -126,8 +134,8 @@ const onAcceptedRequests = (user, SEA) => {
res(feed) res(feed)
}) })
}), }),
// retry on undefined, might be a false negative // @ts-expect-error
v => typeof v === 'undefined' v => size(v) === 0
) )
const feedIDExistsOnRecipientsOutgoings = const feedIDExistsOnRecipientsOutgoings =

View file

@ -1,5 +1,6 @@
/** @format */ /** @format */
const logger = require('winston') const logger = require('winston')
const size = require('lodash/size')
const Key = require('../key') const Key = require('../key')
/** /**
@ -13,7 +14,7 @@ const pubToAddress = {}
const listeners = new Set() const listeners = new Set()
listeners.add(() => { listeners.add(() => {
logger.info(`pubToAddress: ${JSON.stringify(pubToAddress, null, 4)}`) logger.info(`pubToAddress length: ${size(pubToAddress)}`)
}) })
const notify = () => listeners.forEach(l => l()) const notify = () => listeners.forEach(l => l())

View file

@ -3,6 +3,7 @@ const uuidv1 = require('uuid/v1')
const logger = require('winston') const logger = require('winston')
const debounce = require('lodash/debounce') const debounce = require('lodash/debounce')
const { Schema, Utils: CommonUtils } = require('shock-common') const { Schema, Utils: CommonUtils } = require('shock-common')
const size = require('lodash/size')
const Key = require('../key') const Key = require('../key')
const Utils = require('../utils') const Utils = require('../utils')
@ -29,7 +30,7 @@ let pubToFeed = {}
const getPubToFeed = () => pubToFeed const getPubToFeed = () => pubToFeed
feedsListeners.add(() => { feedsListeners.add(() => {
logger.info(`new pubToFeed: ${JSON.stringify(getPubToFeed())}`) logger.info(`new pubToFeed length: ${size(getPubToFeed())}`)
}) })
/** @param {Feeds} ptf */ /** @param {Feeds} ptf */

View file

@ -3,6 +3,7 @@ const uuidv1 = require('uuid/v1')
const debounce = require('lodash/debounce') const debounce = require('lodash/debounce')
const logger = require('winston') const logger = require('winston')
const { Utils: CommonUtils } = require('shock-common') const { Utils: CommonUtils } = require('shock-common')
const size = require('lodash/size')
const { USER_TO_INCOMING } = require('../key') const { USER_TO_INCOMING } = require('../key')
/** @typedef {import('../SimpleGUN').OpenListenerData} OpenListenerData */ /** @typedef {import('../SimpleGUN').OpenListenerData} OpenListenerData */
@ -30,9 +31,7 @@ const setPubToIncoming = pti => {
let latestUpdate = uuidv1() let latestUpdate = uuidv1()
listeners.add(() => { listeners.add(() => {
logger.info( logger.info(`new pubToIncoming length: ${size(getPubToIncoming())}`)
`new pubToIncoming: ${JSON.stringify(getPubToIncoming(), null, 4)}`
)
}) })
const onOpen = debounce(async uti => { const onOpen = debounce(async uti => {

View file

@ -13,6 +13,7 @@ const responseTime = require("response-time");
const uuid = require("uuid/v4"); const uuid = require("uuid/v4");
const Common = require('shock-common') const Common = require('shock-common')
const isARealUsableNumber = require('lodash/isFinite') const isARealUsableNumber = require('lodash/isFinite')
const size = require('lodash/size')
const getListPage = require("../utils/paginate"); const getListPage = require("../utils/paginate");
const auth = require("../services/auth/auth"); const auth = require("../services/auth/auth");
@ -23,6 +24,7 @@ const GunDB = require("../services/gunDB/Mediator");
const { unprotectedRoutes, nonEncryptedRoutes } = require("../utils/protectedRoutes"); const { unprotectedRoutes, nonEncryptedRoutes } = require("../utils/protectedRoutes");
const GunActions = require("../services/gunDB/contact-api/actions") const GunActions = require("../services/gunDB/contact-api/actions")
const GunGetters = require('../services/gunDB/contact-api/getters') const GunGetters = require('../services/gunDB/contact-api/getters')
const GunKey = require('../services/gunDB/contact-api/key')
const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10; const DEFAULT_MAX_NUM_ROUTES_TO_QUERY = 10;
const SESSION_ID = uuid(); const SESSION_ID = uuid();
@ -272,8 +274,6 @@ module.exports = async (
app.use(async (req, res, next) => { app.use(async (req, res, next) => {
try { try {
logger.info("Route:", req.path)
if (unprotectedRoutes[req.method][req.path]) { if (unprotectedRoutes[req.method][req.path]) {
next(); next();
return; return;
@ -437,76 +437,6 @@ module.exports = async (
}); });
/*
const feedObj = {
feed: [
{
id:'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
paragraphs:[
"SOme text and stuff 12"
"SOme text and stuff"
],
profilePic:"",
username:"bobni",
media:[
{
type:'VIDEO',
ratio_x: 1024,
ratio_y: 436,
magnetUri:'magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent',
},
]
},
{
id:'3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
paragraphs:[
"SOme text and stuff"
],
profilePic:"",
username:"bobni",
media:[
{
type:'VIDEO',
ratio_x: 1920,
ratio_y: 804,
magnetUri:'magnet:?xt=urn:btih:c9e15763f722f23e98a29decdfae341b98d53056&dn=Cosmos+Laundromat&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fcosmos-laundromat.torrent',
},
]
},
{
id:'58694a0f-3da1-471f-bd96-145571e29d72',
paragraphs:[
"SOme text and stuff"
],
profilePic:"",
username:"bobni",
media:[
{
type:'VIDEO',
ratio_x: 1920,
ratio_y: 1080,
magnetUri:'magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c&dn=Big+Buck+Bunny&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fbig-buck-bunny.torrent',
},
]
}
]
}
user.get("FEED_POC").put(JSON.stringify(feedObj), ack => {
if (ack.err) {
//rej(new Error(ack.err))
}*/
const feedObj = {
feed :{}
}
user.get("FEED_POC").put(feedObj, ack => {
if (ack.err) {
//rej(ack.err)
logger.log(ack.err)
} else {
logger.log(ack.err)
}
})
//register to listen for channel backups //register to listen for channel backups
const onNewChannelBackup = () => { const onNewChannelBackup = () => {
logger.warn("Subscribing to channel backup ...") logger.warn("Subscribing to channel backup ...")
@ -1715,49 +1645,12 @@ module.exports = async (
const Events = require('../services/gunDB/contact-api/events') const Events = require('../services/gunDB/contact-api/events')
app.get(`/api/gun/${GunEvent.ON_RECEIVED_REQUESTS}`, (_, res) => {
try {
// spinup
Events.onSimplerReceivedRequests(() => {})()
const data = Events.getCurrentReceivedReqs()
res.json({
data,
})
} catch (err) {
logger.info('Error in Received Requests poll:')
logger.error(err)
res.status(err.message === 'NON_AUTH' ? 401 : 500).json({
errorMessage: typeof err === 'string' ? err : err.message
})
}
})
app.get(`/api/gun/${GunEvent.ON_SENT_REQUESTS}`, (_, res) => {
try {
// spinup
Events.onSimplerSentRequests(() => {})()
const data = Events.getCurrentSentReqs()
logger.info(`Sent requests poll: ${JSON.stringify(data, null, 4)}`)
res.json({
data,
})
} catch (err) {
logger.info('Error in sentRequests poll:')
logger.error(err)
res.status(err.message === 'NON_AUTH' ? 401 : 500).json({
errorMessage: typeof err === 'string' ? err : err.message
})
}
})
app.get(`/api/gun/${GunEvent.ON_CHATS}`, (_, res) => { app.get(`/api/gun/${GunEvent.ON_CHATS}`, (_, res) => {
try { try {
// spinup
Events.onChats(() => {})()
const data = Events.getChats() const data = Events.getChats()
logger.info(`Chats polled: ${JSON.stringify(data, null, 4)}`) logger.info(`Chats polled: ${data.length}`)
res.json({ res.json({
data data,
}) })
} catch (err) { } catch (err) {
logger.info('Error in Chats poll:') logger.info('Error in Chats poll:')
@ -1772,7 +1665,7 @@ module.exports = async (
try { try {
const user = require('../services/gunDB/Mediator').getUser() const user = require('../services/gunDB/Mediator').getUser()
const data = await timeout5(user.get(Key.PROFILE).get(Key.AVATAR).then()) const data = await timeout5(user.get(Key.PROFILE).get(Key.AVATAR).then())
logger.info(`avatar poll:${data}`) logger.info(`avatar poll:${(data || '').length} chars`)
res.json({ res.json({
data data
}) })
@ -2025,8 +1918,13 @@ module.exports = async (
* @type {RequestHandler<{}>} * @type {RequestHandler<{}>}
*/ */
const apiGunMePut = async (req, res) => { const apiGunMePut = async (req, res) => {
/**
* @typedef {Omit<Common.Schema.User, 'publicKey'>} UserWithoutPK
* @typedef {{ handshakeAddress: boolean }} HasHandshakeAddress
* @typedef {UserWithoutPK & HasHandshakeAddress} MePutBody
*/
try { try {
const { avatar, bio , displayName} = /** @type {Partial<Omit<Common.Schema.User, 'publicKey'>>} */ (req.body) const { avatar, bio , displayName, handshakeAddress } = /** @type {Partial<MePutBody>} */ (req.body)
if (avatar) { if (avatar) {
await GunActions.setAvatar(avatar, require('../services/gunDB/Mediator').getUser()) await GunActions.setAvatar(avatar, require('../services/gunDB/Mediator').getUser())
@ -2040,6 +1938,10 @@ module.exports = async (
await GunActions.setDisplayName(displayName, require('../services/gunDB/Mediator').getUser()) await GunActions.setDisplayName(displayName, require('../services/gunDB/Mediator').getUser())
} }
if (handshakeAddress) {
await GunActions.generateHandshakeAddress();
}
return res.status(200).json({ return res.status(200).json({
ok: true ok: true
}) })
@ -2054,6 +1956,432 @@ module.exports = async (
ap.get(`/api/gun/me`, apiGunMeGet) ap.get(`/api/gun/me`, apiGunMeGet)
ap.put(`/api/gun/me`, apiGunMePut) ap.put(`/api/gun/me`, apiGunMePut)
/**
* @typedef {object} ChatsRouteParams
* @prop {(string|undefined)=} publicKey
*/
/**
* @type {RequestHandler<ChatsRouteParams>}
*/
const apiGunChatsPost = async (req, res) => {
const { publicKey } = req.params
const { body } = req.body
if (!publicKey) {
return res.status(400).json({
errorMessage: `Must specify a publicKey route param for POSTing a message`
})
}
try {
const user = GunDB.getUser()
const SEA = GunDB.mySEA
return res.status(200).json(
await GunActions.sendMessageNew(publicKey,body, user, SEA)
)
} catch (err) {
logger.error(err)
return res.status(500).json({
errorMessage: err.message
})
}
}
/**
* @type {RequestHandler<ChatsRouteParams>}
*/
const apiGunChatsDelete = async (req, res) => {
const { publicKey } = req.params
if (!publicKey) {
return res.status(400).json({
errorMessage: `Must specify a publicKey route param for DELETING a chat`
})
}
try {
await GunActions.disconnect(publicKey)
return res.status(200).json({
ok: true
})
} catch (err) {
logger.error(err)
return res.status(500).json({
errorMessage: err.message
})
}
}
ap.post(`/api/gun/chats/:publicKey?`, apiGunChatsPost)
ap.delete(`/api/gun/chats/:publicKey?`, apiGunChatsDelete)
/**
* @typedef {object} RequestsRouteParams
* @prop {(string|undefined)=} requestID
*/
/**
* @type {RequestHandler<{}>}
*/
const apiGunRequestsReceivedGet = (_, res) => {
try {
const data = Events.getCurrentReceivedReqs()
res.json({
data,
})
} catch (err) {
logger.error(err)
return res.status(500).json({
errorMessage: err.message
})
}
}
/**
* @type {RequestHandler<{}>}
*/
const apiGunRequestsSentGet = (_, res) => {
try {
const data = Events.getCurrentSentReqs()
res.json({
data,
})
} catch (err) {
logger.error(err)
return res.status(500).json({
errorMessage: err.message
})
}
}
/**
* @typedef {object} RequestsRoutePOSTBody
* @prop {string=} initialMsg
* @prop {string} publicKey
*/
/**
* @type {RequestHandler<{}>}
*/
const apiGunRequestsPost = async (req, res) => {
const { initialMsg, publicKey } = /** @type {RequestsRoutePOSTBody} */(req.body)
if (!publicKey) {
return res.status(400).json({
errorMessage: `Must specify a publicKey route param for POSTing a message`
})
}
try {
const gun = require('../services/gunDB/Mediator').getGun()
const user = require('../services/gunDB/Mediator').getUser()
const SEA = require('../services/gunDB/Mediator').mySEA
if (initialMsg) {
await GunActions.sendHRWithInitialMsg(initialMsg, publicKey, gun, user, SEA)
} else {
await GunActions.sendHandshakeRequest(publicKey, gun, user, SEA)
}
return res.status(200).json({
ok: true
})
} catch (err) {
logger.error(err);
return res.status(500).json({
errorMessage: err.message
})
}
}
/**
* @typedef {object} RequestsRoutePUTBody
* @prop {boolean=} accept
*/
/**
* @type {RequestHandler<RequestsRouteParams>}
*/
const apiGunRequestsPut = async (req, res) => {
const { requestID } = req.params
const { accept } = /** @type {RequestsRoutePUTBody} */(req.body)
if (!requestID) {
return res.status(400).json({
errorMessage: `Must specify a requestID route param for accepting a request`
})
}
if (!accept) {
return res.status(200).json({
ok: true
})
}
try {
const gun = require('../services/gunDB/Mediator').getGun()
const user = require('../services/gunDB/Mediator').getUser()
const SEA = require('../services/gunDB/Mediator').mySEA
await GunActions.acceptRequest(requestID, gun, user, SEA)
return res.status(200).json({
ok: true
})
} catch (err) {
logger.error(err);
return res.status(500).json({
errorMessage: err.message
})
}
}
ap.get(`/api/gun/${GunEvent.ON_RECEIVED_REQUESTS}`, apiGunRequestsReceivedGet)
ap.get(`/api/gun/${GunEvent.ON_SENT_REQUESTS}`, apiGunRequestsSentGet)
ap.get(`/api/gun/requests/received`, apiGunRequestsReceivedGet)
ap.get(`/api/gun/requests/sent`, apiGunRequestsSentGet)
ap.post('/api/gun/requests/', apiGunRequestsPost)
ap.put(`/api/gun/requests/:requestID?`, apiGunRequestsPut)
ap.get(`/api/gun/dev/userToIncoming`, async (_, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((_, u) => new Promise(res => {
u.get(GunKey.USER_TO_INCOMING).load(data => {
res(data)
})
}), v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/recipientToOutgoing`, async (_, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((_, u) => new Promise(res => {
u.get(GunKey.RECIPIENT_TO_OUTGOING).load(data => {
res(data)
})
}), v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/outgoings`, async (_, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((_, u) => new Promise(res => {
u.get(GunKey.OUTGOINGS).load(data => {
res(data)
})
}), v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/currentHandshakeAddress`, async (_, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((_, u) => u.get(GunKey.CURRENT_HANDSHAKE_ADDRESS).then())
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/handshakeNodes/:handshakeAddress`, async (req, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((g) =>
new Promise((res) => {
g.get(GunKey.HANDSHAKE_NODES).get(req.params.handshakeAddress).load(data => {
res(data)
})
})
, v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/user/:publicKey`, async (req, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((g) =>
new Promise((res) => {
g.user(req.params.publicKey).load(data => {
res(data)
})
})
, v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/storedReqs`, async (req, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((_, u) =>
new Promise((res) => u.get(Key.STORED_REQS).load(res))
, v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
ap.get(`/api/gun/dev/userToLastReqSent`, async (req, res) => {
try {
const {tryAndWait} = require('../services/gunDB/contact-api/utils')
const data = await tryAndWait((_, u) =>
new Promise((res) => u.get(Key.USER_TO_LAST_REQUEST_SENT).load(res))
, v => {
if (typeof v !== 'object') {
return true
}
if (v === null) {
return true
}
// load sometimes returns an empty set on the first try
return size(v) === 0
})
return res.status(200).json({
data
})
} catch (err) {
return res.status(500).json({
errorMessage: err.message
})
}
})
/** /**
* Return app so that it can be used by express. * Return app so that it can be used by express.
*/ */

View file

@ -198,28 +198,30 @@ const server = program => {
}) })
app.use((req, res, next) => { app.use((req, res, next) => {
if (sensitiveRoutes[req.method][req.path]) { if (process.env.ROUTE_LOGGING === 'true') {
logger.info( if (sensitiveRoutes[req.method][req.path]) {
JSON.stringify({ logger.info(
time: new Date(), JSON.stringify({
ip: req.ip, time: new Date(),
method: req.method, ip: req.ip,
path: req.path, method: req.method,
sessionId: req.sessionId path: req.path,
}) sessionId: req.sessionId
) })
} else { )
logger.info( } else {
JSON.stringify({ logger.info(
time: new Date(), JSON.stringify({
ip: req.ip, time: new Date(),
method: req.method, ip: req.ip,
path: req.path, method: req.method,
body: req.body, path: req.path,
query: req.query, body: req.body,
sessionId: req.sessionId query: req.query,
}) sessionId: req.sessionId
) })
)
}
} }
next() next()
}) })