Skip to content

Instantly share code, notes, and snippets.

@admwrd
Forked from maxkostinevich/worker.js
Last active August 5, 2020 10:36
Show Gist options
  • Save admwrd/0f6084857791bf46a778e7b69cd25c93 to your computer and use it in GitHub Desktop.
Save admwrd/0f6084857791bf46a778e7b69cd25c93 to your computer and use it in GitHub Desktop.
Serverless Geolocation Service
/*
* Serverless Geolocation via Cloudflare Workers.
*
* Idea originally from blog https://maxkostinevich.com/blog/serverless-geolocation
*
* Tested and working on deployed Cloudflare worker.
*
* Code Authors, Contact and Ownership/License
* 1. Marius. (https://gist.github.com/maephisto/9228207) © 2014. License Unknown.
* 2. Max Kostinevich. (https://maxkostinevich.com) © 2020. License Unknown.
* 3. AdmWrd. (https://github.com/admwrd) No copyright / No attribution required. BSD 3 Clause / MIT License.
*/
/*
Code primarily by Author 1.
Changes by Author 3:
* adding 'KP' (North Korea)
* updating 'KR' to refer to 'South Korea', rather than just 'Korea'
*/
const isoCountries = {
'AD': 'Andorra',
'AE': 'United Arab Emirates',
'AF': 'Afghanistan',
'AG': 'Antigua And Barbuda',
'AI': 'Anguilla',
'AL': 'Albania',
'AM': 'Armenia',
'AN': 'Netherlands Antilles',
'AO': 'Angola',
'AQ': 'Antarctica',
'AR': 'Argentina',
'AS': 'American Samoa',
'AT': 'Austria',
'AU': 'Australia',
'AW': 'Aruba',
'AX': 'Aland Islands',
'AZ': 'Azerbaijan',
'BA': 'Bosnia And Herzegovina',
'BB': 'Barbados',
'BD': 'Bangladesh',
'BE': 'Belgium',
'BF': 'Burkina Faso',
'BG': 'Bulgaria',
'BH': 'Bahrain',
'BI': 'Burundi',
'BJ': 'Benin',
'BL': 'Saint Barthelemy',
'BM': 'Bermuda',
'BN': 'Brunei Darussalam',
'BO': 'Bolivia',
'BR': 'Brazil',
'BS': 'Bahamas',
'BT': 'Bhutan',
'BV': 'Bouvet Island',
'BW': 'Botswana',
'BY': 'Belarus',
'BZ': 'Belize',
'CA': 'Canada',
'CC': 'Cocos (Keeling) Islands',
'CD': 'Congo, Democratic Republic',
'CF': 'Central African Republic',
'CG': 'Congo',
'CH': 'Switzerland',
'CI': 'Cote D\'Ivoire',
'CK': 'Cook Islands',
'CL': 'Chile',
'CM': 'Cameroon',
'CN': 'China',
'CO': 'Colombia',
'CR': 'Costa Rica',
'CU': 'Cuba',
'CV': 'Cape Verde',
'CX': 'Christmas Island',
'CY': 'Cyprus',
'CZ': 'Czech Republic',
'DE': 'Germany',
'DJ': 'Djibouti',
'DK': 'Denmark',
'DM': 'Dominica',
'DO': 'Dominican Republic',
'DZ': 'Algeria',
'EC': 'Ecuador',
'EE': 'Estonia',
'EG': 'Egypt',
'EH': 'Western Sahara',
'ER': 'Eritrea',
'ES': 'Spain',
'ET': 'Ethiopia',
'FI': 'Finland',
'FJ': 'Fiji',
'FK': 'Falkland Islands (Malvinas)',
'FM': 'Micronesia, Federated States Of',
'FO': 'Faroe Islands',
'FR': 'France',
'GA': 'Gabon',
'GB': 'United Kingdom',
'GD': 'Grenada',
'GE': 'Georgia',
'GF': 'French Guiana',
'GG': 'Guernsey',
'GH': 'Ghana',
'GI': 'Gibraltar',
'GL': 'Greenland',
'GM': 'Gambia',
'GN': 'Guinea',
'GP': 'Guadeloupe',
'GQ': 'Equatorial Guinea',
'GR': 'Greece',
'GS': 'South Georgia And Sandwich Isl.',
'GT': 'Guatemala',
'GU': 'Guam',
'GW': 'Guinea-Bissau',
'GY': 'Guyana',
'HK': 'Hong Kong',
'HM': 'Heard Island & Mcdonald Islands',
'HN': 'Honduras',
'HR': 'Croatia',
'HT': 'Haiti',
'HU': 'Hungary',
'ID': 'Indonesia',
'IE': 'Ireland',
'IL': 'Israel',
'IM': 'Isle Of Man',
'IN': 'India',
'IO': 'British Indian Ocean Territory',
'IQ': 'Iraq',
'IR': 'Iran, Islamic Republic Of',
'IS': 'Iceland',
'IT': 'Italy',
'JE': 'Jersey',
'JM': 'Jamaica',
'JO': 'Jordan',
'JP': 'Japan',
'KE': 'Kenya',
'KG': 'Kyrgyzstan',
'KH': 'Cambodia',
'KI': 'Kiribati',
'KM': 'Comoros',
'KN': 'Saint Kitts And Nevis',
'KP': 'North Korea',
'KR': 'South Korea',
'KW': 'Kuwait',
'KY': 'Cayman Islands',
'KZ': 'Kazakhstan',
'LA': 'Lao People\'s Democratic Republic',
'LB': 'Lebanon',
'LC': 'Saint Lucia',
'LI': 'Liechtenstein',
'LK': 'Sri Lanka',
'LR': 'Liberia',
'LS': 'Lesotho',
'LT': 'Lithuania',
'LU': 'Luxembourg',
'LV': 'Latvia',
'LY': 'Libyan Arab Jamahiriya',
'MA': 'Morocco',
'MC': 'Monaco',
'MD': 'Moldova',
'ME': 'Montenegro',
'MF': 'Saint Martin',
'MG': 'Madagascar',
'MH': 'Marshall Islands',
'MK': 'Macedonia',
'ML': 'Mali',
'MM': 'Myanmar',
'MN': 'Mongolia',
'MO': 'Macao',
'MP': 'Northern Mariana Islands',
'MQ': 'Martinique',
'MR': 'Mauritania',
'MS': 'Montserrat',
'MT': 'Malta',
'MU': 'Mauritius',
'MV': 'Maldives',
'MW': 'Malawi',
'MX': 'Mexico',
'MY': 'Malaysia',
'MZ': 'Mozambique',
'NA': 'Namibia',
'NC': 'New Caledonia',
'NE': 'Niger',
'NF': 'Norfolk Island',
'NG': 'Nigeria',
'NI': 'Nicaragua',
'NL': 'Netherlands',
'NO': 'Norway',
'NP': 'Nepal',
'NR': 'Nauru',
'NU': 'Niue',
'NZ': 'New Zealand',
'OM': 'Oman',
'PA': 'Panama',
'PE': 'Peru',
'PF': 'French Polynesia',
'PG': 'Papua New Guinea',
'PH': 'Philippines',
'PK': 'Pakistan',
'PL': 'Poland',
'PM': 'Saint Pierre And Miquelon',
'PN': 'Pitcairn',
'PR': 'Puerto Rico',
'PS': 'Palestinian Territory, Occupied',
'PT': 'Portugal',
'PW': 'Palau',
'PY': 'Paraguay',
'QA': 'Qatar',
'RE': 'Reunion',
'RO': 'Romania',
'RS': 'Serbia',
'RU': 'Russian Federation',
'RW': 'Rwanda',
'SA': 'Saudi Arabia',
'SB': 'Solomon Islands',
'SC': 'Seychelles',
'SD': 'Sudan',
'SE': 'Sweden',
'SG': 'Singapore',
'SH': 'Saint Helena',
'SI': 'Slovenia',
'SJ': 'Svalbard And Jan Mayen',
'SK': 'Slovakia',
'SL': 'Sierra Leone',
'SM': 'San Marino',
'SN': 'Senegal',
'SO': 'Somalia',
'SR': 'Suriname',
'ST': 'Sao Tome And Principe',
'SV': 'El Salvador',
'SY': 'Syrian Arab Republic',
'SZ': 'Swaziland',
'TC': 'Turks And Caicos Islands',
'TD': 'Chad',
'TF': 'French Southern Territories',
'TG': 'Togo',
'TH': 'Thailand',
'TJ': 'Tajikistan',
'TK': 'Tokelau',
'TL': 'Timor-Leste',
'TM': 'Turkmenistan',
'TN': 'Tunisia',
'TO': 'Tonga',
'TR': 'Turkey',
'TT': 'Trinidad And Tobago',
'TV': 'Tuvalu',
'TW': 'Taiwan',
'TZ': 'Tanzania',
'UA': 'Ukraine',
'UG': 'Uganda',
'UM': 'United States Outlying Islands',
'US': 'United States',
'UY': 'Uruguay',
'UZ': 'Uzbekistan',
'VA': 'Holy See (Vatican City State)',
'VC': 'Saint Vincent And Grenadines',
'VE': 'Venezuela',
'VG': 'Virgin Islands, British',
'VI': 'Virgin Islands, U.S.',
'VN': 'Viet Nam',
'VU': 'Vanuatu',
'WF': 'Wallis And Futuna',
'WS': 'Samoa',
'YE': 'Yemen',
'YT': 'Mayotte',
'ZA': 'South Africa',
'ZM': 'Zambia',
'ZW': 'Zimbabwe'
};
// Code originally by Author 2.
// License for changes by Author 3.
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3 Clause
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat (MIT) License
/**
* Return the full name of a country when given the ISO 3166-2 code.
* If the code is not found, returns 'Unknown' with an error about the code.
*
*/
const getCountryName = (countryCode) => {
countryCode = countryCode.toUpperCase();
if (isoCountries.hasOwnProperty(countryCode)) {
return isoCountries[countryCode];
} else {
return "Unknown. Could not find country for code " + countryCode;
}
}
// @license-end
// Code originally by Author 2.
// License for changes by Author 3.
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3 Clause
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat (MIT) License
/**
* Creates a Response that contains either a JSON object or a primitive type.
* This defaults to returning with a 200 OK Status, but can be overridden.
*
* @param message
* @param status
* @return {Response}
* @constructor
*/
const JSONResponse = (message, status = 200) => {
status = status > 99 && status < 600 ? status : 200;
let headers = {
headers: {
"content-type": "application/json;charset=UTF-8",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type"
},
status: status
};
if (typeof message === 'string') {
return new Response(JSON.stringify({message: message}), headers);
} else {
return new Response(JSON.stringify(message), headers);
}
};
// @license-end
// Code by Author 2.
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type"
};
// Code by Author 2.
/**
* Returns information on endpoint when met with an OPTION method.
*
* @param request
* @return {Response}
*/
function handleOptions(request) {
if (
request.headers.get("Origin") !== null &&
request.headers.get("Access-Control-Request-Method") !== null &&
request.headers.get("Access-Control-Request-Headers") !== null
) {
// Handle CORS pre-flight request.
return new Response(null, {
headers: corsHeaders
});
} else {
// Handle standard OPTIONS request.
return new Response(null, {
headers: {
Allow: "GET, HEAD, POST, OPTIONS"
}
});
}
}
// Code originally by Author 2.
// License for changes by Author 3.
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3 Clause
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat (MIT) License
/**
* Respond to the Request
*
* @param request
* @return {Promise<Response>}
*/
async function handleRequest(request) {
console.log("We have " + JSON.stringify(request))
try {
const ip = request.headers.get('cf-connecting-ip');
if (typeof request.cf === 'undefined' || typeof request.cf.country === 'undefined' || request.cf.country.trim() === '') {
return JSONResponse("Bad Request. You must supply a value for country code.", 400);
}
const countryCode = request.cf.country.trim();
const country = getCountryName(countryCode);
return JSONResponse({message: 'success', ip, country: {code: countryCode, name: country}});
} catch (err) {
console.log("Error! " + err);
return JSONResponse("Oops! Something went wrong.", 500);
}
}
// @license-end
// Code originally by Author 2.
// License for changes by Author 3.
// @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3 Clause
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat (MIT) License
/**
* Sets up an Event Listener depending on what HTTP Method is being requested.
*/
addEventListener('fetch', event => {
switch (event.request.method.toUpperCase()) {
case "OPTIONS":
event.respondWith(handleOptions(event.request));
break;
default:
event.respondWith(handleRequest(event.request));
}
});
// @license-end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment