Language

DEX acts as the trust anchor in the ecosystem, and in addition to verifying DataPlugs and Offers, it also verifies that only certified HATs participate in the exchange. What this means is that even though the core HAT is open-source and anyone could run their own copy, such HATs may not comply with the security requirements, modify data exchange mechanisms, produce fraudulent data, break ecosystem rules, etc. It is therefore the responsibility of HAT Platform Providers who provision HATs as well as of the HAT Community Foundation certifying the Platform Providers’ compliance.

DEX recognises HAT clusters by the domain they are addressed under (e.g. hubat.net for the testing HATs) and assumes that once the domain manager has been certified, ensuring that individual HATs are compliant is the responsibility of the HAT Platform Provider managing the domain.

Registering individual HATs

Individual HATs still need to be registered with DEX before they can connect DataPlugs, claim Offers or report any statistics. Registering a HAT is done via an unauthenticated call:

curl --request POST \
  --url https://dex.hubofallthings.com/api/users/registerHat \
  --header 'content-type: application/json' \
  --data '{"hatAddress":"test.hubat.net"}'
var data = JSON.stringify({
  "hatAddress": "test.hubat.net"
});

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://dex.hubofallthings.com/api/users/registerHat");
xhr.setRequestHeader("content-type", "application/json");

xhr.send(data);
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://dex.hubofallthings.com/api/users/registerHat",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"hatAddress\":\"test.hubat.net\"}",
  CURLOPT_HTTPHEADER => array(
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import requests

url = "https://dex.hubofallthings.com/api/users/registerHat"

payload = "{\"hatAddress\":\"test.hubat.net\"}"
headers = {'content-type': 'application/json'}

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)
require 'uri'
require 'net/http'

url = URI("https://dex.hubofallthings.com/api/users/registerHat")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/json'
request.body = "{\"hatAddress\":\"test.hubat.net\"}"

response = http.request(request)
puts response.read_body

At this point, DEX verifies that the HAT is up and running, retrieves its Public Key and stores it. The Public Key is used to verify validity of requests coming in from the HAT by checking if the attached Access Token matches the stored public key.

Result of this security model with DEX is that HAT addresses cannot easily be reused: if an address gets reused, the Private/Public key must be regenerated by a certified provisioning system, and requests from such HAT will no longer be authorized. The decision to restrict Personal HAT Address reuse has been made due to the fact that the address identifies the individual when logging in to other services, retrieving and exchanging data, etc. and the inherent risks do not justify the potential convenience gains.

Updating certified apps on a HAT

Similarly to DataPlugs, new certified applications may be registered within the ecosystem after a HAT gets created, resulting in the HAT not recognising the app. Certain information, including access details may also need to change throughout the lifetime of the app. Therefore, DEX has the ability to update the details on selected HATs.

Proeprties of an app are:

ParameterDescription
titleTitle (Name) of the app used for logging in
namespaceNamespace where the app can write its data
descriptionTextual description of the app
logoUrlURL of the logo for the app
urlURL of the application to send the user to
authUrlRelative path within the URL for authetnication, empty string if the main URL used
browserBoolean flag of whether or not the app is a full browser, i.e. allows user to manage their HAT fully
categoryCategory of the app, e.g. “app” or “dataPlug”

Registering of an application (or updating them) is currently only available for the administrative accounts, however is done via a single call:

curl --request POST \
  --url 'https://dex.hubofallthings.com/api/users/update-application?hatFilter=test.hubat.net&cluster=hubat.net' \
  --header 'content-type: application/json' \
  --header 'x-auth-token: ACCESS_TOKEN' \
  --data '{"title":"TestApp","namespace":"testing","description":"Test Application","logoUrl":"/assets/images/testapp.png","url":"https://example.com","authUrl":"/signin/hat","browser":true,"category":"app","setup":true,"loginAvailable":true}'
var data = JSON.stringify({
  "title": "TestApp",
  "namespace": "testing",
  "description": "Test Application",
  "logoUrl": "/assets/images/testapp.png",
  "url": "https://example.com",
  "authUrl": "/signin/hat",
  "browser": true,
  "category": "app",
  "setup": true,
  "loginAvailable": true
});

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === this.DONE) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://dex.hubofallthings.com/api/users/update-application?hatFilter=test.hubat.net&cluster=hubat.net");
xhr.setRequestHeader("x-auth-token", "ACCESS_TOKEN");
xhr.setRequestHeader("content-type", "application/json");

xhr.send(data);
<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://dex.hubofallthings.com/api/users/update-application?hatFilter=test.hubat.net&cluster=hubat.net",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"title\":\"TestApp\",\"namespace\":\"testing\",\"description\":\"Test Application\",\"logoUrl\":\"/assets/images/testapp.png\",\"url\":\"https://example.com\",\"authUrl\":\"/signin/hat\",\"browser\":true,\"category\":\"app\",\"setup\":true,\"loginAvailable\":true}",
  CURLOPT_HTTPHEADER => array(
    "content-type: application/json",
    "x-auth-token: ACCESS_TOKEN"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
import requests

url = "https://dex.hubofallthings.com/api/users/update-application"

payload = "{\"title\":\"TestApp\",\"namespace\":\"testing\",\"description\":\"Test Application\",\"logoUrl\":\"/assets/images/testapp.png\",\"url\":\"https://example.com\",\"authUrl\":\"/signin/hat\",\"browser\":true,\"category\":\"app\",\"setup\":true,\"loginAvailable\":true}"
headers = {
    'x-auth-token': "ACCESS_TOKEN",
    'content-type': "application/json"
    }

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)
require 'uri'
require 'net/http'

url = URI("https://dex.hubofallthings.com/api/users/update-application?hatFilter=test.hubat.net&cluster=hubat.net")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["x-auth-token"] = 'ACCESS_TOKEN'
request["content-type"] = 'application/json'
request.body = "{\"title\":\"TestApp\",\"namespace\":\"testing\",\"description\":\"Test Application\",\"logoUrl\":\"/assets/images/testapp.png\",\"url\":\"https://example.com\",\"authUrl\":\"/signin/hat\",\"browser\":true,\"category\":\"app\",\"setup\":true,\"loginAvailable\":true}"

response = http.request(request)
puts response.read_body