Skip to content

Commit

Permalink
fix: authenticateRequest
Browse files Browse the repository at this point in the history
  • Loading branch information
Betree committed Feb 19, 2024
1 parent 187eb87 commit a904325
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 16 deletions.
6 changes: 4 additions & 2 deletions lib/graphql/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async function fetch(url, options = {}) {
// options.headers['oc-secret'] = process.env.OC_SECRET; // TODO
options.headers['oc-application'] = 'pdf';
options.headers['user-agent'] = 'opencollective-pdf/1.0 node-fetch/1.0';

console.log('FETCH', url, options);

Check warning on line 30 in lib/graphql/index.js

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
const result = await nodeFetch(url, options);

return result;
Expand All @@ -50,14 +50,16 @@ function getCustomAgent() {
export const createClient = (authorizationHeaders) => {
const authLink = setContext((_, { headers }) => {
const newHeaders = { ...headers, ...authorizationHeaders };
console.log({ headers, newHeaders });

Check warning on line 53 in lib/graphql/index.js

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
return { headers: newHeaders };
});

console.log('URI:', getGraphqlUrl('v2'));

Check warning on line 57 in lib/graphql/index.js

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
const apiLink = new HttpLink({ uri: getGraphqlUrl('v2'), fetch });
return new ApolloClient({
connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
link: ApolloLink.from([authLink, apiLink]),
link: authLink.concat(apiLink),
cache: new InMemoryCache({
// Documentation:
// https://www.apollographql.com/docs/react/data/fragments/#using-fragments-with-unions-and-interfaces
Expand Down
11 changes: 8 additions & 3 deletions lib/graphql/queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,14 @@ export async function fetchTransactionInvoice(transactionId, authorizationHeader
variables: { transactionId },
fetchPolicy: 'no-cache',
});
} catch (e) {
console.error('Query Error', JSON.stringify(e, null, 2));
throw e;
} catch (error) {
console.error(

Check warning on line 238 in lib/graphql/queries.js

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
'Query Error',
JSON.stringify({
response,
}),
);
throw error;
}

if (!response.data.transaction) {
Expand Down
20 changes: 9 additions & 11 deletions lib/req-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ import { get, isEmpty } from 'lodash';
* To forward API Key or Authorization headers from the request to the API calls.
* Returns `null` if no headers are found.
*/
export const getAuthorizationHeadersFromReq = (req) => {
const getAuthorizationHeadersFromReq = (req) => {
const { headers, query } = req;
const result = {};
const apiKey = get(headers, 'api-key') || get(query, 'apiKey');
const personalToken = get(headers, 'personal-token') || get(query, 'personalToken') || get(query, 'app_key');
const authorization = get(headers, 'authorization') || req.cookies?.authorization;
const authorization = get(headers, 'authorization');
if (authorization) {
const parts = authorization.split(' ');
const scheme = parts[0];
const accessToken = parts[1];
if (!/^Bearer$/i.test(scheme) || !accessToken) {
const [scheme, accessToken] = authorization.split(' ');
if (scheme !== 'Bearer' || !accessToken) {
throw new Error('Invalid authorization header. Format should be: Authorization: Bearer [token]');
}

Expand All @@ -29,19 +27,19 @@ export const getAuthorizationHeadersFromReq = (req) => {
result['Personal-Token'] = personalToken;
}

return isEmpty(headers) ? null : headers;
return isEmpty(headers) ? null : result;
};

/**
* Some syntax sugar around the `getAuthorizationHeadersFromReq` function, that throws for non-authenticated requests
* but allows `OPTIONS` requests to pass through
*/
export const authenticateRequest = (ctx) => {
const authorizationHeaders = getAuthorizationHeadersFromReq(ctx);
export const authenticateRequest = (req) => {
const authorizationHeaders = getAuthorizationHeadersFromReq(req);
if (!authorizationHeaders) {
// Frontend sends an OPTIONS request to check CORS, we should just return OK when that happens
if (ctx.req.method === 'OPTIONS') {
return {};
if (req.method === 'OPTIONS') {
return null;
} else {
throw new Error('Please provide an access token or an APP key');
}
Expand Down
4 changes: 4 additions & 0 deletions pages/expense/[id]/[filename].js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ class TransactionReceipt extends React.Component {
if (isServer) {
const { id } = ctx.query;
const authorizationHeaders = authenticateRequest(ctx.req);
if (!authorizationHeaders) {
return {};
}

const expense = await fetchExpenseInvoiceData(id, authorizationHeaders);
return { expense, pageFormat: ctx.query.pageFormat };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ class TransactionReceipt extends React.Component {
if (isServer) {
const { fromCollectiveSlug, toCollectiveSlug: hostSlug, isoStartDate: dateFrom, isoEndDate: dateTo } = ctx.query;
const authorizationHeaders = authenticateRequest(ctx.req);
if (!authorizationHeaders) {
return {};
}

const queryParams = { fromCollectiveSlug, hostSlug, dateFrom, dateTo };
const response = await fetchInvoiceByDateRange(queryParams, authorizationHeaders);

Expand Down
4 changes: 4 additions & 0 deletions pages/receipts/transactions/[id]/[filename].js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ class TransactionReceipt extends React.Component {
if (isServer) {
const { id, pageFormat } = ctx.query;
const authorizationHeaders = authenticateRequest(ctx.req);
if (!authorizationHeaders) {
return {};
}

const transaction = await fetchTransactionInvoice(id, authorizationHeaders);
return {
pageFormat: pageFormat,
Expand Down

0 comments on commit a904325

Please sign in to comment.