UNPKG

@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
"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 });