@hint/hint-validate-set-cookie-header
Version:
hint for best practices related to the usage of the Set-Cookie response header.
266 lines (265 loc) • 11.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_tests_helpers_1 = require("@hint/utils-tests-helpers");
const utils_types_1 = require("@hint/utils-types");
const hintPath = (0, utils_tests_helpers_1.getHintPath)(__filename);
const setCookie = (fields) => {
return { 'set-cookie': fields };
};
const doubleQuotedValueHeader = setCookie(`cookieName="cookieValue"; Secure; HttpOnly`);
const standardHeader = setCookie(`cookieName=cookieValue; Secure; HttpOnly`);
const starnderHeaderLowerCase = setCookie(`cookieName=cookieValue; secure; httponly`);
const standardHeaderWithSecurePrefix = setCookie(`__Secure-ID=123; Secure; Domain=example.com; HttpOnly`);
const standardHeaderWithHostPrefix = setCookie(`__Host-ID=123; Secure; Path=/; HttpOnly`);
const noNameValueStringHeader = setCookie(`Max-Age=0; Secure; HttpOnly`);
const invalidAttributeHeader = setCookie(`cookieName=cookieValue; MaxAge=0; Secure; HttpOnly`);
const noSecureHeader = setCookie(`cookieName=cookieValue; HttpOnly`);
const noHttpOnlyHeader = setCookie(`cookieName=cookieValue; Secure`);
const invalidNameHeader = setCookie(`"cookieName"=cookieValue; Secure; HttpOnly`);
const invalidValueHeader = setCookie(`cookieName=cookie value; Secure; HttpOnly`);
const invalidHeaderBackslash = setCookie(`cookie\\Name=cookie\\Value; Secure; HttpOnly`);
const invalidDateFormatHeader = setCookie(`cookieName=cookieValue; expires=Wed, 31-Dec-97 23:59:59 GMT; Secure; HttpOnly`);
const trailingSemicolonHeader = setCookie(`cookieName=cookieValue; Secure; HttpOnly;`);
const multipleErrorsHeader = setCookie(`"cookieName"=cookie value`);
const noPathHostPrefixHeader = setCookie(`__Host-id=1; Secure; HttpOnly`);
const hasDomainHostPrefixHeader = setCookie(`__Host-id=1; Secure; Path=/; domain=example.com; HttpOnly`);
const maxAgeOnlyHeader = setCookie(`cookieName=cookieValue; Max-Age=123; secure; httponly`);
const expiresOnlyHeader = setCookie(`cookieName=cookieValue; expires=Wed, 21 Oct 2015 07:28:00 GMT; secure; httponly`);
const bothMaxAgeAndExpireHeader = setCookie(`cookieName=cookieValue; Max-Age=123; expires=Wed, 21 Oct 2015 07:28:00 GMT; secure; httponly`);
const messages = {
hasDomainHostPrefixError: `A 'set-cookie' header contains '__Host-' prefix but the 'domain' directive is set.`,
invalidAttributeError: `A 'set-cookie' header contains unknown attribute 'maxage'.`,
invalidDateFormatError: `A 'set-cookie' has an invalid 'expires' date format. The recommended format is: Wed, 31 Dec 1997 23:59:59 GMT`,
invalidNameError: `A 'set-cookie' header has an invalid cookie name.`,
invalidValueError: `A 'set-cookie' header has an invalid cookie value.`,
maxAgeNoExpireWarning: `Internet Explorer (IE 6, IE 7, and IE 8) doesn't support 'max-age' directive in the 'set-cookie' header.`,
maxAgePrecedenceWarning: `The 'max-age' attribute takes precedence when both 'expires' and 'max-age' both exist.`,
noHttpOnlyHeaderError: `A 'set-cookie' header doesn't have the 'httponly' directive.`,
noNameValueStringError: `A 'set-cookie' header doesn't contain a cookie name-value string.`,
noPathHasHostPrefixError: `A 'set-cookie' header contains '__Host-' prefix but the 'path' directive doesn't have a value of '/'.`,
noSecureHeaderError: `A 'set-cookie' header doesn't have the 'secure' directive.`,
trailingSemicolonError: `A 'set-cookie' header has a trailing ';'.`
};
const defaultTests = [
{
name: `Standard set-cookie header`,
serverConfig: { '/': { headers: standardHeader } }
},
{
name: `Cooke value is wrapped in double quotes`,
serverConfig: { '/': { headers: doubleQuotedValueHeader } }
},
{
name: `Directive names are in lowercases`,
serverConfig: { '/': { headers: starnderHeaderLowerCase } }
},
{
name: `Standard set-cookie header with '__secure' prefix`,
serverConfig: { '/': { headers: standardHeaderWithSecurePrefix } }
},
{
name: `Standard set-cookie header with '__Host' prefix`,
serverConfig: { '/': { headers: standardHeaderWithHostPrefix } }
},
{
name: `Header doesn't have cookie name-value-string`,
reports: [{
message: messages.noNameValueStringError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: noNameValueStringHeader } }
},
{
name: `Header contains unknown attributes`,
reports: [{
message: messages.invalidAttributeError,
severity: utils_types_1.Severity.warning
}],
serverConfig: { '/': { headers: invalidAttributeHeader } }
},
{
name: `Header doesn't have 'Secure' directive`,
reports: [{
message: messages.noSecureHeaderError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: noSecureHeader } }
},
{
name: `Header doesn't have 'HttpOnly' directive`,
reports: [{
message: messages.noHttpOnlyHeaderError,
severity: utils_types_1.Severity.warning
}],
serverConfig: { '/': { headers: noHttpOnlyHeader } }
},
{
name: `Cookie name contains invalid characters`,
reports: [{
message: messages.invalidNameError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: invalidNameHeader } }
},
{
name: `Cookie value contains invalid characters`,
reports: [{
message: messages.invalidValueError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: invalidValueHeader } }
},
{
name: `Cookie name and value contains invalid character (backslash)`,
reports: [{
message: messages.invalidNameError,
severity: utils_types_1.Severity.error
},
{
message: messages.invalidValueError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: invalidHeaderBackslash } }
},
{
name: `'Expires' directive contains invalid date format`,
reports: [{
message: messages.invalidDateFormatError,
severity: utils_types_1.Severity.warning
}],
serverConfig: { '/': { headers: invalidDateFormatHeader } }
},
{
name: `Header contains trailing semicolon`,
reports: [{
message: messages.trailingSemicolonError,
severity: utils_types_1.Severity.hint
}],
serverConfig: { '/': { headers: trailingSemicolonHeader } }
},
{
name: `Header contains multiple errors`,
reports: [
{
message: messages.invalidNameError,
severity: utils_types_1.Severity.error
},
{
message: messages.invalidValueError,
severity: utils_types_1.Severity.error
},
{
message: messages.noSecureHeaderError,
severity: utils_types_1.Severity.error
},
{
message: messages.noHttpOnlyHeaderError,
severity: utils_types_1.Severity.warning
}
],
serverConfig: { '/': { headers: multipleErrorsHeader } }
},
{
name: `Cookie name has '__Host' prefix but doesn't have 'Path' directive`,
reports: [{
message: messages.noPathHasHostPrefixError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: noPathHostPrefixHeader } }
},
{
name: `Cookie name has '__Host' prefix but has 'Domain' directive set`,
reports: [{
message: messages.hasDomainHostPrefixError,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: hasDomainHostPrefixHeader } }
}
];
const olderBrowserOnlyTests = [
{
name: `'Max-Age' only in old browsers (older browsers only)`,
reports: [{
message: messages.maxAgeNoExpireWarning,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: maxAgeOnlyHeader } }
},
{
name: `Both 'Max-Age' and 'Expires' exist in new browsers (older browsers only)`,
serverConfig: { '/': { headers: bothMaxAgeAndExpireHeader } }
},
{
name: `'Expires' only in new browsers (older browsers only)`,
serverConfig: { '/': { headers: expiresOnlyHeader } }
},
{
name: `No 'Max-Age' or 'Expires' in new browsers (older browsers only)`,
serverConfig: { '/': { headers: standardHeader } }
}
];
const newBrowserOnlyTests = [
{
name: `Both 'Max-Age' and 'Expires' exist in new browsers (new browsers only)`,
reports: [{
message: messages.maxAgePrecedenceWarning,
severity: utils_types_1.Severity.hint
}],
serverConfig: { '/': { headers: bothMaxAgeAndExpireHeader } }
},
{
name: `'Max-Age' only in new browsers`,
serverConfig: { '/': { headers: maxAgeOnlyHeader } }
},
{
name: `'Expires' only in new browsers (new browsers only)`,
serverConfig: { '/': { headers: expiresOnlyHeader } }
},
{
name: `No 'Max-Age' or 'Expires' in new browsers (new browsers only)`,
serverConfig: { '/': { headers: standardHeader } }
}
];
const oldAndNewBrowsersTest = [
{
name: `'Max-Age' only in old browsers (old and new browsers)`,
reports: [{
message: messages.maxAgeNoExpireWarning,
severity: utils_types_1.Severity.error
}],
serverConfig: { '/': { headers: maxAgeOnlyHeader } }
},
{
name: `Both 'Max-Age' and 'Expires' exist in new browsers (old and new browsers)`,
serverConfig: { '/': { headers: bothMaxAgeAndExpireHeader } }
},
{
name: `'Expires' only in new browsers (old and new browsers)`,
serverConfig: { '/': { headers: expiresOnlyHeader } }
},
{
name: `No 'Max-Age' or 'Expires' in new browsers (old and new browsers)`,
serverConfig: { '/': { headers: standardHeader } }
}
];
(0, utils_tests_helpers_1.testHint)(hintPath, defaultTests, { https: true });
(0, utils_tests_helpers_1.testHint)(hintPath, newBrowserOnlyTests, {
browserslist: [
'> 1%',
'last 2 versions'
],
https: true
});
(0, utils_tests_helpers_1.testHint)(hintPath, olderBrowserOnlyTests, {
browserslist: [
'ie 6', 'ie 7'
],
https: true
});
(0, utils_tests_helpers_1.testHint)(hintPath, oldAndNewBrowsersTest, {
browserslist: [
'ie >= 6',
'last 2 versions'
],
https: true
});