Commit a8a52a58 authored by Eric Eastwood's avatar Eric Eastwood

Protect against unknown emojis in frequently used list

See https://gitlab.slack.com/archives/frontend/p1489690607738864
parent ce5d1b6f
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import emojiMap from 'emojis/digests.json'; import emojiMap from 'emojis/digests.json';
import emojiAliases from 'emojis/aliases.json'; import emojiAliases from 'emojis/aliases.json';
import { glEmojiTag } from './behaviors/gl_emoji'; import { glEmojiTag } from './behaviors/gl_emoji';
import isEmojiNameValid from './behaviors/gl_emoji/is_emoji_name_valid';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const requestAnimationFrame = window.requestAnimationFrame || const requestAnimationFrame = window.requestAnimationFrame ||
...@@ -454,14 +455,21 @@ AwardsHandler.prototype.normalizeEmojiName = function normalizeEmojiName(emoji) ...@@ -454,14 +455,21 @@ AwardsHandler.prototype.normalizeEmojiName = function normalizeEmojiName(emoji)
AwardsHandler AwardsHandler
.prototype .prototype
.addEmojiToFrequentlyUsedList = function addEmojiToFrequentlyUsedList(emoji) { .addEmojiToFrequentlyUsedList = function addEmojiToFrequentlyUsedList(emoji) {
const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); if (isEmojiNameValid(emoji)) {
frequentlyUsedEmojis.push(emoji); this.frequentlyUsedEmojis = _.uniq(this.getFrequentlyUsedEmojis().concat(emoji));
Cookies.set('frequently_used_emojis', frequentlyUsedEmojis.join(','), { expires: 365 }); Cookies.set('frequently_used_emojis', this.frequentlyUsedEmojis.join(','), { expires: 365 });
}
}; };
AwardsHandler.prototype.getFrequentlyUsedEmojis = function getFrequentlyUsedEmojis() { AwardsHandler.prototype.getFrequentlyUsedEmojis = function getFrequentlyUsedEmojis() {
const frequentlyUsedEmojis = (Cookies.get('frequently_used_emojis') || '').split(','); return this.frequentlyUsedEmojis || (() => {
return _.compact(_.uniq(frequentlyUsedEmojis)); const frequentlyUsedEmojis = _.uniq((Cookies.get('frequently_used_emojis') || '').split(','));
this.frequentlyUsedEmojis = frequentlyUsedEmojis.filter(
inputName => isEmojiNameValid(inputName),
);
return this.frequentlyUsedEmojis;
})();
}; };
AwardsHandler.prototype.setupSearch = function setupSearch() { AwardsHandler.prototype.setupSearch = function setupSearch() {
......
...@@ -13,9 +13,14 @@ function emojiImageTag(name, src) { ...@@ -13,9 +13,14 @@ function emojiImageTag(name, src) {
} }
function assembleFallbackImageSrc(inputName) { function assembleFallbackImageSrc(inputName) {
const name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ? let name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ?
emojiAliases[inputName] : inputName; emojiAliases[inputName] : inputName;
const emojiInfo = emojiMap[name]; let emojiInfo = emojiMap[name];
// Fallback to question mark for unknown emojis
if (!emojiInfo) {
name = 'grey_question';
emojiInfo = emojiMap[name];
}
const fallbackImageSrc = `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/emoji/${name}-${emojiInfo.digest}.png`; const fallbackImageSrc = `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/emoji/${name}-${emojiInfo.digest}.png`;
return fallbackImageSrc; return fallbackImageSrc;
...@@ -26,9 +31,15 @@ const glEmojiTagDefaults = { ...@@ -26,9 +31,15 @@ const glEmojiTagDefaults = {
}; };
function glEmojiTag(inputName, options) { function glEmojiTag(inputName, options) {
const opts = Object.assign({}, glEmojiTagDefaults, options); const opts = Object.assign({}, glEmojiTagDefaults, options);
const name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ? let name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ?
emojiAliases[inputName] : inputName; emojiAliases[inputName] : inputName;
const emojiInfo = emojiMap[name]; let emojiInfo = emojiMap[name];
// Fallback to question mark for unknown emojis
if (!emojiInfo) {
name = 'grey_question';
emojiInfo = emojiMap[name];
}
const fallbackImageSrc = assembleFallbackImageSrc(name); const fallbackImageSrc = assembleFallbackImageSrc(name);
const fallbackSpriteClass = `emoji-${name}`; const fallbackSpriteClass = `emoji-${name}`;
......
import emojiMap from 'emojis/digests.json';
import emojiAliases from 'emojis/aliases.json';
function isEmojiNameValid(inputName) {
const name = Object.prototype.hasOwnProperty.call(emojiAliases, inputName) ?
emojiAliases[inputName] : inputName;
return name && emojiMap[name];
}
export default isEmojiNameValid;
...@@ -287,6 +287,20 @@ import AwardsHandler from '~/awards_handler'; ...@@ -287,6 +287,20 @@ import AwardsHandler from '~/awards_handler';
done.fail(`Failed to open and build emoji menu: ${err.message}`); done.fail(`Failed to open and build emoji menu: ${err.message}`);
}); });
}); });
it('should disregard invalid frequently used emoji that are being attempted to be added', function() {
awardsHandler.addEmojiToFrequentlyUsedList('8ball');
awardsHandler.addEmojiToFrequentlyUsedList('invalid_emoji');
awardsHandler.addEmojiToFrequentlyUsedList('grinning');
expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']);
});
it('should disregard invalid frequently used emoji already set in cookie', function() {
Cookies.set('frequently_used_emojis', '8ball,invalid_emoji,grinning');
expect(awardsHandler.getFrequentlyUsedEmojis()).toEqual(['8ball', 'grinning']);
});
}); });
}); });
}).call(window); }).call(window);
...@@ -43,6 +43,11 @@ const emojiFixtureMap = { ...@@ -43,6 +43,11 @@ const emojiFixtureMap = {
moji: '5️⃣', moji: '5️⃣',
unicodeVersion: '3.0', unicodeVersion: '3.0',
}, },
grey_question: {
name: 'grey_question',
moji: '',
unicodeVersion: '6.0',
},
}; };
function markupToDomElement(markup) { function markupToDomElement(markup) {
...@@ -153,6 +158,37 @@ describe('gl_emoji', () => { ...@@ -153,6 +158,37 @@ describe('gl_emoji', () => {
}, },
); );
}); });
it('question mark when invalid emoji name given', () => {
const name = 'invalid_emoji';
const emojiKey = 'grey_question';
const markup = glEmojiTag(name);
const glEmojiElement = markupToDomElement(markup);
testGlEmojiElement(
glEmojiElement,
emojiFixtureMap[emojiKey].name,
emojiFixtureMap[emojiKey].unicodeVersion,
emojiFixtureMap[emojiKey].moji,
);
});
it('question mark with image fallback when invalid emoji name given', () => {
const name = 'invalid_emoji';
const emojiKey = 'grey_question';
const markup = glEmojiTag(name, {
forceFallback: true,
});
const glEmojiElement = markupToDomElement(markup);
testGlEmojiElement(
glEmojiElement,
emojiFixtureMap[emojiKey].name,
emojiFixtureMap[emojiKey].unicodeVersion,
emojiFixtureMap[emojiKey].moji,
{
forceFallback: true,
},
);
});
}); });
describe('isFlagEmoji', () => { describe('isFlagEmoji', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment