UI for blacklisting unverified devices per-room & globally

(written blind; untested as yet)
pull/21833/head
Matthew Hodgson 2017-01-21 17:39:31 +00:00
parent 2e15e8f9b4
commit 3071fc0ddc
4 changed files with 94 additions and 3 deletions

View File

@ -149,6 +149,22 @@ module.exports = {
return MatrixClientPeg.get().setAccountData("im.vector.web.settings", settings);
},
getLocalSettings: function() {
return localStorage.getItem('mx_local_settings');
},
getLocalSetting: function(type, defaultValue = null) {
var settings = this.getLocalSettings();
return settings.hasOwnProperty(type) ? settings[type] : null;
},
setLocalSetting: function(type, value) {
var settings = this.getLocalSettings();
settings[type] = value;
// FIXME: handle errors
localStorage.setItem('mx_local_settings', settings);
},
isFeatureEnabled: function(feature: string): boolean {
// Disable labs for guests.
if (MatrixClientPeg.get().isGuest()) return false;

View File

@ -57,6 +57,18 @@ const SETTINGS_LABELS = [
*/
];
const CRYPTO_SETTINGS_LABELS = [
{
id: 'blacklistUnverifiedDevices',
label: 'Never send encrypted messages to unverified devices',
},
// XXX: this is here for documentation; the actual setting is managed via RoomSettings
// {
// id: 'blacklistUnverifiedDevicesPerRoom'
// label: 'Never send encrypted messages to unverified devices in this room',
// }
];
// Enumerate the available themes, with a nice human text label.
// 'id' gives the key name in the im.vector.web.settings account data event
// 'value' is the value for that key in the event
@ -146,6 +158,8 @@ module.exports = React.createClass({
syncedSettings.theme = 'light';
}
this._syncedSettings = syncedSettings;
this._localSettings = UserSettingsStore.getLocalSettings();
},
componentDidMount: function() {
@ -471,10 +485,32 @@ module.exports = React.createClass({
<li><label>Device key:</label> <span><code><b>{identityKey}</b></code></span></li>
</ul>
</div>
{ CRYPTO_SETTINGS_LABELS.map( this._renderLocalSetting ) }
</div>
);
},
_renderLocalSetting: function(setting) {
const client = MatrixClientPeg.get();
return <div className="mx_UserSettings_toggle" key={ setting.id }>
<input id={ setting.id }
type="checkbox"
defaultChecked={ this._localSettings[setting.id] }
onChange={
e => {
UserSettingsStore.setLocalSetting(setting.id, e.target.checked)
if (setting.id === 'blacklistUnverifiedDevices') { // XXX: this is a bit ugly
client.setGlobalBlacklistUnverifiedDevices(e.target.checked);
}
}
}
/>
<label htmlFor={ setting.id }>
{ setting.label }
</label>
</div>;
},
_renderDevicesPanel: function() {
var DevicesPanel = sdk.getComponent('settings.DevicesPanel');
return (

View File

@ -69,5 +69,7 @@ module.exports = React.createClass({
</div>
</div>
);
// XXX: do we want to give the user the option to enable blacklistUnverifiedDevices for this room (or globally) at this point?
// It feels like confused users will likely turn it on and then disappear in a cloud of UISIs...
}
});

View File

@ -228,11 +228,13 @@ module.exports = React.createClass({
}
// encryption
p = this.saveEncryption();
p = this.saveEnableEncryption();
if (!q.isFulfilled(p)) {
promises.push(p);
}
this.saveBlacklistUnverifiedDevicesPerRoom();
console.log("Performing %s operations: %s", promises.length, JSON.stringify(promises));
return promises;
},
@ -252,11 +254,11 @@ module.exports = React.createClass({
return this.refs.url_preview_settings.saveSettings();
},
saveEncryption: function() {
saveEnableEncryption: function() {
if (!this.refs.encrypt) { return q(); }
var encrypt = this.refs.encrypt.checked;
if (!encrypt) { return q(); }
if (encrypt) { return q(); }
var roomId = this.props.room.roomId;
return MatrixClientPeg.get().sendStateEvent(
@ -265,6 +267,29 @@ module.exports = React.createClass({
);
},
saveBlacklistUnverifiedDevicesPerRoom: function() {
if (!this.refs.blacklistUnverified) return;
if (this._isRoomBlacklistUnverified() !== this.refs.blacklistUnverified.checked) {
this._setRoomBlacklistUnverified(this.refs.blacklistUnverified.checked);
}
},
_isRoomBlacklistUnverified: function() {
var blacklistUnverifiedDevicesPerRoom = UserSettingsStore.getLocalSettings().blacklistUnverifiedDevicesPerRoom;
if (blacklistUnverifiedDevicesPerRoom) {
return blacklistUnverifiedDevicesPerRoom[this.props.room.roomId];
}
return false;
},
_setRoomBlacklistUnverified: function(value) {
var blacklistUnverifiedDevicesPerRoom = UserSettingsStore.getLocalSettings().blacklistUnverifiedDevicesPerRoom;
blacklistUnverifiedDevicesPerRoom[this.props.room.roomId] = value;
UserSettingsStore.setLocalSettings('blacklistUnverifiedDevicesPerRoom', blacklistUnverifiedDevicesPerRoom);
this.props.room.setBlacklistUnverifiedDevices(value);
},
_hasDiff: function(strA, strB) {
// treat undefined as an empty string because other components may blindly
// call setName("") when there has been no diff made to the name!
@ -477,6 +502,16 @@ module.exports = React.createClass({
var cli = MatrixClientPeg.get();
var roomState = this.props.room.currentState;
var isEncrypted = cli.isRoomEncrypted(this.props.room.roomId);
var isGlobalBlacklistUnverified = UserSettingsStore.getLocalSettings().blacklistUnverifiedDevices;
var isRoomBlacklistUnverified = this._isRoomBlacklistUnverified();
var settings =
<label>
<input type="checkbox" ref="blacklistUnverified"
checked={ isGlobalBlacklistUnverified || isRoomBlacklistUnverified }
disabled={ isGlobalBlacklistUnverified || !this.refs.encrypt.checked }/>
Never send encrypted messages to unverified devices in this room.
</label>;
if (!isEncrypted &&
roomState.mayClientSendStateEvent("m.room.encryption", cli)) {
@ -486,6 +521,7 @@ module.exports = React.createClass({
<img className="mx_RoomSettings_e2eIcon" src="img/e2e-unencrypted.svg" width="12" height="12" />
Enable encryption (warning: cannot be disabled again!)
</label>
{ settings }
);
}
else {
@ -497,6 +533,7 @@ module.exports = React.createClass({
}
Encryption is { isEncrypted ? "" : "not " } enabled in this room.
</label>
{ settings }
);
}
},