|
@@ -1,14 +1,33 @@
|
|
|
-import {useCallback, useEffect, useState} from 'react';
|
|
|
+import {useEffect, useState} from 'react';
|
|
|
import styled from '@emotion/styled';
|
|
|
-import type HasherHelper from 'crypto-js/sha256';
|
|
|
import * as qs from 'query-string';
|
|
|
|
|
|
import ConfigStore from 'sentry/stores/configStore';
|
|
|
-import {useIsMountedRef} from 'sentry/utils/useIsMountedRef';
|
|
|
|
|
|
import type {ImageStyleProps} from './styles';
|
|
|
import {imageStyle} from './styles';
|
|
|
|
|
|
+function isCryptoSubtleDigestAvailable() {
|
|
|
+ return (
|
|
|
+ !!window.crypto &&
|
|
|
+ !!window.crypto.subtle &&
|
|
|
+ typeof window.crypto.subtle.digest === 'function'
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Available only in secure contexts. (https)
|
|
|
+ * Gravatar will not work in http
|
|
|
+ */
|
|
|
+async function hashGravatarId(message = ''): Promise<string> {
|
|
|
+ const encoder = new TextEncoder();
|
|
|
+ const data = encoder.encode(message);
|
|
|
+ const hash = await window.crypto.subtle.digest('SHA-256', data);
|
|
|
+ return Array.from(new Uint8Array(hash))
|
|
|
+ .map(b => b.toString(16).padStart(2, '0'))
|
|
|
+ .join('');
|
|
|
+}
|
|
|
+
|
|
|
type Props = {
|
|
|
remoteSize: number;
|
|
|
gravatarId?: string;
|
|
@@ -26,24 +45,23 @@ function Gravatar({
|
|
|
onLoad,
|
|
|
suggested,
|
|
|
}: Props) {
|
|
|
- const isMountedRef = useIsMountedRef();
|
|
|
- const [SHA256, setSHA256] = useState<typeof HasherHelper>();
|
|
|
-
|
|
|
- const loadSHA256Helper = useCallback(async () => {
|
|
|
- const mod = await import('crypto-js/sha256');
|
|
|
-
|
|
|
- if (isMountedRef.current) {
|
|
|
- // XXX: Use function invocation of `useState`s setter since the mod.default
|
|
|
- // is a function itself.
|
|
|
- setSHA256(() => mod.default);
|
|
|
+ const [sha256, setSha256] = useState<string | null>(null);
|
|
|
+ useEffect(() => {
|
|
|
+ if (!isCryptoSubtleDigestAvailable()) {
|
|
|
+ return;
|
|
|
}
|
|
|
- }, [isMountedRef]);
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- loadSHA256Helper();
|
|
|
- }, [loadSHA256Helper]);
|
|
|
+ hashGravatarId((gravatarId ?? '').trim())
|
|
|
+ .then(hash => {
|
|
|
+ setSha256(hash);
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ // If there is an error with the hash, we should not render the gravatar
|
|
|
+ setSha256(null);
|
|
|
+ });
|
|
|
+ }, [gravatarId]);
|
|
|
|
|
|
- if (SHA256 === undefined) {
|
|
|
+ if (!sha256) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
@@ -56,7 +74,6 @@ function Gravatar({
|
|
|
|
|
|
const gravatarBaseUrl = ConfigStore.get('gravatarBaseUrl');
|
|
|
|
|
|
- const sha256 = SHA256((gravatarId ?? '').trim());
|
|
|
const url = `${gravatarBaseUrl}/avatar/${sha256}?${query}`;
|
|
|
|
|
|
return (
|