From d9a2d33913ca27e4122b9f7b5dd7dae2d90b4fa9 Mon Sep 17 00:00:00 2001 From: Mike Fitzpatrick Date: Thu, 4 Jul 2019 16:19:30 -0400 Subject: [PATCH] - Initial commit... A DB, some routes, and basic authentication routines... --- config.js | 30 + index.js | 66 ++ lib/validateType.js | 11 + models/bid.js | 36 + models/common/address.js | 44 ++ models/common/email.js | 30 + models/common/phone.js | 29 + models/constants.js | 16 + models/event.js | 147 ++++ models/install.js | 49 ++ models/item.js | 136 ++++ models/organization.js | 63 ++ models/sale.js | 44 ++ models/user.js | 284 ++++++++ package.json | 28 + routes/auth.js | 92 +++ routes/bids.js | 110 +++ routes/events.js | 110 +++ routes/index.js | 9 + routes/installs.js | 110 +++ routes/items.js | 110 +++ routes/sales.js | 116 +++ routes/signup.js | 42 ++ routes/users.js | 169 +++++ strategies/auth/apple.js | 5 + strategies/auth/facebook.js | 46 ++ strategies/auth/google.js | 40 ++ strategies/auth/index.js | 82 +++ strategies/auth/jwt.js | 30 + strategies/auth/local.js | 24 + strategies/selects/user.js | 10 + yarn.lock | 1347 +++++++++++++++++++++++++++++++++++ 32 files changed, 3465 insertions(+) create mode 100644 config.js create mode 100644 index.js create mode 100644 lib/validateType.js create mode 100644 models/bid.js create mode 100644 models/common/address.js create mode 100644 models/common/email.js create mode 100644 models/common/phone.js create mode 100644 models/constants.js create mode 100644 models/event.js create mode 100644 models/install.js create mode 100644 models/item.js create mode 100644 models/organization.js create mode 100644 models/sale.js create mode 100644 models/user.js create mode 100644 package.json create mode 100644 routes/auth.js create mode 100644 routes/bids.js create mode 100644 routes/events.js create mode 100644 routes/index.js create mode 100644 routes/installs.js create mode 100644 routes/items.js create mode 100644 routes/sales.js create mode 100644 routes/signup.js create mode 100644 routes/users.js create mode 100644 strategies/auth/apple.js create mode 100644 strategies/auth/facebook.js create mode 100644 strategies/auth/google.js create mode 100644 strategies/auth/index.js create mode 100644 strategies/auth/jwt.js create mode 100644 strategies/auth/local.js create mode 100644 strategies/selects/user.js create mode 100644 yarn.lock diff --git a/config.js b/config.js new file mode 100644 index 0000000..d84b37a --- /dev/null +++ b/config.js @@ -0,0 +1,30 @@ +module.exports = { + name: 'wEvent API', + env: process.env.NODE_ENV || 'development', + port: process.env.PORT || 3001, + base_url: process.env.BASE_URL || 'http://localhost:3000', + db: { + uri: process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/wEvent-dev', + }, + version: '0.0.1', + assetStoreUrl: 'https://www.google.com/', + services: { + apple: {}, + facebook: { + appId: '2359355590971136', + appSecret: 'a5703f7d0af8e694aec5bd4175a85d6b', + }, + google: { + appId: '442412638360-p0idffou0qlpgor7agideudb1dh10mpf.apps.googleusercontent.com', + appSecret: 'a7fmS7Wc9Ssycr21WXdQ4TYl', + }, + }, + security: { + jwt: { + audience: 'wEvents.io', + daysValid: 365, + issuer: 'patrons.wEvents.io', + secret: 'Th!sIs a d3v3lopm3nt server $#cr¢T.', + }, + }, +}; diff --git a/index.js b/index.js new file mode 100644 index 0000000..a94adb0 --- /dev/null +++ b/index.js @@ -0,0 +1,66 @@ +const jwt = require('jsonwebtoken'); +const mongoose = require('mongoose'); +const passport = require('passport'); +const restify = require('restify'); + +const config = require('./config'); + +const auth = require('./strategies/auth')(passport); + +const validateJsonData = require('./lib/validateType.js'); + +/** + * Initialize Server + */ +const server = restify.createServer({ + name: config.name, + version: config.version, +}); + +/** + * Middleware + */ +server.use(restify.plugins.acceptParser(server.acceptable)); +server.use(restify.plugins.bodyParser({ + hash: 'sha1', + mapParams: true, + multiples: true, +})); +server.use(restify.plugins.fullResponse()); +server.use(restify.plugins.gzipResponse()); +server.use(restify.plugins.queryParser({ mapParams: true })); +server.use(auth.passport.initialize()); + +/** + * Error checking + */ +server.post('*', validateJsonData); +server.put('*', validateJsonData); + +/** + * Start Server, Connect to DB & Require Routes + */ +server.listen(config.port, () => { + // establish connection to mongodb + mongoose.Promise = global.Promise; + mongoose.connect( + config.db.uri, + { + useCreateIndex: true, + useFindAndModify: false, + useNewUrlParser: true, + }, + ); + + const db = mongoose.connection; + + db.on('error', (err) => { + console.error(err); + process.exit(1); + }); + + db.once('open', () => { + require('./routes')(server, auth); + console.log(`Server is listening on port ${config.port}`); + }); +}); diff --git a/lib/validateType.js b/lib/validateType.js new file mode 100644 index 0000000..a0dc560 --- /dev/null +++ b/lib/validateType.js @@ -0,0 +1,11 @@ +const validateJsonData = (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + next(); +}; + +module.exports = validateJsonData; diff --git a/models/bid.js b/models/bid.js new file mode 100644 index 0000000..9a500e4 --- /dev/null +++ b/models/bid.js @@ -0,0 +1,36 @@ +const mongoose = require('mongoose'); +const timestamps = require('mongoose-timestamp'); + +const BidSchema = new mongoose.Schema( + { + itemId: { + type: String, + required: true, + trim: true, + }, + bidderId: { + type: String, + required: true, + trim: true, + }, + bidAmount: { + type: Number, + required: true, + }, + maxAmount: { + type: Number, + required: true, + }, + time: { + type: Number, + required: true, + }, + }, + + { minimize: false }, +); + +BidSchema.plugin(timestamps); + +const Bid = mongoose.model('Bid', BidSchema); +module.exports = Bid; diff --git a/models/common/address.js b/models/common/address.js new file mode 100644 index 0000000..25e696c --- /dev/null +++ b/models/common/address.js @@ -0,0 +1,44 @@ +const mongoose = require('mongoose'); +const mongooseStringQuery = require('mongoose-string-query'); +const mongooseTimestamps = require('mongoose-timestamp'); + +const AddressSchema = new mongoose.Schema( + { + address1: { + type: String, + required: true, + trim: true, + }, + address2: { + type: String, + trim: true, + }, + locality: { + type: String, + required: true, + trim: true, + }, + state: { + type: String, + required: true, + trim: true, + }, + postalCode: { + type: String, + required: true, + trim: true, + }, + label: { + type: String, + required: true, + enum: [ 'billing', 'shipping' ], + }, + }, + + { minimize: false }, +); + +AddressSchema.plugin(mongooseStringQuery); +AddressSchema.plugin(mongooseTimestamps); + +module.exports = AddressSchema; diff --git a/models/common/email.js b/models/common/email.js new file mode 100644 index 0000000..f4db21e --- /dev/null +++ b/models/common/email.js @@ -0,0 +1,30 @@ +const mongoose = require('mongoose'); +const mongooseStringQuery = require('mongoose-string-query'); +const mongooseTimestamps = require('mongoose-timestamp'); + +const EmailSchema = new mongoose.Schema( + { + user: { + type: String, + required: true, + }, + domain: { + type: String, + required: true, + }, + label: { + type: String, + }, + }, + + { minimize: false }, +); + +EmailSchema.virtual('address').get(function() { + return this.user + '@' + this.domain; +}); + +EmailSchema.plugin(mongooseStringQuery); +EmailSchema.plugin(mongooseTimestamps); + +module.exports = EmailSchema; diff --git a/models/common/phone.js b/models/common/phone.js new file mode 100644 index 0000000..22d4147 --- /dev/null +++ b/models/common/phone.js @@ -0,0 +1,29 @@ +const mongoose = require('mongoose'); +const mongooseStringQuery = require('mongoose-string-query'); +const mongooseTimestamps = require('mongoose-timestamp'); + +const PhoneSchema = new mongoose.Schema( + { + countryCode: { + type: String, + required: true, + default: '1', + }, + number: { + type: String, + required: true, + }, + label: { + type: String, + required: true, + enum: [ 'home', 'mobile' ], + }, + }, + + { minimize: false }, +); + +PhoneSchema.plugin(mongooseStringQuery); +PhoneSchema.plugin(mongooseTimestamps); + +module.exports = PhoneSchema; diff --git a/models/constants.js b/models/constants.js new file mode 100644 index 0000000..cccb8ce --- /dev/null +++ b/models/constants.js @@ -0,0 +1,16 @@ +module.exports = { + ITEM_TYPES: { + type: String, + required: true, + enum: [ + 'auction', + 'donation', + 'event', + 'raffle', + 'membership', + 'popup', + 'ticket', + ], + default: 'auction', + }, +}; diff --git a/models/event.js b/models/event.js new file mode 100644 index 0000000..99b49d4 --- /dev/null +++ b/models/event.js @@ -0,0 +1,147 @@ +const config = require('../config.js'); +const mongoose = require('mongoose'); +const timestamps = require('mongoose-timestamp'); + +const PostSchema = new mongoose.Schema( + { + author: String, + + title: { + type: String, + required: true, + }, + content: { + type: String, + required: true, + }, + + isPublic: { + type: Boolean, + default: true, + }, + + scheduledPost: String, + + sendNotification: { + type: Boolean, + default: false, + }, + notificationContent: String, + notificationLinksTo: String, + } +); + +const TicketSchema = new mongoose.Schema( + { + name: { + type: String, + required: true, + trim: true, + }, + price: { + type: Number, + default: 0, + }, + + capacity: { + type: Number, + required: true, + }, + available: { + type: Number, + required: true, + }, + + itemId: { + type: String, + required: true, + trim: true, + }, + + startSale: { + type: String, + required: true, + trim: true, + }, + endSale: { + type: String, + required: true, + trim: true, + }, + }, + + { minimize: false }, +); + +const EventSchema = new mongoose.Schema( + { + eventDate: { + type: String, + required: true, + trim: true, + }, + startTime: { + type: String, + required: true, + trim: true, + }, + endTime: { + type: Number, + required: true, + }, + + title: { + type: String, + required: true, + trim: true, + }, + tagline: { + type: String, + required: true, + trim: true, + }, + description: { + type: String, + required: true, + trim: true, + }, + + isTicketed: { + type: Boolean, + default: false, + }, + ticketClasses: [ TicketSchema ], + + showFrom: { + type: String, + required: true, + trim: true, + }, + showUntil: { + type: String, + required: true, + trim: true, + }, + + requireLoginToSeeAuction: { + type: Boolean, + default: false, + }, + + images: [{ + url: String, + }], + url: String, + + posts: [ PostSchema ], + }, + + { minimize: false }, +); + +EventSchema.plugin(timestamps); + +EventSchema.path('images').get(v => `${config.assetStoreUrl}${v.url}`) + +const Event = mongoose.model('Event', EventSchema); +module.exports = Event; diff --git a/models/install.js b/models/install.js new file mode 100644 index 0000000..4f15bf1 --- /dev/null +++ b/models/install.js @@ -0,0 +1,49 @@ +const mongoose = require('mongoose'); +const timestamps = require('mongoose-timestamp'); + +const InstallSchema = new mongoose.Schema( + { + timeZone: { + type: String, + required: true, + trim: true, + }, + deviceType: { + type: String, + required: true, + trim: true, + enum: [ 'android', 'ios', 'web' ], + }, + badge: { + type: Number, + default: 0, + }, + installationId: { + type: String, + required: true, + unique: true, + }, + email: { + type: String, + required: true, + trim: true, + }, + appIdentifier: { + type: String, + required: true, + trim: true, + }, + localeIdentifier: { + type: String, + required: true, + trim: true, + }, + }, + + { minimize: false }, +); + +InstallSchema.plugin(timestamps); + +const Install = mongoose.model('Install', InstallSchema); +module.exports = Install; diff --git a/models/item.js b/models/item.js new file mode 100644 index 0000000..bf0f611 --- /dev/null +++ b/models/item.js @@ -0,0 +1,136 @@ +const { ITEM_TYPES } = require('./constants.js'); + +const config = require('../config.js'); +const mongoose = require('mongoose'); +const mongooseStringQuery = require('mongoose-string-query'); +const timestamps = require('mongoose-timestamp'); + +const ItemSchema = new mongoose.Schema( + { + eventId: { + type: String, + required: true, + trim: true, + }, + + title: { + type: String, + required: true, + trim: true, + }, + subtitle: { + type: String, + trim: true, + }, + donor: { + type: String, + trim: true, + }, + description: { + type: String, + required: true, + trim: true, + }, + images: [{ + url: String + }], + + type: ITEM_TYPES, + + quantityAvailable: { + type: Number, + required: true, + default: 1, + }, + soldCount: { + type: Number, + default: 0, + }, + + currentPrice: { + required: true, + type: Number, + }, + startingPrice: { + type: Number, + }, + reservePrice: { + type: Number, + }, + estimatedValue: { + type: Number, + }, + + currentWinner: { + type: String, + trim: true, + }, + bidders: [{ + name: String, + }], + bidCount: { + type: Number, + default: 0, + }, + bidIncrement: { + type: Number, + default: 10, + }, + + catalogNumber: { + type: Number, + }, + + start: { + type: Number, + required: true, + }, + end: { + type: Number, + required: true, + }, + hideBeforeStart: { + type: Boolean, + required: true, + default: false, + }, + hideAfterEnd: { + type: Boolean, + required: true, + default: false, + }, + notifyOnAvailable: { + type: Boolean, + required: true, + default: false, + }, + + isShippable: { + type: Boolean, + default: false, + }, + shippingCost: Number, + + organizationTake: { + type: Number, + required: true, + default: 1, + }, + }, + + { minimize: false }, +); + +ItemSchema.plugin(timestamps); + +ItemSchema.path('images').get(v => `${config.assetStoreUrl}${v.url}`); + +/** + * STATICS + */ +ItemSchema.statics.addBatch = function(data = [], callback = () => {}) { + +}; + +const Item = mongoose.model('Item', ItemSchema); +module.exports = Item; diff --git a/models/organization.js b/models/organization.js new file mode 100644 index 0000000..2bb807d --- /dev/null +++ b/models/organization.js @@ -0,0 +1,63 @@ +const mongoose = require('mongoose'); +const timestamps = require('mongoose-timestamp'); + +const PeopleSchema = new mongoose.Schema( + { + name: { + type: String, + required: true, + trim: true, + }, + title: { + type: String, + required: true, + trim: true, + }, + + bio: { + type: String, + trim: true, + }, + + address: AddressSchema, + email: EmailSchema, + phone: PhoneSchema, + }, + + { minimize: false }, +); + +const OrganizationSchema = new mongoose.Schema( + { + name: { + type: String, + required: true, + trim: true, + }, + + url: String, + address: [ AddressSchema ], + telephone: [ TelephoneSchema ], + + about: { + type: String, + required: true, + trim: true, + }, + + team: [ PeopleSchema ], + board: [ PeopleSchema ], + + privacyUrl: String, + tosUrl: String, + + copyright: String, + }, + + { minimize: false }, +); + +OrganizationSchema.plugin(timestamps); + +const Organization = mongoose.model('Organization', OrganizationSchema); +module.exports = Organization; diff --git a/models/sale.js b/models/sale.js new file mode 100644 index 0000000..4de664a --- /dev/null +++ b/models/sale.js @@ -0,0 +1,44 @@ +const { ITEM_TYPES } = require('./constants.js'); + +const mongoose = require('mongoose'); +const timestamps = require('mongoose-timestamp'); + +const SaleSchema = new mongoose.Schema( + { + itemId: { + type: String, + required: true, + trim: true, + }, + userId: { + type: String, + required: true, + trim: true, + }, + amount: { + type: Number, + required: true, + }, + + itemType: ITEM_TYPES, + paymentToken: String, + + isPaid: { + type: Boolean, + required: true, + default: false, + }, + isPickedUp: { + type: Boolean, + required: true, + default: false, + }, + }, + + { minimize: false }, +); + +SaleSchema.plugin(timestamps); + +const Sale = mongoose.model('Sale', SaleSchema); +module.exports = Sale; diff --git a/models/user.js b/models/user.js new file mode 100644 index 0000000..ee28dd7 --- /dev/null +++ b/models/user.js @@ -0,0 +1,284 @@ +const crypto = require('crypto'); +const jwt = require('jsonwebtoken'); +const mongoose = require('mongoose'); +const timestamps = require('mongoose-timestamp'); + +const config = require('../config.js'); + +const AddressSchema = require('./common/address.js'); +const PhoneSchema = require('./common/phone.js'); + +const LoginSchema = new mongoose.Schema( + { + method: { + type: String, + required: true, + enum: [ 'apple', 'facebook', 'google', 'local' ], + }, + userId: { + type: String, + trim: true, + }, + accessToken: { + type: String, + required: true, + trim: true, + }, + secret: { + type: String, + trim: true, + }, + profile: {}, + }, + + { minimize: false }, +); + +const UserSchema = new mongoose.Schema( + { + nomDeBid: { + type: String, + trim: true, + unique: true, + }, + firstName: { + type: String, + required: true, + trim: true, + }, + lastName: { + type: String, + required: true, + trim: true, + }, + email: { + type: String, + required: true, + unique: true, + }, + + avatar: { + type: String, + trim: true, + }, + + address: [ AddressSchema ], + phone: [ PhoneSchema ], + + credentials: [ LoginSchema ], + + organizationIdentifier: { + type: String, + trim: true, + }, + paymentToken: { + type: String, + trim: true, + }, + + isVerified: { + type: Boolean, + default: false, + }, + isAllowedToBid: { + type: Boolean, + default: false, + }, + isOrganizationEmployee: { + type: Boolean, + default: false, + }, + }, + + { minimize: false }, +); + +/** + * PLUGINS + */ +UserSchema.plugin(timestamps); + + +/** + * METHODS + */ +UserSchema.methods.authenticate = function (username, password) { + const user = this.model('User').findOne({ email: username }); + const strategy = user ? user.getAuthStrategy('local') : null; + + if (strategy) { + let hash = crypto.pbkdf2Sync(password, strategy.get('secret'), 10000, 512, 'sha512').toString('hex') + return strategy.get('accessToken') === hash; + } + + return false; +}; + +UserSchema.methods.generateJWT = function (props = {}) { + const { exp, iss } = props; + const today = new Date(); + + let expirationDate = exp; + if (!expirationDate) { + expirationDate = new Date(today); + expirationDate.setDate(today.getDate() + config.security.jwt.daysValid); + } + + return jwt.sign({ + sub: this._id, + iss: iss || config.security.jwt.issuer, + aud: config.security.jwt.audience, + iat: parseInt(today.getTime()), + exp: parseInt(expirationDate.getTime() / 1000, 10), + }, config.security.jwt.secret); +} + +UserSchema.methods.getAuthStrategy = function (method = 'local') { + return this.credentials.filter((strategy) => { + return strategy.method === method; + }).pop() || false; +}; + +UserSchema.methods.getNomDeBid = function () { + return this.nomDeBid || `${this.firstName} ${this.lastName.charAt(0)}`; +}; + +UserSchema.methods.isEventManager = function () { + return this.isOrganizationEmployee || false; +}; + +UserSchema.methods.isRegistrationVerified = function () { + return this.isVerified || false; +}; + +UserSchema.methods.setPassword = function (password, callback = () => {}) { + const hasLocalStrategy = !!this.credentials.length && + !!this.credentials.filter(strategy => strategy.method === 'local').length; + + const salt = crypto.randomBytes(16).toString('hex'); + const accessToken = crypto.pbkdf2Sync(password, salt, 10000, 512, 'sha512').toString('hex'); + + const strategy = { + accessToken, + method: 'local', + secret: salt, + }; + + if (hasLocalStrategy) { + this.model('User').findOneAndUpdate( + { _id: this._id, 'credentials.method': 'local' }, + { $set: { 'credentials.$': strategy } }, + { upsert: true }, + callback, + ); + } + + if (!hasLocalStrategy) { + this.credentials.push(strategy); + this.save(callback); + } +}; + +UserSchema.methods.toAuthJSON = function () { + const hasNomDeBid = !!this.nomDeBid; + const nomDeBid = this.getNomDeBid(); + + return { + email: this.email, + token: this.generateJWT(), + user: { + nomDeBid: nomDeBid, + email: this.email, + firstName: this.firstName, + lastName: this.lastName, + avatar: this.avatar, + isAllowedToBid: this.isAllowedToBid, + isOrganizationEmployee: this.isOrganizationEmployee, + generatedNomDeBid: !hasNomDeBid, + }, + }; +}; + +UserSchema.methods.validatePassword = function (password) { + const strategy = this.getAuthStrategy('local'); + + if (strategy) { + let hash = crypto.pbkdf2Sync(password, strategy.secret, 10000, 512, 'sha512').toString('hex'); + return strategy.accessToken === hash; + } + + return false; +}; + + +/** + * STATICS + */ +UserSchema.statics.findOrCreate = function (filter = {}, profile = {}, callback = () => {}) { + const self = this; + + this.findOne(filter, function(err,result) { + if (err) { + callback(err, null); + } + + if (!result) { + self.create(profile, (err, result) => callback(err, result)); + }else{ + callback(err, result); + } + }); +}; + +UserSchema.statics.findOneAndUpdateOrCreate = function ( + filter = {}, + strategy = {}, + profile = {}, + callback = () => {}, +) { + const self = this; + + this.findOne(filter, function(err, result) { + if (err) { + callback(err, null); + } + + if (!result) { + self.create( + { + strategy: [ strategy ], + ...profile + }, + (err, result) => callback(err, result), + ); + } else { + const hasStrategy = !!result.credentials.length && + !!result.credentials.filter(auth => auth.method === strategy.method).length; + + if (hasStrategy) { + self.model('User').findOneAndUpdate( + { _id: result._id, 'credentials.method': strategy.method }, + { $set: { 'credentials.$': strategy } }, + { upsert: true }, + callback, + ); + } else { + result.credentials.push(strategy); + result.save(callback); + } + } + }); +}; + + +/** + * PATH OPERATIONS + */ +UserSchema.path('avatar').get(v => `${config.assetStoreUrl}${v}`); + +/** + * Export + */ +const User = mongoose.model('User', UserSchema); + +module.exports = User; diff --git a/package.json b/package.json new file mode 100644 index 0000000..9675eab --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "api", + "version": "0.0.1", + "description": "The wEvent API and DB server", + "main": "index.js", + "author": "mike@fitz.guru", + "license": "MIT", + "notes": "b'VJ!4a{L(8T(CvG8BKGj).]", + "dependencies": { + "api-query-params": "^4.13.0", + "crypto": "^1.0.1", + "jsonwebtoken": "^8.5.1", + "mongoose": "^5.6.0", + "mongoose-find-or-create": "^1.3.1", + "mongoose-string-query": "^0.2.7", + "mongoose-timestamp": "^0.6.0", + "passport": "^0.4.0", + "passport-facebook": "^3.0.0", + "passport-google-oauth": "^2.0.0", + "passport-http-bearer": "^1.0.1", + "passport-jwt": "^4.0.0", + "passport-local": "^1.0.0", + "restify": "^8.3.3", + "restify-errors": "^8.0.0", + "restify-jwt-community": "^1.0.13", + "restify-plugins": "^1.6.0" + } +} diff --git a/routes/auth.js b/routes/auth.js new file mode 100644 index 0000000..ac126d5 --- /dev/null +++ b/routes/auth.js @@ -0,0 +1,92 @@ +const errors = require('restify-errors'); + +const config = require('../config'); + +const handlePassportResponse = (req, res, next) => (err, passportUser, info) => { + if (err) { + return next(err); + } + + const isVerifiedUser = passportUser.isRegistrationVerified(); + if (passportUser && isVerifiedUser) { + const user = passportUser; + user.token = passportUser.generateJWT(); + return res.send({ ...user.toAuthJSON() }); + } else if (passportUser && !isVerifiedUser){ + return res.send({ + registrationSuccess: true, + nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.' + }); + } + + return res.send(400, info); +}; + +module.exports = function (server, auth) { + const { passport } = auth; + + /* Local Auth */ + server.post('/auth', (req, res, next) => { + const { body: { username = null, password = null } = {} } = req; + + if (!username || !password) { + let errors = {}; + + if (!username) { + errors.username = 'is required'; + } + + if (!password) { + errors.password = 'is required'; + } + + return res.send(422, { errors }); + } + + const callback = handlePassportResponse(req, res, next); + return passport.authenticate('local', { session: false }, callback)(req, res, next); + }); + + /** + * SERVICES + */ + + /* Google */ + server.get( + '/auth/google', + passport.authenticate('google', { scope: 'profile email', session: false }), + ); + + server.get( + '/auth/google/callback', + (req, res, next) => { + const callback = handlePassportResponse(req, res, next); + return passport.authenticate( + 'google', + { failureRedirect: '/login' }, + callback, + )(req, res, next); + }, + ); + + /* Facebook */ + server.get( + '/auth/facebook', + passport.authenticate('facebook', { + scope: ['email', 'public_profile'], + session: false, + }), + ); + + server.get( + '/auth/facebook/callback', + (req, res, next) => { + const callback = handlePassportResponse(req, res, next); + return passport.authenticate( + 'facebook', + { failureRedirect: '/login' }, + callback, + )(req, res, next); + } + ); +}; diff --git a/routes/bids.js b/routes/bids.js new file mode 100644 index 0000000..eb1fef7 --- /dev/null +++ b/routes/bids.js @@ -0,0 +1,110 @@ +const errors = require('restify-errors'); + +const Bid = require('../models/bid'); + +module.exports = function(server) { + server.post('/bids', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + let bid = new Bid(data); + bid.save(function(err) { + if (err) { + console.error(err); + return next(new errors.InternalError(err.message)); + next(); + } + + res.send(201); + next(); + }); + }); + + server.get('/bids', (req, res, next) => { + Bid.apiQuery(req.params, function(err, docs) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(docs); + next(); + }); + }); + + server.get('/bids/:bid_id', (req, res, next) => { + Bid.findOne({ _id: req.params.bid_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(doc); + next(); + }); + }); + + server.put('/bids/:bid_id', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + if (!data._id) { + data = Object.assign({}, data, { _id: req.params.bid_id }); + } + + Bid.findOne({ _id: req.params.bid_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } else if (!doc) { + return next( + new errors.ResourceNotFoundError( + 'The resource you requested could not be found.', + ), + ); + } + + Bid.update({ _id: data._id }, data, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.del('/bids/:bid_id', (req, res, next) => { + Bid.deleteOne({ _id: req.params.bid_id }, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(204); + next(); + }); + }); +}; diff --git a/routes/events.js b/routes/events.js new file mode 100644 index 0000000..eab7f05 --- /dev/null +++ b/routes/events.js @@ -0,0 +1,110 @@ +const errors = require('restify-errors'); + +const Event = require('../models/event'); + +module.exports = function(server) { + server.post('/events', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + let event = new Event(data); + event.save(function(err) { + if (err) { + console.error(err); + return next(new errors.InternalError(err.message)); + next(); + } + + res.send(201); + next(); + }); + }); + + server.get('/events', (req, res, next) => { + Event.apiQuery(req.params, function(err, docs) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(docs); + next(); + }); + }); + + server.get('/events/:event_id', (req, res, next) => { + Event.findOne({ _id: req.params.event_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(doc); + next(); + }); + }); + + server.put('/events/:event_id', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + if (!data._id) { + data = Object.assign({}, data, { _id: req.params.event_id }); + } + + Event.findOne({ _id: req.params.event_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } else if (!doc) { + return next( + new errors.ResourceNotFoundError( + 'The resource you requested could not be found.', + ), + ); + } + + Event.update({ _id: data._id }, data, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.del('/events/:event_id', (req, res, next) => { + Event.deleteOne({ _id: req.params.event_id }, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(204); + next(); + }); + }); +}; diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..9da8d31 --- /dev/null +++ b/routes/index.js @@ -0,0 +1,9 @@ +module.exports = function(server, auth) { + require('./auth.js')(server, auth); + require('./bids.js')(server, auth); + require('./events.js')(server, auth); + require('./installs.js')(server, auth); + require('./items.js')(server, auth); + require('./sales.js')(server, auth); + require('./users.js')(server, auth); +}; diff --git a/routes/installs.js b/routes/installs.js new file mode 100644 index 0000000..bc377c3 --- /dev/null +++ b/routes/installs.js @@ -0,0 +1,110 @@ +const errors = require('restify-errors'); + +const Install = require('../models/install'); + +module.exports = function(server) { + server.post('/installs', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + let install = new Install(data); + install.save(function(err) { + if (err) { + console.error(err); + return next(new errors.InternalError(err.message)); + next(); + } + + res.send(201); + next(); + }); + }); + + server.get('/installs', (req, res, next) => { + Install.apiQuery(req.params, function(err, docs) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(docs); + next(); + }); + }); + + server.get('/installs/:install_id', (req, res, next) => { + Install.findOne({ _id: req.params.install_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(doc); + next(); + }); + }); + + server.put('/installs/:install_id', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + if (!data._id) { + data = Object.assign({}, data, { _id: req.params.install_id }); + } + + Install.findOne({ _id: req.params.install_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } else if (!doc) { + return next( + new errors.ResourceNotFoundError( + 'The resource you requested could not be found.', + ), + ); + } + + Install.update({ _id: data._id }, data, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.del('/installs/:install_id', (req, res, next) => { + Install.deleteOne({ _id: req.params.install_id }, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(204); + next(); + }); + }); +}; diff --git a/routes/items.js b/routes/items.js new file mode 100644 index 0000000..2f60ba1 --- /dev/null +++ b/routes/items.js @@ -0,0 +1,110 @@ +const errors = require('restify-errors'); + +const Item = require('../models/item'); + +module.exports = function(server) { + server.post('/items', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + let item = new Item(data); + item.save(function(err) { + if (err) { + console.error(err); + return next(new errors.InternalError(err.message)); + next(); + } + + res.send(201); + next(); + }); + }); + + server.get('/items', (req, res, next) => { + Item.apiQuery(req.params, function(err, docs) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(docs); + next(); + }); + }); + + server.get('/items/:item_id', (req, res, next) => { + Item.findOne({ _id: req.params.item_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(doc); + next(); + }); + }); + + server.put('/items/:item_id', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + if (!data._id) { + data = Object.assign({}, data, { _id: req.params.item_id }); + } + + Item.findOne({ _id: req.params.item_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } else if (!doc) { + return next( + new errors.ResourceNotFoundError( + 'The resource you requested could not be found.', + ), + ); + } + + Item.update({ _id: data._id }, data, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.del('/items/:item_id', (req, res, next) => { + Item.deleteOne({ _id: req.params.item_id }, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(204); + next(); + }); + }); +}; diff --git a/routes/sales.js b/routes/sales.js new file mode 100644 index 0000000..48c0d4b --- /dev/null +++ b/routes/sales.js @@ -0,0 +1,116 @@ +/** + * Module Dependencies + */ +const errors = require('restify-errors'); + +/** + * Model Schema + */ +const Sale = require('../models/sale'); + +module.exports = function(server) { + server.post('/sales', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + let sale = new Sale(data); + sale.save(function(err) { + if (err) { + console.error(err); + return next(new errors.InternalError(err.message)); + next(); + } + + res.send(201); + next(); + }); + }); + + server.get('/sales', (req, res, next) => { + Sale.apiQuery(req.params, function(err, docs) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(docs); + next(); + }); + }); + + server.get('/sales/:sale_id', (req, res, next) => { + Sale.findOne({ _id: req.params.sale_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(doc); + next(); + }); + }); + + server.put('/sales/:sale_id', (req, res, next) => { + if (!req.is('application/json')) { + return next( + new errors.InvalidContentError("Expects 'application/json'"), + ); + } + + let data = req.body || {}; + + if (!data._id) { + data = Object.assign({}, data, { _id: req.params.sale_id }); + } + + Sale.findOne({ _id: req.params.sale_id }, function(err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } else if (!doc) { + return next( + new errors.ResourceNotFoundError( + 'The resource you requested could not be found.', + ), + ); + } + + Sale.update({ _id: data._id }, data, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.del('/sales/:sale_id', (req, res, next) => { + Sale.deleteOne({ _id: req.params.sale_id }, function(err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err.errors.name.message), + ); + } + + res.send(204); + next(); + }); + }); +}; diff --git a/routes/signup.js b/routes/signup.js new file mode 100644 index 0000000..a727b24 --- /dev/null +++ b/routes/signup.js @@ -0,0 +1,42 @@ +const errors = require('restify-errors'); + +const User = require('../models/user'); + +module.exports = function (server, auth) { + const { passport } = auth; + + server.post('/signup', (req, res, next) => { + const { body: { user = null } = {} } = req; + + let errors = {}; + let errorCount = 0; + if (!user) { + errors.user = 'is required - can\'t make something from nothing...''; + errorCount++; + } + + if (errorCount) { + return res.send(422, { errors }); + } + + User.register(user, (err, user, info) => { + if (err) { + next(err); + } + + if (info) { + res.send(200, { + registrationSuccess: false, + nextSteps: 'Please fix the problems indicated and try again.' + ...info + }); + return next(); + } + + res.send(200, { + registrationSuccess: true, + nextSteps: 'Check your email for our confirmation email, you will not be able to login without confirming.' + }) + }); + }); +}; diff --git a/routes/users.js b/routes/users.js new file mode 100644 index 0000000..6658f91 --- /dev/null +++ b/routes/users.js @@ -0,0 +1,169 @@ +const aqp = require('api-query-params'); +const errors = require('restify-errors'); + +const User = require('../models/user'); +const { PUBLIC, PROTECTED } = require('../strategies/selects/user'); + +module.exports = function (server, auth) { + server.post('/users', auth.manager, (req, res, next) => { + let { password = null, ...data } = req.body || {}; + + let user = new User(data); + user.save(function(err) { + if (err) { + console.error(err); + return next(new errors.InternalError(err.message)); + next(); + } + + if (password) { + user.setPassword(password); + } + + res.send(201); + next(); + }); + }); + + server.get('/users', auth.manager, (req, res, next) => { + const { filter } = aqp(req.query); + const select = req.user.isManager ? PROTECTED : PUBLIC; + + User.find(filter, select, function (err, docs) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } + + res.send(docs); + next(); + }); + }); + + server.get('/users/:user_id', auth.managerOrSelf, (req, res, next) => { + const select = req.user.isManager ? PROTECTED : PUBLIC; + + User.findOne({ _id: req.params.user_id }, select, function (err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } + + res.send(doc); + next(); + }); + }); + + server.put('/users/:user_id', auth.managerOrSelf, (req, res, next) => { + let data = req.body || {}; + + if (!data._id) { + data = Object.assign({}, data, { _id: req.params.user_id }); + } + + User.findOne({ _id: req.params.user_id }, function (err, doc) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } else if (!doc) { + return next( + new errors.ResourceNotFoundError( + 'The resource you requested could not be found.', + ), + ); + } + + User.update({ _id: data._id }, data, function (err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.put('/users/password/:user_id/:reset_token?', function (req, res, next) { + let { + currentPassword = null, + newPassword = null, + ...data + } = req.body || {}; + + if (!newPassword) { + return next( + new errors.InvalidContentError('Password cannot be empty.'), + ); + } + + let filter = { _id: req.params.user_id }; + let resetToken = req.params.reset_token || null; + if (resetToken) { + fiter.resetToken = resetToken; + } + + User.findOne(filter, function (err, user) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } + + if (!user) { + return next( + new errors.ResourceNotFoundError( + 'The user you requested could not be found.', + ), + ); + } + + if (!resetToken && + !!user.getAuthStrategy('local') && + !user.validatePassword(currentPassword) + ) { + return next( + new errors.InvalidContentError( + 'The current password was incorrect.', + ), + ); + } + + user.setPassword(newPassword, function (err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } + + res.send(200, data); + next(); + }); + }); + }); + + server.del('/users/:user_id', auth.manager, (req, res, next) => { + User.deleteOne({ _id: req.params.user_id }, function (err) { + if (err) { + console.error(err); + return next( + new errors.InvalidContentError(err), + ); + } + + res.send(204); + next(); + }); + }); +}; diff --git a/strategies/auth/apple.js b/strategies/auth/apple.js new file mode 100644 index 0000000..5d144e2 --- /dev/null +++ b/strategies/auth/apple.js @@ -0,0 +1,5 @@ +const passport = require('passport'); + +module.exports = function(passport) { + return passport; +}; diff --git a/strategies/auth/facebook.js b/strategies/auth/facebook.js new file mode 100644 index 0000000..baf57fd --- /dev/null +++ b/strategies/auth/facebook.js @@ -0,0 +1,46 @@ +const passport = require('passport'); +const FacebookStrategy = require('passport-facebook').Strategy; + +const config = require('../../config'); +const User = require('../../models/user'); + +module.exports = function(passport) { + passport.use(new FacebookStrategy( + { + clientID: config.services.facebook.appId, + clientSecret: config.services.facebook.appSecret, + callbackURL: 'http://localhost:3001/auth/facebook/callback', + profileFields: ['id', 'email', 'first_name', 'last_name', 'picture'], + }, + (accessToken, refreshToken, profile, done) => { + const { + email, + first_name: firstName, + id: userId, + last_name: lastName, + picture: { data: { url = null } = {} } = {}, + } = profile._json; + const avatar = url; + + User.findOneAndUpdateOrCreate( + { + email, + }, + { + accessToken, + method: profile.provider, + userId, + }, + { + avatar, + email, + firstName, + lastName, + }, + (err, user) => { + return done(err, user, { accessToken, refreshToken }); + } + ); + } + )); +}; diff --git a/strategies/auth/google.js b/strategies/auth/google.js new file mode 100644 index 0000000..b7864f2 --- /dev/null +++ b/strategies/auth/google.js @@ -0,0 +1,40 @@ +const passport = require('passport'); +const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy; + +const config = require('../../config'); +const User = require('../../models/user'); + +module.exports = function(passport) { + passport.use(new GoogleStrategy({ + clientID: config.services.google.appId, + clientSecret: config.services.google.appSecret, + callbackURL: "http://www.example.com/auth/google/callback", + }, + (accessToken, refreshToken, profile, callback) => { + const googleUser = profile.getBasicProfile(); + + User.findOrCreate( + { + email: googleUser.getEmail(), + 'credentials.method': 'google', + 'credentials.userId': googleUser.getId(), + }, + { + avatar: googleUser.getImageUrl(), + email: googleUser.getEmail(), + firstName: googleUser.getGivenName(), + lastName: googleUser.getFamilyName(), + credentials: [{ + accessToken, + userId: googleUser.getId(), + method: 'facebook', + profile, + }], + }, + (err, user) => { + return done(err, user, { accessToken, refreshToken }); + } + ); + } + )); +}; diff --git a/strategies/auth/index.js b/strategies/auth/index.js new file mode 100644 index 0000000..e40279d --- /dev/null +++ b/strategies/auth/index.js @@ -0,0 +1,82 @@ +const createRequestUserObject = (req, user) => ({ + isGuest: !(user && user.id), + isManager: user && user.isEventManager(), + isSelf: user && user.id === req.params.user_id, + record: user || null, +}); + +const authenticateBasic = (passport) => (req, res, next) => ( + passport.authenticate('jwt', { session: false }, (err, user, info) => { + if (err) { + next(err); + } + + req.user = createRequestUserObject(req, user); + next(); + })(req, res, next) +); + +const authenticateEventManager = (passport) => (req, res, next) => ( + passport.authenticate('jwt', { session: false }, (err, user, info) => { + if (err) { + next(err); + } + + const record = createRequestUserObject(req, user); + + if (!user || !record.isManager) { + return res.send(401); + } + + req.user = record; + next(); + })(req, res, next) +); + +const authenticateEventManagerOrSelf = (passport) => (req, res, next) => ( + passport.authenticate('jwt', { session: false }, (err, user, info) => { + if (err) { + next(err); + } + + const record = createRequestUserObject(req, user); + + if (user && (!record.isManager && !record.isSelf)) { + return res.send(401); + } + + req.user = record; + next(); + })(req, res, next) +); + +const authenticateSecure = (passport) => (req, res, next) => ( + passport.authenticate('jwt', { session: false }, (err, user, info) => { + if (err) { + next(err); + } + + if (!user) { + return res.send(401); + } + + req.user = createRequestUserObject(req, user); + next(); + })(req, res, next) +); + +module.exports = function (passport) { + require('./apple.js')(passport); + require('./facebook.js')(passport); + require('./google.js')(passport); + require('./jwt.js')(passport); + require('./local.js')(passport); + + return { + basic: authenticateBasic(passport), + manager: authenticateEventManager(passport), + managerOrSelf: authenticateEventManagerOrSelf(passport), + passport, + secure: authenticateSecure(passport), + }; +}; diff --git a/strategies/auth/jwt.js b/strategies/auth/jwt.js new file mode 100644 index 0000000..b8b1ed3 --- /dev/null +++ b/strategies/auth/jwt.js @@ -0,0 +1,30 @@ +const passport = require('passport'); +const JwtStrategy = require('passport-jwt').Strategy; +const ExtractJwt = require('passport-jwt').ExtractJwt; + +const config = require('../../config'); +const User = require('../../models/user'); + +module.exports = function(passport) { + passport.use(new JwtStrategy( + { + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: config.security.jwt.secret, + issuer: config.security.jwt.issuer, + audience: config.security.jwt.audience, + }, + (jwt_payload, done) => { + User.findOne({ _id: jwt_payload.sub }, (err, user) => { + if (err) { + return done(err, false); + } + + if (user) { + return done(null, user); + } + + return done(null, false); + }); + } + )); +} diff --git a/strategies/auth/local.js b/strategies/auth/local.js new file mode 100644 index 0000000..1281abd --- /dev/null +++ b/strategies/auth/local.js @@ -0,0 +1,24 @@ +const passport = require('passport'); +const LocalStrategy = require('passport-local').Strategy; + +const User = require('../../models/user'); + +module.exports = function(passport) { + passport.use(new LocalStrategy( + { + usernameField: 'username', + passwordField: 'password', + }, + (username, password, done) => { + User.findOne({ email: username }, (err, user) => { + if (err) { return done(err); } + + if (!user || !user.validatePassword(password)) { + return done(null, false, { message: 'Incorrect username or password.' }); + } + + return done(null, user); + }); + } + )); +}; diff --git a/strategies/selects/user.js b/strategies/selects/user.js new file mode 100644 index 0000000..6915078 --- /dev/null +++ b/strategies/selects/user.js @@ -0,0 +1,10 @@ +module.exports = { + PUBLIC: { + credentials: 0, + isVerified: 0, + organizationIdentifier: 0, + paymentToken: 0, + }, + PROTECTED: {}, +}; + diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..aa823fe --- /dev/null +++ b/yarn.lock @@ -0,0 +1,1347 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@netflix/nerror@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@netflix/nerror/-/nerror-1.1.0.tgz#0ab9bdf0c0de6fb565c91af7744099bf8ebe21ba" + integrity sha512-VGB1t59S6j4ZuIaYc7PAtIQ1GgF8xPtwq/pl+VFoyjMP1jDcPgMWcLH9A5ZQEmj5p1CQ/ycN7kReKEny/CjJ8Q== + dependencies: + assert-plus "^1.0.0" + extsprintf "^1.4.0" + lodash "^4.17.11" + +api-query-params@^4.13.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/api-query-params/-/api-query-params-4.13.0.tgz#39df249184e77fb2a7b2033f14ae1bf802c2d33d" + integrity sha512-GY8dFYbVBA46ymOiRlXOkE8pHaUJlhM8v9WWzy89wEhoqf1XXwOK7nzivKyvnsZSAdzLjsRpmEBnPvTsP6Zn9g== + +asn1@0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.1.11.tgz#559be18376d08a4ec4dbe80877d27818639b2df7" + integrity sha1-VZvhg3bQik7E2+gId9J4GGObLfc= + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert-plus@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.1.5.tgz#ee74009413002d84cec7219c6ac811812e723160" + integrity sha1-7nQAlBMALYTOxyGcasgRgS5yMWA= + +async@2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== + dependencies: + lodash "^4.17.11" + +async@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/async/-/async-3.0.1.tgz#dfeb34657d1e63c94c0eee424297bf8a2c9a8182" + integrity sha512-ZswD8vwPtmBZzbn9xyi8XBQWXH3AvOQ43Za1KWYq7JeycrZuUYzx01KvHcVbXltjqH4y0MWrQ33008uLTqXuDw== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +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== + +basic-auth@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +bluebird@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== + +body-parser@^1.18.3: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +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" + +bson@^1.1.1, bson@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.1.tgz#4330f5e99104c4e751e7351859e2d408279f2f13" + integrity sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg== + +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" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + +bunyan@^1.8.0, bunyan@^1.8.12: + version "1.8.12" + resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797" + integrity sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c= + optionalDependencies: + dtrace-provider "~0.8" + moment "^2.10.6" + mv "~2" + safe-json-stringify "~1" + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +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= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +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" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +crypto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" + integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== + +csv-generate@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-1.1.2.tgz#ec6b00edaed6e59ad9c20582f4c364e28b146240" + integrity sha1-7GsA7a7W5ZrZwgWC9MNk4osUYkA= + +csv-generate@^3.2.0: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csv-generate/-/csv-generate-3.2.3.tgz#24004f21de61c2ea1c4474d3e65a18261f638a80" + integrity sha512-IcR3K0Nx+nJAkcU2eAglVR7DuHnxcuhUM2w2cR+aHOW7bZp2S5LyN2HF3zTkp6BV/DjR6ykoKznUm+AjnWcOKg== + +csv-parse@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-1.3.3.tgz#d1cfd8743c2f849a0abb2fd544db56695d19a490" + integrity sha1-0c/YdDwvhJoKuy/VRNtWaV0ZpJA= + +csv-parse@^4.3.0: + version "4.4.3" + resolved "https://registry.yarnpkg.com/csv-parse/-/csv-parse-4.4.3.tgz#a3fc56b6f54de88db76fbd34a55c091861522712" + integrity sha512-TiLGAy14FPJ7/yB+Gn6RgSxoZLpf6pJTRkGqmCt9t/SGVwubrXjbUWtEw39RlKB6hDHzbdjLyBZaysQ0Ji6p/w== + +csv-stringify@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-1.1.2.tgz#77a41526581bce3380f12b00d7c5bbac70c82b58" + integrity sha1-d6QVJlgbzjOA8SsA18W7rHDIK1g= + dependencies: + lodash.get "~4.4.2" + +csv-stringify@^5.1.2: + version "5.3.0" + resolved "https://registry.yarnpkg.com/csv-stringify/-/csv-stringify-5.3.0.tgz#ff2dfafa6fcccd455ff5039be9c202475aa3bbe0" + integrity sha512-VMYPbE8zWz475smwqb9VbX9cj0y4J0PBl59UdcqzLkzXHZZ8dh4Rmbb0ZywsWEtUml4A96Hn7Q5MW9ppVghYzg== + dependencies: + lodash.get "~4.4.2" + +csv@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/csv/-/csv-1.2.1.tgz#5231edfc1c7152512ec45781076a7a97ff525c0c" + integrity sha1-UjHt/BxxUlEuxFeBB2p6l/9SXAw= + dependencies: + csv-generate "^1.1.2" + csv-parse "^1.3.3" + csv-stringify "^1.1.2" + stream-transform "^0.2.2" + +csv@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/csv/-/csv-5.1.1.tgz#bd715f15a4ed9141309a24ec6dab1c903ab79f92" + integrity sha512-gezB9D+enrh2tLj+vsAD8JyYRMIJdSMpec/Pgbb+7YRj6Q6/D12HLSwjhx+CrirRT4dESjZYXWX1JfqlV4RlTA== + dependencies: + csv-generate "^3.2.0" + csv-parse "^4.3.0" + csv-stringify "^5.1.2" + stream-transform "^1.0.8" + +ctype@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/ctype/-/ctype-0.5.3.tgz#82c18c2461f74114ef16c135224ad0b9144ca12f" + integrity sha1-gsGMJGH3QRTvFsE1IkrQuRRMoS8= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +debug@2.6.9, debug@~2.6.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-node@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" + integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== + +dtrace-provider@^0.8.1, dtrace-provider@~0.8: + version "0.8.7" + resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.7.tgz#dc939b4d3e0620cfe0c1cd803d0d2d7ed04ffd04" + integrity sha1-3JObTT4GIM/gwc2APQ0tftBP/QQ= + dependencies: + nan "^2.10.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + 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" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-regexp-component@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz#9c63b6d0b25ff2a88c3adbd18c5b61acc3b9faa2" + integrity sha1-nGO20LJf8qiMOtvRjFthrMO5+qI= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +ewma@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ewma/-/ewma-2.0.1.tgz#9876c1c491ac5733c8666001a3961a04c97cf1e8" + integrity sha512-MYYK17A76cuuyvkR7MnqLW4iFYPEi5Isl2qb8rXiWpLiwFS9dxW/rncuNnjjgSENuVqZQkIuR4+DChVL4g1lnw== + dependencies: + assert-plus "^1.0.0" + +express-unless@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/express-unless/-/express-unless-0.5.0.tgz#c2ece477f4155089143dbb869d07c57c5eb6ab9b" + integrity sha1-wuzkd/QVUIkUPbuGnQfFfF62q5s= + +extsprintf@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.2.0.tgz#5ad946c22f5b32ba7f8cd7426711c6e8a3fc2529" + integrity sha1-WtlGwi9bMrp/jNdCZxHG6KP8JSk= + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0, extsprintf@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-decode-uri-component@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543" + integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg== + +find-my-way@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-2.0.1.tgz#965aa7cacac2362d47d5d7ce219f51bf76216af7" + integrity sha512-c+YnWk4LKcWSNu743wfoqNOZTYQ6kZ/kzZCjALGblLpzbEAv3INakGMZ1K/by+Wmf/NP3+3LpOQMOFw6/q52wQ== + dependencies: + fast-decode-uri-component "^1.0.0" + safe-regex2 "^2.0.0" + semver-store "^0.3.0" + +formidable@^1.0.17, formidable@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659" + integrity sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI= + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +handle-thing@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" + integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-signature@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-0.11.0.tgz#1796cf67a001ad5cd6849dca0991485f09089fe6" + integrity sha1-F5bPZ6ABrVzWhJ3KCZFIXwkIn+Y= + dependencies: + asn1 "0.1.11" + assert-plus "^0.1.5" + ctype "0.5.3" + +http-signature@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +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" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +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== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +kareem@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.0.tgz#ef33c42e9024dce511eeaf440cd684f3af1fc769" + integrity sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg== + +lodash.get@~4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +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.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.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@^4.17.11, lodash@^4.2.1: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +mime-db@1.40.0: + version "1.40.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" + integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== + +mime-types@~2.1.24: + version "2.1.24" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" + integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== + dependencies: + mime-db "1.40.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" + integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +"minimatch@2 || 3": + 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" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +moment@^2.10.6: + version "2.24.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== + +mongodb-core@3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-3.2.7.tgz#a8ef1fe764a192c979252dacbc600dc88d77e28f" + integrity sha512-WypKdLxFNPOH/Jy6i9z47IjG2wIldA54iDZBmHMINcgKOUcWJh8og+Wix76oGd7EyYkHJKssQ2FAOw5Su/n4XQ== + dependencies: + bson "^1.1.1" + require_optional "^1.0.1" + safe-buffer "^5.1.2" + optionalDependencies: + saslprep "^1.0.0" + +mongodb@3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.2.7.tgz#8ba149e4be708257cad0dea72aebb2bbb311a7ac" + integrity sha512-2YdWrdf1PJgxcCrT1tWoL6nHuk6hCxhddAAaEh8QJL231ci4+P9FLyqopbTm2Z2sAU6mhCri+wd9r1hOcHdoMw== + dependencies: + mongodb-core "3.2.7" + safe-buffer "^5.1.2" + +mongoose-find-or-create@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mongoose-find-or-create/-/mongoose-find-or-create-1.3.1.tgz#415a4a7d1094a9b56ca42b0366926f05aef0e362" + integrity sha512-eS5mkEMFYmP0krwTqKjFHwJTpRjLAxiHEG3cbBf9rEaAYsH0NVLgWF8ipaSyWM4c2gnh4nzR4VCUpkaVJFbTyg== + +mongoose-legacy-pluralize@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" + integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== + +mongoose-string-query@^0.2.7: + version "0.2.7" + resolved "https://registry.yarnpkg.com/mongoose-string-query/-/mongoose-string-query-0.2.7.tgz#d37303c0905aeffbce425892e96a3019a02186ca" + integrity sha512-UaYpX/5wmAdE9ocTBm9X8DaWCWrSMS8IiVW8aR8dmbK3BO8P4bKWObxJKqXhBoBcU4y88ZpXCAzmWpRo5z5oWQ== + dependencies: + body-parser "^1.18.3" + debug "~2.6.3" + morgan "^1.9.1" + serve-favicon "~2.4.2" + +mongoose-timestamp@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/mongoose-timestamp/-/mongoose-timestamp-0.6.0.tgz#da54110ca8e6d4c2b9957a0366836c362ed272be" + integrity sha1-2lQRDKjm1MK5lXoDZoNsNi7Scr4= + dependencies: + defaults "^1.0.3" + +mongoose@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.6.0.tgz#6c3984d2330bc3b28ae800d8b8025a0686d1e450" + integrity sha512-bhevx8u4NfZf2Un+CcKWRsiNekrLH7dSI8mBC49FcY2SUXQPZf3w+Yby+cgDrpZA46nkqRW9Qaqhs7PT0XCtYQ== + dependencies: + async "2.6.2" + bson "~1.1.1" + kareem "2.3.0" + mongodb "3.2.7" + mongodb-core "3.2.7" + mongoose-legacy-pluralize "1.0.2" + mpath "0.6.0" + mquery "3.2.1" + ms "2.1.2" + regexp-clone "1.0.0" + safe-buffer "5.1.2" + sift "7.0.1" + sliced "1.0.1" + +morgan@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" + integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA== + dependencies: + basic-auth "~2.0.0" + debug "2.6.9" + depd "~1.1.2" + on-finished "~2.3.0" + on-headers "~1.0.1" + +mpath@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.6.0.tgz#aa922029fca4f0f641f360e74c5c1b6a4c47078e" + integrity sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw== + +mquery@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.1.tgz#8b059a49cdae0a8a9e804284ef64c2f58d3ac05d" + integrity sha512-kY/K8QToZWTTocm0U+r8rqcJCp5PRl6e8tPmoDs5OeSO3DInZE2rAL6AYH+V406JTo8305LdASOQcxRDqHojyw== + dependencies: + bluebird "3.5.1" + debug "3.1.0" + regexp-clone "^1.0.0" + safe-buffer "5.1.2" + sliced "1.0.1" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mv@~2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" + integrity sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI= + dependencies: + mkdirp "~0.5.1" + ncp "~2.0.0" + rimraf "~2.4.0" + +nan@^2.10.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +ncp@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= + +negotiator@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +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= + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.2, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +parseurl@~1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +passport-facebook@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/passport-facebook/-/passport-facebook-3.0.0.tgz#b16f7314128be55d020a2b75f574c194bd6d9805" + integrity sha512-K/qNzuFsFISYAyC1Nma4qgY/12V3RSLFdFVsPKXiKZt434wOvthFW1p7zKa1iQihQMRhaWorVE1o3Vi1o+ZgeQ== + dependencies: + passport-oauth2 "1.x.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-http-bearer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz#147469ea3669e2a84c6167ef99dbb77e1f0098a8" + integrity sha1-FHRp6jZp4qhMYWfvmdu3fh8AmKg= + dependencies: + passport-strategy "1.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.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.0" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811" + integrity sha1-xQlWkTR71a07XhgCOMORTRbwWBE= + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + +pidusage@^2.0.17: + version "2.0.17" + resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-2.0.17.tgz#6b4a2b4a09026f0e9828f7e5627837e4c0672581" + integrity sha512-N8X5v18rBmlBoArfS83vrnD0gIFyZkXEo7a5pAS2aT0i2OLVymFb2AzVg+v8l/QcXnE1JwZcaXR8daJcoJqtjw== + dependencies: + safe-buffer "^5.1.2" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +qs@6.7.0, qs@^6.2.1, qs@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +range-parser@~1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.1: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +regexp-clone@1.0.0, regexp-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" + integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== + +require_optional@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" + integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= + +restify-errors@^4.2.3: + version "4.3.0" + resolved "https://registry.yarnpkg.com/restify-errors/-/restify-errors-4.3.0.tgz#ec90f30934d7f3119135181dfc303e30be601abe" + integrity sha1-7JDzCTTX8xGRNRgd/DA+ML5gGr4= + dependencies: + assert-plus "^1.0.0" + lodash "^4.2.1" + verror "^1.8.1" + optionalDependencies: + safe-json-stringify "^1.0.3" + +restify-errors@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/restify-errors/-/restify-errors-8.0.0.tgz#8a1b58b0fb645f3df5cb78783ec56a3abc45ac71" + integrity sha512-UpY727sc65Zuz0vBS3Pk3wU4UD1HluIwNRINlPaA/dxLzmf2RlzH/gqZUne9X+MO48cn+DVL7SleDG+9V5YzYQ== + dependencies: + "@netflix/nerror" "^1.0.0" + assert-plus "^1.0.0" + lodash "^4.17.11" + optionalDependencies: + safe-json-stringify "^1.0.4" + +restify-jwt-community@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/restify-jwt-community/-/restify-jwt-community-1.0.13.tgz#35f1cdc3fa6730de230cf19b1171ec5d28f67e86" + integrity sha512-vMoipjRLVxrwchtHc4sZYgAlu4OEE/SIvDWathJPG9F2HjuExasK+w2siGFgNCpPTr0EqfKj2uCkFJ+u69rJtQ== + dependencies: + async "^3.0.0" + express-unless "^0.5.0" + jsonwebtoken "^8.5.1" + restify-errors "^8.0.0" + +restify-plugins@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/restify-plugins/-/restify-plugins-1.6.0.tgz#79e118887b7f0eb02e645780f9c5680cb7ab9aa9" + integrity sha1-eeEYiHt/DrAuZFeA+cVoDLermqk= + dependencies: + assert-plus "^1.0.0" + bunyan "^1.8.0" + csv "^1.1.0" + escape-regexp-component "^1.0.2" + formidable "^1.0.17" + http-signature "^0.11.0" + lru-cache "^4.0.1" + mime "^1.3.4" + once "^1.3.2" + qs "^6.2.1" + restify-errors "^4.2.3" + vasync "^1.6.3" + +restify@^8.3.3: + version "8.3.3" + resolved "https://registry.yarnpkg.com/restify/-/restify-8.3.3.tgz#9d89bb6e22fe7c7e4c89fc53820b481fe41cc449" + integrity sha512-E1xYBmC1gD3IUAeDhZx7VdmD69SSz8Ti5b69nwBgWCpTPIi3XImucPNnAtSEz5fHUW2F/arwSDUe1TPqt+5/zQ== + dependencies: + assert-plus "^1.0.0" + bunyan "^1.8.12" + csv "^5.1.1" + escape-regexp-component "^1.0.2" + ewma "^2.0.1" + find-my-way "^2.0.1" + formidable "^1.2.1" + http-signature "^1.2.0" + lodash "^4.17.11" + lru-cache "^5.1.1" + mime "^2.4.3" + negotiator "^0.6.2" + once "^1.4.0" + pidusage "^2.0.17" + qs "^6.7.0" + restify-errors "^8.0.0" + semver "^6.1.1" + send "^0.16.2" + spdy "^4.0.0" + uuid "^3.3.2" + vasync "^2.2.0" + optionalDependencies: + dtrace-provider "^0.8.1" + +ret@~0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.2.2.tgz#b6861782a1f4762dce43402a71eb7a283f44573c" + integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== + +rimraf@~2.4.0: + version "2.4.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" + integrity sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto= + dependencies: + glob "^6.0.1" + +safe-buffer@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== + +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-json-stringify@^1.0.3, safe-json-stringify@^1.0.4, safe-json-stringify@~1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" + integrity sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg== + +safe-regex2@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/safe-regex2/-/safe-regex2-2.0.0.tgz#b287524c397c7a2994470367e0185e1916b1f5b9" + integrity sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ== + dependencies: + ret "~0.2.0" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +saslprep@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +semver-store@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" + integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== + +semver@^5.1.0, semver@^5.6.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +semver@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.1.1.tgz#53f53da9b30b2103cd4f15eab3a18ecbcb210c9b" + integrity sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ== + +send@^0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-favicon@~2.4.2: + version "2.4.5" + resolved "https://registry.yarnpkg.com/serve-favicon/-/serve-favicon-2.4.5.tgz#49d9a46863153a9240691c893d2b0e7d85d6d436" + integrity sha512-s7F8h2NrslMkG50KxvlGdj+ApSwaLex0vexuJ9iFf3GLTIp1ph/l1qZvRe9T9TJEYZgmq72ZwJ2VYiAEtChknw== + dependencies: + etag "~1.8.1" + fresh "0.5.2" + ms "2.0.0" + parseurl "~1.3.2" + safe-buffer "5.1.1" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sift@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" + integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== + +sliced@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= + dependencies: + memory-pager "^1.0.2" + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52" + integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stream-transform@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-0.2.2.tgz#75867487f49528f8bf1d82499658753d02df7838" + integrity sha1-dYZ0h/SVKPi/HYJJllh1PQLfeDg= + +stream-transform@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-1.0.8.tgz#54f721122d310eca855a16c97939881ab5bbb76c" + integrity sha512-1q+dL790Ps0NV33rISMq9OLtfDA9KMJZdo1PHZXE85orrWsM4FAh8CVyAOTHO0rhyeM138KNPngBPrx33bFsxw== + +string_decoder@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" + integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== + dependencies: + safe-buffer "~5.1.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-is@~1.6.17: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +uid2@0.0.x: + version "0.0.3" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82" + integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I= + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +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" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +vasync@^1.6.3: + version "1.6.4" + resolved "https://registry.yarnpkg.com/vasync/-/vasync-1.6.4.tgz#dfe93616ad0e7ae801b332a9d88bfc5cdc8e1d1f" + integrity sha1-3+k2Fq0OeugBszKp2Iv8XNyOHR8= + dependencies: + verror "1.6.0" + +vasync@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vasync/-/vasync-2.2.0.tgz#cfde751860a15822db3b132bc59b116a4adaf01b" + integrity sha1-z951GGChWCLbOxMrxZsRakra8Bs= + dependencies: + verror "1.10.0" + +verror@1.10.0, verror@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +verror@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.6.0.tgz#7d13b27b1facc2e2da90405eb5ea6e5bdd252ea5" + integrity sha1-fROyex+swuLakEBetepuW90lLqU= + dependencies: + extsprintf "1.2.0" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==