diff options
Diffstat (limited to 'web/gui/src/dashboard.js/registry.js')
-rw-r--r-- | web/gui/src/dashboard.js/registry.js | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/web/gui/src/dashboard.js/registry.js b/web/gui/src/dashboard.js/registry.js new file mode 100644 index 0000000..77a822b --- /dev/null +++ b/web/gui/src/dashboard.js/registry.js @@ -0,0 +1,303 @@ + +// Registry of netdata hosts + +NETDATA.registry = { + server: null, // the netdata registry server + isCloudEnabled: false,// is netdata.cloud functionality enabled? + cloudBaseURL: null, // the netdata cloud base url + person_guid: null, // the unique ID of this browser / user + machine_guid: null, // the unique ID the netdata server that served dashboard.js + hostname: 'unknown', // the hostname of the netdata server that served dashboard.js + machines: null, // the user's other URLs + machines_array: null, // the user's other URLs in an array + person_urls: null, + + MASKED_DATA: "***", + + isUsingGlobalRegistry: function() { + return NETDATA.registry.server == "https://registry.my-netdata.io"; + }, + + isRegistryEnabled: function() { + return !(NETDATA.registry.isUsingGlobalRegistry() || isSignedIn()) + }, + + parsePersonUrls: function (person_urls) { + NETDATA.registry.person_urls = person_urls; + + if (person_urls) { + NETDATA.registry.machines = {}; + NETDATA.registry.machines_array = []; + + let apu = person_urls; + let i = apu.length; + while (i--) { + if (typeof NETDATA.registry.machines[apu[i][0]] === 'undefined') { + // console.log('adding: ' + apu[i][4] + ', ' + ((now - apu[i][2]) / 1000).toString()); + + let obj = { + guid: apu[i][0], + url: apu[i][1], + last_t: apu[i][2], + accesses: apu[i][3], + name: apu[i][4], + alternate_urls: [] + }; + obj.alternate_urls.push(apu[i][1]); + + NETDATA.registry.machines[apu[i][0]] = obj; + NETDATA.registry.machines_array.push(obj); + } else { + // console.log('appending: ' + apu[i][4] + ', ' + ((now - apu[i][2]) / 1000).toString()); + + let pu = NETDATA.registry.machines[apu[i][0]]; + if (pu.last_t < apu[i][2]) { + pu.url = apu[i][1]; + pu.last_t = apu[i][2]; + pu.name = apu[i][4]; + } + pu.accesses += apu[i][3]; + pu.alternate_urls.push(apu[i][1]); + } + } + } + + if (typeof netdataRegistryCallback === 'function') { + netdataRegistryCallback(NETDATA.registry.machines_array); + } + }, + + init: function () { + if (netdataRegistry !== true) { + return; + } + + NETDATA.registry.hello(NETDATA.serverDefault, function (data) { + if (data) { + NETDATA.registry.server = data.registry; + if (data.cloud_base_url != "") { + NETDATA.registry.isCloudEnabled = true; + NETDATA.registry.cloudBaseURL = data.cloud_base_url; + } else { + NETDATA.registry.isCloudEnabled = false; + NETDATA.registry.cloudBaseURL = ""; + } + NETDATA.registry.machine_guid = data.machine_guid; + NETDATA.registry.hostname = data.hostname; + if (dataLayer) { + if (data.anonymous_statistics) dataLayer.push({"anonymous_statistics" : "true", "machine_guid" : data.machine_guid}); + } + NETDATA.registry.access(2, function (person_urls) { + NETDATA.registry.parsePersonUrls(person_urls); + }); + } + }); + }, + + hello: function (host, callback) { + host = NETDATA.fixHost(host); + + // send HELLO to a netdata server: + // 1. verifies the server is reachable + // 2. responds with the registry URL, the machine GUID of this netdata server and its hostname + $.ajax({ + url: host + '/api/v1/registry?action=hello', + async: true, + cache: false, + headers: { + 'Cache-Control': 'no-cache, no-store', + 'Pragma': 'no-cache' + }, + xhrFields: {withCredentials: true} // required for the cookie + }) + .done(function (data) { + data = NETDATA.xss.checkOptional('/api/v1/registry?action=hello', data); + + if (typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(408, host + ' response: ' + JSON.stringify(data)); + data = null; + } + + if (typeof callback === 'function') { + return callback(data); + } + }) + .fail(function () { + NETDATA.error(407, host); + + if (typeof callback === 'function') { + return callback(null); + } + }); + }, + + access: function (max_redirects, callback) { + let name = NETDATA.registry.MASKED_DATA; + let url = NETDATA.registry.MASKED_DATA; + + if (!NETDATA.registry.isUsingGlobalRegistry()) { + // If the user is using a private registry keep sending identifiable + // data. + name = NETDATA.registry.hostname; + url = NETDATA.serverDefault; + } + + console.log("ACCESS", name, url); + + // send ACCESS to a netdata registry: + // 1. it lets it know we are accessing a netdata server (its machine GUID and its URL) + // 2. it responds with a list of netdata servers we know + // the registry identifies us using a cookie it sets the first time we access it + // the registry may respond with a redirect URL to send us to another registry + $.ajax({ + url: NETDATA.registry.server + '/api/v1/registry?action=access&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(name) + '&url=' + encodeURIComponent(url), // + '&visible_url=' + encodeURIComponent(document.location), + async: true, + cache: false, + headers: { + 'Cache-Control': 'no-cache, no-store', + 'Pragma': 'no-cache' + }, + xhrFields: {withCredentials: true} // required for the cookie + }) + .done(function (data) { + data = NETDATA.xss.checkAlways('/api/v1/registry?action=access', data); + + let redirect = null; + if (typeof data.registry === 'string') { + redirect = data.registry; + } + + if (typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(409, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); + data = null; + } + + if (data === null) { + if (redirect !== null && max_redirects > 0) { + NETDATA.registry.server = redirect; + NETDATA.registry.access(max_redirects - 1, callback); + } + else { + if (typeof callback === 'function') { + return callback(null); + } + } + } else { + if (typeof data.person_guid === 'string') { + NETDATA.registry.person_guid = data.person_guid; + } + + if (typeof callback === 'function') { + const urls = data.urls.filter((u) => u[1] !== NETDATA.registry.MASKED_DATA); + return callback(urls); + } + } + }) + .fail(function () { + NETDATA.error(410, NETDATA.registry.server); + + if (typeof callback === 'function') { + return callback(null); + } + }); + }, + + delete: function (delete_url, callback) { + // send DELETE to a netdata registry: + $.ajax({ + url: NETDATA.registry.server + '/api/v1/registry?action=delete&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&delete_url=' + encodeURIComponent(delete_url), + async: true, + cache: false, + headers: { + 'Cache-Control': 'no-cache, no-store', + 'Pragma': 'no-cache' + }, + xhrFields: {withCredentials: true} // required for the cookie + }) + .done(function (data) { + data = NETDATA.xss.checkAlways('/api/v1/registry?action=delete', data); + + if (typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(411, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); + data = null; + } + + if (typeof callback === 'function') { + return callback(data); + } + }) + .fail(function () { + NETDATA.error(412, NETDATA.registry.server); + + if (typeof callback === 'function') { + return callback(null); + } + }); + }, + + search: function (machine_guid, callback) { + // SEARCH for the URLs of a machine: + $.ajax({ + url: NETDATA.registry.server + '/api/v1/registry?action=search&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&for=' + machine_guid, + async: true, + cache: false, + headers: { + 'Cache-Control': 'no-cache, no-store', + 'Pragma': 'no-cache' + }, + xhrFields: {withCredentials: true} // required for the cookie + }) + .done(function (data) { + data = NETDATA.xss.checkAlways('/api/v1/registry?action=search', data); + + if (typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(417, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); + data = null; + } + + if (typeof callback === 'function') { + return callback(data); + } + }) + .fail(function () { + NETDATA.error(418, NETDATA.registry.server); + + if (typeof callback === 'function') { + return callback(null); + } + }); + }, + + switch: function (new_person_guid, callback) { + // impersonate + $.ajax({ + url: NETDATA.registry.server + '/api/v1/registry?action=switch&machine=' + NETDATA.registry.machine_guid + '&name=' + encodeURIComponent(NETDATA.registry.hostname) + '&url=' + encodeURIComponent(NETDATA.serverDefault) + '&to=' + new_person_guid, + async: true, + cache: false, + headers: { + 'Cache-Control': 'no-cache, no-store', + 'Pragma': 'no-cache' + }, + xhrFields: {withCredentials: true} // required for the cookie + }) + .done(function (data) { + data = NETDATA.xss.checkAlways('/api/v1/registry?action=switch', data); + + if (typeof data.status !== 'string' || data.status !== 'ok') { + NETDATA.error(413, NETDATA.registry.server + ' responded with: ' + JSON.stringify(data)); + data = null; + } + + if (typeof callback === 'function') { + return callback(data); + } + }) + .fail(function () { + NETDATA.error(414, NETDATA.registry.server); + + if (typeof callback === 'function') { + return callback(null); + } + }); + } +}; |