Merge branch 'develop' of https://github.com/matrix-org/matrix-react-sdk into t3chguy/cs_verification_decoration
Conflicts: src/components/views/right_panel/VerificationPanel.js
This commit is contained in:
commit
ddb0f06005
42 changed files with 1083 additions and 110 deletions
|
@ -33,6 +33,10 @@ export default class AuthBody extends React.PureComponent {
|
|||
const classes = {
|
||||
'mx_AuthBody': true,
|
||||
'mx_AuthBody_noHeader': !this.props.header,
|
||||
// XXX The login pages all use a smaller fonts size but we don't want this
|
||||
// for subsequent auth screens like the e2e setup. Doing this a terrible way
|
||||
// for now.
|
||||
'mx_AuthBody_loginRegister': this.props.header,
|
||||
};
|
||||
|
||||
return <div className={classnames(classes)}>
|
||||
|
|
|
@ -641,7 +641,7 @@ const AuthEntryComponents = [
|
|||
TermsAuthEntry,
|
||||
];
|
||||
|
||||
export function getEntryComponentForLoginType(loginType) {
|
||||
export default function getEntryComponentForLoginType(loginType) {
|
||||
for (const c of AuthEntryComponents) {
|
||||
if (c.LOGIN_TYPE == loginType) {
|
||||
return c;
|
||||
|
|
|
@ -27,7 +27,7 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
|||
import {MenuItem} from "../../structures/ContextMenu";
|
||||
import * as sdk from "../../../index";
|
||||
|
||||
export class TopLeftMenu extends React.Component {
|
||||
export default class TopLeftMenu extends React.Component {
|
||||
static propTypes = {
|
||||
displayName: PropTypes.string.isRequired,
|
||||
userId: PropTypes.string.isRequired,
|
||||
|
|
|
@ -16,6 +16,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as sdk from '../../../../index';
|
||||
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
|
||||
import { MatrixClient } from 'matrix-js-sdk';
|
||||
|
@ -32,6 +33,16 @@ const RESTORE_TYPE_SECRET_STORAGE = 2;
|
|||
* Dialog for restoring e2e keys from a backup and the user's recovery key
|
||||
*/
|
||||
export default class RestoreKeyBackupDialog extends React.PureComponent {
|
||||
static propTypes = {
|
||||
// if false, will close the dialog as soon as the restore completes succesfully
|
||||
// default: true
|
||||
showSummary: PropTypes.bool,
|
||||
};
|
||||
|
||||
defaultProps = {
|
||||
showSummary: true,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -96,6 +107,10 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword(
|
||||
this.state.passPhrase, undefined, undefined, this.state.backupInfo,
|
||||
);
|
||||
if (!this.props.showSummary) {
|
||||
this.props.onFinished(true);
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
loading: false,
|
||||
recoverInfo,
|
||||
|
@ -119,6 +134,10 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey(
|
||||
this.state.recoveryKey, undefined, undefined, this.state.backupInfo,
|
||||
);
|
||||
if (!this.props.showSummary) {
|
||||
this.props.onFinished(true);
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
loading: false,
|
||||
recoverInfo,
|
||||
|
@ -253,6 +272,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
title = _t("Error");
|
||||
content = _t("No backup found!");
|
||||
} else if (this.state.recoverInfo) {
|
||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
title = _t("Backup Restored");
|
||||
let failedToDecrypt;
|
||||
if (this.state.recoverInfo.total > this.state.recoverInfo.imported) {
|
||||
|
@ -264,6 +284,11 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
|
|||
content = <div>
|
||||
<p>{_t("Restored %(sessionCount)s session keys", {sessionCount: this.state.recoverInfo.imported})}</p>
|
||||
{failedToDecrypt}
|
||||
<DialogButtons primaryButton={_t('OK')}
|
||||
onPrimaryButtonClick={this._onDone}
|
||||
hasCancel={false}
|
||||
focus={true}
|
||||
/>
|
||||
</div>;
|
||||
} else if (backupHasPassphrase && !this.state.forceRecoveryKey) {
|
||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
|
|
|
@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
|
|||
import * as sdk from '../../../index';
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
||||
import * as recent from './recent';
|
||||
import * as recent from '../../../emojipicker/recent';
|
||||
import {DATA_BY_CATEGORY, getEmojiFromUnicode} from "../../../emoji";
|
||||
|
||||
export const CATEGORY_HEADER_HEIGHT = 22;
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
Copyright 2019 Tulir Asokan <tulir@maunium.net>
|
||||
|
||||
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 REACTION_COUNT = JSON.parse(window.localStorage.mx_reaction_count || '{}');
|
||||
let sorted = null;
|
||||
|
||||
export function add(emoji) {
|
||||
const [count] = REACTION_COUNT[emoji] || [0];
|
||||
REACTION_COUNT[emoji] = [count + 1, Date.now()];
|
||||
window.localStorage.mx_reaction_count = JSON.stringify(REACTION_COUNT);
|
||||
sorted = null;
|
||||
}
|
||||
|
||||
export function get(limit = 24) {
|
||||
if (sorted === null) {
|
||||
sorted = Object.entries(REACTION_COUNT)
|
||||
.sort(([, [count1, date1]], [, [count2, date2]]) =>
|
||||
count2 === count1 ? date2 - date1 : count2 - count1)
|
||||
.map(([emoji, count]) => emoji);
|
||||
}
|
||||
return sorted.slice(0, limit);
|
||||
}
|
|
@ -363,7 +363,7 @@ export default class RoomBreadcrumbs extends React.Component {
|
|||
}
|
||||
|
||||
let dmIndicator;
|
||||
if (this._isDmRoom(r.room)) {
|
||||
if (this._isDmRoom(r.room) && !SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||
dmIndicator = <img
|
||||
src={require("../../../../res/img/icon_person.svg")}
|
||||
className="mx_RoomBreadcrumbs_dmIndicator"
|
||||
|
|
|
@ -31,6 +31,7 @@ import ManageIntegsButton from '../elements/ManageIntegsButton';
|
|||
import {CancelButton} from './SimpleRoomHeader';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import RoomHeaderButtons from '../right_panel/RoomHeaderButtons';
|
||||
import DMRoomMap from '../../../utils/DMRoomMap';
|
||||
import E2EIcon from './E2EIcon';
|
||||
import InviteOnlyIcon from './InviteOnlyIcon';
|
||||
|
||||
|
@ -161,10 +162,12 @@ export default createReactClass({
|
|||
<E2EIcon status={this.props.e2eStatus} /> :
|
||||
undefined;
|
||||
|
||||
const dmUserId = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId);
|
||||
const joinRules = this.props.room && this.props.room.currentState.getStateEvents("m.room.join_rules", "");
|
||||
const joinRule = joinRules && joinRules.getContent().join_rule;
|
||||
let privateIcon;
|
||||
if (SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||
// Don't show an invite-only icon for DMs. Users know they're invite-only.
|
||||
if (!dmUserId && SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||
if (joinRule == "invite") {
|
||||
privateIcon = <InviteOnlyIcon />;
|
||||
}
|
||||
|
|
|
@ -478,8 +478,9 @@ export default createReactClass({
|
|||
|
||||
let dmIndicator;
|
||||
let dmOnline;
|
||||
// If we can place a shield, do that instead
|
||||
if (dmUserId && !this.state.e2eStatus) {
|
||||
/* Post-cross-signing we don't show DM indicators at all, instead relying on user
|
||||
context to let them know when that is. */
|
||||
if (dmUserId && !SettingsStore.isFeatureEnabled("feature_cross_signing")) {
|
||||
dmIndicator = <img
|
||||
src={require("../../../../res/img/icon_person.svg")}
|
||||
className="mx_RoomTile_dm"
|
||||
|
|
|
@ -32,7 +32,7 @@ export default class VerifySessionToast extends React.PureComponent {
|
|||
DeviceListener.sharedInstance().dismissVerification(this.props.deviceId);
|
||||
};
|
||||
|
||||
_onVerifyClick = async () => {
|
||||
_onReviewClick = async () => {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
|
||||
|
||||
|
@ -47,10 +47,10 @@ export default class VerifySessionToast extends React.PureComponent {
|
|||
render() {
|
||||
const FormButton = sdk.getComponent("elements.FormButton");
|
||||
return (<div>
|
||||
<div className="mx_Toast_description">{_t("Other users may not trust it")}</div>
|
||||
<div className="mx_Toast_description">{_t("Review & verify your new session")}</div>
|
||||
<div className="mx_Toast_buttons" aria-live="off">
|
||||
<FormButton label={_t("Later")} kind="danger" onClick={this._onLaterClick} />
|
||||
<FormButton label={_t("Verify")} onClick={this._onVerifyClick} />
|
||||
<FormButton label={_t("Review")} onClick={this._onReviewClick} />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
|
68
src/components/views/toasts/SetupEncryptionToast.js
Normal file
68
src/components/views/toasts/SetupEncryptionToast.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as sdk from "../../../index";
|
||||
import { _t } from '../../../languageHandler';
|
||||
import DeviceListener from '../../../DeviceListener';
|
||||
import { accessSecretStorage } from '../../../CrossSigningManager';
|
||||
|
||||
export default class SetupEncryptionToast extends React.PureComponent {
|
||||
static propTypes = {
|
||||
toastKey: PropTypes.string.isRequired,
|
||||
kind: PropTypes.oneOf(['set_up_encryption', 'verify_this_session', 'upgrade_encryption']).isRequired,
|
||||
};
|
||||
|
||||
_onLaterClick = () => {
|
||||
DeviceListener.sharedInstance().dismissEncryptionSetup();
|
||||
};
|
||||
|
||||
_onSetupClick = async () => {
|
||||
accessSecretStorage();
|
||||
};
|
||||
|
||||
getDescription() {
|
||||
switch (this.props.kind) {
|
||||
case 'set_up_encryption':
|
||||
case 'upgrade_encryption':
|
||||
return _t('Verify your other devices easier');
|
||||
case 'verify_this_session':
|
||||
return _t('Other users may not trust it');
|
||||
}
|
||||
}
|
||||
|
||||
getSetupCaption() {
|
||||
switch (this.props.kind) {
|
||||
case 'set_up_encryption':
|
||||
case 'upgrade_encryption':
|
||||
return _t('Upgrade');
|
||||
case 'verify_this_session':
|
||||
return _t('Verify');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const FormButton = sdk.getComponent("elements.FormButton");
|
||||
return (<div>
|
||||
<div className="mx_Toast_description">{this.getDescription()}</div>
|
||||
<div className="mx_Toast_buttons" aria-live="off">
|
||||
<FormButton label={_t("Later")} kind="danger" onClick={this._onLaterClick} />
|
||||
<FormButton label={this.getSetupCaption()} onClick={this._onSetupClick} />
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
|
@ -39,6 +39,13 @@ export default class VerificationRequestToast extends React.PureComponent {
|
|||
this.setState({counter});
|
||||
}, 1000);
|
||||
request.on("change", this._checkRequestIsPending);
|
||||
// We should probably have a separate class managing the active verification toasts,
|
||||
// rather than monitoring this in the toast component itself, since we'll get problems
|
||||
// like the toasdt not going away when the verification is cancelled unless it's the
|
||||
// one on the top (ie. the one that's mounted).
|
||||
// As a quick & dirty fix, check the toast is still relevant when it mounts (this prevents
|
||||
// a toast hanging around after logging in if you did a verification as part of login).
|
||||
this._checkRequestIsPending();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue