Skip to content

Commit

Permalink
feat(node): Vendor cookie module (#9308)
Browse files Browse the repository at this point in the history
  • Loading branch information
timfish authored Oct 19, 2023
1 parent 7abd153 commit 7236510
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 4 deletions.
1 change: 0 additions & 1 deletion packages/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"@sentry/core": "7.74.1",
"@sentry/types": "7.74.1",
"@sentry/utils": "7.74.1",
"cookie": "^0.5.0",
"https-proxy-agent": "^5.0.0"
},
"devDependencies": {
Expand Down
78 changes: 78 additions & 0 deletions packages/node/src/cookie.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* This code was originally copied from the 'cookie` module at v0.5.0 and was simplified for our use case.
* https://github.com/jshttp/cookie/blob/a0c84147aab6266bdb3996cf4062e93907c0b0fc/index.js
* It had the following license:
*
* (The MIT License)
*
* Copyright (c) 2012-2014 Roman Shtylman <[email protected]>
* Copyright (c) 2015 Douglas Christopher Wilson <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/**
* Parses a cookie string
*/
export function parseCookie(str: string): Record<string, string> {
const obj: Record<string, string> = {};
let index = 0;

while (index < str.length) {
const eqIdx = str.indexOf('=', index);

// no more cookie pairs
if (eqIdx === -1) {
break;
}

let endIdx = str.indexOf(';', index);

if (endIdx === -1) {
endIdx = str.length;
} else if (endIdx < eqIdx) {
// backtrack on prior semicolon
index = str.lastIndexOf(';', eqIdx - 1) + 1;
continue;
}

const key = str.slice(index, eqIdx).trim();

// only assign once
if (undefined === obj[key]) {
let val = str.slice(eqIdx + 1, endIdx).trim();

// quoted values
if (val.charCodeAt(0) === 0x22) {
val = val.slice(1, -1);
}

try {
obj[key] = val.indexOf('%') !== -1 ? decodeURIComponent(val) : val;
} catch (e) {
obj[key] = val;
}
}

index = endIdx + 1;
}

return obj;
}
6 changes: 3 additions & 3 deletions packages/node/src/requestdata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import type {
TransactionSource,
} from '@sentry/types';
import { isPlainObject, isString, normalize, stripUrlQueryAndFragment } from '@sentry/utils';
import * as cookie from 'cookie';
import * as url from 'url';

import { parseCookie } from './cookie';

const DEFAULT_INCLUDES = {
ip: false,
request: true,
Expand Down Expand Up @@ -202,11 +203,10 @@ export function extractRequestData(
// cookies:
// node, express, koa: req.headers.cookie
// vercel, sails.js, express (w/ cookie middleware), nextjs: req.cookies
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
requestData.cookies =
// TODO (v8 / #5257): We're only sending the empty object for backwards compatibility, so the last bit can
// come off in v8
req.cookies || (headers.cookie && cookie.parse(headers.cookie)) || {};
req.cookies || (headers.cookie && parseCookie(headers.cookie)) || {};
break;
}
case 'query_string': {
Expand Down
67 changes: 67 additions & 0 deletions packages/node/test/cookie.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* This code was originally copied from the 'cookie` module at v0.5.0 and was simplified for our use case.
* https://github.com/jshttp/cookie/blob/a0c84147aab6266bdb3996cf4062e93907c0b0fc/test/parse.js
* It had the following license:
*
* (The MIT License)
*
* Copyright (c) 2012-2014 Roman Shtylman <[email protected]>
* Copyright (c) 2015 Douglas Christopher Wilson <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { parseCookie } from '../src/cookie';

describe('parseCookie(str)', function () {
it('should parse cookie string to object', function () {
expect(parseCookie('foo=bar')).toEqual({ foo: 'bar' });
expect(parseCookie('foo=123')).toEqual({ foo: '123' });
});

it('should ignore OWS', function () {
expect(parseCookie('FOO = bar; baz = raz')).toEqual({ FOO: 'bar', baz: 'raz' });
});

it('should parse cookie with empty value', function () {
expect(parseCookie('foo= ; bar=')).toEqual({ foo: '', bar: '' });
});

it('should URL-decode values', function () {
expect(parseCookie('foo="bar=123456789&name=Magic+Mouse"')).toEqual({ foo: 'bar=123456789&name=Magic+Mouse' });

expect(parseCookie('email=%20%22%2c%3b%2f')).toEqual({ email: ' ",;/' });
});

it('should return original value on escape error', function () {
expect(parseCookie('foo=%1;bar=bar')).toEqual({ foo: '%1', bar: 'bar' });
});

it('should ignore cookies without value', function () {
expect(parseCookie('foo=bar;fizz ; buzz')).toEqual({ foo: 'bar' });
expect(parseCookie(' fizz; foo= bar')).toEqual({ foo: 'bar' });
});

it('should ignore duplicate cookies', function () {
expect(parseCookie('foo=%1;bar=bar;foo=boo')).toEqual({ foo: '%1', bar: 'bar' });
expect(parseCookie('foo=false;bar=bar;foo=tre')).toEqual({ foo: 'false', bar: 'bar' });
expect(parseCookie('foo=;bar=bar;foo=boo')).toEqual({ foo: '', bar: 'bar' });
});
});

0 comments on commit 7236510

Please sign in to comment.