diff --git a/src/headless/plugins/vcard/api.js b/src/headless/plugins/vcard/api.js index a58f6ec019..51cca74463 100644 --- a/src/headless/plugins/vcard/api.js +++ b/src/headless/plugins/vcard/api.js @@ -50,11 +50,19 @@ export default { // Optimistically update the vcard with image data. Otherwise some servers (e.g. Ejabberd) // could send a XEP-0153 vcard:update presence which would cause us to refetch the vcard again. const buffer = u.base64ToArrayBuffer(data.image); - const hash_ab = await crypto.subtle.digest('SHA-1', buffer); + // Check if crypto.subtle is available (requires secure context/HTTPS) + let image_hash; + if (window.isSecureContext) { + const hash_ab = await crypto.subtle.digest('SHA-1', buffer); + image_hash = u.arrayBufferToHex(hash_ab); + } else { + // Fallback for non-HTTPS contexts: use base64 as pseudo-hash + image_hash = data.image.substring(0, 32); + } vcard.save({ image: data.image, image_type: data.image_type, - image_hash: u.arrayBufferToHex(hash_ab), + image_hash: image_hash, }); } diff --git a/src/headless/plugins/vcard/parsers.js b/src/headless/plugins/vcard/parsers.js index 94e0bd14a3..579d4c09d4 100644 --- a/src/headless/plugins/vcard/parsers.js +++ b/src/headless/plugins/vcard/parsers.js @@ -23,8 +23,14 @@ export async function parseVCardResultStanza(iq) { }; if (result.image) { const buffer = u.base64ToArrayBuffer(result.image); - const ab = await crypto.subtle.digest('SHA-1', buffer); - result['image_hash'] = u.arrayBufferToHex(ab); + // Check if crypto.subtle is available (requires secure context/HTTPS) + if (window.isSecureContext) { + const ab = await crypto.subtle.digest('SHA-1', buffer); + result['image_hash'] = u.arrayBufferToHex(ab); + } else { + // Fallback for non-HTTPS contexts: use base64 as pseudo-hash + result['image_hash'] = result.image.substring(0, 32); + } } return result; } diff --git a/src/headless/utils/color.js b/src/headless/utils/color.js index a6bfcf0dd8..808ab0b868 100644 --- a/src/headless/utils/color.js +++ b/src/headless/utils/color.js @@ -14,13 +14,21 @@ export async function colorize(s) { const v = cache.get(s); if (v) return v; - // Run the input through SHA-1 - const digest = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-1', new TextEncoder().encode(s)))); - - // Treat the output as little endian and extract the least-significant 16 bits. - // (These are the first two bytes of the output, with the second byte being the most significant one.) - // Divide the value by 65536 (use float division) and multiply it by 360 (to map it to degrees in a full circle). - const angle = ((digest[0] + digest[1] * 256) / 65536.0) * 360; + // Run the input through SHA-1 (only available in secure context/HTTPS) + let angle; + if (window.isSecureContext) { + const digest = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-1', new TextEncoder().encode(s)))); + // Treat the output as little endian and extract the least-significant 16 bits. + angle = ((digest[0] + digest[1] * 256) / 65536.0) * 360; + } else { + // Fallback for non-HTTPS contexts: use a simple hash based on string characters + let hash = 0; + for (let i = 0; i < s.length; i++) { + hash = ((hash << 5) - hash) + s.charCodeAt(i); + hash = hash & hash; // Convert to 32bit integer + } + angle = Math.abs(hash % 360); + } // Convert HSLuv angle to RGB Hex notation const hsluv = new Hsluv();