Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
Whilst working on another tech project, I needed to keep an eye on network traffic coming to my home router. There was more traffic than I expected, so I decided to look into where these were coming from. I took some details and using the site ipinfo.io I found that it was all rather benign and nothing to worry about, but it did make me think about how easy it is to send all over the world.
To find this info out I would normally have to either open up another window and investigate on my laptop (not convenient if I am in the middle of something) or note down numbers for checking later. My Alexa was sat on the side, which made me think, why don't I just ask her?
My personal view on Skills is that they should be small and deal with a single problem or function, so this fitted that bill. So using the Rest API for ipinfo.io and with a bit of help from another open source tool country.io to convert country codes to standard names, I put together a skill to do this.
Feel free to look at the code and process and if you want to take a few bits for working on your own skills, be my guest.
AWS Lambda Function for Alexa
JavaScript'use strict';
var http = require('http');
function buildSpeechletResponseWithCard(title, output, cardOutput, reprompt, shouldEndSession) {
return {
outputSpeech:{
type: 'PlainText',
text: output,
},
card: {
type: 'Simple',
title: title,
content: cardOutput,
},
reprompt: {
outputSpeech: {
type: 'PlainText',
text: reprompt,
},
},
shouldEndSession,
};
}
function buildSpeechletResponse(output, reprompt, shouldEndSession) {
return {
outputSpeech:{
type: 'PlainText',
text: output,
},
reprompt: {
outputSpeech: {
type: 'PlainText',
text: reprompt,
},
},
shouldEndSession,
};
}
function buildResponse(attributes, response) {
return {
version: '1.0',
attributes,
response: response,
};
}
//Json doc for country codes to name from country.io!! Thanks guys!!
function getCountryFromCode(code) {
var countries = JSON.parse("{\"BD\": \"Bangladesh\", \"BE\": \"Belgium\", \"BF\": \"Burkina Faso\", \"BG\": \"Bulgaria\", \"BA\": \"Bosnia and Herzegovina\", \"BB\": \"Barbados\", \"WF\": \"Wallis and Futuna\", \"BL\": \"Saint Barthelemy\", \"BM\": \"Bermuda\", \"BN\": \"Brunei\", \"BO\": \"Bolivia\", \"BH\": \"Bahrain\", \"BI\": \"Burundi\", \"BJ\": \"Benin\", \"BT\": \"Bhutan\", \"JM\": \"Jamaica\", \"BV\": \"Bouvet Island\", \"BW\": \"Botswana\", \"WS\": \"Samoa\", \"BQ\": \"Bonaire, Saint Eustatius and Saba \", \"BR\": \"Brazil\", \"BS\": \"Bahamas\", \"JE\": \"Jersey\", \"BY\": \"Belarus\", \"BZ\": \"Belize\", \"RU\": \"Russia\", \"RW\": \"Rwanda\", \"RS\": \"Serbia\", \"TL\": \"East Timor\", \"RE\": \"Reunion\", \"TM\": \"Turkmenistan\", \"TJ\": \"Tajikistan\", \"RO\": \"Romania\", \"TK\": \"Tokelau\", \"GW\": \"Guinea-Bissau\", \"GU\": \"Guam\", \"GT\": \"Guatemala\", \"GS\": \"South Georgia and the South Sandwich Islands\", \"GR\": \"Greece\", \"GQ\": \"Equatorial Guinea\", \"GP\": \"Guadeloupe\", \"JP\": \"Japan\", \"GY\": \"Guyana\", \"GG\": \"Guernsey\", \"GF\": \"French Guiana\", \"GE\": \"Georgia\", \"GD\": \"Grenada\", \"GB\": \"United Kingdom\", \"GA\": \"Gabon\", \"SV\": \"El Salvador\", \"GN\": \"Guinea\", \"GM\": \"Gambia\", \"GL\": \"Greenland\", \"GI\": \"Gibraltar\", \"GH\": \"Ghana\", \"OM\": \"Oman\", \"TN\": \"Tunisia\", \"JO\": \"Jordan\", \"HR\": \"Croatia\", \"HT\": \"Haiti\", \"HU\": \"Hungary\", \"HK\": \"Hong Kong\", \"HN\": \"Honduras\", \"HM\": \"Heard Island and McDonald Islands\", \"VE\": \"Venezuela\", \"PR\": \"Puerto Rico\", \"PS\": \"Palestinian Territory\", \"PW\": \"Palau\", \"PT\": \"Portugal\", \"SJ\": \"Svalbard and Jan Mayen\", \"PY\": \"Paraguay\", \"IQ\": \"Iraq\", \"PA\": \"Panama\", \"PF\": \"French Polynesia\", \"PG\": \"Papua New Guinea\", \"PE\": \"Peru\", \"PK\": \"Pakistan\", \"PH\": \"Philippines\", \"PN\": \"Pitcairn\", \"PL\": \"Poland\", \"PM\": \"Saint Pierre and Miquelon\", \"ZM\": \"Zambia\", \"EH\": \"Western Sahara\", \"EE\": \"Estonia\", \"EG\": \"Egypt\", \"ZA\": \"South Africa\", \"EC\": \"Ecuador\", \"IT\": \"Italy\", \"VN\": \"Vietnam\", \"SB\": \"Solomon Islands\", \"ET\": \"Ethiopia\", \"SO\": \"Somalia\", \"ZW\": \"Zimbabwe\", \"SA\": \"Saudi Arabia\", \"ES\": \"Spain\", \"ER\": \"Eritrea\", \"ME\": \"Montenegro\", \"MD\": \"Moldova\", \"MG\": \"Madagascar\", \"MF\": \"Saint Martin\", \"MA\": \"Morocco\", \"MC\": \"Monaco\", \"UZ\": \"Uzbekistan\", \"MM\": \"Myanmar\", \"ML\": \"Mali\", \"MO\": \"Macao\", \"MN\": \"Mongolia\", \"MH\": \"Marshall Islands\", \"MK\": \"Macedonia\", \"MU\": \"Mauritius\", \"MT\": \"Malta\", \"MW\": \"Malawi\", \"MV\": \"Maldives\", \"MQ\": \"Martinique\", \"MP\": \"Northern Mariana Islands\", \"MS\": \"Montserrat\", \"MR\": \"Mauritania\", \"IM\": \"Isle of Man\", \"UG\": \"Uganda\", \"TZ\": \"Tanzania\", \"MY\": \"Malaysia\", \"MX\": \"Mexico\", \"IL\": \"Israel\", \"FR\": \"France\", \"IO\": \"British Indian Ocean Territory\", \"SH\": \"Saint Helena\", \"FI\": \"Finland\", \"FJ\": \"Fiji\", \"FK\": \"Falkland Islands\", \"FM\": \"Micronesia\", \"FO\": \"Faroe Islands\", \"NI\": \"Nicaragua\", \"NL\": \"Netherlands\", \"NO\": \"Norway\", \"NA\": \"Namibia\", \"VU\": \"Vanuatu\", \"NC\": \"New Caledonia\", \"NE\": \"Niger\", \"NF\": \"Norfolk Island\", \"NG\": \"Nigeria\", \"NZ\": \"New Zealand\", \"NP\": \"Nepal\", \"NR\": \"Nauru\", \"NU\": \"Niue\", \"CK\": \"Cook Islands\", \"XK\": \"Kosovo\", \"CI\": \"Ivory Coast\", \"CH\": \"Switzerland\", \"CO\": \"Colombia\", \"CN\": \"China\", \"CM\": \"Cameroon\", \"CL\": \"Chile\", \"CC\": \"Cocos Islands\", \"CA\": \"Canada\", \"CG\": \"Republic of the Congo\", \"CF\": \"Central African Republic\", \"CD\": \"Democratic Republic of the Congo\", \"CZ\": \"Czech Republic\", \"CY\": \"Cyprus\", \"CX\": \"Christmas Island\", \"CR\": \"Costa Rica\", \"CW\": \"Curacao\", \"CV\": \"Cape Verde\", \"CU\": \"Cuba\", \"SZ\": \"Swaziland\", \"SY\": \"Syria\", \"SX\": \"Sint Maarten\", \"KG\": \"Kyrgyzstan\", \"KE\": \"Kenya\", \"SS\": \"South Sudan\", \"SR\": \"Suriname\", \"KI\": \"Kiribati\", \"KH\": \"Cambodia\", \"KN\": \"Saint Kitts and Nevis\", \"KM\": \"Comoros\", \"ST\": \"Sao Tome and Principe\", \"SK\": \"Slovakia\", \"KR\": \"South Korea\", \"SI\": \"Slovenia\", \"KP\": \"North Korea\", \"KW\": \"Kuwait\", \"SN\": \"Senegal\", \"SM\": \"San Marino\", \"SL\": \"Sierra Leone\", \"SC\": \"Seychelles\", \"KZ\": \"Kazakhstan\", \"KY\": \"Cayman Islands\", \"SG\": \"Singapore\", \"SE\": \"Sweden\", \"SD\": \"Sudan\", \"DO\": \"Dominican Republic\", \"DM\": \"Dominica\", \"DJ\": \"Djibouti\", \"DK\": \"Denmark\", \"VG\": \"British Virgin Islands\", \"DE\": \"Germany\", \"YE\": \"Yemen\", \"DZ\": \"Algeria\", \"US\": \"United States\", \"UY\": \"Uruguay\", \"YT\": \"Mayotte\", \"UM\": \"United States Minor Outlying Islands\", \"LB\": \"Lebanon\", \"LC\": \"Saint Lucia\", \"LA\": \"Laos\", \"TV\": \"Tuvalu\", \"TW\": \"Taiwan\", \"TT\": \"Trinidad and Tobago\", \"TR\": \"Turkey\", \"LK\": \"Sri Lanka\", \"LI\": \"Liechtenstein\", \"LV\": \"Latvia\", \"TO\": \"Tonga\", \"LT\": \"Lithuania\", \"LU\": \"Luxembourg\", \"LR\": \"Liberia\", \"LS\": \"Lesotho\", \"TH\": \"Thailand\", \"TF\": \"French Southern Territories\", \"TG\": \"Togo\", \"TD\": \"Chad\", \"TC\": \"Turks and Caicos Islands\", \"LY\": \"Libya\", \"VA\": \"Vatican\", \"VC\": \"Saint Vincent and the Grenadines\", \"AE\": \"United Arab Emirates\", \"AD\": \"Andorra\", \"AG\": \"Antigua and Barbuda\", \"AF\": \"Afghanistan\", \"AI\": \"Anguilla\", \"VI\": \"U.S. Virgin Islands\", \"IS\": \"Iceland\", \"IR\": \"Iran\", \"AM\": \"Armenia\", \"AL\": \"Albania\", \"AO\": \"Angola\", \"AQ\": \"Antarctica\", \"AS\": \"American Samoa\", \"AR\": \"Argentina\", \"AU\": \"Australia\", \"AT\": \"Austria\", \"AW\": \"Aruba\", \"IN\": \"India\", \"AX\": \"Aland Islands\", \"AZ\": \"Azerbaijan\", \"IE\": \"Ireland\", \"ID\": \"Indonesia\", \"UA\": \"Ukraine\", \"QA\": \"Qatar\", \"MZ\": \"Mozambique\"}");
return countries[code];
}
function getCountry(intent, session, callback) {
var attributes = {};
var address = intent.slots.Address.value.replace(" point ", ".");
var address = address.replace(/ /g, "");
var address = address.replace(/[^\d.]/g, "");
var output = address;
var repromptText = "I'm sorry, I didn't catch that.";
var shouldEnd = false;
http.get('http://ipinfo.io/' + address, function(res) {
output = 'http://ipinfo.io/' + address + " - " + res.statusCode;
if (res.statusCode === 200)
{
res.on('data', (chunk) => {
var js = JSON.parse(chunk);
var loc = js.city + " " + js.region + " " + getCountryFromCode(js.country);
output = "That IP address is located in: " + loc.trim();
repromptText = "Is there anything else I can do?";
callback(attributes, buildSpeechletResponse(output, repromptText, shouldEnd));
});
}
else
{
output = "Sorry but there is a problem with the entered address. " + address;
repromptText = "Is there anything else I can do?";
callback(attributes, buildSpeechletResponse(output, repromptText, shouldEnd));
}
}).on('error', function(e) {
output = "Sorry but there is a problem with the entered address. " + address;
repromptText = "Is there anything else I can do?";
callback(attributes, buildSpeechletResponse(output, repromptText, shouldEnd));
});
}
function getHelpMessage(callback) {
const attributes = {};
const title = "Where is that IP Help?";
const speechOutput = "Use Where is that IP to easily locate a city, region and country an IP address is located. To locate a country based on IP say, Locate 192 point 168 point 0 point 1. Remember to state point between the numbers to ensure the address is formatted correctly.";
const repromptText = "Sorry I didnt get that, can you repeat the request?";
const shouldEnd = false;
callback(attributes, buildSpeechletResponseWithCard(title, speechOutput, speechOutput, repromptText, shouldEnd));
}
function getWelcomeMessage(callback) {
const attributes = {};
const speechOutput = "Hi and welcome to Where is that IP, your helpful IP locator tool. What can I do for you?";
const repromptText = "What was that again?";
const shouldEnd = false;
callback(attributes, buildSpeechletResponse(speechOutput, repromptText, shouldEnd));
}
function getEndMessage(callback) {
const attributes = {};
const speechOutput = "Thank you for using Where is that IP.";
const shouldEnd = true;
callback(attributes, buildSpeechletResponse(speechOutput, null, shouldEnd));
}
function onLaunch(launchRequest, session, callback) {
getWelcomeMessage(callback);
}
function onSessionEnded(request, session, callback) {
getEndMessage(callback);
}
function onIntent(intentRequest, session, callback) {
const intent = intentRequest.intent;
const intentName = intentRequest.intent.name;
if (intentName === "GetCountry") {
return getCountry(intent, session, callback);
} else if (intentName === "AMAZON.HelpIntent") {
return getHelpMessage(callback);
} else if (intentName === "AMAZON.CancelIntent") {
return getEndMessage(callback);
} else if (intentName === "AMAZON.StopIntent") {
return getEndMessage(callback);
} else {
throw new Error('Invalid intent');
}
}
exports.handler = (event, context, callback) => {
try
{
if (event.session.application.applicationId != 'Add Your Own App ID here') {
callback('Invalid Application ID');
}
if (event.request.type === 'LaunchRequest') {
onLaunch(event.request,
event.session,
(sessionAttributes, speechletResponse) => {
callback(null, buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type === 'IntentRequest') {
onIntent(event.request,
event.session,
(sessionAttributes, speechletResponse) => {
callback(null, buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type === 'SessionEndedRequest') {
onSessionEnded(event.request, event.session);
callback();
}
} catch (err) {
callback(err);
}
};
Alexa Intent Scheme
JSON{
"intents": [
{
"intent": "GetCountry",
"slots": [
{
"name": "Address",
"type": "AddressValues"
}
]
},
{
"intent": "AMAZON.HelpIntent"
},
{
"intent": "AMAZON.CancelIntent"
},
{
"intent": "AMAZON.StopIntent"
}
]
}
Comments