Skip to content

Commit

Permalink
fix: make sure rest cookies work only with rest domain (#10715)
Browse files Browse the repository at this point in the history
  • Loading branch information
kewitz authored Nov 5, 2024
1 parent c8edbe3 commit bd0ab62
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 34 deletions.
13 changes: 2 additions & 11 deletions components/ExportTransactionsCSVModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { flatten, isEmpty, omit } from 'lodash';
import { FormattedMessage } from 'react-intl';

import { setRestAuthorizationCookie } from '../lib/auth';
import { simpleDateToISOString } from '../lib/date-utils';
import { getEnvVar } from '../lib/env-utils';
import {
Expand Down Expand Up @@ -34,8 +35,6 @@ import StyledModal, { ModalBody, ModalFooter, ModalHeader } from './StyledModal'
import StyledSelect from './StyledSelect';
import { Span } from './Text';

const env = process.env.OC_ENV;

type ExportTransactionsCSVModalProps = {
onClose: () => void;
dateFrom?: string;
Expand Down Expand Up @@ -166,15 +165,7 @@ const ExportTransactionsCSVModal = ({
}, [tmpDateInterval, collective, host, accounts]);

React.useEffect(() => {
const accessToken = getFromLocalStorage(LOCAL_STORAGE_KEYS.ACCESS_TOKEN);
if (typeof document !== 'undefined' && accessToken) {
document.cookie =
env === 'development' || env === 'e2e'
? `authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120`
: // It is not possible to use HttpOnly when setting from JavaScript.
// I'm enforcing SameSite and Domain in production to prevent CSRF.
`authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120;domain=opencollective.com;secure`;
}
setRestAuthorizationCookie();
setDownloadUrl(getUrl());
}, [fields, flattenTaxesAndPaymentProcessorFees, tmpDateInterval]);

Expand Down
13 changes: 2 additions & 11 deletions components/dashboard/ExportHostedCollectivesCSVModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { MouseEventHandler } from 'react';
import { FormattedMessage } from 'react-intl';
import slugify from 'slugify';

import { setRestAuthorizationCookie } from '../../lib/auth';
import {
AVERAGE_ROWS_PER_MINUTE,
FIELD_OPTIONS,
Expand Down Expand Up @@ -48,8 +49,6 @@ import {
import { Input } from '../ui/Input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/Select';

const env = process.env.OC_ENV;

const TOTAL_AVAILABLE_FIELDS = FIELDS.length;

const TABS = Object.keys(GROUP_FIELDS).map(group => ({
Expand Down Expand Up @@ -243,15 +242,7 @@ const ExportHostedCollectivesCSVModal = ({
}, [queryFilter.values, account, open]);

React.useEffect(() => {
const accessToken = getFromLocalStorage(LOCAL_STORAGE_KEYS.ACCESS_TOKEN);
if (typeof document !== 'undefined' && accessToken) {
document.cookie =
env === 'development' || env === 'e2e'
? `authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120`
: // It is not possible to use HttpOnly when setting from JavaScript.
// I'm enforcing SameSite and Domain in production to prevent CSRF.
`authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120;domain=opencollective.com;secure`;
}
setRestAuthorizationCookie();
setDownloadUrl(makeUrl({ account, queryFilter, fields }));
}, [fields, queryFilter, account, isHostReport, setDownloadUrl]);

Expand Down
13 changes: 2 additions & 11 deletions components/dashboard/ExportTransactionsCSVModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type { MouseEventHandler } from 'react';
import { FormattedMessage } from 'react-intl';
import slugify from 'slugify';

import { setRestAuthorizationCookie } from '../../lib/auth';
import { getEnvVar } from '../../lib/env-utils';
import type { CSVField } from '../../lib/export-csv/transactions-csv';
import {
Expand Down Expand Up @@ -44,8 +45,6 @@ import { Input } from '../ui/Input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/Select';
import { Switch } from '../ui/Switch';

const env = process.env.OC_ENV;

const TOTAL_AVAILABLE_FIELDS = FIELDS.length;

const TABS = Object.keys(GROUP_FIELDS).map(group => ({
Expand Down Expand Up @@ -305,15 +304,7 @@ const ExportTransactionsCSVModal = ({
}, [queryFilter.values, account, open]);

React.useEffect(() => {
const accessToken = getFromLocalStorage(LOCAL_STORAGE_KEYS.ACCESS_TOKEN);
if (typeof document !== 'undefined' && accessToken) {
document.cookie =
env === 'development' || env === 'e2e'
? `authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120`
: // It is not possible to use HttpOnly when setting from JavaScript.
// I'm enforcing SameSite and Domain in production to prevent CSRF.
`authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120;domain=opencollective.com;secure`;
}
setRestAuthorizationCookie();
setDownloadUrl(makeUrl({ account, isHostReport, queryFilter, flattenTaxesAndPaymentProcessorFees, fields }));
}, [fields, flattenTaxesAndPaymentProcessorFees, queryFilter, account, isHostReport, setDownloadUrl]);

Expand Down
20 changes: 19 additions & 1 deletion lib/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type Express from 'express';

import { LOCAL_STORAGE_KEYS, removeFromLocalStorage } from './local-storage';
import { getFromLocalStorage, LOCAL_STORAGE_KEYS, removeFromLocalStorage } from './local-storage';

const env = process.env.OC_ENV;

export function logout() {
removeFromLocalStorage(LOCAL_STORAGE_KEYS.ACCESS_TOKEN);
Expand All @@ -12,6 +14,22 @@ export function logout() {
document.cookie = 'accessTokenPayload=;Max-Age=0;secure;path=/';
}

/**
* Set rest domain authorization cookie with the current access token.
*/
export function setRestAuthorizationCookie() {
const accessToken = getFromLocalStorage(LOCAL_STORAGE_KEYS.ACCESS_TOKEN);
if (typeof document !== 'undefined' && accessToken) {
const domain = new URL(process.env.REST_URL || 'https://rest.opencollective.com').hostname;
document.cookie =
env === 'development' || env === 'e2e'
? `authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120`
: // It is not possible to use HttpOnly when setting from JavaScript.
// I'm enforcing SameSite and Domain in production to prevent CSRF.
`authorization="Bearer ${accessToken}";path=/;SameSite=strict;max-age=120;domain=${domain};secure`;
}
}

export function getTokenFromCookie(req: Express.Request) {
return req?.cookies?.accessTokenPayload && req?.cookies?.accessTokenSignature
? [req.cookies.accessTokenPayload, req.cookies.accessTokenSignature].join('.')
Expand Down

0 comments on commit bd0ab62

Please sign in to comment.