Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Options to useOnlyUTC in the mail header #2

Open
wants to merge 2 commits into
base: random-fixes
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
69 changes: 52 additions & 17 deletions headeremitter.js
Expand Up @@ -72,10 +72,17 @@ function clamp(value, min, max, def) {
* @param [options.useASCII=true] {Boolean}
* If true, then RFC 2047 and RFC 2231 encoding of headers will be performed
* as needed to retain headers as ASCII.
* @param [options.useOnlyUTC=true] {Boolean}
* If true, then date added in header is always in UTC. This is to provide
* user location privacy by not revealing Timezone location.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The option is probably better named "hideDateTimezone". Also, your English is not grammatically correct here:

If true, then use the UTC time zone instead of the local time zone when emitting date values.

[No need to mention the second sentence]

Also, note that "time zone" is two words in English, not one, and that capitalization is reserved for acronyms or the first word of a sentence.

*/
function HeaderEmitter(handler, options) {
/// The inferred value of options.useASCII
this._useASCII = options.useASCII === undefined ? true : options.useASCII;

/// The inferred value of options.useOnlyUTC
this._useOnlyUTC = options.useOnlyUTC === undefined ? false : options.useOnlyUTC;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is > 80 characters.


/// The handler to use.
this._handler = handler;
/**
Expand Down Expand Up @@ -728,26 +735,54 @@ HeaderEmitter.prototype.addDate = function (date) {
if (date.getFullYear() < 1900 || date.getFullYear() > 9999)
throw new Error("Date year is out of encodable range");

// Start by computing the timezone offset for a day. We lack a good format, so
// the the 0-padding is done by hand. Note that the tzoffset we output is in
// the form ±hhmm, so we need to separate the offset (in minutes) into an hour
// and minute pair.
let tzOffset = date.getTimezoneOffset();
let tzOffHours = Math.abs(Math.trunc(tzOffset / 60));
let tzOffMinutes = Math.abs(tzOffset) % 60;
let tzOffsetStr = (tzOffset > 0 ? "-" : "+") +
padTo2Digits(tzOffHours) + padTo2Digits(tzOffMinutes);
let day = "", dDate = "", month = "", fullYear = "", hours = "",
minutes = "", seconds = "", tzOffsetStr = ""
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's simpler to replace most of this logic with something like:

let getDayProp = this._useOnlyUTC ? (prop => date["getUTC" + prop]()) : (prop => date["get" + prop]());

and then you can say getDayProp("Day") without needing to have all of the getters in the block.


//handle OnlyUTC based date pref
if (this._useOnlyUTC){

day = date.getUTCDay();
dDate = date.getUTCDate();
month = date.getUTCMonth();
fullYear = date.getUTCFullYear();
hours = date.getUTCHours();
minutes = date.getUTCMinutes();
seconds = date.getUTCSeconds();

// Because we are setting time corresponding to UTC
tzOffsetStr = "+0000";

} else {

// Start by computing the timezone offset for a day. We lack a good format, so
// the the 0-padding is done by hand. Note that the tzoffset we output is in
// the form ±hhmm, so we need to separate the offset (in minutes) into an hour
// and minute pair.
let tzOffset = date.getTimezoneOffset();
let tzOffHours = Math.abs(Math.trunc(tzOffset / 60));
let tzOffMinutes = Math.abs(tzOffset) % 60;

tzOffsetStr = (tzOffset > 0 ? "-" : "+") +
padTo2Digits(tzOffHours) + padTo2Digits(tzOffMinutes);

day = date.getDay();
dDate = date.getDate();
month = date.getMonth();
fullYear = date.getFullYear();
hours = date.getHours();
minutes = date.getMinutes();
seconds = date.getSeconds();
}

// Convert the day-time figure into a single value to avoid unwanted line
// breaks in the middle.
let dayTime = [
kDaysOfWeek[date.getDay()] + ",",
date.getDate(),
mimeutils.kMonthNames[date.getMonth()],
date.getFullYear(),
padTo2Digits(date.getHours()) + ":" +
padTo2Digits(date.getMinutes()) + ":" +
padTo2Digits(date.getSeconds()),
let dayTime = [ kDaysOfWeek[day] + ",",
dDate,
mimeutils.kMonthNames[month],
fullYear,
padTo2Digits(hours) + ":" +
padTo2Digits(minutes) + ":" +
padTo2Digits(seconds),
tzOffsetStr
].join(" ");
this.addText(dayTime, false);
Expand Down
99 changes: 99 additions & 0 deletions test/test_header_emitter.js
Expand Up @@ -305,6 +305,105 @@ suite('headeremitter', function () {
assert.equal(now.getTime() - now.getMilliseconds(), reparsed.getTime());
});
});

/**
* Test addDate method when displayUTC flag is set. This is to support add-ons which dont want
* emails to contain TimeStamp information when email is sent. For example, Torbirdy add-on doesnt
* want timestamp to be shown as it can leak the user location.
*/
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need a documentation comment for this test suite--if the test suite name isn't indicative of what's being tested, then something's wrong.

suite("addDateAsUTCOnly", function () {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although the suite here should be named "addDate (with hidden timezone)", to keep the convention that the suites are named after the actual functions being tested.

let handler = {
reset: function (expected) {
this.output = '';
this.expected = expected;
},
deliverData: function (data) { this.output += data; },
deliverEOF: function () {
assert.equal(this.output, this.expected + '\r\n');
}
};
let header_tests = [
["2000-01-01T00:00:00Z", "Sat, 1 Jan 2000 00:00:00 +0000"],
["2000-02-01T00:00:00Z", "Tue, 1 Feb 2000 00:00:00 +0000"],
["2000-03-01T00:00:00Z", "Wed, 1 Mar 2000 00:00:00 +0000"],
["2000-04-01T00:00:00Z", "Sat, 1 Apr 2000 00:00:00 +0000"],
["2000-05-01T00:00:00Z", "Mon, 1 May 2000 00:00:00 +0000"],
["2000-06-01T00:00:00Z", "Thu, 1 Jun 2000 00:00:00 +0000"],
["2000-07-01T00:00:00Z", "Sat, 1 Jul 2000 00:00:00 +0000"],
["2000-08-01T00:00:00Z", "Tue, 1 Aug 2000 00:00:00 +0000"],
["2000-09-01T00:00:00Z", "Fri, 1 Sep 2000 00:00:00 +0000"],
["2000-10-01T00:00:00Z", "Sun, 1 Oct 2000 00:00:00 +0000"],
["2000-11-01T00:00:00Z", "Wed, 1 Nov 2000 00:00:00 +0000"],
["2000-12-01T00:00:00Z", "Fri, 1 Dec 2000 00:00:00 +0000"],

// Test timezone offsets
["2000-06-01T12:00:00Z", "Thu, 1 Jun 2000 12:00:00 +0000"],
["2000-06-01T12:00:00+0100", "Thu, 1 Jun 2000 11:00:00 +0000"],
["2000-06-01T12:00:00+0130", "Thu, 1 Jun 2000 10:30:00 +0000"],
["2000-06-01T12:00:00-0100", "Thu, 1 Jun 2000 13:00:00 +0000"],
["2000-06-01T12:00:00-0130", "Thu, 1 Jun 2000 13:30:00 +0000"],
["2000-06-01T12:00:00+1345", "Wed, 31 May 2000 22:15:00 +0000"],
["2000-06-01T12:00:00-1200", "Fri, 2 Jun 2000 00:00:00 +0000"],
["2000-06-01T12:00:00+1337", "Wed, 31 May 2000 22:23:00 +0000"],
["2000-06-01T12:00:00+0101", "Thu, 1 Jun 2000 10:59:00 +0000"],
["2000-06-01T12:00:00-1337", "Fri, 2 Jun 2000 01:37:00 +0000"],

//Some new cases with respect to changing Timezone to UTC

// Trying change of year conversion
["2000-12-31T12:00:00-1200", "Mon, 1 Jan 2001 00:00:00 +0000"],
["2001-01-01T00:00:00+1200", "Sun, 31 Dec 2000 12:00:00 +0000"],

// Trying leap year conversion
["2000-02-28T12:00:00-1200", "Tue, 29 Feb 2000 00:00:00 +0000"],
["2000-03-01T00:00:00+1200", "Tue, 29 Feb 2000 12:00:00 +0000"],

// Trying non-leap year conversion
["2001-02-28T12:00:00-1200", "Thu, 1 Mar 2001 00:00:00 +0000"],
["2001-03-01T00:00:00+1200", "Wed, 28 Feb 2001 12:00:00 +0000"],

// Try some varying hour, minute, and second amounts, to double-check
// padding and time dates.
["2000-06-01T01:02:03Z", "Thu, 1 Jun 2000 01:02:03 +0000"],
["2000-06-01T23:13:17Z", "Thu, 1 Jun 2000 23:13:17 +0000"],
["2000-06-01T00:05:04Z", "Thu, 1 Jun 2000 00:05:04 +0000"],
["2000-06-01T23:59:59Z", "Thu, 1 Jun 2000 23:59:59 +0000"],
["2000-06-01T13:17:40Z", "Thu, 1 Jun 2000 13:17:40 +0000"],
["2000-06-01T11:15:34Z", "Thu, 1 Jun 2000 11:15:34 +0000"],
["2000-06-01T04:09:09Z", "Thu, 1 Jun 2000 04:09:09 +0000"],
["2000-06-01T04:10:10Z", "Thu, 1 Jun 2000 04:10:10 +0000"],
["2000-06-01T09:13:17Z", "Thu, 1 Jun 2000 09:13:17 +0000"],
["2000-06-01T13:12:14Z", "Thu, 1 Jun 2000 13:12:14 +0000"],
["2000-06-01T14:16:48Z", "Thu, 1 Jun 2000 14:16:48 +0000"],

// Try varying month, date, and year values.
["2000-01-31T00:00:00Z", "Mon, 31 Jan 2000 00:00:00 +0000"],
["2000-02-28T00:00:00Z", "Mon, 28 Feb 2000 00:00:00 +0000"],
["2000-02-29T00:00:00Z", "Tue, 29 Feb 2000 00:00:00 +0000"],
["2001-02-28T00:00:00Z", "Wed, 28 Feb 2001 00:00:00 +0000"],
["2000-03-31T00:00:00Z", "Fri, 31 Mar 2000 00:00:00 +0000"],
["2000-04-30T00:00:00Z", "Sun, 30 Apr 2000 00:00:00 +0000"],
["2000-05-31T00:00:00Z", "Wed, 31 May 2000 00:00:00 +0000"],
["2000-06-30T00:00:00Z", "Fri, 30 Jun 2000 00:00:00 +0000"],
["2000-07-31T00:00:00Z", "Mon, 31 Jul 2000 00:00:00 +0000"],
["2000-08-31T00:00:00Z", "Thu, 31 Aug 2000 00:00:00 +0000"],
["2000-09-30T00:00:00Z", "Sat, 30 Sep 2000 00:00:00 +0000"],
["2000-10-31T00:00:00Z", "Tue, 31 Oct 2000 00:00:00 +0000"],
["2000-11-30T00:00:00Z", "Thu, 30 Nov 2000 00:00:00 +0000"],
["2000-12-31T00:00:00Z", "Sun, 31 Dec 2000 00:00:00 +0000"],
["1900-01-01T00:00:00Z", "Mon, 1 Jan 1900 00:00:00 +0000"],
["9999-12-31T23:59:59Z", "Fri, 31 Dec 9999 23:59:59 +0000"],
];
header_tests.forEach(function (data) {
arrayTest(data, function () {
let emitter = headeremitter.makeStreamingEmitter(handler, { useOnlyUTC: true });
handler.reset(data[1]);
emitter.addDate(new MockDate(data[0]));
emitter.finish(true);
});
});
});

suite("addParameter", function () {
let handler = {
reset: function (expected) {
Expand Down