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

Extended Static-Images Endpoint #619

Merged
merged 4 commits into from
Oct 28, 2022

Conversation

benedikt-brandtner-bikemap
Copy link
Contributor

@benedikt-brandtner-bikemap benedikt-brandtner-bikemap commented Sep 29, 2022

I have Extended the Static-Images Endpoint with the following capabilities:

Additional Changes:

  • In order to keep performance drawing of elements has been refactored to be asynchronous
  • Refactored a lot of helpers in serve_rendered.js to be more modular and reusable

Please let me know if this would be interesting to you.

Cheers :)

Copy link
Contributor

@mnutt mnutt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this contribution! I'll be looking through it more thoroughly but wanted to leave a few initial comments.

Dockerfile_test Outdated
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN curl http://archive.ubuntu.com/ubuntu/pool/main/libj/libjpeg-turbo/libjpeg-turbo8_2.0.3-0ubuntu1_amd64.deb --output libjpeg-turbo8_2.0.3-0ubuntu1_amd64.deb
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason we need to download this manually vs apt-getting it? Is it a versioning thing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like mablibre-gl depends on a version of libjpeg-turbo with legacy-capabilities enabled for version 8 which doesn't seem to be available in the current apt repository and also a libicu version which is not in the repository.

But for Dockerfile_test i just copied the packages from Dockerfile

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have removed the commit which edited Dockerfile_test to resolve conflicts


* e.g. ``0.5`` - Scales the image to half it's original size

* ``offset`` - Image offset as positive or negative pixel value in format ``[offsetX],[offsetY]``
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not opposed to this by any means, but have you considered just requiring that all markers be centered both horizontally and vertically on the coordinates? IMO it makes it really easy to get placement right when designing icons, and works really well with scaling, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Check if icon is served via http otherwise marker icons are expected to
// be provided as filepaths relative to configured icon path
if (!(iconURI.startsWith('http://') || iconURI.startsWith('https://'))) {
iconURI = path.resolve(options.paths.icons, iconURI);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this would let someone specify a relative path that broke out of the icons dir and could pull from anywhere in the system. Maybe extract a function that checks that iconURI.startsWith(options.paths.icons)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should definitely try to sanitize the input here. I would like to propose something like this: acalcutt@64cad7d

Not sure if we might need to be stricter and catch even more?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have added the path sanitation with sanitize-filename

if (!(iconURI.startsWith('http://') || iconURI.startsWith('https://'))) {
iconURI = path.resolve(options.paths.icons, iconURI);
// Ensure icon exists at provided path
if (!fs.existsSync(iconURI)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We likely want to see if we can somehow avoid existsSync since it's in the request path. One way would be on startup to just synchronously pull a list of images in the icons dir, put them in an object, and retrieve their full paths here. It'd also solve the above issue around limiting the paths to the icons dir.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all icons are now loaded into a settings object on server startup and the provided icon is checked against this list

Copy link
Contributor

@boldtrn boldtrn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for this great PR @benedikt-brandtner-bikemap. The features are really awesome 👍 .

I personally think that we should add a bit of security logic to this PR. Maybe we could make requesting external images configureable. For example if this is a public server, a malicious user might host a https:// image somewhere and get the server to download this. At the very least it might be possible to force the server to download huge files and essentially DDOS the server.

The same applies to the file name, in theory a malicious user could request some sensitive files and draw them on the map or in the worst case might even run some code injection.

WDYT?

@mnutt
Copy link
Contributor

mnutt commented Oct 3, 2022

There's also the tricky concept of SSRF--allowing a server to take instruction to download any URL means it can fetch internal resources that the server has access to (ec2 instances often have access to sensitive metadata on localhost, etc) and it's not very easy to set up rules to prevent it.

Realistically, siphoning internal resources through embedded markers is probably pretty difficult but would still potentially allow someone to prod around. I think it'd probably be best to leave the remote feature disabled by default, and let people enable it knowing the security implications.

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 3, 2022

Should this use a similar syntax to maptilers other products, like https://documentation.maptiler.com/hc/en-us/articles/360020805897-Static-maps-for-your-web . Seems like they support icon urls

@benedikt-brandtner-bikemap
Copy link
Contributor Author

Hey, thanks a lot for all for you responses unfortunately i got sick over the weekend and wasn't able to respond sooner 🙁

Will have a look right now and push my proposed changes to address the issues asap!

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 4, 2022

Hope you are feeling better @benedikt-brandtner-bikemap . No rush here.

@benedikt-brandtner-bikemap
Copy link
Contributor Author

thanks a lot, but yeah am bored anyways so this is a welcome distraction 🙂

Have implemented the following fixes to address the mentioned issues:

  1. Loading of remote images must now be allowed via the configuration parameter allowRemoteMarkerIcons
  2. Locally available icons get loaded as relative paths to the icon-folder into the settings object paths.availableIcons on server startup (thanks a lot for the idea @mnutt)
  3. When providing a local icon as a marker, the path gets sanitized first and then checked against the paths.availableIcons settings object if the icon exists and is allowed to be used

I think these measures should remedy a lot of the security concerns mentioned, although you are correct as soon as the icons get fetched from a remote server we are still exposed.

…hing of remote marker icons only when option is set to true;

asynchronously load all available icons in a settings object on server startup;
replaced fs.existsSync() call in serve_rendered when drawing marker icons with a check against available icons settings object;
@benedikt-brandtner-bikemap
Copy link
Contributor Author

Have rebased my changes ontop of current master to resolve conflicts in Dockerfile_test

return files.flat();
}

// Load all available icons into a settings object
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great idea 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, did the implementation but credit goes to @mnutt fir the idea!

@boldtrn
Copy link
Contributor

boldtrn commented Oct 6, 2022

I think these measures should remedy a lot of the security concerns mentioned, although you are correct as soon as the icons get fetched from a remote server we are still exposed.

Thanks a lot for the changes. At least from my side, this solves the concerns I had and I am looking forward to using this 👍

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 7, 2022

How do you use linecap?

@benedikt-brandtner-bikemap
Copy link
Contributor Author

Hey, awesome that you approve of my changes if i should add/change anything else i'll be happy to do so!

@acalcutt I use linecap in the drawing context of the path if one is provided to define the rendering-style of the start- and end-points of the line as described here
implementation

Also you can find documentation for the new staticmap endpoint parameters (including markers) here

added linejoin parameter to staticmaps endpoint;
@benedikt-brandtner-bikemap
Copy link
Contributor Author

Have updated documentation for the linecap parameter and also added a linejoin parameter as well to be able to alter the rendering style of overlapping segments as described here

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 7, 2022

Based on the docs and links, shouldn't this give me squared off line endings?

http://192.168.0.251:8080/styles/test-style/static/auto/800x600.png?&path=5.9,45.3|5.7,45.2&linecap=square
800x600 (3)

@benedikt-brandtner-bikemap
Copy link
Contributor Author

benedikt-brandtner-bikemap commented Oct 7, 2022

Seems to work maybe you just cant see it because the width is too thin

default (butt):
http://127.0.0.1:8080/styles/bikemap-2021-3D/static/auto/800x600.png?width=10&path=16.370079517364502,48.2174529909167|16.3616681098938,48.21362115453811
default

square:
http://127.0.0.1:8080/styles/bikemap-2021-3D/static/auto/800x600.png?width=10&linecap=square&path=16.370079517364502,48.2174529909167|16.3616681098938,48.21362115453811
square

round:
http://127.0.0.1:8080/styles/bikemap-2021-3D/static/auto/800x600.png?width=10&linecap=round&path=16.370079517364502,48.2174529909167|16.3616681098938,48.21362115453811
round

Also i've added the capability to draw multiple paths, which i wanted to do when i initially wrote the extensions but which came up again now.

sorry for extending the scope of this PR but it was only a minor change on top

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 7, 2022

Your right, it does work. i guess I expected more of a square at the ends. looks good.

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 8, 2022

@mnutt and @boldtrn Any other things you would like to see before this is merged. it seems like most of the complaints have been fixed and it seems to work pretty well. I'd approve it and merge it in.

the only thing I wish we had was a default marker icon in our test style...but I think that would be something I would have to add to the old release zip file we use.

@boldtrn
Copy link
Contributor

boldtrn commented Oct 8, 2022

Default Marker would be nice indeed. So far I think this PR seems nice and I'd love to start using it.

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 15, 2022

I've been thinking a bit about the use case where you give tileserver a mbtiles file but do not give it a config. In that case it uses the built in style in '/node_modules/tileserver-gl-styles/' and generates it's own config, so it makes it somewhat hard to add the marker icons unless you add your own config.

I was thinking, what if we put some default marker images in 'public/resources/icons/' and in main.js add that icon path to the default generated config like this around line 125

      const styleDir = path.resolve(__dirname, '../node_modules/tileserver-gl-styles/');
      const iconDir = path.resolve(__dirname, 'public/resources/icons/');

      const config = {
        'options': {
          'paths': {
            'root': styleDir,
            'fonts': 'fonts',
            'icons': iconDir,
            'styles': 'styles',
            'mbtiles': path.dirname(mbtilesFile)
          }
        },
        'styles': {},
        'data': {}
      };

I think one side benifit of having the icons in the public folder is you could also use them in your vector maps, like https://maplibre.org/maplibre-gl-js-docs/example/add-image/

@acalcutt
Copy link
Collaborator

maybe something CC0 licensed for a default icon, like https://uxwing.com/map-pin-icon/

@acalcutt
Copy link
Collaborator

I was also thinking I wonder if the icons should be more like sprites so you could use a single image like https://github.com/sigma-geosistemas/Leaflet.awesome-markers/blob/master/dist/images/markers-matte.png with multiple colors in one file.

Not sure its needed to merge this, I was just wondering if that would be better. it seems like sprites are very similar to markers.

@mnutt
Copy link
Contributor

mnutt commented Oct 16, 2022

I've looked over it and am good with it.

Regarding default markers: for what it's worth my old branch has a default marker that can be colorized based on a hex code:

https://github.com/mnutt/tileserver-gl/blob/master/src/markers/color.js

The 'template' uses solid red as the replacement color, and will dynamically generate PNGs of other colors.

@acalcutt
Copy link
Collaborator

I've looked over it and am good with it.

Regarding default markers: for what it's worth my old branch has a default marker that can be colorized based on a hex code:

https://github.com/mnutt/tileserver-gl/blob/master/src/markers/color.js

The 'template' uses solid red as the replacement color, and will dynamically generate PNGs of other colors.

That is a really nice feature.

@benedikt-brandtner-bikemap
Copy link
Contributor Author

Sorry for not beeing more active was focused on other tasks..

Is there anything I can do?

greets

@acalcutt
Copy link
Collaborator

acalcutt commented Oct 20, 2022

What did you think of #619 (comment) , adding a default icon path and maybe a default, open license, icon.

Copy link
Collaborator

@acalcutt acalcutt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. I still would like to see a default marker included, just so this can be used out of the box with the built in styles (like when just loading a mbtiles file with no config). then we could also use that default marker name in the documentation.

@benedikt-brandtner-bikemap
Copy link
Contributor Author

Hey, sorry for not answering sooner was again occupied with something else...

Hmm I could implement a default marker with a choosable color utilizing @mnutt lib but I think I'll only have time end of next week so maybe we merge this PR and I'll open a new one with a default marker?

Greets

@acalcutt
Copy link
Collaborator

that sounds fine to me. I'll merge this.

@acalcutt acalcutt merged commit f3f6349 into maptiler:master Oct 28, 2022
@acalcutt
Copy link
Collaborator

acalcutt commented Oct 28, 2022

EDIT: nevermind, fixed it with #631

Hey @benedikt-brandtner-bikemap ,

I noticed this after I merged, but would it be possible to make a PR that changes

import pkg from 'canvas'; https://github.com/maptiler/tileserver-gl/blob/master/src/serve_rendered.js#L10
to
import {createCanvas, Image} from 'canvas';

and remove the line
const {createCanvas, Image} = pkg; https://github.com/maptiler/tileserver-gl/blob/master/src/serve_rendered.js#L25

@benedikt-brandtner-bikemap
Copy link
Contributor Author

sorry just saw your comment, thanks for fixing this and merging :)!

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.

4 participants