From 08c158c1210402acefd4f1784e3207c16e33cc19 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 27 Apr 2021 17:29:05 +0100 Subject: [PATCH 01/19] Adding a redis client to the auth system, as part of work towards the reset password flow. --- hosting/docker-compose.dev.yaml | 1 + hosting/docker-compose.yaml | 5 + hosting/hosting.properties | 1 + packages/auth/package.json | 1 + packages/auth/src/environment.js | 2 + packages/auth/src/redis/index.js | 140 ++++++++++++++++++ packages/auth/src/redis/utils.js | 20 +++ packages/auth/yarn.lock | 75 ++++++++++ packages/cli/src/hosting/makeEnv.js | 1 + packages/server/src/environment.js | 2 + .../worker/src/api/controllers/admin/email.js | 78 +--------- packages/worker/src/api/controllers/auth.js | 75 +++++----- packages/worker/src/api/routes/auth.js | 22 ++- packages/worker/src/environment.js | 2 + packages/worker/src/utilities/email.js | 84 ++++++++++- 15 files changed, 394 insertions(+), 115 deletions(-) create mode 100644 packages/auth/src/redis/index.js create mode 100644 packages/auth/src/redis/utils.js diff --git a/hosting/docker-compose.dev.yaml b/hosting/docker-compose.dev.yaml index 9b4c353981..3b99ef796c 100644 --- a/hosting/docker-compose.dev.yaml +++ b/hosting/docker-compose.dev.yaml @@ -59,6 +59,7 @@ services: container_name: budi-redis-dev restart: always image: redis + command: redis-server --requirepass ${REDIS_PASSWORD} ports: - "${REDIS_PORT}:6379" volumes: diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml index 5e21cc9efd..e062f0590e 100644 --- a/hosting/docker-compose.yaml +++ b/hosting/docker-compose.yaml @@ -23,6 +23,8 @@ services: LOG_LEVEL: info SENTRY_DSN: https://a34ae347621946bf8acded18e5b7d4b8@o420233.ingest.sentry.io/5338131 ENABLE_ANALYTICS: "true" + REDIS_URL: redis-service:6379 + REDIS_PASSWORD: ${REDIS_PASSWORD} depends_on: - worker-service @@ -43,6 +45,8 @@ services: COUCH_DB_PASSWORD: ${COUCH_DB_PASSWORD} COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984 SELF_HOST_KEY: ${HOSTING_KEY} + REDIS_URL: redis-service:6379 + REDIS_PASSWORD: ${REDIS_PASSWORD} depends_on: - minio-service - couch-init @@ -100,6 +104,7 @@ services: redis-service: restart: always image: redis + command: redis-server --requirepass ${REDIS_PASSWORD} ports: - "${REDIS_PORT}:6379" volumes: diff --git a/hosting/hosting.properties b/hosting/hosting.properties index 138e66d629..4297ec60a1 100644 --- a/hosting/hosting.properties +++ b/hosting/hosting.properties @@ -12,6 +12,7 @@ MINIO_ACCESS_KEY=budibase MINIO_SECRET_KEY=budibase COUCH_DB_PASSWORD=budibase COUCH_DB_USER=budibase +REDIS_PASSWORD=budibase # This section contains variables that do not need to be altered under normal circumstances APP_PORT=4002 diff --git a/packages/auth/package.json b/packages/auth/package.json index b4f4b1cb33..2de0bd7a3e 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -7,6 +7,7 @@ "license": "AGPL-3.0", "dependencies": { "bcryptjs": "^2.4.3", + "ioredis": "^4.27.1", "jsonwebtoken": "^8.5.1", "koa-passport": "^4.1.4", "passport-google-auth": "^1.0.2", diff --git a/packages/auth/src/environment.js b/packages/auth/src/environment.js index 3a5c81ea8b..4f195337b6 100644 --- a/packages/auth/src/environment.js +++ b/packages/auth/src/environment.js @@ -2,4 +2,6 @@ module.exports = { JWT_SECRET: process.env.JWT_SECRET, COUCH_DB_URL: process.env.COUCH_DB_URL, SALT_ROUNDS: process.env.SALT_ROUNDS, + REDIS_URL: process.env.REDIS_URL, + REDIS_PASSWORD: process.env.REDIS_PASSWORD, } diff --git a/packages/auth/src/redis/index.js b/packages/auth/src/redis/index.js new file mode 100644 index 0000000000..3d7253e624 --- /dev/null +++ b/packages/auth/src/redis/index.js @@ -0,0 +1,140 @@ +const Redis = require("ioredis") +const env = require("../environment") +const { addDbPrefix, removeDbPrefix } = require("./utils") + +const CONNECT_TIMEOUT_MS = 10000 +const SLOT_REFRESH_MS = 2000 +const CLUSTERED = false + +let CLIENT + +/** + * Inits the system, will error if unable to connect to redis cluster (may take up to 10 seconds) otherwise + * will return the ioredis client which will be ready to use. + * @return {Promise} The ioredis client. + */ +function init() { + return new Promise((resolve, reject) => { + const [ host, port ] = env.REDIS_URL.split(":") + const opts = { + connectTimeout: CONNECT_TIMEOUT_MS + } + if (CLUSTERED) { + opts.redisOptions = {} + opts.redisOptions.tls = {} + opts.redisOptions.password = env.REDIS_PASSWORD + opts.slotsRefreshTimeout = SLOT_REFRESH_MS + opts.dnsLookup = (address, callback) => callback(null, address) + CLIENT = new Redis.Cluster([ { port, host } ]) + } else { + opts.password = env.REDIS_PASSWORD + opts.port = port + opts.host = host + CLIENT = new Redis(opts) + } + CLIENT.on("end", err => { + reject(err) + }) + CLIENT.on("error", err => { + reject(err) + }) + CLIENT.on("connect", () => { + resolve(CLIENT) + }) + }) +} + +/** + * Utility function, takes a redis stream and converts it to a promisified response - + * this can only be done with redis streams because they will have an end. + * @param stream A redis stream, specifically as this type of stream will have an end. + * @return {Promise} The final output of the stream + */ +function promisifyStream(stream) { + return new Promise((resolve, reject) => { + const outputKeys = new Set() + stream.on("data", keys => { + keys.forEach(key => { + outputKeys.add(key) + }) + }) + stream.on("error", (err) => { + reject(err) + }) + stream.on("end", async () => { + const keysArray = Array.from(outputKeys) + try { + let getPromises = [] + for (let key of keysArray) { + getPromises.push(CLIENT.get(key)) + } + const jsonArray = await Promise.all(getPromises) + resolve(keysArray.map(key => ({ + key: removeDbPrefix(key), + value: JSON.parse(jsonArray.shift()), + }))) + } catch (err) { + reject(err) + } + }) + }) +} + +class RedisWrapper { + constructor(db) { + this._db = db + } + + async init() { + this._client = await init() + return this + } + + async scan() { + const db = this._db, client = this._client + let stream + if (CLUSTERED) { + let node = client.nodes("master") + stream = node[0].scanStream({match: db + "-*", count: 100}) + + } else { + stream = client.scanStream({match: db + "-*", count: 100}) + } + return promisifyStream(stream) + } + + async get(key) { + const db = this._db, client = this._client + let response = await client.get(addDbPrefix(db, key)) + // overwrite the prefixed key + if (response != null && response.key) { + response.key = key + } + return JSON.parse(response) + } + + async store(key, value, expirySeconds = null) { + const db = this._db, client = this._client + if (typeof(value) === "object") { + value = JSON.stringify(value) + } + const prefixedKey = addDbPrefix(db, key) + await client.set(prefixedKey, value) + if (expirySeconds) { + await client.expire(prefixedKey, expirySeconds) + } + } + + async delete(key) { + const db = this._db, client = this._client + await client.del(addDbPrefix(db, key)) + } + + async clear() { + const db = this._db + let items = await this.scan(db) + await Promise.all(items.map(obj => this.delete(db, obj.key))) + } +} + +module.exports = RedisWrapper diff --git a/packages/auth/src/redis/utils.js b/packages/auth/src/redis/utils.js new file mode 100644 index 0000000000..90f82d041a --- /dev/null +++ b/packages/auth/src/redis/utils.js @@ -0,0 +1,20 @@ +const SEPARATOR = "-" + +exports.Databases = { + PW_RESETS: "pwReset", +} + +exports.addDbPrefix = (db, key) => { + return `${db}${SEPARATOR}${key}` +} + +exports.removeDbPrefix = key => { + let parts = key.split(SEPARATOR) + if (parts.length >= 2) { + parts.shift() + return parts.join(SEPARATOR) + } else { + // return the only part + return parts[0] + } +} diff --git a/packages/auth/yarn.lock b/packages/auth/yarn.lock index c3066ebdc1..0dbdaadf8d 100644 --- a/packages/auth/yarn.lock +++ b/packages/auth/yarn.lock @@ -73,6 +73,11 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -92,11 +97,23 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +debug@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= +denque@^1.1.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" + integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -216,6 +233,22 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +ioredis@^4.27.1: + version "4.27.1" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.1.tgz#4ef947b455a1b995baa4b0d7e2c4e4f75f746421" + integrity sha512-PaFNFeBbOcEYHXAdrJuy7uesJcyvzStTM1aYMchTuky+VgKqDbXhnTJHaDsjAwcTwPx8Asatx+l2DW8zZ2xlsQ== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -296,6 +329,16 @@ koa-passport@^4.1.4: dependencies: passport "^0.4.0" +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -358,6 +401,11 @@ mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -378,6 +426,11 @@ oauth@0.9.x: resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + passport-google-auth@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" @@ -481,6 +534,23 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + request@^2.72.0, request@^2.74.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" @@ -537,6 +607,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + string-template@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" diff --git a/packages/cli/src/hosting/makeEnv.js b/packages/cli/src/hosting/makeEnv.js index 318a72def1..a4fbce6ee0 100644 --- a/packages/cli/src/hosting/makeEnv.js +++ b/packages/cli/src/hosting/makeEnv.js @@ -20,6 +20,7 @@ MINIO_ACCESS_KEY=${randomString.generate()} MINIO_SECRET_KEY=${randomString.generate()} COUCH_DB_PASSWORD=${randomString.generate()} COUCH_DB_USER=${randomString.generate()} +REDIS_PASSWORD=${randomString.generate()} # This section contains variables that do not need to be altered under normal circumstances APP_PORT=4002 diff --git a/packages/server/src/environment.js b/packages/server/src/environment.js index dc15bc8a9a..061f38a985 100644 --- a/packages/server/src/environment.js +++ b/packages/server/src/environment.js @@ -32,6 +32,8 @@ module.exports = { MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, USE_QUOTAS: process.env.USE_QUOTAS, + REDIS_URL: process.env.REDIS_URL, + REDIS_PASSWORD: process.env.REDIS_PASSWORD, // environment NODE_ENV: process.env.NODE_ENV, JEST_WORKER_ID: process.env.JEST_WORKER_ID, diff --git a/packages/worker/src/api/controllers/admin/email.js b/packages/worker/src/api/controllers/admin/email.js index 9f4060d20f..0a29468133 100644 --- a/packages/worker/src/api/controllers/admin/email.js +++ b/packages/worker/src/api/controllers/admin/email.js @@ -1,82 +1,8 @@ -const CouchDB = require("../../../db") -const { StaticDatabases, determineScopedConfig } = require("@budibase/auth").db -const { - EmailTemplatePurpose, - TemplateTypes, - Configs, -} = require("../../../constants") -const { getTemplateByPurpose } = require("../../../constants/templates") -const { getSettingsTemplateContext } = require("../../../utilities/templates") -const { processString } = require("@budibase/string-templates") -const { createSMTPTransport } = require("../../../utilities/email") - -const GLOBAL_DB = StaticDatabases.GLOBAL.name -const TYPE = TemplateTypes.EMAIL - -const FULL_EMAIL_PURPOSES = [ - EmailTemplatePurpose.INVITATION, - EmailTemplatePurpose.PASSWORD_RECOVERY, - EmailTemplatePurpose.WELCOME, -] - -async function buildEmail(purpose, email, user) { - // this isn't a full email - if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) { - throw `Unable to build an email of type ${purpose}` - } - let [base, styles, body] = await Promise.all([ - getTemplateByPurpose(TYPE, EmailTemplatePurpose.BASE), - getTemplateByPurpose(TYPE, EmailTemplatePurpose.STYLES), - getTemplateByPurpose(TYPE, purpose), - ]) - if (!base || !styles || !body) { - throw "Unable to build email, missing base components" - } - base = base.contents - styles = styles.contents - body = body.contents - - // TODO: need to extend the context as much as possible - const context = { - ...(await getSettingsTemplateContext()), - email, - user: user || {}, - } - - body = await processString(body, context) - styles = await processString(styles, context) - // this should now be the complete email HTML - return processString(base, { - ...context, - styles, - body, - }) -} +const { sendEmail } = require("../../../utilities/email") exports.sendEmail = async ctx => { const { groupId, email, userId, purpose } = ctx.request.body - const db = new CouchDB(GLOBAL_DB) - const params = {} - if (groupId) { - params.group = groupId - } - params.type = Configs.SMTP - let user = {} - if (userId) { - user = db.get(userId) - } - const config = await determineScopedConfig(db, params) - if (!config) { - ctx.throw(400, "Unable to find SMTP configuration") - } - const transport = createSMTPTransport(config) - const message = { - from: config.from, - subject: config.subject, - to: email, - html: await buildEmail(purpose, email, user), - } - const response = await transport.sendMail(message) + const response = await sendEmail(email, purpose, { groupId, userId }) ctx.body = { ...response, message: `Email sent to ${email}.`, diff --git a/packages/worker/src/api/controllers/auth.js b/packages/worker/src/api/controllers/auth.js index bcda523a93..05895c8358 100644 --- a/packages/worker/src/api/controllers/auth.js +++ b/packages/worker/src/api/controllers/auth.js @@ -2,31 +2,36 @@ const authPkg = require("@budibase/auth") const { google } = require("@budibase/auth/src/middleware") const { Configs } = require("../../constants") const CouchDB = require("../../db") -const { clearCookie } = authPkg.utils +const { sendEmail } = require("../../utilities/email") +const { clearCookie, getGlobalUserByEmail } = authPkg.utils const { Cookies } = authPkg.constants const { passport } = authPkg.auth const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name +function authInternal(ctx, user, err = null) { + if (err) { + return ctx.throw(403, "Unauthorized") + } + + const expires = new Date() + expires.setDate(expires.getDate() + 1) + + if (!user) { + return ctx.throw(403, "Unauthorized") + } + + ctx.cookies.set(Cookies.Auth, user.token, { + expires, + path: "/", + httpOnly: false, + overwrite: true, + }) +} + exports.authenticate = async (ctx, next) => { return passport.authenticate("local", async (err, user) => { - if (err) { - return ctx.throw(403, "Unauthorized") - } - - const expires = new Date() - expires.setDate(expires.getDate() + 1) - - if (!user) { - return ctx.throw(403, "Unauthorized") - } - - ctx.cookies.set(Cookies.Auth, user.token, { - expires, - path: "/", - httpOnly: false, - overwrite: true, - }) + authInternal(ctx, err, user) delete user.token @@ -34,6 +39,22 @@ exports.authenticate = async (ctx, next) => { })(ctx, next) } +/** + * Reset the user password, used as part of a forgotten password flow. + */ +exports.reset = async ctx => { + const { email } = ctx.request.body + try { + const user = getGlobalUserByEmail(email) + if (user) { + + } + } catch (err) { + // don't throw any kind of error to the user, this might give away something + } + ctx.body = {} +} + exports.logout = async ctx => { clearCookie(ctx, Cookies.Auth) ctx.body = { message: "User logged out" } @@ -69,23 +90,7 @@ exports.googleAuth = async (ctx, next) => { strategy, { successRedirect: "/", failureRedirect: "/error" }, async (err, user) => { - if (err) { - return ctx.throw(403, "Unauthorized") - } - - const expires = new Date() - expires.setDate(expires.getDate() + 1) - - if (!user) { - return ctx.throw(403, "Unauthorized") - } - - ctx.cookies.set(Cookies.Auth, user.token, { - expires, - path: "/", - httpOnly: false, - overwrite: true, - }) + authInternal(ctx, user, err) ctx.redirect("/") } diff --git a/packages/worker/src/api/routes/auth.js b/packages/worker/src/api/routes/auth.js index 72fddec399..e914f334d7 100644 --- a/packages/worker/src/api/routes/auth.js +++ b/packages/worker/src/api/routes/auth.js @@ -1,12 +1,30 @@ const Router = require("@koa/router") const authController = require("../controllers/auth") +const joiValidator = require("../../middleware/joi-validator") +const Joi = require("joi") const router = Router() +function buildAuthValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + username: Joi.string().required(), + password: Joi.string().required(), + }).required().unknown(false)) +} + +function buildResetValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + email: Joi.string().required(), + }).required().unknown(false)) +} + router - .post("/api/admin/auth", authController.authenticate) + .post("/api/admin/auth", buildAuthValidation(), authController.authenticate) + .post("/api/admin/auth/reset", buildResetValidation(), authController.reset) + .post("/api/admin/auth/logout", authController.logout) .get("/api/admin/auth/google", authController.googlePreAuth) .get("/api/admin/auth/google/callback", authController.googleAuth) - .post("/api/admin/auth/logout", authController.logout) module.exports = router diff --git a/packages/worker/src/environment.js b/packages/worker/src/environment.js index 79c9cd1109..0adfe2afae 100644 --- a/packages/worker/src/environment.js +++ b/packages/worker/src/environment.js @@ -26,6 +26,8 @@ module.exports = { LOG_LEVEL: process.env.LOG_LEVEL, JWT_SECRET: process.env.JWT_SECRET, SALT_ROUNDS: process.env.SALT_ROUNDS, + REDIS_URL: process.env.REDIS_URL, + REDIS_PASSWORD: process.env.REDIS_PASSWORD, /* TODO: to remove - once deployment removed */ SELF_HOST_KEY: process.env.SELF_HOST_KEY, COUCH_DB_USERNAME: process.env.COUCH_DB_USERNAME, diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index b5e64a2793..f1059c081e 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -1,6 +1,25 @@ const nodemailer = require("nodemailer") +const CouchDB = require("../db") +const { StaticDatabases, determineScopedConfig } = require("@budibase/auth").db +const { + EmailTemplatePurpose, + TemplateTypes, + Configs, +} = require("../constants") +const { getTemplateByPurpose } = require("../constants/templates") +const { getSettingsTemplateContext } = require("./templates") +const { processString } = require("@budibase/string-templates") -exports.createSMTPTransport = config => { +const GLOBAL_DB = StaticDatabases.GLOBAL.name +const TYPE = TemplateTypes.EMAIL + +const FULL_EMAIL_PURPOSES = [ + EmailTemplatePurpose.INVITATION, + EmailTemplatePurpose.PASSWORD_RECOVERY, + EmailTemplatePurpose.WELCOME, +] + +function createSMTPTransport(config) { const options = { port: config.port, host: config.host, @@ -15,7 +34,68 @@ exports.createSMTPTransport = config => { return nodemailer.createTransport(options) } +async function buildEmail(purpose, email, user) { + // this isn't a full email + if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) { + throw `Unable to build an email of type ${purpose}` + } + let [base, styles, body] = await Promise.all([ + getTemplateByPurpose(TYPE, EmailTemplatePurpose.BASE), + getTemplateByPurpose(TYPE, EmailTemplatePurpose.STYLES), + getTemplateByPurpose(TYPE, purpose), + ]) + if (!base || !styles || !body) { + throw "Unable to build email, missing base components" + } + base = base.contents + styles = styles.contents + body = body.contents + + // TODO: need to extend the context as much as possible + const context = { + ...(await getSettingsTemplateContext()), + email, + user: user || {}, + } + + body = await processString(body, context) + styles = await processString(styles, context) + // this should now be the complete email HTML + return processString(base, { + ...context, + styles, + body, + }) +} + +exports.sendEmail = async (email, purpose, { groupId, userId }) => { + const db = new CouchDB(GLOBAL_DB) + const params = { + type: Configs.SMTP, + } + if (groupId) { + params.group = groupId + } + let user = {} + if (userId) { + user = db.get(userId) + } + const config = await determineScopedConfig(db, params) + if (!config) { + throw "Unable to find SMTP configuration" + } + const transport = createSMTPTransport(config) + const message = { + from: config.from, + subject: config.subject, + to: email, + html: await buildEmail(purpose, email, user), + } + return transport.sendMail(message) +} + + exports.verifyConfig = async config => { - const transport = exports.createSMTPTransport(config) + const transport = createSMTPTransport(config) await transport.verify() } From adce859f98890aee0f1aa0f9f3e05672a91a3a91 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 27 Apr 2021 17:30:19 +0100 Subject: [PATCH 02/19] Formatting. --- packages/auth/src/redis/index.js | 37 ++++++++++++--------- packages/worker/src/api/controllers/auth.js | 1 - packages/worker/src/utilities/email.js | 7 +--- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/auth/src/redis/index.js b/packages/auth/src/redis/index.js index 3d7253e624..b81c3aee74 100644 --- a/packages/auth/src/redis/index.js +++ b/packages/auth/src/redis/index.js @@ -15,9 +15,9 @@ let CLIENT */ function init() { return new Promise((resolve, reject) => { - const [ host, port ] = env.REDIS_URL.split(":") + const [host, port] = env.REDIS_URL.split(":") const opts = { - connectTimeout: CONNECT_TIMEOUT_MS + connectTimeout: CONNECT_TIMEOUT_MS, } if (CLUSTERED) { opts.redisOptions = {} @@ -25,7 +25,7 @@ function init() { opts.redisOptions.password = env.REDIS_PASSWORD opts.slotsRefreshTimeout = SLOT_REFRESH_MS opts.dnsLookup = (address, callback) => callback(null, address) - CLIENT = new Redis.Cluster([ { port, host } ]) + CLIENT = new Redis.Cluster([{ port, host }]) } else { opts.password = env.REDIS_PASSWORD opts.port = port @@ -58,7 +58,7 @@ function promisifyStream(stream) { outputKeys.add(key) }) }) - stream.on("error", (err) => { + stream.on("error", err => { reject(err) }) stream.on("end", async () => { @@ -69,10 +69,12 @@ function promisifyStream(stream) { getPromises.push(CLIENT.get(key)) } const jsonArray = await Promise.all(getPromises) - resolve(keysArray.map(key => ({ - key: removeDbPrefix(key), - value: JSON.parse(jsonArray.shift()), - }))) + resolve( + keysArray.map(key => ({ + key: removeDbPrefix(key), + value: JSON.parse(jsonArray.shift()), + })) + ) } catch (err) { reject(err) } @@ -91,20 +93,21 @@ class RedisWrapper { } async scan() { - const db = this._db, client = this._client + const db = this._db, + client = this._client let stream if (CLUSTERED) { let node = client.nodes("master") - stream = node[0].scanStream({match: db + "-*", count: 100}) - + stream = node[0].scanStream({ match: db + "-*", count: 100 }) } else { - stream = client.scanStream({match: db + "-*", count: 100}) + stream = client.scanStream({ match: db + "-*", count: 100 }) } return promisifyStream(stream) } async get(key) { - const db = this._db, client = this._client + const db = this._db, + client = this._client let response = await client.get(addDbPrefix(db, key)) // overwrite the prefixed key if (response != null && response.key) { @@ -114,8 +117,9 @@ class RedisWrapper { } async store(key, value, expirySeconds = null) { - const db = this._db, client = this._client - if (typeof(value) === "object") { + const db = this._db, + client = this._client + if (typeof value === "object") { value = JSON.stringify(value) } const prefixedKey = addDbPrefix(db, key) @@ -126,7 +130,8 @@ class RedisWrapper { } async delete(key) { - const db = this._db, client = this._client + const db = this._db, + client = this._client await client.del(addDbPrefix(db, key)) } diff --git a/packages/worker/src/api/controllers/auth.js b/packages/worker/src/api/controllers/auth.js index 05895c8358..15c38e7f09 100644 --- a/packages/worker/src/api/controllers/auth.js +++ b/packages/worker/src/api/controllers/auth.js @@ -47,7 +47,6 @@ exports.reset = async ctx => { try { const user = getGlobalUserByEmail(email) if (user) { - } } catch (err) { // don't throw any kind of error to the user, this might give away something diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index f1059c081e..23af1ab623 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -1,11 +1,7 @@ const nodemailer = require("nodemailer") const CouchDB = require("../db") const { StaticDatabases, determineScopedConfig } = require("@budibase/auth").db -const { - EmailTemplatePurpose, - TemplateTypes, - Configs, -} = require("../constants") +const { EmailTemplatePurpose, TemplateTypes, Configs } = require("../constants") const { getTemplateByPurpose } = require("../constants/templates") const { getSettingsTemplateContext } = require("./templates") const { processString } = require("@budibase/string-templates") @@ -94,7 +90,6 @@ exports.sendEmail = async (email, purpose, { groupId, userId }) => { return transport.sendMail(message) } - exports.verifyConfig = async config => { const transport = createSMTPTransport(config) await transport.verify() From 60b61f1322a9ee4dc547c53792802ee676d85988 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 28 Apr 2021 14:28:25 +0100 Subject: [PATCH 03/19] Fixing login issue. --- packages/auth/src/middleware/authenticated.js | 4 ++ packages/server/yarn.lock | 53 +------------------ .../worker/src/api/controllers/admin/users.js | 7 +++ packages/worker/src/api/controllers/auth.js | 2 +- 4 files changed, 13 insertions(+), 53 deletions(-) diff --git a/packages/auth/src/middleware/authenticated.js b/packages/auth/src/middleware/authenticated.js index d64c30a70a..007ebe229d 100644 --- a/packages/auth/src/middleware/authenticated.js +++ b/packages/auth/src/middleware/authenticated.js @@ -3,6 +3,10 @@ const database = require("../db") const { getCookie, clearCookie } = require("../utils") const { StaticDatabases } = require("../db/utils") +function makeRegex() { + +} + module.exports = (noAuthPatterns = []) => { const regex = new RegExp(noAuthPatterns.join("|")) return async (ctx, next) => { diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index 61bb1aac1d..da88ffcdf5 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -5198,22 +5198,6 @@ jsonschema@1.4.0: resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw== -jsonwebtoken@8.5.1: - version "8.5.1" - resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" - integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== - dependencies: - jws "^3.2.2" - lodash.includes "^4.3.0" - lodash.isboolean "^3.0.3" - lodash.isinteger "^4.0.4" - lodash.isnumber "^3.0.3" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.once "^4.0.0" - ms "^2.1.1" - semver "^5.6.0" - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -5253,7 +5237,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@3.x.x, jws@^3.2.2: +jws@3.x.x: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -5650,41 +5634,11 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.includes@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" - integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= - -lodash.isboolean@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" - integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= - lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= -lodash.isinteger@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" - integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= - -lodash.isnumber@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" - integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - -lodash.isstring@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" - integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= - lodash.keys@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" @@ -5700,11 +5654,6 @@ lodash.omit@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= -lodash.once@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= - lodash.pick@^4.0.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js index 146373e671..e9e6b64ac0 100644 --- a/packages/worker/src/api/controllers/admin/users.js +++ b/packages/worker/src/api/controllers/admin/users.js @@ -61,7 +61,14 @@ exports.save = async ctx => { } exports.firstUser = async ctx => { + const existing = await getGlobalUserByEmail(FIRST_USER_EMAIL) + const params = {} + if (existing) { + params._id = existing._id + params._rev = existing._rev + } ctx.request.body = { + ...params, email: FIRST_USER_EMAIL, password: FIRST_USER_PASSWORD, roles: {}, diff --git a/packages/worker/src/api/controllers/auth.js b/packages/worker/src/api/controllers/auth.js index 15c38e7f09..18ee2d64e8 100644 --- a/packages/worker/src/api/controllers/auth.js +++ b/packages/worker/src/api/controllers/auth.js @@ -31,7 +31,7 @@ function authInternal(ctx, user, err = null) { exports.authenticate = async (ctx, next) => { return passport.authenticate("local", async (err, user) => { - authInternal(ctx, err, user) + authInternal(ctx, user, err) delete user.token From 04fd81eb7aa55875cf3e4b2627e47080b23f2918 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 28 Apr 2021 15:13:33 +0100 Subject: [PATCH 04/19] v0.18.6 --- packages/auth/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/package.json b/packages/auth/package.json index 2de0bd7a3e..72ea0bc3ba 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.0.1", + "version": "0.18.6", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", From 2b58d695afba48021923d17ae522ed305df3589a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 28 Apr 2021 15:25:49 +0100 Subject: [PATCH 05/19] Updating packages so that @budibase/auth doesn't stop installations. --- packages/server/package.json | 2 +- packages/server/yarn.lock | 1367 +++++++++++++++++++++++++++++++++- packages/worker/package.json | 2 +- packages/worker/yarn.lock | 163 +++- 4 files changed, 1512 insertions(+), 22 deletions(-) diff --git a/packages/server/package.json b/packages/server/package.json index eadef19528..8d8f6704df 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -79,7 +79,7 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.0.1", + "@budibase/auth": "^0.18.6", "@budibase/client": "^0.8.16", "@budibase/string-templates": "^0.8.16", "@elastic/elasticsearch": "7.10.0", diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index da88ffcdf5..0451fa956b 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -7,6 +7,11 @@ resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.0.3.tgz#bc5b5532ecafd923a61f2fb097e3b108c0106a3f" integrity sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA== +"@adobe/spectrum-css-workflow-icons@^1.1.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@adobe/spectrum-css-workflow-icons/-/spectrum-css-workflow-icons-1.2.1.tgz#7e2cb3fcfb5c8b12d7275afafbb6ec44913551b4" + integrity sha512-uVgekyBXnOVkxp+CUssjN/gefARtudZC8duEn1vm0lBQFwGRZFlDEzU1QC+aIRWCrD1Z8OgRpmBYlSZ7QS003w== + "@azure/abort-controller@^1.0.0": version "1.0.4" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.0.4.tgz#fd3c4d46c8ed67aace42498c8e2270960250eafd" @@ -261,6 +266,125 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@budibase/auth@^0.18.6": + version "0.18.6" + resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.18.6.tgz#d893005962afd9425f10e2ac8d1d495047d0d44e" + integrity sha512-pdyqR8G240lToMe2OZNpw2YzuRwOlOT+cAfVHPMBxJJKF0VvZ0K500NoSUINEQPr4IfWpPSu6CQhq+ROf4pMXA== + dependencies: + bcryptjs "^2.4.3" + ioredis "^4.27.1" + jsonwebtoken "^8.5.1" + koa-passport "^4.1.4" + passport-google-auth "^1.0.2" + passport-google-oauth "^2.0.0" + passport-jwt "^4.0.0" + passport-local "^1.0.0" + uuid "^8.3.2" + +"@budibase/bbui@^1.58.13": + version "1.58.13" + resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-1.58.13.tgz#59df9c73def2d81c75dcbd2266c52c19db88dbd7" + integrity sha512-Zk6CKXdBfKsTVzA1Xs5++shdSSZLfphVpZuKVbjfzkgtuhyH7ruucexuSHEpFsxjW5rEKgKIBoRFzCK5vPvN0w== + dependencies: + markdown-it "^12.0.2" + quill "^1.3.7" + sirv-cli "^0.4.6" + svelte-flatpickr "^2.4.0" + svelte-portal "^1.0.0" + turndown "^7.0.0" + +"@budibase/client@^0.8.16": + version "0.8.17" + resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.8.17.tgz#71b58f124b36d07994f0733c7bd4aba40bb4672d" + integrity sha512-CGYDBLJU4se4rRvDohKlp0Ip2indqnrBS1WDsjfQIyf8pt8v2qx69A/MrpXF3z0LU7uxKLKIWtxeZtKAJ7Lysw== + dependencies: + "@budibase/string-templates" "^0.8.17" + regexparam "^1.3.0" + shortid "^2.2.15" + svelte-spa-router "^3.0.5" + +"@budibase/handlebars-helpers@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.3.tgz#b6e5c91b83e8906e7d7ff10ddde277a3d561016e" + integrity sha512-MS1ptZEYq8o9J3tNLM7cZ2RGSSJIer4GiMIUHtbBI3sC9UKqZebao1JYNfmZKpNjntuqhZKgjqc5GfnVIEjsYQ== + dependencies: + arr-flatten "^1.1.0" + array-sort "^0.1.4" + define-property "^1.0.0" + extend-shallow "^3.0.2" + "falsey" "^0.3.2" + for-in "^1.0.2" + for-own "^1.0.0" + get-object "^0.2.0" + get-value "^2.0.6" + handlebars "^4.0.11" + handlebars-utils "^1.0.6" + has-value "^1.0.0" + helper-date "^1.0.1" + helper-markdown "^1.0.0" + helper-md "^0.2.2" + html-tag "^2.0.0" + is-even "^1.0.0" + is-glob "^4.0.0" + is-number "^4.0.0" + kind-of "^6.0.0" + logging-helpers "^1.0.0" + micromatch "^3.1.4" + relative "^3.0.2" + striptags "^3.1.0" + to-gfm-code-block "^0.1.1" + year "^0.2.1" + +"@budibase/standard-components@^0.8.16": + version "0.8.17" + resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.8.17.tgz#9a0141e429e15e31d5cb2523fc66f19062a38fb0" + integrity sha512-N0D26NVxFqvhf+DuyNVH4c2LibuzwQbwIOeeeso6NUGBP7mZ0II1Ky+sW5kZS3ObGkqsuO5QkZUfHb+m1xTIVA== + dependencies: + "@adobe/spectrum-css-workflow-icons" "^1.1.0" + "@budibase/bbui" "^1.58.13" + "@budibase/svelte-ag-grid" "^1.0.4" + "@spectrum-css/actionbutton" "^1.0.0-beta.1" + "@spectrum-css/button" "^3.0.0-beta.6" + "@spectrum-css/checkbox" "^3.0.0-beta.6" + "@spectrum-css/fieldlabel" "^3.0.0-beta.7" + "@spectrum-css/icon" "^3.0.0-beta.2" + "@spectrum-css/inputgroup" "^3.0.0-beta.7" + "@spectrum-css/menu" "^3.0.0-beta.5" + "@spectrum-css/page" "^3.0.0-beta.0" + "@spectrum-css/picker" "^1.0.0-beta.3" + "@spectrum-css/popover" "^3.0.0-beta.6" + "@spectrum-css/stepper" "^3.0.0-beta.7" + "@spectrum-css/textfield" "^3.0.0-beta.6" + "@spectrum-css/vars" "^3.0.0-beta.2" + apexcharts "^3.22.1" + flatpickr "^4.6.6" + loadicons "^1.0.0" + lodash.debounce "^4.0.8" + markdown-it "^12.0.2" + quill "^1.3.7" + remixicon "^2.5.0" + svelte-apexcharts "^1.0.2" + svelte-flatpickr "^3.1.0" + turndown "^7.0.0" + +"@budibase/string-templates@^0.8.16", "@budibase/string-templates@^0.8.17": + version "0.8.17" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.8.17.tgz#107937d1a0d1249fc65b61cc050ee3d54e744b65" + integrity sha512-FTjzF4HdfXUuyHtbJ6jH+xhp+dzYpvwOvvbG6yXnV0WZg3Xj8svm6GqKPkwODyMYqtLVzEoExZU7JaM0ZX0iqg== + dependencies: + "@budibase/handlebars-helpers" "^0.11.3" + dayjs "^1.10.4" + handlebars "^4.7.6" + handlebars-utils "^1.0.6" + lodash "^4.17.20" + +"@budibase/svelte-ag-grid@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@budibase/svelte-ag-grid/-/svelte-ag-grid-1.0.4.tgz#41cceec4bde2c4aea8b9da8f610fe36055c7709f" + integrity sha512-JZm6qujxnZpqw7Twbegr6se4sHhyWzN0Cibrk5bVBH32hBgzD6dd33fxwrjHKkWFxjys9wRT+cqYgYVlSt9E3w== + dependencies: + ag-grid-community "^24.0.0" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -806,6 +930,11 @@ dependencies: cross-spawn "^7.0.1" +"@polka/url@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-0.5.0.tgz#b21510597fd601e5d7c95008b76bf0d254ebfd31" + integrity sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw== + "@sendgrid/client@^7.1.1": version "7.4.2" resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.4.2.tgz#204a9fbb5dc05a721a5d8cd8930f57f9f8e612b1" @@ -918,6 +1047,73 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== +"@spectrum-css/actionbutton@^1.0.0-beta.1": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/actionbutton/-/actionbutton-1.0.3.tgz#8f7342a69b303c5acdcfa0a59f5e9267b9f3cb30" + integrity sha512-P9qoCPSiZ1SB6ZYqK5hub0vGty00YYqonQE0KTjtb1i+T1nYR/87vWqVPERx9j63uhgZncjwFYaThTvRqye7eQ== + +"@spectrum-css/button@^3.0.0-beta.6": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/button/-/button-3.0.3.tgz#2df1efaab6c7e0b3b06cb4b59e1eae59c7f1fc84" + integrity sha512-6CnLPqqtaU/PcSSIGeGRi0iFIIxIUByYLKFO6zn5NEUc12KQ28dJ4PLwB6WBa0L8vRoAGlnWWH2ZZweTijbXgg== + +"@spectrum-css/checkbox@^3.0.0-beta.6": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/checkbox/-/checkbox-3.0.3.tgz#8577067fc8b97e4609f92bd242364937a533a7bb" + integrity sha512-QVG9uMHq+lh70Dh6mDNnY+vEvNz2p7VC6xgLfDYfijp2qeiqYPq72fQK6p/SiyqPk96ZACzNRwgeROU6Xf6Wgg== + +"@spectrum-css/fieldlabel@^3.0.0-beta.7": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/fieldlabel/-/fieldlabel-3.0.3.tgz#f73c04d20734d4718ffb620dc46458904685b449" + integrity sha512-nEvIkEXCD5n4fW67Unq6Iu7VXoauEd/JGpfTY02VsC5p4FJLnwKfPDbJUuUsqClAxqw7nAsmXVKtn4zQFf5yPQ== + +"@spectrum-css/icon@^3.0.0-beta.2": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/icon/-/icon-3.0.3.tgz#5c612822380927087aebd526855d82ed2c3e2cba" + integrity sha512-hyloKOejPCXhP3MBNsm3SjR9j8xT1R1S19p32KW/0Qhj+VMUtfyEPmevyFptpn7wcovQccdl/vZVIVDuML/imw== + +"@spectrum-css/inputgroup@^3.0.0-beta.7": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/inputgroup/-/inputgroup-3.0.3.tgz#00c9a370ddc2c55cf0f37dd6069faa9501fd7eb5" + integrity sha512-FqRJTiLL7jiGfzDVXWUGVLqHryJjCcqQIrqAi+Tq0oenapzsBe2qc/zIrKgh2wtMI+NTIBLXTECvij3L1HlqAg== + +"@spectrum-css/menu@^3.0.0-beta.5": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/menu/-/menu-3.0.3.tgz#46a9b221bb5f470a2f8a934bdfd512d84d2fdc4d" + integrity sha512-qKA9J/MrikNKIpCEHsAazG2vY3im5tjGCmo6p9Pdnu8/aQMsiuZDHZayukeCttJUZkrb9guDVL9OIHlK5RZvcQ== + +"@spectrum-css/page@^3.0.0-beta.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/page/-/page-3.0.2.tgz#8f0c03d25f5565fb13115541a8fcaf0e1d3a8ee0" + integrity sha512-lCXWjonLwYBg8FHUEkiFX0Mmfk+9Uivgvxq0DTulPlWrJcULTwjaOiY28/YBz7Fy1wuv/0KORbkPRALpYldBZg== + dependencies: + "@spectrum-css/vars" "^3.0.2" + +"@spectrum-css/picker@^1.0.0-beta.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/picker/-/picker-1.0.3.tgz#21379bcf8ae94277deeb6ad65dcd9e2bbfacb487" + integrity sha512-oHLGxBx5BwVCSGo7/T1C9PTHX1+/5AmVjyLiTJ4UoIdSJmOERw9YcRZbcGZgBJNWbxcjr4TyGtwj1EcSjEy97w== + +"@spectrum-css/popover@^3.0.0-beta.6": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/popover/-/popover-3.0.3.tgz#6fb69873474fb968afb738eacb9e121f93e83a09" + integrity sha512-KvmXv4TV19FBx39KfmgVlDYtvtBqv/8RRK7RRLDDHGViTxZtShjVsVpwIgfkfgn4iJztCnXpWzFqRXWUu2XCpQ== + +"@spectrum-css/stepper@^3.0.0-beta.7": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@spectrum-css/stepper/-/stepper-3.0.3.tgz#ae89846886431e3edeee060207b8f81540f73a34" + integrity sha512-prAD61ImlOTs9b6PfB3cB08x4lAfxtvnW+RZiTYky0E8GgZdrc/MfCkL5/oqQaIQUtyQv/3Lb7ELAf/0K8QTXw== + +"@spectrum-css/textfield@^3.0.0-beta.6": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/textfield/-/textfield-3.0.2.tgz#907f62d2dc82852dd6236a820be99e252b531631" + integrity sha512-nkFgAb0cP4jUodkUBErMNfyF78jJLtgL1Mrr9/rvGpGobo10IAbb8zZY4CkZ64o8XmMy/85+wZTKcx+KHatqpg== + +"@spectrum-css/vars@^3.0.0-beta.2", "@spectrum-css/vars@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@spectrum-css/vars/-/vars-3.0.2.tgz#ea9062c3c98dfc6ba59e5df14a03025ad8969999" + integrity sha512-vzS9KqYXot4J3AEER/u618MXWAS+IoMvYMNrOoscKiLLKYQWenaueakUWulFonToPd/9vIpqtdbwxznqrK5qDw== + "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -1200,6 +1396,11 @@ adal-node@^0.1.28: xmldom ">= 0.1.x" xpath.js "~1.1.0" +ag-grid-community@^24.0.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/ag-grid-community/-/ag-grid-community-24.1.0.tgz#1e3cab51211822e08d56f03a491b7c0deaa398e6" + integrity sha512-pWnWphuDcejZ8ahf6C734EpCx3XQ6dHEZWMWTlCdHNT0mZBLJ4YKCGACX+ttAEtSX2MGM3G13JncvuratUlYag== + agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" @@ -1245,6 +1446,130 @@ ansi-align@^3.0.0: dependencies: string-width "^3.0.0" +ansi-bgblack@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz#a68ba5007887701b6aafbe3fa0dadfdfa8ee3ca2" + integrity sha1-poulAHiHcBtqr74/oNrf36juPKI= + dependencies: + ansi-wrap "0.1.0" + +ansi-bgblue@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz#67bdc04edc9b9b5278969da196dea3d75c8c3613" + integrity sha1-Z73ATtybm1J4lp2hlt6j11yMNhM= + dependencies: + ansi-wrap "0.1.0" + +ansi-bgcyan@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz#58489425600bde9f5507068dd969ebfdb50fe768" + integrity sha1-WEiUJWAL3p9VBwaN2Wnr/bUP52g= + dependencies: + ansi-wrap "0.1.0" + +ansi-bggreen@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz#4e3191248529943f4321e96bf131d1c13816af49" + integrity sha1-TjGRJIUplD9DIelr8THRwTgWr0k= + dependencies: + ansi-wrap "0.1.0" + +ansi-bgmagenta@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz#9b28432c076eaa999418672a3efbe19391c2c7a1" + integrity sha1-myhDLAduqpmUGGcqPvvhk5HCx6E= + dependencies: + ansi-wrap "0.1.0" + +ansi-bgred@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgred/-/ansi-bgred-0.1.1.tgz#a76f92838382ba43290a6c1778424f984d6f1041" + integrity sha1-p2+Sg4OCukMpCmwXeEJPmE1vEEE= + dependencies: + ansi-wrap "0.1.0" + +ansi-bgwhite@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz#6504651377a58a6ececd0331994e480258e11ba8" + integrity sha1-ZQRlE3elim7OzQMxmU5IAljhG6g= + dependencies: + ansi-wrap "0.1.0" + +ansi-bgyellow@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz#c3fe2eb08cd476648029e6874d15a0b38f61d44f" + integrity sha1-w/4usIzUdmSAKeaHTRWgs49h1E8= + dependencies: + ansi-wrap "0.1.0" + +ansi-black@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-black/-/ansi-black-0.1.1.tgz#f6185e889360b2545a1ec50c0bf063fc43032453" + integrity sha1-9hheiJNgslRaHsUMC/Bj/EMDJFM= + dependencies: + ansi-wrap "0.1.0" + +ansi-blue@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-blue/-/ansi-blue-0.1.1.tgz#15b804990e92fc9ca8c5476ce8f699777c21edbf" + integrity sha1-FbgEmQ6S/JyoxUds6PaZd3wh7b8= + dependencies: + ansi-wrap "0.1.0" + +ansi-bold@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-bold/-/ansi-bold-0.1.1.tgz#3e63950af5acc2ae2e670e6f67deb115d1a5f505" + integrity sha1-PmOVCvWswq4uZw5vZ96xFdGl9QU= + dependencies: + ansi-wrap "0.1.0" + +ansi-colors@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-0.2.0.tgz#72c31de2a0d9a2ccd0cac30cc9823eeb2f6434b5" + integrity sha1-csMd4qDZoszQysMMyYI+6y9kNLU= + dependencies: + ansi-bgblack "^0.1.1" + ansi-bgblue "^0.1.1" + ansi-bgcyan "^0.1.1" + ansi-bggreen "^0.1.1" + ansi-bgmagenta "^0.1.1" + ansi-bgred "^0.1.1" + ansi-bgwhite "^0.1.1" + ansi-bgyellow "^0.1.1" + ansi-black "^0.1.1" + ansi-blue "^0.1.1" + ansi-bold "^0.1.1" + ansi-cyan "^0.1.1" + ansi-dim "^0.1.1" + ansi-gray "^0.1.1" + ansi-green "^0.1.1" + ansi-grey "^0.1.1" + ansi-hidden "^0.1.1" + ansi-inverse "^0.1.1" + ansi-italic "^0.1.1" + ansi-magenta "^0.1.1" + ansi-red "^0.1.1" + ansi-reset "^0.1.1" + ansi-strikethrough "^0.1.1" + ansi-underline "^0.1.1" + ansi-white "^0.1.1" + ansi-yellow "^0.1.1" + lazy-cache "^2.0.1" + +ansi-cyan@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" + integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= + dependencies: + ansi-wrap "0.1.0" + +ansi-dim@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-dim/-/ansi-dim-0.1.1.tgz#40de4c603aa8086d8e7a86b8ff998d5c36eefd6c" + integrity sha1-QN5MYDqoCG2Oeoa4/5mNXDbu/Ww= + dependencies: + ansi-wrap "0.1.0" + ansi-escapes@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -1257,6 +1582,62 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + dependencies: + ansi-wrap "0.1.0" + +ansi-green@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-green/-/ansi-green-0.1.1.tgz#8a5d9a979e458d57c40e33580b37390b8e10d0f7" + integrity sha1-il2al55FjVfEDjNYCzc5C44Q0Pc= + dependencies: + ansi-wrap "0.1.0" + +ansi-grey@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-grey/-/ansi-grey-0.1.1.tgz#59d98b6ac2ba19f8a51798e9853fba78339a33c1" + integrity sha1-WdmLasK6GfilF5jphT+6eDOaM8E= + dependencies: + ansi-wrap "0.1.0" + +ansi-hidden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-hidden/-/ansi-hidden-0.1.1.tgz#ed6a4c498d2bb7cbb289dbf2a8d1dcc8567fae0f" + integrity sha1-7WpMSY0rt8uyidvyqNHcyFZ/rg8= + dependencies: + ansi-wrap "0.1.0" + +ansi-inverse@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-inverse/-/ansi-inverse-0.1.1.tgz#b6af45826fe826bfb528a6c79885794355ccd269" + integrity sha1-tq9Fgm/oJr+1KKbHmIV5Q1XM0mk= + dependencies: + ansi-wrap "0.1.0" + +ansi-italic@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-italic/-/ansi-italic-0.1.1.tgz#104743463f625c142a036739cf85eda688986f23" + integrity sha1-EEdDRj9iXBQqA2c5z4XtpoiYbyM= + dependencies: + ansi-wrap "0.1.0" + +ansi-magenta@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-magenta/-/ansi-magenta-0.1.1.tgz#063b5ba16fb3f23e1cfda2b07c0a89de11e430ae" + integrity sha1-BjtboW+z8j4c/aKwfAqJ3hHkMK4= + dependencies: + ansi-wrap "0.1.0" + +ansi-red@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" + integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= + dependencies: + ansi-wrap "0.1.0" + ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -1277,6 +1658,20 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-reset@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-reset/-/ansi-reset-0.1.1.tgz#e7e71292c3c7ddcd4d62ef4a6c7c05980911c3b7" + integrity sha1-5+cSksPH3c1NYu9KbHwFmAkRw7c= + dependencies: + ansi-wrap "0.1.0" + +ansi-strikethrough@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz#d84877140b2cff07d1c93ebce69904f68885e568" + integrity sha1-2Eh3FAss/wfRyT685pkE9oiF5Wg= + dependencies: + ansi-wrap "0.1.0" + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1291,6 +1686,32 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-underline@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-underline/-/ansi-underline-0.1.1.tgz#dfc920f4c97b5977ea162df8ffb988308aaa71a4" + integrity sha1-38kg9Ml7WXfqFi34/7mIMIqqcaQ= + dependencies: + ansi-wrap "0.1.0" + +ansi-white@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-white/-/ansi-white-0.1.1.tgz#9c77b7c193c5ee992e6011d36ec4c921b4578944" + integrity sha1-nHe3wZPF7pkuYBHTbsTJIbRXiUQ= + dependencies: + ansi-wrap "0.1.0" + +ansi-wrap@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + +ansi-yellow@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-yellow/-/ansi-yellow-0.1.1.tgz#cb9356f2f46c732f0e3199e6102955a77da83c1d" + integrity sha1-y5NW8vRscy8OMZnmEClVp32oPB0= + dependencies: + ansi-wrap "0.1.0" + any-base@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" @@ -1317,6 +1738,18 @@ anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" +apexcharts@^3.19.2, apexcharts@^3.22.1: + version "3.26.1" + resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.26.1.tgz#2094ec0cfd00ed8129d93e73e75018716d55ef5b" + integrity sha512-Z/pfGTsL4YUm1tHd6a0d0G2hX4XUmhEI0b/5BxVK69dEB/XXvVMX9hKCkcIx+kPyVqVFCuo91ZjCdqjMcmSVBA== + dependencies: + svg.draggable.js "^2.2.2" + svg.easing.js "^2.0.0" + svg.filter.js "^2.0.2" + svg.pathmorphing.js "^0.1.3" + svg.resize.js "^1.4.3" + svg.select.js "^3.0.1" + app-builder-bin@3.5.12: version "3.5.12" resolved "https://registry.yarnpkg.com/app-builder-bin/-/app-builder-bin-3.5.12.tgz#bbe174972cc1f481f73d6d92ad47a8b4c7eb4530" @@ -1369,7 +1802,7 @@ archive-type@^4.0.0: dependencies: file-type "^4.2.0" -argparse@^1.0.7: +argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -1416,6 +1849,15 @@ array-equal@^1.0.0: resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= +array-sort@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-0.1.4.tgz#662855eaeb671b4188df4451b2f24a0753992b23" + integrity sha512-BNcM+RXxndPxiZ2rd76k6nyQLRZr2/B/sdi8pQ+Joafr5AH279L40dfokSUTp8O+AaqYjXWhblBWa2st2nc4fQ== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1485,6 +1927,13 @@ async@>=0.6.0: resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== +async@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" + integrity sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw= + dependencies: + lodash "^4.14.0" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1505,6 +1954,13 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +autolinker@~0.28.0: + version "0.28.1" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" + integrity sha1-BlK0kYgYefB3XazgzcoyM5QqTkc= + dependencies: + gulp-header "^1.7.1" + aws-sdk@^2.767.0: version "2.877.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.877.0.tgz#e580c08aeba8cb148d1dc0ee16348a410bf6852e" @@ -1595,6 +2051,11 @@ base64-js@^1.0.2, base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +base64url@3.x.x: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1615,7 +2076,7 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bcryptjs@2.4.3: +bcryptjs@2.4.3, bcryptjs@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= @@ -2130,6 +2591,16 @@ clone-response@1.0.2, clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + co-body@^5.1.1: version "5.2.0" resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124" @@ -2253,6 +2724,13 @@ concat-stream@^1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" +concat-with-sourcemaps@*: + version "1.1.0" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== + dependencies: + source-map "^0.6.1" + config-chain@^1.1.11: version "1.1.12" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" @@ -2273,6 +2751,11 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" +console-clear@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/console-clear/-/console-clear-1.1.1.tgz#995e20cbfbf14dd792b672cde387bd128d674bf7" + integrity sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ== + content-disposition@^0.5.2, content-disposition@~0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -2407,11 +2890,23 @@ date-utils@*: resolved "https://registry.yarnpkg.com/date-utils/-/date-utils-1.2.21.tgz#61fb16cdc1274b3c9acaaffe9fc69df8720a2b64" integrity sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q= +date.js@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/date.js/-/date.js-0.3.3.tgz#ef1e92332f507a638795dbb985e951882e50bbda" + integrity sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw== + dependencies: + debug "~3.1.0" + dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +dayjs@^1.10.4: + version "1.10.4" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.4.tgz#8e544a9b8683f61783f570980a8a80eaf54ab1e2" + integrity sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw== + debug@4, debug@^4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" @@ -2517,6 +3012,18 @@ decompress@^4.2.1: pify "^2.3.0" strip-dirs "^2.0.0" +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -2537,6 +3044,13 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + default-shell@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" @@ -2607,7 +3121,7 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= -denque@^1.4.1: +denque@^1.1.0, denque@^1.4.1: version "1.5.0" resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ== @@ -2713,6 +3227,11 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domino@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe" + integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ== + dot-prop@^5.2.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -2937,6 +3456,16 @@ ensure-error@^2.0.0: resolved "https://registry.yarnpkg.com/ensure-error/-/ensure-error-2.1.0.tgz#f11fbe383c0cf4a54850ac77acceb7bc06e0f99d" integrity sha512-+BMSJHw9gxiJAAp2ZR1E0TNcL09dD3lOvkl7WVm4+Y6xnes/pMetP/TzCHiDduh8ihNDjbGfuYxl7l4PA1xZ8A== +ent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + +entities@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5" + integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -2966,6 +3495,11 @@ error-inject@^1.0.0: resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= +error-symbol@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/error-symbol/-/error-symbol-0.1.0.tgz#0a4dae37d600d15a29ba453d8ef920f1844333f6" + integrity sha1-Ck2uN9YA0VopukU9jvkg8YRDM/Y= + es-abstract@^1.18.0-next.2: version "1.18.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" @@ -3208,6 +3742,11 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +eventemitter3@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" + integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo= + events@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -3309,7 +3848,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@^3.0.0, extend@~3.0.2: +extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -3367,11 +3906,23 @@ falafel@^1.0.1: isarray "0.0.1" object-keys "^1.0.6" +"falsey@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/falsey/-/falsey-0.3.2.tgz#b21c90c5c34660fc192bf909575db95b6880d597" + integrity sha512-lxEuefF5MBIVDmE6XeqCdM4BWk1+vYmGZtkbKZ/VFcg6uBBw6fXNEbWmxCjDdQlFc9hy450nkiWwM3VAW6G1qg== + dependencies: + kind-of "^5.0.2" + fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig== + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -3551,6 +4102,11 @@ flat-cache@^2.0.1: rimraf "2.6.3" write "1.0.3" +flatpickr@^4.5.2, flatpickr@^4.6.6: + version "4.6.9" + resolved "https://registry.yarnpkg.com/flatpickr/-/flatpickr-4.6.9.tgz#9a13383e8a6814bda5d232eae3fcdccb97dc1499" + integrity sha512-F0azNNi8foVWKSF+8X+ZJzz8r9sE1G4hl06RyceIaLvyltKvDl6vqk9Lm/6AUUCi5HWaIjiUbk7UpeE/fOXOpw== + flatstr@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.12.tgz#c2ba6a08173edbb6c9640e3055b95e287ceb5931" @@ -3573,11 +4129,18 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -for-in@^1.0.2: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -3636,6 +4199,11 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0= + fs-extra@8.1.0, fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -3702,6 +4270,19 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-object@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" + integrity sha1-2S/31RkMZFMM2gVD2sY6PUf+jAw= + dependencies: + is-number "^2.0.2" + isobject "^0.2.0" + +get-port@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw= + get-stream@3.0.0, get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -3843,6 +4424,32 @@ globalthis@^1.0.1: dependencies: define-properties "^1.1.3" +google-auth-library@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" + integrity sha1-bhW6vuhf0d0U2NEoopW2g41SE24= + dependencies: + gtoken "^1.2.1" + jws "^3.1.4" + lodash.noop "^3.0.1" + request "^2.74.0" + +google-p12-pem@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" + integrity sha1-M8RqsCGqc0+gMys5YKmj/8svMXc= + dependencies: + node-forge "^0.7.1" + +googleapis@^16.0.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576" + integrity sha1-Dxny1wVy2RiIGg9ibjsaL6hilXY= + dependencies: + async "~2.1.4" + google-auth-library "~0.10.0" + string-template "~1.0.0" + got@^8.3.1: version "8.3.2" resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" @@ -3898,6 +4505,45 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +gtoken@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" + integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== + dependencies: + google-p12-pem "^0.1.0" + jws "^3.0.0" + mime "^1.4.1" + request "^2.72.0" + +gulp-header@^1.7.1: + version "1.8.12" + resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" + integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== + dependencies: + concat-with-sourcemaps "*" + lodash.template "^4.4.0" + through2 "^2.0.0" + +handlebars-utils@^1.0.2, handlebars-utils@^1.0.4, handlebars-utils@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" + integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== + dependencies: + kind-of "^6.0.0" + typeof-article "^0.1.1" + +handlebars@^4.0.11, handlebars@^4.7.6: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -3986,6 +4632,39 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +helper-date@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/helper-date/-/helper-date-1.0.1.tgz#12fedea3ad8e44a7ca4c4efb0ff4104a5120cffb" + integrity sha512-wU3VOwwTJvGr/w5rZr3cprPHO+hIhlblTJHD6aFBrKLuNbf4lAmkawd2iK3c6NbJEvY7HAmDpqjOFSI5/+Ey2w== + dependencies: + date.js "^0.3.1" + handlebars-utils "^1.0.4" + moment "^2.18.1" + +helper-markdown@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/helper-markdown/-/helper-markdown-1.0.0.tgz#ee7e9fc554675007d37eb90f7853b13ce74f3e10" + integrity sha512-AnDqMS4ejkQK0MXze7pA9TM3pu01ZY+XXsES6gEE0RmCGk5/NIfvTn0NmItfyDOjRAzyo9z6X7YHbHX4PzIvOA== + dependencies: + handlebars-utils "^1.0.2" + highlight.js "^9.12.0" + remarkable "^1.7.1" + +helper-md@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" + integrity sha1-wfWdflW7riM2L9ig6XFgeuxp1B8= + dependencies: + ent "^2.2.0" + extend-shallow "^2.0.1" + fs-exists-sync "^0.1.0" + remarkable "^1.6.2" + +highlight.js@^9.12.0: + version "9.18.5" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825" + integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA== + hosted-git-info@^2.1.4: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" @@ -4022,6 +4701,14 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-tag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" + integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== + dependencies: + is-self-closing "^1.0.1" + kind-of "^6.0.0" + http-assert@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.4.1.tgz#c5f725d677aa7e873ef736199b89686cceb37878" @@ -4192,6 +4879,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" +info-symbol@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/info-symbol/-/info-symbol-0.1.0.tgz#27841d72867ddb4242cd612d79c10633881c6a78" + integrity sha1-J4QdcoZ920JCzWEtecEGM4gcang= + inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" @@ -4264,6 +4956,22 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== +ioredis@^4.27.1: + version "4.27.1" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.1.tgz#4ef947b455a1b995baa4b0d7e2c4e4f75f746421" + integrity sha512-PaFNFeBbOcEYHXAdrJuy7uesJcyvzStTM1aYMchTuky+VgKqDbXhnTJHaDsjAwcTwPx8Asatx+l2DW8zZ2xlsQ== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4278,6 +4986,13 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arguments@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + dependencies: + call-bind "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -4373,6 +5088,13 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== +is-even@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" + integrity sha1-drUFX7rY0pSoa2qUkBXhyXtxfAY= + dependencies: + is-odd "^0.1.2" + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -4463,6 +5185,13 @@ is-number-object@^1.0.4: resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== +is-number@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -4470,6 +5199,11 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -4485,6 +5219,13 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== +is-odd@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" + integrity sha1-vFc7XONx7yqtbm9JeZtyvvE5eKc= + dependencies: + is-number "^3.0.0" + is-path-inside@^3.0.1, is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -4502,7 +5243,7 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.1.2: +is-regex@^1.0.4, is-regex@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== @@ -4515,6 +5256,13 @@ is-retry-allowed@^1.1.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== +is-self-closing@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" + integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== + dependencies: + self-closing-tags "^1.0.1" + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -4588,6 +5336,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isobject@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" + integrity sha1-o0MhkvObkQtfAsyYlIeDbscKqF4= + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -5198,6 +5951,22 @@ jsonschema@1.4.0: resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw== +jsonwebtoken@^8.2.0, jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -5237,7 +6006,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@3.x.x: +jws@3.x.x, jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -5264,7 +6033,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= @@ -5278,7 +6047,7 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0: +kind-of@^5.0.0, kind-of@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== @@ -5288,7 +6057,7 @@ kind-of@^6.0.0, kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -kleur@^3.0.3: +kleur@^3.0.0, kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== @@ -5338,6 +6107,13 @@ koa-is-json@^1.0.0: resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= +koa-passport@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa" + integrity sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg== + dependencies: + passport "^0.4.0" + koa-pino-logger@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/koa-pino-logger/-/koa-pino-logger-3.0.0.tgz#27600b4f3639e8767dfc6b66493109c5457f53ba" @@ -5419,6 +6195,13 @@ latest-version@^5.0.0, latest-version@^5.1.0: dependencies: package-json "^6.3.0" +lazy-cache@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" + integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ= + dependencies: + set-getter "^0.1.0" + lazy-val@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.4.tgz#882636a7245c2cfe6e0a4e3ba6c5d68a137e5c65" @@ -5590,6 +6373,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +linkify-it@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8" + integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ== + dependencies: + uc.micro "^1.0.1" + load-bmfont@^1.3.1, load-bmfont@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" @@ -5614,6 +6404,16 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" +loadicons@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/loadicons/-/loadicons-1.0.0.tgz#79fd9b08ef2933988c94068cbd246ef3f21cbd04" + integrity sha512-KSywiudfuOK5sTdhNMM8hwRpMxZ5TbQlU4ZijMxUFwRW7jpxUmb9YJoLIzDn7+xuxeLzCZWBmLJS2JDjDWCpsw== + +local-access@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/local-access/-/local-access-1.1.0.tgz#e007c76ba2ca83d5877ba1a125fc8dfe23ba4798" + integrity sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw== + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -5629,16 +6429,61 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + lodash.keys@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" @@ -5649,11 +6494,21 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.noop@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" + integrity sha1-OBiPTWUKOkdCWEObluxFsyYXEzw= + lodash.omit@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + lodash.pick@^4.0.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -5664,6 +6519,21 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash.template@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -5679,11 +6549,40 @@ lodash@4.17.13: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" integrity sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA== -lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.3: +lodash@^4.14.0, lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.3: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-ok@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/log-ok/-/log-ok-0.1.1.tgz#bea3dd36acd0b8a7240d78736b5b97c65444a334" + integrity sha1-vqPdNqzQuKckDXhza1uXxlREozQ= + dependencies: + ansi-green "^0.1.1" + success-symbol "^0.1.0" + +log-utils@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/log-utils/-/log-utils-0.2.1.tgz#a4c217a0dd9a50515d9b920206091ab3d4e031cf" + integrity sha1-pMIXoN2aUFFdm5ICBgkas9TgMc8= + dependencies: + ansi-colors "^0.2.0" + error-symbol "^0.1.0" + info-symbol "^0.1.0" + log-ok "^0.1.1" + success-symbol "^0.1.0" + time-stamp "^1.0.1" + warning-symbol "^0.1.0" + +logging-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/logging-helpers/-/logging-helpers-1.0.0.tgz#b5a37b32ad53eb0137c58c7898a47b175ddb7c36" + integrity sha512-qyIh2goLt1sOgQQrrIWuwkRjUx4NUcEqEGAcYqD8VOnOC6ItwkrVE8/tA4smGpjzyp4Svhc6RodDp9IO5ghpyA== + dependencies: + isobject "^3.0.0" + log-utils "^0.2.1" + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -5779,6 +6678,17 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-it@^12.0.2: + version "12.0.6" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.0.6.tgz#adcc8e5fe020af292ccbdf161fe84f1961516138" + integrity sha512-qv3sVLl4lMT96LLtR7xeRJX11OUFjsaD5oVat2/SNBIb21bJXwal2+SklcRbTwGwqWpWH/HRtYavOoJE+seL8w== + dependencies: + argparse "^2.0.1" + entities "~2.1.0" + linkify-it "^3.0.1" + mdurl "^1.0.1" + uc.micro "^1.0.5" + matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -5786,6 +6696,11 @@ matcher@^3.0.0: dependencies: escape-string-regexp "^4.0.0" +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -5871,7 +6786,7 @@ mime@^1.3.4, mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.5.0: +mime@^2.3.1, mime@^2.5.0: version "2.5.2" resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== @@ -5925,6 +6840,11 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4: dependencies: minimist "^1.2.5" +moment@^2.18.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + mongodb@3.6.3: version "3.6.3" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.3.tgz#eddaed0cc3598474d7a15f0f2a5b04848489fd05" @@ -5943,6 +6863,11 @@ mri@1.1.4: resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== +mri@^1.1.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.6.tgz#49952e1044db21dbf90f6cd92bc9c9a777d415a6" + integrity sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -6009,6 +6934,11 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== +nanoid@^2.1.0: + version "2.1.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" + integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -6056,6 +6986,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + new-github-issue-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz#e17be1f665a92de465926603e44b9f8685630c1d" @@ -6086,6 +7021,11 @@ node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-forge@^0.7.1: + version "0.7.6" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" + integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== + node-gyp-build@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" @@ -6211,6 +7151,11 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +oauth@0.9.x: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= + object-assign@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" @@ -6235,6 +7180,14 @@ object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -6408,6 +7361,11 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + p-reduce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" @@ -6445,6 +7403,11 @@ pako@^1.0.5: resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== +parchment@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5" + integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -6508,6 +7471,84 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +passport-google-auth@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" + integrity sha1-izALWqRC70M94dgy7TESh30LKTg= + dependencies: + googleapis "^16.0.0" + passport-strategy "1.x" + +passport-google-oauth1@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc" + integrity sha1-r3SoA99R7GRvZqRNgigr5vEI4Mw= + dependencies: + passport-oauth1 "1.x.x" + +passport-google-oauth20@2.x.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz#0d241b2d21ebd3dc7f2b60669ec4d587e3a674ef" + integrity sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ== + dependencies: + passport-oauth2 "1.x.x" + +passport-google-oauth@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz#f6eb4bc96dd6c16ec0ecfdf4e05ec48ca54d4dae" + integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA== + dependencies: + passport-google-oauth1 "1.x.x" + passport-google-oauth20 "2.x.x" + +passport-jwt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +passport-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + integrity sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4= + dependencies: + passport-strategy "1.x.x" + +passport-oauth1@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.1.0.tgz#a7de988a211f9cf4687377130ea74df32730c918" + integrity sha1-p96YiiEfnPRoc3cTDqdN8ycwyRg= + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + utils-merge "1.x.x" + +passport-oauth2@1.x.x: + version "1.5.0" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108" + integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ== + dependencies: + base64url "3.x.x" + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-strategy@1.x, passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= + +passport@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -6552,6 +7593,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -7129,6 +8175,27 @@ quick-format-unescaped@4.0.1: resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz#437a5ea1a0b61deb7605f8ab6a8fd3858dbeb701" integrity sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A== +quill-delta@^3.6.2: + version "3.6.3" + resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032" + integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg== + dependencies: + deep-equal "^1.0.1" + extend "^3.0.2" + fast-diff "1.1.2" + +quill@^1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/quill/-/quill-1.3.7.tgz#da5b2f3a2c470e932340cdbf3668c9f21f9286e8" + integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g== + dependencies: + clone "^2.1.1" + deep-equal "^1.0.1" + eventemitter3 "^2.0.3" + extend "^3.0.2" + parchment "^1.1.4" + quill-delta "^3.6.2" + raw-body@^2.2.0: version "2.4.1" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" @@ -7292,6 +8359,23 @@ recast@^0.11.17: private "~0.1.5" source-map "~0.5.0" +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: version "0.13.7" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" @@ -7305,6 +8389,19 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexp.prototype.flags@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexparam@1.3.0, regexparam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" + integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== + regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -7324,6 +8421,26 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" +relative@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" + integrity sha1-Dc2OxUpdNaPBXhBFA9ZTdbWlNn8= + dependencies: + isobject "^2.0.0" + +remarkable@^1.6.2, remarkable@^1.7.1: + version "1.7.4" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" + integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== + dependencies: + argparse "^1.0.10" + autolinker "~0.28.0" + +remixicon@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/remixicon/-/remixicon-2.5.0.tgz#b5e245894a1550aa23793f95daceadbf96ad1a41" + integrity sha512-q54ra2QutYDZpuSnFjmeagmEiN9IMo56/zz5dDNitzKD23oFRw77cWo4TsrAdmdkPiEn8mxlrTqxnkujDbEGww== + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -7355,7 +8472,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -"request@>= 2.52.0", request@^2.87.0: +"request@>= 2.52.0", request@^2.72.0, request@^2.74.0, request@^2.87.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -7510,6 +8627,13 @@ rxjs@^6.6.0: dependencies: tslib "^1.9.0" +sade@^1.4.0: + version "1.7.4" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.7.4.tgz#ea681e0c65d248d2095c90578c03ca0bb1b54691" + integrity sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA== + dependencies: + mri "^1.1.0" + safe-buffer@*, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -7588,6 +8712,11 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" +self-closing-tags@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" + integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== + semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -7634,6 +8763,13 @@ set-blocking@^2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-getter@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" + integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y= + dependencies: + to-object-path "^0.3.0" + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -7704,6 +8840,13 @@ shellwords@^0.1.1: resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== +shortid@^2.2.15: + version "2.2.16" + resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" + integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g== + dependencies: + nanoid "^2.1.0" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -7718,6 +8861,27 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +sirv-cli@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/sirv-cli/-/sirv-cli-0.4.6.tgz#c28ab20deb3b34637f5a60863dc350f055abca04" + integrity sha512-/Vj85/kBvPL+n9ibgX6FicLE8VjidC1BhlX67PYPBfbBAphzR6i0k0HtU5c2arejfU3uzq8l3SYPCwl1x7z6Ww== + dependencies: + console-clear "^1.1.0" + get-port "^3.2.0" + kleur "^3.0.0" + local-access "^1.0.1" + sade "^1.4.0" + sirv "^0.4.6" + tinydate "^1.0.0" + +sirv@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-0.4.6.tgz#185e44eb93d24009dd183b7494285c5180b81f22" + integrity sha512-rYpOXlNbpHiY4nVXxuDf4mXPvKz1reZGap/LkWp9TvcZ84qD/nPBjjH/6GZsgIjVMbOslnY8YYULAyP8jMn1GQ== + dependencies: + "@polka/url" "^0.5.0" + mime "^2.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -7957,6 +9121,11 @@ stack-utils@^1.0.1: dependencies: escape-string-regexp "^2.0.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + stat-mode@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465" @@ -7998,6 +9167,11 @@ string-length@^2.0.0: astral-regex "^1.0.0" strip-ansi "^4.0.0" +string-template@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" + integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y= + string-width@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -8128,6 +9302,11 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" +striptags@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.1.1.tgz#c8c3e7fdd6fb4bb3a32a3b752e5b5e3e38093ebd" + integrity sha1-yMPn/db7S7OjKjt1LltePjgJPr0= + sublevel-pouchdb@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/sublevel-pouchdb/-/sublevel-pouchdb-7.2.2.tgz#49e46cd37883bf7ff5006d7c5b9bcc7bcc1f422f" @@ -8138,6 +9317,11 @@ sublevel-pouchdb@7.2.2: ltgt "2.2.1" readable-stream "1.1.14" +success-symbol@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/success-symbol/-/success-symbol-0.1.0.tgz#24022e486f3bf1cdca094283b769c472d3b72897" + integrity sha1-JAIuSG878c3KCUKDt2nEctO3KJc= + sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" @@ -8190,11 +9374,99 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +svelte-apexcharts@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/svelte-apexcharts/-/svelte-apexcharts-1.0.2.tgz#4e000f8b8f7c901c05658c845457dfc8314d54c1" + integrity sha512-6qlx4rE+XsonZ0FZudfwqOQ34Pq+3wpxgAD75zgEmGoYhYBJcwmikTuTf3o8ZBsZue9U/pAwhNy3ed1Bkq1gmA== + dependencies: + apexcharts "^3.19.2" + +svelte-flatpickr@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-2.4.0.tgz#190871fc3305956c8c8fd3601cd036b8ac71ef49" + integrity sha512-UUC5Te+b0qi4POg7VDwfGh0m5W3Hf64OwkfOTj6FEe/dYZN4cBzpQ82EuuQl0CTbbBAsMkcjJcixV1d2V6EHCQ== + dependencies: + flatpickr "^4.5.2" + +svelte-flatpickr@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-3.1.0.tgz#ad83588430dbd55196a1a258b8ba27e7f9c1ee37" + integrity sha512-zKyV+ukeVuJ8CW0Ing3T19VSekc4bPkou/5Riutt1yATrLvSsanNqcgqi7Q5IePvIoOF9GJ5OtHvn1qK9Wx9BQ== + dependencies: + flatpickr "^4.5.2" + +svelte-portal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" + integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== + +svelte-spa-router@^3.0.5: + version "3.1.0" + resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.1.0.tgz#a929f0def7e12c41f32bc356f91685aeadcd75bf" + integrity sha512-jlM/xwjn57mylr+pzHYCOOy+IPQauT46gOucNGTBu6jHcFXu3F+oaojN4PXC1LYizRGxFB6QA0qnYbZnRfX7Sg== + dependencies: + regexparam "1.3.0" + svelte@3.30.0: version "3.30.0" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.30.0.tgz#cbde341e96bf34f4ac73c8f14f8a014e03bfb7d6" integrity sha512-z+hdIACb9TROGvJBQWcItMtlr4s0DBUgJss6qWrtFkOoIInkG+iAMo/FJZQFyDBQZc+dul2+TzYSi/tpTT5/Ag== +svg.draggable.js@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba" + integrity sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw== + dependencies: + svg.js "^2.0.1" + +svg.easing.js@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/svg.easing.js/-/svg.easing.js-2.0.0.tgz#8aa9946b0a8e27857a5c40a10eba4091e5691f12" + integrity sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI= + dependencies: + svg.js ">=2.3.x" + +svg.filter.js@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/svg.filter.js/-/svg.filter.js-2.0.2.tgz#91008e151389dd9230779fcbe6e2c9a362d1c203" + integrity sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM= + dependencies: + svg.js "^2.2.5" + +svg.js@>=2.3.x, svg.js@^2.0.1, svg.js@^2.2.5, svg.js@^2.4.0, svg.js@^2.6.5: + version "2.7.1" + resolved "https://registry.yarnpkg.com/svg.js/-/svg.js-2.7.1.tgz#eb977ed4737001eab859949b4a398ee1bb79948d" + integrity sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA== + +svg.pathmorphing.js@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz#c25718a1cc7c36e852ecabc380e758ac09bb2b65" + integrity sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww== + dependencies: + svg.js "^2.4.0" + +svg.resize.js@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/svg.resize.js/-/svg.resize.js-1.4.3.tgz#885abd248e0cd205b36b973c4b578b9a36f23332" + integrity sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw== + dependencies: + svg.js "^2.6.5" + svg.select.js "^2.1.2" + +svg.select.js@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-2.1.2.tgz#e41ce13b1acff43a7441f9f8be87a2319c87be73" + integrity sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ== + dependencies: + svg.js "^2.2.5" + +svg.select.js@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-3.0.1.tgz#a4198e359f3825739226415f82176a90ea5cc917" + integrity sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw== + dependencies: + svg.js "^2.6.5" + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -8354,6 +9626,11 @@ through@^2.3.6, through@^2.3.8, through@~2.3.4: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +time-stamp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + timed-out@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -8374,6 +9651,11 @@ tinycolor2@^1.4.1: resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== +tinydate@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/tinydate/-/tinydate-1.3.0.tgz#e6ca8e5a22b51bb4ea1c3a2a4fd1352dbd4c57fb" + integrity sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -8396,6 +9678,11 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +to-gfm-code-block@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" + integrity sha1-JdBFpfrlUxielje1kJANpzLYqoI= + to-json-schema@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" @@ -8517,6 +9804,13 @@ tunnel@0.0.6, tunnel@^0.0.6: resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== +turndown@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.0.0.tgz#19b2a6a2d1d700387a1e07665414e4af4fec5225" + integrity sha512-G1FfxfR0mUNMeGjszLYl3kxtopC4O9DRRiMlMDDVHvU1jaBkGFg4qxIyjIk2aiKLHyDyZvZyu4qBO2guuYBy3Q== + dependencies: + domino "^2.1.6" + tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -8574,6 +9868,28 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typeof-article@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" + integrity sha1-nwfnM8P7tkb/qeYcCN66zUYOBq8= + dependencies: + kind-of "^3.1.0" + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^3.1.4: + version "3.13.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.4.tgz#592588bb9f47ae03b24916e2471218d914955574" + integrity sha512-kv7fCkIXyQIilD5/yQy8O+uagsYIOt5cZvs890W40/e/rvjMSzJw81o9Bg0tkURxzZBROtDQhW2LFjOGoK3RZw== + +uid2@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" + integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= + unbox-primitive@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" @@ -8762,6 +10078,11 @@ util.promisify@^1.0.0: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.1" +utils-merge@1.x.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + uuid@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -8782,6 +10103,11 @@ uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -8845,6 +10171,11 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" +warning-symbol@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/warning-symbol/-/warning-symbol-0.1.0.tgz#bb31dd11b7a0f9d67ab2ed95f457b65825bbad21" + integrity sha1-uzHdEbeg+dZ6su2V9Fe2WCW7rSE= + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -8922,6 +10253,11 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + worker-farm@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" @@ -9155,6 +10491,11 @@ yauzl@^2.10.0, yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" +year@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" + integrity sha1-QIOuUgoxiyPshgN/MADLiSvfm7A= + ylru@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" diff --git a/packages/worker/package.json b/packages/worker/package.json index f30455ca57..e8db71fc46 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -19,7 +19,7 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "0.0.1", + "@budibase/auth": "^0.18.6", "@budibase/string-templates": "^0.8.16", "@koa/router": "^8.0.0", "aws-sdk": "^2.811.0", diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 9510f6cd5c..150a8685f1 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -287,6 +287,21 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@budibase/auth@0.0.1": + version "0.18.6" + resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.18.6.tgz#d893005962afd9425f10e2ac8d1d495047d0d44e" + integrity sha512-pdyqR8G240lToMe2OZNpw2YzuRwOlOT+cAfVHPMBxJJKF0VvZ0K500NoSUINEQPr4IfWpPSu6CQhq+ROf4pMXA== + dependencies: + bcryptjs "^2.4.3" + ioredis "^4.27.1" + jsonwebtoken "^8.5.1" + koa-passport "^4.1.4" + passport-google-auth "^1.0.2" + passport-google-oauth "^2.0.0" + passport-jwt "^4.0.0" + passport-local "^1.0.0" + uuid "^8.3.2" + "@budibase/handlebars-helpers@^0.11.3": version "0.11.3" resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.3.tgz#b6e5c91b83e8906e7d7ff10ddde277a3d561016e" @@ -1209,6 +1224,13 @@ ast-types@0.9.6: resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk= +async@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" + integrity sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw= + dependencies: + lodash "^4.14.0" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1662,6 +1684,11 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + co-body@^5.1.1: version "5.2.0" resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124" @@ -1920,7 +1947,7 @@ debug@^3.1.0, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.1.0, debug@^4.1.1: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -2045,6 +2072,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +denque@^1.1.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de" + integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ== + depd@^1.1.2, depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2692,6 +2724,32 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +google-auth-library@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" + integrity sha1-bhW6vuhf0d0U2NEoopW2g41SE24= + dependencies: + gtoken "^1.2.1" + jws "^3.1.4" + lodash.noop "^3.0.1" + request "^2.74.0" + +google-p12-pem@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" + integrity sha1-M8RqsCGqc0+gMys5YKmj/8svMXc= + dependencies: + node-forge "^0.7.1" + +googleapis@^16.0.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576" + integrity sha1-Dxny1wVy2RiIGg9ibjsaL6hilXY= + dependencies: + async "~2.1.4" + google-auth-library "~0.10.0" + string-template "~1.0.0" + got@^11.8.1: version "11.8.1" resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d" @@ -2741,6 +2799,16 @@ growly@^1.3.0: resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +gtoken@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" + integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== + dependencies: + google-p12-pem "^0.1.0" + jws "^3.0.0" + mime "^1.4.1" + request "^2.72.0" + gulp-header@^1.7.1: version "1.8.12" resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" @@ -3062,6 +3130,22 @@ inline-process-browser@^1.0.0: falafel "^1.0.1" through2 "^0.6.5" +ioredis@^4.27.1: + version "4.27.1" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.1.tgz#4ef947b455a1b995baa4b0d7e2c4e4f75f746421" + integrity sha512-PaFNFeBbOcEYHXAdrJuy7uesJcyvzStTM1aYMchTuky+VgKqDbXhnTJHaDsjAwcTwPx8Asatx+l2DW8zZ2xlsQ== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -3878,7 +3962,7 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" -jsonwebtoken@^8.2.0: +jsonwebtoken@^8.2.0, jsonwebtoken@^8.5.1: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== @@ -3933,7 +4017,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@^3.2.2: +jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -4254,6 +4338,16 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + lodash.includes@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" @@ -4284,6 +4378,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= +lodash.noop@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" + integrity sha1-OBiPTWUKOkdCWEObluxFsyYXEzw= + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -4304,7 +4403,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash@^4.17.19, lodash@^4.17.20, lodash@^4.7.0: +lodash@^4.14.0, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4469,6 +4568,11 @@ mime-types@^2.1.18, mime-types@~2.1.24: dependencies: mime-db "1.44.0" +mime@^1.4.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mime@^2.4.6: version "2.5.2" resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" @@ -4593,6 +4697,11 @@ node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-forge@^0.7.1: + version "0.7.6" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" + integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== + node-gyp-build@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" @@ -4819,6 +4928,11 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-map@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -4859,6 +4973,14 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +passport-google-auth@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" + integrity sha1-izALWqRC70M94dgy7TESh30LKTg= + dependencies: + googleapis "^16.0.0" + passport-strategy "1.x" + passport-google-oauth1@1.x.x: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc" @@ -4916,7 +5038,7 @@ passport-oauth2@1.x.x: uid2 "0.0.x" utils-merge "1.x.x" -passport-strategy@1.x.x, passport-strategy@^1.0.0: +passport-strategy@1.x, passport-strategy@1.x.x, passport-strategy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= @@ -5419,6 +5541,23 @@ recast@^0.11.17: private "~0.1.5" source-map "~0.5.0" +redis-commands@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -5487,7 +5626,7 @@ request-promise-native@^1.0.9: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.88.2: +request@^2.72.0, request@^2.74.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -5933,6 +6072,11 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -5964,6 +6108,11 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +string-template@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" + integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y= + string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -6474,7 +6623,7 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0: +uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== From 58ca0d4224a49a7b4faac631f2f11d520f8ddbd1 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 28 Apr 2021 18:13:21 +0100 Subject: [PATCH 06/19] Updating auth middleware to accomodate public endpoints for the server properly and some refactoring. --- packages/auth/src/middleware/authenticated.js | 36 +++++++++++++++---- packages/server/src/api/index.js | 13 +++---- .../src/api/controllers/{ => admin}/auth.js | 6 ++-- packages/worker/src/api/index.js | 20 ++++++++--- .../worker/src/api/routes/{ => admin}/auth.js | 4 +-- packages/worker/src/api/routes/index.js | 2 +- 6 files changed, 57 insertions(+), 24 deletions(-) rename packages/worker/src/api/controllers/{ => admin}/auth.js (94%) rename packages/worker/src/api/routes/{ => admin}/auth.js (86%) diff --git a/packages/auth/src/middleware/authenticated.js b/packages/auth/src/middleware/authenticated.js index 007ebe229d..5d8d4e7e13 100644 --- a/packages/auth/src/middleware/authenticated.js +++ b/packages/auth/src/middleware/authenticated.js @@ -3,15 +3,35 @@ const database = require("../db") const { getCookie, clearCookie } = require("../utils") const { StaticDatabases } = require("../db/utils") -function makeRegex() { +const PARAM_REGEX = /\/:(.*?)\//g +function buildNoAuthRegex(patterns) { + return patterns.map(pattern => { + const isObj = typeof pattern === "object" && pattern.route + const method = isObj ? pattern.method : "GET" + let route = isObj ? pattern.route : pattern + + const matches = route.match(PARAM_REGEX) + if (matches) { + for (let match of matches) { + route = route.replace(match, "/.*/") + } + } + return { regex: new RegExp(route), method } + }) } -module.exports = (noAuthPatterns = []) => { - const regex = new RegExp(noAuthPatterns.join("|")) +module.exports = (noAuthPatterns = [], opts) => { + const noAuthOptions = noAuthPatterns ? buildNoAuthRegex(noAuthPatterns) : [] return async (ctx, next) => { // the path is not authenticated - if (regex.test(ctx.request.url)) { + const found = noAuthOptions.find(({ regex, method }) => { + return ( + regex.test(ctx.request.url) && + ctx.request.method.toLowerCase() === method.toLowerCase() + ) + }) + if (found != null) { return next() } try { @@ -34,10 +54,14 @@ module.exports = (noAuthPatterns = []) => { if (ctx.isAuthenticated !== true) { ctx.isAuthenticated = false } - return next() } catch (err) { - ctx.throw(err.status || 403, err) + // allow configuring for public access + if (opts && opts.publicAllowed) { + ctx.isAuthenticated = false + } else { + ctx.throw(err.status || 403, err) + } } } } diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 369578d05e..8dfd2f5c6a 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -9,13 +9,6 @@ const pkg = require("../../package.json") const router = new Router() const env = require("../environment") -const NO_AUTH_ENDPOINTS = [ - "/health", - "/version", - "webhooks/trigger", - "webhooks/schema", -] - router .use( compress({ @@ -38,7 +31,11 @@ router }) .use("/health", ctx => (ctx.status = 200)) .use("/version", ctx => (ctx.body = pkg.version)) - .use(buildAuthMiddleware(NO_AUTH_ENDPOINTS)) + .use( + buildAuthMiddleware(null, { + publicAllowed: true, + }) + ) .use(currentApp) // error handling middleware diff --git a/packages/worker/src/api/controllers/auth.js b/packages/worker/src/api/controllers/admin/auth.js similarity index 94% rename from packages/worker/src/api/controllers/auth.js rename to packages/worker/src/api/controllers/admin/auth.js index 18ee2d64e8..94fb8e0ece 100644 --- a/packages/worker/src/api/controllers/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -1,8 +1,8 @@ const authPkg = require("@budibase/auth") const { google } = require("@budibase/auth/src/middleware") -const { Configs } = require("../../constants") -const CouchDB = require("../../db") -const { sendEmail } = require("../../utilities/email") +const { Configs } = require("../../../constants") +const CouchDB = require("../../../db") +const { sendEmail } = require("../../../utilities/email") const { clearCookie, getGlobalUserByEmail } = authPkg.utils const { Cookies } = authPkg.constants const { passport } = authPkg.auth diff --git a/packages/worker/src/api/index.js b/packages/worker/src/api/index.js index d0e60ffcd2..c4877beabf 100644 --- a/packages/worker/src/api/index.js +++ b/packages/worker/src/api/index.js @@ -5,10 +5,22 @@ const { routes } = require("./routes") const { buildAuthMiddleware } = require("@budibase/auth").auth const NO_AUTH_ENDPOINTS = [ - "/api/admin/users/first", - "/api/admin/auth", - "/api/admin/auth/google", - "/api/admin/auth/google/callback", + { + route: "/api/admin/users/first", + method: "POST", + }, + { + route: "/api/admin/auth", + method: "POST", + }, + { + route: "/api/admin/auth/google", + method: "GET", + }, + { + route: "/api/admin/auth/google/callback", + method: "GET", + }, ] const router = new Router() diff --git a/packages/worker/src/api/routes/auth.js b/packages/worker/src/api/routes/admin/auth.js similarity index 86% rename from packages/worker/src/api/routes/auth.js rename to packages/worker/src/api/routes/admin/auth.js index e914f334d7..60d2f4ae7d 100644 --- a/packages/worker/src/api/routes/auth.js +++ b/packages/worker/src/api/routes/admin/auth.js @@ -1,6 +1,6 @@ const Router = require("@koa/router") -const authController = require("../controllers/auth") -const joiValidator = require("../../middleware/joi-validator") +const authController = require("../../controllers/admin/auth") +const joiValidator = require("../../../middleware/joi-validator") const Joi = require("joi") const router = Router() diff --git a/packages/worker/src/api/routes/index.js b/packages/worker/src/api/routes/index.js index 412d8c255a..90fafffa2a 100644 --- a/packages/worker/src/api/routes/index.js +++ b/packages/worker/src/api/routes/index.js @@ -3,7 +3,7 @@ const configRoutes = require("./admin/configs") const groupRoutes = require("./admin/groups") const templateRoutes = require("./admin/templates") const emailRoutes = require("./admin/email") -const authRoutes = require("./auth") +const authRoutes = require("./admin/auth") const appRoutes = require("./app") exports.routes = [ From 1cf778845aafc7856ae7383abf2d76cbd793dea3 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 4 May 2021 18:13:44 +0100 Subject: [PATCH 07/19] Fixing issues with Redis/Bull and the integration with new redis module. --- hosting/docker-compose.yaml | 2 -- hosting/envoy.dev.yaml.hbs | 19 ----------------- hosting/envoy.yaml | 20 ------------------ packages/auth/src/index.js | 4 ++++ packages/auth/src/redis/index.js | 20 +++--------------- packages/auth/src/redis/utils.js | 23 +++++++++++++++++++++ packages/server/scripts/dev/manage.js | 3 ++- packages/server/src/automations/triggers.js | 4 +++- packages/worker/scripts/dev/manage.js | 2 ++ 9 files changed, 37 insertions(+), 60 deletions(-) diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml index e062f0590e..6d9f64c07e 100644 --- a/hosting/docker-compose.yaml +++ b/hosting/docker-compose.yaml @@ -105,8 +105,6 @@ services: restart: always image: redis command: redis-server --requirepass ${REDIS_PASSWORD} - ports: - - "${REDIS_PORT}:6379" volumes: - redis_data:/data diff --git a/hosting/envoy.dev.yaml.hbs b/hosting/envoy.dev.yaml.hbs index a4e2a97118..98b554165c 100644 --- a/hosting/envoy.dev.yaml.hbs +++ b/hosting/envoy.dev.yaml.hbs @@ -21,11 +21,6 @@ static_resources: cluster: couchdb-service prefix_rewrite: "/" - - match: { prefix: "/cache/" } - route: - cluster: redis-service - prefix_rewrite: "/" - - match: { prefix: "/api/admin/" } route: cluster: worker-dev @@ -89,20 +84,6 @@ static_resources: address: couchdb-service port_value: 5984 - - name: redis-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: redis-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: redis-service - port_value: 6379 - - name: server-dev connect_timeout: 0.25s type: strict_dns diff --git a/hosting/envoy.yaml b/hosting/envoy.yaml index 1fbd2070ff..d2202ff870 100644 --- a/hosting/envoy.yaml +++ b/hosting/envoy.yaml @@ -41,11 +41,6 @@ static_resources: cluster: worker-service prefix_rewrite: "/" - - match: { prefix: "/cache/" } - route: - cluster: redis-service - prefix_rewrite: "/" - - match: { prefix: "/db/" } route: cluster: couchdb-service @@ -117,18 +112,3 @@ static_resources: address: couchdb-service port_value: 5984 - - name: redis-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: redis-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: redis-service - port_value: 6379 - - diff --git a/packages/auth/src/index.js b/packages/auth/src/index.js index 348f911f80..5b3de3e336 100644 --- a/packages/auth/src/index.js +++ b/packages/auth/src/index.js @@ -28,6 +28,10 @@ module.exports = { setDB(pouch) }, db: require("./db/utils"), + redis: { + client: require("./redis"), + utils: require("./redis/utils"), + }, utils: { ...require("./utils"), ...require("./hashing"), diff --git a/packages/auth/src/redis/index.js b/packages/auth/src/redis/index.js index b81c3aee74..cdd51fc2a4 100644 --- a/packages/auth/src/redis/index.js +++ b/packages/auth/src/redis/index.js @@ -1,9 +1,6 @@ const Redis = require("ioredis") -const env = require("../environment") -const { addDbPrefix, removeDbPrefix } = require("./utils") +const { addDbPrefix, removeDbPrefix, getRedisOptions } = require("./utils") -const CONNECT_TIMEOUT_MS = 10000 -const SLOT_REFRESH_MS = 2000 const CLUSTERED = false let CLIENT @@ -15,21 +12,10 @@ let CLIENT */ function init() { return new Promise((resolve, reject) => { - const [host, port] = env.REDIS_URL.split(":") - const opts = { - connectTimeout: CONNECT_TIMEOUT_MS, - } + const { opts, host, port } = getRedisOptions(CLUSTERED) if (CLUSTERED) { - opts.redisOptions = {} - opts.redisOptions.tls = {} - opts.redisOptions.password = env.REDIS_PASSWORD - opts.slotsRefreshTimeout = SLOT_REFRESH_MS - opts.dnsLookup = (address, callback) => callback(null, address) - CLIENT = new Redis.Cluster([{ port, host }]) + CLIENT = new Redis.Cluster([{ host, port }], opts) } else { - opts.password = env.REDIS_PASSWORD - opts.port = port - opts.host = host CLIENT = new Redis(opts) } CLIENT.on("end", err => { diff --git a/packages/auth/src/redis/utils.js b/packages/auth/src/redis/utils.js index 90f82d041a..54b0c882cd 100644 --- a/packages/auth/src/redis/utils.js +++ b/packages/auth/src/redis/utils.js @@ -1,9 +1,32 @@ +const env = require("../environment") + +const SLOT_REFRESH_MS = 2000 +const CONNECT_TIMEOUT_MS = 10000 const SEPARATOR = "-" exports.Databases = { PW_RESETS: "pwReset", } +exports.getRedisOptions = (clustered = false) => { + const [host, port] = env.REDIS_URL.split(":") + const opts = { + connectTimeout: CONNECT_TIMEOUT_MS, + } + if (clustered) { + opts.redisOptions = {} + opts.redisOptions.tls = {} + opts.redisOptions.password = env.REDIS_PASSWORD + opts.slotsRefreshTimeout = SLOT_REFRESH_MS + opts.dnsLookup = (address, callback) => callback(null, address) + } else { + opts.host = host + opts.port = port + opts.password = env.REDIS_PASSWORD + } + return { opts, host, port } +} + exports.addDbPrefix = (db, key) => { return `${db}${SEPARATOR}${key}` } diff --git a/packages/server/scripts/dev/manage.js b/packages/server/scripts/dev/manage.js index 305df573e4..24cac981cf 100644 --- a/packages/server/scripts/dev/manage.js +++ b/packages/server/scripts/dev/manage.js @@ -37,9 +37,10 @@ async function init() { PORT: 4001, MINIO_URL: "http://localhost:10000/", COUCH_DB_URL: "http://budibase:budibase@localhost:10000/db/", - REDIS_URL: "http://localhost:10000/cache/", + REDIS_URL: "localhost:6379", WORKER_URL: "http://localhost:4002", JWT_SECRET: "testsecret", + REDIS_PASSWORD: "budibase", MINIO_ACCESS_KEY: "budibase", MINIO_SECRET_KEY: "budibase", COUCH_DB_PASSWORD: "budibase", diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index e11784eb95..77eb32377a 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -4,8 +4,10 @@ const Queue = require("bull") const { setQueues, BullAdapter } = require("bull-board") const { getAutomationParams } = require("../db/utils") const { coerce } = require("../utilities/rowProcessor") +const { utils } = require("@budibase/auth").redis -let automationQueue = new Queue("automationQueue") +const { opts } = utils.getRedisOptions() +let automationQueue = new Queue("automationQueue", { redis: opts }) // Set up queues for bull board admin setQueues([new BullAdapter(automationQueue)]) diff --git a/packages/worker/scripts/dev/manage.js b/packages/worker/scripts/dev/manage.js index f363bd05ac..7322349b72 100644 --- a/packages/worker/scripts/dev/manage.js +++ b/packages/worker/scripts/dev/manage.js @@ -12,6 +12,8 @@ async function init() { MINIO_SECRET_KEY: "budibase", COUCH_DB_USER: "budibase", COUCH_DB_PASSWORD: "budibase", + REDIS_URL: "localhost:6379", + REDIS_PASSWORD: "budibase", MINIO_URL: "http://localhost:10000/", COUCH_DB_URL: "http://budibase:budibase@localhost:10000/db/", } From b372d2a824801fdb0dfef79f8ae353825816a4b7 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 12:11:06 +0100 Subject: [PATCH 08/19] Fleshed out fully all redis interactions for invitations and password resets. --- packages/auth/src/index.js | 2 +- packages/auth/src/redis/index.js | 9 +++ packages/auth/src/redis/utils.js | 1 + .../worker/src/api/controllers/admin/auth.js | 15 ++-- packages/worker/src/constants/index.js | 2 + packages/worker/src/utilities/email.js | 70 ++++++++++++++++--- packages/worker/src/utilities/redis.js | 51 ++++++++++++++ packages/worker/src/utilities/templates.js | 27 ++++--- 8 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 packages/worker/src/utilities/redis.js diff --git a/packages/auth/src/index.js b/packages/auth/src/index.js index 5b3de3e336..e330684197 100644 --- a/packages/auth/src/index.js +++ b/packages/auth/src/index.js @@ -29,7 +29,7 @@ module.exports = { }, db: require("./db/utils"), redis: { - client: require("./redis"), + Client: require("./redis"), utils: require("./redis/utils"), }, utils: { diff --git a/packages/auth/src/redis/index.js b/packages/auth/src/redis/index.js index cdd51fc2a4..0cb92c4622 100644 --- a/packages/auth/src/redis/index.js +++ b/packages/auth/src/redis/index.js @@ -12,6 +12,11 @@ let CLIENT */ function init() { return new Promise((resolve, reject) => { + // if a connection existed, close it and re-create it + if (CLIENT) { + CLIENT.disconnect() + CLIENT = null + } const { opts, host, port } = getRedisOptions(CLUSTERED) if (CLUSTERED) { CLIENT = new Redis.Cluster([{ host, port }], opts) @@ -78,6 +83,10 @@ class RedisWrapper { return this } + async finish() { + this._client.disconnect() + } + async scan() { const db = this._db, client = this._client diff --git a/packages/auth/src/redis/utils.js b/packages/auth/src/redis/utils.js index 54b0c882cd..a29f786c41 100644 --- a/packages/auth/src/redis/utils.js +++ b/packages/auth/src/redis/utils.js @@ -6,6 +6,7 @@ const SEPARATOR = "-" exports.Databases = { PW_RESETS: "pwReset", + INVITATIONS: "invitation", } exports.getRedisOptions = (clustered = false) => { diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index 94fb8e0ece..1d6981d0ed 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -2,7 +2,7 @@ const authPkg = require("@budibase/auth") const { google } = require("@budibase/auth/src/middleware") const { Configs } = require("../../../constants") const CouchDB = require("../../../db") -const { sendEmail } = require("../../../utilities/email") +const { sendEmail, isEmailConfigured } = require("../../../utilities/email") const { clearCookie, getGlobalUserByEmail } = authPkg.utils const { Cookies } = authPkg.constants const { passport } = authPkg.auth @@ -44,14 +44,19 @@ exports.authenticate = async (ctx, next) => { */ exports.reset = async ctx => { const { email } = ctx.request.body + const configured = await isEmailConfigured() + if (!configured) { + throw "Please contact your platform administrator, SMTP is not configured." + } try { - const user = getGlobalUserByEmail(email) - if (user) { - } + const user = await getGlobalUserByEmail(email) + sendEmail() } catch (err) { // don't throw any kind of error to the user, this might give away something } - ctx.body = {} + ctx.body = { + message: "If user exists an email has been sent." + } } exports.logout = async ctx => { diff --git a/packages/worker/src/constants/index.js b/packages/worker/src/constants/index.js index f5702d3e96..618e8e036d 100644 --- a/packages/worker/src/constants/index.js +++ b/packages/worker/src/constants/index.js @@ -45,6 +45,8 @@ const TemplateBindings = { LOGIN_URL: "loginUrl", CURRENT_YEAR: "currentYear", CURRENT_DATE: "currentDate", + RESET_CODE: "resetCode", + INVITE_CODE: "inviteCode", } const TemplateMetadata = { diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index 23af1ab623..524d305899 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -5,6 +5,7 @@ const { EmailTemplatePurpose, TemplateTypes, Configs } = require("../constants") const { getTemplateByPurpose } = require("../constants/templates") const { getSettingsTemplateContext } = require("./templates") const { processString } = require("@budibase/string-templates") +const { getResetPasswordCode, getInviteCode } = require("../utilities/redis") const GLOBAL_DB = StaticDatabases.GLOBAL.name const TYPE = TemplateTypes.EMAIL @@ -30,6 +31,24 @@ function createSMTPTransport(config) { return nodemailer.createTransport(options) } +async function getLinkCode(purpose, email, user) { + switch (purpose) { + case EmailTemplatePurpose.PASSWORD_RECOVERY: + return getResetPasswordCode(user._id) + case EmailTemplatePurpose.INVITATION: + return getInviteCode(email) + default: + return null + } +} + +/** + * Builds an email using handlebars and the templates found in the system (default or otherwise). + * @param {string} purpose the purpose of the email being built, e.g. invitation, password reset. + * @param {string} email the address which it is being sent to for contextual purposes. + * @param {object|null} user If being sent to an existing user then the object can be provided for context. + * @return {Promise} returns the built email HTML if all provided parameters were valid. + */ async function buildEmail(purpose, email, user) { // this isn't a full email if (FULL_EMAIL_PURPOSES.indexOf(purpose) === -1) { @@ -47,9 +66,10 @@ async function buildEmail(purpose, email, user) { styles = styles.contents body = body.contents - // TODO: need to extend the context as much as possible + // if there is a link code needed this will retrieve it + const code = await getLinkCode(purpose, email, user) const context = { - ...(await getSettingsTemplateContext()), + ...(await getSettingsTemplateContext(purpose, code)), email, user: user || {}, } @@ -64,19 +84,46 @@ async function buildEmail(purpose, email, user) { }) } -exports.sendEmail = async (email, purpose, { groupId, userId }) => { - const db = new CouchDB(GLOBAL_DB) +/** + * Utility function for finding most valid SMTP configuration. + * @param {object} db The CouchDB database which is to be looked up within. + * @param {string|null} groupId If using finer grain control of configs a group can be used. + * @return {Promise} returns the SMTP configuration if it exists + */ +async function getSmtpConfiguration(db, groupId = null) { const params = { type: Configs.SMTP, } if (groupId) { params.group = groupId } - let user = {} - if (userId) { - user = db.get(userId) - } - const config = await determineScopedConfig(db, params) + return determineScopedConfig(db, params) +} + +/** + * Checks if a SMTP config exists based on passed in parameters. + * @param groupId + * @return {Promise} returns true if there is a configuration that can be used. + */ +exports.isEmailConfigured = async (groupId = null) => { + const db = new CouchDB(GLOBAL_DB) + const config = await getSmtpConfiguration(db, groupId) + return config != null +} + +/** + * Given an email address and an email purpose this will retrieve the SMTP configuration and + * send an email using it. + * @param {string} email The email address to send to. + * @param {string} purpose The purpose of the email being sent (e.g. reset password). + * @param {string|null} groupId If finer grain controls being used then this will lookup config for group. + * @param {object|null} if sending to an existing user the object can be provided, this is used in the context. + * @return {Promise} returns details about the attempt to send email, e.g. if it is successful; based on + * nodemailer response. + */ +exports.sendEmail = async (email, purpose, { groupId, user }) => { + const db = new CouchDB(GLOBAL_DB) + const config = await getSmtpConfiguration(db, groupId) if (!config) { throw "Unable to find SMTP configuration" } @@ -90,6 +137,11 @@ exports.sendEmail = async (email, purpose, { groupId, userId }) => { return transport.sendMail(message) } +/** + * Given an SMTP configuration this runs it through nodemailer to see if it is infact functional. + * @param {object} config an SMTP configuration - this is based on the nodemailer API. + * @return {Promise} returns true if the configuration is valid. + */ exports.verifyConfig = async config => { const transport = createSMTPTransport(config) await transport.verify() diff --git a/packages/worker/src/utilities/redis.js b/packages/worker/src/utilities/redis.js new file mode 100644 index 0000000000..7e40af6b65 --- /dev/null +++ b/packages/worker/src/utilities/redis.js @@ -0,0 +1,51 @@ +const { Client, utils } = require("@budibase/auth").redis +const { newid } = require("@budibase/auth").utils + +const EXPIRE_TOKEN_SECONDS = 3600 + +async function getClient(db) { + return await (new Client(db)).init() +} + +async function writeACode(db, value) { + const client = await getClient(db) + const code = newid() + await client.store(code, value, EXPIRE_TOKEN_SECONDS) + client.finish() + return code +} + +/** + * Given a user ID this will store a code (that is returned) for an hour in redis. + * The user can then return this code for resetting their password (through their reset link). + * @param {string} userId the ID of the user which is to be reset. + * @return {Promise} returns the code that was stored to redis. + */ +exports.getResetPasswordCode = async userId => { + return writeACode(utils.Databases.PW_RESETS, userId) +} + +/** + * Given a reset code this will lookup to redis, check if the code is valid and delete if required. + * @param {string} resetCode The code provided via the email link. + * @param {boolean} deleteCode If the code is used/finished with this will delete it. + * @return {Promise} returns the user ID if it is found + */ +exports.checkResetPasswordCode = async (resetCode, deleteCode = false) => { + const client = await getClient(utils.Databases.PW_RESETS) + const userId = await client.get(resetCode) + if (deleteCode) { + await client.delete(resetCode) + } + client.finish() + return userId +} + +/** + * Generates an invitation code and writes it to redis - which can later be checked for user creation. + * @param {string} email the email address which the code is being sent to (for use later). + * @return {Promise} returns the code that was stored to redis. + */ +exports.getInviteCode = async email => { + return writeACode(utils.Databases.INVITATIONS, email) +} \ No newline at end of file diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js index 3035dc2bbc..1c32461245 100644 --- a/packages/worker/src/utilities/templates.js +++ b/packages/worker/src/utilities/templates.js @@ -1,13 +1,13 @@ const CouchDB = require("../db") const { getConfigParams, StaticDatabases } = require("@budibase/auth").db -const { Configs, TemplateBindings, LOGO_URL } = require("../constants") +const { Configs, TemplateBindings, LOGO_URL, EmailTemplatePurpose } = require("../constants") const { checkSlashesInUrl } = require("./index") const env = require("../environment") const LOCAL_URL = `http://localhost:${env.PORT}` const BASE_COMPANY = "Budibase" -exports.getSettingsTemplateContext = async () => { +exports.getSettingsTemplateContext = async (purpose, code = null) => { const db = new CouchDB(StaticDatabases.GLOBAL.name) const response = await db.allDocs( getConfigParams(Configs.SETTINGS, { @@ -18,15 +18,10 @@ exports.getSettingsTemplateContext = async () => { if (!settings.platformUrl) { settings.platformUrl = LOCAL_URL } - // TODO: need to fully spec out the context const URL = settings.platformUrl - return { + const context = { [TemplateBindings.LOGO_URL]: settings.logoUrl || LOGO_URL, [TemplateBindings.PLATFORM_URL]: URL, - [TemplateBindings.REGISTRATION_URL]: checkSlashesInUrl( - `${URL}/registration` - ), - [TemplateBindings.RESET_URL]: checkSlashesInUrl(`${URL}/reset`), [TemplateBindings.COMPANY]: settings.company || BASE_COMPANY, [TemplateBindings.DOCS_URL]: settings.docsUrl || "https://docs.budibase.com/", @@ -34,4 +29,20 @@ exports.getSettingsTemplateContext = async () => { [TemplateBindings.CURRENT_DATE]: new Date().toISOString(), [TemplateBindings.CURRENT_YEAR]: new Date().getFullYear(), } + // attach purpose specific context + switch (purpose) { + case EmailTemplatePurpose.PASSWORD_RECOVERY: + context[TemplateBindings.RESET_CODE] = code + context[TemplateBindings.RESET_URL] = checkSlashesInUrl( + `${URL}/reset/${code}` + ) + break + case EmailTemplatePurpose.INVITATION: + context[TemplateBindings.INVITE_CODE] = code + context[TemplateBindings.REGISTRATION_URL] = checkSlashesInUrl( + `${URL}/registration/${code}` + ) + break + } + return context } From fc01bdaac9ffebf99382d9237f8a3fcec0cb275f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 12:11:31 +0100 Subject: [PATCH 09/19] Formatting. --- packages/worker/src/api/controllers/admin/auth.js | 2 +- packages/worker/src/utilities/redis.js | 4 ++-- packages/worker/src/utilities/templates.js | 7 ++++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index 1d6981d0ed..6318e523bf 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -55,7 +55,7 @@ exports.reset = async ctx => { // don't throw any kind of error to the user, this might give away something } ctx.body = { - message: "If user exists an email has been sent." + message: "If user exists an email has been sent.", } } diff --git a/packages/worker/src/utilities/redis.js b/packages/worker/src/utilities/redis.js index 7e40af6b65..c78060df52 100644 --- a/packages/worker/src/utilities/redis.js +++ b/packages/worker/src/utilities/redis.js @@ -4,7 +4,7 @@ const { newid } = require("@budibase/auth").utils const EXPIRE_TOKEN_SECONDS = 3600 async function getClient(db) { - return await (new Client(db)).init() + return await new Client(db).init() } async function writeACode(db, value) { @@ -48,4 +48,4 @@ exports.checkResetPasswordCode = async (resetCode, deleteCode = false) => { */ exports.getInviteCode = async email => { return writeACode(utils.Databases.INVITATIONS, email) -} \ No newline at end of file +} diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js index 1c32461245..4a7ca6fc7c 100644 --- a/packages/worker/src/utilities/templates.js +++ b/packages/worker/src/utilities/templates.js @@ -1,6 +1,11 @@ const CouchDB = require("../db") const { getConfigParams, StaticDatabases } = require("@budibase/auth").db -const { Configs, TemplateBindings, LOGO_URL, EmailTemplatePurpose } = require("../constants") +const { + Configs, + TemplateBindings, + LOGO_URL, + EmailTemplatePurpose, +} = require("../constants") const { checkSlashesInUrl } = require("./index") const env = require("../environment") From 7bc3514fc140df21f38313e778c2db995029698a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 15:10:28 +0100 Subject: [PATCH 10/19] Finalising the usage of redis in the password reset and invitation systems. --- packages/auth/src/utils.js | 6 +++ .../worker/src/api/controllers/admin/auth.js | 29 ++++++++-- .../worker/src/api/controllers/admin/users.js | 20 ++++++- packages/worker/src/api/index.js | 13 +++-- packages/worker/src/api/routes/admin/auth.js | 9 ++++ packages/worker/src/api/routes/admin/users.js | 19 ++++++- packages/worker/src/utilities/email.js | 6 +-- packages/worker/src/utilities/redis.js | 54 +++++++++++++++---- 8 files changed, 133 insertions(+), 23 deletions(-) diff --git a/packages/auth/src/utils.js b/packages/auth/src/utils.js index 10507410b1..a0ba0d25b5 100644 --- a/packages/auth/src/utils.js +++ b/packages/auth/src/utils.js @@ -105,6 +105,12 @@ exports.isClient = ctx => { return ctx.headers["x-budibase-type"] === "client" } +/** + * Given an email address this will use a view to search through + * all the users to find one with this email address. + * @param {string} email the email to lookup the user by. + * @return {Promise} + */ exports.getGlobalUserByEmail = async email => { const db = getDB(StaticDatabases.GLOBAL.name) try { diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index 6318e523bf..c565974d28 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -1,11 +1,12 @@ const authPkg = require("@budibase/auth") const { google } = require("@budibase/auth/src/middleware") -const { Configs } = require("../../../constants") +const { Configs, EmailTemplatePurpose } = require("../../../constants") const CouchDB = require("../../../db") const { sendEmail, isEmailConfigured } = require("../../../utilities/email") -const { clearCookie, getGlobalUserByEmail } = authPkg.utils +const { clearCookie, getGlobalUserByEmail, hash } = authPkg.utils const { Cookies } = authPkg.constants const { passport } = authPkg.auth +const { checkResetPasswordCode } = require("../../../utilities/redis") const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name @@ -50,18 +51,36 @@ exports.reset = async ctx => { } try { const user = await getGlobalUserByEmail(email) - sendEmail() + await sendEmail(email, EmailTemplatePurpose.PASSWORD_RECOVERY, { user }) } catch (err) { // don't throw any kind of error to the user, this might give away something } ctx.body = { - message: "If user exists an email has been sent.", + message: "Please check your email for a reset link.", + } +} + +/** + * Perform the user password update if the provided reset code is valid. + */ +exports.resetUpdate = async ctx => { + const { resetCode, password } = ctx.request.body + const userId = await checkResetPasswordCode(resetCode) + if (!userId) { + throw "Cannot reset password." + } + const db = new CouchDB(GLOBAL_DB) + const user = await db.get(userId) + user.password = await hash(password) + await db.put(user) + ctx.body = { + message: "password reset successfully.", } } exports.logout = async ctx => { clearCookie(ctx, Cookies.Auth) - ctx.body = { message: "User logged out" } + ctx.body = { message: "User logged out." } } /** diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js index e9e6b64ac0..d141ca88e9 100644 --- a/packages/worker/src/api/controllers/admin/users.js +++ b/packages/worker/src/api/controllers/admin/users.js @@ -6,6 +6,7 @@ const { } = require("@budibase/auth").db const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils const { UserStatus } = require("../../../constants") +const { checkResetPasswordCode, checkInviteCode } = require("../../../utilities/redis") const FIRST_USER_EMAIL = "test@test.com" const FIRST_USER_PASSWORD = "test" @@ -42,7 +43,7 @@ exports.save = async ctx => { user.status = UserStatus.ACTIVE } try { - const response = await db.post({ + const response = await db.put({ password: hashedPassword, ...user, }) @@ -121,3 +122,20 @@ exports.find = async ctx => { } ctx.body = user } + +exports.invite = async ctx => { + +} + +exports.inviteAccept = async ctx => { + const { inviteCode } = ctx.request.body + const email = await checkInviteCode(inviteCode) + if (!email) { + throw "Unable to create new user, invitation invalid." + } + // redirect the request + delete ctx.request.body.inviteCode + ctx.request.body.email = email + // this will flesh out the body response + await exports.save(ctx) +} diff --git a/packages/worker/src/api/index.js b/packages/worker/src/api/index.js index c4877beabf..eb87c0e2fa 100644 --- a/packages/worker/src/api/index.js +++ b/packages/worker/src/api/index.js @@ -4,11 +4,15 @@ const zlib = require("zlib") const { routes } = require("./routes") const { buildAuthMiddleware } = require("@budibase/auth").auth -const NO_AUTH_ENDPOINTS = [ +const PUBLIC_ENDPOINTS = [ { route: "/api/admin/users/first", method: "POST", }, + { + route: "/api/admin/users/invite/accept", + method: "POST", + }, { route: "/api/admin/auth", method: "POST", @@ -21,10 +25,13 @@ const NO_AUTH_ENDPOINTS = [ route: "/api/admin/auth/google/callback", method: "GET", }, + { + route: "/api/admin/auth/reset", + method: "POST", + }, ] const router = new Router() - router .use( compress({ @@ -39,7 +46,7 @@ router }) ) .use("/health", ctx => (ctx.status = 200)) - .use(buildAuthMiddleware(NO_AUTH_ENDPOINTS)) + .use(buildAuthMiddleware(PUBLIC_ENDPOINTS)) // for now no public access is allowed to worker (bar health check) .use((ctx, next) => { if (!ctx.isAuthenticated) { diff --git a/packages/worker/src/api/routes/admin/auth.js b/packages/worker/src/api/routes/admin/auth.js index 60d2f4ae7d..8f109417ff 100644 --- a/packages/worker/src/api/routes/admin/auth.js +++ b/packages/worker/src/api/routes/admin/auth.js @@ -20,9 +20,18 @@ function buildResetValidation() { }).required().unknown(false)) } +function buildResetUpdateValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + resetCode: Joi.string().required(), + password: Joi.string().required(), + }).required().unknown(false)) +} + router .post("/api/admin/auth", buildAuthValidation(), authController.authenticate) .post("/api/admin/auth/reset", buildResetValidation(), authController.reset) + .post("/api/admin/auth/reset/update", buildResetUpdateValidation(), authController.resetUpdate) .post("/api/admin/auth/logout", authController.logout) .get("/api/admin/auth/google", authController.googlePreAuth) .get("/api/admin/auth/google/callback", authController.googleAuth) diff --git a/packages/worker/src/api/routes/admin/users.js b/packages/worker/src/api/routes/admin/users.js index d4bc4b6b62..a5e2d9f87e 100644 --- a/packages/worker/src/api/routes/admin/users.js +++ b/packages/worker/src/api/routes/admin/users.js @@ -21,7 +21,22 @@ function buildUserSaveValidation() { .pattern(/.*/, Joi.string()) .required() .unknown(true) - }).required().unknown(true).optional()) + }).required().unknown(true)) +} + +function buildInviteValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + email: Joi.string().required(), + }).required()) +} + +function buildInviteAcceptValidation() { + // prettier-ignore + return joiValidator.body(Joi.object({ + inviteCode: Joi.string().required(), + password: Joi.string().required(), + }).required().unknown(true)) } router @@ -30,5 +45,7 @@ router .post("/api/admin/users/first", controller.firstUser) .delete("/api/admin/users/:id", controller.destroy) .get("/api/admin/users/:id", controller.find) + .post("/api/admin/users/invite", buildInviteValidation(), controller.invite) + .post("/api/admin/users/invite/accept", buildInviteAcceptValidation(), controller.inviteAccept) module.exports = router diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index 524d305899..745abdf7a2 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -116,8 +116,8 @@ exports.isEmailConfigured = async (groupId = null) => { * send an email using it. * @param {string} email The email address to send to. * @param {string} purpose The purpose of the email being sent (e.g. reset password). - * @param {string|null} groupId If finer grain controls being used then this will lookup config for group. - * @param {object|null} if sending to an existing user the object can be provided, this is used in the context. + * @param {string|undefined} groupId If finer grain controls being used then this will lookup config for group. + * @param {object|undefined} user if sending to an existing user the object can be provided, this is used in the context. * @return {Promise} returns details about the attempt to send email, e.g. if it is successful; based on * nodemailer response. */ @@ -125,7 +125,7 @@ exports.sendEmail = async (email, purpose, { groupId, user }) => { const db = new CouchDB(GLOBAL_DB) const config = await getSmtpConfiguration(db, groupId) if (!config) { - throw "Unable to find SMTP configuration" + throw "Unable to find SMTP configuration." } const transport = createSMTPTransport(config) const message = { diff --git a/packages/worker/src/utilities/redis.js b/packages/worker/src/utilities/redis.js index c78060df52..73ef8a0d43 100644 --- a/packages/worker/src/utilities/redis.js +++ b/packages/worker/src/utilities/redis.js @@ -1,7 +1,16 @@ const { Client, utils } = require("@budibase/auth").redis const { newid } = require("@budibase/auth").utils -const EXPIRE_TOKEN_SECONDS = 3600 +function getExpirySecondsForDB(db) { + switch (db) { + case utils.Databases.PW_RESETS: + // a hour + return 3600 + case utils.Databases.INVITATIONS: + // a day + return 86400 + } +} async function getClient(db) { return await new Client(db).init() @@ -10,11 +19,24 @@ async function getClient(db) { async function writeACode(db, value) { const client = await getClient(db) const code = newid() - await client.store(code, value, EXPIRE_TOKEN_SECONDS) + await client.store(code, value, getExpirySecondsForDB(db)) client.finish() return code } +async function getACode(db, code, deleteCode = true) { + const client = await getClient(db) + const value = await client.get(code) + if (!value) { + throw "Invalid code." + } + if (deleteCode) { + await client.delete(code) + } + client.finish() + return value +} + /** * Given a user ID this will store a code (that is returned) for an hour in redis. * The user can then return this code for resetting their password (through their reset link). @@ -28,17 +50,15 @@ exports.getResetPasswordCode = async userId => { /** * Given a reset code this will lookup to redis, check if the code is valid and delete if required. * @param {string} resetCode The code provided via the email link. - * @param {boolean} deleteCode If the code is used/finished with this will delete it. + * @param {boolean} deleteCode If the code is used/finished with this will delete it - defaults to true. * @return {Promise} returns the user ID if it is found */ -exports.checkResetPasswordCode = async (resetCode, deleteCode = false) => { - const client = await getClient(utils.Databases.PW_RESETS) - const userId = await client.get(resetCode) - if (deleteCode) { - await client.delete(resetCode) +exports.checkResetPasswordCode = async (resetCode, deleteCode = true) => { + try { + return getACode(utils.Databases.PW_RESETS, resetCode, deleteCode) + } catch (err) { + throw "Provided information is not valid, cannot reset password - please try again." } - client.finish() - return userId } /** @@ -49,3 +69,17 @@ exports.checkResetPasswordCode = async (resetCode, deleteCode = false) => { exports.getInviteCode = async email => { return writeACode(utils.Databases.INVITATIONS, email) } + +/** + * Checks that the provided invite code is valid - will return the email address of user that was invited. + * @param {string} inviteCode the invite code that was provided as part of the link. + * @param {boolean} deleteCode whether or not the code should be deleted after retrieval - defaults to true. + * @return {Promise} If the code is valid then an email address will be returned. + */ +exports.checkInviteCode = async (inviteCode, deleteCode = true) => { + try { + return getACode(utils.Databases.INVITATIONS, inviteCode, deleteCode) + } catch (err) { + throw "Invitation is not valid or has expired, please request a new one." + } +} From b4beb4d8daafa9def44b8739574247564c8e2e58 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 15:17:15 +0100 Subject: [PATCH 11/19] Finishing invite send email. --- .../worker/src/api/controllers/admin/auth.js | 23 ++++++------- .../worker/src/api/controllers/admin/users.js | 32 ++++++++++++------- packages/worker/src/utilities/email.js | 2 +- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index c565974d28..386b1f4a88 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -47,7 +47,7 @@ exports.reset = async ctx => { const { email } = ctx.request.body const configured = await isEmailConfigured() if (!configured) { - throw "Please contact your platform administrator, SMTP is not configured." + ctx.throw(400, "Please contact your platform administrator, SMTP is not configured.") } try { const user = await getGlobalUserByEmail(email) @@ -65,16 +65,17 @@ exports.reset = async ctx => { */ exports.resetUpdate = async ctx => { const { resetCode, password } = ctx.request.body - const userId = await checkResetPasswordCode(resetCode) - if (!userId) { - throw "Cannot reset password." - } - const db = new CouchDB(GLOBAL_DB) - const user = await db.get(userId) - user.password = await hash(password) - await db.put(user) - ctx.body = { - message: "password reset successfully.", + try { + const userId = await checkResetPasswordCode(resetCode) + const db = new CouchDB(GLOBAL_DB) + const user = await db.get(userId) + user.password = await hash(password) + await db.put(user) + ctx.body = { + message: "password reset successfully.", + } + } catch (err) { + ctx.throw(400, "Cannot reset password.") } } diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js index d141ca88e9..48a20141a3 100644 --- a/packages/worker/src/api/controllers/admin/users.js +++ b/packages/worker/src/api/controllers/admin/users.js @@ -5,8 +5,9 @@ const { StaticDatabases, } = require("@budibase/auth").db const { hash, getGlobalUserByEmail } = require("@budibase/auth").utils -const { UserStatus } = require("../../../constants") -const { checkResetPasswordCode, checkInviteCode } = require("../../../utilities/redis") +const { UserStatus, EmailTemplatePurpose } = require("../../../constants") +const { checkInviteCode } = require("../../../utilities/redis") +const { sendEmail } = require("../../../utilities/email") const FIRST_USER_EMAIL = "test@test.com" const FIRST_USER_PASSWORD = "test" @@ -124,18 +125,27 @@ exports.find = async ctx => { } exports.invite = async ctx => { - + const { email } = ctx.request.body + const existing = await getGlobalUserByEmail(FIRST_USER_EMAIL) + if (existing) { + ctx.throw(400, "Email address already in use.") + } + await sendEmail(email, EmailTemplatePurpose.INVITATION) + ctx.body = { + message: "Invitation has been sent." + } } exports.inviteAccept = async ctx => { const { inviteCode } = ctx.request.body - const email = await checkInviteCode(inviteCode) - if (!email) { - throw "Unable to create new user, invitation invalid." + try { + const email = await checkInviteCode(inviteCode) + // redirect the request + delete ctx.request.body.inviteCode + ctx.request.body.email = email + // this will flesh out the body response + await exports.save(ctx) + } catch (err) { + ctx.throw(400, "Unable to create new user, invitation invalid.") } - // redirect the request - delete ctx.request.body.inviteCode - ctx.request.body.email = email - // this will flesh out the body response - await exports.save(ctx) } diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index 745abdf7a2..f7b9284402 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -121,7 +121,7 @@ exports.isEmailConfigured = async (groupId = null) => { * @return {Promise} returns details about the attempt to send email, e.g. if it is successful; based on * nodemailer response. */ -exports.sendEmail = async (email, purpose, { groupId, user }) => { +exports.sendEmail = async (email, purpose, { groupId, user } = {}) => { const db = new CouchDB(GLOBAL_DB) const config = await getSmtpConfiguration(db, groupId) if (!config) { From 403ee4a870d083d4a43c8afa08653ef1048fa748 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 15:19:44 +0100 Subject: [PATCH 12/19] Formatting. --- packages/worker/src/api/controllers/admin/auth.js | 5 ++++- packages/worker/src/api/controllers/admin/users.js | 2 +- packages/worker/src/api/routes/admin/auth.js | 6 +++++- packages/worker/src/api/routes/admin/users.js | 6 +++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index 386b1f4a88..04c835a2e7 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -47,7 +47,10 @@ exports.reset = async ctx => { const { email } = ctx.request.body const configured = await isEmailConfigured() if (!configured) { - ctx.throw(400, "Please contact your platform administrator, SMTP is not configured.") + ctx.throw( + 400, + "Please contact your platform administrator, SMTP is not configured." + ) } try { const user = await getGlobalUserByEmail(email) diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js index 48a20141a3..cd307bbc6b 100644 --- a/packages/worker/src/api/controllers/admin/users.js +++ b/packages/worker/src/api/controllers/admin/users.js @@ -132,7 +132,7 @@ exports.invite = async ctx => { } await sendEmail(email, EmailTemplatePurpose.INVITATION) ctx.body = { - message: "Invitation has been sent." + message: "Invitation has been sent.", } } diff --git a/packages/worker/src/api/routes/admin/auth.js b/packages/worker/src/api/routes/admin/auth.js index 8f109417ff..04e30fc006 100644 --- a/packages/worker/src/api/routes/admin/auth.js +++ b/packages/worker/src/api/routes/admin/auth.js @@ -31,7 +31,11 @@ function buildResetUpdateValidation() { router .post("/api/admin/auth", buildAuthValidation(), authController.authenticate) .post("/api/admin/auth/reset", buildResetValidation(), authController.reset) - .post("/api/admin/auth/reset/update", buildResetUpdateValidation(), authController.resetUpdate) + .post( + "/api/admin/auth/reset/update", + buildResetUpdateValidation(), + authController.resetUpdate + ) .post("/api/admin/auth/logout", authController.logout) .get("/api/admin/auth/google", authController.googlePreAuth) .get("/api/admin/auth/google/callback", authController.googleAuth) diff --git a/packages/worker/src/api/routes/admin/users.js b/packages/worker/src/api/routes/admin/users.js index a5e2d9f87e..c15b43bd4f 100644 --- a/packages/worker/src/api/routes/admin/users.js +++ b/packages/worker/src/api/routes/admin/users.js @@ -46,6 +46,10 @@ router .delete("/api/admin/users/:id", controller.destroy) .get("/api/admin/users/:id", controller.find) .post("/api/admin/users/invite", buildInviteValidation(), controller.invite) - .post("/api/admin/users/invite/accept", buildInviteAcceptValidation(), controller.inviteAccept) + .post( + "/api/admin/users/invite/accept", + buildInviteAcceptValidation(), + controller.inviteAccept + ) module.exports = router From 5d2c1c23aa9fe0354ffb0e62fc91ba4186f4cbec Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 15:59:24 +0100 Subject: [PATCH 13/19] Updating configs API based on some feedback during the development of the settings frontend. --- .../worker/src/api/controllers/admin/configs.js | 11 +++++------ packages/worker/src/api/routes/admin/configs.js | 13 ++++++++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/worker/src/api/controllers/admin/configs.js b/packages/worker/src/api/controllers/admin/configs.js index bf9259f953..0a2e2feccb 100644 --- a/packages/worker/src/api/controllers/admin/configs.js +++ b/packages/worker/src/api/controllers/admin/configs.js @@ -48,7 +48,7 @@ exports.save = async function (ctx) { exports.fetch = async function (ctx) { const db = new CouchDB(GLOBAL_DB) const response = await db.allDocs( - getConfigParams(undefined, { + getConfigParams({ type: ctx.params.type }, { include_docs: true, }) ) @@ -61,11 +61,10 @@ exports.fetch = async function (ctx) { */ exports.find = async function (ctx) { const db = new CouchDB(GLOBAL_DB) - const userId = ctx.params.user && ctx.params.user._id - const { group } = ctx.query - if (group) { - const group = await db.get(group) + const { userId, groupId } = ctx.query + if (groupId && userId) { + const group = await db.get(groupId) const userInGroup = group.users.some(groupUser => groupUser === userId) if (!ctx.user.admin && !userInGroup) { ctx.throw(400, `User is not in specified group: ${group}.`) @@ -77,7 +76,7 @@ exports.find = async function (ctx) { const scopedConfig = await determineScopedConfig(db, { type: ctx.params.type, user: userId, - group, + group: groupId, }) if (scopedConfig) { diff --git a/packages/worker/src/api/routes/admin/configs.js b/packages/worker/src/api/routes/admin/configs.js index 5865259a29..1b5150ef27 100644 --- a/packages/worker/src/api/routes/admin/configs.js +++ b/packages/worker/src/api/routes/admin/configs.js @@ -54,14 +54,21 @@ function buildConfigSaveValidation() { { is: Configs.GOOGLE, then: googleValidation() } ], }), - }), + }).required(), ) } +function buildConfigGetValidation() { + // prettier-ignore + return joiValidator.params(Joi.object({ + type: Joi.string().valid(...Object.values(Configs)).required() + }).unknown(true).required()) +} + router .post("/api/admin/configs", buildConfigSaveValidation(), controller.save) .delete("/api/admin/configs/:id", controller.destroy) - .get("/api/admin/configs", controller.fetch) - .get("/api/admin/configs/:type", controller.find) + .get("/api/admin/configs/all/:type", buildConfigGetValidation(), controller.fetch) + .get("/api/admin/configs/:type", buildConfigGetValidation(), controller.find) module.exports = router From 48236b2c2f05d24a1a32b8fdb019b75dbd4f0ee7 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 16:00:15 +0100 Subject: [PATCH 14/19] Formatting. --- packages/worker/src/api/controllers/admin/configs.js | 9 ++++++--- packages/worker/src/api/routes/admin/configs.js | 6 +++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/worker/src/api/controllers/admin/configs.js b/packages/worker/src/api/controllers/admin/configs.js index 0a2e2feccb..0b114a7b0b 100644 --- a/packages/worker/src/api/controllers/admin/configs.js +++ b/packages/worker/src/api/controllers/admin/configs.js @@ -48,9 +48,12 @@ exports.save = async function (ctx) { exports.fetch = async function (ctx) { const db = new CouchDB(GLOBAL_DB) const response = await db.allDocs( - getConfigParams({ type: ctx.params.type }, { - include_docs: true, - }) + getConfigParams( + { type: ctx.params.type }, + { + include_docs: true, + } + ) ) ctx.body = response.rows.map(row => row.doc) } diff --git a/packages/worker/src/api/routes/admin/configs.js b/packages/worker/src/api/routes/admin/configs.js index 1b5150ef27..7bef117a70 100644 --- a/packages/worker/src/api/routes/admin/configs.js +++ b/packages/worker/src/api/routes/admin/configs.js @@ -68,7 +68,11 @@ function buildConfigGetValidation() { router .post("/api/admin/configs", buildConfigSaveValidation(), controller.save) .delete("/api/admin/configs/:id", controller.destroy) - .get("/api/admin/configs/all/:type", buildConfigGetValidation(), controller.fetch) + .get( + "/api/admin/configs/all/:type", + buildConfigGetValidation(), + controller.fetch + ) .get("/api/admin/configs/:type", buildConfigGetValidation(), controller.find) module.exports = router From 2ee4fd21e4db969c6c3886af8c770b4c4af0b739 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 17:49:34 +0100 Subject: [PATCH 15/19] Updating testing system across the board after playing around with it, having the worker tests run when top level test is ran, fixing environment in worker when testing, removing the use of redis (replacing with ioredis-mock) when in test. --- packages/auth/package.json | 3 + packages/auth/src/environment.js | 9 +++ packages/auth/src/redis/index.js | 18 ++++- packages/auth/src/redis/utils.js | 8 +- packages/auth/yarn.lock | 74 ++++++++++++++++++- packages/server/src/api/index.js | 11 ++- .../server/src/api/routes/tests/row.spec.js | 6 +- packages/server/src/automations/triggers.js | 3 +- packages/worker/package.json | 9 ++- packages/worker/scripts/jestSetup.js | 5 ++ .../worker/src/api/controllers/admin/email.js | 11 ++- .../worker/src/api/controllers/admin/users.js | 2 +- .../worker/src/api/routes/tests/auth.spec.js | 49 ++++++++++++ .../worker/src/api/routes/tests/email.spec.js | 7 +- .../src/api/routes/tests/realEmail.spec.js | 4 +- .../worker/src/api/routes/tests/users.spec.js | 52 +++++++++++++ .../tests/utilities/TestConfiguration.js | 26 +++++++ .../src/api/routes/tests/utilities/index.js | 15 +++- packages/worker/src/environment.js | 2 +- packages/worker/src/index.js | 4 - packages/worker/src/utilities/templates.js | 2 +- packages/worker/yarn.lock | 67 ++++++++++++++++- 22 files changed, 353 insertions(+), 34 deletions(-) create mode 100644 packages/worker/scripts/jestSetup.js create mode 100644 packages/worker/src/api/routes/tests/auth.spec.js create mode 100644 packages/worker/src/api/routes/tests/users.spec.js diff --git a/packages/auth/package.json b/packages/auth/package.json index 72ea0bc3ba..dfbb63c431 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -15,5 +15,8 @@ "passport-jwt": "^4.0.0", "passport-local": "^1.0.0", "uuid": "^8.3.2" + }, + "devDependencies": { + "ioredis-mock": "^5.5.5" } } diff --git a/packages/auth/src/environment.js b/packages/auth/src/environment.js index 4f195337b6..5b0b141019 100644 --- a/packages/auth/src/environment.js +++ b/packages/auth/src/environment.js @@ -1,7 +1,16 @@ +function isTest() { + return ( + process.env.NODE_ENV === "jest" || + process.env.NODE_ENV === "cypress" || + process.env.JEST_WORKER_ID != null + ) +} + module.exports = { JWT_SECRET: process.env.JWT_SECRET, COUCH_DB_URL: process.env.COUCH_DB_URL, SALT_ROUNDS: process.env.SALT_ROUNDS, REDIS_URL: process.env.REDIS_URL, REDIS_PASSWORD: process.env.REDIS_PASSWORD, + isTest, } diff --git a/packages/auth/src/redis/index.js b/packages/auth/src/redis/index.js index 0cb92c4622..dc670c07fb 100644 --- a/packages/auth/src/redis/index.js +++ b/packages/auth/src/redis/index.js @@ -1,9 +1,12 @@ -const Redis = require("ioredis") +const env = require("../environment") +// ioredis mock is all in memory +const Redis = env.isTest() ? require("ioredis-mock") : require("ioredis") const { addDbPrefix, removeDbPrefix, getRedisOptions } = require("./utils") const CLUSTERED = false -let CLIENT +// for testing just generate the client once +let CLIENT = env.isTest() ? new Redis(getRedisOptions()) : null /** * Inits the system, will error if unable to connect to redis cluster (may take up to 10 seconds) otherwise @@ -12,6 +15,10 @@ let CLIENT */ function init() { return new Promise((resolve, reject) => { + // testing uses a single in memory client + if (env.isTest()) { + return resolve(CLIENT) + } // if a connection existed, close it and re-create it if (CLIENT) { CLIENT.disconnect() @@ -108,7 +115,12 @@ class RedisWrapper { if (response != null && response.key) { response.key = key } - return JSON.parse(response) + // if its not an object just return the response + try { + return JSON.parse(response) + } catch (err) { + return response + } } async store(key, value, expirySeconds = null) { diff --git a/packages/auth/src/redis/utils.js b/packages/auth/src/redis/utils.js index a29f786c41..bd4a762e1d 100644 --- a/packages/auth/src/redis/utils.js +++ b/packages/auth/src/redis/utils.js @@ -3,6 +3,8 @@ const env = require("../environment") const SLOT_REFRESH_MS = 2000 const CONNECT_TIMEOUT_MS = 10000 const SEPARATOR = "-" +const REDIS_URL = !env.REDIS_URL ? "localhost:6379" : env.REDIS_URL +const REDIS_PASSWORD = !env.REDIS_PASSWORD ? "budibase" : env.REDIS_PASSWORD exports.Databases = { PW_RESETS: "pwReset", @@ -10,20 +12,20 @@ exports.Databases = { } exports.getRedisOptions = (clustered = false) => { - const [host, port] = env.REDIS_URL.split(":") + const [host, port] = REDIS_URL.split(":") const opts = { connectTimeout: CONNECT_TIMEOUT_MS, } if (clustered) { opts.redisOptions = {} opts.redisOptions.tls = {} - opts.redisOptions.password = env.REDIS_PASSWORD + opts.redisOptions.password = REDIS_PASSWORD opts.slotsRefreshTimeout = SLOT_REFRESH_MS opts.dnsLookup = (address, callback) => callback(null, address) } else { opts.host = host opts.port = port - opts.password = env.REDIS_PASSWORD + opts.password = REDIS_PASSWORD } return { opts, host, port } } diff --git a/packages/auth/yarn.lock b/packages/auth/yarn.lock index 0dbdaadf8d..a3c95bf42c 100644 --- a/packages/auth/yarn.lock +++ b/packages/auth/yarn.lock @@ -46,6 +46,11 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + base64url@3.x.x: version "3.0.1" resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" @@ -63,6 +68,14 @@ bcryptjs@^2.4.3: resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -85,6 +98,11 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -154,6 +172,20 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== +fengari-interop@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/fengari-interop/-/fengari-interop-0.1.2.tgz#f7731dcdd2ff4449073fb7ac3c451a8841ce1e87" + integrity sha512-8iTvaByZVoi+lQJhHH9vC+c/Yaok9CwOqNQZN6JrVpjmWwW4dDkeblBXhnHC+BoI6eF4Cy5NKW3z6ICEjvgywQ== + +fengari@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/fengari/-/fengari-0.1.4.tgz#72416693cd9e43bd7d809d7829ddc0578b78b0bb" + integrity sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g== + dependencies: + readline-sync "^1.4.9" + sprintf-js "^1.1.1" + tmp "^0.0.33" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -233,6 +265,17 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +ioredis-mock@^5.5.5: + version "5.5.5" + resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-5.5.5.tgz#dec9fedd238c6ab9f56c026fc366533144f8a256" + integrity sha512-7SxCAwNtDLC8IFDptqIhOC7ajp3fciVtCrXOEOkpyjPboAGRQkJbnpNPy1NYORoWi+0/iOtUPUQckSKtSQj4DA== + dependencies: + fengari "^0.1.4" + fengari-interop "^0.1.2" + lodash "^4.17.21" + minimatch "^3.0.4" + standard-as-callback "^2.1.0" + ioredis@^4.27.1: version "4.27.1" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.1.tgz#4ef947b455a1b995baa4b0d7e2c4e4f75f746421" @@ -379,7 +422,7 @@ lodash.once@^4.0.0: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash@^4.14.0: +lodash@^4.14.0, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -401,6 +444,13 @@ mime@^1.4.1: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -426,6 +476,11 @@ oauth@0.9.x: resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + p-map@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" @@ -534,6 +589,11 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +readline-sync@^1.4.9: + version "1.4.10" + resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" + integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== + redis-commands@1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" @@ -592,6 +652,11 @@ semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -617,6 +682,13 @@ string-template@~1.0.0: resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" diff --git a/packages/server/src/api/index.js b/packages/server/src/api/index.js index 5d16134eb4..84ea0aaf20 100644 --- a/packages/server/src/api/index.js +++ b/packages/server/src/api/index.js @@ -5,13 +5,16 @@ const compress = require("koa-compress") const zlib = require("zlib") const { mainRoutes, staticRoutes } = require("./routes") const pkg = require("../../package.json") -const bullboard = require("bull-board") -const expressApp = require("express")() +const env = require("../environment") -expressApp.use("/bulladmin", bullboard.router) +if (!env.isTest()) { + const bullboard = require("bull-board") + const expressApp = require("express")() + + expressApp.use("/bulladmin", bullboard.router) +} const router = new Router() -const env = require("../environment") router .use( diff --git a/packages/server/src/api/routes/tests/row.spec.js b/packages/server/src/api/routes/tests/row.spec.js index 6a1c309c39..fb8ff96efa 100644 --- a/packages/server/src/api/routes/tests/row.spec.js +++ b/packages/server/src/api/routes/tests/row.spec.js @@ -402,14 +402,16 @@ describe("/rows", () => { name: "test", description: "test", attachment: [{ - url: "/test/thing", + key: `/assets/${config.getAppId()}/attachment/test/thing.csv`, }], tableId: table._id, }) // the environment needs configured for this await setup.switchToSelfHosted(async () => { const enriched = await outputProcessing(config.getAppId(), table, [row]) - expect(enriched[0].attachment[0].url).toBe(`/app-assets/assets/${config.getAppId()}/test/thing`) + expect(enriched[0].attachment[0].url).toBe( + `/prod-budi-app-assets/assets/${config.getAppId()}/attachment/test/thing.csv` + ) }) }) }) diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index 77eb32377a..f303856779 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -1,6 +1,7 @@ const CouchDB = require("../db") const emitter = require("../events/index") -const Queue = require("bull") +const env = require("../environment") +const Queue = env.isTest() ? require("../utilities/queue/inMemoryQueue") : require("bull") const { setQueues, BullAdapter } = require("bull-board") const { getAutomationParams } = require("../db/utils") const { coerce } = require("../utilities/rowProcessor") diff --git a/packages/worker/package.json b/packages/worker/package.json index e8db71fc46..1e478f8d5d 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -14,7 +14,8 @@ "scripts": { "run:docker": "node src/index.js", "dev:stack:init": "node ./scripts/dev/manage.js init", - "dev:builder": "npm run dev:stack:init && nodemon src/index.js" + "dev:builder": "npm run dev:stack:init && nodemon src/index.js", + "test": "jest --runInBand" }, "author": "Budibase", "license": "AGPL-3.0-or-later", @@ -50,5 +51,11 @@ "nodemon": "^2.0.7", "pouchdb-adapter-memory": "^7.2.2", "supertest": "^6.1.3" + }, + "jest": { + "testEnvironment": "node", + "setupFiles": [ + "./scripts/jestSetup.js" + ] } } diff --git a/packages/worker/scripts/jestSetup.js b/packages/worker/scripts/jestSetup.js new file mode 100644 index 0000000000..4e3b05b8f9 --- /dev/null +++ b/packages/worker/scripts/jestSetup.js @@ -0,0 +1,5 @@ +const env = require("../src/environment") + +env._set("NODE_ENV", "jest") +env._set("JWT_SECRET", "test-jwtsecret") +env._set("LOG_LEVEL", "silent") \ No newline at end of file diff --git a/packages/worker/src/api/controllers/admin/email.js b/packages/worker/src/api/controllers/admin/email.js index 0a29468133..04e85e7f44 100644 --- a/packages/worker/src/api/controllers/admin/email.js +++ b/packages/worker/src/api/controllers/admin/email.js @@ -1,8 +1,17 @@ const { sendEmail } = require("../../../utilities/email") +const CouchDB = require("../../../db") +const authPkg = require("@budibase/auth") + +const GLOBAL_DB = authPkg.StaticDatabases.GLOBAL.name exports.sendEmail = async ctx => { const { groupId, email, userId, purpose } = ctx.request.body - const response = await sendEmail(email, purpose, { groupId, userId }) + let user + if (userId) { + const db = new CouchDB(GLOBAL_DB) + user = await db.get(userId) + } + const response = await sendEmail(email, purpose, { groupId, user }) ctx.body = { ...response, message: `Email sent to ${email}.`, diff --git a/packages/worker/src/api/controllers/admin/users.js b/packages/worker/src/api/controllers/admin/users.js index cd307bbc6b..075b82ec6c 100644 --- a/packages/worker/src/api/controllers/admin/users.js +++ b/packages/worker/src/api/controllers/admin/users.js @@ -126,7 +126,7 @@ exports.find = async ctx => { exports.invite = async ctx => { const { email } = ctx.request.body - const existing = await getGlobalUserByEmail(FIRST_USER_EMAIL) + const existing = await getGlobalUserByEmail(email) if (existing) { ctx.throw(400, "Email address already in use.") } diff --git a/packages/worker/src/api/routes/tests/auth.spec.js b/packages/worker/src/api/routes/tests/auth.spec.js new file mode 100644 index 0000000000..ea7ab829a3 --- /dev/null +++ b/packages/worker/src/api/routes/tests/auth.spec.js @@ -0,0 +1,49 @@ +const setup = require("./utilities") + +jest.mock("nodemailer") +const sendMailMock = setup.emailMock() + +describe("/api/admin/auth", () => { + let request = setup.getRequest() + let config = setup.getConfig() + let code + + beforeAll(async () => { + await config.init() + }) + + afterAll(setup.afterAll) + + it("should be able to generate password reset email", async () => { + // initially configure settings + await config.saveSmtpConfig() + await config.saveSettingsConfig() + await config.createUser("test@test.com") + const res = await request + .post(`/api/admin/auth/reset`) + .send({ + email: "test@test.com", + }) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body).toEqual({ message: "Please check your email for a reset link." }) + expect(sendMailMock).toHaveBeenCalled() + const emailCall = sendMailMock.mock.calls[0][0] + // after this URL there should be a code + const parts = emailCall.html.split("http://localhost:10000/reset/") + code = parts[1].split("\"")[0] + expect(code).toBeDefined() + }) + + it("should allow resetting user password with code", async () => { + const res = await request + .post(`/api/admin/auth/reset/update`) + .send({ + password: "newpassword", + resetCode: code, + }) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body).toEqual({ message: "password reset successfully." }) + }) +}) \ No newline at end of file diff --git a/packages/worker/src/api/routes/tests/email.spec.js b/packages/worker/src/api/routes/tests/email.spec.js index 797b0326ed..11bdb3fb1f 100644 --- a/packages/worker/src/api/routes/tests/email.spec.js +++ b/packages/worker/src/api/routes/tests/email.spec.js @@ -2,13 +2,8 @@ const setup = require("./utilities") const { EmailTemplatePurpose } = require("../../../constants") // mock the email system -const sendMailMock = jest.fn() jest.mock("nodemailer") -const nodemailer = require("nodemailer") -nodemailer.createTransport.mockReturnValue({ - sendMail: sendMailMock, - verify: jest.fn() -}) +const sendMailMock = setup.emailMock() describe("/api/admin/email", () => { let request = setup.getRequest() diff --git a/packages/worker/src/api/routes/tests/realEmail.spec.js b/packages/worker/src/api/routes/tests/realEmail.spec.js index c96b8ab561..f593b2cc09 100644 --- a/packages/worker/src/api/routes/tests/realEmail.spec.js +++ b/packages/worker/src/api/routes/tests/realEmail.spec.js @@ -16,11 +16,13 @@ describe("/api/admin/email", () => { async function sendRealEmail(purpose) { await config.saveEtherealSmtpConfig() await config.saveSettingsConfig() + const user = await config.getUser("test@test.com") const res = await request .post(`/api/admin/email/send`) .send({ email: "test@test.com", purpose, + userId: user._id, }) .set(config.defaultHeaders()) .expect("Content-Type", /json/) @@ -55,6 +57,6 @@ describe("/api/admin/email", () => { }) it("should be able to send a password recovery email", async () => { - const res = await sendRealEmail(EmailTemplatePurpose.PASSWORD_RECOVERY) + await sendRealEmail(EmailTemplatePurpose.PASSWORD_RECOVERY) }) }) \ No newline at end of file diff --git a/packages/worker/src/api/routes/tests/users.spec.js b/packages/worker/src/api/routes/tests/users.spec.js new file mode 100644 index 0000000000..135d29f0f5 --- /dev/null +++ b/packages/worker/src/api/routes/tests/users.spec.js @@ -0,0 +1,52 @@ +const setup = require("./utilities") + +jest.mock("nodemailer") +const sendMailMock = setup.emailMock() + +describe("/api/admin/users", () => { + let request = setup.getRequest() + let config = setup.getConfig() + let code + + beforeAll(async () => { + await config.init() + }) + + afterAll(setup.afterAll) + + it("should be able to generate an invitation", async () => { + // initially configure settings + await config.saveSmtpConfig() + await config.saveSettingsConfig() + const res = await request + .post(`/api/admin/users/invite`) + .send({ + email: "invite@test.com", + }) + .set(config.defaultHeaders()) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body).toEqual({ message: "Invitation has been sent." }) + expect(sendMailMock).toHaveBeenCalled() + const emailCall = sendMailMock.mock.calls[0][0] + // after this URL there should be a code + const parts = emailCall.html.split("http://localhost:10000/invite/") + code = parts[1].split("\"")[0] + expect(code).toBeDefined() + }) + + it("should be able to create new user from invite", async () => { + const res = await request + .post(`/api/admin/users/invite/accept`) + .send({ + password: "newpassword", + inviteCode: code, + }) + .expect("Content-Type", /json/) + .expect(200) + expect(res.body._id).toBeDefined() + const user = await config.getUser("invite@test.com") + expect(user).toBeDefined() + expect(user._id).toEqual(res.body._id) + }) +}) \ No newline at end of file diff --git a/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js b/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js index 0f97b50c82..d6ef6744f3 100644 --- a/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js +++ b/packages/worker/src/api/routes/tests/utilities/TestConfiguration.js @@ -4,6 +4,7 @@ const supertest = require("supertest") const { jwt } = require("@budibase/auth").auth const { Cookies } = require("@budibase/auth").constants const { Configs, LOGO_URL } = require("../../../../constants") +const { getGlobalUserByEmail } = require("@budibase/auth").utils class TestConfiguration { constructor(openServer = true) { @@ -53,6 +54,12 @@ class TestConfiguration { ) } + async end() { + if (this.server) { + await this.server.close() + } + } + defaultHeaders() { const user = { _id: "us_uuid1", @@ -65,6 +72,25 @@ class TestConfiguration { } } + async getUser(email) { + return getGlobalUserByEmail(email) + } + + async createUser(email = "test@test.com", password = "test") { + const user = await this.getUser(email) + if (user) { + return user + } + await this._req( + { + email, + password, + }, + null, + controllers.users.save + ) + } + async deleteConfig(type) { try { const cfg = await this._req( diff --git a/packages/worker/src/api/routes/tests/utilities/index.js b/packages/worker/src/api/routes/tests/utilities/index.js index d63b837f6d..90f95de49b 100644 --- a/packages/worker/src/api/routes/tests/utilities/index.js +++ b/packages/worker/src/api/routes/tests/utilities/index.js @@ -7,9 +7,9 @@ exports.beforeAll = () => { request = config.getRequest() } -exports.afterAll = () => { +exports.afterAll = async () => { if (config) { - config.end() + await config.end() } request = null config = null @@ -28,3 +28,14 @@ exports.getConfig = () => { } return config } + +exports.emailMock = () => { + // mock the email system + const sendMailMock = jest.fn() + const nodemailer = require("nodemailer") + nodemailer.createTransport.mockReturnValue({ + sendMail: sendMailMock, + verify: jest.fn() + }) + return sendMailMock +} diff --git a/packages/worker/src/environment.js b/packages/worker/src/environment.js index 0adfe2afae..04c010ce16 100644 --- a/packages/worker/src/environment.js +++ b/packages/worker/src/environment.js @@ -11,7 +11,7 @@ function isTest() { } let LOADED = false -if (!LOADED && isDev()) { +if (!LOADED && isDev() && !isTest()) { require("dotenv").config() LOADED = true } diff --git a/packages/worker/src/index.js b/packages/worker/src/index.js index 8b67181fcc..f94846b370 100644 --- a/packages/worker/src/index.js +++ b/packages/worker/src/index.js @@ -12,10 +12,6 @@ const api = require("./api") const app = new Koa() -if (!env.SELF_HOSTED) { - throw "Currently this service only supports use in self hosting" -} - // set up top level koa middleware app.use(koaBody({ multipart: true })) diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js index 4a7ca6fc7c..e4d6b7d396 100644 --- a/packages/worker/src/utilities/templates.js +++ b/packages/worker/src/utilities/templates.js @@ -45,7 +45,7 @@ exports.getSettingsTemplateContext = async (purpose, code = null) => { case EmailTemplatePurpose.INVITATION: context[TemplateBindings.INVITE_CODE] = code context[TemplateBindings.REGISTRATION_URL] = checkSlashesInUrl( - `${URL}/registration/${code}` + `${URL}/invite/${code}` ) break } diff --git a/packages/worker/yarn.lock b/packages/worker/yarn.lock index 150a8685f1..ac60b6c188 100644 --- a/packages/worker/yarn.lock +++ b/packages/worker/yarn.lock @@ -287,7 +287,7 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@budibase/auth@0.0.1": +"@budibase/auth@^0.18.6": version "0.18.6" resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.18.6.tgz#d893005962afd9425f10e2ac8d1d495047d0d44e" integrity sha512-pdyqR8G240lToMe2OZNpw2YzuRwOlOT+cAfVHPMBxJJKF0VvZ0K500NoSUINEQPr4IfWpPSu6CQhq+ROf4pMXA== @@ -2505,6 +2505,20 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +fengari-interop@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/fengari-interop/-/fengari-interop-0.1.2.tgz#f7731dcdd2ff4449073fb7ac3c451a8841ce1e87" + integrity sha512-8iTvaByZVoi+lQJhHH9vC+c/Yaok9CwOqNQZN6JrVpjmWwW4dDkeblBXhnHC+BoI6eF4Cy5NKW3z6ICEjvgywQ== + +fengari@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/fengari/-/fengari-0.1.4.tgz#72416693cd9e43bd7d809d7829ddc0578b78b0bb" + integrity sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g== + dependencies: + readline-sync "^1.4.9" + sprintf-js "^1.1.1" + tmp "^0.0.33" + fetch-cookie@0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.10.1.tgz#5ea88f3d36950543c87997c27ae2aeafb4b5c4d4" @@ -3130,6 +3144,17 @@ inline-process-browser@^1.0.0: falafel "^1.0.1" through2 "^0.6.5" +ioredis-mock@^5.5.5: + version "5.5.5" + resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-5.5.5.tgz#dec9fedd238c6ab9f56c026fc366533144f8a256" + integrity sha512-7SxCAwNtDLC8IFDptqIhOC7ajp3fciVtCrXOEOkpyjPboAGRQkJbnpNPy1NYORoWi+0/iOtUPUQckSKtSQj4DA== + dependencies: + fengari "^0.1.4" + fengari-interop "^0.1.2" + lodash "^4.17.21" + minimatch "^3.0.4" + standard-as-callback "^2.1.0" + ioredis@^4.27.1: version "4.27.1" resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.1.tgz#4ef947b455a1b995baa4b0d7e2c4e4f75f746421" @@ -3146,6 +3171,22 @@ ioredis@^4.27.1: redis-parser "^3.0.0" standard-as-callback "^2.1.0" +ioredis@^4.27.2: + version "4.27.2" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.2.tgz#6a79bca05164482da796f8fa010bccefd3bf4811" + integrity sha512-7OpYymIthonkC2Jne5uGWXswdhlua1S1rWGAERaotn0hGJWTSURvxdHA9G6wNbT/qKCloCja/FHsfKXW8lpTmg== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -4403,7 +4444,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash@^4.14.0, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.7.0: +lodash@^4.14.0, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4894,6 +4935,11 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + p-cancelable@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" @@ -5521,6 +5567,11 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" +readline-sync@^1.4.9: + version "1.4.10" + resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" + integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== + recast@^0.10.1: version "0.10.43" resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.43.tgz#b95d50f6d60761a5f6252e15d80678168491ce7f" @@ -6045,6 +6096,11 @@ split2@^3.1.1: dependencies: readable-stream "^3.0.0" +sprintf-js@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -6327,6 +6383,13 @@ tiny-queue@^0.2.0: resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" integrity sha1-JaZ/LG4lOyypQZd7XvdELvl6YEY= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" From 83c16a9f141ada195623ad31d720e0e0adb8c244 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 17:49:53 +0100 Subject: [PATCH 16/19] Formatting. --- packages/server/src/automations/triggers.js | 4 +++- packages/worker/scripts/jestSetup.js | 2 +- packages/worker/src/api/routes/tests/utilities/index.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/server/src/automations/triggers.js b/packages/server/src/automations/triggers.js index f303856779..ca5e90ed14 100644 --- a/packages/server/src/automations/triggers.js +++ b/packages/server/src/automations/triggers.js @@ -1,7 +1,9 @@ const CouchDB = require("../db") const emitter = require("../events/index") const env = require("../environment") -const Queue = env.isTest() ? require("../utilities/queue/inMemoryQueue") : require("bull") +const Queue = env.isTest() + ? require("../utilities/queue/inMemoryQueue") + : require("bull") const { setQueues, BullAdapter } = require("bull-board") const { getAutomationParams } = require("../db/utils") const { coerce } = require("../utilities/rowProcessor") diff --git a/packages/worker/scripts/jestSetup.js b/packages/worker/scripts/jestSetup.js index 4e3b05b8f9..07648f693f 100644 --- a/packages/worker/scripts/jestSetup.js +++ b/packages/worker/scripts/jestSetup.js @@ -2,4 +2,4 @@ const env = require("../src/environment") env._set("NODE_ENV", "jest") env._set("JWT_SECRET", "test-jwtsecret") -env._set("LOG_LEVEL", "silent") \ No newline at end of file +env._set("LOG_LEVEL", "silent") diff --git a/packages/worker/src/api/routes/tests/utilities/index.js b/packages/worker/src/api/routes/tests/utilities/index.js index 90f95de49b..a639caef60 100644 --- a/packages/worker/src/api/routes/tests/utilities/index.js +++ b/packages/worker/src/api/routes/tests/utilities/index.js @@ -35,7 +35,7 @@ exports.emailMock = () => { const nodemailer = require("nodemailer") nodemailer.createTransport.mockReturnValue({ sendMail: sendMailMock, - verify: jest.fn() + verify: jest.fn(), }) return sendMailMock } From 6e5d985436b1e6a471619eaf6cbe9da122eb003e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 18:00:50 +0100 Subject: [PATCH 17/19] Formatting. --- packages/bbui/src/Avatar/Avatar.svelte | 2 +- .../src/pages/portal/oauth/logos/Google.svelte | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/bbui/src/Avatar/Avatar.svelte b/packages/bbui/src/Avatar/Avatar.svelte index 141b7c1b37..1b2310b61f 100644 --- a/packages/bbui/src/Avatar/Avatar.svelte +++ b/packages/bbui/src/Avatar/Avatar.svelte @@ -16,7 +16,7 @@ function getInitials(name) { let parts = name.split(" ") - return parts.map((name) => name[0]).join("") + return parts.map(name => name[0]).join("") } diff --git a/packages/builder/src/pages/portal/oauth/logos/Google.svelte b/packages/builder/src/pages/portal/oauth/logos/Google.svelte index 518a668f75..5686e50abc 100644 --- a/packages/builder/src/pages/portal/oauth/logos/Google.svelte +++ b/packages/builder/src/pages/portal/oauth/logos/Google.svelte @@ -3,32 +3,37 @@ height="18" viewBox="0 0 268 268" fill="none" - xmlns="http://www.w3.org/2000/svg"> + xmlns="http://www.w3.org/2000/svg" +> + fill="#EA4335" + /> + fill="#34A853" + /> + fill="#4A90E2" + /> + fill="#FBBC05" + /> From b3292e991a0f74cffa32b22937ce5afd20d48867 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 5 May 2021 18:13:59 +0100 Subject: [PATCH 18/19] Making the code a query string parameter for invite/reset urls. --- packages/worker/src/api/routes/tests/auth.spec.js | 2 +- packages/worker/src/api/routes/tests/users.spec.js | 2 +- packages/worker/src/utilities/templates.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/worker/src/api/routes/tests/auth.spec.js b/packages/worker/src/api/routes/tests/auth.spec.js index ea7ab829a3..df90210433 100644 --- a/packages/worker/src/api/routes/tests/auth.spec.js +++ b/packages/worker/src/api/routes/tests/auth.spec.js @@ -30,7 +30,7 @@ describe("/api/admin/auth", () => { expect(sendMailMock).toHaveBeenCalled() const emailCall = sendMailMock.mock.calls[0][0] // after this URL there should be a code - const parts = emailCall.html.split("http://localhost:10000/reset/") + const parts = emailCall.html.split("http://localhost:10000/reset?code=") code = parts[1].split("\"")[0] expect(code).toBeDefined() }) diff --git a/packages/worker/src/api/routes/tests/users.spec.js b/packages/worker/src/api/routes/tests/users.spec.js index 135d29f0f5..0a4812ea09 100644 --- a/packages/worker/src/api/routes/tests/users.spec.js +++ b/packages/worker/src/api/routes/tests/users.spec.js @@ -30,7 +30,7 @@ describe("/api/admin/users", () => { expect(sendMailMock).toHaveBeenCalled() const emailCall = sendMailMock.mock.calls[0][0] // after this URL there should be a code - const parts = emailCall.html.split("http://localhost:10000/invite/") + const parts = emailCall.html.split("http://localhost:10000/invite?code=") code = parts[1].split("\"")[0] expect(code).toBeDefined() }) diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js index f3fe881b21..e5d94859f2 100644 --- a/packages/worker/src/utilities/templates.js +++ b/packages/worker/src/utilities/templates.js @@ -35,13 +35,13 @@ exports.getSettingsTemplateContext = async (purpose, code = null) => { case EmailTemplatePurpose.PASSWORD_RECOVERY: context[TemplateBindings.RESET_CODE] = code context[TemplateBindings.RESET_URL] = checkSlashesInUrl( - `${URL}/reset/${code}` + `${URL}/reset?code=${code}` ) break case EmailTemplatePurpose.INVITATION: context[TemplateBindings.INVITE_CODE] = code context[TemplateBindings.REGISTRATION_URL] = checkSlashesInUrl( - `${URL}/invite/${code}` + `${URL}/invite?code=${code}` ) break } From 8c1f274fbbec2e782624a8a703e00bbfd0635196 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 6 May 2021 10:51:21 +0100 Subject: [PATCH 19/19] Making some changes to how configs are scoped. --- packages/auth/src/db/utils.js | 10 ++++++++-- packages/worker/src/api/controllers/admin/auth.js | 4 ++-- packages/worker/src/api/controllers/admin/configs.js | 8 ++++---- packages/worker/src/utilities/email.js | 4 ++-- packages/worker/src/utilities/templates.js | 4 ++-- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index 4bc0427976..40f5f05b70 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -123,7 +123,7 @@ const getConfigParams = ({ type, group, user }, otherProps = {}) => { * @param {Object} scopes - the type, group and userID scopes of the configuration. * @returns The most granular configuration document based on the scope. */ -const determineScopedConfig = async function (db, { type, user, group }) { +const getScopedFullConfig = async function (db, { type, user, group }) { const response = await db.allDocs( getConfigParams( { type, user, group }, @@ -160,6 +160,12 @@ const determineScopedConfig = async function (db, { type, user, group }) { return scopedConfig.doc } +async function getScopedConfig(db, params) { + const configDoc = await getScopedFullConfig(db, params) + return configDoc && configDoc.config ? configDoc.config : configDoc +} + +exports.getScopedConfig = getScopedConfig exports.generateConfigID = generateConfigID exports.getConfigParams = getConfigParams -exports.determineScopedConfig = determineScopedConfig +exports.getScopedFullConfig = getScopedFullConfig diff --git a/packages/worker/src/api/controllers/admin/auth.js b/packages/worker/src/api/controllers/admin/auth.js index 04c835a2e7..598e43e8ad 100644 --- a/packages/worker/src/api/controllers/admin/auth.js +++ b/packages/worker/src/api/controllers/admin/auth.js @@ -93,7 +93,7 @@ exports.logout = async ctx => { */ exports.googlePreAuth = async (ctx, next) => { const db = new CouchDB(GLOBAL_DB) - const config = await authPkg.db.determineScopedConfig(db, { + const config = await authPkg.db.getScopedConfig(db, { type: Configs.GOOGLE, group: ctx.query.group, }) @@ -107,7 +107,7 @@ exports.googlePreAuth = async (ctx, next) => { exports.googleAuth = async (ctx, next) => { const db = new CouchDB(GLOBAL_DB) - const config = await authPkg.db.determineScopedConfig(db, { + const config = await authPkg.db.getScopedConfig(db, { type: Configs.GOOGLE, group: ctx.query.group, }) diff --git a/packages/worker/src/api/controllers/admin/configs.js b/packages/worker/src/api/controllers/admin/configs.js index 790fbcbe35..121cfa1c0b 100644 --- a/packages/worker/src/api/controllers/admin/configs.js +++ b/packages/worker/src/api/controllers/admin/configs.js @@ -3,7 +3,7 @@ const { generateConfigID, StaticDatabases, getConfigParams, - determineScopedConfig, + getScopedFullConfig, } = require("@budibase/auth").db const { Configs } = require("../../../constants") const email = require("../../../utilities/email") @@ -16,7 +16,7 @@ exports.save = async function (ctx) { // Config does not exist yet if (!ctx.request.body._id) { - config._id = generateConfigID({ + ctx.request.body._id = generateConfigID({ type, group, user, @@ -31,7 +31,7 @@ exports.save = async function (ctx) { } try { - const response = await db.put(config) + const response = await db.put(ctx.request.body) ctx.body = { type, _id: response.id, @@ -73,7 +73,7 @@ exports.find = async function (ctx) { try { // Find the config with the most granular scope based on context - const scopedConfig = await determineScopedConfig(db, { + const scopedConfig = await getScopedFullConfig(db, { type: ctx.params.type, user: userId, group: groupId, diff --git a/packages/worker/src/utilities/email.js b/packages/worker/src/utilities/email.js index f7b9284402..e06b98a31e 100644 --- a/packages/worker/src/utilities/email.js +++ b/packages/worker/src/utilities/email.js @@ -1,6 +1,6 @@ const nodemailer = require("nodemailer") const CouchDB = require("../db") -const { StaticDatabases, determineScopedConfig } = require("@budibase/auth").db +const { StaticDatabases, getScopedConfig } = require("@budibase/auth").db const { EmailTemplatePurpose, TemplateTypes, Configs } = require("../constants") const { getTemplateByPurpose } = require("../constants/templates") const { getSettingsTemplateContext } = require("./templates") @@ -97,7 +97,7 @@ async function getSmtpConfiguration(db, groupId = null) { if (groupId) { params.group = groupId } - return determineScopedConfig(db, params) + return getScopedConfig(db, params) } /** diff --git a/packages/worker/src/utilities/templates.js b/packages/worker/src/utilities/templates.js index e5d94859f2..ea03f2727b 100644 --- a/packages/worker/src/utilities/templates.js +++ b/packages/worker/src/utilities/templates.js @@ -1,5 +1,5 @@ const CouchDB = require("../db") -const { determineScopedConfig, StaticDatabases } = require("@budibase/auth").db +const { getScopedConfig, StaticDatabases } = require("@budibase/auth").db const { Configs, TemplateBindings, @@ -15,7 +15,7 @@ const BASE_COMPANY = "Budibase" exports.getSettingsTemplateContext = async (purpose, code = null) => { const db = new CouchDB(StaticDatabases.GLOBAL.name) // TODO: use more granular settings in the future if required - const settings = await determineScopedConfig(db, { type: Configs.SETTINGS }) + const settings = await getScopedConfig(db, { type: Configs.SETTINGS }) if (!settings.platformUrl) { settings.platformUrl = LOCAL_URL }