Merge branch 'develop' into t3chguy/password_completion

This commit is contained in:
Michael Telatynski 2020-02-05 20:24:37 +00:00 committed by GitHub
commit 4d0d6cdaa4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
150 changed files with 2181 additions and 4589 deletions

View file

@ -53,6 +53,7 @@ import createRoom from "../../createRoom";
import KeyRequestHandler from '../../KeyRequestHandler';
import { _t, getCurrentLanguage } from '../../languageHandler';
import SettingsStore, {SettingLevel} from "../../settings/SettingsStore";
import ThemeController from "../../settings/controllers/ThemeController";
import { startAnyRegistrationFlow } from "../../Registration.js";
import { messageForSyncError } from '../../utils/ErrorUtils';
import ResizeNotifier from "../../utils/ResizeNotifier";
@ -506,6 +507,8 @@ export default createReactClass({
view: VIEWS.LOGIN,
});
this.notifyNewScreen('login');
ThemeController.isLogin = true;
this._themeWatcher.recheck();
break;
case 'start_post_registration':
this.setState({
@ -760,6 +763,8 @@ export default createReactClass({
}
this.setStateForNewView(newState);
ThemeController.isLogin = true;
this._themeWatcher.recheck();
this.notifyNewScreen('register');
},
@ -910,6 +915,8 @@ export default createReactClass({
view: VIEWS.WELCOME,
});
this.notifyNewScreen('welcome');
ThemeController.isLogin = true;
this._themeWatcher.recheck();
},
_viewHome: function() {
@ -919,6 +926,8 @@ export default createReactClass({
});
this._setPage(PageTypes.HomePage);
this.notifyNewScreen('home');
ThemeController.isLogin = false;
this._themeWatcher.recheck();
},
_viewUser: function(userId, subAction) {
@ -1231,6 +1240,8 @@ export default createReactClass({
});
this.subTitleStatus = '';
this._setPageSubtitle();
ThemeController.isLogin = true;
this._themeWatcher.recheck();
},
/**
@ -1864,7 +1875,9 @@ export default createReactClass({
try {
masterKeyInStorage = !!await cli.getAccountDataFromServer("m.cross_signing.master");
} catch (e) {
if (e.errcode !== "M_NOT_FOUND") throw e;
if (e.errcode !== "M_NOT_FOUND") {
console.warn("Secret storage account data check failed", e);
}
}
if (masterKeyInStorage) {
@ -1983,6 +1996,7 @@ export default createReactClass({
onLoggedIn={this.onRegisterFlowComplete}
onLoginClick={this.onLoginClick}
onServerConfigChange={this.onServerConfigChange}
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
{...this.getServerProperties()}
/>
);

View file

@ -465,6 +465,12 @@ export default class MessagePanel extends React.Component {
}
return false;
};
// events that we include in the group but then eject out and place
// above the group.
const shouldEject = (ev) => {
if (ev.getType() === "m.room.encryption") return true;
return false;
};
if (mxEv.getType() === "m.room.create") {
let summaryReadMarker = null;
const ts1 = mxEv.getTs();
@ -484,6 +490,7 @@ export default class MessagePanel extends React.Component {
}
const summarisedEvents = []; // Don't add m.room.create here as we don't want it inside the summary
const ejectedEvents = [];
for (;i + 1 < this.props.events.length; i++) {
const collapsedMxEv = this.props.events[i + 1];
@ -501,7 +508,11 @@ export default class MessagePanel extends React.Component {
// If RM event is in the summary, mark it as such and the RM will be appended after the summary.
summaryReadMarker = summaryReadMarker || this._readMarkerForEvent(collapsedMxEv.getId());
summarisedEvents.push(collapsedMxEv);
if (shouldEject(collapsedMxEv)) {
ejectedEvents.push(collapsedMxEv);
} else {
summarisedEvents.push(collapsedMxEv);
}
}
// At this point, i = the index of the last event in the summary sequence
@ -513,6 +524,10 @@ export default class MessagePanel extends React.Component {
return this._getTilesForEvent(e, e, e === lastShownEvent);
}).reduce((a, b) => a.concat(b), []);
for (const ejected of ejectedEvents) {
ret.push(...this._getTilesForEvent(mxEv, ejected, last));
}
// Get sender profile from the latest event in the summary as the m.room.create doesn't contain one
const ev = this.props.events[i];
ret.push(<EventListSummary

View file

@ -48,6 +48,7 @@ export default class RightPanel extends React.Component {
phase: this._getPhaseFromProps(),
isUserPrivilegedInGroup: null,
member: this._getUserForPanel(),
verificationRequest: RightPanelStore.getSharedInstance().roomPanelPhaseParams.verificationRequest,
};
this.onAction = this.onAction.bind(this);
this.onRoomStateMember = this.onRoomStateMember.bind(this);
@ -68,15 +69,34 @@ export default class RightPanel extends React.Component {
return this.props.user || lastParams['member'];
}
// gets the current phase from the props and also maybe the store
_getPhaseFromProps() {
const rps = RightPanelStore.getSharedInstance();
const userForPanel = this._getUserForPanel();
if (this.props.groupId) {
if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.groupPanelPhase)) {
dis.dispatch({action: "set_right_panel_phase", phase: RIGHT_PANEL_PHASES.GroupMemberList});
return RIGHT_PANEL_PHASES.GroupMemberList;
}
return rps.groupPanelPhase;
} else if (this._getUserForPanel()) {
} else if (userForPanel) {
// XXX FIXME AAAAAARGH: What is going on with this class!? It takes some of its state
// from its props and some from a store, except if the contents of the store changes
// while it's mounted in which case it replaces all of its state with that of the store,
// except it uses a dispatch instead of a normal store listener?
// Unfortunately rewriting this would almost certainly break showing the right panel
// in some of the many cases, and I don't have time to re-architect it and test all
// the flows now, so adding yet another special case so if the store thinks there is
// a verification going on for the member we're displaying, we show that, otherwise
// we race if a verification is started while the panel isn't displayed because we're
// not mounted in time to get the dispatch.
// Until then, let this code serve as a warning from history.
if (
userForPanel.userId === rps.roomPanelPhaseParams.member.userId &&
rps.roomPanelPhaseParams.verificationRequest
) {
return rps.roomPanelPhase;
}
return RIGHT_PANEL_PHASES.RoomMemberInfo;
} else {
if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.roomPanelPhase)) {

View file

@ -155,7 +155,7 @@ export default createReactClass({
this.nextBatch = data.next_batch;
this.setState((s) => {
s.publicRooms.push(...data.chunk);
s.publicRooms.push(...(data.chunk || []));
s.loading = false;
return s;
});

View file

@ -220,12 +220,12 @@ export default createReactClass({
});
if (hasUDE) {
title = _t("Message not sent due to unknown devices being present");
title = _t("Message not sent due to unknown sessions being present");
content = _t(
"<showDevicesText>Show devices</showDevicesText>, <sendAnywayText>send anyway</sendAnywayText> or <cancelText>cancel</cancelText>.",
"<showSessionsText>Show sessions</showSessionsText>, <sendAnywayText>send anyway</sendAnywayText> or <cancelText>cancel</cancelText>.",
{},
{
'showDevicesText': (sub) => <a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this._onShowDevicesClick}>{ sub }</a>,
'showSessionsText': (sub) => <a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this._onShowDevicesClick}>{ sub }</a>,
'sendAnywayText': (sub) => <a className="mx_RoomStatusBar_resend_link" key="sendAnyway" onClick={this._onSendWithoutVerifyingClick}>{ sub }</a>,
'cancelText': (sub) => <a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={this._onCancelAllClick}>{ sub }</a>,
},

View file

@ -811,7 +811,9 @@ export default createReactClass({
debuglog("e2e verified", verified, "unverified", unverified);
/* Check all verified user devices. */
for (const userId of [...verified, cli.getUserId()]) {
/* Don't alarm if no other users are verified */
const targets = (verified.length > 0) ? [...verified, cli.getUserId()] : verified;
for (const userId of targets) {
const devices = await cli.getStoredDevicesForUser(userId);
const anyDeviceNotVerified = devices.some(({deviceId}) => {
return !cli.checkDeviceTrust(userId, deviceId).isVerified();
@ -820,7 +822,7 @@ export default createReactClass({
this.setState({
e2eStatus: "warning",
});
debuglog("e2e status set to warning as not all users trust all of their devices." +
debuglog("e2e status set to warning as not all users trust all of their sessions." +
" Aborted on user", userId);
return;
}

View file

@ -1,5 +1,6 @@
/*
Copyright 2017, 2018 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -64,8 +65,8 @@ const TagPanel = createReactClass({
this.unmounted = true;
this.context.removeListener("Group.myMembership", this._onGroupMyMembership);
this.context.removeListener("sync", this._onClientSync);
if (this._filterStoreToken) {
this._filterStoreToken.remove();
if (this._tagOrderStoreToken) {
this._tagOrderStoreToken.remove();
}
},

View file

@ -1171,28 +1171,40 @@ const TimelinePanel = createReactClass({
// get the user's membership at the last event by getting the timeline
// that the event belongs to, and traversing the timeline looking for
// that event, while keeping track of the user's membership
const lastEvent = events[events.length - 1];
const timeline = room.getTimelineForEvent(lastEvent.getId());
const userMembershipEvent =
timeline.getState(EventTimeline.FORWARDS).getMember(userId);
let userMembership = userMembershipEvent
? userMembershipEvent.membership : "leave";
const timelineEvents = timeline.getEvents();
for (let i = timelineEvents.length - 1; i >= 0; i--) {
const event = timelineEvents[i];
if (event.getId() === lastEvent.getId()) {
// found the last event, so we can stop looking through the timeline
break;
} else if (event.getStateKey() === userId
&& event.getType() === "m.room.member") {
const prevContent = event.getPrevContent();
userMembership = prevContent.membership || "leave";
let i;
let userMembership = "leave";
for (i = events.length - 1; i >= 0; i--) {
const timeline = room.getTimelineForEvent(events[i].getId());
if (!timeline) {
// Somehow, it seems to be possible for live events to not have
// a timeline, even though that should not happen. :(
// https://github.com/vector-im/riot-web/issues/12120
console.warn(
`Event ${events[i].getId()} in room ${room.roomId} is live, ` +
`but it does not have a timeline`,
);
continue;
}
const userMembershipEvent =
timeline.getState(EventTimeline.FORWARDS).getMember(userId);
userMembership = userMembershipEvent ? userMembershipEvent.membership : "leave";
const timelineEvents = timeline.getEvents();
for (let j = timelineEvents.length - 1; j >= 0; j--) {
const event = timelineEvents[j];
if (event.getId() === events[i].getId()) {
break;
} else if (event.getStateKey() === userId
&& event.getType() === "m.room.member") {
const prevContent = event.getPrevContent();
userMembership = prevContent.membership || "leave";
}
}
break;
}
// now go through the events that we have and find the first undecryptable
// now go through the rest of the events and find the first undecryptable
// one that was sent when the user wasn't in the room
for (let i = events.length - 1; i >= 0; i--) {
for (; i >= 0; i--) {
const event = events[i];
if (event.getStateKey() === userId
&& event.getType() === "m.room.member") {

View file

@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { accessSecretStorage } from '../../../CrossSigningManager';
import { accessSecretStorage, AccessCancelledError } from '../../../CrossSigningManager';
const PHASE_INTRO = 0;
const PHASE_BUSY = 1;
@ -73,6 +73,9 @@ export default class CompleteSecurity extends React.Component {
});
}
} catch (e) {
if (!(e instanceof AccessCancelledError)) {
console.log(e);
}
// this will throw if the user hits cancel, so ignore
this.setState({
phase: PHASE_INTRO,
@ -197,7 +200,7 @@ export default class CompleteSecurity extends React.Component {
body = (
<div>
<p>{_t(
"Without completing security on this device, it wont have " +
"Without completing security on this session, it wont have " +
"access to encrypted messages.",
)}</p>
<div className="mx_CompleteSecurity_actionRow">
@ -220,7 +223,7 @@ export default class CompleteSecurity extends React.Component {
} else if (phase === PHASE_BUSY) {
const Spinner = sdk.getComponent('views.elements.Spinner');
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning"></span>;
title = '';
title = _t("Complete security");
body = <Spinner />;
} else {
throw new Error(`Unknown phase ${phase}`);

View file

@ -152,8 +152,8 @@ export default createReactClass({
<div>
{ _t(
"Changing your password will reset any end-to-end encryption keys " +
"on all of your devices, making encrypted chat history unreadable. Set up " +
"Key Backup or export your room keys from another device before resetting your " +
"on all of your sessions, making encrypted chat history unreadable. Set up " +
"Key Backup or export your room keys from another session before resetting your " +
"password.",
) }
</div>,
@ -358,7 +358,7 @@ export default createReactClass({
return <div>
<p>{_t("Your password has been reset.")}</p>
<p>{_t(
"You have been logged out of all devices and will no longer receive " +
"You have been logged out of all sessions and will no longer receive " +
"push notifications. To re-enable notifications, sign in again on each " +
"device.",
)}</p>

View file

@ -2,7 +2,7 @@
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018, 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -62,6 +62,7 @@ export default createReactClass({
// registration shouldn't know or care how login is done.
onLoginClick: PropTypes.func.isRequired,
onServerConfigChange: PropTypes.func.isRequired,
defaultDeviceDisplayName: PropTypes.string,
},
getInitialState: function() {
@ -432,15 +433,14 @@ export default createReactClass({
// session).
if (!this.state.formVals.password) inhibitLogin = null;
return this.state.matrixClient.register(
this.state.formVals.username,
this.state.formVals.password,
undefined, // session id: included in the auth dict already
auth,
null,
null,
inhibitLogin,
);
const registerParams = {
username: this.state.formVals.username,
password: this.state.formVals.password,
initial_device_display_name: this.props.defaultDeviceDisplayName,
};
if (auth) registerParams.auth = auth;
if (inhibitLogin !== undefined && inhibitLogin !== null) registerParams.inhibitLogin = inhibitLogin;
return this.state.matrixClient.registerRequest(registerParams);
},
_getUIAuthInputs: function() {

View file

@ -83,7 +83,7 @@ export default class SoftLogout extends React.Component {
onFinished: (wipeData) => {
if (!wipeData) return;
console.log("Clearing data from soft-logged-out device");
console.log("Clearing data from soft-logged-out session");
Lifecycle.logout();
},
});
@ -212,8 +212,8 @@ export default class SoftLogout extends React.Component {
let introText = null; // null is translated to something area specific in this function
if (this.state.keyBackupNeeded) {
introText = _t(
"Regain access to your account and recover encryption keys stored on this device. " +
"Without them, you wont be able to read all of your secure messages on any device.");
"Regain access to your account and recover encryption keys stored in this session. " +
"Without them, you wont be able to read all of your secure messages in any session.");
}
if (this.state.loginView === LOGIN_VIEW.PASSWORD) {
@ -306,7 +306,7 @@ export default class SoftLogout extends React.Component {
<p>
{_t(
"Warning: Your personal data (including encryption keys) is still stored " +
"on this device. Clear it if you're finished using this device, or want to sign " +
"in this session. Clear it if you're finished using this session, or want to sign " +
"in to another account.",
)}
</p>