UNPKG

@jsxc/jsxc

Version:

Real-time XMPP chat application with video calls, file transfer and encrypted communication

177 lines (135 loc) 5.23 kB
import { AbstractPlugin, IMetaData } from '../plugin/AbstractPlugin'; import PluginAPI from '../plugin/PluginAPI'; import Avatar from '../Avatar'; import AvatarUI from '../ui/AvatarSet'; import JID from '../JID'; import { ContactType, IContact } from '@src/Contact.interface'; import Translation from '@util/Translation'; import { IAvatar } from '@src/Avatar.interface'; import { IJID } from '@src/JID.interface'; import Hash from '@util/Hash'; const MIN_VERSION = '4.0.0'; const MAX_VERSION = '99.0.0'; export default class AvatarVCardPlugin extends AbstractPlugin { public static getId(): string { return 'vcard-avatars'; } public static getName(): string { return 'vCard-based Avatars'; } public static getMetaData(): IMetaData { return { description: Translation.t('setting-vcard-avatar-enable'), xeps: [ { id: 'XEP-0153', name: 'vCard-Based Avatars', version: '1.1', }, ], }; } constructor(pluginAPI: PluginAPI) { super(MIN_VERSION, MAX_VERSION, pluginAPI); let connection = pluginAPI.getConnection(); connection.registerHandler(this.onPresenceVCardUpdate, 'vcard-temp:x:update', 'presence'); pluginAPI.addPublishAvatarProcessor(this.publishAvatarProcessor); pluginAPI.addAvatarProcessor(this.avatarProcessor); } private getStorage() { return this.pluginAPI.getStorage(); } private onPresenceVCardUpdate = stanza => { let from = new JID($(stanza).attr('from')); let xVCard = $(stanza).find('x[xmlns="vcard-temp:x:update"]'); if (xVCard.length > 0) { let photo = xVCard.find('photo'); if (photo.length > 0) { let contact = this.pluginAPI.getContact(from); if (contact && contact.getType() === ContactType.GROUPCHAT && from.resource) { return true; } let sha1OfAvatar = photo.text()?.trim() || null; this.getStorage().setItem(from.bare, sha1OfAvatar); //@REVIEW use this as trigger for all tabs? if (!contact) { this.pluginAPI.Log.warn('No contact found for', from); return true; } let avatarUI = AvatarUI.get(contact); avatarUI.reload(); } } return true; }; private publishAvatarProcessor = (avatar: IAvatar | null): Promise<[IAvatar]> => { if (typeof avatar === 'undefined') { return Promise.resolve([avatar]); } const vcardService = this.pluginAPI.getConnection().getVcardService(); const jid = this.pluginAPI.getConnection().getJID(); return vcardService .setAvatar(jid, avatar?.getData(), avatar?.getType()) .then(() => { this.getStorage().setItem(jid.bare, avatar?.getHash() || ''); return [undefined]; }) .catch(err => { this.pluginAPI.Log.error('Could not publish avatar', err); return [avatar]; }); }; private avatarProcessor = async (contact: IContact, avatar: IAvatar): Promise<[IContact, IAvatar]> => { let storage = this.getStorage(); let hash = storage.getItem(contact.getJid().bare); if (!hash && !avatar && this.shouldForceRetrieval(contact)) { try { const avatarObject = await this.getAvatar(contact.getJid()); const data = avatarObject.src.replace(/^.+;base64,/, ''); avatar = new Avatar(Hash.SHA1FromBase64(data), avatarObject.type, avatarObject.src); this.getStorage().setItem(contact.getJid().bare, avatar.getHash() || ''); let avatarUI = AvatarUI.get(contact); avatarUI.reload(); } catch (err) { // we could not find any avatar } } if (!hash || avatar) { return [contact, avatar]; } try { avatar = new Avatar(hash); } catch (err) { try { const avatarObject = await this.getAvatar(contact.getJid()); return [contact, new Avatar(hash, avatarObject.type, avatarObject.src)]; } catch (err) { this.pluginAPI.Log.warn('Error during avatar retrieval', err); return [contact, avatar]; } } return [contact, avatar]; }; private getAvatar(jid: IJID): Promise<{ src: string; type: string }> { let connection = this.pluginAPI.getConnection(); return connection .getVcardService() .loadVcard(jid) .then(function (vcard) { if (vcard.PHOTO && vcard.PHOTO.src) { return vcard.PHOTO; } throw new Error('No photo available'); }); } private shouldForceRetrieval(contact: IContact): boolean { if (contact.getJid().bare !== this.pluginAPI.getConnection().getJID().bare) { return false; } const sessionStorage = this.pluginAPI.getSessionStorage(); if (sessionStorage.getItem('forced', contact.getJid().bare)) { return false; } sessionStorage.setItem('forced', contact.getJid().bare, true); return true; } }