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. ...@@ -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). - #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'` - #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. - #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 `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` - 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. - 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; const u = converse.env.utils;
...@@ -11,8 +11,8 @@ describe("The Login Form", function () { ...@@ -11,8 +11,8 @@ describe("The Login Form", function () {
allow_registration: false }, allow_registration: false },
async function (done, _converse) { async function (done, _converse) {
mock.openControlBox(_converse);
const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox')); const cbview = await u.waitUntil(() => _converse.chatboxviews.get('controlbox'));
mock.toggleControlBox();
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]'); const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1); expect(checkboxes.length).toBe(1);
...@@ -24,17 +24,16 @@ describe("The Login Form", function () { ...@@ -24,17 +24,16 @@ describe("The Login Form", function () {
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit'; cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
cbview.el.querySelector('input[name="password"]').value = 'secret'; cbview.el.querySelector('input[name="password"]').value = 'secret';
spyOn(cbview.loginpanel, 'connect'); expect(_converse.config.get('trusted')).toBe(true);
cbview.delegateEvents(); expect(_converse.getDefaultStore()).toBe('persistent');
expect(_converse.config.get('storage')).toBe('persistent');
cbview.el.querySelector('input[type="submit"]').click(); cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('persistent'); expect(_converse.config.get('trusted')).toBe(true);
expect(cbview.loginpanel.connect).toHaveBeenCalled(); expect(_converse.getDefaultStore()).toBe('persistent');
checkbox.click(); checkbox.click();
cbview.el.querySelector('input[type="submit"]').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(); done();
})); }));
...@@ -42,14 +41,13 @@ describe("The Login Form", function () { ...@@ -42,14 +41,13 @@ describe("The Login Form", function () {
mock.initConverse( mock.initConverse(
['chatBoxesInitialized'], ['chatBoxesInitialized'],
{ auto_login: false, { auto_login: false,
trusted: false, allow_user_trust_override: 'off',
allow_registration: false }, allow_registration: false },
function (done, _converse) { async function (done, _converse) {
u.waitUntil(() => _converse.chatboxviews.get('controlbox')) await u.waitUntil(() => _converse.chatboxviews.get('controlbox'))
.then(() => { const cbview = _converse.chatboxviews.get('controlbox');
var cbview = _converse.chatboxviews.get('controlbox'); mock.toggleControlBox();
mock.openControlBox(_converse);
const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]'); const checkboxes = cbview.el.querySelectorAll('input[type="checkbox"]');
expect(checkboxes.length).toBe(1); expect(checkboxes.length).toBe(1);
...@@ -61,17 +59,14 @@ describe("The Login Form", function () { ...@@ -61,17 +59,14 @@ describe("The Login Form", function () {
cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit'; cbview.el.querySelector('input[name="jid"]').value = 'romeo@montague.lit';
cbview.el.querySelector('input[name="password"]').value = 'secret'; cbview.el.querySelector('input[name="password"]').value = 'secret';
spyOn(cbview.loginpanel, 'connect');
expect(_converse.config.get('storage')).toBe('session');
cbview.el.querySelector('input[type="submit"]').click(); cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('session'); expect(_converse.config.get('trusted')).toBe(false);
expect(cbview.loginpanel.connect).toHaveBeenCalled(); expect(_converse.getDefaultStore()).toBe('session');
checkbox.click(); checkbox.click();
cbview.el.querySelector('input[type="submit"]').click(); cbview.el.querySelector('input[type="submit"]').click();
expect(_converse.config.get('storage')).toBe('persistent'); expect(_converse.config.get('trusted')).toBe(true);
expect(_converse.getDefaultStore()).toBe('persistent');
done(); done();
});
})); }));
}); });
...@@ -75,16 +75,20 @@ window.addEventListener('converse-loaded', () => { ...@@ -75,16 +75,20 @@ window.addEventListener('converse-loaded', () => {
return Promise.all(_converse.chatboxviews.map(view => view.close())); return Promise.all(_converse.chatboxviews.map(view => view.close()));
}; };
mock.openControlBox = async function (_converse) { mock.toggleControlBox = function () {
const model = await _converse.api.controlbox.open(); const toggle = document.querySelector(".toggle-controlbox");
await u.waitUntil(() => model.get('connected'));
var toggle = document.querySelector(".toggle-controlbox");
if (!u.isVisible(document.querySelector("#controlbox"))) { if (!u.isVisible(document.querySelector("#controlbox"))) {
if (!u.isVisible(toggle)) { if (!u.isVisible(toggle)) {
u.removeClass('hidden', toggle); u.removeClass('hidden', toggle);
} }
toggle.click(); toggle.click();
} }
}
mock.openControlBox = async function (_converse) {
const model = await _converse.api.controlbox.open();
await u.waitUntil(() => model.get('connected'));
mock.toggleControlBox();
return this; return this;
}; };
......
...@@ -102,6 +102,7 @@ converse.plugins.add('converse-controlbox', { ...@@ -102,6 +102,7 @@ converse.plugins.add('converse-controlbox', {
*/ */
api.settings.extend({ api.settings.extend({
allow_logout: true, allow_logout: true,
allow_user_trust_override: true,
default_domain: undefined, default_domain: undefined,
locked_domain: undefined, locked_domain: undefined,
show_controlbox_by_default: false, show_controlbox_by_default: false,
...@@ -378,7 +379,7 @@ converse.plugins.add('converse-controlbox', { ...@@ -378,7 +379,7 @@ converse.plugins.add('converse-controlbox', {
'conn_feedback_message': _converse.connfeedback.get('message'), 'conn_feedback_message': _converse.connfeedback.get('message'),
'placeholder_username': (api.settings.get('locked_domain') || api.settings.get('default_domain')) && 'placeholder_username': (api.settings.get('locked_domain') || api.settings.get('default_domain')) &&
__('Username') || __('user@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', { ...@@ -407,9 +408,11 @@ converse.plugins.add('converse-controlbox', {
return true; return true;
}, },
authenticate (ev) { /**
/* Authenticate the user based on a form submission event. * Authenticate the user based on a form submission event.
* @param { Event } ev
*/ */
authenticate (ev) {
if (ev && ev.preventDefault) { ev.preventDefault(); } if (ev && ev.preventDefault) { ev.preventDefault(); }
if (api.settings.get("authentication") === _converse.ANONYMOUS) { if (api.settings.get("authentication") === _converse.ANONYMOUS) {
return this.connect(_converse.jid, null); return this.connect(_converse.jid, null);
...@@ -417,18 +420,7 @@ converse.plugins.add('converse-controlbox', { ...@@ -417,18 +420,7 @@ converse.plugins.add('converse-controlbox', {
if (!this.validate()) { return; } if (!this.validate()) { return; }
const form_data = new FormData(ev.target); const form_data = new FormData(ev.target);
_converse.config.save({ 'trusted': form_data.get('trusted') && true || false });
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'
});
}
let jid = form_data.get('jid'); let jid = form_data.get('jid');
if (api.settings.get('locked_domain')) { if (api.settings.get('locked_domain')) {
......
...@@ -405,7 +405,8 @@ async function fetchOwnDevices () { ...@@ -405,7 +405,8 @@ async function fetchOwnDevices () {
} }
async function initOMEMO () { 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; return;
} }
_converse.devicelists = new _converse.DeviceLists(); _converse.devicelists = new _converse.DeviceLists();
...@@ -513,7 +514,9 @@ function getOMEMOToolbarButton (toolbar_el, buttons) { ...@@ -513,7 +514,9 @@ function getOMEMOToolbarButton (toolbar_el, buttons) {
converse.plugins.add('converse-omemo', { converse.plugins.add('converse-omemo', {
enabled (_converse) { 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"], dependencies: ["converse-chatview", "converse-pubsub", "converse-profile"],
...@@ -1358,4 +1361,3 @@ converse.plugins.add('converse-omemo', { ...@@ -1358,4 +1361,3 @@ converse.plugins.add('converse-omemo', {
}); });
} }
}); });
...@@ -404,4 +404,3 @@ export class MockConnection extends Connection { ...@@ -404,4 +404,3 @@ export class MockConnection extends Connection {
} }
} }
} }
...@@ -95,13 +95,14 @@ const DEFAULT_SETTINGS = { ...@@ -95,13 +95,14 @@ const DEFAULT_SETTINGS = {
auto_login: false, // Currently only used in connection with anonymous login auto_login: false, // Currently only used in connection with anonymous login
auto_reconnect: true, auto_reconnect: true,
blacklisted_plugins: [], blacklisted_plugins: [],
clear_cache_on_logout: false,
connection_options: {}, connection_options: {},
credentials_url: null, // URL from where login credentials can be fetched credentials_url: null, // URL from where login credentials can be fetched
discover_connection_methods: true, discover_connection_methods: true,
geouri_regex: /https\:\/\/www.openstreetmap.org\/.*#map=[0-9]+\/([\-0-9.]+)\/([\-0-9.]+)\S*/g, 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', 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', i18n: 'en',
idle_presence_timeout: 300, // Seconds after which an idle presence is sent
jid: undefined, jid: undefined,
keepalive: true, keepalive: true,
loglevel: 'info', loglevel: 'info',
...@@ -118,7 +119,6 @@ const DEFAULT_SETTINGS = { ...@@ -118,7 +119,6 @@ const DEFAULT_SETTINGS = {
sid: undefined, sid: undefined,
singleton: false, singleton: false,
strict_plugin_dependencies: false, strict_plugin_dependencies: false,
trusted: true,
view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile' view_mode: 'overlayed', // Choices are 'overlayed', 'fullscreen', 'mobile'
websocket_url: undefined, websocket_url: undefined,
whitelisted_plugins: [] whitelisted_plugins: []
...@@ -585,7 +585,7 @@ export const api = _converse.api = { ...@@ -585,7 +585,7 @@ export const api = _converse.api = {
/** /**
* Get the value of a particular user setting. * Get the value of a particular user setting.
* @method _converse.api.user.settings.get * @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 * @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. * @returns {Promise} Promise which resolves with the value of the particular configuration setting.
* @example _converse.api.user.settings.get("foo"); * @example _converse.api.user.settings.get("foo");
...@@ -688,6 +688,7 @@ export const api = _converse.api = { ...@@ -688,6 +688,7 @@ export const api = _converse.api = {
return _converse[key]; return _converse[key];
} }
}, },
/** /**
* Set one or many configuration settings. * Set one or many configuration settings.
* *
...@@ -973,7 +974,7 @@ async function initSessionStorage () { ...@@ -973,7 +974,7 @@ async function initSessionStorage () {
function initPersistentStorage () { function initPersistentStorage () {
if (_converse.config.get('storage') !== 'persistent') { if (api.settings.get('persistent_store') === 'sessionStorage') {
return; return;
} }
const config = { const config = {
...@@ -991,8 +992,18 @@ function initPersistentStorage () { ...@@ -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) { 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); return new Storage(id, s);
} }
...@@ -1049,11 +1060,7 @@ function initClientConfig () { ...@@ -1049,11 +1060,7 @@ function initClientConfig () {
* user sessions. * user sessions.
*/ */
const id = 'converse.client-config'; const id = 'converse.client-config';
_converse.config = new Model({ _converse.config = new Model({ id, 'trusted': true });
'id': id,
'trusted': _converse.api.settings.get("trusted") && true || false,
'storage': _converse.api.settings.get("trusted") ? 'persistent' : 'session'
});
_converse.config.browserStorage = createStore(id, "session"); _converse.config.browserStorage = createStore(id, "session");
_converse.config.fetch(); _converse.config.fetch();
/** /**
...@@ -1141,7 +1148,11 @@ function connect (credentials) { ...@@ -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 () { export function clearSession () {
......
...@@ -51,7 +51,7 @@ function getCorrectionAttributes (stanza, original_stanza) { ...@@ -51,7 +51,7 @@ function getCorrectionAttributes (stanza, original_stanza) {
function getEncryptionAttributes (stanza, _converse) { function getEncryptionAttributes (stanza, _converse) {
const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).pop(); const encrypted = sizzle(`encrypted[xmlns="${Strophe.NS.OMEMO}"]`, stanza).pop();
const attrs = { 'is_encrypted': !!encrypted }; const attrs = { 'is_encrypted': !!encrypted };
if (!encrypted || !_converse.config.get('trusted')) { if (!encrypted || api.settings.get('clear_cache_on_logout')) {
return attrs; return attrs;
} }
const header = encrypted.querySelector('header'); const header = encrypted.querySelector('header');
......
import tpl_spinner from './spinner.js'; import tpl_spinner from './spinner.js';
import { __ } from '../i18n'; import { __ } from '../i18n';
import { api } from "@converse/headless/converse-core"; import { _converse, api } from "@converse/headless/converse-core";
import { html } from "lit-html"; import { html } from "lit-html";
const trust_checkbox = (o) => { const trust_checkbox = (checked) => {
const i18n_hint_trusted = __( const i18n_hint_trusted = __(
'To improve performance, we cache your data in this browser. '+ '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. '+ '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) => { ...@@ -13,7 +13,7 @@ const trust_checkbox = (o) => {
const i18n_trusted = __('This is a trusted device'); const i18n_trusted = __('This is a trusted device');
return html` return html`
<div class="form-group form-check login-trusted"> <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> <label for="converse-login-trusted" class="form-check-label login-trusted__desc">${i18n_trusted}</label>
<i class="fa fa-info-circle" data-toggle="popover" <i class="fa fa-info-circle" data-toggle="popover"
data-title="Trusted device?" data-title="Trusted device?"
...@@ -43,8 +43,7 @@ const register_link = () => { ...@@ -43,8 +43,7 @@ const register_link = () => {
`; `;
} }
const show_register_link = (o) => { const show_register_link = () => {
const _converse = o._converse;
return _converse.allow_registration && return _converse.allow_registration &&
!api.settings.get("auto_login") && !api.settings.get("auto_login") &&
_converse.pluggable.plugins['converse-register'].enabled(_converse); _converse.pluggable.plugins['converse-register'].enabled(_converse);
...@@ -66,11 +65,11 @@ const auth_fields = (o) => { ...@@ -66,11 +65,11 @@ const auth_fields = (o) => {
placeholder="${o.placeholder_username}"/> placeholder="${o.placeholder_username}"/>
</div> </div>
${ (o.authentication !== o.EXTERNAL) ? password_input() : '' } ${ (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"> <fieldset class="buttons">
<input class="btn btn-primary" type="submit" value="${i18n_login}"/> <input class="btn btn-primary" type="submit" value="${i18n_login}"/>
</fieldset> </fieldset>
${ show_register_link(o) ? register_link(o) : '' } ${ show_register_link() ? register_link(o) : '' }
`; `;
} }
...@@ -93,6 +92,6 @@ export default (o) => html` ...@@ -93,6 +92,6 @@ export default (o) => html`
<p class="feedback-subject">${ o.conn_feedback_subject }</p> <p class="feedback-subject">${ o.conn_feedback_subject }</p>
<p class="feedback-message ${ !o.conn_feedback_message ? 'hidden' : '' }">${o.conn_feedback_message}</p> <p class="feedback-message ${ !o.conn_feedback_message ? 'hidden' : '' }">${o.conn_feedback_message}</p>
</div> </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> </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