Visitar URL original
fix(common): avoid prototype lookups in date format caches · angular/angular@359fb50 · GitHub
Skip to content

Commit 359fb50

Browse files
arshsmith1mattrbeck
authored andcommitted
fix(common): avoid prototype lookups in date format caches
The NAMED_FORMATS and DATE_FORMATS caches were plain objects read with a truthy check keyed by a token from the format string, so a token matching an inherited Object member (e.g. `__proto__`) resolved to a prototype value. Create both caches with a null prototype so only real entries are returned.
1 parent 37f3279 commit 359fb50

2 files changed

Lines changed: 14 additions & 3 deletions

File tree

‎packages/common/src/i18n/format_date.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ import {RuntimeErrorCode} from '../errors';
3333
export const ISO8601_DATE_REGEX =
3434
/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
3535
// 1 2 3 4 5 6 7 8 9 10 11
36-
const NAMED_FORMATS: {[localeId: string]: {[format: string]: string}} = {};
36+
// tslint:disable-next-line:no-toplevel-property-access
37+
const NAMED_FORMATS: {[localeId: string]: {[format: string]: string}} = Object.create(null);
3738
const DATE_FORMATS_SPLIT =
3839
/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;
3940
const MAX_DATE_FORMAT_LENGTH = 256;
@@ -201,7 +202,7 @@ function createDate(year: number, month: number, date: number): Date {
201202

202203
function getNamedFormat(locale: string, format: string): string {
203204
const localeId = getLocaleId(locale);
204-
NAMED_FORMATS[localeId] ??= {};
205+
NAMED_FORMATS[localeId] ??= Object.create(null);
205206

206207
if (NAMED_FORMATS[localeId][format]) {
207208
return NAMED_FORMATS[localeId][format];
@@ -570,7 +571,8 @@ function weekNumberingYearGetter(size: number, trim = false): DateFormatter {
570571

571572
type DateFormatter = (date: Date, locale: string, offset: number) => string;
572573

573-
const DATE_FORMATS: {[format: string]: DateFormatter} = {};
574+
// tslint:disable-next-line:no-toplevel-property-access
575+
const DATE_FORMATS: {[format: string]: DateFormatter} = Object.create(null);
574576

575577
// Based on CLDR formats:
576578
// See complete list: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table

‎packages/common/test/i18n/format_date_spec.ts‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,15 @@ describe('Format date', () => {
361361
);
362362
});
363363

364+
it('should treat format tokens that collide with Object.prototype members as literals', () => {
365+
// A format token that matches an inherited property name (e.g. `__proto__`) must not
366+
// resolve to a value off the prototype of the internal format caches. Before the caches
367+
// were given a null prototype, `__proto__` read back `Object.prototype`, garbling the
368+
// named-format lookup and crashing the token lookup (it was invoked as a formatter).
369+
expect(formatDate(date, '__proto__', ɵDEFAULT_LOCALE_ID)).toEqual('__proto__');
370+
expect(formatDate(date, 'y__proto__', ɵDEFAULT_LOCALE_ID)).toEqual('2015__proto__');
371+
});
372+
364373
it('should format invalid in IE ISO date', () =>
365374
expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, ɵDEFAULT_LOCALE_ID)).toEqual(
366375
'Jan 11, 2017',

0 commit comments

Comments
 (0)