parent
ce447e4035
commit
bcd6845756
@ -2346,7 +2346,7 @@
|
||||
--primary: #387592;
|
||||
--secondary: #6c757d;
|
||||
--success: #3AA569;
|
||||
--info: #17a2b8;
|
||||
--info: #3AA569;
|
||||
--warning: #ffc107;
|
||||
--danger: #E77051;
|
||||
--light: #f8f9fa;
|
||||
@ -3594,24 +3594,24 @@
|
||||
box-shadow: 0 0 0 0.2rem rgba(58, 165, 105, 0.5); }
|
||||
#conversejs .btn-info {
|
||||
color: #fff;
|
||||
background-color: #17a2b8;
|
||||
border-color: #17a2b8; }
|
||||
background-color: #3AA569;
|
||||
border-color: #3AA569; }
|
||||
#conversejs .btn-info:hover {
|
||||
color: #fff;
|
||||
background-color: #138496;
|
||||
border-color: #117a8b; }
|
||||
background-color: #308957;
|
||||
border-color: #2d7f51; }
|
||||
#conversejs .btn-info:focus, #conversejs .btn-info.focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); }
|
||||
box-shadow: 0 0 0 0.2rem rgba(58, 165, 105, 0.5); }
|
||||
#conversejs .btn-info.disabled, #conversejs .btn-info:disabled {
|
||||
color: #fff;
|
||||
background-color: #17a2b8;
|
||||
border-color: #17a2b8; }
|
||||
background-color: #3AA569;
|
||||
border-color: #3AA569; }
|
||||
#conversejs .btn-info:not(:disabled):not(.disabled):active, #conversejs .btn-info:not(:disabled):not(.disabled).active, .show > #conversejs .btn-info.dropdown-toggle {
|
||||
color: #fff;
|
||||
background-color: #117a8b;
|
||||
border-color: #10707f; }
|
||||
background-color: #2d7f51;
|
||||
border-color: #29764b; }
|
||||
#conversejs .btn-info:not(:disabled):not(.disabled):active:focus, #conversejs .btn-info:not(:disabled):not(.disabled).active:focus, .show > #conversejs .btn-info.dropdown-toggle:focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); }
|
||||
box-shadow: 0 0 0 0.2rem rgba(58, 165, 105, 0.5); }
|
||||
#conversejs .btn-warning {
|
||||
color: #212529;
|
||||
background-color: #ffc107;
|
||||
@ -3753,25 +3753,25 @@
|
||||
#conversejs .btn-outline-success:not(:disabled):not(.disabled):active:focus, #conversejs .btn-outline-success:not(:disabled):not(.disabled).active:focus, .show > #conversejs .btn-outline-success.dropdown-toggle:focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(58, 165, 105, 0.5); }
|
||||
#conversejs .btn-outline-info {
|
||||
color: #17a2b8;
|
||||
color: #3AA569;
|
||||
background-color: transparent;
|
||||
background-image: none;
|
||||
border-color: #17a2b8; }
|
||||
border-color: #3AA569; }
|
||||
#conversejs .btn-outline-info:hover {
|
||||
color: #fff;
|
||||
background-color: #17a2b8;
|
||||
border-color: #17a2b8; }
|
||||
background-color: #3AA569;
|
||||
border-color: #3AA569; }
|
||||
#conversejs .btn-outline-info:focus, #conversejs .btn-outline-info.focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); }
|
||||
box-shadow: 0 0 0 0.2rem rgba(58, 165, 105, 0.5); }
|
||||
#conversejs .btn-outline-info.disabled, #conversejs .btn-outline-info:disabled {
|
||||
color: #17a2b8;
|
||||
color: #3AA569;
|
||||
background-color: transparent; }
|
||||
#conversejs .btn-outline-info:not(:disabled):not(.disabled):active, #conversejs .btn-outline-info:not(:disabled):not(.disabled).active, .show > #conversejs .btn-outline-info.dropdown-toggle {
|
||||
color: #fff;
|
||||
background-color: #17a2b8;
|
||||
border-color: #17a2b8; }
|
||||
background-color: #3AA569;
|
||||
border-color: #3AA569; }
|
||||
#conversejs .btn-outline-info:not(:disabled):not(.disabled):active:focus, #conversejs .btn-outline-info:not(:disabled):not(.disabled).active:focus, .show > #conversejs .btn-outline-info.dropdown-toggle:focus {
|
||||
box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); }
|
||||
box-shadow: 0 0 0 0.2rem rgba(58, 165, 105, 0.5); }
|
||||
#conversejs .btn-outline-warning {
|
||||
color: #ffc107;
|
||||
background-color: transparent;
|
||||
@ -4582,11 +4582,11 @@
|
||||
background-color: #2d7f51; }
|
||||
#conversejs .badge-info {
|
||||
color: #fff;
|
||||
background-color: #17a2b8; }
|
||||
background-color: #3AA569; }
|
||||
#conversejs .badge-info[href]:hover, #conversejs .badge-info[href]:focus {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
background-color: #117a8b; }
|
||||
background-color: #2d7f51; }
|
||||
#conversejs .badge-warning {
|
||||
color: #212529;
|
||||
background-color: #ffc107; }
|
||||
@ -4658,13 +4658,13 @@
|
||||
#conversejs .alert-success .alert-link {
|
||||
color: #11301f; }
|
||||
#conversejs .alert-info {
|
||||
color: #0c5460;
|
||||
background-color: #d1ecf1;
|
||||
border-color: #bee5eb; }
|
||||
color: #1e5637;
|
||||
background-color: #d8ede1;
|
||||
border-color: #c8e6d5; }
|
||||
#conversejs .alert-info hr {
|
||||
border-top-color: #abdde5; }
|
||||
border-top-color: #b6dec8; }
|
||||
#conversejs .alert-info .alert-link {
|
||||
color: #062c33; }
|
||||
color: #11301f; }
|
||||
#conversejs .alert-warning {
|
||||
color: #856404;
|
||||
background-color: #fff3cd;
|
||||
@ -4782,15 +4782,15 @@
|
||||
background-color: #1e5637;
|
||||
border-color: #1e5637; }
|
||||
#conversejs .list-group-item-info {
|
||||
color: #0c5460;
|
||||
background-color: #bee5eb; }
|
||||
color: #1e5637;
|
||||
background-color: #c8e6d5; }
|
||||
#conversejs .list-group-item-info.list-group-item-action:hover, #conversejs .list-group-item-info.list-group-item-action:focus {
|
||||
color: #0c5460;
|
||||
background-color: #abdde5; }
|
||||
color: #1e5637;
|
||||
background-color: #b6dec8; }
|
||||
#conversejs .list-group-item-info.list-group-item-action.active {
|
||||
color: #fff;
|
||||
background-color: #0c5460;
|
||||
border-color: #0c5460; }
|
||||
background-color: #1e5637;
|
||||
border-color: #1e5637; }
|
||||
#conversejs .list-group-item-warning {
|
||||
color: #856404;
|
||||
background-color: #ffeeba; }
|
||||
@ -5179,11 +5179,11 @@
|
||||
#conversejs button.bg-success:focus {
|
||||
background-color: #2d7f51 !important; }
|
||||
#conversejs .bg-info {
|
||||
background-color: #17a2b8 !important; }
|
||||
background-color: #3AA569 !important; }
|
||||
#conversejs a.bg-info:hover, #conversejs a.bg-info:focus,
|
||||
#conversejs button.bg-info:hover,
|
||||
#conversejs button.bg-info:focus {
|
||||
background-color: #117a8b !important; }
|
||||
background-color: #2d7f51 !important; }
|
||||
#conversejs .bg-warning {
|
||||
background-color: #ffc107 !important; }
|
||||
#conversejs a.bg-warning:hover, #conversejs a.bg-warning:focus,
|
||||
@ -5239,7 +5239,7 @@
|
||||
#conversejs .border-success {
|
||||
border-color: #3AA569 !important; }
|
||||
#conversejs .border-info {
|
||||
border-color: #17a2b8 !important; }
|
||||
border-color: #3AA569 !important; }
|
||||
#conversejs .border-warning {
|
||||
border-color: #ffc107 !important; }
|
||||
#conversejs .border-danger {
|
||||
@ -6792,9 +6792,9 @@
|
||||
#conversejs a.text-success:hover, #conversejs a.text-success:focus {
|
||||
color: #2d7f51 !important; }
|
||||
#conversejs .text-info {
|
||||
color: #17a2b8 !important; }
|
||||
color: #3AA569 !important; }
|
||||
#conversejs a.text-info:hover, #conversejs a.text-info:focus {
|
||||
color: #117a8b !important; }
|
||||
color: #2d7f51 !important; }
|
||||
#conversejs .text-warning {
|
||||
color: #ffc107 !important; }
|
||||
#conversejs a.text-warning:hover, #conversejs a.text-warning:focus {
|
||||
@ -7213,6 +7213,9 @@ body.reset {
|
||||
@media screen and (max-height: 450px) {
|
||||
#conversejs {
|
||||
left: 0; } }
|
||||
#conversejs .btn--small {
|
||||
font-size: 80%;
|
||||
font-weight: normal; }
|
||||
#conversejs form .form-group {
|
||||
margin-bottom: 2em; }
|
||||
#conversejs form .form-check-label {
|
||||
@ -7291,6 +7294,10 @@ body.reset {
|
||||
|
||||
#conversejs #user-profile-modal label {
|
||||
font-weight: bold; }
|
||||
#conversejs .fingerprint-trust {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 95%; }
|
||||
|
||||
#conversejs .chatbox-navback {
|
||||
display: none; }
|
||||
|
681
dist/converse.js
vendored
681
dist/converse.js
vendored
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: Converse.js 0.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-07-22 11:17+0200\n"
|
||||
"PO-Revision-Date: 2018-07-22 12:12+0200\n"
|
||||
"PO-Revision-Date: 2018-07-22 15:37+0200\n"
|
||||
"Last-Translator: JC Brand <jc@opkode.com>\n"
|
||||
"Language-Team: Afrikaans <https://hosted.weblate.org/projects/conversejs/"
|
||||
"translations/af/>\n"
|
||||
|
@ -1,4 +1,9 @@
|
||||
#conversejs {
|
||||
.btn--small {
|
||||
font-size: 80%;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
form {
|
||||
.form-group {
|
||||
margin-bottom: 2em;
|
||||
|
@ -4,4 +4,9 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.fingerprint-trust {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 95%;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ $green: #3AA569;
|
||||
$dark-green: #1E9652;
|
||||
$darkest-green: #0E763B;
|
||||
|
||||
$info: $green !default;
|
||||
|
||||
$lightest-green: #E7FBF0;
|
||||
$light-green: #5CBC86;
|
||||
$green: #3AA569;
|
||||
|
129
spec/omemo.js
129
spec/omemo.js
@ -245,7 +245,7 @@
|
||||
devicelist = _converse.devicelists.get(contact_jid);
|
||||
expect(devicelist.devices.length).toBe(1);
|
||||
let device = devicelist.devices.at(0);
|
||||
expect(device.get('bundle').identity_key).toBe(3333);
|
||||
expect(device.get('bundle').identity_key).toBe('3333');
|
||||
expect(device.get('bundle').signed_prekey.public_key).toBe('1111');
|
||||
expect(device.get('bundle').signed_prekey.id).toBe(4223);
|
||||
expect(device.get('bundle').signed_prekey.signature).toBe('2222');
|
||||
@ -276,7 +276,7 @@
|
||||
devicelist = _converse.devicelists.get(contact_jid);
|
||||
expect(devicelist.devices.length).toBe(1);
|
||||
device = devicelist.devices.at(0);
|
||||
expect(device.get('bundle').identity_key).toBe(7777);
|
||||
expect(device.get('bundle').identity_key).toBe('7777');
|
||||
expect(device.get('bundle').signed_prekey.public_key).toBe('5555');
|
||||
expect(device.get('bundle').signed_prekey.id).toBe(4223);
|
||||
expect(device.get('bundle').signed_prekey.signature).toBe('6666');
|
||||
@ -309,7 +309,7 @@
|
||||
expect(devicelist.devices.at(0).get('id')).toBe('555');
|
||||
expect(devicelist.devices.at(1).get('id')).toBe('123456789');
|
||||
device = devicelist.devices.at(1);
|
||||
expect(device.get('bundle').identity_key).toBe(1111);
|
||||
expect(device.get('bundle').identity_key).toBe('1111');
|
||||
expect(device.get('bundle').signed_prekey.public_key).toBe('8888');
|
||||
expect(device.get('bundle').signed_prekey.id).toBe(9999);
|
||||
expect(device.get('bundle').signed_prekey.signature).toBe('3333');
|
||||
@ -396,8 +396,15 @@
|
||||
`</publish>`+
|
||||
`</pubsub>`+
|
||||
`</iq>`)
|
||||
done();
|
||||
});
|
||||
|
||||
const stanza = $iq({
|
||||
'from': _converse.bare_jid,
|
||||
'id': iq_stanza.getAttribute('id'),
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'result'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
return _converse.api.waitUntil('OMEMOInitialized');
|
||||
}).then(done).catch(_.partial(console.error, _));
|
||||
}));
|
||||
|
||||
it("adds a toolbar button for starting an encrypted chat session",
|
||||
@ -494,7 +501,6 @@
|
||||
'type': 'result'});
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
|
||||
return test_utils.waitUntil(() => {
|
||||
return _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
@ -565,6 +571,117 @@
|
||||
done();
|
||||
}).catch(_.partial(console.error, _));
|
||||
}));
|
||||
|
||||
it("shows OMEMO device fingerprints in the user details modal",
|
||||
mock.initConverseWithPromises(
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
let iq_stanza;
|
||||
test_utils.createContacts(_converse, 'current', 1);
|
||||
const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@localhost';
|
||||
test_utils.openChatBoxFor(_converse, contact_jid);
|
||||
|
||||
// We simply emit, to avoid doing all the setup work
|
||||
_converse.emit('OMEMOInitialized');
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const show_modal_button = view.el.querySelector('.show-user-details-modal');
|
||||
show_modal_button.click();
|
||||
const modal = view.user_details_modal;
|
||||
|
||||
test_utils.waitUntil(() => u.isVisible(modal.el), 1000).then(() => {
|
||||
return test_utils.waitUntil(() => {
|
||||
return _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
(iq) => {
|
||||
const node = iq.nodeTree.querySelector('iq[to="'+contact_jid+'"] query[node="eu.siacs.conversations.axolotl.devicelist"]');
|
||||
if (node) { iq_stanza = iq.nodeTree; }
|
||||
return node;
|
||||
}).length;});
|
||||
}).then(() => {
|
||||
iq_stanza;
|
||||
expect(iq_stanza.outerHTML).toBe(
|
||||
`<iq type="get" from="dummy@localhost" to="max.frankfurter@localhost" xmlns="jabber:client" id="${iq_stanza.getAttribute('id')}">`+
|
||||
`<query xmlns="http://jabber.org/protocol/disco#items" node="eu.siacs.conversations.axolotl.devicelist"/>`+
|
||||
`</iq>`);
|
||||
|
||||
const stanza = $iq({
|
||||
'from': contact_jid,
|
||||
'id': iq_stanza.getAttribute('id'),
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'result',
|
||||
}).c('query', {
|
||||
'xmlns': 'http://jabber.org/protocol/disco#items',
|
||||
'node': 'eu.siacs.conversations.axolotl.devicelist'
|
||||
}).c('device', {'id': '555'}).up()
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
return test_utils.waitUntil(() => u.isVisible(modal.el), 1000).then(function () {
|
||||
return test_utils.waitUntil(() => {
|
||||
return _.filter(
|
||||
_converse.connection.IQ_stanzas,
|
||||
(iq) => {
|
||||
const node = iq.nodeTree.querySelector('iq[to="'+contact_jid+'"] items[node="eu.siacs.conversations.axolotl.bundles:555"]');
|
||||
if (node) { iq_stanza = iq.nodeTree; }
|
||||
return node;
|
||||
}).length;});
|
||||
});
|
||||
}).then(() => {
|
||||
expect(iq_stanza.outerHTML).toBe(
|
||||
`<iq type="get" from="dummy@localhost" to="max.frankfurter@localhost" xmlns="jabber:client" id="${iq_stanza.getAttribute('id')}">`+
|
||||
`<pubsub xmlns="http://jabber.org/protocol/pubsub">`+
|
||||
`<items node="eu.siacs.conversations.axolotl.bundles:555"/>`+
|
||||
`</pubsub>`+
|
||||
`</iq>`);
|
||||
|
||||
const stanza = $iq({
|
||||
'from': contact_jid,
|
||||
'id': iq_stanza.getAttribute('id'),
|
||||
'to': _converse.bare_jid,
|
||||
'type': 'result',
|
||||
}).c('pubsub', {
|
||||
'xmlns': 'http://jabber.org/protocol/pubsub'
|
||||
}).c('items', {'node': "eu.siacs.conversations.axolotl.bundles:555"})
|
||||
.c('item')
|
||||
.c('bundle', {'xmlns': 'eu.siacs.conversations.axolotl'})
|
||||
.c('signedPreKeyPublic', {'signedPreKeyId': '4223'}).t(btoa('1111')).up()
|
||||
.c('signedPreKeySignature').t(btoa('2222')).up()
|
||||
.c('identityKey').t(btoa('3333')).up()
|
||||
.c('prekeys')
|
||||
.c('preKeyPublic', {'preKeyId': '1'}).t(btoa('1001')).up()
|
||||
.c('preKeyPublic', {'preKeyId': '2'}).t(btoa('1002')).up()
|
||||
.c('preKeyPublic', {'preKeyId': '3'}).t(btoa('1003'));
|
||||
_converse.connection._dataRecv(test_utils.createRequest(stanza));
|
||||
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const modal = view.user_details_modal;
|
||||
return test_utils.waitUntil(() => modal.el.querySelectorAll('.fingerprints .fingerprint').length);
|
||||
}).then(() => {
|
||||
const view = _converse.chatboxviews.get(contact_jid);
|
||||
const modal = view.user_details_modal;
|
||||
expect(modal.el.querySelectorAll('.fingerprints .fingerprint').length).toBe(1);
|
||||
const el = modal.el.querySelector('.fingerprints .fingerprint');
|
||||
expect(el.textContent).toBe('f56d6351aa71cff0debea014d13525e42036187a');
|
||||
|
||||
expect(modal.el.querySelectorAll('input[type="radio"]').length).toBe(2);
|
||||
|
||||
let trusted_radio = modal.el.querySelector('input[type="radio"][name="555"][value="1"]');
|
||||
expect(trusted_radio.checked).toBe(true);
|
||||
|
||||
let untrusted_radio = modal.el.querySelector('input[type="radio"][name="555"][value="-1"]');
|
||||
expect(untrusted_radio.checked).toBe(false);
|
||||
|
||||
// Test that the device can be set to untrusted
|
||||
untrusted_radio.click();
|
||||
trusted_radio = document.querySelector('input[type="radio"][name="555"][value="1"]');
|
||||
expect(trusted_radio.hasAttribute('checked')).toBe(false);
|
||||
|
||||
untrusted_radio = document.querySelector('input[type="radio"][name="555"][value="-1"]');
|
||||
expect(untrusted_radio.hasAttribute('checked')).toBe(true);
|
||||
done();
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
describe("A chatbox with an active OMEMO session", function() {
|
||||
|
@ -389,7 +389,6 @@
|
||||
function (done, _converse) {
|
||||
|
||||
_converse.roster_groups = true;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
_converse.rosterview.render();
|
||||
test_utils.openControlBox();
|
||||
@ -430,7 +429,6 @@
|
||||
function (done, _converse) {
|
||||
|
||||
_converse.roster_groups = true;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
_converse.rosterview.render();
|
||||
|
||||
@ -477,7 +475,6 @@
|
||||
|
||||
_converse.roster_groups = true;
|
||||
var groups = ['colleagues', 'friends'];
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
test_utils.openControlBox();
|
||||
_converse.rosterview.render();
|
||||
@ -576,7 +573,6 @@
|
||||
null, ['rosterGroupsFetched'], {},
|
||||
function (done, _converse) {
|
||||
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
test_utils.openControlBox();
|
||||
_converse.roster.create({
|
||||
@ -726,7 +722,6 @@
|
||||
|
||||
var i, t;
|
||||
test_utils.openControlBox();
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
for (i=0; i<mock.pend_names.length; i++) {
|
||||
_converse.roster.create({
|
||||
@ -908,7 +903,6 @@
|
||||
test_utils.waitUntil(() => $(_converse.rosterview.el).find('.roster-group li').length, 700)
|
||||
.then(function () {
|
||||
var jid, t;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
var $roster = $(_converse.rosterview.el);
|
||||
for (var i=0; i<mock.cur_names.length; i++) {
|
||||
@ -935,7 +929,6 @@
|
||||
return $(_converse.rosterview.el).find('.roster-group li').length;
|
||||
}, 700).then(function () {
|
||||
var jid, t;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
var $roster = $(_converse.rosterview.el);
|
||||
for (var i=0; i<mock.cur_names.length; i++) {
|
||||
@ -963,7 +956,6 @@
|
||||
return $(_converse.rosterview.el).find('.roster-group li').length;
|
||||
}, 700).then(function () {
|
||||
var jid, t;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
var $roster = $(_converse.rosterview.el);
|
||||
for (var i=0; i<mock.cur_names.length; i++) {
|
||||
@ -991,7 +983,6 @@
|
||||
return $(_converse.rosterview.el).find('.roster-group li').length;
|
||||
}, 700).then(function () {
|
||||
var jid, t;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
var $roster = $(_converse.rosterview.el);
|
||||
for (var i=0; i<mock.cur_names.length; i++) {
|
||||
@ -1020,7 +1011,6 @@
|
||||
}, 500)
|
||||
.then(function () {
|
||||
var jid, t;
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
var $roster = $(_converse.rosterview.el);
|
||||
for (var i=0; i<mock.cur_names.length; i++) {
|
||||
@ -1151,7 +1141,6 @@
|
||||
names.push($(item).text().replace(/^\s+|\s+$/g, ''));
|
||||
}
|
||||
};
|
||||
spyOn(_converse, 'emit');
|
||||
spyOn(_converse.rosterview, 'update').and.callThrough();
|
||||
spyOn(_converse.controlboxtoggle, 'showControlBox').and.callThrough();
|
||||
for (i=0; i<mock.req_names.length; i++) {
|
||||
|
@ -239,32 +239,29 @@
|
||||
|
||||
events: {
|
||||
'click button.remove-contact': 'removeContact',
|
||||
'click button.refresh-contact': 'refreshContact'
|
||||
'click button.refresh-contact': 'refreshContact',
|
||||
'click .fingerprint-trust .btn input': 'toggleDeviceTrust'
|
||||
},
|
||||
|
||||
initialize () {
|
||||
_converse.BootstrapModal.prototype.initialize.apply(this, arguments);
|
||||
this.model.on('contactAdded', this.registerContactEventHandlers, this);
|
||||
this.model.on('change', this.render, this);
|
||||
this.registerContactEventHandlers();
|
||||
_converse.emit('userDetailsModalInitialized', this.model);
|
||||
},
|
||||
|
||||
toHTML () {
|
||||
return tpl_user_details_modal(_.extend(
|
||||
this.model.toJSON(),
|
||||
this.model.vcard.toJSON(), {
|
||||
'_': _,
|
||||
'__': __,
|
||||
'view': this,
|
||||
'_converse': _converse,
|
||||
'allow_contact_removal': _converse.allow_contact_removal,
|
||||
'alt_profile_image': __("The User's Profile Image"),
|
||||
'display_name': this.model.getDisplayName(),
|
||||
'is_roster_contact': !_.isUndefined(this.model.contact),
|
||||
'label_close': __('Close'),
|
||||
'label_email': __('Email'),
|
||||
'label_fullname': __('Full Name'),
|
||||
'label_jid': __('Jabber ID'),
|
||||
'label_nickname': __('Nickname'),
|
||||
'label_remove': __('Remove as contact'),
|
||||
'label_refresh': __('Refresh'),
|
||||
'label_role': __('Role'),
|
||||
'label_url': __('URL')
|
||||
'is_roster_contact': !_.isUndefined(this.model.contact)
|
||||
}));
|
||||
},
|
||||
|
||||
|
@ -44,7 +44,7 @@
|
||||
}
|
||||
});
|
||||
return {
|
||||
'identity_key': parseInt(bundle_el.querySelector('identityKey').textContent, 10),
|
||||
'identity_key': bundle_el.querySelector('identityKey').textContent,
|
||||
'signed_prekey': {
|
||||
'id': parseInt(signed_prekey_public_el.getAttribute('signedPreKeyId'), 10),
|
||||
'public_key': signed_prekey_public_el.textContent,
|
||||
@ -65,6 +65,27 @@
|
||||
|
||||
overrides: {
|
||||
|
||||
UserDetailsModal: {
|
||||
events: {
|
||||
'click .fingerprint-trust .btn input': 'toggleDeviceTrust'
|
||||
},
|
||||
|
||||
initialize () {
|
||||
const { _converse } = this.__super__;
|
||||
const jid = this.model.get('jid');
|
||||
this.devicelist = _converse.devicelists.get(jid) || _converse.devicelists.create({'jid': jid});
|
||||
this.devicelist.devices.on('change:bundle', this.render, this);
|
||||
this.devicelist.devices.on('change:trusted', this.render, this);
|
||||
return this.__super__.initialize.apply(this, arguments);
|
||||
},
|
||||
|
||||
toggleDeviceTrust (ev) {
|
||||
const radio = ev.target;
|
||||
const device = this.devicelist.devices.get(radio.getAttribute('name'));
|
||||
device.save('trusted', parseInt(radio.value, 10));
|
||||
}
|
||||
},
|
||||
|
||||
ChatBox: {
|
||||
|
||||
getBundlesAndBuildSessions () {
|
||||
@ -77,7 +98,6 @@
|
||||
this.buildSessions(devices)
|
||||
.then(() => resolve(devices))
|
||||
.catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
@ -194,6 +214,27 @@
|
||||
|
||||
_converse.NUM_PREKEYS = 100; // Set here so that tests can override
|
||||
|
||||
function generateFingerprint (device) {
|
||||
return new Promise((resolve, reject) => {
|
||||
device.getBundle().then((bundle) => {
|
||||
// TODO: only generate fingerprints when necessary
|
||||
crypto.subtle.digest('SHA-1', u.base64ToArrayBuffer(bundle['identity_key']))
|
||||
.then((fp) => {
|
||||
bundle['fingerprint'] = u.arrayBufferToHex(fp);
|
||||
device.save('bundle', bundle);
|
||||
device.trigger('change:bundle'); // Doesn't get triggered automatically due to pass-by-reference
|
||||
resolve();
|
||||
}).catch(reject);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_converse.getFingerprintsForContact = function (jid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
_converse.getDevicesForContact(jid)
|
||||
.then((devices) => Promise.all(devices.map(d => generateFingerprint(d))).then(resolve).catch(reject));
|
||||
});
|
||||
}
|
||||
|
||||
_converse.getDevicesForContact = function (jid) {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -405,14 +446,15 @@
|
||||
'from': _converse.bare_jid,
|
||||
'to': this.get('jid')
|
||||
}).c('pubsub', {'xmlns': Strophe.NS.PUBSUB})
|
||||
.c('items', {'xmlns': `${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}`});
|
||||
.c('items', {'node': `${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}`});
|
||||
_converse.connection.sendIQ(
|
||||
stanza,
|
||||
(iq) => {
|
||||
const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, stanza).pop();
|
||||
const bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop();
|
||||
this.save(parseBundle(bundle_el));
|
||||
resolve();
|
||||
const publish_el = sizzle(`items[node="${Strophe.NS.OMEMO_BUNDLES}:${this.get('id')}"]`, iq).pop(),
|
||||
bundle_el = sizzle(`bundle[xmlns="${Strophe.NS.OMEMO}"]`, publish_el).pop(),
|
||||
bundle = parseBundle(bundle_el);
|
||||
this.save('bundle', bundle);
|
||||
resolve(bundle);
|
||||
},
|
||||
reject,
|
||||
_converse.IQ_TIMEOUT
|
||||
@ -479,7 +521,7 @@
|
||||
(iq) => {
|
||||
_.forEach(
|
||||
iq.querySelectorAll('device'),
|
||||
(dev) => this.devices.create({'id': dev.getAttribute('id')})
|
||||
(dev) => this.devices.create({'id': dev.getAttribute('id'), 'jid': this.get('jid')})
|
||||
);
|
||||
resolve();
|
||||
},
|
||||
@ -493,7 +535,7 @@
|
||||
* server.
|
||||
* https://xmpp.org/extensions/xep-0384.html#usecases-announcing
|
||||
*/
|
||||
this.devices.create({'id': device_id});
|
||||
this.devices.create({'id': device_id, 'jid': this.get('jid')});
|
||||
return new Promise((resolve, reject) => {
|
||||
const stanza = $iq({
|
||||
'from': _converse.bare_jid,
|
||||
@ -589,7 +631,7 @@
|
||||
jid = stanza.getAttribute('from'),
|
||||
bundle_el = sizzle(`item > bundle`, items_el).pop(),
|
||||
devicelist = _converse.devicelists.get(jid) || _converse.devicelists.create({'jid': jid}),
|
||||
device = devicelist.devices.get(device_id) || devicelist.devices.create({'id': device_id});
|
||||
device = devicelist.devices.get(device_id) || devicelist.devices.create({'id': device_id, 'jid': jid});
|
||||
device.save({'bundle': parseBundle(bundle_el)});
|
||||
}
|
||||
|
||||
@ -613,7 +655,7 @@
|
||||
if (dev) {
|
||||
dev.save({'active': true});
|
||||
} else {
|
||||
devices.create({'id': device_id})
|
||||
devices.create({'id': device_id, 'jid': jid})
|
||||
}
|
||||
});
|
||||
// Make sure our own device is on the list (i.e. if it was
|
||||
@ -661,6 +703,11 @@
|
||||
_converse.api.listen.on('statusInitialized', initOMEMO);
|
||||
_converse.api.listen.on('addClientFeatures',
|
||||
() => _converse.api.disco.own.features.add(Strophe.NS.OMEMO_DEVICELIST+"notify"));
|
||||
|
||||
_converse.api.listen.on('userDetailsModalInitialized', (contact) => {
|
||||
const jid = contact.get('jid');
|
||||
_converse.getFingerprintsForContact(jid).catch(_.partial(_converse.log, _, Strophe.LogLevel.ERROR));
|
||||
});
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
@ -1,39 +1,70 @@
|
||||
<div class="modal fade" id="user-profile-modal" tabindex="-1" role="dialog" aria-labelledby="user-profile-modal-label" aria-hidden="true">
|
||||
<div class="modal fade" id="user-details-modal" tabindex="-1" role="dialog" aria-labelledby="user-details-modal-label" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="user-profile-modal-label">{{{o.display_name}}}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="{{{o.label_close}}}"><span aria-hidden="true">×</span></button>
|
||||
<h5 class="modal-title" id="user-details-modal-label">{{{o.display_name}}}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="{{{o.__('Close')}}}"><span aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{[ if (o.image) { ]}
|
||||
<img alt="{{{o.alt_profile_image}}}"
|
||||
<img alt="{{{o.__('The User\'s Profile Image')}}}"
|
||||
class="img-thumbnail avatar align-self-center mb-3"
|
||||
height="100" width="100" src="data:{{{o.image_type}}};base64,{{{o.image}}}"/>
|
||||
{[ } ]}
|
||||
{[ if (o.fullname) { ]}
|
||||
<p><label>{{{o.label_fullname}}}:</label> {{{o.fullname}}}</p>
|
||||
<p><label>{{{o.__('Full Name')}}}:</label> {{{o.fullname}}}</p>
|
||||
{[ } ]}
|
||||
<p><label>{{{o.label_jid}}}:</label> {{{o.jid}}}</p>
|
||||
<p><label>{{{o.__('XMPP Address')}}}:</label> {{{o.jid}}}</p>
|
||||
{[ if (o.nickname) { ]}
|
||||
<p><label>{{{o.label_nickname}}}:</label> {{{o.nickname}}}</p>
|
||||
<p><label>{{{o.__('Nickname')}}}:</label> {{{o.nickname}}}</p>
|
||||
{[ } ]}
|
||||
{[ if (o.url) { ]}
|
||||
<p><label>{{{o.label_url}}}:</label> <a target="_blank" rel="noopener" href="{{{o.url}}}">{{{o.url}}}</a></p>
|
||||
<p><label>{{{o.__('URL')}}}:</label> <a target="_blank" rel="noopener" href="{{{o.url}}}">{{{o.url}}}</a></p>
|
||||
{[ } ]}
|
||||
{[ if (o.email) { ]}
|
||||
<p><label>{{{o.label_email}}}:</label> <a href="mailto:{{{o.email}}}">{{{o.email}}}</a></p>
|
||||
<p><label>{{{o.__('Email')}}}:</label> <a href="mailto:{{{o.email}}}">{{{o.email}}}</a></p>
|
||||
{[ } ]}
|
||||
{[ if (o.role) { ]}
|
||||
<p><label>{{{o.label_role}}}:</label> {{{o.role}}}</p>
|
||||
<p><label>{{{o.__('Role')}}}:</label> {{{o.role}}}</p>
|
||||
{[ } ]}
|
||||
|
||||
{[ if (o._converse.pluggable.plugins['converse-omemo'].enabled()) { ]}
|
||||
<hr>
|
||||
<ul class="list-group fingerprints">
|
||||
<li class="list-group-item active">{{{o.__('OMEMO Fingerprints')}}}</li>
|
||||
{[ if (!o.view.devicelist.devices) { ]}
|
||||
<li class="list-group-item"><span class="spinner fa fa-spinner centered"/></li>
|
||||
{[ } ]}
|
||||
{[ if (o.view.devicelist.devices) { ]}
|
||||
{[ o.view.devicelist.devices.each(function (device) { ]}
|
||||
{[ if (device.get('bundle') && device.get('bundle').fingerprint) { ]}
|
||||
<li class="list-group-item">
|
||||
<form class="fingerprint-trust">
|
||||
<span class="fingerprint">{{{device.get('bundle').fingerprint}}}</span>
|
||||
<div class="btn-group btn-group-toggle">
|
||||
<label class="btn btn--small {[ if (device.get('trusted') !== -1) { ]} btn-primary active {[ } else { ]} btn-secondary {[ } ]}">
|
||||
<input type="radio" name="{{{device.get('id')}}}" value="1"
|
||||
{[ if (device.get('trusted') !== -1) { ]} checked="checked" {[ } ]}>{{{o.__('Trusted')}}}
|
||||
</label>
|
||||
<label class="btn btn--small {[ if (device.get('trusted') === -1) { ]} btn-primary active {[ } else { ]} btn-secondary {[ } ]}">
|
||||
<input type="radio" name="{{{device.get('id')}}}" value="-1"
|
||||
{[ if (device.get('trusted') === -1) { ]} checked="checked" {[ } ]}>{{{o.__('Untrusted')}}}
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
</li>
|
||||
{[ } ]}
|
||||
{[ }); ]}
|
||||
{[ } ]}
|
||||
</ul>
|
||||
{[ } ]}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{[ if (o.allow_contact_removal && o.is_roster_contact) { ]}
|
||||
<button type="button" class="btn btn-danger remove-contact"><i class="fa fa-trash"> </i>{{{o.label_remove}}}</button>
|
||||
<button type="button" class="btn btn-danger remove-contact"><i class="fa fa-trash"> </i>{{{o.__('Remove as contact')}}}</button>
|
||||
{[ } ]}
|
||||
<button type="button" class="btn btn-info refresh-contact"><i class="fa fa-refresh"> </i>{{{o.label_refresh}}}</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{{o.label_close}}}</button>
|
||||
<button type="button" class="btn btn-info refresh-contact"><i class="fa fa-refresh"> </i>{{{o.__('Refresh')}}}</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{{o.__('Close')}}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -846,6 +846,22 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
u.arrayBufferToHex = function (ab) {
|
||||
const hexCodes = [];
|
||||
const padding = '00000000';
|
||||
const view = new window.DataView(ab);
|
||||
for (var i = 0; i < view.byteLength; i += 4) {
|
||||
// Using getUint32 reduces the number of iterations needed (we process 4 bytes each time)
|
||||
const value = view.getUint32(i)
|
||||
// toString(16) will give the hex representation of the number without padding
|
||||
const stringValue = value.toString(16)
|
||||
// We use concatenation and slice for padding
|
||||
const paddedValue = (padding + stringValue).slice(-padding.length)
|
||||
hexCodes.push(paddedValue);
|
||||
}
|
||||
return hexCodes.join("");
|
||||
};
|
||||
|
||||
u.arrayBufferToString = function (ab) {
|
||||
var enc = new TextDecoder("utf-8");
|
||||
return enc.decode(new Uint8Array(ab));
|
||||
|
Loading…
Reference in New Issue
Block a user