Skip to content
Abbas Razaghpanah edited this page Mar 25, 2015 · 4 revisions

Centinel server API specification

  • version: 0.1.0
  • date: March 25, 2015

Version

GET /version

  • Get the latest recommended version of Centinel
➜  ~  curl -i http://127.0.0.1:8082/version

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 20
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "version": 1.1
}

Register

POST /register

  • Create a new user
  • Ex - username: foo and password: bar
➜  ~  curl -i -H "Content-Type: application/json" -X POST -d '{"username":"foo", "password":"bar"}' http://127.0.0.1:8082/register

HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 25
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "status": "success"
}
  • Creating the same user again
➜  ~  curl -i -H "Content-Type: application/json" -X POST -d '{"username":"foo", "password":"bar"}' http://127.0.0.1:8082/register

HTTP/1.0 400 BAD REQUEST
Content-Type: application/json
Content-Length: 28
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "error": "Bad request"
}

Results

GET /results

  • Download all the result files.
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/results

Content-Type: application/json
Content-Length: 1136659
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 02 Sep 2014 03:05:53 GMT

{
  "results": {
    "result-2014-09-01T22:21:14.306037": {
      "http_request": [
        {...}
      ]
  }
}
        

POST /results

  • Upload a result file
  • Requires authentication
➜  ~  curl -i -u foo:bar -0 -X POST -F files='{"result": {"status": "success"}}' http://127.0.0.1:8082/results

HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 28
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "status": "success"
}
        

Experiments

GET /experiments

  • Get names and file content hash values of experiment files on the server
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/experiments

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 65
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "experiments": {
    "baseline.py": "STF2udEp3WyQk9fYnr3reQ==",
    "scheduler.info": "mZFLkyvTelC5g8XnyQrpOw=="
  }
}

GET /experiments/<experiment>

  • Download <experiment> file
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/experiments/http_request.py

HTTP/1.0 200 OK
Content-Length: 549
Content-Type: text/x-python; charset=utf-8
Last-Modified: Tue, 02 Sep 2014 03:14:54 GMT
Cache-Control: public, max-age=43200
Expires: Tue, 02 Sep 2014 15:16:50 GMT
ETag: "flask-1409627694.0-549-267654249"
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

import centinel.primitives.http as http

from centinel.experiment import Experiment

class HTTPRequestExperiment(Experiment):
    name = "http_request"

    def __init__(self, input_file):
        self.input_file  = input_file
        self.results = []
        self.host = None
        self.path = "/"

    def run(self):
        for line in self.input_file:
            self.host = line.strip()
            self.http_request()

    def http_request(self):
        result = http.get_request(self.host, self.path)
        self.results.append(result)

GET /input_files

  • Get names and file content hash values of experiment input files on the server
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/input_files

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 65
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "inputs": {
    "world.txt": "BdkuwYAd3kf-whlsPmpCLw=="
  }
}

GET /input_files/<input_file>

  • Download <input_file> file
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/input_files/world.txt

HTTP/1.0 200 OK
Content-Length: 549
Content-Type: text/x-python; charset=utf-8
Last-Modified: Tue, 02 Sep 2014 03:14:54 GMT
Cache-Control: public, max-age=43200
Expires: Tue, 02 Sep 2014 15:16:50 GMT
ETag: "flask-1409627694.0-549-267654249"
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

url,rank
google.com,1
facebook.com,2
youtube.com,3
baidu.com,4
yahoo.com,5

Clients

GET /clients

  • Get all clients' basic information (country, AS info, and date last seen)
➜  ~  curl -i http://127.0.0.1:8082/clients

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 77
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "clients": [
    {
      "as_owner": "Some AS Inc.",
      "asn": 12345,
      "country": "US",
      "is_vpn": true,
      "last_seen": "2015-01-01",
      "num": 0
    }
  ]
}

GET /client_details

  • Get all clients' full information
  • Requires admin-level authentication
➜  ~  curl -u admin:password -i http://127.0.0.1:8082/client_details

HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 77
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "clients": [
    {
      "country": "US",
      "date_given_consent": "Thu, 01 Feb 2015 20:00:00 GMT",
      "handle": abcde123,
      "has_given_consent": true,
      "is_vpn": false,
      "last_ip": "1.1.1.0/24",
      "last_seen": "Wed, 01 Feb 2015 21:00:00 GMT",
      "registered_date": "Thu, 01 Jan 2015 00:00:00 GMT",
      "username": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
    }
  ]
}

Miscellaneous

GET /set_ip/<ip_address>

  • Set client IP address as <ip_address>
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/set_ip/1.1.1.1

HTTP/1.0 200 OK
Content-Length: 549
Content-Type: text/x-python; charset=utf-8
Last-Modified: Tue, 02 Sep 2014 03:14:54 GMT
Cache-Control: public, max-age=43200
Expires: Tue, 02 Sep 2014 15:16:50 GMT
ETag: "flask-1409627694.0-549-267654249"
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "status": "success"
}

GET /set_country/<country_code>

  • Set client's ISO 3166-1 2-letter country code as <country_code>
  • Requires authentication
➜  ~  curl -u foo:bar -i -H "Content-Type: application/json"  http://127.0.0.1:8082/set_country/US

HTTP/1.0 200 OK
Content-Length: 549
Content-Type: text/x-python; charset=utf-8
Last-Modified: Tue, 02 Sep 2014 03:14:54 GMT
Cache-Control: public, max-age=43200
Expires: Tue, 02 Sep 2014 15:16:50 GMT
ETag: "flask-1409627694.0-549-267654249"
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "status": "success"
}

GET /geolocate/

  • Get client's ISO 3166-1 2-letter country code using their IP address
➜  ~  curl -i -H "Content-Type: application/json"  http://127.0.0.1:8082/geolocate/

HTTP/1.0 200 OK
Content-Length: 549
Content-Type: text/x-python; charset=utf-8
Last-Modified: Tue, 02 Sep 2014 03:14:54 GMT
Cache-Control: public, max-age=43200
Expires: Tue, 02 Sep 2014 15:16:50 GMT
ETag: "flask-1409627694.0-549-267654249"
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "country": "US",
  "ip": "1.1.1.0/24"
}

GET /geolocate/<ip_address>

  • Get client's ISO 3166-1 2-letter country code using the provided IP address <ip_address>`
➜  ~  curl -i -H "Content-Type: application/json"  http://127.0.0.1:8082/geolocate/1.1.1.1

HTTP/1.0 200 OK
Content-Length: 549
Content-Type: text/x-python; charset=utf-8
Last-Modified: Tue, 02 Sep 2014 03:14:54 GMT
Cache-Control: public, max-age=43200
Expires: Tue, 02 Sep 2014 15:16:50 GMT
ETag: "flask-1409627694.0-549-267654249"
Server: Werkzeug/0.9.6 Python/2.7.5
Date: Tue, 01 Mar 2015 03:00:00 GMT

{
  "country": "US",
  "ip": "1.1.1.0/24"
}