Commit 19dc6690 authored by JC Brand's avatar JC Brand

Split the `trusted` setting into two new ones:

- `allow_user_trust_override`
- `clear_cache_on_logout`

The `persistent_store` setting can now also be set to `sessionStorage`

The `trusted` settings was in effect playing the role of two separate settings
and implicitly affecting a third ('persistent_store').

By breaking it up, we make things more explicit and allow for new
configurations. For example, clearing the cache on logout, while using
some kind of persistent store.
parent 5341a1ea
......@@ -36,6 +36,10 @@ Soon we'll deprecate the latter, so prepare now.
- #2220: fix rendering of emojis in case `use_system_emojis == false` (again).
- #2092: fixes room list update loop when having the `locked_muc_domain` truthy or `'hidden'`
- #2285: Rename config option `muc_hats_from_vcard` to [muc_hats](https://conversejs.org/docs/html/configuration.html#muc-hats). Now accepts a list instead of a boolean and allows for more flexible choices regarding user badges.
- The `trusted` configuration setting has been removed in favor of two new settings:
[allow_user_trust_override](https://conversejs.org/docs/html/configuration.html#allow-user-trust-override)
[clear_cache_on_logout](https://conversejs.org/docs/html/configuration.html#clear-cache-on-logout)
- The `persistent_store` setting can now also be set to `sessionStorage`
- The `api.archive.query` method no longer accepts an RSM instance as argument.
- The plugin `converse-uniview` has been removed and its functionality merged into `converse-chatboxviews`
- Removed the mockups from the project. Recommended to use tests instead.
......
This diff is collapsed.
/*global mock */
/*global mock, converse */
const u = converse.env.utils;
......@@ -11,8 +11,8 @@ describe("The Login Form", function () {
allow_registration: false },
async function (done, _converse) {
mock.openControlBox(_converse);
const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
mock.toggleControlBox();
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1);
......@@ -24,17 +24,16 @@ describe("The Login Form", function () {
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
cbview.el.querySelector('input[name="password"]').value = 'secret';
spyOn(cbview.loginpanel, 'connect');
cbview.delegateEvents();
expect(_converse.config.get('storage')).toBe('persistent');
expect(_converse.config.get('trusted')).toBe(true);
expect(_converse.getDefaultStore()).toBe('persistent');
cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('persistent');
expect(cbview.loginpanel.connect).toHaveBeenCalled();
expect(_converse.config.get('trusted')).toBe(true);
expect(_converse.getDefaultStore()).toBe('persistent');
checkbox.click();
cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('session');
expect(_converse.config.get('trusted')).toBe(false);
expect(_converse.getDefaultStore()).toBe('session');
done();
}));
......@@ -42,36 +41,32 @@ describe("The Login Form", function () {
mock.initConverse(
['chatBoxesInitialized'],
{ auto_login: false,
trusted: false,
allow_user_trust_override: 'off',
allow_registration: false },
function (done, _converse) {
u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
.then(() => {
var cbview = _converse.chatboxviews.get('controlbox');
mock.openControlBox(_converse);
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1);
async function (done, _converse) {
const checkbox = checkboxes[0];
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
expect(label.textContent).toBe('This is a trusted device');
expect(checkbox.checked).toBe(false);
await u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
const cbview = _converse.chatboxviews.get('controlbox');
mock.toggleControlBox();
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1);
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
cbview.el.querySelector('input[name="password"]').value = 'secret';
const checkbox = checkboxes[0];
const label = cbview.el.querySelector(`label[for="${checkbox.getAttribute('id')}"]`);
expect(label.textContent).toBe('This is a trusted device');
expect(checkbox.checked).toBe(false);
spyOn(cbview.loginpanel, 'connect');
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
cbview.el.querySelector('input[name="password"]').value = 'secret';
expect(_converse.config.get('storage')).toBe('session');
cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('session');
expect(cbview.loginpanel.connect).toHaveBeenCalled();
cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('trusted')).toBe(false);
expect(_converse.getDefaultStore()).toBe('session');
checkbox.click();
cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('persistent');
done();
});
checkbox.click();
cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('trusted')).toBe(true);
expect(_converse.getDefaultStore()).toBe('persistent');
done();
}));
});
......@@ -75,16 +75,20 @@ window.addEventListener('converse-loaded', () => {
return Promise.all(_converse.chatboxviews.map(view => view.close()));
};
mock.openControlBox = async function (_converse) {
const model = await _converse.api.controlbox.open();
await u.waitUntil(() => model.get('connected'));
var toggle = document.querySelector(".toggle-controlbox");
mock.toggleControlBox = function () {
const toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) {
if (!u.isVisible(toggle)) {
u.removeClass('hidden', toggle);
}
toggle.click();
}
}
mock.openControlBox = async function (_converse) {
const model = await _converse.api.controlbox.open();
await u.waitUntil(() => model.get('connected'));
mock.toggleControlBox();
return this;
};
......
......@@ -102,6 +102,7 @@ converse.plugins.add('converse-controlbox', {
*/
api.settings.extend({
allow_logout: true,
allow_user_trust_override: true,
default_domain: undefined,
locked_domain: undefined,
show_controlbox_by_default: false,
......@@ -378,7 +379,7 @@ converse.plugins.add('converse-controlbox', {
'conn_feedback_message': _converse.connfeedback.get('message'),
'placeholder_username': (api.settings.get('locked_domain') || api.settings.get('default_domain')) &&
__('Username') || __('user@domain'),
'show_trust_checkbox': _converse.trusted !== 'on' && _converse.trusted !== 'off'
'show_trust_checkbox': api.settings.get('allow_user_trust_override')
})
);
},
......@@ -407,9 +408,11 @@ converse.plugins.add('converse-controlbox', {
return true;
},
/**
* Authenticate the user based on a form submission event.
* @param { Event } ev
*/
authenticate (ev) {
/* Authenticate the user based on a form submission event.
*/
if (ev && ev.preventDefault) { ev.preventDefault(); }
if (api.settings.get("authentication") === _converse.ANONYMOUS) {
return this.connect(_converse.jid, null);
......@@ -417,18 +420,7 @@ converse.plugins.add('converse-controlbox', {
if (!this.validate()) { return; }
const form_data = new FormData(ev.target);
if (_converse.trusted === 'on' || _converse.trusted === 'off') {
_converse.config.save({
'trusted': _converse.trusted === 'on',
'storage': _converse.trusted === 'on' ? 'persistent' : 'session'
});
} else {
_converse.config.save({
'trusted': form_data.get('trusted') && true || false,
'storage': form_data.get('trusted') ? 'persistent' : 'session'
});
}
_converse.config.save({ 'trusted': form_data.get('trusted') && true || false });
let jid = form_data.get('jid');
if (api.settings.get('locked_domain')) {
......
......@@ -405,7 +405,8 @@ async function fetchOwnDevices () {
}
async function initOMEMO () {
if (!_converse.config.get('trusted')) {
if (!_converse.config.get('trusted') || api.settings.get('clear_cache_on_logout')) {
log.warn("Not initializing OMEMO, since this browser is not trusted or clear_cache_on_logout is set to true");
return;
}
_converse.devicelists = new _converse.DeviceLists();
......@@ -513,7 +514,9 @@ function getOMEMOToolbarButton (toolbar_el, buttons) {
converse.plugins.add('converse-omemo', {
enabled (_converse) {
return window.libsignal && !_converse.api.settings.get("blacklisted_plugins").includes('converse-omemo') && _converse.config.get('trusted');
return window.libsignal &&
!_converse.api.settings.get("blacklisted_plugins").includes('converse-omemo') &&
(_converse.config.get('trusted') || !api.settings.get('clear_cache_on_logout'));
},
dependencies: ["converse-chatview", "converse-pubsub", "converse-profile"],
......@@ -1358,4 +1361,3 @@ converse.plugins.add('converse-omemo', {
});
}
});
......@@ -404,4 +404,3 @@ export class MockConnection extends Connection {
}
}
}
......@@ -95,13 +95,14 @@ const DEFAULT_SETTINGS = {
auto_login: false, // Currently only used in connection with anonymous login
auto_reconnect: true,
blacklisted_plugins: [],
clear_cache_on_logout: false,
connection_options: {},
credentials_url: null, // URL from where login credentials can be fetched
discover_connection_methods: true,
geouri_regex: /https\:\/\/www.openstreetmap.org\/.*#map=[0-9]+\/([\-0-9.]+)\/([\-0-9.]+)\S*/g,
geouri_replacement: 'https://www.openstreetmap.org/?mlat=$1&mlon=$2#map=18/$1/$2',
idle_presence_timeout: 300, // Seconds after which an idle presence is sent
i18n: 'en',
idle_presence_timeout: 300, // Seconds after which an idle presence is sent
jid: undefined,
keepalive: true,
loglevel: 'info',
......@@ -118,7 +119,6 @@ const DEFAULT_SETTINGS = {
sid: undefined,
singleton: false,
strict_plugin_dependencies: false,
trusted: true,
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
websocket_url: undefined,
whitelisted_plugins: []
......@@ -585,7 +585,7 @@ export const api = _converse.api = {
/**
* Get the value of a particular user setting.
* @method _converse.api.user.settings.get
* @param {String} key - hello world
* @param {String} key - The setting name
* @param {*} fallback - An optional fallback value if the user setting is undefined
* @returns {Promise} Promise which resolves with the value of the particular configuration setting.
* @example _converse.api.user.settings.get("foo");
......@@ -688,6 +688,7 @@ export const api = _converse.api = {
return _converse[key];
}
},
/**
* Set one or many configuration settings.
*
......@@ -973,7 +974,7 @@ async function initSessionStorage () {
function initPersistentStorage () {
if (_converse.config.get('storage') !== 'persistent') {
if (api.settings.get('persistent_store') === 'sessionStorage') {
return;
}
const config = {
......@@ -991,8 +992,18 @@ function initPersistentStorage () {
}
_converse.getDefaultStore = function () {
if (_converse.config.get('trusted')) {
const is_non_persistent = api.settings.get('persistent_store') === 'sessionStorage';
return is_non_persistent ? 'session': 'persistent';
} else {
return 'session';
}
}
function createStore (id, storage) {
const s = _converse.storage[storage ? storage : _converse.config.get('storage')];
const s = _converse.storage[storage || _converse.getDefaultStore()];
return new Storage(id, s);
}
......@@ -1049,11 +1060,7 @@ function initClientConfig () {
* user sessions.
*/
const id = 'converse.client-config';
_converse.config = new Model({
'id': id,
'trusted': _converse.api.settings.get("trusted") && true || false,
'storage': _converse.api.settings.get("trusted") ? 'persistent' : 'session'
});
_converse.config = new Model({ id, 'trusted': true });
_converse.config.browserStorage = createStore(id, "session");
_converse.config.fetch();
/**
......@@ -1141,7 +1148,11 @@ function connect (credentials) {
}
_converse.shouldClearCache = () => (!_converse.config.get('trusted') || _converse.isTestEnv());
_converse.shouldClearCache = () => (
!_converse.config.get('trusted') ||
api.settings.get('clear_cache_on_logout') ||
_converse.isTestEnv()
);
export function clearSession () {
......
......@@ -51,7 +51,7 @@ function getCorrectionAttributes (stanza, original_stanza) {
function getEncryptionAttributes (stanza, _converse) {
const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).pop();
const attrs = { 'is_encrypted': !!encrypted };
if (!encrypted || !_converse.config.get('trusted')) {
if (!encrypted || api.settings.get('clear_cache_on_logout')) {
return attrs;
}
const header = encrypted.querySelector('header');
......
import tpl_spinner from './spinner.js';
import { __ } from '../i18n';
import { api } from "@converse/headless/converse-core";
import { _converse, api } from "@converse/headless/converse-core";
import { html } from "lit-html";
const trust_checkbox = (o) => {
const trust_checkbox = (checked) => {
const i18n_hint_trusted = __(
'To improve performance, we cache your data in this browser. '+
'Uncheck this box if this is a public computer or if you want your data to be deleted when you log out. '+
......@@ -13,7 +13,7 @@ const trust_checkbox = (o) => {
const i18n_trusted = __('This is a trusted device');
return html`
<div class="form-group form-check login-trusted">
<input id="converse-login-trusted" type="checkbox" class="form-check-input" name="trusted" ?checked=${o._converse.config.get('trusted')}>
<input id="converse-login-trusted" type="checkbox" class="form-check-input" name="trusted" ?checked=${checked}>
<label for="converse-login-trusted" class="form-check-label login-trusted__desc">${i18n_trusted}</label>
<i class="fa fa-info-circle" data-toggle="popover"
data-title="Trusted device?"
......@@ -43,8 +43,7 @@ const register_link = () => {
`;
}
const show_register_link = (o) => {
const _converse = o._converse;
const show_register_link = () => {
return _converse.allow_registration &&
!api.settings.get("auto_login") &&
_converse.pluggable.plugins['converse-register'].enabled(_converse);
......@@ -66,11 +65,11 @@ const auth_fields = (o) => {
placeholder="${o.placeholder_username}"/>
</div>
${ (o.authentication !== o.EXTERNAL) ? password_input() : '' }
${ o.show_trust_checkbox ? trust_checkbox(o) : '' }
${ o.show_trust_checkbox ? trust_checkbox(o.show_trust_checkbox === 'off' ? false : true) : '' }
<fieldset class="buttons">
<input class="btn btn-primary" type="submit" value="${i18n_login}"/>
</fieldset>
${ show_register_link(o) ? register_link(o) : '' }
${ show_register_link() ? register_link(o) : '' }
`;
}
......@@ -93,6 +92,6 @@ export default (o) => html`
<p class="feedback-subject">${ o.conn_feedback_subject }</p>
<p class="feedback-message ${ !o.conn_feedback_message ? 'hidden' : '' }">${o.conn_feedback_message}</p>
</div>
${ (o._converse.CONNECTION_STATUS[o.connection_status] === 'CONNECTING') ? tpl_spinner({'classes': 'hor_centered'}) : form_fields(o) }
${ (_converse.CONNECTION_STATUS[o.connection_status] === 'CONNECTING') ? tpl_spinner({'classes': 'hor_centered'}) : form_fields(o) }
</form>
`;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment