Switch to a logged out state when auth tokens expire (#2290)

This commit is contained in:
Kumar McMillan 2017-04-27 09:57:17 -05:00 коммит произвёл GitHub
Родитель 0640cfa76f
Коммит 2f480b474f
13 изменённых файлов: 579 добавлений и 227 удалений

Просмотреть файл

@ -104,4 +104,9 @@ module.exports = {
// https://sentry.prod.mozaws.net/operations/addons-frontend-amo-prod/
publicSentryDsn: 'https://dbce4e759d8b4dc6a1731d3301fdaab7@sentry.prod.mozaws.net/183',
// The amount of time (in seconds) that an auth token lives for.
// This needs to match the SESSION_COOKIE_AGE in addons-server:
// https://github.com/mozilla/addons-server/blob/master/src/olympia/lib/settings_base.py#L990
authTokenValidFor: 2592000, // 30 days
};

Просмотреть файл

@ -66,6 +66,7 @@ module.exports = {
//
clientConfigKeys: [
'allowErrorSimulation',
'authTokenValidFor',
'amoCDN',
'apiHost',
'apiPath',
@ -238,4 +239,8 @@ module.exports = {
sentryDsn: process.env.SENTRY_DSN || null,
publicSentryDsn: null,
// The amount of time (in seconds) that an auth token lives for. This is
// currently only used in AMO.
authTokenValidFor: null,
};

Просмотреть файл

@ -175,6 +175,7 @@
"dependencies": {
"babel-plugin-dedent": "2.0.0",
"babel-polyfill": "6.20.0",
"base62": "1.1.2",
"base64url": "2.0.0",
"better-npm-run": "0.0.15",
"bunyan": "1.8.10",

Просмотреть файл

@ -167,7 +167,7 @@ export class RatingManagerBase extends React.Component {
return (
<div className="RatingManager">
{showTextEntry ?
{showTextEntry && isLoggedIn ?
<AddonReview
onReviewSubmitted={onReviewSubmitted}
review={userReview}

Просмотреть файл

@ -1,6 +1,9 @@
/* global navigator, window */
/* @flow */
/* eslint-disable react/sort-comp */
/* global $PropertyType, Event, Navigator, Node, navigator, window */
import config from 'config';
import React, { PropTypes } from 'react';
import { oneLine } from 'common-tags';
import React from 'react';
import cookie from 'react-cookie';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
@ -8,39 +11,55 @@ import LoadingBar from 'react-redux-loading-bar';
import { compose } from 'redux';
import SearchForm from 'amo/components/SearchForm';
import { getErrorComponent } from 'amo/utils';
import { getDjangoBase62, getErrorComponent } from 'amo/utils';
import Footer from 'amo/components/Footer';
import MastHead from 'amo/components/MastHead';
import { addChangeListeners } from 'core/addonManager';
import { setUserAgent as setUserAgentAction } from 'core/actions';
import { INSTALL_STATE } from 'core/constants';
import {
logOutUser as logOutUserAction, setUserAgent as setUserAgentAction,
} from 'core/actions';
import { INSTALL_STATE, maximumSetTimeoutDelay } from 'core/constants';
import DefaultErrorPage from 'core/components/ErrorPage';
import InfoDialog from 'core/containers/InfoDialog';
import translate from 'core/i18n/translate';
import log from 'core/logger';
import type { UrlFormatParams } from 'core/api';
import type { ApiStateType } from 'core/reducers/api';
import type { DispatchFunc } from 'core/types/redux';
import type { InstalledAddon } from 'core/reducers/installations';
import 'amo/css/App.scss';
import 'core/fonts/fira.scss';
interface MozNavigator extends Navigator {
mozAddonManager?: Object,
}
type AppProps = {
ErrorPage: typeof DefaultErrorPage,
FooterComponent: typeof Footer,
InfoDialogComponent: typeof InfoDialog,
MastHeadComponent: typeof MastHead,
_addChangeListeners: () => void,
_navigator: typeof navigator,
authToken?: string,
authTokenValidFor?: number,
children: any,
clientApp: string,
handleGlobalEvent: () => void,
i18n: Object,
lang: string,
location: UrlFormatParams,
logOutUser: () => void,
mozAddonManager: $PropertyType<MozNavigator, 'mozAddonManager'>,
setUserAgent: () => void,
userAgent: string,
}
export class AppBase extends React.Component {
static propTypes = {
ErrorPage: PropTypes.node.isRequired,
FooterComponent: PropTypes.node.isRequired,
InfoDialogComponent: PropTypes.node.isRequired,
MastHeadComponent: PropTypes.node.isRequired,
_addChangeListeners: PropTypes.func,
_navigator: PropTypes.object,
children: PropTypes.node,
clientApp: PropTypes.string.isRequired,
handleGlobalEvent: PropTypes.func.isRequired,
i18n: PropTypes.object.isRequired,
lang: PropTypes.string.isRequired,
location: PropTypes.object.isRequired,
mozAddonManager: PropTypes.object,
setUserAgent: PropTypes.func.isRequired,
userAgent: PropTypes.string,
}
mastHead: Node;
props: AppProps;
scheduledLogout: number;
static defaultProps = {
ErrorPage: DefaultErrorPage,
@ -49,7 +68,9 @@ export class AppBase extends React.Component {
MastHeadComponent: MastHead,
_addChangeListeners: addChangeListeners,
_navigator: (typeof navigator !== 'undefined' ? navigator : null),
mozAddonManager: config.get('server') ? {} : navigator.mozAddonManager,
authTokenValidFor: config.get('authTokenValidFor'),
mozAddonManager:
config.get('server') ? {} : (navigator: MozNavigator).mozAddonManager,
userAgent: null,
}
@ -57,6 +78,7 @@ export class AppBase extends React.Component {
const {
_addChangeListeners,
_navigator,
authToken,
handleGlobalEvent,
mozAddonManager,
setUserAgent,
@ -74,13 +96,85 @@ export class AppBase extends React.Component {
'userAgent not in state on App load; using navigator.userAgent.');
setUserAgent(_navigator.userAgent);
}
if (authToken) {
this.setLogOutTimer(authToken);
}
}
onViewDesktop = (event, { window_ = window, cookie_ = cookie } = {}) => {
componentWillReceiveProps(nextProps: AppProps) {
const { authToken } = nextProps;
if (authToken) {
this.setLogOutTimer(authToken);
}
}
setLogOutTimer(authToken: string) {
const { authTokenValidFor, logOutUser } = this.props;
const expiresAt = authTokenValidFor;
if (!expiresAt) {
log.warn(oneLine`configured authTokenValidFor is falsey, not
checking for auth expiration`);
return;
}
const parts = authToken.split(':');
const encodedTimestamp = parts[1];
const base62 = getDjangoBase62();
let createdAt;
try {
// This is a UTC Unix timestamp.
createdAt = base62.decode(encodedTimestamp);
} catch (base62Error) {
log.error(
`Auth token "${encodedTimestamp}" triggered this base62 error: "${base62Error}"`);
return;
}
// If the encoded timestamp was malformed it will be 0 or negative.
if (createdAt <= 0) {
log.error(oneLine`Got an invalid timestamp from auth token;
encoded value: ${encodedTimestamp}; decoded value: ${createdAt}`);
return;
}
const readableCreatedAt = new Date(createdAt * 1000).toString();
log.debug(`Auth token was created at: ${readableCreatedAt}`);
// Get the current UTC Unix timestamp.
const now = Date.now() / 1000;
// Set the expiration time in seconds.
const expirationTime = (createdAt + expiresAt) - now;
const readableExpiration =
new Date((now + expirationTime) * 1000).toString();
log.debug(`Auth token expires at ${readableExpiration}`);
const setTimeoutDelay = expirationTime * 1000;
if (setTimeoutDelay >= maximumSetTimeoutDelay) {
log.debug(oneLine`No logout was scheduled because the expiration
exceeded the setTimeout limit`);
return;
}
if (this.scheduledLogout) {
clearTimeout(this.scheduledLogout);
}
log.info('Setting a logout timer for when the token expires');
this.scheduledLogout = setTimeout(() => {
log.info('Logging out because the auth token has expired');
logOutUser();
}, setTimeoutDelay);
}
onViewDesktop = (
event: Event,
{
_window = window, _cookie = cookie,
}: {|
_window: typeof window, _cookie: typeof cookie,
|} = {}
) => {
event.preventDefault();
if (window_ && window_.location) {
cookie_.save('mamo', 'off', { path: '/' });
window_.location.reload();
if (_window && _window.location) {
_cookie.save('mamo', 'off', { path: '/' });
_window.location.reload();
}
}
@ -120,18 +214,22 @@ export class AppBase extends React.Component {
}
}
export const mapStateToProps = (state) => ({
export const mapStateToProps = (state: { api: ApiStateType }) => ({
authToken: state.api && state.api.token,
clientApp: state.api.clientApp,
lang: state.api.lang,
userAgent: state.api.userAgent,
});
export function mapDispatchToProps(dispatch) {
export function mapDispatchToProps(dispatch: DispatchFunc) {
return {
handleGlobalEvent(payload) {
logOutUser() {
dispatch(logOutUserAction());
},
handleGlobalEvent(payload: InstalledAddon) {
dispatch({ type: INSTALL_STATE, payload });
},
setUserAgent(userAgent) {
setUserAgent(userAgent: string) {
dispatch(setUserAgentAction(userAgent));
},
};

Просмотреть файл

@ -1,3 +1,5 @@
import base62 from 'base62';
import {
FEATURED_ADDONS_TO_LOAD,
LANDING_PAGE_ADDON_COUNT,
@ -73,3 +75,17 @@ export function getErrorComponent(status) {
return ServerError;
}
}
/*
* Return a base62 object that encodes/decodes just like how Django does it
* for cookie timestamps.
*
* See:
* https://github.com/django/django/blob/0b9f366c60134a0ca2873c156b9c80acb7ffd8b5/django/core/signing.py#L180
*/
export function getDjangoBase62() {
// This is the alphabet used by Django.
base62.setCharacterSet(
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
return base62;
}

Просмотреть файл

@ -173,3 +173,9 @@ export const ERROR_UNKNOWN = 'ERROR_UNKNOWN';
export const API_ERROR_DECODING_SIGNATURE = 'ERROR_DECODING_SIGNATURE';
export const API_ERROR_INVALID_HEADER = 'ERROR_INVALID_HEADER';
export const API_ERROR_SIGNATURE_EXPIRED = 'ERROR_SIGNATURE_EXPIRED';
// This is the limit in milleseconds for how long a setTimeout delay can be.
// No setTimeout should be scheduled for this time because it
// will be triggered immediately.
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value
export const maximumSetTimeoutDelay = 2147483647;

Просмотреть файл

@ -1,3 +1,5 @@
/* @flow */
/* global Node, $PropertyType */
import {
DOWNLOAD_PROGRESS,
DOWNLOADING,
@ -13,86 +15,117 @@ import {
UNINSTALLED,
UNINSTALL_COMPLETE,
} from 'core/constants';
import log from 'core/logger';
import type { AddonType } from 'core/types/addons';
export type InstalledAddon = {
downloadProgress?: number,
error?: string,
guid: $PropertyType<AddonType, 'guid'>,
isPreviewingTheme?: boolean,
needsRestart?: boolean,
status?: $PropertyType<AddonType, 'status'>,
themePreviewNode?: Node,
url?: $PropertyType<AddonType, 'url'>,
};
export function loadAddon({ guid, state }) {
if (state[guid]) {
return { ...state[guid] };
type InstallationAction = {|
payload: InstalledAddon,
type: string,
|};
type InstallationState = {
[guid: $PropertyType<AddonType, 'guid'>]: InstalledAddon,
};
export default function installations(
state: InstallationState = {}, { type, payload }: InstallationAction,
) {
function updateAddon(newProps: Object): InstalledAddon {
const guid = payload.guid;
const addon = state[guid];
if (!addon) {
throw new Error(
`Cannot reduce type ${type}; no add-on with guid ${guid} found.`);
}
return {
...addon,
...newProps,
};
}
log.warn(`No add-on with guid ${guid} found.`);
return null;
}
export default function installations(state = {}, { type, payload }) {
let addon;
switch (type) {
case INSTALL_STATE:
addon = {
guid: payload.guid,
url: payload.url,
error: payload.error,
downloadProgress: 0,
status: payload.status,
needsRestart: payload.needsRestart || false,
return {
...state,
[payload.guid]: {
guid: payload.guid,
url: payload.url,
error: payload.error,
downloadProgress: 0,
status: payload.status,
needsRestart: payload.needsRestart || false,
},
};
return { ...state, [payload.guid]: addon };
case START_DOWNLOAD:
addon = loadAddon({ guid: payload.guid, state });
addon.status = DOWNLOADING;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
status: DOWNLOADING,
}),
};
case DOWNLOAD_PROGRESS:
addon = loadAddon({ guid: payload.guid, state });
addon.downloadProgress = payload.downloadProgress;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
downloadProgress: payload.downloadProgress,
}),
};
case INSTALL_COMPLETE:
addon = loadAddon({ guid: payload.guid, state });
addon.status = INSTALLED;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
status: INSTALLED,
}),
};
case UNINSTALL_COMPLETE:
addon = loadAddon({ guid: payload.guid, state });
addon.status = UNINSTALLED;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
status: UNINSTALLED,
}),
};
case INSTALL_CANCELLED:
addon = loadAddon({ guid: payload.guid, state });
addon.downloadProgress = 0;
addon.status = UNINSTALLED;
return { ...state, [payload.guid]: addon };
/* istanbul ignore case */
return {
...state,
[payload.guid]: updateAddon({
downloadProgress: 0,
status: UNINSTALLED,
}),
};
case INSTALL_ERROR:
addon = loadAddon({ guid: payload.guid, state });
addon.downloadProgress = 0;
addon.status = ERROR;
addon.error = payload.error;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
downloadProgress: 0,
error: payload.error,
status: ERROR,
}),
};
case THEME_PREVIEW:
addon = loadAddon({ guid: payload.guid, state });
addon.isPreviewingTheme = true;
addon.themePreviewNode = payload.themePreviewNode;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
isPreviewingTheme: true,
themePreviewNode: payload.themePreviewNode,
}),
};
case THEME_RESET_PREVIEW:
addon = loadAddon({ guid: payload.guid, state });
addon.isPreviewingTheme = false;
return { ...state, [payload.guid]: addon };
return {
...state,
[payload.guid]: updateAddon({
isPreviewingTheme: false,
}),
};
default:
return state;
}

Просмотреть файл

@ -180,6 +180,22 @@ describe('RatingManager', () => {
});
});
it('does not render an AddonReview when logged out', () => {
const userReview = setReview(fakeReview).payload;
const FakeAddonReview = sinon.spy(() => <div />);
const userId = null; // logged out
const root = render({ AddonReview: FakeAddonReview, userReview, userId });
assert.equal(FakeAddonReview.called, false,
'expected AddonReview to initially not be visible');
return root.onSelectRating(5)
.then(() => {
assert.notOk(
FakeAddonReview.called, 'AddonReview was rendered unexpectedly');
});
});
it('configures a rating component', () => {
const userReview = setReview(fakeReview).payload;
const RatingStub = sinon.spy(() => (<div />));

Просмотреть файл

@ -14,15 +14,16 @@ import {
} from 'amo/containers/App';
import createStore from 'amo/store';
import {
logOutUser as logOutUserAction,
setClientApp,
setLang,
setUserAgent as setUserAgentAction,
} from 'core/actions';
import { createApiError } from 'core/api';
import DefaultErrorPage from 'core/components/ErrorPage';
import { INSTALL_STATE } from 'core/constants';
import { INSTALL_STATE, maximumSetTimeoutDelay } from 'core/constants';
import I18nProvider from 'core/i18n/Provider';
import { getFakeI18nInst } from 'tests/client/helpers';
import { getFakeI18nInst, userAuthToken } from 'tests/client/helpers';
describe('App', () => {
@ -60,6 +61,7 @@ describe('App', () => {
function render({ children = [], ...customProps } = {}) {
const props = {
i18n: getFakeI18nInst(),
logOutUser: sinon.stub(),
location: sinon.stub(),
isAuthenticated: true,
store: createStore(),
@ -110,7 +112,7 @@ describe('App', () => {
};
const root = render();
root.onViewDesktop(fakeEvent, { window_: fakeWindow, cookie_: fakeCookieLib });
root.onViewDesktop(fakeEvent, { _window: fakeWindow, _cookie: fakeCookieLib });
assert.ok(fakeEvent.preventDefault.called);
assert.ok(fakeCookieLib.save.calledWith('mamo', 'off'));
assert.ok(fakeWindow.location.reload.called);
@ -204,4 +206,130 @@ describe('App', () => {
assert.include(rootNode.textContent, 'Page not found');
});
describe('handling expired auth tokens', () => {
let clock;
function renderAppWithAuth(customProps = {}) {
const props = {
authToken: userAuthToken(),
logOutUser: sinon.stub(),
...customProps,
};
return render(props);
}
beforeEach(() => {
clock = sinon.useFakeTimers(Date.now());
});
afterEach(() => {
clock.restore();
});
it('logs out when the token expires', () => {
const authTokenValidFor = 10; // seconds
const logOutUser = sinon.stub();
renderAppWithAuth({ authTokenValidFor, logOutUser });
const fuzz = 3; // account for the rounded offset calculation.
clock.tick((authTokenValidFor + fuzz) * 1000);
assert.ok(logOutUser.called, 'expected logOutUser() to be called');
});
it('only sets one timer when receiving new props', () => {
const authTokenValidFor = 10; // seconds
const authToken = userAuthToken();
const logOutUser = sinon.stub();
const root = render({ authToken, authTokenValidFor, logOutUser });
// Simulate updating the component with new properties.
root.componentWillReceiveProps({ authToken });
const fuzz = 3; // account for the rounded offset calculation.
clock.tick((authTokenValidFor + fuzz) * 1000);
assert.ok(logOutUser.called, 'expected logOutUser() to be called');
assert.ok(logOutUser.calledOnce,
'logOutUser() should only be called once');
});
it('does not log out until the token expires', () => {
const authTokenValidFor = 10; // seconds
const logOutUser = sinon.stub();
renderAppWithAuth({ authTokenValidFor, logOutUser });
clock.tick(5 * 1000); // 5 seconds
assert.notOk(logOutUser.called,
'expected logOutUser() NOT to be called');
});
it('only starts a timer when authTokenValidFor is configured', () => {
const logOutUser = sinon.stub();
renderAppWithAuth({ authTokenValidFor: null, logOutUser });
clock.tick(100 * 1000);
assert.notOk(logOutUser.called,
'expected logOutUser() NOT to be called');
});
it('ignores malformed timestamps', () => {
const authTokenValidFor = 10; // seconds
const authToken = userAuthToken({}, {
tokenCreatedAt: 'bogus-timestamp',
});
const logOutUser = sinon.stub();
render({ authToken, authTokenValidFor, logOutUser });
clock.tick(authTokenValidFor * 1000);
assert.notOk(logOutUser.called,
'expected logOutUser() NOT to be called');
});
it('ignores empty timestamps', () => {
const authTokenValidFor = 10; // seconds
const authToken = 'this-is-a-token-with-an-empty-timestamp';
const logOutUser = sinon.stub();
render({ authToken, authTokenValidFor, logOutUser });
clock.tick(authTokenValidFor * 1000);
assert.notOk(logOutUser.called,
'expected logOutUser() NOT to be called');
});
it('ignores malformed tokens', () => {
const authTokenValidFor = 10; // seconds
const authToken = 'not-auth-data:^&invalid-characters:not-a-signature';
const logOutUser = sinon.stub();
render({ authToken, authTokenValidFor, logOutUser });
clock.tick(authTokenValidFor * 1000);
assert.notOk(logOutUser.called,
'expected logOutUser() NOT to be called');
});
it('does not set a timeout for expirations too far in the future', () => {
const authTokenValidFor = (maximumSetTimeoutDelay / 1000) + 1;
const logOutUser = sinon.stub();
renderAppWithAuth({ authTokenValidFor, logOutUser });
const fuzz = 3; // account for the rounded offset calculation.
clock.tick((authTokenValidFor + fuzz) * 1000);
assert.notOk(logOutUser.called,
'expected logOutUser() NOT to be called');
});
it('maps a logOutUser action', () => {
const dispatch = sinon.stub();
const { logOutUser } = mapDispatchToProps(dispatch);
logOutUser();
assert.deepEqual(dispatch.firstCall.args[0], logOutUserAction());
});
});
});

Просмотреть файл

@ -17,7 +17,7 @@ import {
UNINSTALLED,
UNINSTALLING,
} from 'core/constants';
import installations, { loadAddon } from 'core/reducers/installations';
import installations from 'core/reducers/installations';
describe('installations reducer', () => {
it('is an empty object by default', () => {
@ -337,11 +337,16 @@ describe('installations reducer', () => {
},
});
});
});
describe('installations loadAddon', () => {
it('returns null when no add-on found', () => {
const addon = loadAddon({ guid: '302', state: {} });
assert.equal(addon, null);
it('cannot update a non-existant add-on', () => {
assert.throws(
() => installations({}, {
type: INSTALL_ERROR,
payload: {
guid: 'my-addon@me.com',
error: 'an-error',
},
}),
/no add-on with guid my-addon@me.com found/);
});
});

Просмотреть файл

@ -5,6 +5,7 @@ import React from 'react';
import { createRenderer } from 'react-addons-test-utils';
import UAParser from 'ua-parser-js';
import { getDjangoBase62 } from 'amo/utils';
import { ADDON_TYPE_EXTENSION } from 'core/constants';
import { makeI18n } from 'core/i18n/utils';
import { initialApiState } from 'core/reducers/api';
@ -13,7 +14,10 @@ import { initialApiState } from 'core/reducers/api';
* Return a fake authentication token that can be
* at least decoded in a realistic way.
*/
export function userAuthToken(dataOverrides = {}, { tokenData } = {}) {
export function userAuthToken(
dataOverrides = {},
{ tokenCreatedAt = (Date.now() / 1000).toFixed(0), tokenData } = {},
) {
const data = {
user_id: 102345,
...dataOverrides,
@ -23,10 +27,12 @@ export function userAuthToken(dataOverrides = {}, { tokenData } = {}) {
if (!encodedToken) {
encodedToken = base64url.encode(JSON.stringify(data));
}
const authId = base64url.encode('pretend this is an auth ID');
const sig = base64url.encode('pretend this is a signature');
return `${encodedToken}:${authId}:${sig}`;
const base62 = getDjangoBase62();
const timestamp = base62.encode(tokenCreatedAt);
const sig = base64url.encode('pretend-this-is-a-signature');
return `${encodedToken}:${timestamp}:${sig}`;
}
export function shallowRender(stuff) {

267
yarn.lock
Просмотреть файл

@ -36,10 +36,6 @@ acorn-jsx@^3.0.0:
dependencies:
acorn "^3.0.4"
acorn@4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a"
acorn@^3.0.0, acorn@^3.0.4:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
@ -48,6 +44,10 @@ acorn@^4.0.4:
version "4.0.11"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0"
acorn@^5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
@ -57,8 +57,8 @@ ajv-keywords@^1.0.0:
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
ajv@^4.7.0, ajv@^4.9.1:
version "4.11.5"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd"
version "4.11.7"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48"
dependencies:
co "^4.6.0"
json-stable-stringify "^1.0.1"
@ -119,11 +119,11 @@ aproba@^1.0.3:
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab"
are-we-there-yet@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3"
version "1.1.4"
resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d"
dependencies:
delegates "^1.0.0"
readable-stream "^2.0.0 || ^1.1.13"
readable-stream "^2.0.6"
argparse@^1.0.7:
version "1.0.9"
@ -138,8 +138,8 @@ arr-diff@^2.0.0:
arr-flatten "^1.0.1"
arr-flatten@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b"
version "1.0.3"
resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1"
array-differ@^1.0.0:
version "1.0.0"
@ -245,8 +245,8 @@ async@^0.9.0, async@~0.9.0:
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
async@^2.1.5:
version "2.2.0"
resolved "https://registry.yarnpkg.com/async/-/async-2.2.0.tgz#c324eba010a237e4fbd55a12dee86367d5c0ef32"
version "2.3.0"
resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9"
dependencies:
lodash "^4.14.0"
@ -949,11 +949,7 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24
lodash "^4.2.0"
to-fast-properties "^1.0.1"
babylon@^6.11.0:
version "6.16.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
babylon@^6.13.0, babylon@^6.15.0, babylon@^6.17.0:
babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0, babylon@^6.17.0:
version "6.17.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.0.tgz#37da948878488b9c4e3c4038893fa3314b3fc932"
@ -965,6 +961,10 @@ balanced-match@^0.4.0, balanced-match@^0.4.1, balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
base62@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/base62/-/base62-1.1.2.tgz#22ced6a49913565bc0b8d9a11563a465c084124c"
base64-arraybuffer@0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
@ -1057,8 +1057,8 @@ boom@2.x.x:
hoek "2.x.x"
brace-expansion@^1.0.0:
version "1.1.6"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9"
version "1.1.7"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59"
dependencies:
balanced-match "^0.4.1"
concat-map "0.0.1"
@ -1093,14 +1093,14 @@ browserify-zlib@^0.1.4:
dependencies:
pako "~0.2.0"
browserslist@^1.0.1, browserslist@^1.1.1, browserslist@^1.1.3, browserslist@^1.5.2, browserslist@^1.7.6:
browserslist@^1.1.1, browserslist@^1.1.3, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
version "1.7.7"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
dependencies:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
buffer-shims@^1.0.0:
buffer-shims@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51"
@ -1181,17 +1181,17 @@ camelize@1.0.0:
resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b"
caniuse-api@^1.5.2:
version "1.5.3"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.5.3.tgz#5018e674b51c393e4d50614275dc017e27c4a2a2"
version "1.6.1"
resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
dependencies:
browserslist "^1.0.1"
caniuse-db "^1.0.30000346"
lodash.memoize "^4.1.0"
lodash.uniq "^4.3.0"
browserslist "^1.3.6"
caniuse-db "^1.0.30000529"
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000346, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000646"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000646.tgz#c724b90d61df24286e015fc528d062073c00def4"
caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000662"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000662.tgz#616b17a525b52fec14611f88af3d5a9b5438c050"
caseless@~0.11.0:
version "0.11.0"
@ -1579,8 +1579,8 @@ cookie@0.3.1, cookie@^0.3.1:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
cookiejar@^2.0.6:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.0.tgz#86549689539b6d0e269b6637a304be508194d898"
version "2.1.1"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a"
core-js@^1.0.0:
version "1.2.7"
@ -1595,14 +1595,15 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
cosmiconfig@^2.1.0, cosmiconfig@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.1.1.tgz#817f2c2039347a1e9bf7d090c0923e53f749ca82"
version "2.1.2"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.1.2.tgz#c43ae86d238f08f1728a345ed60ceb0aef63c060"
dependencies:
is-directory "^0.3.1"
js-yaml "^3.4.3"
json-parse-helpfulerror "^1.0.3"
minimist "^1.2.0"
object-assign "^4.1.0"
os-homedir "^1.0.1"
parse-json "^2.2.0"
require-from-string "^1.1.0"
coveralls@~2.11.2:
@ -1807,8 +1808,8 @@ dashify@^0.2.0:
resolved "https://registry.yarnpkg.com/dashify/-/dashify-0.2.2.tgz#6a07415a01c91faf4a32e38d9dfba71f61cb20fe"
date-fns@^1.23.0:
version "1.28.2"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.2.tgz#19e4192d68875c0bf7c9537e3f296a8ec64853ef"
version "1.28.4"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.4.tgz#7938aec34ba31fc8bd134d2344bc2e0bbfd95165"
date-now@^0.1.4:
version "0.1.4"
@ -1845,11 +1846,11 @@ debug@2.6.1, debug@^2.1.1, debug@^2.2.0, debug@^2.6.0:
dependencies:
ms "0.7.2"
debug@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d"
debug@2.6.4:
version "2.6.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0"
dependencies:
ms "0.7.2"
ms "0.7.3"
decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
version "1.2.0"
@ -2063,8 +2064,8 @@ ee-first@1.1.1:
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
electron-to-chromium@^1.2.7:
version "1.3.2"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.2.tgz#b8ce5c93b308db0e92f6d0435c46ddec8f6363ab"
version "1.3.8"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.8.tgz#b2c8a2c79bb89fbbfd3724d9555e15095b5f5fb6"
emojis-list@^2.0.0:
version "2.1.0"
@ -2347,10 +2348,10 @@ eslint@3.19.0:
user-home "^2.0.0"
espree@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.0.tgz#41656fa5628e042878025ef467e78f125cb86e1d"
version "3.4.2"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592"
dependencies:
acorn "4.0.4"
acorn "^5.0.1"
acorn-jsx "^3.0.0"
esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1:
@ -2422,8 +2423,8 @@ execall@^1.0.0:
clone-regexp "^1.0.0"
exenv@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.1.tgz#75de1c8dee02e952b102aa17f8875973e0df14f9"
version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
exit-hook@^1.0.0:
version "1.1.1"
@ -2616,10 +2617,10 @@ finalhandler@1.0.0:
unpipe "~1.0.0"
finalhandler@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8"
version "1.0.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a"
dependencies:
debug "2.6.3"
debug "2.6.4"
encodeurl "~1.0.1"
escape-html "~1.0.3"
on-finished "~2.3.0"
@ -2688,8 +2689,8 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@^2.1.1, form-data@~2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4"
version "2.1.4"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1"
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.5"
@ -2764,8 +2765,8 @@ gather-stream@^1.0.0:
resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b"
gauge@~2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09"
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
dependencies:
aproba "^1.0.3"
console-control-strings "^1.0.0"
@ -2805,8 +2806,8 @@ get-stdin@^5.0.0:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
getpass@^0.1.1:
version "0.1.6"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6"
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
dependencies:
assert-plus "^1.0.0"
@ -2871,8 +2872,8 @@ glob@^6.0.1:
path-is-absolute "^1.0.0"
global@^4.3.0:
version "4.3.1"
resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df"
version "4.3.2"
resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
dependencies:
min-document "^2.19.0"
process "~0.5.1"
@ -3065,8 +3066,8 @@ home-or-tmp@^2.0.0:
os-tmpdir "^1.0.1"
hosted-git-info@^2.1.4:
version "2.4.1"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8"
version "2.4.2"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67"
hpack.js@^2.1.6:
version "2.1.6"
@ -3098,8 +3099,8 @@ html-encoding-sniffer@^1.0.1:
whatwg-encoding "^1.0.1"
html-entities@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2"
version "1.2.1"
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
html-tags@^1.1.1:
version "1.1.1"
@ -3202,8 +3203,8 @@ ienoopen@1.0.0:
resolved "https://registry.yarnpkg.com/ienoopen/-/ienoopen-1.0.0.tgz#346a428f474aac8f50cf3784ea2d0f16f62bda6b"
ignore@^3.2.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.6.tgz#26e8da0644be0bb4cb39516f6c79f0e0f4ffe48c"
version "3.2.7"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd"
imurmurhash@^0.1.4:
version "0.1.4"
@ -3269,8 +3270,8 @@ interpret@^0.6.4:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b"
interpret@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.2.tgz#f4f623f0bb7122f15f5717c8e254b8161b5c5b2d"
version "1.0.3"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1:
version "2.2.2"
@ -3304,7 +3305,7 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.0.2:
is-buffer@^1.0.2, is-buffer@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc"
@ -3322,6 +3323,10 @@ is-date-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
is-directory@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
is-dotfile@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
@ -3551,6 +3556,10 @@ jed@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4"
jju@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/jju/-/jju-1.3.0.tgz#dadd9ef01924bc728b03f2f7979bdbd62f7a2aaa"
jodid25519@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
@ -3573,8 +3582,8 @@ js-yaml@3.6.1:
esprima "^2.6.0"
js-yaml@3.x, js-yaml@^3.4.3, js-yaml@^3.5.1:
version "3.8.2"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.2.tgz#02d3e2c0f6beab20248d412c352203827d786721"
version "3.8.3"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766"
dependencies:
argparse "^1.0.7"
esprima "^3.1.1"
@ -3626,6 +3635,12 @@ json-loader@0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de"
json-parse-helpfulerror@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz#13f14ce02eed4e981297b64eb9e3b932e2dd13dc"
dependencies:
jju "^1.1.0"
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
@ -3689,10 +3704,8 @@ jsprim@^1.2.2:
verror "1.3.6"
jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4:
version "1.4.0"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.0.tgz#5afe38868f56bc8cc7aeaef0100ba8c75bd12591"
dependencies:
object-assign "^4.1.0"
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
karma-chai@0.1.0:
version "0.1.0"
@ -3790,10 +3803,10 @@ kind-of@^2.0.1:
is-buffer "^1.0.2"
kind-of@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47"
version "3.2.0"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.0.tgz#b58abe4d5c044ad33726a8c1525b48cf891bff07"
dependencies:
is-buffer "^1.0.2"
is-buffer "^1.1.5"
klaw@^1.0.0:
version "1.3.1"
@ -3975,7 +3988,7 @@ lodash.map@^4.4.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
lodash.memoize@^4.1.0:
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
@ -4007,7 +4020,7 @@ lodash.tail@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
lodash.uniq@^4.3.0:
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
@ -4155,7 +4168,7 @@ micromatch@^2.1.5, micromatch@^2.3.11:
version "1.27.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1"
mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7:
mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7:
version "2.1.15"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
dependencies:
@ -4238,6 +4251,10 @@ ms@0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
ms@0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff"
multimatch@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b"
@ -4260,8 +4277,8 @@ mv@~2:
rimraf "~2.4.0"
nan@^2.3.0, nan@^2.3.2, nan@^2.3.3:
version "2.5.1"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.1.tgz#d5b01691253326a97a2bbee9e61c55d8d60351e2"
version "2.6.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45"
native-promise-only@^0.8.1:
version "0.8.1"
@ -4394,8 +4411,8 @@ nopt@^4.0.1:
osenv "^0.1.4"
normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
version "2.3.6"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff"
version "2.3.8"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb"
dependencies:
hosted-git-info "^2.1.4"
is-builtin-module "^1.0.0"
@ -4660,6 +4677,10 @@ path-is-inside@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
path-parse@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
@ -4687,8 +4708,8 @@ performance-now@^0.2.0:
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5"
photoswipe@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-4.1.1.tgz#41b756a2387e220c286598945503014bf622bba9"
version "4.1.2"
resolved "https://registry.yarnpkg.com/photoswipe/-/photoswipe-4.1.2.tgz#95c20a75cea23b70d6299641cad82e03cae7f797"
pify@^2.0.0, pify@^2.3.0:
version "2.3.0"
@ -5060,8 +5081,8 @@ postcss-zindex@^2.0.1:
uniqs "^2.0.0"
postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.18, postcss@^5.0.2, postcss@^5.0.20, postcss@^5.0.21, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.13, postcss@^5.2.15, postcss@^5.2.16, postcss@^5.2.4:
version "5.2.16"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.16.tgz#732b3100000f9ff8379a48a53839ed097376ad57"
version "5.2.17"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.17.tgz#cf4f597b864d65c8a492b2eabe9d706c879c388b"
dependencies:
chalk "^1.1.3"
js-base64 "^2.1.9"
@ -5089,8 +5110,8 @@ process-nextick-args@~1.0.6:
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3"
process@^0.11.0:
version "0.11.9"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1"
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
process@~0.5.1:
version "0.5.2"
@ -5158,8 +5179,8 @@ query-string@^3.0.0:
strict-uri-encode "^1.0.0"
query-string@^4.1.0:
version "4.3.2"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.2.tgz#ec0fd765f58a50031a3968c2431386f8947a5cdd"
version "4.3.4"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
dependencies:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
@ -5210,8 +5231,8 @@ raw-body@~2.2.0:
unpipe "1.0.0"
rc@^1.1.7:
version "1.2.0"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.0.tgz#c7de973b7b46297c041366b2fd3d2363b1697c66"
version "1.2.1"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
dependencies:
deep-extend "~0.4.0"
ini "~1.3.0"
@ -5401,16 +5422,16 @@ readable-stream@^1.0.33, readable-stream@~1.1.9:
isarray "0.0.1"
string_decoder "~0.10.x"
"readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.4, readable-stream@^2.2.2:
version "2.2.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.6.tgz#8b43aed76e71483938d12a8d46c6cf1a00b1f816"
readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6:
version "2.2.9"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8"
dependencies:
buffer-shims "^1.0.0"
buffer-shims "~1.0.0"
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
string_decoder "~1.0.0"
util-deprecate "~1.0.1"
readdirp@^2.0.0:
@ -5513,8 +5534,8 @@ regenerate@^1.2.1:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
regenerator-runtime@^0.10.0:
version "0.10.3"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e"
version "0.10.4"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.4.tgz#74cb6598d3ba2eb18694e968a40e2b3b4df9cf93"
regenerator-transform@0.9.11:
version "0.9.11"
@ -5669,10 +5690,16 @@ resolve-from@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
resolve@1.1.x, resolve@^1.1.6:
resolve@1.1.x:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
resolve@^1.1.6:
version "1.3.3"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5"
dependencies:
path-parse "^1.0.5"
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@ -6058,8 +6085,8 @@ sri-stats-webpack-plugin@0.7.3:
webpack-custom-stats-patch "^0.3.0"
sshpk@^1.7.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77"
version "1.13.0"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c"
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
@ -6101,12 +6128,12 @@ stream-combiner@^0.2.1:
through "~2.3.4"
stream-http@^2.3.1:
version "2.6.3"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.3.tgz#4c3ddbf9635968ea2cfd4e48d43de5def2625ac3"
version "2.7.0"
resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.0.tgz#cec1f4e3b494bc4a81b451808970f8b20b4ed5f6"
dependencies:
builtin-status-codes "^3.0.0"
inherits "^2.0.1"
readable-stream "^2.1.0"
readable-stream "^2.2.6"
to-arraybuffer "^1.0.0"
xtend "^4.0.0"
@ -6133,6 +6160,12 @@ string_decoder@^0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
string_decoder@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667"
dependencies:
buffer-shims "~1.0.0"
stringstream@~0.0.4:
version "0.0.5"
resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878"
@ -6523,15 +6556,15 @@ type-detect@^3.0.0:
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-3.0.0.tgz#46d0cc8553abb7b13a352b0d6dea2fd58f2d9b55"
type-detect@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.0.tgz#62053883542a321f2f7b25746dc696478b18ff6b"
version "4.0.3"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea"
type-is@~1.6.14:
version "1.6.14"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2"
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
dependencies:
media-typer "0.3.0"
mime-types "~2.1.13"
mime-types "~2.1.15"
typedarray@^0.0.6:
version "0.0.6"
@ -6542,8 +6575,8 @@ ua-parser-js@0.7.12, ua-parser-js@^0.7.9:
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
uglify-js@^2.6, uglify-js@^2.7.0:
version "2.8.18"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.18.tgz#925d14bae48ab62d1883b41afe6e2261662adb8e"
version "2.8.22"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0"
dependencies:
source-map "~0.5.1"
yargs "~3.10.0"
@ -6841,8 +6874,8 @@ whatwg-fetch@^0.9.0:
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-0.9.0.tgz#0e3684c6cb9995b43efc9df03e4c365d95fd9cc0"
whatwg-url@^4.3.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.6.0.tgz#ef98da442273be04cf9632e176f257d2395a1ae4"
version "4.7.1"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.7.1.tgz#df4dc2e3f25a63b1fa5b32ed6d6c139577d690de"
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"