// ----- Config //Where to open the map DEFAULT_MAP_LATITUDE = 63.027722; DEFAULT_MAP_LONGITUDE = 15.58136; DEFAULT_MAP_ZOOM = 4; // ----- Global variables var map; var infoWindow; var countryPolygons = {}; // key is country.code var opacityOfPolygon = 0.6; var selectedTab = 0; var lastSelectedDate; // ----- Utility functions function endsWith(str, suffix) { return str.indexOf(suffix, str.length - suffix.length) !== -1; } dateToday = function() { var d = new Date(); var yyyy = d.getFullYear().toString(); var mm = (d.getMonth()+1).toString(); // getMonth() is zero-based var dd = d.getDate().toString(); return yyyy + "-" + (mm[1]?mm:"0"+mm[0]) + "-" + (dd[1]?dd:"0"+dd[0]); } // ----- Get parameters from URL query = $.parseJSON(query); // query from URL debug = query.debug; if (debug) console.log("query", query); if (query.date != "") { lastSelectedDate = query.date; } else { lastSelectedDate = dateToday(); } noTestData = {}; noTestData.knnr = "0"; noTestData.name = "unknown"; noTestData.url = "unknown"; noTestData.contact = "unknown"; noTestData.dnsSecSigned = "0"; noTestData.isRecursive = "0"; noTestData.ipDns = "0"; noTestData.ipMail = "0"; noTestData.ipWww = "0"; noTestData.dnsList = []; noTestData.errors = []; noTestData.warnings = []; noTestData.nodata = true; //---------------------------------------------------------------------------- // // 'Class' that contains test results for a municipality // // ---------------------------------------------------------------------------- Testresult = function() { this.dnsSecSigned = "0"; this.isRecursive = "0"; this.ipDns = "0"; this.ipMail = "0"; this.ipWww = "0"; this.dnsList = []; this.errors = []; this.warnings = []; this.nodata = true; } //---------------------------------------------------------------------------- // // 'Class' that contains information related to a municipality // // ---------------------------------------------------------------------------- Municipality = function() { this.knnr = -1; // this.name = ""; // this.url = ""; this.contact = ""; this.polygons = []; // polygons on the map this.testresult = null; // } // Municipality.prototype.get = function(country) { // } // ---------------------------------------------------------------------------- // // 'Class' that reads in coordinates for a countrys municipalities // // ---------------------------------------------------------------------------- CountryMgr = function() { this.data = {}; // key is country.code this.polygons = {}; // key is country.code }; CountryMgr.prototype.get = function(country) { if (debug) console.log("CountryMgr.get(", country, ")"); if (this.data[country.code] !== undefined) { if (debug) console.log(" coordinates already loaded, result from cache"); return this.data[country.code]; } result = new Array(); if (query.https) { url = "https://"; } else { url = "http://"; } url = url + query.server_name + "/getcountryinfo.php?country_code=" + country.code; $.ajax({ async: false, type: "GET", cache: false, url: url, dataType: "json", success: function (data) { result = data.municipalities; }, error: function (xhr, status, error) { if (debug) console.log(" Error loading data:", xhr, status, error); } }); this.data[country.code] = result; if (debug) { this.polygons[country.code] = {}; polygons = this.polygons[country.code]; // create and cache all polygons for municipalities in a country $.each(result, function(knnr, municipality) { knnr = municipality.knnr; coordinates = municipality.coordinates; var polyCoords = new Array(); if (coordinates !== null) { len = coordinates.length; for(ix = 0; ix < len; ix++) { lat = coordinates[ix][0]; lng = coordinates[ix][1]; polyCoords.push(new google.maps.LatLng(lat, lng)); } } if (polygons[knnr] === undefined) { polygons[knnr] = [] } var polygon = new google.maps.Polygon({ paths: polyCoords, strokeColor: "#000", strokeOpacity: 0.8, strokeWeight: 0.5, fillColor: "#000", fillOpacity: 0, }); polygons[knnr].push(polygon); }); } return result; }; // Return the polygons for a country/municipality CountryMgr.prototype.getPolygons = function(country_code, knnr) { if (this.polygons[country_code] !== undefined) { if (this.polygons[country_code][knnr] !== undefined) { return this.polygons[country_code][knnr]; } } if (debug) console.log("getPolygons(", country_code, knnr, ")", "Could not find polygon"); }; countryMgr = new CountryMgr(); //---------------------------------------------------------------------------- // // 'Class' that handles test results for municipalities // Caches data for the selected date // //---------------------------------------------------------------------------- var TestresultMgr = function() { this.data = {}; // key is country.code this.date = undefined; // date the data is valid for }; TestresultMgr.prototype.get = function(country, date) { if (debug) console.log("TestresultMgr.get(", country, date, ")"); if (this.date != date) { this.data = {}; // flush cache this.date = date; } if (this.data[country.code] !== undefined) { if (debug) console.log(" testdata already loaded, result from cache"); return this.data[country.code]; // already loaded } result = {}; if (query.https) { url = "https://"; } else { url = "http://"; } var url = url + query.server_name + "/gettestresult.php?date=" + date + "&code=" + country.code; $.ajax({ async: false, type: "GET", url: url, dataType: "json", cache: false, contentType: "application/json", success: function (data) { $(data.municipalities.municipality).each(function () { result[this.knnr] = this; }); }, error: function (xhr, status, error) { if (debug) console.log(" Error loading data:", xhr, status, error); } }); this.data[country.code] = result; return result; }; testresultMgr = new TestresultMgr(); //---------------------------------------------------------------------------- // date or country or filter or tab has changed // reload everything // if date is not specified, use last selected date function reloadAll(date) { if (debug) console.log("reloadAll(", date, ")"); $("#loader").show(); infowindow.close(); if (typeof date == 'undefined') { date = lastSelectedDate; } var boxes = document.getElementsByName('country[]'); $.each(boxes, function(index, box) { country = countries[box.value]; clearMunicipalitiesColoring(country); if (this.checked == true) { updateMunicipalityColoring(country, date); } }); $("#loader").hide(); statistics(); } // Remove all municipality colors function clearMunicipalitiesColoring(country) { if (debug) console.log("clearMunicipalitiesColoring(", country, ")"); if (countryPolygons[country.code] !== undefined) { $.each(countryPolygons[country.code], function() { $.each(this, function() { this.setMap(null); }); }); } } var cntTotalDomains = 0; var cntOnlyOneDns = 0; var cntSignedDomains = 0; var cntWithWarning = 0; var cntWithError = 0; var cntRecursive = 0; var isNoneSelected = false; var isSigned = false; var isNoerror = false; var isWarnings = false; var isErrors = false; var isWww = false; var isDns = false; var isMail = false; // update all municipalitites in selected countries // // color each municipality according to test status function updateMunicipalityColoring(country, date) { if (debug) console.log("updateMunicipalityColoring(", country, ")"); google.maps.event.clearListeners(map, 'click̈́'); cntTotalDomains = 0; cntOnlyOneDns = 0; cntSignedDomains = 0; cntWithWarning = 0; cntWithError = 0; cntRecursive = 0; // Get GUI state to avoid many DOM lookups, tab DNSSEC isNoneSelected = $("#tabs input[value='dns']:checked").size()- $("#tabs input#signed[type='checkbox']:checked").size() == 0; isSigned = $("#signed").is(':checked'); isNoerror = $("#noerror").is(':checked'); isWarnings = $("#warnings").is(':checked'); isErrors = $("#errors").is(':checked'); // Get GUI state to avoid many DOM lookups, tab IPv6 isWww = $("#www").is(':checked'); isDns = $("#dns").is(':checked'); isMail = $("#mail").is(':checked'); municipalititesInfo = countryMgr.get(country); countryTestdata = testresultMgr.get(country, date); countryPolygons[country.code] = {}; $.each(municipalititesInfo, function(knnr, municipality) { knnr = municipality.knnr; var testdata = countryTestdata[knnr]; if (testdata != null) { addPolygon(country.code, municipality, testdata); } else { if (debug) console.log("No testdata for knnr", knnr); if (debug) addPolygon(country.code, municipality, noTestData); } }); var dnsCheckInfoString = "A Zonemaster against {0} domains {1} gave a result of {2} recursive DNS´s and Zonemaster also found {3} ERROR and {4} WARNINGS. {5} domains has just one DNS."; dnsCheckInfoString = dnsCheckInfoString.replace(/\{0\}/, cntTotalDomains.toString()); dnsCheckInfoString = dnsCheckInfoString.replace(/\{1\}/, lastSelectedDate); dnsCheckInfoString = dnsCheckInfoString.replace(/\{2\}/, cntRecursive.toString()); dnsCheckInfoString = dnsCheckInfoString.replace(/\{3\}/, cntWithError.toString()); dnsCheckInfoString = dnsCheckInfoString.replace(/\{4\}/, cntWithWarning.toString()); dnsCheckInfoString = dnsCheckInfoString.replace(/\{5\}/, cntOnlyOneDns.toString()); } // Add polygons around a municipality // Add handlers for infoview popup function addPolygon(code, municipality, testdata) { var secure = true; var ipv6 = true; var knnr = municipality.knnr; cntTotalDomains++; try{ if (testdata.dnsList.length == 1) {cntOnlyOneDns++; secure = false} if (testdata.dnsSecSigned == 1) cntSignedDomains++; else secure = false; if (testdata.errors.length > 0) {cntWithError++;secure = false} if (testdata.warnings.length > 0) {cntWithWarning++;secure = false} if (testdata.isRecursive == 1) {cntRecursive++;secure = false} } catch(e) { console.log("Error " + e); } var polyCoords = new Array(); tmp = municipality.coordinates; if (tmp !== null) { len = tmp.length; for(ix = 0; ix < len; ix++) { lat = tmp[ix][0]; lng = tmp[ix][1]; polyCoords.push(new google.maps.LatLng(lat, lng)); } } var hasErrors = (testdata.errors != null && $(testdata.errors).size() > 0); var hasWarnings = (testdata.warnings != null && $(testdata.warnings).size() > 0); var show = true; var color = "fff"; switch (selectedTab) { case 0: // DNSSEC tab show = !isSigned && !isNoerror && !isWarnings && !isErrors; if ((isNoerror || isNoneSelected) && !hasErrors && !hasWarnings) { show = true; if (testdata != null && testdata.dnsSecSigned == 1) { color = "0f0"; } else { color = "eaea6a"; // unsigned but without error } if (isSigned && testdata.dnsSecSigned != 1) { show = false; } } if ((isWarnings || isNoneSelected) && hasWarnings) { show = true; color = "f90" if (isSigned && testdata.dnsSecSigned != 1) { show = false; } } if ((isErrors || isNoneSelected) && hasErrors) { show = true; color = "f00" if (isSigned && testdata.dnsSecSigned != 1) { show = false; } } break; case 1: // IPv6 tab if (isWww && testdata.ipWww != 1) { show = false; } if (isDns && testdata.ipDns != 1) { show = false; } if (isMail && testdata.ipMail != 1) { show = false; } color = "0f0"; if (testdata.ipWww != 1 || testdata.ipDns != 1 || testdata.ipMail != 1) {color = "f90"; ipv6 = false;} if (testdata.ipWww != 1 && testdata.ipDns != 1 && testdata.ipMail != 1) {color = "f00"; ipv6 = false;} if (testdata.eWww == 1 || testdata.eDns == 1 || testdata.eMail == 1) {color = "000"; ipv6 = false;} break; } if (countryPolygons[code][testdata.knnr] == null) { countryPolygons[code][testdata.knnr] = new Array(); } if (debug) { polygons = countryMgr.getPolygons(code, knnr); len = polygons.length; for(ix = 0; ix < len; ix++) { polygons[ix].setOptions({ fillColor: "#" + color, fillOpacity: opacityOfPolygon, countryCode: code, secure: secure, ipv6: ipv6 }); } } else { var polygons = []; polygons[0] = new google.maps.Polygon({ paths: polyCoords, strokeColor: "#000", strokeOpacity: 0.8, strokeWeight: color == "fff" ? 0.5 : 0.5, fillColor: "#" + color, fillOpacity: color == "fff" ? 0 : opacityOfPolygon, countryCode: code, secure: secure, ipv6: ipv6 }); } for(ix = 0; ix < polygons.length; ix++) { countryPolygons[code][testdata.knnr].push(polygons[ix]); polygons[ix].setMap(map); if(!show) { polygons[ix].setOptions({fillOpacity: 0.0, strokeWeight: 0.5}); } } polygon = polygons[0]; //if (!show) { // if (typeof countryPolygons[code][testdata.knnr] !== 'undefined') { // $.each(countryPolygons[code][testdata.knnr], function() { // tmppolygons = this; // for(ix = 0; ix < tmppolygons.length; ix++) { // tmppolygons[ix].setOptions({ fillOpacity: 0.0, strokeWeight: 0.5 }); // } // }); // } //} // Handle click on a municipality, show detailed test information for(ix = 0; ix < polygons.length; ix++) { google.maps.event.addListener(polygons[ix], "click", function (event) { var vertices = this.getPath(); var contentString = testdata.name; if (debug) contentString += " (" + knnr + ")"; var contentString = "

" + contentString + "

\n"; if (debug) { marker = vertices.getAt(0); contentString += "Latitude " + marker.lat() + ", Longitude " + marker.lng() + "

"; } switch (selectedTab) { case 0: // DNSSEC tab var dnsString = "Without remarks in Zonemaster but not signed"; if (testdata.dnsSecSigned == 1) dnsString = "Signed with DNSSEC and without remarks"; if (testdata.dnsSecSigned == 1 && hasWarnings) dnsString = "Signed with DNSSEC but with warnings"; if (testdata.dnsSecSigned != 1 && (hasWarnings || hasErrors)) dnsString = "Warnings in Zonemaster"; if (testdata.dnsSecSigned == 1) dnsString = "Signed with DNSSEC and without remarks"; if (testdata.dnsSecSigned == 1 && hasWarnings) dnsString = "Signed with DNSSEC but with warnings"; if (testdata.dnsSecSigned != 1&& (hasWarnings || hasErrors)) dnsString = "Warnings in Zonemaster"; if (hasErrors) dnsString = "Error in Zonemaster"; contentString += "DNSSEC: " + dnsString + "
"; contentString += "Contact: " + testdata.contact + "
"; if (testdata.isRecursive == 1) contentString += "DNS is: Recursive
"; contentString += generateListFromArray("Errors", testdata.errors); contentString += generateListFromArray("Warnings", testdata.warnings); contentString += generateListFromArray("DNS Entries", testdata.dnsList); break; case 1: // IPv6 tab contentString += "IPv6 status:

\n"; contentString += "\n"; if(testdata.eWww === 1) { ok = "Broken"; } else { ok = testdata.ipWww == "1" ? "Ok": "Missing"; } contentString += "\n"; contentString += "\n"; contentString += "\n"; contentString += "\n"; if(testdata.eDns === 1) { ok = "Broken"; } else { ok = testdata.ipDns == "1" ? "Ok": "Missing"; } contentString += "\n"; contentString += "\n"; contentString += "\n"; contentString += "\n"; if(testdata.eMail === 1) { ok = "Broken"; } else { ok = testdata.ipMail == "1" ? "Ok": "Missing"; } contentString += "\n"; contentString += "\n"; contentString += "\n"; contentString += "\n"; contentString += "
WWW" + ok + "
DNS" + ok + "
Mail" + ok + "
\n"; break; } if (testdata.url != null) { //contentString += "
Test www and DNS: " + testdata.url + "
"; } contentString += "
Test www and DNS: " + testdata.url + "
"; contentString += "
Test mail: " + testdata.url + "
"; infowindow.setContent(contentString); infowindow.setPosition(event.latLng); infowindow.open(map); }); } } // // Display statistics for all selected countries // function statistics() { if (debug) console.log("statistics()"); var totalDomains = 0; var secureDomains = 0; var ipv6Domains = 0; var boxes = document.getElementsByName('country2[]'); $.each(boxes, function(index, box) { if (this.checked == true) { $.each(countryPolygons[this.value], function() { totalDomains++; if (this[0].secure) secureDomains++; if (this[0].ipv6) ipv6Domains++; }); } }); switch (selectedTab) { case 0: // DNSSEC tab var stats = "{0} of {1} municipalities secured without warnings and errors."; stats = stats.replace(/\{0\}/, secureDomains); break; case 1: // IPv6 tab var stats = "{0} of {1} municipalities have IPv6 on www, mail and dns."; stats = stats.replace(/\{0\}/, ipv6Domains); break; } stats = stats.replace(/\{1\}/, totalDomains); $('#statistics').text(stats); } // function getValueOfFirstAttribute(object) { var firstProp; for (var key in object) { if (object.hasOwnProperty(key)) { return object[key]; } } return null; } // function generateListFromArray(title, arr) { if (arr != null && $(arr).size() > 0) { var result = "
" + title + "
"; $(arr).each(function () { result += "" + (getValueOfFirstAttribute(this) == null ? "" : getValueOfFirstAttribute(this)) + "
\n"; }); return result; } return ""; } // Called from country checkboxes // Syncronize country checkboxes between DNSSEC and IPv6 tab function checkBox(box) { var boxes = document.getElementsByName('country[]'); var boxes2 = document.getElementsByName('country2[]'); if (!box.checked) { boxes[box.value-1].checked = false; boxes2[box.value-1].checked = false; } else { boxes[box.value-1].checked = true; boxes2[box.value-1].checked = true; } reloadAll(); } // Called from checkbox function selectAllIpv6() { val = document.getElementById('allIp').checked == true; document.getElementById('www').checked = val; document.getElementById('dns').checked = val; document.getElementById('mail').checked = val; reloadAll(); } // // Called when DOM/jquery is ready // Initialize // $(function () { if (debug) console.log("jQuery initialized"); // activate jqueryUI button $( "#rewind" ).button({ text: false, icons: { primary: "ui-icon-seek-prev" } }) .click(function() { var new_date = $('#datepicker').datepicker('getDate'); new_date.setDate(new_date.getDate() - 1); $('#datepicker').datepicker('setDate', new_date); var d = $('#datepicker').val(); reloadAll(d); }); // activate jqueryUI button $( "#today" ).button({ text: false, icons: { primary: "ui-icon-stop" } }) .click(function() { var new_date = dateToday(); $('#datepicker').datepicker('setDate', new_date); reloadAll(new_date); }); // activate jqueryUI button $( "#forward" ).button({ text: false, icons: { primary: "ui-icon-seek-next" } }).click(function() { var new_date = $('#datepicker').datepicker('getDate'); new_date.setDate(new_date.getDate() + 1); $('#datepicker').datepicker('setDate', new_date); var d = $('#datepicker').val(); reloadAll(d); }); // Get country names and ID var boxes = document.getElementsByName('country[]'); countries = {}; $.each(boxes, function(index, box) { countries[box.value] = new Object({ name: box.id, code: box.value }); }); if (query.country == "") { query.country = "sverige"; } // Enable checkbox for selected country $("#tabs input").prop("checked", false); $("." + query.country).prop("checked", true); // activate jqueryUI tabs $("#tabs").tabs({ show: function () { }, select: function(event, ui) { selectedTab = ui.index; if (debug) console.log("Selected tab=", selectedTab); reloadAll(); } }); // activate jqueryUI datepicker $("#datepicker").datepicker({ maxDate: '-0d', defaultDate: query.date, autoSize: true, firstDay: 1, dateFormat: 'yy-mm-dd', onSelect: function (dateText, inst) { lastSelectedDate = dateText; reloadAll(dateText); }, monthNames: ['January','February','March','April','May','June','July','August','September','October','November','December'], monthNamesShort : ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'], dayNamesMin: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], }); // Setup google maps default_latitude = query.map_latitude ? parseFloat(query.map_latitude) : DEFAULT_MAP_LATITUDE; default_longitude = query.map_longitude ? parseFloat(query.map_longitude) : DEFAULT_MAP_LONGITUDE; default_zoom = query.map_zoom ? parseInt(query.map_zoom) : DEFAULT_MAP_ZOOM; if (debug) console.log("default_latitude", default_latitude, "default_longitude", default_longitude) // options for google map var mapOptions = { center: new google.maps.LatLng(default_latitude, default_longitude), zoom: default_zoom, mapTypeId: google.maps.MapTypeId.ROADMAP, rotateControl: false, overviewMapControl: false, streetViewControl: false, panControl: false, mapTypeControl: false }; // enable the google map map = new google.maps.Map( document.getElementById("map_canvas"), mapOptions ); // google maps popup window that show details on a municipality infowindow = new google.maps.InfoWindow({ content: '', }); // handler, clicking outside the infowindow will close it google.maps.event.addListener(map, "click", function(event) { infowindow.close(); }); // If user wants kommunermedipv6.se, switch tab if (endsWith(query.http_host, "kommunermedipv6.se")) { $("#tabs").tabs('select', 1); if (debug) console.log("Selected IPv6 tab due to URL ending with ipv6.se") } reloadAll(); });