-
-
Notifications
You must be signed in to change notification settings - Fork 776
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for XEP-0191 Blocking Command
- Loading branch information
Showing
39 changed files
with
624 additions
and
130 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import promise_api from '../../shared/api/promise.js'; | ||
import { sendBlockStanza, sendUnblockStanza } from './utils.js'; | ||
|
||
const { waitUntil } = promise_api; | ||
|
||
/** | ||
* Groups methods relevant to XEP-0191 Blocking Command | ||
* @namespace api.blocklist | ||
* @memberOf api | ||
*/ | ||
const blocklist = { | ||
/** | ||
* Retrieves the current user's blocklist | ||
* @returns {Promise<import('./collection').default>} | ||
*/ | ||
async get() { | ||
return await waitUntil('blocklistInitialized'); | ||
}, | ||
|
||
/** | ||
* Adds a new entity to the blocklist | ||
* @param {string|string[]} jid | ||
* @param {boolean} [send_stanza=true] | ||
* @returns {Promise<import('./collection').default>} | ||
*/ | ||
async add(jid, send_stanza = true) { | ||
const blocklist = await waitUntil('blocklistInitialized'); | ||
const jids = Array.isArray(jid) ? jid : [jid]; | ||
if (send_stanza) await sendBlockStanza(jids); | ||
jids.forEach((jid) => blocklist.create({ jid })); | ||
return blocklist; | ||
}, | ||
|
||
/** | ||
* Removes an entity from the blocklist | ||
* @param {string|string[]} jid | ||
* @param {boolean} [send_stanza=true] | ||
* @returns {Promise<import('./collection').default>} | ||
*/ | ||
async remove(jid, send_stanza = true) { | ||
const blocklist = await waitUntil('blocklistInitialized'); | ||
const jids = Array.isArray(jid) ? jid : [jid]; | ||
if (send_stanza) await sendUnblockStanza(jids); | ||
blocklist.remove(jids); | ||
return blocklist; | ||
}, | ||
}; | ||
|
||
const blocklist_api = { blocklist }; | ||
|
||
export default blocklist_api; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { getOpenPromise } from '@converse/openpromise'; | ||
import { Collection } from '@converse/skeletor'; | ||
import log from '../../log.js'; | ||
import _converse from '../../shared/_converse.js'; | ||
import { initStorage } from '../../utils/storage.js'; | ||
import api from '../../shared/api/index.js'; | ||
import converse from '../../shared/api/public.js'; | ||
import BlockedEntity from './model.js'; | ||
|
||
const { stx, u } = converse.env; | ||
|
||
class Blocklist extends Collection { | ||
get idAttribute() { | ||
return 'jid'; | ||
} | ||
|
||
constructor() { | ||
super(); | ||
this.model = BlockedEntity; | ||
} | ||
|
||
async initialize() { | ||
const { session } = _converse; | ||
const cache_key = `converse.blocklist-${session.get('bare_jid')}`; | ||
this.fetched_flag = `${cache_key}-fetched`; | ||
initStorage(this, cache_key); | ||
|
||
await this.fetchBlocklist(); | ||
|
||
/** | ||
* Triggered once the {@link Blocklist} collection | ||
* has been created and cached blocklist have been fetched. | ||
* @event _converse#blocklistInitialized | ||
* @type {Blocklist} | ||
* @example _converse.api.listen.on('blocklistInitialized', (blocklist) => { ... }); | ||
*/ | ||
api.trigger('blocklistInitialized', this); | ||
} | ||
|
||
fetchBlocklist() { | ||
const deferred = getOpenPromise(); | ||
if (window.sessionStorage.getItem(this.fetched_flag)) { | ||
this.fetch({ | ||
success: () => deferred.resolve(), | ||
error: () => deferred.resolve(), | ||
}); | ||
} else { | ||
this.fetchBlocklistFromServer(deferred); | ||
} | ||
return deferred; | ||
} | ||
|
||
/** | ||
* @param {Object} deferred | ||
*/ | ||
async fetchBlocklistFromServer(deferred) { | ||
const stanza = stx`<iq xmlns="jabber:client" | ||
type="get" | ||
id="${u.getUniqueId()}"><blocklist xmlns="urn:xmpp:blocking"/></iq>`; | ||
|
||
try { | ||
this.onBlocklistReceived(deferred, await api.sendIQ(stanza)); | ||
} catch (e) { | ||
log.error(e); | ||
deferred.resolve(); | ||
return; | ||
} | ||
} | ||
|
||
/** | ||
* @param {Object} deferred | ||
* @param {Element} iq | ||
*/ | ||
async onBlocklistReceived(deferred, iq) { | ||
Array.from(iq.querySelectorAll('blocklist item')).forEach((item) => { | ||
const jid = item.getAttribute('jid'); | ||
const blocked = this.get(jid); | ||
blocked ? blocked.save({ jid }) : this.create({ jid }); | ||
}); | ||
|
||
window.sessionStorage.setItem(this.fetched_flag, 'true'); | ||
if (deferred !== undefined) { | ||
return deferred.resolve(); | ||
} | ||
} | ||
} | ||
|
||
export default Blocklist; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import './plugin.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Model } from '@converse/skeletor'; | ||
import converse from '../../shared/api/public.js'; | ||
|
||
const { Strophe } = converse.env; | ||
|
||
class BlockedEntity extends Model { | ||
get idAttribute () { | ||
return 'jid'; | ||
} | ||
|
||
getDisplayName () { | ||
return Strophe.xmlunescape(this.get('name')); | ||
} | ||
} | ||
|
||
export default BlockedEntity; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** | ||
* @copyright The Converse.js contributors | ||
* @license Mozilla Public License (MPLv2) | ||
* @description Adds support for XEP-0191 Blocking Command | ||
*/ | ||
import _converse from '../../shared/_converse.js'; | ||
import api from '../../shared/api/index.js'; | ||
import converse from '../../shared/api/public.js'; | ||
import log from '../../log.js'; | ||
import Blocklist from './collection.js'; | ||
import BlockedEntity from './model.js'; | ||
import blocklist_api from './api.js'; | ||
|
||
const { Strophe, sizzle } = converse.env; | ||
|
||
Strophe.addNamespace('BLOCKING', 'urn:xmpp:blocking'); | ||
|
||
converse.plugins.add('converse-blocking', { | ||
dependencies: ['converse-disco'], | ||
|
||
initialize() { | ||
const exports = { Blocklist, BlockedEntity }; | ||
Object.assign(_converse.exports, exports); | ||
Object.assign(api, blocklist_api); | ||
|
||
api.promises.add(['blocklistInitialized']); | ||
|
||
api.listen.on('connected', () => { | ||
const connection = api.connection.get(); | ||
connection.addHandler( | ||
/** @param {Element} stanza */ (stanza) => { | ||
const bare_jid = _converse.session.get('bare_jid'); | ||
const from = stanza.getAttribute('from'); | ||
if (Strophe.getBareJidFromJid(from ?? bare_jid) != bare_jid) { | ||
log.warn(`Received a blocklist push stanza from a suspicious JID ${from}`); | ||
return true; | ||
} | ||
|
||
const add_jids = sizzle(`block[xmlns="${Strophe.NS.BLOCKING}"] item`, stanza).map( | ||
/** @param {Element} item */ (item) => item.getAttribute('jid') | ||
); | ||
if (add_jids.length) api.blocklist.add(add_jids, false); | ||
|
||
const remove_jids = sizzle(`unblock[xmlns="${Strophe.NS.BLOCKING}"] item`, stanza).map( | ||
/** @param {Element} item */ (item) => item.getAttribute('jid') | ||
); | ||
if (remove_jids.length) api.blocklist.remove(remove_jids, false); | ||
|
||
return true; | ||
}, | ||
Strophe.NS.BLOCKING, | ||
'iq', | ||
'set' | ||
); | ||
}); | ||
|
||
api.listen.on('clearSession', () => { | ||
const { state } = _converse; | ||
if (state.blocklist) { | ||
state.blocklist.clearStore({ 'silent': true }); | ||
window.sessionStorage.removeItem(state.blocklist.fetched_flag); | ||
delete state.blocklist; | ||
} | ||
}); | ||
|
||
api.listen.on('discoInitialized', async () => { | ||
const domain = _converse.session.get('domain'); | ||
if (await api.disco.supports(Strophe.NS.BLOCKING, domain)) { | ||
_converse.state.blocklist = new _converse.exports.Blocklist(); | ||
} | ||
}); | ||
}, | ||
}); |
Oops, something went wrong.