From 6ab7bbab61d77e9324f51855613c9c67d43d0d6d Mon Sep 17 00:00:00 2001 From: Aaron Parecki Date: Sat, 4 Jun 2022 09:47:03 -0700 Subject: [PATCH] lock down fetching external icons or tile URLs to authenticated requests for #8 --- .gitignore | 1 + controllers/main.php | 2 +- data/static-maps.md | 9 +++++++++ lib/helpers.php | 16 ++++++++++++++++ p3k/geo/StaticMap.php | 21 +++++++++++---------- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index b7570c0..25fe40b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ vendor/ lib/config.php data/airports.csv +data/apikeys.txt diff --git a/controllers/main.php b/controllers/main.php index 4661ffe..84860ec 100644 --- a/controllers/main.php +++ b/controllers/main.php @@ -17,5 +17,5 @@ $app->map('/map/img', function() use($app) { $params = $app->request()->params(); $app->response['Content-type'] = 'image/png'; $assetPath = dirname(__FILE__) . '/../public/map-images'; - $map = p3k\geo\StaticMap\generate($params, null, $assetPath); + $map = p3k\geo\StaticMap\generate($params, null, $assetPath, is_authenticated($params)); })->via('GET','POST'); diff --git a/data/static-maps.md b/data/static-maps.md index a46eece..d9d6320 100644 --- a/data/static-maps.md +++ b/data/static-maps.md @@ -40,6 +40,7 @@ Parameters can be included in either the query string or in the POST body. * `location` - optional - Free-form text that will be geocoded to center the map. Not needed if specifying a location with the latitude and longitude parameters, or if a marker is specified. * `marker[]` - Specify one or more markers to overlay on the map. Parameters are specified as: `key:value;`. See below for the full list of parameters. * `path[]` - Specify one or more paths to draw on the map. See below for the full list of parameters to draw a path. +* `token` - To use external icons or tile URLs, provide an API key in the request. See below for documentation on configuring this. ## Markers @@ -110,6 +111,14 @@ Parameters can be included in either the query string or in the POST body. * ![small-yellow-cutout](map-images/small-yellow-cutout.png) `small-yellow-cutout` * ![small-yellow-user](map-images/small-yellow-user.png) `small-yellow-user` + +## Authentication + +To be able to use externally-referenced icons or tile URLs, you will need to configure API keys and provide a token in the request. This locks down the ability to fetch external resources to only trusted users of the system. + +Create a file `data/apikeys.txt` and generate a random string with a tool of your choosing, and with one API key per line. Any value passed in the parameter `token` that matches the text in a line in this file will enable the request to use the restricted features that reference external URLs. + + ## Paths A path is specified as a list of longitude and latitudes, as well as optional properties to specify the weight and color of the path. diff --git a/lib/helpers.php b/lib/helpers.php index 4aad534..a18ddf1 100644 --- a/lib/helpers.php +++ b/lib/helpers.php @@ -24,3 +24,19 @@ function k($a, $k, $default=null) { } } +function is_authenticated($params) { + if(!isset($params['token'])) + return false; + + $token_file = __DIR__.'/../data/apikeys.txt'; + + if(!file_exists($token_file)) + return false; + + $valid_tokens = array_filter(file($token_file)); + + if(in_array($params['token'], $valid_tokens)) + return true; + + return false; +} diff --git a/p3k/geo/StaticMap.php b/p3k/geo/StaticMap.php index 3ca4621..fb5d378 100644 --- a/p3k/geo/StaticMap.php +++ b/p3k/geo/StaticMap.php @@ -3,7 +3,7 @@ namespace p3k\geo\StaticMap; use p3k\geo\WebMercator, p3k\Geocoder; use Imagick, ImagickPixel, ImagickDraw; -function generate($params, $filename, $assetPath) { +function generate($params, $filename, $assetPath, $is_authenticated=false) { $bounds = array( 'minLat' => 90, @@ -46,14 +46,15 @@ function generate($params, $filename, $assetPath) { } if(preg_match('/https?:\/\/(.+)/', $properties['icon'], $match)) { - // Looks like an external image, attempt to download it - $ch = curl_init($properties['icon']); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); - $img = curl_exec($ch); - $properties['iconImg'] = @imagecreatefromstring($img); - if(!$properties['iconImg']) { - $properties['iconImg'] = false; + $properties['iconImg'] = false; + // Only allow external referenced icons from authenticated requests + if($is_authenticated) { + // Looks like an external image, attempt to download it + $ch = curl_init($properties['icon']); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + $img = curl_exec($ch); + $properties['iconImg'] = @imagecreatefromstring($img); } } else { $properties['iconImg'] = imagecreatefrompng($assetPath . '/' . $properties['icon'] . '.png'); @@ -252,7 +253,7 @@ function generate($params, $filename, $assetPath) { $overlayURL = $tileServices[k($params,'basemap')][1]; else $overlayURL = 0; - } elseif(k($params, 'basemap') == 'custom') { + } elseif(k($params, 'basemap') == 'custom' && $is_authenticated) { $tileURL = $params['tileurl']; $overlayURL = false; } else {