Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSRF token: handle failed url-decoding #1265

Merged
merged 5 commits into from
Nov 9, 2024

Conversation

@matthew-white
Copy link
Member

My feeling overall when looking at these PRs is that the try/catch blocks make the main logic slightly harder to follow. Is there an alternative to try/catch that we could consider? How about a function that returns something like null or Option.none() if the string can't be decoded? Something like:

const tryDecodeURI = (s) => {
  try {
    return decodeURIComponent(s);
  } catch (error) {
    return null;
  }
};

or

const tryDecodeURI = (s) => {
  try {
    return Option.of(decodeURIComponent(s));
  } catch (error) {
    return Option.none();
  }
};

I think a function like this could reduce the number of nested blocks or otherwise enable us to structure the code in a different way from what try/catch requires.

@alxndrsn
Copy link
Contributor Author

alxndrsn commented Nov 7, 2024

Is there an alternative to try/catch that we could consider? How about a function that returns something like null or Option.none() if the string can't be decoded?

How would this work for something like #1270:

// Given an OData URL subpath, returns a contextStack: [ [ pathName: String, tableId: String? ] ]
// that the subpath represents.
const extractPathContext = (subpath) => {
  const rawParts = subpath.split('/').slice(1);
  let parts;
  try {
    parts = rawParts.map(part => decodeURIComponent(part));
  } catch (err) {
    throw Problem.user.unparseableODataExpression({ reason: 'URL-decoding failed' });
  }
  return parts.map((part) => {
    const match = /^([^(]+)\('((?:uuid:)?[a-z0-9-]+)'\)$/i.exec(part);
    return (match == null) ? [ part, null ] : [ match[1], match[2] ];
  });
};

@matthew-white
Copy link
Member

How about something like:

const extractPathContext = (subpath) =>
  subpath.split('/').slice(1).map((part) => {
    const decoded = tryDecodeURI(part);
    if (decoded == null)
      throw Problem.user.unparseableODataExpression({ reason: 'URL-decoding failed' });
    const match = /^([^(]+)\('((?:uuid:)?[a-z0-9-]+)'\)$/i.exec(decoded);
    return (match == null) ? [ part, null ] : [ match[1], match[2] ];
  });

@alxndrsn
Copy link
Contributor Author

alxndrsn commented Nov 7, 2024

@matthew-white looks good; is that preferred to:

const extractPathContext = (subpath) =>
  subpath.split('/').slice(1).map((part) => {
    const decoded = decodeURI(part);
    if (decoded.isEmpty())
      throw Problem.user.unparseableODataExpression({ reason: 'URL-decoding failed' });
    const match = /^([^(]+)\('((?:uuid:)?[a-z0-9-]+)'\)$/i.exec(decoded.get());
    return (match == null) ? [ part, null ] : [ match[1], match[2] ];
  });

?

@matthew-white
Copy link
Member

An approach that uses Option sounds great to me. 👍

lib/util/http.js Outdated Show resolved Hide resolved
@alxndrsn alxndrsn merged commit 9ba21ef into getodk:master Nov 9, 2024
1 check passed
@alxndrsn alxndrsn deleted the handle-uri-decode-failures branch November 9, 2024 06:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants