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

first attempt to upgrade express to v5 #1429

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

acalcutt
Copy link
Collaborator

@acalcutt acalcutt commented Dec 29, 2024

Today I was researching how we could fix #1412 and get express upgraded.

The main issue is in newer versions of express the syntax for optional parameters and paths has changed due to their upgrade of https://github.com/pillarjs/path-to-regexp which no longer allows options items by surrounding them with ( and )? . It also doesn't seem to support checking the values/value types by putting the type inside ( and )

https://github.com/pillarjs/path-to-regexp?tab=readme-ov-file#errors

Unexpected ? or +
In past releases, ?, *, and + were used to denote optional or repeating parameters. As an alternative, try these:
For optional (?), use an empty segment in a group such as /:file{.:ext}.
For repeating (+), only wildcard matching is supported, such as /*path.
For optional repeating (*), use a group and a wildcard parameter such as /files{/*path}.
Unexpected (, ), [, ], etc.
Previous versions of Path-to-RegExp used these for RegExp features. This version no longer supports them so they've been reserved to avoid ambiguity. To use these characters literally, escape them with a backslash, e.g. "\\(".

Unfortunately we used a lot of these features to direct how tileserver replied to requests.... Things like optional paths for rile size or raw co-ordinates. or validating the data types before picking up the request.

I went through and I tried to remove all parenthesis that it did now like, but this caused a bit of trouble because now some of our paths are a bit to similar. to support the paths we have a had to do a few ugly workarounds to get around misrouting. They do allow {/:variable} for optional paths, so I was somewhat rework some things to use that.

This still needs a lot of work and if anyone has any suggestions (or would like open a new PR based on it and finish it) I can use all the help I can get with this.

return res.send(concatenated);
} catch (err) {
console.error('Error serving font:', err);
return res.status(400).header('Content-Type', 'text/plain').send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
src/serve_rendered.js Fixed Show fixed Hide fixed
src/serve_style.js Fixed Show fixed Hide fixed
src/serve_style.js Fixed Show fixed Hide fixed
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
src/serve_style.js Fixed Show fixed Hide fixed
src/serve_style.js Fixed Show fixed Hide fixed
Co-Authored-By: Andrew Calcutt <[email protected]>
*/
function allowedSpriteScales(scale) {
if (!scale) return '';
const match = scale.match(/(\d+)x/);

Check failure

Code scanning / CodeQL

Polynomial regular expression used on uncontrolled data High

This
regular expression
that depends on
a user-provided value
may run slow on strings with many repetitions of '0'.
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
y = ll[1];
}
const staticTypeMatch = staticType.match(staticTypeRegex);
console.log(staticTypeMatch);

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
Log entry depends on a
user-provided value
.
src/serve_style.js Fixed Show fixed Hide fixed
const spriteScale = allowedSpriteScales(scale);
const filename = `${sprite.path}${spriteScale}.${format}`;

fs.readFile(filename, (err, data) => {

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.

fs.readFile(filename, (err, data) => {
if (err) {
console.error('Sprite load error: %s, Error: %s', filename, err);

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
if (!allowedFonts || (allowedFonts[name] && fallbacks)) {
if (!name || typeof name !== 'string' || name.trim() === '') {
console.error('ERROR: Invalid font name: %s', name);

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
return reject('Invalid font name');
}
if (!/^\d+-\d+$/.test(range)) {
console.error('ERROR: Invalid range: %s', range);

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
fs.readFile(filename, (err, data) => {
if (err) {
console.error(`ERROR: Font not found: ${name}`);
console.error('ERROR: Font not found: %s, Error: %s', filename, err);

Check warning

Code scanning / CodeQL

Log injection Medium

Log entry depends on a
user-provided value
.
Co-Authored-By: Andrew Calcutt <[email protected]>
Co-Authored-By: Andrew Calcutt <[email protected]>
Comment on lines +66 to +96
app.get(`/:id/sprite{/:spriteID}{@:scale}{.:format}`, (req, res, next) => {
const { spriteID = 'default', id, format } = req.params;
const spriteScale = allowedSpriteScales(req.params.scale);

const item = repo[id];
if (!item || !allowedSpriteFormats(format)) {
return res.sendStatus(404);
}

const sprite = item.spritePaths.find((sprite) => sprite.id === spriteID);
if (!sprite) {
return res.status(400).send('Bad Sprite ID or Scale');
}

const filename = `${sprite.path}${spriteScale}.${format}`;

// eslint-disable-next-line security/detect-non-literal-fs-filename
fs.readFile(filename, (err, data) => {
if (err) {
console.error('Sprite load error: %s, Error: %s', filename, err);
return res.sendStatus(404);
}
},
);

if (format === 'json') {
res.header('Content-type', 'application/json');
} else if (format === 'png') {
res.header('Content-type', 'image/png');
}
return res.send(data);
});
});

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a file system access
, but is not rate-limited.
if (format === 'pbf') {
if (isGzipped) {
response.data = await gunzipP(response.data);
isGzipped = false;

Check warning

Code scanning / CodeQL

Useless assignment to local variable Warning

The value assigned to isGzipped here is unused.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Security Vulnerabilities - Request to update express version from 4.19.2 to 4.21.1
1 participant