fix(protocol): validate profile birthdays against the calendar
Omit invalid birthdays and preserve valid leap days when the birth year is private. Refs #594
This commit is contained in:
@@ -94,7 +94,7 @@ export function applyProfileDetails(info: UserProfileInfo, numMap: Map<number, n
|
||||
export function applyBirthday(info: UserProfileInfo, bytesMap: Map<number, Uint8Array>): void {
|
||||
const raw = bytesMap.get(20031);
|
||||
|
||||
if (!raw || raw.length < 4) {
|
||||
if (raw?.length !== 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,11 @@ export function applyBirthday(info: UserProfileInfo, bytesMap: Map<number, Uint8
|
||||
const month = bytes.readUInt8(2);
|
||||
const day = bytes.readUInt8(3);
|
||||
|
||||
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
||||
// A hidden year can still represent February 29.
|
||||
const date = new Date(0);
|
||||
date.setUTCFullYear(year || 2000, month - 1, day);
|
||||
|
||||
if (date.getUTCMonth() !== month - 1 || date.getUTCDate() !== day) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,17 +148,22 @@ describe('FetchUserProfile namespace', () => {
|
||||
},
|
||||
);
|
||||
|
||||
it('omits only the birth year when the year is hidden', async () => {
|
||||
it.each([
|
||||
[12, 31],
|
||||
[2, 29],
|
||||
])('keeps a hidden-year birthday %i/%i', async (month, day) => {
|
||||
const sender = makeSender({
|
||||
body: {
|
||||
uin: 10001,
|
||||
properties: {
|
||||
bytesProperties: [{ code: 20031, value: new Uint8Array([0, 0, 12, 31]) }],
|
||||
bytesProperties: [
|
||||
{ code: 20031, value: new Uint8Array([0, 0, month, day]) },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
const profile = await FetchUserProfile.invoke(sender, { uin: 10001 });
|
||||
expect(profile).toMatchObject({ birthdayMonth: 12, birthdayDay: 31 });
|
||||
expect(profile).toMatchObject({ birthdayMonth: month, birthdayDay: day });
|
||||
expect(profile).not.toHaveProperty('birthdayYear');
|
||||
});
|
||||
|
||||
@@ -167,7 +172,10 @@ describe('FetchUserProfile namespace', () => {
|
||||
['an all-zero value', [0, 0, 0, 0]],
|
||||
['an out-of-range month', [0x07, 0xd0, 13, 1]],
|
||||
['an out-of-range day', [0x07, 0xd0, 1, 32]],
|
||||
['April 31', [0x07, 0xd0, 4, 31]],
|
||||
['a leap day in 1900', [0x07, 0x6c, 2, 29]],
|
||||
['a truncated value', [0x07, 0xd0, 3]],
|
||||
['an oversized value', [0x07, 0xd0, 3, 15, 0]],
|
||||
])('leaves the birthday unavailable for %s', async (_case, value) => {
|
||||
const sender = makeSender({
|
||||
body: {
|
||||
|
||||
Reference in New Issue
Block a user