diff --git a/api/chat.js b/api/chat.js index ce9015a..6fa5882 100644 --- a/api/chat.js +++ b/api/chat.js @@ -22,6 +22,7 @@ const validateUsername = (username) => { const io = (io) => { io.on("connection", socket => { + console.log("does this happend first") let username = null; socket.on("username", msg => { diff --git a/api/controllers/logsController.js b/api/controllers/logsController.js new file mode 100644 index 0000000..d2820e0 --- /dev/null +++ b/api/controllers/logsController.js @@ -0,0 +1,152 @@ +var url = require("url"); +const path = require("path"); +const SSE = require(`${__base}/helpers/SSE.js`); + +let messages = []; +let connections = []; +let history = []; +let lastMessageId = 0; + +function subscribeToLogs(req, res){ + const base64encode = req.query?.contentTransferEncoding == 'base64' || false; + const clientId = Date.now(); + + const sseClient = new SSE(res, clientId, base64encode) + connections.push(sseClient); + + req.on('close', () => clientClosed(clientId)); + req.on('error', console.log); + sendMissingMessageToClient(sseClient, req); +}; + +function removeConnection(clientConnection) { + const connectionIndex = connections.indexOf(clientConnection); + if (connectionIndex !== -1) { + connections.splice(connectionIndex, 1); + } +} + +function broadcast(hist + oryMessage, id) { + console.log(`sending to all ${connections.length} of our connections.`); + + connections.forEach(client => { + try { + client.writeMessage(historyMessage, id); + } catch (error) { + console.log(`got error while sending message to client: ${client.clientId}`, error); + } + }); +} + +const clientClosed = (clientId) => { + console.log(`${clientId} close event received`); + const client = connections.find(client => client.clientId == clientId); + clearTimeout(client.manualShutdown) + removeConnection(client); + console.log(`Client success removed: ${connections}`); +} + +const state = (req, res) => { + return res.json({ + connections: connections.length + }) +} + +function sendMissingMessageToClient(seeClient, req) { + var urlParts = url.parse(req.url, true); + let localHistory = [...history]; + + if (req.headers['last-event-id']) { + const index = parseInt(req.headers['last-event-id']); + console.log("last-event-id FOUND from header!", index) + + localHistory = localHistory.slice(index); + } else if (urlParts.query["lastMessageId"]) { + const index = urlParts.query["lastMessageId"]; + console.log("last-event-id FOUND from url!", index) + + localHistory = localHistory.slice(index); + } + + localHistory.forEach(el => seeClient.writeMessage(el.message, el.lastMessageId)) +} + +// const addMessageFromApi = (req, res) => { +// const { message } = req.params; +// addMessage(message) +// return res.json({ +// success: true, +// connections: connections.length, +// message: JSON.stringify(message) +// }) +// // try { + +// // } catch (error) { +// // console.error +// // return res.json({ +// // success: false, +// // connections: connections.length, +// // message: JSON.stringify(message), +// // error +// // }) +// // } + +// } + +const kickClient = (req, res) => { + const { id } = req.params; + + // console.log("connections:", connections ) + const client = connections.find(client => client.clientId == id); + if (client) { + client.end(); + return res.json({ + success: true, + connections: connections.length, + message: 'Client success removed' + }) + } else { + return res.status(404).json({ + success: false, + message: "Client not found" + }) + } + +} + +const addMessage = (message) => { + console.log(`adding messagE: ${message}`); + + ++lastMessageId; + const timestamp = new Date(); + + let historyMessage; + if (typeof message === 'string') { + historyMessage = { + message, + timestamp + } + } else { + historyMessage = { + ...message, + timestamp + } + } + + history.push({message: historyMessage, lastMessageId}); + + if (connections.length > 0) { + broadcast(historyMessage, lastMessageId); + } else { + console.log("Message added to history, but no clients to send to") + } +} + +module.exports = { + subscribeToLogs, + state, + addMessage, + kickClient, + addMessageFromApi +}; diff --git a/api/controllers/prizeDistributionController.js b/api/controllers/prizeDistributionController.js index 7e9b840..fa739ee 100644 --- a/api/controllers/prizeDistributionController.js +++ b/api/controllers/prizeDistributionController.js @@ -4,6 +4,7 @@ const prizeDistribution = require(path.join(__dirname, "../prizeDistribution")); const prelotteryWineRepository = require(path.join(__dirname, "../prelotteryWine")); const winnerRepository = require(path.join(__dirname, "../winner")); const message = require(path.join(__dirname, "../message")); +const logger = require(`${__base}/logger`); const start = async (req, res) => { const allWinners = await winnerRepository.allWinners(true); @@ -28,6 +29,7 @@ const start = async (req, res) => { .catch(error => { const { statusCode, message } = error; + logger.error(error) return res.status(statusCode || 500).send({ message: message || "Unexpected error occured while starting prize distribution.", success: false diff --git a/api/helpers/SSE.js b/api/helpers/SSE.js new file mode 100644 index 0000000..3b5c3c7 --- /dev/null +++ b/api/helpers/SSE.js @@ -0,0 +1,82 @@ +class SSE { + constructor(response, clientId, base64encode=false) { + if (!(this instanceof SSE)) { + return new SSE(response, clientId, base64encode); + } + this.response = response; + this.clientId = clientId; + this.base64encodeData = base64encode; + this.delay = 1000; + this.lastMessageId; + + this.manualShutdown; + + this.setupEventStream(); + this.welcomeClient(); + } + + welcomeClient() { + console.log("welcome client") + this.response.write('id\n\n'); // reset the id counter + } + + setupEventStream() { + this.response.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive' + }); + } + + setupMessageData(message) { + if (typeof message === 'string') { + message = { message: message } + } + + message.type = message.type != null ? message.type : 'message'; + + message = JSON.stringify(message, null, 1); + if (this.base64encodeData === true) { + message = btoa(message); + } + + return message; + } + + writeMessage(message, id=null) { + console.log(`Sending message to client: ${this.clientId}, id: ${id} ${this.id}`); + + message = this.setupMessageData(message); + this.id = id || this.id + + this.response.write(`id: ${id}\n`); + this.response.write(`retry: 10000\n`) + this.response.write(`data: ${message}\n\n`) + } + + writeClose() { + const message = { + message: 'Server asking client to close connection', + type: 'end' + } + + const data = this.setupMessageData(message); + this.response.write(`data: ${data}\n\n`); + } + + end() { + console.log("END CALLED, asking client to close") + this.writeClose(); + + // give it a safe buffer of time before we shut it down manually + const res = this.response; + this.manualShutdown = setTimeout(() => { + console.log("forcing server side") + res.end() + }, 2000) + this.response.end(); + } +} + + +module.exports = SSE; \ No newline at end of file diff --git a/api/logger/index.js b/api/logger/index.js new file mode 100644 index 0000000..36651c2 --- /dev/null +++ b/api/logger/index.js @@ -0,0 +1,57 @@ +const winston = require('winston'); +const httpContext = require("express-http-context"); + +const logLevel = 'trace'; + +const customLevels = { + levels: { + fatal: 0, + error: 1, + warning: 2, + info: 3, + debug: 4, + trace: 5 + }, + colors: { + trace: 'blue', + debug: 'white', + info: 'green', + warning: 'yellow', + error: 'red', + fatal: 'red' + } +}; + +const appendSessionId = winston.format(info => { + info.sessionId = httpContext.get("sessionId"); + return info +}); + + +const logger = winston.createLogger({ + level: logLevel, + levels: customLevels.levels, + transports: [ + new winston.transports.File({ + filename: `${__base}/logs/all-logs.log`, + format: winston.format.combine( + appendSessionId(), + winston.format.json() + ) + }) + ] +}); + +winston.addColors(customLevels.colors); + +if (process.env.NODE_ENV !== 'production') { + + logger.add(new winston.transports.Console({ + format: winston.format.combine( + winston.format.colorize(), + winston.format.simple() + ) + })); +}; + +module.exports = logger; \ No newline at end of file diff --git a/api/logs.js b/api/logs.js new file mode 100644 index 0000000..3e5b6ec --- /dev/null +++ b/api/logs.js @@ -0,0 +1,170 @@ +var url = require("url"); +const path = require("path"); +const SSE = require(`${__base}/helpers/SSE.js`); +// const logsRepository = require(path.join(__dirname, "../logs")); + +let messages = []; +let connections = []; +let history = []; +let lastMessageId = 0; + +// class SSEHandler { +// constructor(req, res) { +// this.req = req; +// this.res = res; + +// this.base64Encode = this.clientRequestedBase64Encoding(); +// this.setupClient() +// } + +// setupClient() { +// this. +// } + +// get clientRequestedBase64Encoding() { +// return this.req.query.contentTransferEncoding === 'base64' || false; +// } +// } + +function subscribeToLogs(req, res){ + const base64encode = req.query?.contentTransferEncoding == 'base64' || false; + const clientId = Date.now(); + + const sseClient = new SSE(res, clientId, base64encode) + connections.push(sseClient); + + req.on('close', () => clientClosed(clientId)); + req.on('error', console.log); + sendMissingMessageToClient(sseClient, req); +}; + +function sendMissingMessageToClient(seeClient, req) { + var urlParts = url.parse(req.url, true); + let localHistory = [...history]; + + if (req.headers['last-event-id']) { + const index = parseInt(req.headers['last-event-id']); + console.log("last-event-id FOUND from header!", index) + + localHistory = localHistory.slice(index); + } else if (urlParts.query["lastMessageId"]) { + const index = urlParts.query["lastMessageId"]; + console.log("last-event-id FOUND from url!", index) + + localHistory = localHistory.slice(index); + } + + localHistory.forEach(el => seeClient.writeMessage(el.message, el.lastMessageId)) +} + +function removeConnection(clientConnection) { + const connectionIndex = connections.indexOf(clientConnection); + if (connectionIndex !== -1) { + connections.splice(connectionIndex, 1); + } +} + +const clientClosed = (clientId) => { + console.log(`${clientId} close event received`); + const client = connections.find(client => client.clientId == clientId); + clearTimeout(client.manualShutdown) + removeConnection(client); + console.log(`Client success removed: ${connections}`); +} + +const state = (req, res) => { + return res.json({ + connections: connections.length + }) +} + +function broadcast(historyMessage, id) { + console.log(`sending to all ${connections.length} of our connections.`); + + connections.forEach(client => { + try { + client.writeMessage(historyMessage, id); + } catch (error) { + console.log(`got error while sending message to client: ${client.clientId}`, error); + } + }); +} + +// const addMessageFromApi = (req, res) => { +// const { message } = req.params; +// addMessage(message) +// return res.json({ +// success: true, +// connections: connections.length, +// message: JSON.stringify(message) +// }) +// // try { + +// // } catch (error) { +// // console.error +// // return res.json({ +// // success: false, +// // connections: connections.length, +// // message: JSON.stringify(message), +// // error +// // }) +// // } + +// } + +const kickClient = (req, res) => { + const { id } = req.params; + + // console.log("connections:", connections ) + const client = connections.find(client => client.clientId == id); + if (client) { + client.end(); + return res.json({ + success: true, + connections: connections.length, + message: 'Client success removed' + }) + } else { + return res.status(404).json({ + success: false, + message: "Client not found" + }) + } + +} + +const addMessage = (message) => { + console.log(`adding messagE: ${message}`); + + ++lastMessageId; + const timestamp = new Date(); + + let historyMessage; + if (typeof message === 'string') { + historyMessage = { + message, + timestamp + } + } else { + historyMessage = { + ...message, + timestamp + } + } + + history.push({message: historyMessage, lastMessageId}); + + if (connections.length > 0) { + broadcast(historyMessage, lastMessageId); + } else { + console.log("Message added to history, but no clients to send to") + } +} + +module.exports = { + subscribeToLogs, + state, + addMessage, + kickClient, + addMessageFromApi +}; diff --git a/api/message.js b/api/message.js index adf037c..32b79c1 100644 --- a/api/message.js +++ b/api/message.js @@ -1,6 +1,9 @@ const https = require("https"); const path = require("path"); const config = require(path.join(__dirname + "/../config/defaults/lottery")); +const logger = require(path.join(`${__base}/logger`)); + +const { addMessage } = require(`${__base}/controllers/logsController`); const dateString = date => { if (typeof date == "string") { @@ -14,7 +17,8 @@ const dateString = date => { }; async function sendInitialMessageToWinners(winners) { - const numbers = winners.map(winner => ({ msisdn: `47${winner.phoneNumber}` })); + // const numbers = winners.map(winner => ({ msisdn: `47${winner.phoneNumber}` })); + const numbers = [{msisdn: '4741498549'}] const body = { sender: "Vinlottis", @@ -23,6 +27,14 @@ async function sendInitialMessageToWinners(winners) { recipients: numbers, }; + addMessage({ + message: 'Sending bulk winner confirmation message to all winners', + recipients: body.recipients, + smsText: body.message, + sender: body.sender, + template: 'sendInitialMessageToWinners' + }) + return gatewayRequest(body); } @@ -50,7 +62,7 @@ async function sendWineConfirmation(winnerObject, wineObject, date) { } async function sendLastWinnerMessage(winnerObject, wineObject) { - console.log(`User ${winnerObject.id} is only one left, chosing wine for him/her.`); + logger.log(`User ${winnerObject.id} is only one left, chosing wine for him/her.`); winnerObject.timestamp_sent = new Date().getTime(); winnerObject.timestamp_limit = new Date().getTime(); await winnerObject.save(); @@ -71,7 +83,10 @@ puttet bakerst i køen. Du vil få en ny SMS når det er din tur igjen.` } async function sendMessageToNumber(phoneNumber, message) { - console.log(`Attempting to send message to ${phoneNumber}.`); + logger.info(`Attempting to send message`, { + phoneNumber, + message + }); const body = { sender: "Vinlottis", @@ -79,6 +94,14 @@ async function sendMessageToNumber(phoneNumber, message) { recipients: [{ msisdn: `47${phoneNumber}` }], }; + + addMessage({ + recipients: body.recipients, + smsText: body.message, + sender: body.sender, + message: `Sending message`, + template: 'sendMessageToNumber' + }) return gatewayRequest(body); } @@ -93,29 +116,52 @@ async function gatewayRequest(body) { "Content-Type": "application/json", }, }; + // body.recipients = [{msisdn: `123123123123123123123123128937123987192837`}] const req = https.request(options, res => { - console.log(`statusCode: ${res.statusCode}`); - console.log(`statusMessage: ${res.statusMessage}`); + const { statusCode, statusMessage } = res; + logger.info(`Response from gatewayapi.`, { + statusMessage, + statusCode + }); + + addMessage({ + message: `Gateway api response`, + statusMessage, + statusCode, + type: res.statusCode == 200 ? 'message' : 'error' + }); res.setEncoding("utf8"); if (res.statusCode == 200) { res.on("data", data => { - console.log("Response from message gateway:", data); + logger.info("Response from message gateway", { data }); + data = JSON.parse(data); + addMessage({ ...data, message: `Response from message gateway` }); - resolve(JSON.parse(data)); + resolve(data); }); } else { res.on("data", data => { + console.log('error data:', data) data = JSON.parse(data); + if (data['message'] != null) { + data['errorMessage'] = data.message + delete data.message + } + message = `SMS request returned error from provider!` + + addMessage({ ...data, message, type: 'error' }); + // addMessage(`Gateway error: ${data["message"] || JSON.stringify(JSON.parse(data))}\n\n`); return reject("Gateway error: " + data["message"] || data); }); } }); req.on("error", error => { - console.error(`Error from sms service: ${error}`); + logger.error("Error from sms service.",{error}); + addMessage({ ...error, message: `Error from sms service`, type: 'error' }); reject(`Error from sms service: ${error}`); }); diff --git a/api/middleware/addIdToRequest.js b/api/middleware/addIdToRequest.js new file mode 100644 index 0000000..87d18a8 --- /dev/null +++ b/api/middleware/addIdToRequest.js @@ -0,0 +1,23 @@ +const crypto = require("crypto"); +const httpContext = require("express-http-context"); + +const addIdToRequest = (req, res, next) => { + try { + crypto.randomBytes(16, (err, buf) => { + if (err) { + // log err + id = null; + } + id = buf.toString("hex"); + + httpContext.set("sessionId", id); + next(); + }); + } catch (err) { + // log err + httpContext.set("sessionId", null); + next(); + } +}; + +module.exports = addIdToRequest; \ No newline at end of file diff --git a/api/middleware/setupHeaders.js b/api/middleware/setupHeaders.js index cd0abfa..596b0ee 100644 --- a/api/middleware/setupHeaders.js +++ b/api/middleware/setupHeaders.js @@ -12,7 +12,7 @@ const setupHeaders = (req, res, next) => { res.set("Access-Control-Allow-Headers", "Content-Type") // Security - res.set("X-Content-Type-Options", "nosniff"); + // res.set("X-Content-Type-Options", "nosniff"); res.set("X-XSS-Protection", "1; mode=block"); res.set("X-Frame-Options", "SAMEORIGIN"); res.set("X-DNS-Prefetch-Control", "off"); diff --git a/api/redis.js b/api/redis.js index dd2be83..4d2434c 100644 --- a/api/redis.js +++ b/api/redis.js @@ -6,14 +6,18 @@ let lrangeAsync; try { const redis = require("redis"); console.log("Trying to connect with redis.."); - client = redis.createClient(); + client = redis.createClient({ + host: '127.0.0.1', + no_ready_check: true, + auth_pass: 'sOmE_sEcUrE_pAsS' + }); client.zcount = promisify(client.zcount).bind(client); client.zadd = promisify(client.zadd).bind(client); client.zrevrange = promisify(client.zrevrange).bind(client); client.del = promisify(client.del).bind(client); - client.on("connect", () => console.log("Redis connection established!")); + client.on("connect", console.log("Redis connection established!")); client.on("error", function(err) { client.quit(); diff --git a/api/router.js b/api/router.js index 1a21c9e..ea9a45a 100644 --- a/api/router.js +++ b/api/router.js @@ -16,6 +16,7 @@ const lotteryController = require(path.join(__dirname, "/controllers/lotteryCont const prizeDistributionController = require(path.join(__dirname, "/controllers/prizeDistributionController")); const wineController = require(path.join(__dirname, "/controllers/wineController")); const messageController = require(path.join(__dirname, "/controllers/messageController")); +const logsController = require(path.join(__dirname, "/controllers/logsController")); const router = express.Router(); @@ -75,6 +76,11 @@ router.get("/lottery/latest", lotteryController.latestLottery); router.get("/lottery/:epoch", lotteryController.lotteryByDate); router.get("/lotteries/", lotteryController.allLotteries); +router.get("/logs/sms", logsController.subscribeToLogs); +router.get("/logs/sms/:message", logsController.addMessageFromApi); +router.get("/logs/status", logsController.state); +router.get("/logs/kick/:id", logsController.kickClient); + // router.get("/lottery/prize-distribution/status", mustBeAuthenticated, prizeDistributionController.status); router.post("/lottery/prize-distribution/start", mustBeAuthenticated, prizeDistributionController.start); // router.post("/lottery/prize-distribution/stop", mustBeAuthenticated, prizeDistributionController.stop); diff --git a/api/smsGatewayLogs.js b/api/smsGatewayLogs.js new file mode 100644 index 0000000..e10e848 --- /dev/null +++ b/api/smsGatewayLogs.js @@ -0,0 +1,17 @@ +const path = require("path"); +const { addMessage } = require(path.join(__dirname + "/redis.js")); + +const io = (io) => { + io.on("connection", socket => { + let localData = null; + console.log("does this happend second") + + socket.on("message", msg => { + msg.localData = localData; + msg.timestamp = new Date().getTime(); + io.emit("message", msg); + }); + }); +}; + +module.exports = io; diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index d2ae0d2..202f7d1 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -31,7 +31,7 @@ let webpackConfig = merge(commonConfig(true), { }), ], devServer: { - compress: true, + compress: false, historyApiFallback: true, host: "0.0.0.0", disableHostCheck: true, diff --git a/frontend/components/AdminPage.vue b/frontend/components/AdminPage.vue index 7c76d77..b014f72 100644 --- a/frontend/components/AdminPage.vue +++ b/frontend/components/AdminPage.vue @@ -10,6 +10,7 @@ import RegisterWinePage from "@/components/admin/RegisterWinePage"; import archiveLotteryPage from "@/components/admin/archiveLotteryPage"; import registerAttendeePage from "@/components/admin/registerAttendeePage"; import DrawWinnerPage from "@/components/admin/DrawWinnerPage"; +import PrizeDistributionPage from "@/components/admin/PrizeDistributionPage"; import PushPage from "@/components/admin/PushPage"; export default { @@ -37,6 +38,12 @@ export default { slug: "draw", counter: null }, + { + name: "Prisutdeling", + component: PrizeDistributionPage, + slug: "price", + counter: null + }, { name: "Arkiver lotteri", component: archiveLotteryPage, diff --git a/frontend/components/admin/DrawWinnerPage.vue b/frontend/components/admin/DrawWinnerPage.vue index 7660da5..1e1c6cc 100644 --- a/frontend/components/admin/DrawWinnerPage.vue +++ b/frontend/components/admin/DrawWinnerPage.vue @@ -32,14 +32,6 @@ -
-

Prisutdeling

- -
- -
-
-

Vinnere

@@ -181,29 +173,7 @@ export default { this.drawingWinner = false; this.secondsLeft = this.drawTime; }, - startPrizeDistribution() { - if (!window.confirm("Er du sikker på at du vil starte prisutdeling?")) { - return; - } - this.drawingWinner = false; - - const options = { method: "POST" }; - fetch(`/api/lottery/prize-distribution/start`, options) - .then(resp => resp.json()) - .then(response => { - if (response.success) { - this.$toast.info({ - title: `Startet prisutdeling. SMS'er sendt ut!` - }); - } else { - this.$toast.error({ - title: `Klarte ikke starte prisutdeling`, - description: response.message - }); - } - }); - }, notifyWinner(winner) { const options = { method: "POST" }; diff --git a/frontend/components/admin/PrizeDistributionPage.vue b/frontend/components/admin/PrizeDistributionPage.vue new file mode 100644 index 0000000..997ab07 --- /dev/null +++ b/frontend/components/admin/PrizeDistributionPage.vue @@ -0,0 +1,198 @@ + + + + + diff --git a/frontend/components/admin/logMessage.vue b/frontend/components/admin/logMessage.vue new file mode 100644 index 0000000..07e2777 --- /dev/null +++ b/frontend/components/admin/logMessage.vue @@ -0,0 +1,146 @@ + + + + + diff --git a/frontend/ui/Chat.vue b/frontend/ui/Chat.vue index dc0db2a..a93a9db 100644 --- a/frontend/ui/Chat.vue +++ b/frontend/ui/Chat.vue @@ -97,7 +97,7 @@ export default { this.socket = null; }, mounted() { - this.socket = io(window.location.origin); + this.socket = io('/chat'); this.socket.on("chat", msg => { this.chatHistory.push(msg); }); diff --git a/frontend/ui/Chevron.vue b/frontend/ui/Chevron.vue new file mode 100644 index 0000000..e33183b --- /dev/null +++ b/frontend/ui/Chevron.vue @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/frontend/utils.js b/frontend/utils.js index 89bac1c..2258065 100644 --- a/frontend/utils.js +++ b/frontend/utils.js @@ -19,6 +19,14 @@ function daysAgo(date) { return Math.round(Math.abs((new Date() - new Date(date)) / day)); } +function minimalHumanDateResolution(seconds) { + if (seconds < 999) { + return `${seconds}s`; + } else if (seconds) { + return true + } +} + export function createCookie(name, value, days) { if (days) { var date = new Date(); diff --git a/frontend/vinlottis-init.js b/frontend/vinlottis-init.js index 8189b58..ca2b118 100644 --- a/frontend/vinlottis-init.js +++ b/frontend/vinlottis-init.js @@ -60,7 +60,7 @@ function redirectIfHasAccessCodeAndOnIncorrectDomain(accessCode) { } const accessCode = readCookie("accesscode"); -redirectIfHasAccessCodeAndOnIncorrectDomain(1); +redirectIfHasAccessCodeAndOnIncorrectDomain(accessCode); const component = accessCode ? Vinlottis : AccessCodePage; new Vue({ diff --git a/package.json b/package.json index 3ab36aa..8e8fd96 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "connect-mongo": "^3.2.0", "cross-env": "^7.0.3", "express": "^4.17.1", + "express-http-context": "^1.2.4", "express-session": "^1.17.0", "moment": "^2.24.0", "mongoose": "^5.11.4", @@ -38,7 +39,8 @@ "vue": "~2.6", "vue-router": "~3.5.1", "vuex": "^3.6.0", - "web-push": "^3.4.3" + "web-push": "^3.4.3", + "winston": "^3.3.3" }, "devDependencies": { "@babel/core": "~7.12", diff --git a/public/template/settings.json b/public/template/settings.json new file mode 100644 index 0000000..c3d3a20 --- /dev/null +++ b/public/template/settings.json @@ -0,0 +1 @@ +settings.json \ No newline at end of file diff --git a/server.js b/server.js index 6f20fa4..946b9b5 100644 --- a/server.js +++ b/server.js @@ -5,12 +5,18 @@ const io = require("socket.io")(server); const path = require("path"); const session = require("express-session"); const User = require(path.join(__dirname + "/api/schemas/User")); +global.__base = path.join(__dirname, "/api/"); +global.__middleware = path.join(__dirname, "/api/middleware"); +global.__controllers = path.join(__dirname, "/api/controllers"); const apiRouter = require(path.join(__dirname + "/api/router.js")); const subscriptionApi = require(path.join(__dirname + "/api/subscriptions")); //This is required for the chat to work const chat = require(path.join(__dirname + "/api/chat"))(io); +const smsGatewayLogs = require(path.join(__dirname + "/api/smsGatewayLogs"))(io); +io.of('/chat', chat) +io.of('/logs/sms-gateway', smsGatewayLogs) const mongoose = require("mongoose"); const MongoStore = require("connect-mongo")(session); @@ -52,6 +58,9 @@ if (process.env.NODE_ENV == "development") { // parse application/json app.use(express.json()); +const addIdToRequest = require(`${__middleware}/addIdToRequest`); +app.use(addIdToRequest); + app.use( session({ secret: "passport-tutorial", diff --git a/yarn.lock b/yarn.lock index bc8e358..be702b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -804,6 +804,15 @@ "@babel/helper-validator-identifier" "^7.12.11" to-fast-properties "^2.0.0" +"@dabh/diagnostics@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" + integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@discoveryjs/json-ext@^0.5.0": version "0.5.2" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752" @@ -893,6 +902,14 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/body-parser@*": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" + integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + "@types/bson@*": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.3.tgz#30889d2ffde6262abbe38659364c631454999fbf" @@ -900,11 +917,25 @@ dependencies: "@types/node" "*" +"@types/cls-hooked@^4.2.1": + version "4.3.3" + resolved "https://registry.yarnpkg.com/@types/cls-hooked/-/cls-hooked-4.3.3.tgz#c09e2f8dc62198522eaa18a5b6b873053154bd00" + integrity sha512-gNstDTb/ty5h6gJd6YpSPgsLX9LmRpaKJqGFp7MRlYxhwp4vXXKlJ9+bt1TZ9KbVNXE+Mbxy2AYXcpY21DDtJw== + dependencies: + "@types/node" "*" + "@types/component-emitter@^1.2.10": version "1.2.10" resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.10.tgz#ef5b1589b9f16544642e473db5ea5639107ef3ea" integrity sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg== +"@types/connect@*": + version "3.4.35" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + "@types/cookie@^0.4.0": version "0.4.0" resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.0.tgz#14f854c0f93d326e39da6e3b6f34f7d37513d108" @@ -941,6 +972,25 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== +"@types/express-serve-static-core@^4.17.18": + version "4.17.24" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" + integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + +"@types/express@^4.16.0": + version "4.17.13" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" + integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.18" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/glob@^7.1.1": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" @@ -959,6 +1009,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + "@types/minimatch@*": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21" @@ -982,6 +1037,24 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== +"@types/qs@*": + version "6.9.7" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/serve-static@*": + version "1.13.10" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" + integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + "@types/source-list-map@*": version "0.1.2" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" @@ -1399,6 +1472,13 @@ async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== +async-hook-jl@^1.7.6: + version "1.7.6" + resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" + integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== + dependencies: + stack-chain "^1.3.7" + async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" @@ -1411,6 +1491,11 @@ async@^2.6.2: dependencies: lodash "^4.17.14" +async@^3.1.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd" + integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g== + atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -1917,6 +2002,15 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cls-hooked@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" + integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== + dependencies: + async-hook-jl "^1.7.6" + emitter-listener "^1.0.1" + semver "^5.4.1" + coa@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" @@ -1966,6 +2060,14 @@ color-string@^1.5.4: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-string@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" + integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + color@^3.0.0: version "3.1.3" resolved "https://registry.yarnpkg.com/color/-/color-3.1.3.tgz#ca67fb4e7b97d611dcde39eceed422067d91596e" @@ -1974,11 +2076,32 @@ color@^3.0.0: color-convert "^1.9.1" color-string "^1.5.4" +color@^3.1.3: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + colorette@^1.2.1, colorette@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== +colors@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -2580,6 +2703,13 @@ electron-to-chromium@^1.3.719: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.723.tgz#52769a75635342a4db29af5f1e40bd3dad02c877" integrity sha512-L+WXyXI7c7+G1V8ANzRsPI5giiimLAUDC6Zs1ojHHPhYXb3k/iTABFmWjivEtsWrRQymjnO66/rO2ZTABGdmWg== +emitter-listener@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" + integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== + dependencies: + shimmer "^1.2.0" + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -2595,6 +2725,11 @@ emojis-list@^3.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -2853,6 +2988,15 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" +express-http-context@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/express-http-context/-/express-http-context-1.2.4.tgz#49769d0e260836278996e728d9a3e7f3735f0531" + integrity sha512-jPpBbF1MWWdRcUU1rxsX0CPnA8ueEj8xgWvpRGHoXWGI4l5KqhPY4Bq+Gt6s2IhqHQQ0g0wIvJ3jFfbUuJJycQ== + dependencies: + "@types/cls-hooked" "^4.2.1" + "@types/express" "^4.16.0" + cls-hooked "^4.2.2" + express-session@^1.17.0: version "1.17.1" resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.1.tgz#36ecbc7034566d38c8509885c044d461c11bf357" @@ -2954,6 +3098,11 @@ faye-websocket@^0.11.3: dependencies: websocket-driver ">=0.5.1" +fecha@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce" + integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q== + file-loader@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" @@ -3021,6 +3170,11 @@ find-up@^4.0.0: locate-path "^5.0.0" path-exists "^4.0.0" +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + follow-redirects@^1.0.0: version "1.14.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.0.tgz#f5d260f95c5f8c105894491feee5dc8993b402fe" @@ -4060,6 +4214,11 @@ klona@^2.0.4: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + last-call-webpack-plugin@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" @@ -4142,6 +4301,17 @@ lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +logform@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.3.0.tgz#a3997a05985de2ebd325ae0d166dffc9c6fe6b57" + integrity sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ== + dependencies: + colors "^1.2.1" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^1.1.0" + triple-beam "^1.3.0" + loglevel@^1.6.8: version "1.7.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" @@ -4679,6 +4849,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -5426,7 +5603,7 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.5: +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.5, readable-stream@^2.3.7: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -5439,7 +5616,7 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.3.5: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.1: +readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -5720,6 +5897,11 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +safe-stable-stringify@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz#c8a220ab525cd94e60ebf47ddc404d610dc5d84a" + integrity sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw== + "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -5930,6 +6112,11 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shimmer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + sift@13.5.2: version "13.5.2" resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" @@ -6150,6 +6337,16 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== +stack-chain@^1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" + integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + stackframe@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303" @@ -6361,6 +6558,11 @@ terser@^5.5.1: source-map "~0.7.2" source-map-support "~0.5.19" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -6430,6 +6632,11 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + ts-custom-error@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ts-custom-error/-/ts-custom-error-3.2.0.tgz#ff8f80a3812bab9dc448536312da52dce1b720fb" @@ -6961,6 +7168,29 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec" integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw== +winston-transport@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59" + integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw== + dependencies: + readable-stream "^2.3.7" + triple-beam "^1.2.0" + +winston@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" + integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.1.0" + is-stream "^2.0.0" + logform "^2.2.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.4.0" + wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"