Skip to content

Load avatar data over HTTP if available in vCard EXTVAL #3782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

edshot99
Copy link

@edshot99 edshot99 commented Aug 5, 2025

Its possible to point the user avatar to a URL address and store it in PEP. It then becomes accessible from vcard-temp in the EXTVAL tag.

The same can be done with MUC avatars by setting the EXTVAL tag with the url, but this is not oficially supported by XEP-0486.

Edit: I think handleVCardUpdatePresence() in src/headless/plugins/vcard/utils.js should be modified, but i'm not sure if its only needed for the binary avatars or not since i'm not too familiar with Javascript or Sizzle. Seems to function fine without any changes to it however.

@@ -12,6 +12,7 @@ export async function parseVCardResultStanza(iq) {
fullname: iq.querySelector(':scope > vCard FN')?.textContent,
image: iq.querySelector(':scope > vCard PHOTO BINVAL')?.textContent,
image_type: iq.querySelector(':scope > vCard PHOTO TYPE')?.textContent,
image_url: iq.querySelector(':scope > vCard PHOTO EXTVAL')?.textContent,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XEP-0054 and XEP-0292 both support PHOTO EXTVAL but funnily enough XEP-0153 VCard-based Avatars discourages it. I'm not sure why.

The <PHOTO/> element SHOULD NOT contain an <EXTVAL/> that points to a URI for the image file.

In any case, the changes look OK to me, but I think we should put result.image first in the if statement below, and then check for result.image_url.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

XEP-0054 and XEP-0292 both support PHOTO EXTVAL but funnily enough XEP-0153 VCard-based Avatars discourages it. I'm not sure why.

I guess it is to prevent IP leaking. An attacker could use this field to point to their server, and get other users IP. Which could be an issue when you have high privacy expectation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, but this is the same with HTTP file upload.

My guess is it's because that XEP deals with creating hashes of BINVAL values and advertising those in order to let clients know when they need to update the VCard.

When you're using a URL, presumably you'd change the URL when there's a new avatar so the usage of a hash is not necessary (but then you'd ideally advertise the new image URL similarly to how the hash is advertised).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, but this is the same with HTTP file upload.

yes, and that's why some clients don't display images automatically.

My guess is it's because that XEP deals with creating hashes of BINVAL values and advertising those in order to let clients know when they need to update the VCard.

When you're using a URL, presumably you'd change the URL when there's a new avatar so the usage of a hash is not necessary (but then you'd ideally advertise the new image URL similarly to how the hash is advertised)

Could be because of this too, indeed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, and that's why some clients don't display images automatically.

This is actually a good feature which I'd like to have in Converse as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see an issue with IP leaks since many clients already block untrusted domains and i'd assume deployments of Converse would set up content security policy rules. I'm not sure if the same applies with Converse Desktop so that would have to be checked first.

If CSP isn't enough then creating some configuration to allow trusted domains for avatars can be created.

Copy link
Author

@edshot99 edshot99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything should be fixed now.

const vcards = [];
if (occupant.get('jid')) {
vcards.push(_converse.state.vcards.get(occupant.get('jid')));
}
vcards.push(_converse.state.vcards.get(occupant.get('from')));
vcards.forEach((v) => hash && v && v?.get('image_hash') !== hash && api.vcard.update(v, true));
vcards.forEach((v) => (hash || url) && v && (v?.get('image_hash') !== hash || v?.get('image_url') !== url) && api.vcard.update(v, true));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still doesn't look right, because of the (hash || url) the hash value could be undefined, but then the v?.get('image_hash') !== hash check could still execute (because url is defined), potentially resulting in an unnecessary call to api.vcard.update.

I think it's better to write this logic out.

Suggested change
vcards.forEach((v) => (hash || url) && v && (v?.get('image_hash') !== hash || v?.get('image_url') !== url) && api.vcard.update(v, true));
vcards.filter((v) => v).forEach((v) => {
if (hash && v.get('image_hash') !== hash || url && v.get('image_url') !== url) {
api.vcard.update(v, true);
}
});

Comment on lines +35 to +36
}
else if (image_url) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Please put the else on the same line as the curly bracket.

Suggested change
}
else if (image_url) {
} else if (image_url) {

Comment on lines +10 to +11
}
else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Please put the else on the same line as the curly bracket.

Suggested change
}
else {
} else {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants