Ensure proper file permissions on startup

Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
Ken Powers 2020-02-21 18:40:04 -05:00 committed by GitHub
parent 6b56dd4ce0
commit 8d9ccd3c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 289 additions and 24 deletions

View File

@ -2,8 +2,7 @@ const crypto = require('crypto');
const path = require('path');
const { app, dialog, shell, remote } = require('electron');
const pify = require('pify');
const glob = require('glob');
const fastGlob = require('fast-glob');
const fse = require('fs-extra');
const toArrayBuffer = require('to-arraybuffer');
const { map, isArrayBuffer, isString } = require('lodash');
@ -28,7 +27,7 @@ exports.getAllAttachments = async userDataPath => {
const dir = exports.getPath(userDataPath);
const pattern = path.join(dir, '**', '*');
const files = await pify(glob)(pattern, { nodir: true });
const files = await fastGlob(pattern, { onlyFiles: true });
return map(files, file => path.relative(dir, file));
};
@ -36,7 +35,7 @@ exports.getAllStickers = async userDataPath => {
const dir = exports.getStickersPath(userDataPath);
const pattern = path.join(dir, '**', '*');
const files = await pify(glob)(pattern, { nodir: true });
const files = await fastGlob(pattern, { onlyFiles: true });
return map(files, file => path.relative(dir, file));
};
@ -44,7 +43,7 @@ exports.getAllDraftAttachments = async userDataPath => {
const dir = exports.getDraftPath(userDataPath);
const pattern = path.join(dir, '**', '*');
const files = await pify(glob)(pattern, { nodir: true });
const files = await fastGlob(pattern, { onlyFiles: true });
return map(files, file => path.relative(dir, file));
};
@ -52,7 +51,7 @@ exports.getBuiltInImages = async () => {
const dir = path.join(__dirname, '../images');
const pattern = path.join(dir, '**', '*.svg');
const files = await pify(glob)(pattern, { nodir: true });
const files = await fastGlob(pattern, { onlyFiles: true });
return map(files, file => path.relative(dir, file));
};

View File

@ -500,6 +500,8 @@
if (newVersion) {
await window.Signal.Data.cleanupOrphanedAttachments();
// Don't block on the following operation
window.Signal.Data.ensureFilePermissions();
}
Views.Initialization.setMessage(window.i18n('loading'));

View File

@ -33,6 +33,7 @@ const ERASE_STICKERS_KEY = 'erase-stickers';
const ERASE_TEMP_KEY = 'erase-temp';
const ERASE_DRAFTS_KEY = 'erase-drafts';
const CLEANUP_ORPHANED_ATTACHMENTS_KEY = 'cleanup-orphaned-attachments';
const ENSURE_FILE_PERMISSIONS = 'ensure-file-permissions';
const _jobs = Object.create(null);
const _DEBUG = false;
@ -169,6 +170,7 @@ module.exports = {
removeOtherData,
cleanupOrphanedAttachments,
ensureFilePermissions,
// Returning plain JSON
getMessagesNeedingUpgrade,
@ -1043,6 +1045,10 @@ async function cleanupOrphanedAttachments() {
await callChannel(CLEANUP_ORPHANED_ATTACHMENTS_KEY);
}
async function ensureFilePermissions() {
await callChannel(ENSURE_FILE_PERMISSIONS);
}
// Note: will need to restart the app after calling this, to set up afresh
async function removeOtherData() {
await Promise.all([

59
main.js
View File

@ -3,9 +3,12 @@
const path = require('path');
const url = require('url');
const os = require('os');
const fs = require('fs');
const fs = require('fs-extra');
const crypto = require('crypto');
const qs = require('qs');
const normalizePath = require('normalize-path');
const fg = require('fast-glob');
const PQueue = require('p-queue').default;
const _ = require('lodash');
const pify = require('pify');
@ -16,6 +19,10 @@ const GlobalErrors = require('./app/global_errors');
GlobalErrors.addHandler();
// Set umask early on in the process lifecycle to ensure file permissions are
// set such that only we have read access to our files
process.umask(0o077);
const getRealPath = pify(fs.realpath);
const {
app,
@ -863,6 +870,8 @@ app.on('ready', async () => {
}
setupMenu();
ensureFilePermissions(['config.json', 'sql/db.sqlite']);
});
function setupMenu(options) {
@ -1195,3 +1204,51 @@ ipc.on('install-sticker-pack', (_event, packId, packKeyHex) => {
const packKey = Buffer.from(packKeyHex, 'hex').toString('base64');
mainWindow.webContents.send('install-sticker-pack', { packId, packKey });
});
ipc.on('ensure-file-permissions', async event => {
await ensureFilePermissions();
event.reply('ensure-file-permissions-done');
});
/**
* Ensure files in the user's data directory have the proper permissions.
* Optionally takes an array of file paths to exclusively affect.
*
* @param {string[]} [onlyFiles] - Only ensure permissions on these given files
*/
async function ensureFilePermissions(onlyFiles) {
console.log('Begin ensuring permissions');
const start = Date.now();
const userDataPath = await getRealPath(app.getPath('userData'));
// fast-glob uses `/` for all platforms
const userDataGlob = normalizePath(path.join(userDataPath, '**', '*'));
// Determine files to touch
const files = onlyFiles
? onlyFiles.map(f => path.join(userDataPath, f))
: await fg(userDataGlob, {
markDirectories: true,
onlyFiles: false,
ignore: ['**/Singleton*'],
});
console.log(`Ensuring file permissions for ${files.length} files`);
// Touch each file in a queue
const q = new PQueue({ concurrency: 5 });
q.addAll(
files.map(f => async () => {
const isDir = f.endsWith('/');
try {
await fs.chmod(path.normalize(f), isDir ? 0o700 : 0o600);
} catch (error) {
console.error('ensureFilePermissions: Error from chmod', error.message);
}
})
);
await q.onEmpty();
console.log(`Finish ensuring permissions in ${Date.now() - start}ms`);
}

View File

@ -82,12 +82,12 @@
"emoji-datasource": "5.0.1",
"emoji-datasource-apple": "5.0.1",
"emoji-regex": "8.0.0",
"fast-glob": "3.2.1",
"filesize": "3.6.1",
"firstline": "1.2.1",
"form-data": "2.3.2",
"fs-extra": "5.0.0",
"fuse.js": "3.4.4",
"glob": "7.1.2",
"google-libphonenumber": "3.2.6",
"got": "8.2.0",
"he": "1.2.0",
@ -103,6 +103,7 @@
"mustache": "2.3.0",
"node-fetch": "https://github.com/scottnonnenberg-signal/node-fetch.git#3e5f51e08c647ee5f20c43b15cf2d352d61c36b4",
"node-gyp": "5.0.3",
"normalize-path": "3.0.0",
"os-locale": "2.1.0",
"p-map": "2.1.0",
"p-queue": "6.2.1",
@ -148,7 +149,7 @@
"devDependencies": {
"@babel/core": "7.7.7",
"@babel/plugin-proposal-class-properties": "7.7.4",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/plugin-transform-runtime": "7.8.3",
"@babel/preset-react": "7.7.4",
"@babel/preset-typescript": "7.7.7",
"@storybook/addon-actions": "5.1.11",
@ -199,7 +200,7 @@
"babel-plugin-lodash": "3.3.4",
"bower": "1.8.2",
"chai": "4.1.2",
"core-js": "^2.4.0",
"core-js": "2.4.0",
"cross-env": "5.2.0",
"css-loader": "3.2.0",
"dashdash": "1.14.1",

View File

@ -397,7 +397,7 @@ require('./js/spell_check');
if (config.environment === 'test') {
/* eslint-disable global-require, import/no-extraneous-dependencies */
window.test = {
glob: require('glob'),
fastGlob: require('fast-glob'),
fse: require('fs-extra'),
tmp: require('tmp'),
path: require('path'),

View File

@ -239,7 +239,7 @@ describe('Backup', () => {
it('exports then imports to produce the same data we started with', async function thisNeeded() {
this.timeout(6000);
const { attachmentsPath, fse, glob, path, tmp } = window.test;
const { attachmentsPath, fse, fastGlob, path, tmp } = window.test;
const {
upgradeMessageSchema,
loadAttachmentData,
@ -509,7 +509,7 @@ describe('Backup', () => {
console.log(
'Backup test: Ensure that all attachments were saved to disk'
);
const attachmentFiles = removeDirs(glob.sync(attachmentsPattern));
const attachmentFiles = removeDirs(fastGlob.sync(attachmentsPattern));
console.log({ attachmentFiles });
assert.strictEqual(ATTACHMENT_COUNT, attachmentFiles.length);
@ -529,7 +529,7 @@ describe('Backup', () => {
'Backup test: Ensure that all attachments made it to backup dir'
);
const backupAttachmentPattern = path.join(backupDir, 'attachments/*');
const backupAttachments = glob.sync(backupAttachmentPattern);
const backupAttachments = fastGlob.sync(backupAttachmentPattern);
console.log({ backupAttachments });
assert.strictEqual(ATTACHMENT_COUNT, backupAttachments.length);
@ -568,7 +568,7 @@ describe('Backup', () => {
console.log('Backup test: ensure that all attachments were imported');
const recreatedAttachmentFiles = removeDirs(
glob.sync(attachmentsPattern)
fastGlob.sync(attachmentsPattern)
);
console.log({ recreatedAttachmentFiles });
assert.strictEqual(ATTACHMENT_COUNT, recreatedAttachmentFiles.length);

View File

@ -3397,6 +3397,62 @@
"reasonCategory": "falseMatch",
"updated": "2018-09-19T18:13:29.628Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " result.push(append(value, stash, enclose));",
"lineNumber": 21,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " result.push(Array.isArray(ele) ? append(item, ele, enclose) : (item + ele));",
"lineNumber": 26,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " q.push(append(q.pop(), stringify(node, options)));",
"lineNumber": 48,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " q.push(append(q.pop(), ['{}']));",
"lineNumber": 53,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " q.push(append(q.pop(), range));",
"lineNumber": 69,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " q.push(append(q.pop(), queue, enclose));",
"lineNumber": 93,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/fast-glob/node_modules/braces/lib/expand.js",
"line": " queue.push(append(queue.pop(), child.value));",
"lineNumber": 98,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-load(",
"path": "node_modules/file-entry-cache/cache.js",
@ -10053,6 +10109,38 @@
"reasonCategory": "falseMatch",
"updated": "2018-09-19T18:13:29.628Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/picomatch/lib/parse.js",
"line": " if (tok.value || tok.output) append(tok);",
"lineNumber": 210,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/picomatch/lib/parse.js",
"line": " append({ value });",
"lineNumber": 415,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/picomatch/lib/parse.js",
"line": " append({ value });",
"lineNumber": 427,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "jQuery-append(",
"path": "node_modules/picomatch/lib/parse.js",
"line": " append({ value });",
"lineNumber": 511,
"reasonCategory": "falseMatch",
"updated": "2020-02-21T14:09:28.005Z"
},
{
"rule": "thenify-multiArgs",
"path": "node_modules/pify/index.js",

View File

@ -3,8 +3,7 @@
import { readFileSync } from 'fs';
import { join, relative } from 'path';
// @ts-ignore
import * as glob from 'glob';
import { sync as fgSync } from 'fast-glob';
import { forEach, some, values } from 'lodash';
import { ExceptionType, REASONS, RuleType } from './types';
@ -44,7 +43,7 @@ const exceptions: Array<ExceptionType> = loadJSON(exceptionsPath);
const exceptionsLookup = createLookup(exceptions);
let scannedCount = 0;
const allSourceFiles = glob.sync(searchPattern, { nodir: true });
const allSourceFiles = fgSync(searchPattern, { onlyFiles: true });
const results: Array<ExceptionType> = [];

125
yarn.lock
View File

@ -823,7 +823,7 @@
resolve "^1.8.1"
semver "^5.5.1"
"@babel/plugin-transform-runtime@^7.8.3":
"@babel/plugin-transform-runtime@7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.8.3.tgz#c0153bc0a5375ebc1f1591cb7eea223adea9f169"
integrity sha512-/vqUt5Yh+cgPZXXjmaG9NT8aVfThKk7G4OqkVhrXqwsC5soMn/qTCxs36rZ2QFhpfTJcjw4SNDIZ4RUb8OL4jQ==
@ -1294,11 +1294,32 @@
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
"@nodelib/fs.scandir@2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==
dependencies:
"@nodelib/fs.stat" "2.0.3"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3"
integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==
"@nodelib/fs.stat@^1.1.2":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@nodelib/fs.walk@^1.2.3":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976"
integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==
dependencies:
"@nodelib/fs.scandir" "2.1.3"
fastq "^1.6.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"
@ -3864,6 +3885,13 @@ braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
braces@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
brorand@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@ -5111,6 +5139,11 @@ core-js-pure@^3.0.1:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.2.1.tgz#879a23699cff46175bfd2d09158b5c50645a3c45"
integrity sha512-+qpvnYrsi/JDeQTArB7NnNc2VoMYLE1YSkziCDHgjexC2KH7OFiGhLUd3urxfyWmNjSwSW7NYXPWHMhuIJx9Ow==
core-js@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.0.tgz#df408ab46d01aff91c01c3e7971935d422c54f81"
integrity sha1-30CKtG0Br/kcAcPnlxk11CLFT4E=
core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
@ -7071,6 +7104,18 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-glob@3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.1.tgz#c5aaea632f92543b744bdcb19f11efd49e56c7b3"
integrity sha512-XObtOQLTl4EptWcBbO9O6wd17VlVf9YXYY/zuzuu7nZfTsv4BL3KupMAMUVzH88CUwWkI3uNHBfxtfU8PveVTQ==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
glob-parent "^5.1.0"
merge2 "^1.3.0"
micromatch "^4.0.2"
picomatch "^2.2.1"
fast-glob@^2.0.2:
version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
@ -7095,6 +7140,13 @@ fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
fastq@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2"
integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==
dependencies:
reusify "^1.0.0"
fault@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.3.tgz#4da88cf979b6b792b4e13c7ec836767725170b7e"
@ -7261,6 +7313,13 @@ fill-range@^4.0.0:
repeat-string "^1.6.1"
to-regex-range "^2.1.0"
fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
finalhandler@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
@ -7825,6 +7884,13 @@ glob-parent@^3.1.0:
is-glob "^3.1.0"
path-dirname "^1.0.0"
glob-parent@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
dependencies:
is-glob "^4.0.1"
glob-to-regexp@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
@ -9345,6 +9411,13 @@ is-glob@^4.0.0:
dependencies:
is-extglob "^2.1.1"
is-glob@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
is-hexadecimal@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69"
@ -9394,6 +9467,11 @@ is-number@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
is-number@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-obj@^1.0.0, is-obj@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
@ -10687,6 +10765,11 @@ merge2@^1.2.3:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.4.tgz#c9269589e6885a60cf80605d9522d4b67ca646e3"
integrity sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==
merge2@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@ -10732,6 +10815,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.2"
micromatch@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
dependencies:
braces "^3.0.1"
picomatch "^2.0.5"
miller-rabin@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@ -11448,17 +11539,17 @@ normalize-package-data@^2.5.0:
semver "2 || 3 || 4 || 5"
validate-npm-package-license "^3.0.1"
normalize-path@3.0.0, normalize-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
dependencies:
remove-trailing-separator "^1.0.1"
normalize-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalize-range@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
@ -12294,6 +12385,11 @@ phantomjs-prebuilt@^2.1.14:
request-progress "^2.0.1"
which "^1.2.10"
picomatch@^2.0.5, picomatch@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
pidtree@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.0.tgz#f6fada10fccc9f99bf50e90d0b23d72c9ebc2e6b"
@ -14561,6 +14657,11 @@ retry@^0.12.0:
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
reusify@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rgb2hex@^0.1.9:
version "0.1.9"
resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.9.tgz#5d3e0e14b0177b568e6f0d5b43e34fbfdb670346"
@ -14620,6 +14721,11 @@ run-async@^2.2.0:
dependencies:
is-promise "^2.1.0"
run-parallel@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
run-queue@^1.0.0, run-queue@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
@ -16251,6 +16357,13 @@ to-regex-range@^2.1.0:
is-number "^3.0.0"
repeat-string "^1.6.1"
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"