diff --git a/auth/auth.js b/auth/auth.js new file mode 100644 index 00000000..a9b55bf3 --- /dev/null +++ b/auth/auth.js @@ -0,0 +1,113 @@ +const jwt = require("jwt-simple"); +const frappe = require("frappejs"); +const passport = require("passport"); +const passportJWT = require("passport-jwt"); +const bcrypt = require('bcrypt'); +const { DateTime } = require('luxon'); +const jwtSecret = require('crypto').randomBytes(256); + +const ExtractJwt = passportJWT.ExtractJwt; +const Strategy = passportJWT.Strategy; + +const params = { + secretOrKey: jwtSecret, + jwtFromRequest: ExtractJwt.fromHeader('token') +}; + + +module.exports = () => { + + const strategy = new Strategy(params, async function (payload, done) { + const email = payload.email; + if (!email) return done(new Error("Invalid Request"), null) + + const user = (await frappe.db.getAll({ + doctype: 'User', + filters: { name: email } + }))[0]; + + if (user) { + return done(null, { + email: user.email + }); + } else { + return done(new Error("User not found"), null); + } + }); + + passport.use(strategy); + + return { + initialize: () => { + return passport.initialize(); + }, + authenticate: () => { + return passport.authenticate("jwt", { session: false }); + }, + login: async function (req, res) { + const { email, password } = req.body; + + if (!(email && password)) { + res.status(400).send('Email and Password are required'); + return; + } + + try { + const user = await frappe.getDoc('User', email); + const match = await bcrypt.compare(password, user.password); + + if (!match) { + throw new Error('Invalid password'); + } + + const payload = { + email: user.name, + exp: timeInSecondsAfterHr(24) + }; + const token = jwt.encode(payload, jwtSecret); + res.json({ + token: token + }); + } catch(e) { + console.error(e); + res.sendStatus(401); + } + }, + signup: async function (req, res) { + const { email, password, fullName } = req.body; + + if (!(email && password && fullName)) { + res.status(400).send('Need email, password and fullName to create User'); + return; + } + + try { + const saltRounds = 10; + const hash = await bcrypt.hash(password, saltRounds); + const now = DateTime.local().toISO(); + + const user = frappe.newDoc({ + doctype: 'User', + name: email, + fullName: fullName, + password: hash, + owner: email, + modifiedBy: email, + creation: now + }); + await user.insert(); + + res.json({ + user: user.email + }); + } catch(e) { + console.error(e); + res.status(500).send('Something went wrong!'); + } + } + }; +}; + +function timeInSecondsAfterHr(hour=1) { + return Math.floor(Date.now() / 1000) + (3600 * hour) +} \ No newline at end of file diff --git a/backends/http.js b/backends/http.js index 242d434f..23a13372 100644 --- a/backends/http.js +++ b/backends/http.js @@ -7,6 +7,7 @@ module.exports = class HTTPClient extends Observable { this.server = server; this.protocol = protocol; + frappe.config.serverURL = this.getURL(); // if the backend is http, then always client! frappe.isServer = false; @@ -104,14 +105,18 @@ module.exports = class HTTPClient extends Observable { } getURL(...parts) { - return this.protocol + '://' + this.server + parts.join('/'); + return this.protocol + '://' + this.server + (parts || []).join('/'); } getHeaders() { - return { + const headers = { 'Accept': 'application/json', 'Content-Type': 'application/json' - } + }; + if (frappe.session && frappe.session.token) { + headers.token = frappe.session.token; + }; + return headers; } initTypeMap() { diff --git a/client/index.js b/client/index.js index 4e3ac28d..cfaa656a 100644 --- a/client/index.js +++ b/client/index.js @@ -7,21 +7,18 @@ const Observable = require('frappejs/utils/observable'); const { getPDF } = require('frappejs/client/pdf'); module.exports = { - async start({server, columns = 2, makeDesk = 1}) { + async start({server, columns = 2, makeDesk = false}) { window.frappe = frappe; frappe.init(); frappe.registerLibs(common); frappe.registerModels(require('frappejs/models'), 'client'); - frappe.fetch = window.fetch.bind(); - this.setCall(); frappe.db = await new HTTPClient({server: server}); - this.socket = io.connect('http://localhost:8000'); // eslint-disable-line + this.socket = io.connect(`http://${server}`); // eslint-disable-line frappe.db.bindSocketClient(this.socket); frappe.docs = new Observable(); - await frappe.getSingle('SystemSettings'); if(makeDesk) { diff --git a/index.js b/index.js index 1cd625cc..10a3804f 100644 --- a/index.js +++ b/index.js @@ -9,6 +9,7 @@ module.exports = { initConfig() { this.config = { + serverURL: '', backend: 'sqlite', port: 8000 }; @@ -58,12 +59,25 @@ module.exports = { } }, - call({method, type, args}) { - if (this.methods[method]) { - return this.methods[method](args); - } else { - throw `${method} not found`; + async call({method, args}) { + if (this.isServer) { + if (this.methods[method]) { + return await this.methods[method](args); + } else { + throw `${method} not found`; + } } + + let url = `/api/method/${method}`; + let response = await fetch(url, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify(args || {}) + }); + return await response.json(); }, addToCache(doc) { @@ -178,8 +192,40 @@ module.exports = { } }, - login(user='guest', user_key) { - this.session = {user: user}; + // only for client side + async login(email, password) { + if (email === 'Administrator') { + this.session = { + user: 'Administrator' + } + return; + } + + let response = await fetch(this.getServerURL() + '/api/login', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ email, password }) + }); + + if (response.status === 200) { + const res = await response.json(); + + this.session = { + user: email, + token: res.token + } + + return; + } + + return await response.text(); + }, + + getServerURL() { + return this.config.serverURL || ''; }, close() { diff --git a/model/document.js b/model/document.js index ad42aa8b..b00c4ac5 100644 --- a/model/document.js +++ b/model/document.js @@ -116,7 +116,10 @@ module.exports = class BaseDocument extends Observable { this.owner = frappe.session.user; this.creation = now; } - this.modifiedBy = frappe.session.user; + + if (!this.modifiedBy) { + this.modifiedBy = frappe.session.user; + } this.modified = now; } } diff --git a/models/doctype/User/User.js b/models/doctype/User/User.js index a0f9e437..d4dd5306 100644 --- a/models/doctype/User/User.js +++ b/models/doctype/User/User.js @@ -5,17 +5,24 @@ module.exports = { "isChild": 0, "keywordFields": [ "name", - "full_name" + "fullName" ], "fields": [ { "fieldname": "name", - "label": "Name", + "label": "Email", "fieldtype": "Data", "required": 1 }, { - "fieldname": "full_name", + "fieldname": "password", + "label": "Password", + "fieldtype": "Password", + "required": 1, + "hidden": 1, + }, + { + "fieldname": "fullName", "label": "Full Name", "fieldtype": "Data", "required": 1 @@ -25,6 +32,12 @@ module.exports = { "label": "Roles", "fieldtype": "Table", "childtype": "UserRole" + }, + { + "fieldname": "userId", + "label": "User ID", + "fieldtype": "Data", + "hidden": 1 } ] } \ No newline at end of file diff --git a/package.json b/package.json index 998af9ea..b2927543 100644 --- a/package.json +++ b/package.json @@ -11,11 +11,13 @@ "dependencies": { "autoprefixer": "^7.2.4", "awesomplete": "^1.1.2", + "bcrypt": "^2.0.1", "body-parser": "^1.18.2", "bootstrap": "^4.0.0", "clusterize.js": "^0.18.0", "codemirror": "^5.35.0", "commander": "^2.13.0", + "cors": "^2.8.4", "deepmerge": "^2.1.0", "eslint": "^4.19.1", "express": "^4.16.2", @@ -23,16 +25,20 @@ "frappe-datatable": "frappe/datatable", "frappejs": "../frappejs", "jquery": "^3.3.1", + "jwt-simple": "^0.5.1", "luxon": "^1.0.0", "mkdirp": "^0.5.1", "mocha": "^4.1.0", "moment": "^2.20.1", + "morgan": "^1.9.0", "mysql": "^2.15.0", "node-fetch": "^1.7.3", "node-sass": "^4.7.2", "nodemon": "^1.14.7", "nunjucks": "^3.1.0", "octicons": "^7.2.0", + "passport": "^0.4.0", + "passport-jwt": "^4.0.0", "popper.js": "^1.12.9", "precss": "^2.0.0", "puppeteer": "^1.2.0", diff --git a/server/index.js b/server/index.js index c734d9e5..e4cbccb6 100644 --- a/server/index.js +++ b/server/index.js @@ -3,6 +3,7 @@ backends.sqlite = require('frappejs/backends/sqlite'); //backends.mysql = require('frappejs/backends/mysql'); const express = require('express'); +const cors = require('cors'); const app = express(); const server = require('http').Server(app); const io = require('socket.io')(server); @@ -13,18 +14,20 @@ const common = require('frappejs/common'); const bodyParser = require('body-parser'); const fs = require('fs'); const { setupExpressRoute: setRouteForPDF } = require('frappejs/server/pdf'); +const auth = require('./../auth/auth')(); +const morgan = require('morgan') require.extensions['.html'] = function (module, filename) { module.exports = fs.readFileSync(filename, 'utf8'); }; module.exports = { - async start({backend, connectionParams, models, staticPath = './'}) { - + async start({backend, connectionParams, models, staticPath = './', authConfig=null}) { await this.init(); if (models) { frappe.registerModels(models, 'server'); + frappe.models.User.documentClass = require('frappejs/models/doctype/User/UserServer.js'); } // database @@ -34,6 +37,15 @@ module.exports = { app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static(staticPath)); + app.use(morgan('tiny')); + + if (connectionParams.enableCORS) { + app.use(cors()); + } + + if(authConfig) { + this.setupAuthentication(app, authConfig); + } // socketio io.on('connection', function (socket) { @@ -42,8 +54,12 @@ module.exports = { // routes restAPI.setup(app); + frappe.config.port = connectionParams.port || 8000; + // listen - server.listen(frappe.config.port); + server.listen(frappe.config.port, () => { + console.log(`FrappeJS server running on http://localhost:${frappe.config.port}`) + }); frappe.app = app; frappe.server = server; @@ -57,7 +73,7 @@ module.exports = { frappe.registerModels(frappeModels, 'server'); frappe.registerLibs(common); - await frappe.login(); + await frappe.login('Administrator'); }, async initDb({backend, connectionParams}) { @@ -65,4 +81,11 @@ module.exports = { await frappe.db.connect(); await frappe.db.migrate(); }, + + setupAuthentication(app, authConfig) { + app.post("/api/signup", auth.signup); + app.post("/api/login", auth.login); + app.use(auth.initialize(authConfig)); + app.all("/api/resource/*", auth.authenticate()); + } } diff --git a/server/pdf.js b/server/pdf.js index 044c15ef..319c7f68 100644 --- a/server/pdf.js +++ b/server/pdf.js @@ -2,7 +2,6 @@ const frappe = require('frappejs'); const puppeteer = require('puppeteer'); const fs = require('fs'); const path = require('path'); -const { shell } = require('electron'); const { getTmpDir } = require('frappejs/server/utils'); const { getHTML } = require('frappejs/common/print'); const { getRandomString } = require('frappejs/utils'); @@ -19,6 +18,7 @@ async function makePDF(html, filepath) { } async function getPDFForElectron(doctype, name) { + const { shell } = require('electron'); const html = await getHTML(doctype, name); const filepath = path.join(frappe.electronSettings.directory, name + '.pdf'); await makePDF(html, filepath); diff --git a/yarn.lock b/yarn.lock index 30934deb..f26156f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -274,12 +274,29 @@ base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" +base64url@2.0.0, base64url@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb" + +basic-auth@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.0.tgz#015db3f353e02e56377755f962742e8981e7bbba" + dependencies: + safe-buffer "5.1.1" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" dependencies: tweetnacl "^0.14.3" +bcrypt@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-2.0.1.tgz#229c5afe09379789f918efe86e5e5b682e509f85" + dependencies: + nan "2.10.0" + node-pre-gyp "0.9.1" + better-assert@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" @@ -390,6 +407,10 @@ browserslist@^2.11.1: caniuse-lite "^1.0.30000792" electron-to-chromium "^1.3.30" +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" + builtin-modules@^1.0.0, builtin-modules@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -508,6 +529,10 @@ chokidar@^1.6.0, chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -707,6 +732,13 @@ core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +cors@^2.8.4: + version "2.8.4" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" + dependencies: + object-assign "^4" + vary "^1" + cosmiconfig@^2.1.0, cosmiconfig@^2.1.1: version "2.2.2" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.2.2.tgz#6173cebd56fac042c1f4390edf7af6c07c7cb892" @@ -848,7 +880,7 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -debug@2.6.9, debug@^2.2.0, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6: +debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -942,6 +974,13 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" +ecdsa-sig-formatter@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz#4bc926274ec3b5abb5016e7e1d60921ac262b2a1" + dependencies: + base64url "^2.0.0" + safe-buffer "^5.0.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1396,6 +1435,7 @@ frappejs@../frappejs: clusterize.js "^0.18.0" codemirror "^5.35.0" commander "^2.13.0" + cors "^2.8.4" deepmerge "^2.1.0" eslint "^4.19.1" express "^4.16.2" @@ -1403,15 +1443,20 @@ frappejs@../frappejs: frappe-datatable frappe/datatable frappejs "../frappejs" jquery "^3.3.1" + jwt-simple "^0.5.1" + luxon "^1.0.0" mkdirp "^0.5.1" mocha "^4.1.0" moment "^2.20.1" + morgan "^1.9.0" mysql "^2.15.0" node-fetch "^1.7.3" node-sass "^4.7.2" nodemon "^1.14.7" nunjucks "^3.1.0" octicons "^7.2.0" + passport "^0.4.0" + passport-jwt "^4.0.0" popper.js "^1.12.9" precss "^2.0.0" puppeteer "^1.2.0" @@ -1455,6 +1500,12 @@ fs-extra@^5.0.0: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1792,6 +1843,12 @@ iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" +iconv-lite@^0.4.4: + version "0.4.21" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" + dependencies: + safer-buffer "^2.1.0" + icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -1800,6 +1857,12 @@ ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + ignore@^3.3.3: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" @@ -2148,6 +2211,21 @@ jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" +jsonwebtoken@^8.2.0: + version "8.2.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.2.1.tgz#333ee39aa8f238f32fa41693e7a2fb7e42f82b31" + dependencies: + jws "^3.1.4" + 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" + xtend "^4.0.1" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -2157,6 +2235,27 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" +jwa@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.1.5.tgz#a0552ce0220742cd52e153774a32905c30e756e5" + dependencies: + base64url "2.0.0" + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.9" + safe-buffer "^5.0.1" + +jws@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.1.4.tgz#f9e8b9338e8a847277d6444b1464f61880e050a2" + dependencies: + base64url "^2.0.0" + jwa "^1.1.4" + safe-buffer "^5.0.1" + +jwt-simple@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/jwt-simple/-/jwt-simple-0.5.1.tgz#79ea01891b61de6b68e13e67c0b4b5bda937b294" + kind-of@^3.0.2: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -2228,6 +2327,30 @@ lodash.clonedeep@^4.3.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -2236,6 +2359,10 @@ lodash.mergewith@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -2389,6 +2516,19 @@ minimist@^1.1.3, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +minipass@^2.2.1, minipass@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.4.tgz#03c824d84551ec38a8d1bb5bc350a5a30a354a40" + dependencies: + safe-buffer "^5.1.1" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + mkdirp@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" @@ -2420,10 +2560,24 @@ moment@^2.20.1: version "2.20.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.20.1.tgz#d6eb1a46cbcc14a2b2f9434112c1ff8907f313fd" +morgan@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.0.tgz#d01fa6c65859b76fcf31b3cb53a3821a311d8051" + dependencies: + basic-auth "~2.0.0" + debug "2.6.9" + depd "~1.1.1" + on-finished "~2.3.0" + on-headers "~1.0.1" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -2437,6 +2591,10 @@ mysql@^2.15.0: safe-buffer "5.1.1" sqlstring "2.3.0" +nan@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + nan@^2.3.0, nan@^2.3.2: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" @@ -2449,6 +2607,14 @@ natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" +needle@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -2484,6 +2650,21 @@ node-gyp@^3.3.1: tar "^2.0.0" which "1" +node-pre-gyp@0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0" + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.0" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.1.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + node-pre-gyp@^0.6.39, node-pre-gyp@~0.6.38: version "0.6.39" resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" @@ -2584,6 +2765,17 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -2622,7 +2814,7 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -2649,6 +2841,10 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-headers@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" + once@^1.3.0, once@^1.3.3: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2767,6 +2963,24 @@ parseurl@~1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" +passport-jwt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +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" + +passport@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811" + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -2811,6 +3025,10 @@ pause-stream@0.0.11: dependencies: through "~2.3" +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -3782,6 +4000,10 @@ safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, s version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + sass-graph@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" @@ -3791,7 +4013,7 @@ sass-graph@^2.2.4: scss-tokenizer "^0.2.3" yargs "^7.0.0" -sax@~1.2.1: +sax@^1.2.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -4178,6 +4400,18 @@ tar@^2.0.0, tar@^2.2.1: fstream "^1.0.2" inherits "2" +tar@^4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.1.tgz#b25d5a8470c976fd7a9a8a350f42c59e9fa81749" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.2.4" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.1" + yallist "^3.0.2" + tcomb@^2.5.1: version "2.7.0" resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-2.7.0.tgz#10d62958041669a5d53567b9a4ee8cde22b1c2b0" @@ -4361,7 +4595,7 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -4466,7 +4700,7 @@ xmlhttprequest-ssl@~1.5.4: version "1.5.5" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" -xtend@^4.0.0: +xtend@^4.0.0, xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" @@ -4478,6 +4712,10 @@ yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"