1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

feat: replace gravatar-url with inline function (#5128)

As #4475 says, MD5 is not available in secure places anymore. This PR
swaps out gravatar-url with an inline function using crypto:sha256 which
is FIPS-140-2 compliant. Since we only used this method for generating
avatar URLs the extra customization wasn't needed and we could hard code
the URL parameters.
 
fixes: Linear
https://linear.app/unleash/issue/SR-112/gh-support-swap-out-gravatar-url-lib
closes: #4475
This commit is contained in:
Christopher Kolstad 2023-10-24 10:07:26 +02:00 committed by GitHub
parent ab390dbaab
commit c60bca777f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 44 additions and 43 deletions

View File

@ -25,7 +25,8 @@
"suspicious": {
"noExplicitAny": "off",
"noExtraNonNullAssertion": "off",
"noRedeclare": "off"
"noRedeclare": "off",
"noPrototypeBuiltins": "off"
}
},
"ignore": [

View File

@ -110,7 +110,6 @@
"express-rate-limit": "^6.6.0",
"express-session": "^1.17.1",
"fast-json-patch": "^3.1.0",
"gravatar-url": "^3.1.0",
"hash-sum": "^2.0.0",
"helmet": "^6.0.0",
"http-errors": "^2.0.0",

View File

@ -531,11 +531,10 @@ export class FeatureEventFormatterMd implements FeatureEventFormatter {
SEMVER_LT: 'is a SemVer less than',
};
const formatConstraint = (constraint: IConstraint) => {
const val = Object.hasOwn(constraint, 'value')
const val = constraint.hasOwnProperty('value')
? constraint.value
: `(${constraint.values?.join(',')})`;
const operator = Object.hasOwn(
constraintOperatorDescriptions,
const operator = constraintOperatorDescriptions.hasOwnProperty(
constraint.operator,
)
? constraintOperatorDescriptions[constraint.operator]

View File

@ -1321,7 +1321,7 @@ class FeatureToggleService {
if (
replaceGroupId &&
s.parameters &&
Object.hasOwn(s.parameters, 'groupId')
s.parameters.hasOwnProperty('groupId')
) {
s.parameters.groupId = newFeatureName;
}

View File

@ -5,7 +5,7 @@ test('should create user', () => {
expect(user.name).toBe('ole');
expect(user.email).toBe('some@email.com');
expect(user.imageUrl).toBe(
'https://gravatar.com/avatar/d8ffeba65ee5baf57e4901690edc8e1b?size=42&default=retro',
'https://gravatar.com/avatar/676212ff796c79a3c06261eb10e3f455aa93998ee6e45263da13679c74b1e674?s=42&d=retro&r=g',
);
});
@ -20,7 +20,7 @@ test('should create user, all fields', () => {
expect(user.username).toBe('admin');
expect(user.email).toBe('some@email.com');
expect(user.imageUrl).toBe(
'https://gravatar.com/avatar/d8ffeba65ee5baf57e4901690edc8e1b?size=42&default=retro',
'https://gravatar.com/avatar/676212ff796c79a3c06261eb10e3f455aa93998ee6e45263da13679c74b1e674?s=42&d=retro&r=g',
);
});
@ -47,7 +47,7 @@ test('Should create user with only username defined', () => {
const user = new User({ id: 133, username: 'some-user' });
expect(user.username).toBe('some-user');
expect(user.imageUrl).toBe(
'https://gravatar.com/avatar/140fd5a002fb8d728a9848f8c9fcea2a?size=42&default=retro',
'https://gravatar.com/avatar/7e90ac329986624ba9929659913354473c6f965d5b559704409e3f933c0643b7?s=42&d=retro&r=g',
);
});

View File

@ -0,0 +1,21 @@
import { generateImageUrl } from './generateImageUrl';
describe('Gravatar image url', () => {
it('generates the correct sha-256 hash for gravatars test idents', () => {
expect(generateImageUrl({ email: 'MyEmailAddress@example.com' })).toBe(
'https://gravatar.com/avatar/84059b07d4be67b806386c0aad8070a23f18836bbaae342275dc0a83414c32ee?s=42&d=retro&r=g',
);
});
it('lowercases and trims all emails', () => {
const upperCaseAndLeadingSpace = ' helloWorld@example.com';
const upperCaseAndTrailingSpace = 'helloWorld@exAMPLE.com ';
const lowerCaseAndNoSpaces = 'helloworld@example.com';
const uCALSHash = generateImageUrl({ email: upperCaseAndLeadingSpace });
const uCATSHash = generateImageUrl({
email: upperCaseAndTrailingSpace,
});
const lCANSHash = generateImageUrl({ email: lowerCaseAndNoSpaces });
expect(uCALSHash).toBe(uCATSHash);
expect(uCATSHash).toBe(lCANSHash);
});
});

View File

@ -1,11 +1,17 @@
import gravatarUrl from 'gravatar-url';
import { createHash } from 'crypto';
const base: string = 'https://gravatar.com/avatar';
export const generateImageUrl = (user: {
email: string;
username: string;
id: number;
}): string =>
gravatarUrl(user.email || user.username || String(user.id), {
size: 42,
default: 'retro',
});
email?: string;
username?: string;
id?: number;
}): string => {
let ident = user.email || user.username || String(user.id);
if (ident.indexOf('@')) {
ident = ident.toLowerCase().trim();
} else {
ident = ident.trim();
}
const identHash = createHash('sha256').update(ident).digest('hex');
return `${base}/${identHash}?s=42&d=retro&r=g`;
};

View File

@ -1859,11 +1859,6 @@ bluebird@^3.1.1, bluebird@^3.7.2:
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
blueimp-md5@^2.10.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz#b53feea5498dcb53dc6ec4b823adb84b729c4af0"
integrity sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==
body-parser@1.20.1:
version "1.20.1"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
@ -3384,14 +3379,6 @@ graceful-fs@^4.2.10, graceful-fs@^4.2.9:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
gravatar-url@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/gravatar-url/-/gravatar-url-3.1.0.tgz#0cbeedab7c00a7bc9b627b3716e331359efcc999"
integrity sha512-+lOs7Rz1A051OqdqE8Tm4lmeyVgkqH8c6ll5fv///ncdIaL+XnOFmKAB70ix1du/yj8c3EWKbP6OhKjihsBSfA==
dependencies:
md5-hex "^3.0.1"
type-fest "^0.8.1"
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
@ -4684,13 +4671,6 @@ map-stream@~0.1.0:
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
integrity sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==
md5-hex@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-3.0.1.tgz#be3741b510591434b2784d79e556eefc2c9a8e5c"
integrity sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==
dependencies:
blueimp-md5 "^2.10.0"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -6631,11 +6611,6 @@ type-fest@^0.21.3:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-fest@^1.0.1, type-fest@^1.2.1, type-fest@^1.2.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1"