diff --git a/.env.example b/.env.example
index 83e2ce68..ce097770 100644
--- a/.env.example
+++ b/.env.example
@@ -5,5 +5,6 @@ DISABLE_SHOCK_ENCRYPTION=false
CACHE_HEADERS_MANDATORY=true
SHOCK_CACHE=true
TRUSTED_KEYS=true
+LOCAL_TUNNEL_SERVER=https://tunnel.rip
TORRENT_SEED_URL=https://webtorrent.shock.network
TORRENT_SEED_TOKEN=jibberish
\ No newline at end of file
diff --git a/README.md b/README.md
index c7dcc9c1..c3cde0d8 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
ShockAPI
-
+
[](http://makeapullrequest.com)
[](https://t.me/Shockwallet)
[](https://twitter.com/shockbtc)
diff --git a/config/defaults.js b/config/defaults.js
index 356edbb1..a44376f4 100644
--- a/config/defaults.js
+++ b/config/defaults.js
@@ -49,6 +49,7 @@ module.exports = (mainnet = false) => {
lndDirPath: lndDirectory,
peers: ['https://gun.shock.network:8765/gun'],
useTLS: false,
- tokenExpirationMS: 259200000
+ tokenExpirationMS: 259200000,
+ localtunnelHost:'https://tunnel.rip'
};
};
diff --git a/main.js b/main.js
index 29f478bb..7f1ae125 100644
--- a/main.js
+++ b/main.js
@@ -6,26 +6,18 @@ const {version} = (JSON.parse(require('fs').readFileSync("./package.json", "utf-
program
.version(version)
.option("-s, --serverport [port]", "web server http listening port (defaults to 8280)")
- .option("-x, --httpsport [port]", "web server https listening port (defaults to 8283)")
.option("-h, --serverhost [host]", "web server listening host (defaults to localhost)")
.option("-l, --lndhost [host:port]", "RPC lnd host (defaults to localhost:10009)")
- .option("-t, --usetls [path]", "path to a directory containing key.pem and cert.pem files")
.option("-u, --user [login]", "basic authentication login")
.option("-p, --pwd [password]", "basic authentication password")
- .option("-r, --limituser [login]", "basic authentication login for readonly account")
- .option("-w, --limitpwd [password]", "basic authentication password for readonly account")
.option("-m, --macaroon-path [file path]", "path to admin.macaroon file")
.option("-d, --lnd-cert-path [file path]", "path to LND cert file")
.option("-f, --logfile [file path]", "path to file where to store the application logs")
.option("-e, --loglevel [level]", "level of logs to display (debug, info, warn, error)")
- .option("-n, --lndlogfile ", "path to lnd log file to send to browser")
.option("-k, --le-email [email]", "lets encrypt required contact email")
.option("-c, --mainnet", "run server on mainnet mode")
+ .option("-t, --tunnel","create a localtunnel to listen behind a firewall")
.parse(process.argv);
// load server
-if (program.serverhost && program.leEmail) {
- require("./app/server-le")(program); // Let"s Encrypt server version
-} else {
- require("./src/server")(program); // Standard server version
-}
+require("./src/server")(program); // Standard server version
diff --git a/package.json b/package.json
index 6debf058..7955cca1 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"dependencies": {
"@grpc/grpc-js": "^1.2.2",
"@grpc/proto-loader": "^0.5.5",
+ "assert-never": "^1.2.1",
"axios": "^0.21.1",
"basic-auth": "^2.0.0",
"big.js": "^5.2.2",
@@ -41,18 +42,19 @@
"husky": "^4.2.5",
"jsonfile": "^4.0.0",
"jsonwebtoken": "^8.3.0",
- "localtunnel": "^1.9.0",
+ "localtunnel": "git://github.com/shocknet/localtunnel#40cc2c2a46b05da2217bf2e20da11a5343a5cce7",
"lodash": "^4.17.20",
"method-override": "^2.3.7",
"node-fetch": "^2.6.1",
"node-persist": "^3.1.0",
"promise": "^8.1.0",
+ "qrcode-terminal": "^0.12.0",
"ramda": "^0.27.1",
"request": "^2.88.2",
"request-promise": "^4.2.6",
"response-time": "^2.3.2",
"shelljs": "^0.8.2",
- "shock-common": "31.1.0",
+ "shock-common": "32.0.0",
"socket.io": "2.1.1",
"text-encoding": "^0.7.0",
"tingodb": "^0.6.1",
@@ -68,6 +70,7 @@
"@types/jest": "^24.0.18",
"@types/jsonwebtoken": "^8.3.7",
"@types/lodash": "^4.14.141",
+ "@types/node-fetch": "^2.5.8",
"@types/ramda": "types/npm-ramda#dist",
"@types/react": "16.x.x",
"@types/socket.io": "^2.1.11",
@@ -86,7 +89,7 @@
"rimraf": "^3.0.2",
"ts-node": "^9.1.1",
"ts-type": "^1.2.16",
- "typescript": "^4.0.2"
+ "typescript": "latest"
},
"lint-staged": {
"*.js": [
diff --git a/services/coordinates.js b/services/coordinates.js
new file mode 100644
index 00000000..d56981bb
--- /dev/null
+++ b/services/coordinates.js
@@ -0,0 +1,63 @@
+/**
+ * @format
+ */
+
+const Common = require('shock-common')
+const mapValues = require('lodash/mapValues')
+const pickBy = require('lodash/pickBy')
+const Bluebird = require('bluebird')
+const Logger = require('winston')
+const Key = require('../services/gunDB/contact-api/key')
+
+const { getUser, getMySecret, mySEA } = require('./gunDB/Mediator')
+
+/**
+ * @param {string} coordID
+ * @param {Common.Coordinate} data
+ * @returns {Promise}
+ */
+module.exports.writeCoordinate = async (coordID, data) => {
+ if (coordID !== data.id) {
+ throw new Error('CoordID must be equal to data.id')
+ }
+
+ try {
+ /**
+ * Because there are optional properties, typescript can also allow them
+ * to be specified but with a value of `undefined`. Filter out these.
+ * @type {Record}
+ */
+ const sanitizedData = pickBy(data, v => typeof v !== 'undefined')
+
+ const encData = await Bluebird.props(
+ mapValues(sanitizedData, v => {
+ return mySEA.encrypt(v, getMySecret())
+ })
+ )
+
+ getUser()
+ .get(Key.COORDINATES)
+ .get(coordID)
+ .put(encData, ack => {
+ if (ack.err && typeof ack.err !== 'number') {
+ Logger.info(
+ `Error writting corrdinate, coordinate id: ${coordID}, data: ${JSON.stringify(
+ data,
+ null,
+ 2
+ )}`
+ )
+ Logger.error(ack.err)
+ }
+ })
+ } catch (e) {
+ Logger.info(
+ `Error writing coordinate, coordinate id: ${coordID}, data: ${JSON.stringify(
+ data,
+ null,
+ 2
+ )}`
+ )
+ Logger.error(e.message)
+ }
+}
diff --git a/services/gunDB/Mediator/index.js b/services/gunDB/Mediator/index.js
index e7914de8..eddb2466 100644
--- a/services/gunDB/Mediator/index.js
+++ b/services/gunDB/Mediator/index.js
@@ -314,7 +314,7 @@ const authenticate = async (alias, pass, __user) => {
// clock skew
await new Promise(res => setTimeout(res, 2000))
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
_user.get(Key.FOLLOWS).put(
{
unused: null
@@ -327,7 +327,7 @@ const authenticate = async (alias, pass, __user) => {
}
}
)
- })
+ }))
return ack.sea.pub
} else {
@@ -345,7 +345,7 @@ const authenticate = async (alias, pass, __user) => {
// clock skew
await new Promise(res => setTimeout(res, 2000))
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
_user.get(Key.FOLLOWS).put(
{
unused: null
@@ -358,7 +358,7 @@ const authenticate = async (alias, pass, __user) => {
}
}
)
- })
+ }))
// move this to a subscription; implement off() ? todo
API.Jobs.onAcceptedRequests(_user, mySEA)
@@ -404,7 +404,7 @@ const authenticate = async (alias, pass, __user) => {
await new Promise(res => setTimeout(res, 5000))
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
_user.get(Key.FOLLOWS).put(
{
unused: null
@@ -417,7 +417,7 @@ const authenticate = async (alias, pass, __user) => {
}
}
)
- })
+ }))
API.Jobs.onAcceptedRequests(_user, mySEA)
API.Jobs.onOrders(_user, gun, mySEA)
diff --git a/services/gunDB/contact-api/actions.js b/services/gunDB/contact-api/actions.js
index c03e0307..05bf741d 100644
--- a/services/gunDB/contact-api/actions.js
+++ b/services/gunDB/contact-api/actions.js
@@ -11,7 +11,8 @@ const { ErrorCode } = Constants
const {
sendPaymentV2Invoice,
- decodePayReq
+ decodePayReq,
+ myLNDPub
} = require('../../../utils/lightningServices/v2')
/**
@@ -100,7 +101,7 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => {
timestamp: Date.now()
}
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.OUTGOINGS)
.get(newOutgoingFeedID)
@@ -113,14 +114,14 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => {
res()
}
})
- })
+ }))
const encryptedForMeNewOutgoingFeedID = await SEA.encrypt(
newOutgoingFeedID,
mySecret
)
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.RECIPIENT_TO_OUTGOING)
.get(withPublicKey)
@@ -131,7 +132,7 @@ const __createOutgoingFeed = async (withPublicKey, user, SEA) => {
res()
}
})
- })
+ }))
outgoingFeedID = newOutgoingFeedID
}
@@ -237,7 +238,7 @@ const acceptRequest = async (
const mySecret = require('../Mediator').getMySecret()
const encryptedForMeIncomingID = await SEA.encrypt(incomingID, mySecret)
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_INCOMING)
.get(senderPublicKey)
@@ -248,7 +249,7 @@ const acceptRequest = async (
res()
}
})
- })
+ }))
////////////////////////////////////////////////////////////////////////////
// NOTE: perform non-reversable actions before destructive actions
@@ -261,7 +262,7 @@ const acceptRequest = async (
ourSecret
)
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
gun
.get(Key.HANDSHAKE_NODES)
.get(handshakeAddress)
@@ -278,7 +279,7 @@ const acceptRequest = async (
}
}
)
- })
+ }))
}
/**
@@ -287,7 +288,7 @@ const acceptRequest = async (
* @param {UserGUNNode} userNode
*/
const authenticate = (user, pass, userNode) =>
- new Promise((resolve, reject) => {
+ /** @type {Promise} */ (new Promise((resolve, reject) => {
if (typeof user !== 'string') {
throw new TypeError('expected user to be of type string')
}
@@ -317,7 +318,7 @@ const authenticate = (user, pass, userNode) =>
resolve()
}
})
- })
+ }))
/**
* @param {string} publicKey
@@ -349,7 +350,7 @@ const generateHandshakeAddress = async () => {
const address = uuidv1()
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user.get(Key.CURRENT_HANDSHAKE_ADDRESS).put(address, ack => {
if (ack.err && typeof ack.err !== 'number') {
rej(new Error(ack.err))
@@ -357,9 +358,9 @@ const generateHandshakeAddress = async () => {
res()
}
})
- })
+ }))
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
gun
.get(Key.HANDSHAKE_NODES)
.get(address)
@@ -370,7 +371,7 @@ const generateHandshakeAddress = async () => {
res()
}
})
- })
+ }))
}
/**
@@ -387,7 +388,7 @@ const cleanup = async pub => {
const promises = []
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_INCOMING)
.get(pub)
@@ -398,11 +399,11 @@ const cleanup = async pub => {
res()
}
})
- })
+ }))
)
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.RECIPIENT_TO_OUTGOING)
.get(pub)
@@ -413,11 +414,11 @@ const cleanup = async pub => {
res()
}
})
- })
+ }))
)
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_LAST_REQUEST_SENT)
.get(pub)
@@ -428,12 +429,12 @@ const cleanup = async pub => {
res()
}
})
- })
+ }))
)
if (outGoingID) {
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.OUTGOINGS)
.get(outGoingID)
@@ -444,7 +445,7 @@ const cleanup = async pub => {
res()
}
})
- })
+ }))
)
}
@@ -618,7 +619,7 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
})
})
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_LAST_REQUEST_SENT)
.get(recipientPublicKey)
@@ -629,7 +630,7 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
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
@@ -644,7 +645,7 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
timestamp
}
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
//@ts-ignore
user.get(Key.STORED_REQS).set(storedReq, ack => {
if (ack.err && typeof ack.err !== 'number') {
@@ -657,7 +658,7 @@ const sendHandshakeRequest = async (recipientPublicKey, gun, user, SEA) => {
res()
}
})
- })
+ }))
}
/**
@@ -1210,7 +1211,7 @@ const generateOrderAddress = user =>
* @returns {Promise}
*/
const setBio = (bio, user) =>
- new Promise((resolve, reject) => {
+ /** @type {Promise} */ (new Promise((resolve, reject) => {
if (!user.is) {
throw new Error(ErrorCode.NOT_AUTH)
}
@@ -1234,7 +1235,7 @@ const setBio = (bio, user) =>
resolve()
}
})
- }).then(
+ })).then(
() =>
new Promise((resolve, reject) => {
user
@@ -1318,7 +1319,7 @@ const disconnect = async pub => {
* @returns {Promise}
*/
const setLastSeenApp = () =>
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
require('../Mediator')
.getUser()
.get(Key.LAST_SEEN_APP)
@@ -1329,7 +1330,7 @@ const setLastSeenApp = () =>
res()
}
})
- }).then(
+ })).then(
() =>
new Promise((res, rej) => {
require('../Mediator')
@@ -1350,10 +1351,10 @@ const setLastSeenApp = () =>
* @param {string[]} tags
* @param {string} title
* @param {Common.Schema.ContentItem[]} content
- * @param {ISEA} SEA
* @returns {Promise<[string, Common.Schema.RawPost]>}
*/
-const createPostNew = async (tags, title, content, SEA) => {
+const createPostNew = async (tags, title, content) => {
+ const SEA = require('../Mediator').mySEA
/** @type {Common.Schema.RawPost} */
const newPost = {
date: Date.now(),
@@ -1362,10 +1363,13 @@ const createPostNew = async (tags, title, content, SEA) => {
title,
contentItems: {}
}
+
const mySecret = require('../Mediator').getMySecret()
+
await Common.Utils.asyncForEach(content, async c => {
// @ts-expect-error
const uuid = Gun.text.random()
+ newPost.contentItems[uuid] = c
if (
(c.type === 'image/embedded' || c.type === 'video/embedded') &&
c.isPrivate
@@ -1459,7 +1463,7 @@ const createPost = async (tags, title, content, SEA) => {
pageIdx = Number(pageIdx + 1).toString()
}
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
require('../Mediator')
.getUser()
.get(Key.WALL)
@@ -1480,7 +1484,7 @@ const createPost = async (tags, title, content, SEA) => {
res()
}
)
- })
+ }))
const [postID, newPost] = await createPostNew(tags, title, content, SEA)
@@ -1506,7 +1510,7 @@ const createPost = async (tags, title, content, SEA) => {
})
if (shouldBeNewPage || numOfPages === 0) {
- await new Promise(res => {
+ await /** @type {Promise} */ (new Promise(res => {
require('../Mediator')
.getUser()
.get(Key.WALL)
@@ -1518,7 +1522,7 @@ const createPost = async (tags, title, content, SEA) => {
res()
})
- })
+ }))
}
const loadedPost = await new Promise(res => {
@@ -1561,7 +1565,7 @@ const createPost = async (tags, title, content, SEA) => {
* @returns {Promise}
*/
const deletePost = async (postId, page) => {
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
require('../Mediator')
.getUser()
.get(Key.WALL)
@@ -1576,15 +1580,15 @@ const deletePost = async (postId, page) => {
res()
}
})
- })
+ }))
}
/**
* @param {string} publicKey
* @param {boolean} isPrivate Will overwrite previous private status.
- * @returns {Promise}
+ * @returns {Promise}
*/
-const follow = (publicKey, isPrivate) => {
+const follow = async (publicKey, isPrivate) => {
/** @type {import('shock-common').Schema.Follow} */
const newFollow = {
private: isPrivate,
@@ -1592,7 +1596,7 @@ const follow = (publicKey, isPrivate) => {
user: publicKey
}
- return new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
require('../Mediator')
.getUser()
.get(Key.FOLLOWS)
@@ -1605,7 +1609,7 @@ const follow = (publicKey, isPrivate) => {
res()
}
})
- })
+ }))
}
/**
@@ -1637,7 +1641,7 @@ const initWall = async () => {
const promises = []
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.WALL)
.get(Key.NUM_OF_PAGES)
@@ -1648,11 +1652,11 @@ const initWall = async () => {
res()
}
})
- })
+ }))
)
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.WALL)
.get(Key.PAGES)
@@ -1670,11 +1674,11 @@ const initWall = async () => {
}
}
)
- })
+ }))
)
promises.push(
- new Promise((res, rej) => {
+ /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.WALL)
.get(Key.PAGES)
@@ -1687,7 +1691,7 @@ const initWall = async () => {
res()
}
})
- })
+ }))
)
await Promise.all(promises)
diff --git a/services/gunDB/contact-api/jobs/onAcceptedRequests.js b/services/gunDB/contact-api/jobs/onAcceptedRequests.js
index ba9cad5a..255cc107 100644
--- a/services/gunDB/contact-api/jobs/onAcceptedRequests.js
+++ b/services/gunDB/contact-api/jobs/onAcceptedRequests.js
@@ -92,7 +92,7 @@ const onAcceptedRequests = (user, SEA) => {
const recipientEpub = await Utils.pubToEpub(recipientPub)
const ourSecret = await SEA.secret(recipientEpub, user._.sea)
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
gun
.get(Key.HANDSHAKE_NODES)
.get(requestAddress)
@@ -151,7 +151,7 @@ const onAcceptedRequests = (user, SEA) => {
mySecret
)
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.USER_TO_INCOMING)
.get(recipientPub)
@@ -162,9 +162,9 @@ const onAcceptedRequests = (user, SEA) => {
res()
}
})
- })
+ }))
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
user
.get(Key.STORED_REQS)
.get(id)
@@ -175,12 +175,12 @@ const onAcceptedRequests = (user, SEA) => {
res()
}
})
- })
+ }))
// ensure this listeners gets called at least once
res()
})
- })
+ }))
} catch (err) {
logger.warn(`Jobs.onAcceptedRequests() -> ${err.message}`)
logger.error(err)
diff --git a/services/gunDB/contact-api/jobs/onOrders.js b/services/gunDB/contact-api/jobs/onOrders.js
index cede83c6..54c56d9d 100644
--- a/services/gunDB/contact-api/jobs/onOrders.js
+++ b/services/gunDB/contact-api/jobs/onOrders.js
@@ -18,9 +18,14 @@ const {
} = Common
const SchemaManager = require('../../../schema')
const LightningServices = require('../../../../utils/lightningServices')
-
+const {
+ addInvoice,
+ myLNDPub
+} = require('../../../../utils/lightningServices/v2')
+const { writeCoordinate } = require('../../../coordinates')
const Key = require('../key')
const Utils = require('../utils')
+const { gunUUID } = require('../../../../utils')
const getUser = () => require('../../Mediator').getUser()
@@ -60,28 +65,6 @@ const ordersProcessed = new Set()
let currentOrderAddr = ''
-/**
- * @param {InvoiceRequest} invoiceReq
- * @returns {Promise}
- */
-const _addInvoice = invoiceReq =>
- new Promise((resolve, rej) => {
- const {
- services: { lightning }
- } = LightningServices
-
- lightning.addInvoice(invoiceReq, (
- /** @type {any} */ error,
- /** @type {InvoiceResponse} */ response
- ) => {
- if (error) {
- rej(error)
- } else {
- resolve(response)
- }
- })
- })
-
/**
* @param {string} addr
* @param {ISEA} SEA
@@ -118,8 +101,6 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
)} -- addr: ${addr}`
)
- const orderAnswerStartTime = performance.now()
-
const alreadyAnswered = await getUser()
.get(Key.ORDER_TO_RESPONSE)
.get(orderID)
@@ -130,12 +111,6 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
return
}
- const orderAnswerEndTime = performance.now() - orderAnswerStartTime
-
- logger.info(`[PERF] Order Already Answered: ${orderAnswerEndTime}ms`)
-
- const decryptStartTime = performance.now()
-
const senderEpub = await Utils.pubToEpub(order.from)
const secret = await SEA.secret(senderEpub, getUser()._.sea)
@@ -144,10 +119,6 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
SEA.decrypt(order.memo, secret)
])
- const decryptEndTime = performance.now() - decryptStartTime
-
- logger.info(`[PERF] Decrypt invoice info: ${decryptEndTime}ms`)
-
const amount = Number(decryptedAmount)
if (!isNumber(amount)) {
@@ -179,26 +150,19 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
`onOrders() -> Will now create an invoice : ${JSON.stringify(invoiceReq)}`
)
- const invoiceStartTime = performance.now()
-
- const invoice = await _addInvoice(invoiceReq)
-
- const invoiceEndTime = performance.now() - invoiceStartTime
-
- logger.info(`[PERF] LND Invoice created in ${invoiceEndTime}ms`)
+ const invoice = await addInvoice(
+ invoiceReq.value,
+ invoiceReq.memo,
+ true,
+ invoiceReq.expiry
+ )
logger.info(
'onOrders() -> Successfully created the invoice, will now encrypt it'
)
- const invoiceEncryptStartTime = performance.now()
-
const encInvoice = await SEA.encrypt(invoice.payment_request, secret)
- const invoiceEncryptEndTime = performance.now() - invoiceEncryptStartTime
-
- logger.info(`[PERF] Invoice encrypted in ${invoiceEncryptEndTime}ms`)
-
logger.info(
`onOrders() -> Will now place the encrypted invoice in order to response usergraph: ${addr}`
)
@@ -213,9 +177,7 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
ackNode
}
- const invoicePutStartTime = performance.now()
-
- await new Promise((res, rej) => {
+ await /** @type {Promise} */ (new Promise((res, rej) => {
getUser()
.get(Key.ORDER_TO_RESPONSE)
.get(orderID)
@@ -231,11 +193,9 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
res()
}
})
- })
+ }))
- const invoicePutEndTime = performance.now() - invoicePutStartTime
-
- logger.info(`[PERF] Added invoice to GunDB in ${invoicePutEndTime}ms`)
+ //logger.info(`[PERF] Added invoice to GunDB in ${invoicePutEndTime}ms`)
/**
*
* @param {Common.Schema.InvoiceWhenListed & {r_hash:Buffer,payment_addr:string}} paidInvoice
@@ -261,7 +221,8 @@ const listenerForAddr = (addr, SEA) => async (order, orderID) => {
}
getUser()
.get('postToTipCount')
- .get(postID)
+ // CAST: Checked above.
+ .get(/** @type {string} */ (order.ackInfo))
.set(null) // each item in the set is a tip
break
}
diff --git a/services/gunDB/contact-api/utils/index.js b/services/gunDB/contact-api/utils/index.js
index bcab3105..3af89742 100644
--- a/services/gunDB/contact-api/utils/index.js
+++ b/services/gunDB/contact-api/utils/index.js
@@ -212,29 +212,19 @@ const tryAndWait = async (promGen, shouldRetry = () => false) => {
*/
const pubToEpub = async pub => {
try {
- const epub = await tryAndWait(async gun => {
- const _epub = await CommonUtils.makePromise(res => {
- gun
+ const epub = await timeout10(
+ CommonUtils.makePromise(res => {
+ require('../../Mediator/index')
+ .getGun()
.user(pub)
.get('epub')
- .once(
- data => {
+ .on(data => {
+ if (typeof data === 'string') {
res(data)
- },
- {
- wait: 1000
}
- )
+ })
})
-
- if (typeof _epub !== 'string') {
- throw new TypeError(
- `Expected gun.user(pub).get(epub) to be an string. Instead got: ${typeof _epub}`
- )
- }
-
- return _epub
- })
+ )
return epub
} catch (err) {
diff --git a/src/server.js b/src/server.js
index 5de6dbd7..02f7c033 100644
--- a/src/server.js
+++ b/src/server.js
@@ -6,6 +6,7 @@
* Module dependencies.
*/
const server = program => {
+ const localtunnel = require('localtunnel')
const Http = require('http')
const Express = require('express')
const Crypto = require('crypto')
@@ -21,6 +22,7 @@ const server = program => {
const bodyParser = require('body-parser')
const session = require('express-session')
const methodOverride = require('method-override')
+ const qrcode = require('qrcode-terminal')
const {
unprotectedRoutes,
sensitiveRoutes,
@@ -36,6 +38,7 @@ const server = program => {
const serverPort = program.serverport || defaults.serverPort
const serverHost = program.serverhost || defaults.serverHost
+ const tunnelHost = process.env.LOCAL_TUNNEL_SERVER || defaults.localtunnelHost
// setup winston logging ==========
const logger = require('../config/log')(
@@ -158,6 +161,10 @@ const server = program => {
// eslint-disable-next-line consistent-return
const startServer = async () => {
+ /**
+ * @type {localtunnel.Tunnel}
+ */
+ let tunnelRef = null
try {
LightningServices.setDefaults(program)
if (!LightningServices.isInitialized()) {
@@ -220,6 +227,49 @@ const server = program => {
await Storage.init({
dir: storageDirectory
})
+ if (program.tunnel) {
+ // setup localtunnel ==========
+ const [tunnelToken, tunnelSubdomain, tunnelUrl] = await Promise.all([
+ Storage.getItem('tunnel/token'),
+ Storage.getItem('tunnel/subdomain'),
+ Storage.getItem('tunnel/url')
+ ])
+ const tunnelOpts = { port: serverPort, host: tunnelHost }
+ if (tunnelToken && tunnelSubdomain) {
+ tunnelOpts.tunnelToken = tunnelToken
+ tunnelOpts.subdomain = tunnelSubdomain
+ logger.info('Recreating tunnel... with subdomain: ' + tunnelSubdomain)
+ } else {
+ logger.info('Creating new tunnel... ')
+ }
+ const tunnel = await localtunnel(tunnelOpts)
+ tunnelRef = tunnel
+ logger.info('Tunnel created! connect to: ' + tunnel.url)
+ const dataToQr = JSON.stringify({
+ internalIP: tunnel.url,
+ walletPort: 443,
+ externalIP: tunnel.url
+ })
+ qrcode.generate(dataToQr, { small: true })
+ if (!tunnelToken) {
+ await Promise.all([
+ Storage.setItem('tunnel/token', tunnel.token),
+ Storage.setItem('tunnel/subdomain', tunnel.clientId),
+ Storage.setItem('tunnel/url', tunnel.url)
+ ])
+ }
+ if (tunnelUrl && tunnel.url !== tunnelUrl) {
+ logger.error('New tunnel URL different from OLD tunnel url')
+ logger.error('OLD: ' + tunnelUrl + ':80')
+ logger.error('NEW: ' + tunnel.url + ':80')
+ logger.error('New pair required')
+ await Promise.all([
+ Storage.setItem('tunnel/token', tunnel.token),
+ Storage.setItem('tunnel/subdomain', tunnel.clientId),
+ Storage.setItem('tunnel/url', tunnel.url)
+ ])
+ }
+ }
const getSessionSecret = async () => {
const sessionSecret = await Storage.getItem('config/sessionSecret')
@@ -317,6 +367,9 @@ const server = program => {
} catch (err) {
logger.error({ exception: err, message: err.message, code: err.code })
logger.info('Restarting server in 30 seconds...')
+ if (tunnelRef) {
+ tunnelRef.close()
+ }
await wait(30)
startServer()
return false
diff --git a/src/sockets.js b/src/sockets.js
index 353435f2..7404745e 100644
--- a/src/sockets.js
+++ b/src/sockets.js
@@ -67,66 +67,6 @@ module.exports = (
}
}
- const parseJSON = data => {
- try {
- if (typeof data === 'string') {
- return JSON.parse(data)
- }
-
- return data
- } catch (err) {
- return data
- }
- }
-
- const decryptEvent = ({ eventName, data, socket }) => {
- try {
- const deviceId = socket.handshake.query['x-shockwallet-device-id']
- if (Encryption.isNonEncrypted(eventName)) {
- return data
- }
-
- if (!data) {
- return data
- }
-
- const parsedData = parseJSON(data)
-
- if (!deviceId) {
- throw {
- field: 'deviceId',
- message: 'Please specify a device ID'
- }
- }
-
- if (!Encryption.isAuthorizedDevice({ deviceId })) {
- throw {
- field: 'deviceId',
- message: 'Please exchange keys with the API before using the socket'
- }
- }
-
- const decryptedKey = Encryption.decryptKey({
- deviceId,
- message: parsedData.encryptedKey
- })
- const decryptedMessage = Encryption.decryptMessage({
- message: parsedData.encryptedData,
- key: decryptedKey,
- iv: parsedData.iv
- })
- const decryptedData = JSON.parse(decryptedMessage)
- return decryptedData
- } catch (err) {
- logger.error(
- `[SOCKET] An error has occurred while decrypting an event (${eventName}):`,
- err
- )
-
- return socket.emit('encryption:error', err)
- }
- }
-
const onNewInvoice = (socket, subID) => {
const { lightning } = LightningServices.services
logger.warn('Subscribing to invoices socket...' + subID)
@@ -701,7 +641,7 @@ module.exports = (
}
/**
- * @param {Common.Schema.SimpleReceivedRequest[]} receivedReqs
+ * @param {ReadonlyArray} receivedReqs
*/
const onReceivedReqs = receivedReqs => {
const processed = receivedReqs.map(({ id, requestorPK, timestamp }) => {
diff --git a/utils/index.js b/utils/index.js
index 90e80eee..516d762a 100644
--- a/utils/index.js
+++ b/utils/index.js
@@ -1,9 +1,21 @@
/**
* @format
*/
+const Gun = require('gun')
const { asyncFilter } = require('./helpers')
-module.exports = {
- asyncFilter
+/**
+ * @returns {string}
+ */
+const gunUUID = () => {
+ // @ts-expect-error Not typed
+ const uuid = Gun.Text.random()
+
+ return uuid
+}
+
+module.exports = {
+ asyncFilter,
+ gunUUID
}
diff --git a/utils/lightningServices/v2.js b/utils/lightningServices/v2.js
index e54e3ee4..6f2cccbb 100644
--- a/utils/lightningServices/v2.js
+++ b/utils/lightningServices/v2.js
@@ -6,6 +6,8 @@ const logger = require('winston')
const Common = require('shock-common')
const Ramda = require('ramda')
+const { writeCoordinate } = require('../../services/coordinates')
+
const lightningServices = require('./lightning-services')
/**
* @typedef {import('./types').PaymentV2} PaymentV2
@@ -213,12 +215,50 @@ const isValidSendPaymentInvoiceParams = sendPaymentInvoiceParams => {
return true
}
+/**
+ * @param {string} payReq
+ * @returns {Promise}
+ */
+const decodePayReq = payReq =>
+ Common.Utils.makePromise((res, rej) => {
+ lightningServices.lightning.decodePayReq(
+ { pay_req: payReq },
+ /**
+ * @param {{ message: any; }} err
+ * @param {any} paymentRequest
+ */
+ (err, paymentRequest) => {
+ if (err) {
+ rej(new Error(err.message))
+ } else {
+ res(paymentRequest)
+ }
+ }
+ )
+ })
+
+/**
+ * @returns {Promise}
+ */
+const myLNDPub = () =>
+ Common.makePromise((res, rej) => {
+ const { lightning } = lightningServices.getServices()
+
+ lightning.getInfo({}, (err, data) => {
+ if (err) {
+ rej(new Error(err.message))
+ } else {
+ res(data.identity_pubkey)
+ }
+ })
+ })
+
/**
* aklssjdklasd
* @param {SendPaymentV2Request} sendPaymentRequest
* @returns {Promise}
*/
-const sendPaymentV2 = sendPaymentRequest => {
+const sendPaymentV2 = async sendPaymentRequest => {
const {
services: { router }
} = lightningServices
@@ -229,7 +269,10 @@ const sendPaymentV2 = sendPaymentRequest => {
)
}
- return new Promise((res, rej) => {
+ /**
+ * @type {import("./types").PaymentV2}
+ */
+ const paymentV2 = await Common.makePromise((res, rej) => {
const stream = router.sendPaymentV2(sendPaymentRequest)
stream.on(
@@ -268,6 +311,33 @@ const sendPaymentV2 = sendPaymentRequest => {
}
)
})
+
+ /** @type {Common.Coordinate} */
+ const coord = {
+ amount: Number(paymentV2.value_sat),
+ id: paymentV2.payment_hash,
+ inbound: false,
+ timestamp: Date.now(),
+ toLndPub: await myLNDPub(),
+ fromLndPub: undefined,
+ invoiceMemo: undefined,
+ type: 'payment'
+ }
+
+ if (sendPaymentRequest.payment_request) {
+ const invoice = await decodePayReq(sendPaymentRequest.payment_request)
+
+ coord.invoiceMemo = invoice.description
+ coord.toLndPub = invoice.destination
+ }
+
+ if (sendPaymentRequest.dest) {
+ coord.toLndPub = sendPaymentRequest.dest.toString('base64')
+ }
+
+ await writeCoordinate(paymentV2.payment_hash, coord)
+
+ return paymentV2
}
/**
@@ -380,28 +450,6 @@ const listPayments = req => {
})
}
-/**
- * @param {string} payReq
- * @returns {Promise}
- */
-const decodePayReq = payReq =>
- Common.Utils.makePromise((res, rej) => {
- lightningServices.lightning.decodePayReq(
- { pay_req: payReq },
- /**
- * @param {{ message: any; }} err
- * @param {any} paymentRequest
- */
- (err, paymentRequest) => {
- if (err) {
- rej(new Error(err.message))
- } else {
- res(paymentRequest)
- }
- }
- )
- })
-
/**
* @param {0|1} type
* @returns {Promise}
diff --git a/yarn.lock b/yarn.lock
index 6b9685a7..4fbe3b46 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -183,9 +183,9 @@
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/runtime@^7.6.3":
- version "7.11.2"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
- integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
+ version "7.12.18"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.18.tgz#af137bd7e7d9705a412b3caaf991fe6aaa97831b"
+ integrity sha512-BogPQ7ciE6SYAUPtlm9tWbgI9+2AgqSam6QivMgXgAT+fKbgppaj4ZX15MHeLC1PVF5sNk70huBu20XxWOs8Cg==
dependencies:
regenerator-runtime "^0.13.4"
@@ -722,6 +722,14 @@
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
+"@types/node-fetch@^2.5.8":
+ version "2.5.8"
+ resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb"
+ integrity sha512-fbjI6ja0N5ZA8TV53RUqzsKNkl9fv8Oj3T7zxW7FGv1GSH7gwJaNF8dzCjrqKaxKeUpTz4yT1DaJFq/omNpGfw==
+ dependencies:
+ "@types/node" "*"
+ form-data "^3.0.0"
+
"@types/node@*":
version "12.7.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.4.tgz#64db61e0359eb5a8d99b55e05c729f130a678b04"
@@ -1105,6 +1113,11 @@ asn1js@^2.0.26:
dependencies:
pvutils latest
+assert-never@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.1.tgz#11f0e363bf146205fb08193b5c7b90f4d1cf44fe"
+ integrity sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==
+
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
@@ -1587,11 +1600,6 @@ camelcase@^2.0.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-camelcase@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
- integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
-
camelcase@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -1734,7 +1742,7 @@ cli-width@^2.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
-cliui@^3.0.3, cliui@^3.2.0:
+cliui@^3.0.3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
@@ -1833,7 +1841,7 @@ colour@~0.7.1:
resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=
-combined-stream@^1.0.6, combined-stream@~1.0.6:
+combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@@ -2375,7 +2383,7 @@ enquirer@^2.3.4:
dependencies:
ansi-colors "^3.2.1"
-error-ex@^1.2.0, error-ex@^1.3.1:
+error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
@@ -2870,14 +2878,6 @@ finalhandler@~1.1.2:
statuses "~1.5.0"
unpipe "~1.0.0"
-find-up@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
- integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
- dependencies:
- path-exists "^2.0.0"
- pinkie-promise "^2.0.0"
-
find-up@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
@@ -2941,6 +2941,15 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+form-data@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
+ integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@@ -3030,11 +3039,6 @@ gcp-metadata@^4.2.0:
gaxios "^4.0.0"
json-bigint "^1.0.0"
-get-caller-file@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
- integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
-
get-caller-file@^2.0.1:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
@@ -3803,11 +3807,6 @@ is-typedarray@~1.0.0:
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-is-utf8@^0.2.0:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
- integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
-
is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
@@ -4525,17 +4524,6 @@ listr2@1.3.8:
through "^2.3.8"
uuid "^7.0.2"
-load-json-file@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
- integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
-
load-json-file@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -4546,15 +4534,14 @@ load-json-file@^4.0.0:
pify "^3.0.0"
strip-bom "^3.0.0"
-localtunnel@^1.9.0:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.9.2.tgz#0012fcabc29cf964c130a01858768aa2bb65b5af"
- integrity sha512-NEKF7bDJE9U3xzJu3kbayF0WTvng6Pww7tzqNb/XtEARYwqw7CKEX7BvOMg98FtE9es2CRizl61gkV3hS8dqYg==
+"localtunnel@git://github.com/shocknet/localtunnel#40cc2c2a46b05da2217bf2e20da11a5343a5cce7":
+ version "2.0.0"
+ resolved "git://github.com/shocknet/localtunnel#40cc2c2a46b05da2217bf2e20da11a5343a5cce7"
dependencies:
axios "0.19.0"
debug "4.1.1"
openurl "1.1.1"
- yargs "6.6.0"
+ yargs "13.3.0"
locate-path@^3.0.0:
version "3.0.0"
@@ -5108,9 +5095,9 @@ normalize-path@^3.0.0:
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalizr@^3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/normalizr/-/normalizr-3.6.0.tgz#b8bbc4546ffe43c1c2200503041642915fcd3e1c"
- integrity sha512-25cd8DiDu+pL46KIaxtVVvvEPjGacJgv0yUg950evr62dQ/ks2JO1kf7+Vi5/rMFjaSTSTls7aCnmRlUSljtiA==
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/normalizr/-/normalizr-3.6.1.tgz#d367ab840e031ff382141b8d81ce279292ff69fe"
+ integrity sha512-8iEmqXmPtll8PwbEFrbPoDxVw7MKnNvt3PZzR2Xvq9nggEEOgBlNICPXYzyZ4w4AkHUzCU998mdatER3n2VaMA==
npm-bundled@^1.0.1:
version "1.0.6"
@@ -5379,13 +5366,6 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
-parse-json@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
- integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
- dependencies:
- error-ex "^1.2.0"
-
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -5438,13 +5418,6 @@ path-dirname@^1.0.0:
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
-path-exists@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
- integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
- dependencies:
- pinkie-promise "^2.0.0"
-
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
@@ -5485,15 +5458,6 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
-path-type@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
- integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
- dependencies:
- graceful-fs "^4.1.2"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
path-type@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
@@ -5516,11 +5480,6 @@ picomatch@^2.0.5:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
-pify@^2.0.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
- integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
-
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
@@ -5531,18 +5490,6 @@ pify@^4.0.1:
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
-pinkie-promise@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
- integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
- dependencies:
- pinkie "^2.0.0"
-
-pinkie@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
- integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
-
pirates@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87"
@@ -5715,6 +5662,11 @@ pvutils@latest:
resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.0.17.tgz#ade3c74dfe7178944fe44806626bd2e249d996bf"
integrity sha512-wLHYUQxWaXVQvKnwIDWFVKDJku9XDCvyhhxoq8dc5MFdIlRenyPI9eSfEtcvgHgD7FlvCyGAlWgOzRnZD99GZQ==
+qrcode-terminal@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
+ integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==
+
qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
@@ -5770,14 +5722,6 @@ react-is@^16.8.4:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.10.1.tgz#0612786bf19df406502d935494f0450b40b8294f"
integrity sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==
-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"
- integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
- dependencies:
- find-up "^1.0.0"
- read-pkg "^1.0.0"
-
read-pkg-up@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
@@ -5786,15 +5730,6 @@ read-pkg-up@^4.0.0:
find-up "^3.0.0"
read-pkg "^3.0.0"
-read-pkg@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
- integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
- dependencies:
- load-json-file "^1.0.0"
- normalize-package-data "^2.3.2"
- path-type "^1.0.0"
-
read-pkg@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@@ -5999,11 +5934,6 @@ require-directory@^2.1.1:
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
-require-main-filename@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
- integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
-
require-main-filename@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
@@ -6282,10 +6212,10 @@ shellwords@^0.1.1:
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
-shock-common@31.1.0:
- version "31.1.0"
- resolved "https://registry.yarnpkg.com/shock-common/-/shock-common-31.1.0.tgz#9c8f25d0d405a9a9c52849c2d96452c5ddd17267"
- integrity sha512-1490v3gTY5ZNEB/Lelfix+6bI4mfFE8hVrtN4ijz0aj/Cl1ZP5ATKdYO+hffReI+4yDaPSAAWd/HYk9b497Kxw==
+shock-common@32.0.0:
+ version "32.0.0"
+ resolved "https://registry.yarnpkg.com/shock-common/-/shock-common-32.0.0.tgz#bb7f70d7a572783c46aeae7420179935eb5096d4"
+ integrity sha512-1GorUFRpkRGXdKT9PImwnj2orpoJaESU/iD+rvL8sqFMLKazkW9LfLAcRwEWCvytWdKFJ35UO2gN49N8dPiRmA==
dependencies:
immer "^6.0.6"
lodash "^4.17.19"
@@ -6561,7 +6491,7 @@ string-length@^2.0.0:
astral-regex "^1.0.0"
strip-ansi "^4.0.0"
-string-width@^1.0.1, string-width@^1.0.2:
+string-width@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
@@ -6672,13 +6602,6 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
-strip-bom@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
- integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
- dependencies:
- is-utf8 "^0.2.0"
-
strip-bom@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
@@ -7031,10 +6954,10 @@ typescript-tuple@^2.2.1:
dependencies:
typescript-compare "^0.0.2"
-typescript@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2"
- integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==
+typescript@latest:
+ version "4.1.5"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.5.tgz#123a3b214aaff3be32926f0d8f1f6e704eb89a72"
+ integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==
uglify-js@^3.1.4:
version "3.10.2"
@@ -7267,11 +7190,6 @@ whatwg-url@^7.0.0:
tr46 "^1.0.1"
webidl-conversions "^4.0.2"
-which-module@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
- integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
-
which-module@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
@@ -7445,7 +7363,7 @@ xmlhttprequest-ssl@~1.5.4:
resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
-y18n@^3.2.0, y18n@^3.2.1:
+y18n@^3.2.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
@@ -7483,33 +7401,7 @@ yargs-parser@^13.1.1:
camelcase "^5.0.0"
decamelize "^1.2.0"
-yargs-parser@^4.2.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"
- integrity sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=
- dependencies:
- camelcase "^3.0.0"
-
-yargs@6.6.0:
- version "6.6.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208"
- integrity sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=
- dependencies:
- camelcase "^3.0.0"
- cliui "^3.2.0"
- decamelize "^1.1.1"
- get-caller-file "^1.0.1"
- os-locale "^1.4.0"
- read-pkg-up "^1.0.1"
- require-directory "^2.1.1"
- require-main-filename "^1.0.1"
- set-blocking "^2.0.0"
- string-width "^1.0.2"
- which-module "^1.0.0"
- y18n "^3.2.1"
- yargs-parser "^4.2.0"
-
-yargs@^13.3.0:
+yargs@13.3.0, yargs@^13.3.0:
version "13.3.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83"
integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==