From 69bf53e05e2529d7cef21bd816da1c39fc73ce59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Tue, 26 Feb 2019 16:28:22 +0100 Subject: [PATCH 1/6] Impplement currentUser query * remove dead code (passport-jwt) * refactor resolves to have a separate folder * currentUser and login have the same response --- package.json | 2 - src/graphql-schema.js | 178 ++--------------------- src/graphql-schema.spec.js | 184 ------------------------ src/jwt/decode.js | 29 ++++ src/jwt/{generateToken.js => encode.js} | 2 +- src/jwt/strategy.js | 42 ------ src/middleware/permissionsMiddleware.js | 3 +- src/resolvers/posts.js | 22 +++ src/resolvers/posts.spec.js | 61 ++++++++ src/resolvers/reports.js | 51 +++++++ src/resolvers/reports.spec.js | 68 +++++++++ src/resolvers/statistics.js | 67 +++++++++ src/resolvers/user_management.js | 52 +++++++ src/resolvers/user_management.spec.js | 183 +++++++++++++++++++++++ src/schema.graphql | 4 +- src/server.js | 27 +--- yarn.lock | 28 +--- 17 files changed, 555 insertions(+), 448 deletions(-) delete mode 100644 src/graphql-schema.spec.js create mode 100644 src/jwt/decode.js rename src/jwt/{generateToken.js => encode.js} (90%) delete mode 100644 src/jwt/strategy.js create mode 100644 src/resolvers/posts.js create mode 100644 src/resolvers/posts.spec.js create mode 100644 src/resolvers/reports.js create mode 100644 src/resolvers/reports.spec.js create mode 100644 src/resolvers/statistics.js create mode 100644 src/resolvers/user_management.js create mode 100644 src/resolvers/user_management.spec.js diff --git a/package.json b/package.json index 39c9c14c6..e313b45d5 100644 --- a/package.json +++ b/package.json @@ -59,8 +59,6 @@ "neo4j-graphql-js": "~2.3.1", "node-fetch": "~2.3.0", "npm-run-all": "~4.1.5", - "passport": "~0.4.0", - "passport-jwt": "~4.0.0", "sanitize-html": "~1.20.0", "slug": "~1.0.0", "trunc-html": "~1.1.2", diff --git a/src/graphql-schema.js b/src/graphql-schema.js index ce84dde36..6d10183c9 100644 --- a/src/graphql-schema.js +++ b/src/graphql-schema.js @@ -1,182 +1,22 @@ import fs from 'fs' import path from 'path' -import bcrypt from 'bcryptjs' -import generateJwt from './jwt/generateToken' -import uuid from 'uuid/v4' -import { fixUrl } from './middleware/fixImageUrlsMiddleware' -import { AuthenticationError } from 'apollo-server' -import { neo4jgraphql } from 'neo4j-graphql-js' +import userManagement from './resolvers/user_management.js' +import statistics from './resolvers/statistics.js' +import reports from './resolvers/reports.js' +import posts from './resolvers/posts.js' export const typeDefs = fs.readFileSync(process.env.GRAPHQL_SCHEMA || path.join(__dirname, 'schema.graphql')) .toString('utf-8') -export const query = (cypher, session) => { - return new Promise((resolve, reject) => { - let data = [] - session - .run(cypher) - .subscribe({ - onNext: function (record) { - let item = {} - record.keys.forEach(key => { - item[key] = record.get(key) - }) - data.push(item) - }, - onCompleted: function () { - session.close() - resolve(data) - }, - onError: function (error) { - reject(error) - } - }) - }) -} -const queryOne = (cypher, session) => { - return new Promise((resolve, reject) => { - query(cypher, session) - .then(res => { - resolve(res.length ? res.pop() : {}) - }) - .catch(err => { - reject(err) - }) - }) -} - export const resolvers = { Query: { - isLoggedIn: (parent, args, { driver, user }) => { - return Boolean(user && user.id) - }, - statistics: async (parent, args, { driver, user }) => { - return new Promise(async (resolve) => { - const session = driver.session() - const queries = { - countUsers: 'MATCH (r:User) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countUsers', - countPosts: 'MATCH (r:Post) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countPosts', - countComments: 'MATCH (r:Comment) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countComments', - countNotifications: 'MATCH (r:Notification) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countNotifications', - countOrganizations: 'MATCH (r:Organization) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countOrganizations', - countProjects: 'MATCH (r:Project) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countProjects', - countInvites: 'MATCH (r:Invite) WHERE r.wasUsed <> true OR NOT exists(r.wasUsed) RETURN COUNT(r) AS countInvites', - countFollows: 'MATCH (:User)-[r:FOLLOWS]->(:User) RETURN COUNT(r) AS countFollows', - countShouts: 'MATCH (:User)-[r:SHOUTED]->(:Post) RETURN COUNT(r) AS countShouts' - } - let data = { - countUsers: (await queryOne(queries.countUsers, session)).countUsers.low, - countPosts: (await queryOne(queries.countPosts, session)).countPosts.low, - countComments: (await queryOne(queries.countComments, session)).countComments.low, - countNotifications: (await queryOne(queries.countNotifications, session)).countNotifications.low, - countOrganizations: (await queryOne(queries.countOrganizations, session)).countOrganizations.low, - countProjects: (await queryOne(queries.countProjects, session)).countProjects.low, - countInvites: (await queryOne(queries.countInvites, session)).countInvites.low, - countFollows: (await queryOne(queries.countFollows, session)).countFollows.low, - countShouts: (await queryOne(queries.countShouts, session)).countShouts.low - } - resolve(data) - }) - } - // usersBySubstring: neo4jgraphql + ...statistics.Query, + ...userManagement.Query }, Mutation: { - signup: async (parent, { email, password }, { req }) => { - // if (data[email]) { - // throw new Error('Another User with same email exists.') - // } - // data[email] = { - // password: await bcrypt.hashSync(password, 10), - // } - - return true - }, - login: async (parent, { email, password }, { driver, req, user }) => { - // if (user && user.id) { - // throw new Error('Already logged in.') - // } - const session = driver.session() - return session.run( - 'MATCH (user:User {email: $userEmail}) ' + - 'RETURN user {.id, .slug, .name, .avatar, .locationName, .about, .email, .password, .role} as user LIMIT 1', { - userEmail: email - }) - .then(async (result) => { - session.close() - const [currentUser] = await result.records.map(function (record) { - return record.get('user') - }) - - if (currentUser && await bcrypt.compareSync(password, currentUser.password)) { - delete currentUser.password - currentUser.avatar = fixUrl(currentUser.avatar) - return Object.assign(currentUser, { - token: generateJwt(currentUser) - }) - } else throw new AuthenticationError('Incorrect email address or password.') - }) - }, - report: async (parent, { resource, description }, { driver, req, user }, resolveInfo) => { - const contextId = uuid() - const session = driver.session() - const data = { - id: contextId, - type: resource.type, - createdAt: (new Date()).toISOString(), - description: resource.description - } - await session.run( - 'CREATE (r:Report $report) ' + - 'RETURN r.id, r.type, r.description', { - report: data - } - ) - let contentType - - switch (resource.type) { - case 'post': - case 'contribution': - contentType = 'Post' - break - case 'comment': - contentType = 'Comment' - break - case 'user': - contentType = 'User' - break - } - - await session.run( - `MATCH (author:User {id: $userId}), (context:${contentType} {id: $resourceId}), (report:Report {id: $contextId}) ` + - 'MERGE (report)<-[:REPORTED]-(author) ' + - 'MERGE (context)<-[:REPORTED]-(report) ' + - 'RETURN context', { - resourceId: resource.id, - userId: user.id, - contextId: contextId - } - ) - session.close() - - // TODO: output Report compatible object - return data - }, - CreatePost: async (object, params, ctx, resolveInfo) => { - const result = await neo4jgraphql(object, params, ctx, resolveInfo, false) - - const session = ctx.driver.session() - await session.run( - 'MATCH (author:User {id: $userId}), (post:Post {id: $postId}) ' + - 'MERGE (post)<-[:WROTE]-(author) ' + - 'RETURN author', { - userId: ctx.user.id, - postId: result.id - }) - session.close() - - return result - } - + ...userManagement.Mutation, + ...reports.Mutation, + ...posts.Mutation } } diff --git a/src/graphql-schema.spec.js b/src/graphql-schema.spec.js deleted file mode 100644 index 7aa47835f..000000000 --- a/src/graphql-schema.spec.js +++ /dev/null @@ -1,184 +0,0 @@ -import Factory from './seed/factories' -import { GraphQLClient, request } from 'graphql-request' -import jwt from 'jsonwebtoken' -import { host, login } from './jest/helpers' - -const factory = Factory() - -beforeEach(async () => { - await factory.create('User', { - email: 'test@example.org', - password: '1234' - }) -}) - -afterEach(async () => { - await factory.cleanDatabase() -}) - -describe('isLoggedIn', () => { - describe('unauthenticated', () => { - it('returns false', async () => { - const query = '{ isLoggedIn }' - await expect(request(host, query)).resolves.toEqual({ isLoggedIn: false }) - }) - }) -}) - -describe('login', () => { - const mutation = (params) => { - const { email, password } = params - return ` - mutation { - login(email:"${email}", password:"${password}"){ - token - } - }` - } - - describe('ask for a `token`', () => { - describe('with valid email/password combination', () => { - it('responds with a JWT token', async () => { - const data = await request(host, mutation({ - email: 'test@example.org', - password: '1234' - })) - const { token } = data.login - jwt.verify(token, process.env.JWT_SECRET, (err, data) => { - expect(data.email).toEqual('test@example.org') - expect(err).toBeNull() - }) - }) - }) - - describe('with a valid email but incorrect password', () => { - it('responds with "Incorrect email address or password."', async () => { - await expect( - request(host, mutation({ - email: 'test@example.org', - password: 'wrong' - })) - ).rejects.toThrow('Incorrect email address or password.') - }) - }) - - describe('with a non-existing email', () => { - it('responds with "Incorrect email address or password."', async () => { - await expect( - request(host, mutation({ - email: 'non-existent@example.org', - password: 'wrong' - })) - ).rejects.toThrow('Incorrect email address or password.') - }) - }) - }) -}) - -describe('CreatePost', () => { - describe('unauthenticated', () => { - let client - it('throws authorization error', async () => { - client = new GraphQLClient(host) - await expect(client.request(`mutation { - CreatePost( - title: "I am a post", - content: "Some content" - ) { slug } - }`)).rejects.toThrow('Not Authorised') - }) - - describe('authenticated', () => { - let headers - let response - beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) - response = await client.request(`mutation { - CreatePost( - title: "A title", - content: "Some content" - ) { title, content } - }`, { headers }) - }) - - it('creates a post', () => { - expect(response).toEqual({ CreatePost: { title: 'A title', content: 'Some content' } }) - }) - - it('assigns the authenticated user as author', async () => { - const { User } = await client.request(`{ - User(email:"test@example.org") { - contributions { - title - } - } - }`, { headers }) - expect(User).toEqual([ { contributions: [ { title: 'A title' } ] } ]) - }) - }) - }) -}) - -describe('report', () => { - beforeEach(async () => { - await factory.create('User', { - email: 'test@example.org', - password: '1234' - }) - await factory.create('User', { - id: 'u2', - name: 'abusive-user', - role: 'user', - email: 'abusive-user@example.org' - }) - }) - - afterEach(async () => { - await factory.cleanDatabase() - }) - - describe('unauthenticated', () => { - let client - it('throws authorization error', async () => { - client = new GraphQLClient(host) - await expect( - client.request(`mutation { - report( - description: "I don't like this user", - resource: { - id: "u2", - type: user - } - ) { id, createdAt } - }`) - ).rejects.toThrow('Not Authorised') - }) - - describe('authenticated', () => { - let headers - let response - beforeEach(async () => { - headers = await login({ email: 'test@example.org', password: '1234' }) - client = new GraphQLClient(host, { headers }) - response = await client.request(`mutation { - report( - description: "I don't like this user", - resource: { - id: "u2", - type: user - } - ) { id, createdAt } - }`, - { headers } - ) - }) - it('creates a report', () => { - let { id, createdAt } = response.report - expect(response).toEqual({ - report: { id, createdAt } - }) - }) - }) - }) -}) diff --git a/src/jwt/decode.js b/src/jwt/decode.js new file mode 100644 index 000000000..0ab1e4529 --- /dev/null +++ b/src/jwt/decode.js @@ -0,0 +1,29 @@ +import jwt from 'jsonwebtoken' + +export default async (driver, authorizationHeader) => { + if (!authorizationHeader) return null + const token = authorizationHeader.replace('Bearer ', '') + let id = null + try { + const decoded = await jwt.verify(token, process.env.JWT_SECRET) + id = decoded.sub + } catch { + return null + } + const session = driver.session() + const query = ` + MATCH (user:User {id: {id} }) + RETURN user {.id, .slug, .name, .avatar, .email, .role} as user + LIMIT 1 + ` + const result = await session.run(query, { id }) + session.close() + const [currentUser] = await result.records.map((record) => { + return record.get('user') + }) + if (!currentUser) return null + return { + token, + ...currentUser + } +} diff --git a/src/jwt/generateToken.js b/src/jwt/encode.js similarity index 90% rename from src/jwt/generateToken.js rename to src/jwt/encode.js index 7cbc70330..62e85616b 100644 --- a/src/jwt/generateToken.js +++ b/src/jwt/encode.js @@ -3,7 +3,7 @@ import jwt from 'jsonwebtoken' import ms from 'ms' // Generate an Access Token for the given User ID -export default function generateJwt (user) { +export default function encode (user) { const token = jwt.sign(user, process.env.JWT_SECRET, { expiresIn: ms('1d'), issuer: process.env.GRAPHQL_URI, diff --git a/src/jwt/strategy.js b/src/jwt/strategy.js deleted file mode 100644 index 5b1ea1231..000000000 --- a/src/jwt/strategy.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Strategy } from 'passport-jwt' -import { fixUrl } from '../middleware/fixImageUrlsMiddleware' - -const cookieExtractor = (req) => { - var token = null - if (req && req.cookies) { - token = req.cookies['jwt'] - } - return token -} - -export default (driver) => { - const options = { - jwtFromRequest: cookieExtractor, - secretOrKey: process.env.JWT_SECRET, - issuer: process.env.GRAPHQL_URI, - audience: process.env.CLIENT_URI - } - - return new Strategy(options, - async (JWTPayload, next) => { - const session = driver.session() - const result = await session.run( - 'MATCH (user:User {id: $userId}) ' + - 'RETURN user {.id, .slug, .name, .avatar, .email, .role} as user LIMIT 1', - { - userId: JWTPayload.id - } - ) - session.close() - const [currentUser] = await result.records.map((record) => { - return record.get('user') - }) - - if (currentUser) { - currentUser.avatar = fixUrl(currentUser.avatar) - return next(null, currentUser) - } else { - return next(null, false) - } - }) -} diff --git a/src/middleware/permissionsMiddleware.js b/src/middleware/permissionsMiddleware.js index 1a3f04ceb..0c6723b4b 100644 --- a/src/middleware/permissionsMiddleware.js +++ b/src/middleware/permissionsMiddleware.js @@ -23,7 +23,8 @@ const isMyOwn = rule({ cache: 'no_cache' })(async (parent, args, ctx, info) => { // Permissions const permissions = shield({ Query: { - statistics: allow + statistics: allow, + currentUser: allow // fruits: and(isAuthenticated, or(isAdmin, isModerator)), // customers: and(isAuthenticated, isAdmin) }, diff --git a/src/resolvers/posts.js b/src/resolvers/posts.js new file mode 100644 index 000000000..6a8a0c25f --- /dev/null +++ b/src/resolvers/posts.js @@ -0,0 +1,22 @@ +import { neo4jgraphql } from 'neo4j-graphql-js' + +export default { + Mutation: { + CreatePost: async (object, params, ctx, resolveInfo) => { + const result = await neo4jgraphql(object, params, ctx, resolveInfo, false) + + const session = ctx.driver.session() + await session.run( + 'MATCH (author:User {id: $userId}), (post:Post {id: $postId}) ' + + 'MERGE (post)<-[:WROTE]-(author) ' + + 'RETURN author', { + userId: ctx.user.id, + postId: result.id + }) + session.close() + + return result + } + + } +} diff --git a/src/resolvers/posts.spec.js b/src/resolvers/posts.spec.js new file mode 100644 index 000000000..a6c1d7e3e --- /dev/null +++ b/src/resolvers/posts.spec.js @@ -0,0 +1,61 @@ +import Factory from '../seed/factories' +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../jest/helpers' + +const factory = Factory() + +beforeEach(async () => { + await factory.create('User', { + email: 'test@example.org', + password: '1234' + }) +}) + +afterEach(async () => { + await factory.cleanDatabase() +}) + +describe('CreatePost', () => { + describe('unauthenticated', () => { + let client + it('throws authorization error', async () => { + client = new GraphQLClient(host) + await expect(client.request(`mutation { + CreatePost( + title: "I am a post", + content: "Some content" + ) { slug } + }`)).rejects.toThrow('Not Authorised') + }) + + describe('authenticated', () => { + let headers + let response + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + response = await client.request(`mutation { + CreatePost( + title: "A title", + content: "Some content" + ) { title, content } + }`, { headers }) + }) + + it('creates a post', () => { + expect(response).toEqual({ CreatePost: { title: 'A title', content: 'Some content' } }) + }) + + it('assigns the authenticated user as author', async () => { + const { User } = await client.request(`{ + User(email:"test@example.org") { + contributions { + title + } + } + }`, { headers }) + expect(User).toEqual([ { contributions: [ { title: 'A title' } ] } ]) + }) + }) + }) +}) diff --git a/src/resolvers/reports.js b/src/resolvers/reports.js new file mode 100644 index 000000000..c471d7b7a --- /dev/null +++ b/src/resolvers/reports.js @@ -0,0 +1,51 @@ +import uuid from 'uuid/v4' + +export default { + Mutation: { + report: async (parent, { resource, description }, { driver, req, user }, resolveInfo) => { + const contextId = uuid() + const session = driver.session() + const data = { + id: contextId, + type: resource.type, + createdAt: (new Date()).toISOString(), + description: resource.description + } + await session.run( + 'CREATE (r:Report $report) ' + + 'RETURN r.id, r.type, r.description', { + report: data + } + ) + let contentType + + switch (resource.type) { + case 'post': + case 'contribution': + contentType = 'Post' + break + case 'comment': + contentType = 'Comment' + break + case 'user': + contentType = 'User' + break + } + + await session.run( + `MATCH (author:User {id: $userId}), (context:${contentType} {id: $resourceId}), (report:Report {id: $contextId}) ` + + 'MERGE (report)<-[:REPORTED]-(author) ' + + 'MERGE (context)<-[:REPORTED]-(report) ' + + 'RETURN context', { + resourceId: resource.id, + userId: user.id, + contextId: contextId + } + ) + session.close() + + // TODO: output Report compatible object + return data + } + } +} diff --git a/src/resolvers/reports.spec.js b/src/resolvers/reports.spec.js new file mode 100644 index 000000000..253cdadcc --- /dev/null +++ b/src/resolvers/reports.spec.js @@ -0,0 +1,68 @@ +import Factory from '../seed/factories' +import { GraphQLClient } from 'graphql-request' +import { host, login } from '../jest/helpers' + +const factory = Factory() + +describe('report', () => { + beforeEach(async () => { + await factory.create('User', { + email: 'test@example.org', + password: '1234' + }) + await factory.create('User', { + id: 'u2', + name: 'abusive-user', + role: 'user', + email: 'abusive-user@example.org' + }) + }) + + afterEach(async () => { + await factory.cleanDatabase() + }) + + describe('unauthenticated', () => { + let client + it('throws authorization error', async () => { + client = new GraphQLClient(host) + await expect( + client.request(`mutation { + report( + description: "I don't like this user", + resource: { + id: "u2", + type: user + } + ) { id, createdAt } + }`) + ).rejects.toThrow('Not Authorised') + }) + + describe('authenticated', () => { + let headers + let response + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + response = await client.request(`mutation { + report( + description: "I don't like this user", + resource: { + id: "u2", + type: user + } + ) { id, createdAt } + }`, + { headers } + ) + }) + it('creates a report', () => { + let { id, createdAt } = response.report + expect(response).toEqual({ + report: { id, createdAt } + }) + }) + }) + }) +}) diff --git a/src/resolvers/statistics.js b/src/resolvers/statistics.js new file mode 100644 index 000000000..17c4be956 --- /dev/null +++ b/src/resolvers/statistics.js @@ -0,0 +1,67 @@ +export const query = (cypher, session) => { + return new Promise((resolve, reject) => { + let data = [] + session + .run(cypher) + .subscribe({ + onNext: function (record) { + let item = {} + record.keys.forEach(key => { + item[key] = record.get(key) + }) + data.push(item) + }, + onCompleted: function () { + session.close() + resolve(data) + }, + onError: function (error) { + reject(error) + } + }) + }) +} +const queryOne = (cypher, session) => { + return new Promise((resolve, reject) => { + query(cypher, session) + .then(res => { + resolve(res.length ? res.pop() : {}) + }) + .catch(err => { + reject(err) + }) + }) +} + +export default { + Query: { + statistics: async (parent, args, { driver, user }) => { + return new Promise(async (resolve) => { + const session = driver.session() + const queries = { + countUsers: 'MATCH (r:User) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countUsers', + countPosts: 'MATCH (r:Post) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countPosts', + countComments: 'MATCH (r:Comment) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countComments', + countNotifications: 'MATCH (r:Notification) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countNotifications', + countOrganizations: 'MATCH (r:Organization) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countOrganizations', + countProjects: 'MATCH (r:Project) WHERE r.deleted <> true OR NOT exists(r.deleted) RETURN COUNT(r) AS countProjects', + countInvites: 'MATCH (r:Invite) WHERE r.wasUsed <> true OR NOT exists(r.wasUsed) RETURN COUNT(r) AS countInvites', + countFollows: 'MATCH (:User)-[r:FOLLOWS]->(:User) RETURN COUNT(r) AS countFollows', + countShouts: 'MATCH (:User)-[r:SHOUTED]->(:Post) RETURN COUNT(r) AS countShouts' + } + let data = { + countUsers: (await queryOne(queries.countUsers, session)).countUsers.low, + countPosts: (await queryOne(queries.countPosts, session)).countPosts.low, + countComments: (await queryOne(queries.countComments, session)).countComments.low, + countNotifications: (await queryOne(queries.countNotifications, session)).countNotifications.low, + countOrganizations: (await queryOne(queries.countOrganizations, session)).countOrganizations.low, + countProjects: (await queryOne(queries.countProjects, session)).countProjects.low, + countInvites: (await queryOne(queries.countInvites, session)).countInvites.low, + countFollows: (await queryOne(queries.countFollows, session)).countFollows.low, + countShouts: (await queryOne(queries.countShouts, session)).countShouts.low + } + resolve(data) + }) + } + } +} diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js new file mode 100644 index 000000000..b0c9d3df5 --- /dev/null +++ b/src/resolvers/user_management.js @@ -0,0 +1,52 @@ +import encode from '../jwt/encode' +import { fixUrl } from '../middleware/fixImageUrlsMiddleware' +import bcrypt from 'bcryptjs' +import { AuthenticationError } from 'apollo-server' + +export default { + Query: { + isLoggedIn: (parent, args, { driver, user }) => { + return Boolean(user && user.id) + }, + currentUser: (parent, args, { user }) => { + return user + } + }, + Mutation: { + signup: async (parent, { email, password }, { req }) => { + // if (data[email]) { + // throw new Error('Another User with same email exists.') + // } + // data[email] = { + // password: await bcrypt.hashSync(password, 10), + // } + + return true + }, + login: async (parent, { email, password }, { driver, req, user }) => { + // if (user && user.id) { + // throw new Error('Already logged in.') + // } + const session = driver.session() + return session.run( + 'MATCH (user:User {email: $userEmail}) ' + + 'RETURN user {.id, .slug, .name, .avatar, .email, .password, .role} as user LIMIT 1', { + userEmail: email + }) + .then(async (result) => { + session.close() + const [currentUser] = await result.records.map(function (record) { + return record.get('user') + }) + + if (currentUser && await bcrypt.compareSync(password, currentUser.password)) { + delete currentUser.password + currentUser.avatar = fixUrl(currentUser.avatar) + return Object.assign(currentUser, { + token: encode(currentUser) + }) + } else throw new AuthenticationError('Incorrect email address or password.') + }) + } + } +} diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js new file mode 100644 index 000000000..cb12efb2d --- /dev/null +++ b/src/resolvers/user_management.spec.js @@ -0,0 +1,183 @@ +import Factory from '../seed/factories' +import { GraphQLClient, request } from 'graphql-request' +import jwt from 'jsonwebtoken' +import { host, login } from '../jest/helpers' + +const factory = Factory() + +// here is the decoded JWT token: +// { +// role: 'user', +// locationName: null, +// name: 'Jenny Rostock', +// about: null, +// avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/sasha_shestakov/128.jpg', +// id: 'u3', +// email: 'user@example.org', +// slug: 'jenny-rostock', +// iat: 1550846680, +// exp: 1637246680, +// aud: 'http://localhost:3000', +// iss: 'http://localhost:4000', +// sub: 'u3' +// } +const jennyRostocksHeaders = { authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoidXNlciIsImxvY2F0aW9uTmFtZSI6bnVsbCwibmFtZSI6Ikplbm55IFJvc3RvY2siLCJhYm91dCI6bnVsbCwiYXZhdGFyIjoiaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL3VpZmFjZXMvZmFjZXMvdHdpdHRlci9zYXNoYV9zaGVzdGFrb3YvMTI4LmpwZyIsImlkIjoidTMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5vcmciLCJzbHVnIjoiamVubnktcm9zdG9jayIsImlhdCI6MTU1MDg0NjY4MCwiZXhwIjoxNjM3MjQ2NjgwLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjMwMDAiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjQwMDAiLCJzdWIiOiJ1MyJ9.eZ_mVKas4Wzoc_JrQTEWXyRn7eY64cdIg4vqQ-F_7Jc' } + +beforeEach(async () => { + await factory.create('User', { + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', + id: 'acb2d923-f3af-479e-9f00-61b12e864666', + name: 'Matilde Hermiston', + slug: 'matilde-hermiston', + role: 'user', + email: 'test@example.org', + password: '1234' + }) +}) + +afterEach(async () => { + await factory.cleanDatabase() +}) + +describe('isLoggedIn', () => { + const query = '{ isLoggedIn }' + describe('unauthenticated', () => { + it('returns false', async () => { + await expect(request(host, query)).resolves.toEqual({ isLoggedIn: false }) + }) + }) + + describe('with malformed JWT Bearer token', () => { + const headers = { authorization: 'blah' } + const client = new GraphQLClient(host, { headers }) + + it('returns false', async () => { + await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false }) + }) + }) + + describe('with valid JWT Bearer token', () => { + const client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) + + it('returns false', async () => { + await expect(client.request(query)).resolves.toEqual({ isLoggedIn: false }) + }) + + describe('and a corresponding user in the database', () => { + it('returns true', async () => { + // see the decoded token above + await factory.create('User', { id: 'u3' }) + await expect(client.request(query)).resolves.toEqual({ isLoggedIn: true }) + }) + }) + }) +}) + +describe('currentUser', () => { + const query = `{ + currentUser { + id + slug + name + avatar + email + role + token + } + }` + + describe('unauthenticated', () => { + it('returns null', async () => { + const expected = { currentUser: null } + await expect(request(host, query)).resolves.toEqual(expected) + }) + }) + + describe('with valid JWT Bearer Token', () => { + let client + let headers + + describe('but no corresponding user in the database', () => { + beforeEach(async () => { + client = new GraphQLClient(host, { headers: jennyRostocksHeaders }) + }) + + it('returns null', async () => { + const expected = { currentUser: null } + await expect(client.request(query)).resolves.toEqual(expected) + }) + }) + + describe('and corresponding user in the database', () => { + beforeEach(async () => { + headers = await login({ email: 'test@example.org', password: '1234' }) + client = new GraphQLClient(host, { headers }) + }) + + it('returns the whole user object', async () => { + const expected = { + currentUser: { + avatar: 'https://s3.amazonaws.com/uifaces/faces/twitter/seyedhossein1/128.jpg', + email: 'test@example.org', + id: 'acb2d923-f3af-479e-9f00-61b12e864666', + name: 'Matilde Hermiston', + slug: 'matilde-hermiston', + role: 'user', + token: headers.authorization.replace('Bearer ', '') + } + } + await expect(client.request(query)).resolves.toEqual(expected) + }) + }) + }) +}) + +describe('login', () => { + const mutation = (params) => { + const { email, password } = params + return ` + mutation { + login(email:"${email}", password:"${password}"){ + token + } + }` + } + + describe('ask for a `token`', () => { + describe('with valid email/password combination', () => { + it('responds with a JWT token', async () => { + const data = await request(host, mutation({ + email: 'test@example.org', + password: '1234' + })) + const { token } = data.login + jwt.verify(token, process.env.JWT_SECRET, (err, data) => { + expect(data.email).toEqual('test@example.org') + expect(err).toBeNull() + }) + }) + }) + + describe('with a valid email but incorrect password', () => { + it('responds with "Incorrect email address or password."', async () => { + await expect( + request(host, mutation({ + email: 'test@example.org', + password: 'wrong' + })) + ).rejects.toThrow('Incorrect email address or password.') + }) + }) + + describe('with a non-existing email', () => { + it('responds with "Incorrect email address or password."', async () => { + await expect( + request(host, mutation({ + email: 'non-existent@example.org', + password: 'wrong' + })) + ).rejects.toThrow('Incorrect email address or password.') + }) + }) + }) +}) diff --git a/src/schema.graphql b/src/schema.graphql index 55f23d5ca..4413e1deb 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -1,5 +1,6 @@ type Query { isLoggedIn: Boolean! + currentUser: LoggedInUser statistics: Statistics! } type Mutation { @@ -7,6 +8,7 @@ type Mutation { signup(email: String!, password: String!): Boolean! report(resource: Resource!, description: String): Report } + type LoggedInUser { id: ID! slug: String! @@ -14,8 +16,6 @@ type LoggedInUser { avatar:String! email: String! role: String! - locationName: String - about: String token: String! } diff --git a/src/server.js b/src/server.js index 5867e6952..2fc3af871 100644 --- a/src/server.js +++ b/src/server.js @@ -8,10 +8,7 @@ import middleware from './middleware' import applyDirectives from './bootstrap/directives' import applyScalars from './bootstrap/scalars' import { getDriver } from './bootstrap/neo4j' - -import passport from 'passport' -import jwtStrategy from './jwt/strategy' -import jwt from 'jsonwebtoken' +import decode from './jwt/decode' dotenv.config() // check env and warn @@ -42,20 +39,14 @@ schema = applyScalars(applyDirectives(schema)) const createServer = (options) => { const defaults = { - context: async (req) => { - const payload = { + context: async ({ request }) => { + const authorizationHeader = request.headers.authorization || '' + const user = await decode(driver, authorizationHeader) + return { driver, - user: null, - req: req.request + user, + req: request } - try { - const token = payload.req.headers.authorization.replace('Bearer ', '') - payload.user = await jwt.verify(token, process.env.JWT_SECRET) - } catch (err) { - // nothing - } - - return payload }, schema: schema, debug: debug, @@ -65,11 +56,7 @@ const createServer = (options) => { } const server = new GraphQLServer(Object.assign({}, defaults, options)) - passport.use('jwt', jwtStrategy(driver)) - server.express.use(passport.initialize()) server.express.use(express.static('public')) - - server.express.post('/graphql', passport.authenticate(['jwt'], { session: false })) return server } diff --git a/yarn.lock b/yarn.lock index 2fe610fee..5ec9c94a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4348,7 +4348,7 @@ jsonify@~0.0.0: resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= -jsonwebtoken@^8.2.0, jsonwebtoken@~8.5.0: +jsonwebtoken@~8.5.0: version "8.5.0" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz#ebd0ca2a69797816e1c5af65b6c759787252947e" integrity sha512-IqEycp0znWHNA11TpYi77bVgyBO/pGESDh7Ajhas+u0ttkGkKYIIAjniL4Bw5+oVejVF+SYkaI7XKfwCCyeTuA== @@ -5348,27 +5348,6 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= -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-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-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -5423,11 +5402,6 @@ pathval@^1.1.0: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= -pause@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" - integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" From 5fd44230ddc5660757185a78b572979da0d5e6de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Sch=C3=A4fer?= Date: Wed, 27 Feb 2019 10:42:55 +0100 Subject: [PATCH 2/6] Get rid of LoggedInUser graphql type This was causing a lot of headache on the frontend. Now, there a single source of truth. If you query `currentUser` you can overwrite your local copy of the user and update the UI. --- src/jest/helpers.js | 6 ++---- src/resolvers/user_management.js | 15 +++++++-------- src/resolvers/user_management.spec.js | 10 +++------- src/schema.graphql | 14 ++------------ src/seed/factories/index.js | 6 ++---- 5 files changed, 16 insertions(+), 35 deletions(-) diff --git a/src/jest/helpers.js b/src/jest/helpers.js index ff6a535e2..0d358ed40 100644 --- a/src/jest/helpers.js +++ b/src/jest/helpers.js @@ -7,12 +7,10 @@ export const host = 'http://127.0.0.1:4123' export async function login ({ email, password }) { const mutation = ` mutation { - login(email:"${email}", password:"${password}"){ - token - } + login(email:"${email}", password:"${password}") }` const response = await request(host, mutation) return { - authorization: `Bearer ${response.login.token}` + authorization: `Bearer ${response.login}` } } diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js index b0c9d3df5..552f6201a 100644 --- a/src/resolvers/user_management.js +++ b/src/resolvers/user_management.js @@ -1,16 +1,18 @@ import encode from '../jwt/encode' -import { fixUrl } from '../middleware/fixImageUrlsMiddleware' import bcrypt from 'bcryptjs' import { AuthenticationError } from 'apollo-server' +import { neo4jgraphql } from 'neo4j-graphql-js' export default { Query: { isLoggedIn: (parent, args, { driver, user }) => { return Boolean(user && user.id) }, - currentUser: (parent, args, { user }) => { - return user - } + currentUser: async (object, params, ctx, resolveInfo) => { + const { user} = ctx + if(!user) return null + return neo4jgraphql(object, {id: user.id}, ctx, resolveInfo, false) + }, }, Mutation: { signup: async (parent, { email, password }, { req }) => { @@ -41,10 +43,7 @@ export default { if (currentUser && await bcrypt.compareSync(password, currentUser.password)) { delete currentUser.password - currentUser.avatar = fixUrl(currentUser.avatar) - return Object.assign(currentUser, { - token: encode(currentUser) - }) + return encode(currentUser) } else throw new AuthenticationError('Incorrect email address or password.') }) } diff --git a/src/resolvers/user_management.spec.js b/src/resolvers/user_management.spec.js index cb12efb2d..a3bf6fdd0 100644 --- a/src/resolvers/user_management.spec.js +++ b/src/resolvers/user_management.spec.js @@ -82,7 +82,6 @@ describe('currentUser', () => { avatar email role - token } }` @@ -122,8 +121,7 @@ describe('currentUser', () => { id: 'acb2d923-f3af-479e-9f00-61b12e864666', name: 'Matilde Hermiston', slug: 'matilde-hermiston', - role: 'user', - token: headers.authorization.replace('Bearer ', '') + role: 'user' } } await expect(client.request(query)).resolves.toEqual(expected) @@ -137,9 +135,7 @@ describe('login', () => { const { email, password } = params return ` mutation { - login(email:"${email}", password:"${password}"){ - token - } + login(email:"${email}", password:"${password}") }` } @@ -150,7 +146,7 @@ describe('login', () => { email: 'test@example.org', password: '1234' })) - const { token } = data.login + const token = data.login jwt.verify(token, process.env.JWT_SECRET, (err, data) => { expect(data.email).toEqual('test@example.org') expect(err).toBeNull() diff --git a/src/schema.graphql b/src/schema.graphql index 4413e1deb..1f9bcb477 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -1,24 +1,14 @@ type Query { isLoggedIn: Boolean! - currentUser: LoggedInUser + currentUser: User statistics: Statistics! } type Mutation { - login(email: String!, password: String!): LoggedInUser + login(email: String!, password: String!): String! signup(email: String!, password: String!): Boolean! report(resource: Resource!, description: String): Report } -type LoggedInUser { - id: ID! - slug: String! - name: String! - avatar:String! - email: String! - role: String! - token: String! -} - type Statistics { countUsers: Int! countPosts: Int! diff --git a/src/seed/factories/index.js b/src/seed/factories/index.js index d9bbd700c..ed35d2c3b 100644 --- a/src/seed/factories/index.js +++ b/src/seed/factories/index.js @@ -15,13 +15,11 @@ export const seedServerHost = 'http://127.0.0.1:4001' const authenticatedHeaders = async ({ email, password }, host) => { const mutation = ` mutation { - login(email:"${email}", password:"${password}"){ - token - } + login(email:"${email}", password:"${password}") }` const response = await request(host, mutation) return { - authorization: `Bearer ${response.login.token}` + authorization: `Bearer ${response.login}` } } const factories = { From f9b60fa0b0b7bbec42eab38c22e39d58695c066d Mon Sep 17 00:00:00 2001 From: Matt Rider Date: Wed, 27 Feb 2019 08:10:20 -0300 Subject: [PATCH 3/6] Fix lint --- src/resolvers/user_management.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/resolvers/user_management.js b/src/resolvers/user_management.js index 552f6201a..ec4ae7ce2 100644 --- a/src/resolvers/user_management.js +++ b/src/resolvers/user_management.js @@ -9,10 +9,10 @@ export default { return Boolean(user && user.id) }, currentUser: async (object, params, ctx, resolveInfo) => { - const { user} = ctx - if(!user) return null - return neo4jgraphql(object, {id: user.id}, ctx, resolveInfo, false) - }, + const { user } = ctx + if (!user) return null + return neo4jgraphql(object, { id: user.id }, ctx, resolveInfo, false) + } }, Mutation: { signup: async (parent, { email, password }, { req }) => { From e74962a2beb2b8ea351a3df92e06afa58a200890 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 28 Feb 2019 04:29:33 +0000 Subject: [PATCH 4/6] Bump apollo-cache-inmemory from 1.5.0 to 1.5.1 Bumps [apollo-cache-inmemory](https://github.com/apollographql/apollo-client) from 1.5.0 to 1.5.1. - [Release notes](https://github.com/apollographql/apollo-client/releases) - [Changelog](https://github.com/apollographql/apollo-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/apollographql/apollo-client/compare/apollo-cache-inmemory@1.5.0...apollo-cache-inmemory@1.5.1) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 1ff3ce9ab..f39b28a22 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ ] }, "dependencies": { - "apollo-cache-inmemory": "~1.5.0", + "apollo-cache-inmemory": "~1.5.1", "apollo-client": "~2.5.1", "apollo-link-http": "~1.5.11", "apollo-server": "~2.4.8", diff --git a/yarn.lock b/yarn.lock index ab8c1d402..15f107045 100644 --- a/yarn.lock +++ b/yarn.lock @@ -961,18 +961,18 @@ apollo-cache-control@^0.1.0: dependencies: graphql-extensions "^0.0.x" -apollo-cache-inmemory@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.5.0.tgz#90b1a38f744762ab47c415b9d7b2d32fbd803088" - integrity sha512-hyg8R7G3XOfZhl8fQLs0vGEwi2rr8PuEIiumCY4qmwviaGsmwjs/Dm63cyeMm3Sfu05vzFQkwMdBf5u7xBg3cQ== +apollo-cache-inmemory@~1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/apollo-cache-inmemory/-/apollo-cache-inmemory-1.5.1.tgz#265d1ee67b0bf0aca9c37629d410bfae44e62953" + integrity sha512-D3bdpPmWfaKQkWy8lfwUg+K8OBITo3sx0BHLs1B/9vIdOIZ7JNCKq3EUcAgAfInomJUdN0QG1yOfi8M8hxkN1g== dependencies: - apollo-cache "^1.2.0" - apollo-utilities "^1.2.0" + apollo-cache "^1.2.1" + apollo-utilities "^1.2.1" optimism "^0.6.9" ts-invariant "^0.2.1" tslib "^1.9.3" -apollo-cache@1.2.1, apollo-cache@^1.2.0: +apollo-cache@1.2.1, apollo-cache@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/apollo-cache/-/apollo-cache-1.2.1.tgz#aae71eb4a11f1f7322adc343f84b1a39b0693644" integrity sha512-nzFmep/oKlbzUuDyz6fS6aYhRmfpcHWqNkkA9Bbxwk18RD6LXC4eZkuE0gXRX0IibVBHNjYVK+Szi0Yied4SpQ== @@ -1264,7 +1264,7 @@ apollo-upload-server@^7.0.0: http-errors "^1.7.0" object-path "^0.11.4" -apollo-utilities@1.2.1, apollo-utilities@^1.0.1, apollo-utilities@^1.2.0, apollo-utilities@^1.2.1: +apollo-utilities@1.2.1, apollo-utilities@^1.0.1, apollo-utilities@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.2.1.tgz#1c3a1ebf5607d7c8efe7636daaf58e7463b41b3c" integrity sha512-Zv8Udp9XTSFiN8oyXOjf6PMHepD4yxxReLsl6dPUy5Ths7jti3nmlBzZUOxuTWRwZn0MoclqL7RQ5UEJN8MAxg== From 4b2ca9368b6eb155175426b7d9f21cecd4194699 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 28 Feb 2019 08:58:00 +0000 Subject: [PATCH 5/6] Bump apollo-server-testing from 2.4.2 to 2.4.8 Bumps [apollo-server-testing](https://github.com/apollographql/apollo-server) from 2.4.2 to 2.4.8. - [Release notes](https://github.com/apollographql/apollo-server/releases) - [Changelog](https://github.com/apollographql/apollo-server/blob/master/CHANGELOG.md) - [Commits](https://github.com/apollographql/apollo-server/compare/apollo-server-testing@2.4.2...apollo-server-testing@2.4.8) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 81 ++++------------------------------------------------ 2 files changed, 6 insertions(+), 77 deletions(-) diff --git a/package.json b/package.json index f39b28a22..50b2eddf3 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@babel/node": "~7.2.2", "@babel/preset-env": "~7.3.1", "@babel/register": "~7.0.0", - "apollo-server-testing": "~2.4.2", + "apollo-server-testing": "~2.4.8", "babel-core": "~7.0.0-0", "babel-eslint": "~10.0.1", "babel-jest": "~24.1.0", diff --git a/yarn.lock b/yarn.lock index 15f107045..70a337743 100644 --- a/yarn.lock +++ b/yarn.lock @@ -938,14 +938,6 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -apollo-cache-control@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.5.1.tgz#db7e86cd7ede6cad0a2e0ea97488d9fb5c33d913" - integrity sha512-82hzX7/fFiu5dODLS8oGieEE4jLjMIhIkQ4JTsWj9drv8PZJltl0xqORtU2jA/FottjxfYab8+ebi3BgGPOaqw== - dependencies: - apollo-server-env "2.2.0" - graphql-extensions "0.5.2" - apollo-cache-control@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.5.2.tgz#47931ede0b11c64d45429850c274b30d19322362" @@ -1010,18 +1002,6 @@ apollo-engine-reporting-protobuf@0.2.1: dependencies: protobufjs "^6.8.6" -apollo-engine-reporting@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.0.2.tgz#5dd5411f17d76e6788a1166367a2ab7b52794224" - integrity sha512-g6JkO5WaMuqXfn3WoZMQyyFzpxfHsw/f7P7XTHSEqTSd/M4uk7/uih/xcqmgBGt4ET30KbaGFz2l4FJzO06A5w== - dependencies: - apollo-engine-reporting-protobuf "0.2.1" - apollo-graphql "^0.1.0" - apollo-server-core "2.4.2" - apollo-server-env "2.2.0" - async-retry "^1.2.1" - graphql-extensions "0.5.2" - apollo-engine-reporting@1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/apollo-engine-reporting/-/apollo-engine-reporting-1.0.7.tgz#d326b51b12b1f71a40885b8189dbcd162171c953" @@ -1085,32 +1065,6 @@ apollo-server-caching@0.3.1: dependencies: lru-cache "^5.0.0" -apollo-server-core@2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.4.2.tgz#916d98636b1bf576a84b4a469006c1c73741e03a" - integrity sha512-IOWhqjjI1sH38sj7ycjke0dXXEgaqOkb2hDpLBTSiVWKBIqFfo4gchWK5wcWW9jReDpf/+G2wogH+UvONs2ejg== - dependencies: - "@apollographql/apollo-tools" "^0.3.3" - "@apollographql/graphql-playground-html" "^1.6.6" - "@types/ws" "^6.0.0" - apollo-cache-control "0.5.1" - apollo-datasource "0.3.1" - apollo-engine-reporting "1.0.2" - apollo-server-caching "0.3.1" - apollo-server-env "2.2.0" - apollo-server-errors "2.2.0" - apollo-server-plugin-base "0.3.2" - apollo-tracing "0.5.1" - fast-json-stable-stringify "^2.0.0" - graphql-extensions "0.5.2" - graphql-subscriptions "^1.0.0" - graphql-tag "^2.9.2" - graphql-tools "^4.0.0" - graphql-upload "^8.0.2" - sha.js "^2.4.11" - subscriptions-transport-ws "^0.9.11" - ws "^6.0.0" - apollo-server-core@2.4.8: version "2.4.8" resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.4.8.tgz#47e503a345e314222725597c889773e018d8c67a" @@ -1154,11 +1108,6 @@ apollo-server-env@2.2.0: node-fetch "^2.1.2" util.promisify "^1.0.0" -apollo-server-errors@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.2.0.tgz#5b452a1d6ff76440eb0f127511dc58031a8f3cb5" - integrity sha512-gV9EZG2tovFtT1cLuCTavnJu2DaKxnXPRNGSTo+SDI6IAk6cdzyW0Gje5N2+3LybI0Wq5KAbW6VLei31S4MWmg== - apollo-server-errors@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.2.1.tgz#f68a3f845929768057da7e1c6d30517db5872205" @@ -1203,22 +1152,17 @@ apollo-server-module-graphiql@^1.3.4, apollo-server-module-graphiql@^1.4.0: resolved "https://registry.yarnpkg.com/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.4.0.tgz#c559efa285578820709f1769bb85d3b3eed3d8ec" integrity sha512-GmkOcb5he2x5gat+TuiTvabnBf1m4jzdecal3XbXBh/Jg+kx4hcvO3TTDFQ9CuTprtzdcVyA11iqG7iOMOt7vA== -apollo-server-plugin-base@0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.3.2.tgz#4609c9a9d154568401d84b7ac17d1e30e3529104" - integrity sha512-yzXrkVSPBoux2uPgbTGROGh7W0axRWopMZM+KT9aF9H/+yMCwtt0EhGOGyNUDMOFA4rT3z+cLVvYuZr1rSQWcg== - apollo-server-plugin-base@0.3.7: version "0.3.7" resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.3.7.tgz#bfa4932fc9481bb36221545578d311db464af5a6" integrity sha512-hW1jaLKf9qNOxMTwRq2CSqz3eqXsZuEiCc8/mmEtOciiVBq1GMtxFf19oIYM9HQuPvQU2RWpns1VrYN59L3vbg== -apollo-server-testing@~2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.4.2.tgz#5c87b34b0b6a1a3e5a1784cadc16bc495dded2e1" - integrity sha512-WZ901nh7uG75342lMukJvuxFF/w3W5JDyWElY8KDhXfaDLbMKqhRqaWRIiEEX4YvciO5ACSzqKt+957/y1yUUQ== +apollo-server-testing@~2.4.8: + version "2.4.8" + resolved "https://registry.yarnpkg.com/apollo-server-testing/-/apollo-server-testing-2.4.8.tgz#eb929a431e059723c298919688355434d53e3ea8" + integrity sha512-AmNn5pDn9FJ9AJbmc7gwsUFaUt4uf44IFHaCfZow/jkAeY2JZnIozt8LYC8Koidy+Lfb+i/HsjkgbBodElbGMQ== dependencies: - apollo-server-core "2.4.2" + apollo-server-core "2.4.8" apollo-server@~2.4.8: version "2.4.8" @@ -1231,14 +1175,6 @@ apollo-server@~2.4.8: graphql-subscriptions "^1.0.0" graphql-tools "^4.0.0" -apollo-tracing@0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.5.1.tgz#16be201bc276120f0f8b7aa180201ee89d57e3bd" - integrity sha512-5gb8OWzkGaJFsmQdyMyZnOjcq6weMTkqJSGj0hfR7uX99X4SBFAzZV4nTeK4z0XkXO2I12xSTJoS4gxbFjgeaA== - dependencies: - apollo-server-env "2.2.0" - graphql-extensions "0.5.2" - apollo-tracing@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.5.2.tgz#cc49936fb435fa98d19c841514cfe05237c85b33" @@ -3164,13 +3100,6 @@ graphql-deduplicator@^2.0.1: resolved "https://registry.yarnpkg.com/graphql-deduplicator/-/graphql-deduplicator-2.0.2.tgz#d8608161cf6be97725e178df0c41f6a1f9f778f3" integrity sha512-0CGmTmQh4UvJfsaTPppJAcHwHln8Ayat7yXXxdnuWT+Mb1dBzkbErabCWzjXyKh/RefqlGTTA7EQOZHofMaKJA== -graphql-extensions@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.5.2.tgz#cdced94c1931c9983fffcc144e336d6cd4d8b02b" - integrity sha512-D/FAvjYEZ8GM3vfALxRvItozy5iLUfzyoauE2lli+0OuUBCAZDLP0fgqeTFK93NnQX/XSjBVGhcuDWBB7JesEw== - dependencies: - "@apollographql/apollo-tools" "^0.3.3" - graphql-extensions@0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.5.4.tgz#18a9674f9adb11aa6c0737485887ea8877914cff" From 57c24f62d19b99174026ec6158817186a390579c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Thu, 28 Feb 2019 09:25:48 +0000 Subject: [PATCH 6/6] Bump @babel/preset-env from 7.3.1 to 7.3.4 Bumps [@babel/preset-env](https://github.com/babel/babel) from 7.3.1 to 7.3.4. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md) - [Commits](https://github.com/babel/babel/compare/v7.3.1...v7.3.4) Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 132 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 92 insertions(+), 42 deletions(-) diff --git a/package.json b/package.json index 50b2eddf3..c276a09d7 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "@babel/cli": "~7.2.3", "@babel/core": "~7.3.3", "@babel/node": "~7.2.2", - "@babel/preset-env": "~7.3.1", + "@babel/preset-env": "~7.3.4", "@babel/register": "~7.0.0", "apollo-server-testing": "~2.4.8", "babel-core": "~7.0.0-0", diff --git a/yarn.lock b/yarn.lock index 70a337743..c36e11172 100644 --- a/yarn.lock +++ b/yarn.lock @@ -69,6 +69,17 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e" + integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg== + dependencies: + "@babel/types" "^7.3.4" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -199,6 +210,16 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-replace-supers@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.3.4.tgz#a795208e9b911a6eeb08e5891faacf06e7013e13" + integrity sha512-pvObL9WVf2ADs+ePg0jrqlhHoxRXlOa+SHRHzAXIz2xkYuOHfGl+fKxPMaS4Fq+uje8JQPobnertBBvyrWnQ1A== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.0.0" + "@babel/helper-optimise-call-expression" "^7.0.0" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -258,6 +279,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.3.tgz#092d450db02bdb6ccb1ca8ffd47d8774a91aef87" integrity sha512-xsH1CJoln2r74hR+y7cg2B5JCPaTh+Hd+EbBRk9nWGSNspuo6krjhX0Om6RnRQuIvFq8wVXCLKH3kwKDYhanSg== +"@babel/parser@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" + integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ== + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -275,10 +301,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-json-strings" "^7.2.0" -"@babel/plugin-proposal-object-rest-spread@^7.3.1": - version "7.3.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.2.tgz#6d1859882d4d778578e41f82cc5d7bf3d5daf6c1" - integrity sha512-DjeMS+J2+lpANkYLLO+m6GjoTMygYglKmRe6cDTbFv3L9i6mmiE8fe6B8MtCSLZpVXscD5kn7s6SgtHrDoBWoA== +"@babel/plugin-proposal-object-rest-spread@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.3.4.tgz#47f73cf7f2a721aad5c0261205405c642e424654" + integrity sha512-j7VQmbbkA+qrzNqbKHrBsW3ddFnOeva6wzSe/zB7T+xaxGc+RCpwo44wCmRixAIGRoIpmVgvzFzNJqQcO3/9RA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" @@ -335,10 +361,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-async-to-generator@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.2.0.tgz#68b8a438663e88519e65b776f8938f3445b1a2ff" - integrity sha512-CEHzg4g5UraReozI9D4fblBYABs7IM6UerAVG7EJVrTLC5keh00aEuLUT+O40+mJCEzaXkYfTCUKIyeDfMOFFQ== +"@babel/plugin-transform-async-to-generator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.3.4.tgz#4e45408d3c3da231c0e7b823f407a53a7eb3048c" + integrity sha512-Y7nCzv2fw/jEZ9f678MuKdMo99MFDJMT/PvD9LisrR5JDFcJH6vYeH6RnjVt3p5tceyGRvTtEN0VOlU+rgHZjA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -351,25 +377,25 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-block-scoping@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.2.0.tgz#f17c49d91eedbcdf5dd50597d16f5f2f770132d4" - integrity sha512-vDTgf19ZEV6mx35yiPJe4fS02mPQUUcBNwWQSZFXSzTSbsJFQvHt7DqyS3LK8oOWALFOsJ+8bbqBgkirZteD5Q== +"@babel/plugin-transform-block-scoping@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.3.4.tgz#5c22c339de234076eee96c8783b2fed61202c5c4" + integrity sha512-blRr2O8IOZLAOJklXLV4WhcEzpYafYQKSGT3+R26lWG41u/FODJuBggehtOwilVAcFu393v3OFj+HmaE6tVjhA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - lodash "^4.17.10" + lodash "^4.17.11" -"@babel/plugin-transform-classes@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.0.tgz#374f8876075d7d21fea55aeb5c53561259163f96" - integrity sha512-aPCEkrhJYebDXcGTAP+cdUENkH7zqOlgbKwLbghjjHpJRJBWM/FSlCjMoPGA8oUdiMfOrk3+8EFPLLb5r7zj2w== +"@babel/plugin-transform-classes@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.3.4.tgz#dc173cb999c6c5297e0b5f2277fdaaec3739d0cc" + integrity sha512-J9fAvCFBkXEvBimgYxCjvaVDzL6thk0j0dBvCeZmIUDBwyt+nv6HfbImsSrWsYXfDNDivyANgJlFXDUWRTZBuA== dependencies: "@babel/helper-annotate-as-pure" "^7.0.0" "@babel/helper-define-map" "^7.1.0" "@babel/helper-function-name" "^7.1.0" "@babel/helper-optimise-call-expression" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" - "@babel/helper-replace-supers" "^7.1.0" + "@babel/helper-replace-supers" "^7.3.4" "@babel/helper-split-export-declaration" "^7.0.0" globals "^11.1.0" @@ -450,10 +476,10 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" -"@babel/plugin-transform-modules-systemjs@^7.2.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.2.0.tgz#912bfe9e5ff982924c81d0937c92d24994bb9068" - integrity sha512-aYJwpAhoK9a+1+O625WIjvMY11wkB/ok0WClVwmeo3mCjcNRjt+/8gHWrB5i+00mUju0gWsBkQnPpdvQ7PImmQ== +"@babel/plugin-transform-modules-systemjs@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.3.4.tgz#813b34cd9acb6ba70a84939f3680be0eb2e58861" + integrity sha512-VZ4+jlGOF36S7TjKs8g4ojp4MEI+ebCQZdswWb/T9I4X84j8OtFAyjXjt/M16iIm5RIZn0UMQgg/VgIwo/87vw== dependencies: "@babel/helper-hoist-variables" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" @@ -497,12 +523,12 @@ "@babel/helper-get-function-arity" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-regenerator@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz#5b41686b4ed40bef874d7ed6a84bdd849c13e0c1" - integrity sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw== +"@babel/plugin-transform-regenerator@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.3.4.tgz#1601655c362f5b38eead6a52631f5106b29fa46a" + integrity sha512-hvJg8EReQvXT6G9H2MvNPXkv9zK36Vxa1+csAVTpE1J3j0zlHplw76uudEbJxgvqZzAq9Yh45FLD4pk5mKRFQA== dependencies: - regenerator-transform "^0.13.3" + regenerator-transform "^0.13.4" "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" @@ -558,16 +584,16 @@ core-js "^2.5.7" regenerator-runtime "^0.11.1" -"@babel/preset-env@~7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.1.tgz#389e8ca6b17ae67aaf9a2111665030be923515db" - integrity sha512-FHKrD6Dxf30e8xgHQO0zJZpUPfVZg+Xwgz5/RdSWCbza9QLNk4Qbp40ctRoqDxml3O8RMzB1DU55SXeDG6PqHQ== +"@babel/preset-env@~7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.4.tgz#887cf38b6d23c82f19b5135298bdb160062e33e1" + integrity sha512-2mwqfYMK8weA0g0uBKOt4FE3iEodiHy9/CW0b+nWXcbL+pGzLx8ESYc+j9IIxr6LTDHWKgPm71i9smo02bw+gA== dependencies: "@babel/helper-module-imports" "^7.0.0" "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-proposal-async-generator-functions" "^7.2.0" "@babel/plugin-proposal-json-strings" "^7.2.0" - "@babel/plugin-proposal-object-rest-spread" "^7.3.1" + "@babel/plugin-proposal-object-rest-spread" "^7.3.4" "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" "@babel/plugin-proposal-unicode-property-regex" "^7.2.0" "@babel/plugin-syntax-async-generators" "^7.2.0" @@ -575,10 +601,10 @@ "@babel/plugin-syntax-object-rest-spread" "^7.2.0" "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" "@babel/plugin-transform-arrow-functions" "^7.2.0" - "@babel/plugin-transform-async-to-generator" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.3.4" "@babel/plugin-transform-block-scoped-functions" "^7.2.0" - "@babel/plugin-transform-block-scoping" "^7.2.0" - "@babel/plugin-transform-classes" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.3.4" + "@babel/plugin-transform-classes" "^7.3.4" "@babel/plugin-transform-computed-properties" "^7.2.0" "@babel/plugin-transform-destructuring" "^7.2.0" "@babel/plugin-transform-dotall-regex" "^7.2.0" @@ -589,13 +615,13 @@ "@babel/plugin-transform-literals" "^7.2.0" "@babel/plugin-transform-modules-amd" "^7.2.0" "@babel/plugin-transform-modules-commonjs" "^7.2.0" - "@babel/plugin-transform-modules-systemjs" "^7.2.0" + "@babel/plugin-transform-modules-systemjs" "^7.3.4" "@babel/plugin-transform-modules-umd" "^7.2.0" "@babel/plugin-transform-named-capturing-groups-regex" "^7.3.0" "@babel/plugin-transform-new-target" "^7.0.0" "@babel/plugin-transform-object-super" "^7.2.0" "@babel/plugin-transform-parameters" "^7.2.0" - "@babel/plugin-transform-regenerator" "^7.0.0" + "@babel/plugin-transform-regenerator" "^7.3.4" "@babel/plugin-transform-shorthand-properties" "^7.2.0" "@babel/plugin-transform-spread" "^7.2.0" "@babel/plugin-transform-sticky-regex" "^7.2.0" @@ -651,6 +677,21 @@ globals "^11.1.0" lodash "^4.17.10" +"@babel/traverse@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06" + integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.3.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.0.0" + "@babel/parser" "^7.3.4" + "@babel/types" "^7.3.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + "@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.3": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.3.tgz#6c44d1cdac2a7625b624216657d5bc6c107ab436" @@ -660,6 +701,15 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.3.4": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed" + integrity sha512-WEkp8MsLftM7O/ty580wAmZzN1nDmCACc5+jFzUt+GUFNNIi3LdRlueYz0YIlmJhlZx1QYDMZL5vdWCL0fNjFQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -5790,10 +5840,10 @@ regenerator-runtime@^0.12.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== -regenerator-transform@^0.13.3: - version "0.13.3" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.3.tgz#264bd9ff38a8ce24b06e0636496b2c856b57bcbb" - integrity sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA== +regenerator-transform@^0.13.4: + version "0.13.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb" + integrity sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A== dependencies: private "^0.1.6"