Merge pull request #46 from matrix-org/bwindels/redesignfixes

Make tests run on redesigned riot
This commit is contained in:
Bruno Windels 2019-04-04 08:20:48 +00:00 committed by GitHub
commit 58e6d1bfd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1714 additions and 469 deletions

4
.gitignore vendored
View file

@ -1,3 +1,3 @@
node_modules node_modules
package-lock.json *.png
*.png riot/env

View file

@ -3,4 +3,4 @@
set -e set -e
./synapse/install.sh ./synapse/install.sh
./riot/install.sh ./riot/install.sh
npm install yarn install

View file

@ -10,10 +10,10 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"cheerio": "^1.0.0-rc.2", "cheerio": "^1.0.0-rc.2",
"commander": "^2.17.1", "commander": "^2.19.0",
"puppeteer": "^1.6.0", "puppeteer": "^1.14.0",
"request": "^2.88.0", "request": "^2.88.0",
"request-promise-native": "^1.0.5", "request-promise-native": "^1.0.7",
"uuid": "^3.3.2" "uuid": "^3.3.2"
} }
} }

View file

@ -8,27 +8,28 @@ if [ -d $BASE_DIR/riot-web ]; then
exit exit
fi fi
cd $BASE_DIR
# Install ComplexHttpServer (a drop in replacement for Python's SimpleHttpServer # Install ComplexHttpServer (a drop in replacement for Python's SimpleHttpServer
# but with support for multiple threads) into a virtualenv. # but with support for multiple threads) into a virtualenv.
( (
virtualenv $BASE_DIR/env virtualenv -p python3 env
source $BASE_DIR/env/bin/activate source env/bin/activate
# Having been bitten by pip SSL fail too many times, I don't trust the existing pip # Having been bitten by pip SSL fail too many times, I don't trust the existing pip
# to be able to --upgrade itself, so grab a new one fresh from source. # to be able to --upgrade itself, so grab a new one fresh from source.
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py python get-pip.py
rm get-pip.py
pip install ComplexHttpServer pip install ComplexHttpServer
deactivate deactivate
) )
cd $BASE_DIR
curl -L https://github.com/vector-im/riot-web/archive/${RIOT_BRANCH}.zip --output riot.zip curl -L https://github.com/vector-im/riot-web/archive/${RIOT_BRANCH}.zip --output riot.zip
unzip -q riot.zip unzip -q riot.zip
rm riot.zip rm riot.zip
mv riot-web-${RIOT_BRANCH} riot-web mv riot-web-${RIOT_BRANCH} riot-web
cd riot-web cd riot-web
npm install yarn install
npm run build yarn run build

View file

@ -21,7 +21,7 @@ const roomDirectoryScenarios = require('./scenarios/directory');
const lazyLoadingScenarios = require('./scenarios/lazy-loading'); const lazyLoadingScenarios = require('./scenarios/lazy-loading');
const e2eEncryptionScenarios = require('./scenarios/e2e-encryption'); const e2eEncryptionScenarios = require('./scenarios/e2e-encryption');
module.exports = async function scenario(createSession, restCreator, runningOnTravis) { module.exports = async function scenario(createSession, restCreator) {
async function createUser(username) { async function createUser(username) {
const session = await createSession(username); const session = await createSession(username);
await signup(session, session.username, 'testtest', session.hsUrl); await signup(session, session.username, 'testtest', session.hsUrl);
@ -33,17 +33,9 @@ module.exports = async function scenario(createSession, restCreator, runningOnTr
await roomDirectoryScenarios(alice, bob); await roomDirectoryScenarios(alice, bob);
await e2eEncryptionScenarios(alice, bob); await e2eEncryptionScenarios(alice, bob);
console.log("create REST users:");
// disable LL tests until we can run synapse on anything > than 2.7.7 as const charlies = await createRestUsers(restCreator);
// /admin/register fails with a missing method. await lazyLoadingScenarios(alice, bob, charlies);
// either switch to python3 on synapse,
// blocked on https://github.com/matrix-org/synapse/issues/3900
// or use a more recent version of ubuntu
// or switch to circleci?
if (!runningOnTravis) {
const charlies = await createRestUsers(restCreator);
await lazyLoadingScenarios(alice, bob, charlies);
}
} }
async function createRestUsers(restCreator) { async function createRestUsers(restCreator) {

View file

@ -18,7 +18,7 @@ limitations under the License.
const join = require('../usecases/join'); const join = require('../usecases/join');
const sendMessage = require('../usecases/send-message'); const sendMessage = require('../usecases/send-message');
const {receiveMessage} = require('../usecases/timeline'); const {receiveMessage} = require('../usecases/timeline');
const createRoom = require('../usecases/create-room'); const {createRoom} = require('../usecases/create-room');
const changeRoomSettings = require('../usecases/room-settings'); const changeRoomSettings = require('../usecases/room-settings');
module.exports = async function roomDirectoryScenarios(alice, bob) { module.exports = async function roomDirectoryScenarios(alice, bob) {

View file

@ -22,30 +22,27 @@ const sendMessage = require('../usecases/send-message');
const acceptInvite = require('../usecases/accept-invite'); const acceptInvite = require('../usecases/accept-invite');
const invite = require('../usecases/invite'); const invite = require('../usecases/invite');
const {receiveMessage} = require('../usecases/timeline'); const {receiveMessage} = require('../usecases/timeline');
const createRoom = require('../usecases/create-room'); const {createRoom} = require('../usecases/create-room');
const changeRoomSettings = require('../usecases/room-settings'); const changeRoomSettings = require('../usecases/room-settings');
const {getE2EDeviceFromSettings} = require('../usecases/settings'); const {startSasVerifcation, acceptSasVerification} = require('../usecases/verify');
const {verifyDeviceForUser} = require('../usecases/memberlist'); const assert = require('assert');
module.exports = async function e2eEncryptionScenarios(alice, bob) { module.exports = async function e2eEncryptionScenarios(alice, bob) {
console.log(" creating an e2e encrypted room and join through invite:"); console.log(" creating an e2e encrypted room and join through invite:");
const room = "secrets"; const room = "secrets";
await createRoom(bob, room); await createRoom(bob, room);
await changeRoomSettings(bob, {encryption: true}); await changeRoomSettings(bob, {encryption: true});
// await cancelKeyBackup(bob);
await invite(bob, "@alice:localhost"); await invite(bob, "@alice:localhost");
await acceptInvite(alice, room); await acceptInvite(alice, room);
const bobDevice = await getE2EDeviceFromSettings(bob); // do sas verifcation
// wait some time for the encryption warning dialog bob.log.step(`starts SAS verification with ${alice.username}`);
// to appear after closing the settings const bobSasPromise = startSasVerifcation(bob, alice.username);
await delay(1000); const aliceSasPromise = acceptSasVerification(alice, bob.username);
await acceptDialogMaybe(bob, "encryption"); // wait in parallel, so they don't deadlock on each other
const aliceDevice = await getE2EDeviceFromSettings(alice); const [bobSas, aliceSas] = await Promise.all([bobSasPromise, aliceSasPromise]);
// wait some time for the encryption warning dialog assert.deepEqual(bobSas, aliceSas);
// to appear after closing the settings bob.log.done(`done (match for ${bobSas.join(", ")})`);
await delay(1000);
await acceptDialogMaybe(alice, "encryption");
await verifyDeviceForUser(bob, "alice", aliceDevice);
await verifyDeviceForUser(alice, "bob", bobDevice);
const aliceMessage = "Guess what I just heard?!" const aliceMessage = "Guess what I just heard?!"
await sendMessage(alice, aliceMessage); await sendMessage(alice, aliceMessage);
await receiveMessage(bob, {sender: "alice", body: aliceMessage, encrypted: true}); await receiveMessage(bob, {sender: "alice", body: aliceMessage, encrypted: true});

View file

@ -22,7 +22,7 @@ const {
checkTimelineContains, checkTimelineContains,
scrollToTimelineTop scrollToTimelineTop
} = require('../usecases/timeline'); } = require('../usecases/timeline');
const createRoom = require('../usecases/create-room'); const {createRoom} = require('../usecases/create-room');
const {getMembersInMemberlist} = require('../usecases/memberlist'); const {getMembersInMemberlist} = require('../usecases/memberlist');
const changeRoomSettings = require('../usecases/room-settings'); const changeRoomSettings = require('../usecases/room-settings');
const {enableLazyLoading} = require('../usecases/settings'); const {enableLazyLoading} = require('../usecases/settings');
@ -30,7 +30,6 @@ const assert = require('assert');
module.exports = async function lazyLoadingScenarios(alice, bob, charlies) { module.exports = async function lazyLoadingScenarios(alice, bob, charlies) {
console.log(" creating a room for lazy loading member scenarios:"); console.log(" creating a room for lazy loading member scenarios:");
await enableLazyLoading(alice);
const charly1to5 = charlies.slice("charly-1..5", 0, 5); const charly1to5 = charlies.slice("charly-1..5", 0, 5);
const charly6to10 = charlies.slice("charly-6..10", 5); const charly6to10 = charlies.slice("charly-6..10", 5);
assert(charly1to5.sessions.length, 5); assert(charly1to5.sessions.length, 5);

View file

@ -161,15 +161,6 @@ module.exports = class RiotSession {
}); });
} }
waitForSyncResponseWith(predicate) {
return this.page.waitForResponse(async (response) => {
if (response.request().url().indexOf("/sync") === -1) {
return false;
}
return predicate(response);
});
}
/** wait for a /sync request started after this call that gets a 200 response */ /** wait for a /sync request started after this call that gets a 200 response */
async waitForNextSuccessfulSync() { async waitForNextSuccessfulSync() {
const syncUrls = []; const syncUrls = [];

View file

@ -34,8 +34,5 @@ module.exports = async function acceptInvite(session, name) {
const acceptInvitationLink = await session.waitAndQuery(".mx_RoomPreviewBar_join_text a:first-child"); const acceptInvitationLink = await session.waitAndQuery(".mx_RoomPreviewBar_join_text a:first-child");
await acceptInvitationLink.click(); await acceptInvitationLink.click();
// accept e2e warning dialog
acceptDialogMaybe(session, "encryption");
session.log.done(); session.log.done();
} }

View file

@ -16,10 +16,22 @@ limitations under the License.
const assert = require('assert'); const assert = require('assert');
module.exports = async function createRoom(session, roomName) { async function openRoomDirectory(session) {
const roomListHeaders = await session.queryAll('.mx_RoomSubList_labelContainer');
const roomListHeaderLabels = await Promise.all(roomListHeaders.map(h => session.innerText(h)));
const roomsIndex = roomListHeaderLabels.findIndex(l => l.toLowerCase().includes("rooms"));
if (roomsIndex === -1) {
throw new Error("could not find room list section that contains rooms in header");
}
const roomsHeader = roomListHeaders[roomsIndex];
const addRoomButton = await roomsHeader.$(".mx_RoomSubList_addRoom");
await addRoomButton.click();
}
async function createRoom(session, roomName) {
session.log.step(`creates room "${roomName}"`); session.log.step(`creates room "${roomName}"`);
//TODO: brittle selector await openRoomDirectory(session);
const createRoomButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Create new room"]'); const createRoomButton = await session.waitAndQuery('.mx_RoomDirectory_createRoom');
await createRoomButton.click(); await createRoomButton.click();
const roomNameInput = await session.waitAndQuery('.mx_CreateRoomDialog_input'); const roomNameInput = await session.waitAndQuery('.mx_CreateRoomDialog_input');
@ -30,4 +42,6 @@ module.exports = async function createRoom(session, roomName) {
await session.waitAndQuery('.mx_MessageComposer'); await session.waitAndQuery('.mx_MessageComposer');
session.log.done(); session.log.done();
} }
module.exports = {openRoomDirectory, createRoom};

View file

@ -16,32 +16,35 @@ limitations under the License.
const assert = require('assert'); const assert = require('assert');
async function assertDialog(session, expectedTitle) {
const titleElement = await session.waitAndQuery(".mx_Dialog .mx_Dialog_title");
const dialogHeader = await session.innerText(titleElement);
assert(dialogHeader, expectedTitle);
}
async function acceptDialog(session, expectedContent) { async function acceptDialog(session, expectedTitle) {
const foundDialog = await acceptDialogMaybe(session, expectedContent); const foundDialog = await acceptDialogMaybe(session, expectedTitle);
if (!foundDialog) { if (!foundDialog) {
throw new Error("could not find a dialog"); throw new Error("could not find a dialog");
} }
} }
async function acceptDialogMaybe(session, expectedContent) { async function acceptDialogMaybe(session, expectedTitle) {
let dialog = null; let primaryButton = null;
try { try {
dialog = await session.waitAndQuery(".mx_QuestionDialog"); primaryButton = await session.waitAndQuery(".mx_Dialog .mx_Dialog_primary", 50);
} catch(err) { } catch(err) {
return false; return false;
} }
if (expectedContent) { if (expectedTitle) {
const contentElement = await dialog.$(".mx_Dialog_content"); await assertDialog(session, expectedTitle);
const content = await (await contentElement.getProperty("innerText")).jsonValue();
assert.ok(content.indexOf(expectedContent) !== -1);
} }
const primaryButton = await dialog.$(".mx_Dialog_primary");
await primaryButton.click(); await primaryButton.click();
return true; return true;
} }
module.exports = { module.exports = {
assertDialog,
acceptDialog, acceptDialog,
acceptDialogMaybe, acceptDialogMaybe,
}; };

View file

@ -19,7 +19,7 @@ const assert = require('assert');
module.exports = async function invite(session, userId) { module.exports = async function invite(session, userId) {
session.log.step(`invites "${userId}" to room`); session.log.step(`invites "${userId}" to room`);
await session.delay(1000); await session.delay(1000);
const inviteButton = await session.waitAndQuery(".mx_RightPanel_invite"); const inviteButton = await session.waitAndQuery(".mx_MemberList_invite");
await inviteButton.click(); await inviteButton.click();
const inviteTextArea = await session.waitAndQuery(".mx_ChatInviteDialog textarea"); const inviteTextArea = await session.waitAndQuery(".mx_ChatInviteDialog textarea");
await inviteTextArea.type(userId); await inviteTextArea.type(userId);

View file

@ -15,14 +15,12 @@ limitations under the License.
*/ */
const assert = require('assert'); const assert = require('assert');
const {openRoomDirectory} = require('./create-room');
module.exports = async function join(session, roomName) { module.exports = async function join(session, roomName) {
session.log.step(`joins room "${roomName}"`); session.log.step(`joins room "${roomName}"`);
//TODO: brittle selector await openRoomDirectory(session);
const directoryButton = await session.waitAndQuery('.mx_RoleButton[aria-label="Room directory"]'); const roomInput = await session.waitAndQuery('.mx_DirectorySearchBox input');
await directoryButton.click();
const roomInput = await session.waitAndQuery('.mx_DirectorySearchBox_input');
await session.replaceInputText(roomInput, roomName); await session.replaceInputText(roomInput, roomName);
const firstRoomLabel = await session.waitAndQuery('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child', 1000); const firstRoomLabel = await session.waitAndQuery('.mx_RoomDirectory_table .mx_RoomDirectory_name:first-child', 1000);
@ -33,4 +31,4 @@ module.exports = async function join(session, roomName) {
await session.waitAndQuery('.mx_MessageComposer'); await session.waitAndQuery('.mx_MessageComposer');
session.log.done(); session.log.done();
} }

View file

@ -16,6 +16,16 @@ limitations under the License.
const assert = require('assert'); const assert = require('assert');
async function openMemberInfo(session, name) {
const membersAndNames = await getMembersInMemberlist(session);
const matchingLabel = membersAndNames.filter((m) => {
return m.displayName === name;
}).map((m) => m.label)[0];
await matchingLabel.click();
};
module.exports.openMemberInfo = openMemberInfo;
module.exports.verifyDeviceForUser = async function(session, name, expectedDevice) { module.exports.verifyDeviceForUser = async function(session, name, expectedDevice) {
session.log.step(`verifies e2e device for ${name}`); session.log.step(`verifies e2e device for ${name}`);
const membersAndNames = await getMembersInMemberlist(session); const membersAndNames = await getMembersInMemberlist(session);
@ -23,8 +33,20 @@ module.exports.verifyDeviceForUser = async function(session, name, expectedDevic
return m.displayName === name; return m.displayName === name;
}).map((m) => m.label)[0]; }).map((m) => m.label)[0];
await matchingLabel.click(); await matchingLabel.click();
// click verify in member info
const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify"); const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify");
await firstVerifyButton.click(); await firstVerifyButton.click();
// expect "Verify device" dialog and click "Begin Verification"
const dialogHeader = await session.innerText(await session.waitAndQuery(".mx_Dialog .mx_Dialog_title"));
assert(dialogHeader, "Verify device");
const beginVerificationButton = await session.waitAndQuery(".mx_Dialog .mx_Dialog_primary")
await beginVerificationButton.click();
// get emoji SAS labels
const sasLabelElements = await session.waitAndQueryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label");
const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e)));
console.log("my sas labels", sasLabels);
const dialogCodeFields = await session.waitAndQueryAll(".mx_QuestionDialog code"); const dialogCodeFields = await session.waitAndQueryAll(".mx_QuestionDialog code");
assert.equal(dialogCodeFields.length, 2); assert.equal(dialogCodeFields.length, 2);
const deviceId = await session.innerText(dialogCodeFields[0]); const deviceId = await session.innerText(dialogCodeFields[0]);

View file

@ -17,11 +17,11 @@ limitations under the License.
const assert = require('assert'); const assert = require('assert');
const {acceptDialog} = require('./dialog'); const {acceptDialog} = require('./dialog');
async function setCheckboxSetting(session, checkbox, enabled) { async function setSettingsToggle(session, toggle, enabled) {
const checked = await session.getElementProperty(checkbox, "checked"); const className = await session.getElementProperty(toggle, "className");
assert.equal(typeof checked, "boolean"); const checked = className.includes("mx_ToggleSwitch_on");
if (checked !== enabled) { if (checked !== enabled) {
await checkbox.click(); await toggle.click();
session.log.done(); session.log.done();
return true; return true;
} else { } else {
@ -31,34 +31,50 @@ async function setCheckboxSetting(session, checkbox, enabled) {
module.exports = async function changeRoomSettings(session, settings) { module.exports = async function changeRoomSettings(session, settings) {
session.log.startGroup(`changes the room settings`); session.log.startGroup(`changes the room settings`);
/// XXX delay is needed here, possible because the header is being rerendered /// XXX delay is needed here, possibly because the header is being rerendered
/// click doesn't do anything otherwise /// click doesn't do anything otherwise
await session.delay(1000); await session.delay(1000);
const settingsButton = await session.query(".mx_RoomHeader .mx_AccessibleButton[title=Settings]"); const settingsButton = await session.query(".mx_RoomHeader .mx_AccessibleButton[title=Settings]");
await settingsButton.click(); await settingsButton.click();
const checks = await session.waitAndQueryAll(".mx_RoomSettings_settings input[type=checkbox]"); //find tabs
assert.equal(checks.length, 3); const tabButtons = await session.waitAndQueryAll(".mx_RoomSettingsDialog .mx_TabbedView_tabLabel");
const e2eEncryptionCheck = checks[0]; const tabLabels = await Promise.all(tabButtons.map(t => session.innerText(t)));
const sendToUnverifiedDevices = checks[1]; const securityTabButton = tabButtons[tabLabels.findIndex(l => l.toLowerCase().includes("security"))];
const isDirectory = checks[2];
const generalSwitches = await session.waitAndQueryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch");
const isDirectory = generalSwitches[0];
if (typeof settings.directory === "boolean") { if (typeof settings.directory === "boolean") {
session.log.step(`sets directory listing to ${settings.directory}`); session.log.step(`sets directory listing to ${settings.directory}`);
await setCheckboxSetting(session, isDirectory, settings.directory); await setSettingsToggle(session, isDirectory, settings.directory);
} }
if (settings.alias) {
session.log.step(`sets alias to ${settings.alias}`);
const aliasField = await session.waitAndQuery(".mx_RoomSettingsDialog .mx_AliasSettings input[type=text]");
await session.replaceInputText(aliasField, settings.alias);
const addButton = await session.waitAndQuery(".mx_RoomSettingsDialog .mx_AliasSettings .mx_AccessibleButton");
await addButton.click();
session.log.done();
}
securityTabButton.click();
await session.delay(500);
const securitySwitches = await session.queryAll(".mx_RoomSettingsDialog .mx_ToggleSwitch");
const e2eEncryptionToggle = securitySwitches[0];
if (typeof settings.encryption === "boolean") { if (typeof settings.encryption === "boolean") {
session.log.step(`sets room e2e encryption to ${settings.encryption}`); session.log.step(`sets room e2e encryption to ${settings.encryption}`);
const clicked = await setCheckboxSetting(session, e2eEncryptionCheck, settings.encryption); const clicked = await setSettingsToggle(session, e2eEncryptionToggle, settings.encryption);
// if enabling, accept beta warning dialog // if enabling, accept beta warning dialog
if (clicked && settings.encryption) { if (clicked && settings.encryption) {
await acceptDialog(session, "encryption"); await acceptDialog(session, "Enable encryption?");
} }
} }
if (settings.visibility) { if (settings.visibility) {
session.log.step(`sets visibility to ${settings.visibility}`); session.log.step(`sets visibility to ${settings.visibility}`);
const radios = await session.waitAndQueryAll(".mx_RoomSettings_settings input[type=radio]"); const radios = await session.waitAndQueryAll(".mx_RoomSettingsDialog input[type=radio]");
assert.equal(radios.length, 7); assert.equal(radios.length, 7);
const inviteOnly = radios[0]; const inviteOnly = radios[0];
const publicNoGuests = radios[1]; const publicNoGuests = radios[1];
@ -76,15 +92,8 @@ module.exports = async function changeRoomSettings(session, settings) {
session.log.done(); session.log.done();
} }
if (settings.alias) { const closeButton = await session.query(".mx_RoomSettingsDialog .mx_Dialog_cancelButton");
session.log.step(`sets alias to ${settings.alias}`); await closeButton.click();
const aliasField = await session.waitAndQuery(".mx_RoomSettings .mx_EditableItemList .mx_EditableItem_editable");
await session.replaceInputText(aliasField, settings.alias);
session.log.done();
}
const saveButton = await session.query(".mx_RoomHeader_wrapper .mx_RoomHeader_textButton");
await saveButton.click();
session.log.endGroup(); session.log.endGroup();
} }

View file

@ -21,6 +21,9 @@ module.exports = async function sendMessage(session, message) {
// this selector needs to be the element that has contenteditable=true, // this selector needs to be the element that has contenteditable=true,
// not any if its parents, otherwise it behaves flaky at best. // not any if its parents, otherwise it behaves flaky at best.
const composer = await session.waitAndQuery('.mx_MessageComposer_editor'); const composer = await session.waitAndQuery('.mx_MessageComposer_editor');
// sometimes the focus that type() does internally doesn't seem to work
// and calling click before seems to fix it 🤷
await composer.click();
await composer.type(message); await composer.type(message);
const text = await session.innerText(composer); const text = await session.innerText(composer);
assert.equal(text.trim(), message.trim()); assert.equal(text.trim(), message.trim());

View file

@ -16,6 +16,17 @@ limitations under the License.
const assert = require('assert'); const assert = require('assert');
async function openSettings(session, section) {
const menuButton = await session.query(".mx_TopLeftMenuButton_name");
await menuButton.click();
const settingsItem = await session.waitAndQuery(".mx_TopLeftMenu_icon_settings");
await settingsItem.click();
if (section) {
const sectionButton = await session.waitAndQuery(`.mx_UserSettingsDialog .mx_TabbedView_tabLabels .mx_UserSettingsDialog_${section}Icon`);
await sectionButton.click();
}
}
module.exports.enableLazyLoading = async function(session) { module.exports.enableLazyLoading = async function(session) {
session.log.step(`enables lazy loading of members in the lab settings`); session.log.step(`enables lazy loading of members in the lab settings`);
const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); const settingsButton = await session.query('.mx_BottomLeftMenu_settings');
@ -30,13 +41,12 @@ module.exports.enableLazyLoading = async function(session) {
module.exports.getE2EDeviceFromSettings = async function(session) { module.exports.getE2EDeviceFromSettings = async function(session) {
session.log.step(`gets e2e device/key from settings`); session.log.step(`gets e2e device/key from settings`);
const settingsButton = await session.query('.mx_BottomLeftMenu_settings'); await openSettings(session, "security");
await settingsButton.click(); const deviceAndKey = await session.waitAndQueryAll(".mx_SettingsTab_section .mx_SecurityUserSettingsTab_deviceInfo code");
const deviceAndKey = await session.waitAndQueryAll(".mx_UserSettings_section.mx_UserSettings_cryptoSection code");
assert.equal(deviceAndKey.length, 2); assert.equal(deviceAndKey.length, 2);
const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue(); const id = await (await deviceAndKey[0].getProperty("innerText")).jsonValue();
const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue(); const key = await (await deviceAndKey[1].getProperty("innerText")).jsonValue();
const closeButton = await session.query(".mx_RoomHeader_cancelButton"); const closeButton = await session.query(".mx_UserSettingsDialog .mx_Dialog_cancelButton");
await closeButton.click(); await closeButton.click();
session.log.done(); session.log.done();
return {id, key}; return {id, key};

View file

@ -19,31 +19,26 @@ const assert = require('assert');
module.exports = async function signup(session, username, password, homeserver) { module.exports = async function signup(session, username, password, homeserver) {
session.log.step("signs up"); session.log.step("signs up");
await session.goto(session.url('/#/register')); await session.goto(session.url('/#/register'));
//click 'Custom server' radio button // change the homeserver by clicking the "Change" link.
if (homeserver) { if (homeserver) {
const advancedRadioButton = await session.waitAndQuery('#advanced'); const changeServerDetailsLink = await session.waitAndQuery('.mx_AuthBody_editServerDetails');
await advancedRadioButton.click(); await changeServerDetailsLink.click();
const hsInputField = await session.query('#mx_ServerConfig_hsUrl');
await session.replaceInputText(hsInputField, homeserver);
const nextButton = await session.query('.mx_Login_submit');
await nextButton.click();
} }
// wait until register button is visible
await session.waitAndQuery('.mx_Login_submit[value=Register]');
//fill out form //fill out form
const loginFields = await session.queryAll('.mx_Login_field'); const usernameField = await session.waitAndQuery("#mx_RegistrationForm_username");
assert.strictEqual(loginFields.length, 7); const passwordField = await session.waitAndQuery("#mx_RegistrationForm_password");
const usernameField = loginFields[2]; const passwordRepeatField = await session.waitAndQuery("#mx_RegistrationForm_passwordConfirm");
const passwordField = loginFields[3];
const passwordRepeatField = loginFields[4];
const hsurlField = loginFields[5];
await session.replaceInputText(usernameField, username); await session.replaceInputText(usernameField, username);
await session.replaceInputText(passwordField, password); await session.replaceInputText(passwordField, password);
await session.replaceInputText(passwordRepeatField, password); await session.replaceInputText(passwordRepeatField, password);
if (homeserver) { //wait 300ms because Registration/ServerConfig have a 250ms
await session.waitAndQuery('.mx_ServerConfig');
await session.replaceInputText(hsurlField, homeserver);
}
//wait over a second because Registration/ServerConfig have a 1000ms
//delay to internally set the homeserver url //delay to internally set the homeserver url
//see Registration::render and ServerConfig::props::delayTimeMs //see Registration::render and ServerConfig::props::delayTimeMs
await session.delay(1500); await session.delay(300);
/// focus on the button to make sure error validation /// focus on the button to make sure error validation
/// has happened before checking the form is good to go /// has happened before checking the form is good to go
const registerButton = await session.query('.mx_Login_submit'); const registerButton = await session.query('.mx_Login_submit');
@ -60,7 +55,7 @@ module.exports = async function signup(session, username, password, homeserver)
await continueButton.click(); await continueButton.click();
//find the privacy policy checkbox and check it //find the privacy policy checkbox and check it
const policyCheckbox = await session.waitAndQuery('.mx_Login_box input[type="checkbox"]'); const policyCheckbox = await session.waitAndQuery('.mx_InteractiveAuthEntryComponents_termsPolicy input');
await policyCheckbox.click(); await policyCheckbox.click();
//now click the 'Accept' button to agree to the privacy policy //now click the 'Accept' button to agree to the privacy policy

View file

@ -20,7 +20,7 @@ module.exports.scrollToTimelineTop = async function(session) {
session.log.step(`scrolls to the top of the timeline`); session.log.step(`scrolls to the top of the timeline`);
await session.page.evaluate(() => { await session.page.evaluate(() => {
return Promise.resolve().then(async () => { return Promise.resolve().then(async () => {
const timelineScrollView = document.querySelector(".mx_RoomView .gm-scroll-view"); const timelineScrollView = document.querySelector(".mx_RoomView_timeline .mx_ScrollPanel");
let timedOut = false; let timedOut = false;
let timeoutHandle = null; let timeoutHandle = null;
// set scrollTop to 0 in a loop and check every 50ms // set scrollTop to 0 in a loop and check every 50ms
@ -54,31 +54,21 @@ module.exports.receiveMessage = async function(session, expectedMessage) {
let lastMessage = null; let lastMessage = null;
let isExpectedMessage = false; let isExpectedMessage = false;
try { let totalTime = 0;
lastMessage = await getLastMessage(); while (!isExpectedMessage) {
isExpectedMessage = lastMessage && try {
lastMessage.body === expectedMessage.body && lastMessage = await getLastMessage();
lastMessage.sender === expectedMessage.sender; isExpectedMessage = lastMessage &&
} catch(ex) {} lastMessage.body === expectedMessage.body &&
// first try to see if the message is already the last message in the timeline lastMessage.sender === expectedMessage.sender
if (isExpectedMessage) { } catch(err) {}
assertMessage(lastMessage, expectedMessage); if (totalTime > 5000) {
} else { throw new Error("timed out after 5000ms");
await session.waitForSyncResponseWith(async (response) => { }
const body = await response.text(); totalTime += 200;
if (expectedMessage.encrypted) { await session.delay(200);
return body.indexOf(expectedMessage.sender) !== -1 &&
body.indexOf("m.room.encrypted") !== -1;
} else {
return body.indexOf(expectedMessage.body) !== -1;
}
});
// wait a bit for the incoming event to be rendered
await session.delay(1000);
lastMessage = await getLastMessage();
assertMessage(lastMessage, expectedMessage);
} }
assertMessage(lastMessage, expectedMessage);
session.log.done(); session.log.done();
} }
@ -117,11 +107,13 @@ function getLastEventTile(session) {
} }
function getAllEventTiles(session) { function getAllEventTiles(session) {
return session.queryAll(".mx_RoomView_MessageList > *"); return session.queryAll(".mx_RoomView_MessageList .mx_EventTile");
} }
async function getMessageFromEventTile(eventTile) { async function getMessageFromEventTile(eventTile) {
const senderElement = await eventTile.$(".mx_SenderProfile_name"); const senderElement = await eventTile.$(".mx_SenderProfile_name");
const className = await (await eventTile.getProperty("className")).jsonValue();
const classNames = className.split(" ");
const bodyElement = await eventTile.$(".mx_EventTile_body"); const bodyElement = await eventTile.$(".mx_EventTile_body");
let sender = null; let sender = null;
if (senderElement) { if (senderElement) {
@ -131,11 +123,10 @@ async function getMessageFromEventTile(eventTile) {
return null; return null;
} }
const body = await(await bodyElement.getProperty("innerText")).jsonValue(); const body = await(await bodyElement.getProperty("innerText")).jsonValue();
const e2eIcon = await eventTile.$(".mx_EventTile_e2eIcon");
return { return {
sender, sender,
body, body,
encrypted: !!e2eIcon encrypted: classNames.includes("mx_EventTile_verified")
}; };
} }

68
src/usecases/verify.js Normal file
View file

@ -0,0 +1,68 @@
/*
Copyright 2019 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
const assert = require('assert');
const {openMemberInfo} = require("./memberlist");
const {assertDialog, acceptDialog} = require("./dialog");
async function assertVerified(session) {
const dialogSubTitle = await session.innerText(await session.waitAndQuery(".mx_Dialog h2"));
assert(dialogSubTitle, "Verified!");
}
async function startVerification(session, name) {
await openMemberInfo(session, name);
// click verify in member info
const firstVerifyButton = await session.waitAndQuery(".mx_MemberDeviceInfo_verify");
await firstVerifyButton.click();
}
async function getSasCodes(session) {
const sasLabelElements = await session.waitAndQueryAll(".mx_VerificationShowSas .mx_VerificationShowSas_emojiSas .mx_VerificationShowSas_emojiSas_label");
const sasLabels = await Promise.all(sasLabelElements.map(e => session.innerText(e)));
return sasLabels;
}
module.exports.startSasVerifcation = async function(session, name) {
await startVerification(session, name);
// expect "Verify device" dialog and click "Begin Verification"
await assertDialog(session, "Verify device");
// click "Begin Verification"
await acceptDialog(session);
const sasCodes = await getSasCodes(session);
// click "Verify"
await acceptDialog(session);
await assertVerified(session);
// click "Got it" when verification is done
await acceptDialog(session);
return sasCodes;
};
module.exports.acceptSasVerification = async function(session, name) {
await assertDialog(session, "Incoming Verification Request");
const opponentLabelElement = await session.query(".mx_IncomingSasDialog_opponentProfile h2");
const opponentLabel = await session.innerText(opponentLabelElement);
assert(opponentLabel, name);
// click "Continue" button
await acceptDialog(session);
const sasCodes = await getSasCodes(session);
// click "Verify"
await acceptDialog(session);
await assertVerified(session);
// click "Got it" when verification is done
await acceptDialog(session);
return sasCodes;
};

View file

@ -26,7 +26,6 @@ program
.option('--windowed', "dont run tests headless", false) .option('--windowed', "dont run tests headless", false)
.option('--slow-mo', "run tests slower to follow whats going on", false) .option('--slow-mo', "run tests slower to follow whats going on", false)
.option('--dev-tools', "open chrome devtools in browser window", false) .option('--dev-tools', "open chrome devtools in browser window", false)
.option('--travis', "running on travis CI, disable tests known to break on Ubuntu 14.04 LTS", false)
.parse(process.argv); .parse(process.argv);
const hsUrl = 'http://localhost:5005'; const hsUrl = 'http://localhost:5005';
@ -59,7 +58,7 @@ async function runTests() {
let failure = false; let failure = false;
try { try {
await scenario(createSession, restCreator, program.travis); await scenario(createSession, restCreator);
} catch(err) { } catch(err) {
failure = true; failure = true;
console.log('failure: ', err); console.log('failure: ', err);

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@ curl https://codeload.github.com/matrix-org/synapse/zip/$SYNAPSE_BRANCH --output
unzip -q synapse.zip unzip -q synapse.zip
mv synapse-$SYNAPSE_BRANCH $SERVER_DIR mv synapse-$SYNAPSE_BRANCH $SERVER_DIR
cd $SERVER_DIR cd $SERVER_DIR
virtualenv -p python2.7 env virtualenv -p python3 env
source env/bin/activate source env/bin/activate
# Having been bitten by pip SSL fail too many times, I don't trust the existing pip # Having been bitten by pip SSL fail too many times, I don't trust the existing pip
@ -31,10 +31,7 @@ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py python get-pip.py
pip install --upgrade setuptools pip install --upgrade setuptools
python synapse/python_dependencies.py | xargs pip install pip install matrix-synapse[all]
pip install lxml mock
pip install .
pip install jinja2 # We use the ConsentResource, which requires jinja2
python -m synapse.app.homeserver \ python -m synapse.app.homeserver \
--server-name localhost \ --server-name localhost \
--config-path homeserver.yaml \ --config-path homeserver.yaml \

759
yarn.lock Normal file
View file

@ -0,0 +1,759 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
"@types/node@*":
version "11.12.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-11.12.1.tgz#d90123f6c61fdf2f7cddd286ddae891586dd3488"
integrity sha512-sKDlqv6COJrR7ar0+GqqhrXQDzQlMcqMnF2iEU6m9hLo8kxozoAGUazwPyELHlRVmjsbvlnGXjnzyptSXVmceA==
agent-base@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==
dependencies:
es6-promisify "^5.0.0"
ajv@^6.5.5:
version "6.10.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
dependencies:
fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
dependencies:
safer-buffer "~2.1.0"
assert-plus@1.0.0, assert-plus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
async-limiter@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
bcrypt-pbkdf@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
dependencies:
tweetnacl "^0.14.3"
boolbase@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
cheerio@^1.0.0-rc.2:
version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
integrity sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=
dependencies:
css-select "~1.2.0"
dom-serializer "~0.1.0"
entities "~1.1.1"
htmlparser2 "^3.9.1"
lodash "^4.15.0"
parse5 "^3.0.1"
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.7"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828"
integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==
dependencies:
delayed-stream "~1.0.0"
commander@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@1.6.2:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
css-select@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
dependencies:
boolbase "~1.0.0"
css-what "2.1"
domutils "1.5.1"
nth-check "~1.0.1"
css-what@2.1:
version "2.1.3"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
dashdash@^1.12.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
dependencies:
assert-plus "^1.0.0"
debug@2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
debug@^3.1.0:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
dependencies:
ms "^2.1.1"
debug@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
dependencies:
ms "^2.1.1"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
dependencies:
domelementtype "^1.3.0"
entities "^1.1.1"
domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
domhandler@^2.3.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
dependencies:
domelementtype "1"
domutils@1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=
dependencies:
dom-serializer "0"
domelementtype "1"
domutils@^1.5.1:
version "1.7.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
dependencies:
dom-serializer "0"
domelementtype "1"
ecc-jsbn@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
dependencies:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
entities@^1.1.1, entities@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
es6-promise@^4.0.3:
version "4.2.6"
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f"
integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q==
es6-promisify@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
dependencies:
es6-promise "^4.0.3"
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extract-zip@^1.6.6:
version "1.6.7"
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=
dependencies:
concat-stream "1.6.2"
debug "2.6.9"
mkdirp "0.5.1"
yauzl "2.4.1"
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^2.0.1:
version "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-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
fd-slicer@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=
dependencies:
pend "~1.2.0"
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
fs.realpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
dependencies:
assert-plus "^1.0.0"
glob@^7.1.3:
version "7.1.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.0:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
dependencies:
ajv "^6.5.5"
har-schema "^2.0.0"
htmlparser2@^3.9.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
dependencies:
domelementtype "^1.3.1"
domhandler "^2.3.0"
domutils "^1.5.1"
entities "^1.1.1"
inherits "^2.0.1"
readable-stream "^3.1.1"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
https-proxy-agent@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0"
integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==
dependencies:
agent-base "^4.1.0"
debug "^3.1.0"
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
verror "1.10.0"
lodash@^4.15.0, lodash@^4.17.11:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
mime-db@~1.38.0:
version "1.38.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad"
integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
mime-types@^2.1.12, mime-types@~2.1.19:
version "2.1.22"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd"
integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
dependencies:
mime-db "~1.38.0"
mime@^2.0.3:
version "2.4.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.0.tgz#e051fd881358585f3279df333fe694da0bcffdd6"
integrity sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w==
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
mkdirp@0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
dependencies:
minimist "0.0.8"
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
nth-check@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
dependencies:
boolbase "~1.0.0"
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
parse5@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c"
integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==
dependencies:
"@types/node" "*"
path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
pend@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
process-nextick-args@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
progress@^2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
proxy-from-env@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
psl@^1.1.24, psl@^1.1.28:
version "1.1.31"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184"
integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
puppeteer@^1.14.0:
version "1.14.0"
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.14.0.tgz#828c1926b307200d5fc8289b99df4e13e962d339"
integrity sha512-SayS2wUX/8LF8Yo2Rkpc5nkAu4Jg3qu+OLTDSOZtisVQMB2Z5vjlY2TdPi/5CgZKiZroYIiyUN3sRX63El9iaw==
dependencies:
debug "^4.1.0"
extract-zip "^1.6.6"
https-proxy-agent "^2.2.1"
mime "^2.0.3"
progress "^2.0.1"
proxy-from-env "^1.0.0"
rimraf "^2.6.1"
ws "^6.1.0"
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
readable-stream@^2.2.2:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.2.0.tgz#de17f229864c120a9f56945756e4f32c4045245d"
integrity sha512-RV20kLjdmpZuTF1INEb9IA3L68Nmi+Ri7ppZqo78wj//Pn62fCoJyV9zalccNzDD/OuJpMG4f+pfMl8+L6QdGw==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
request-promise-core@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346"
integrity sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==
dependencies:
lodash "^4.17.11"
request-promise-native@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.7.tgz#a49868a624bdea5069f1251d0a836e0d89aa2c59"
integrity sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==
dependencies:
request-promise-core "1.1.2"
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
request@^2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.0"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.4.3"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
rimraf@^2.6.1:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
dependencies:
glob "^7.1.3"
safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
dependencies:
asn1 "~0.2.3"
assert-plus "^1.0.0"
bcrypt-pbkdf "^1.0.0"
dashdash "^1.12.0"
ecc-jsbn "~0.1.1"
getpass "^0.1.1"
jsbn "~0.1.0"
safer-buffer "^2.0.2"
tweetnacl "~0.14.0"
stealthy-require@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
string_decoder@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
dependencies:
safe-buffer "~5.1.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
tough-cookie@^2.3.3:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
dependencies:
psl "^1.1.28"
punycode "^2.1.1"
tough-cookie@~2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
dependencies:
psl "^1.1.24"
punycode "^1.4.1"
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
dependencies:
safe-buffer "^5.0.1"
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
version "0.14.5"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
uri-js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
dependencies:
punycode "^2.1.0"
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
dependencies:
assert-plus "^1.0.0"
core-util-is "1.0.2"
extsprintf "^1.2.0"
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
ws@^6.1.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
dependencies:
async-limiter "~1.0.0"
yauzl@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=
dependencies:
fd-slicer "~1.0.1"