Introduction

Sauron is the GraphQL API your application’s server will call to request the data you seek using the data key.

Check out the GraphQL Schema Reference to see details on all Queries, Mutations, Types and their descriptions.

Sauron Helper Packages

We provide packages that makes it super easy to interact with the Sauron API. They completely abstract away the complexity of authentication and interacting with the GraphQL APIs.

Installation

npm i -g @gandalf-network/eyeofsauron

eyeofsauron generate

This will generate an eyeofsauron folder in your project root directory.

Usage

Import the package

// Typescript
import Eye, { Source } from './eyeofsauron';
// ESModules
import Eye, { Source } from './eyeofsauron/index.js';
// CommonJS
const Eye = require('./eyeofsauron').default
const { Source } = require('./eyeofsauron');

Get Activity

const eye = new Eye({privateKey: process.env.PRIVATE_KEY})

const { data } = await eye.getActivity({dataKey: dataKey,  source: Source.Amazon, limit: 100, page: 2})

Get Traits

const { data: traits } = await eye.getTraits({
    dataKey: dataKey,
    source: Source.UBER,
    labels: [TraitLabel.RATING, TraitLabel.TRIP_COUNT],
})

Read more on Github.


Roll Your Own

Every request to the Sauron API needs to be authenticated using your privateKey. This is required to validate that the data request is truly coming from your application.

The packages above handle all of this authentication stuff automagically! You might want to consider using them instead.
1

Prepare the signature

Start by creating a digital signature of your request’s body. You’ll need to hash the body of your request using SHA-256 and then sign the hash with ECDSA using your privateKey.

2

Encode the signature

After signing, encode the digital signature using Base64.

3

Add signature header

Add the Base64-encoded signature to the request’s headers with the key X-Gandalf-Signature.

Securing your privateKey is extremely important. All requests to Sauron should be made server-side.

See example code snippets:

import base64
import hashlib
import json
import ecdsa
from ecdsa import SigningKey, VerifyingKey, SECP256k1, BadSignatureError
from graphqlclient import GraphQLClient


# Step 1: Prepare the signature
def prepare_signature(private_key_hex, message):
    sk = SigningKey.from_string(bytes.fromhex(private_key_hex), curve=SECP256k1)
    message_hash = hashlib.sha256(message).digest()
    signature_der = sk.sign_digest(message_hash, sigencode=ecdsa.util.sigencode_der)

    # Encode the signature in base64
    signature_base64 = encode_signature(signature_der)
    return signature_base64

# Step 2: Encode the signature
def encode_signature(signature):
    return base64.b64encode(signature).decode('utf-8')

def verify_signature(public_key_hex, message, signature_base64):
    vk = VerifyingKey.from_string(bytes.fromhex(public_key_hex), curve=SECP256k1)
    message_hash = hashlib.sha256(message.encode()).digest()
    signature_der = base64.b64decode(signature_base64)
    try:
        vk.verify_digest(signature_der, message_hash, sigdecode=ecdsa.util.sigdecode_der)
        return True
    except BadSignatureError:
        return False

private_key_hex = "GANDALF_PRIVATE_KEY"
query = """
    query getActivity($dataKey: String!, $source: Source!, $limit: Int, $page: Int) {
        getActivity(dataKey: $dataKey, source: $source, limit: $limit, page: $page) {
            # ... specify the fields you want to get back
        }
    }
"""

variables = {
    "dataKey": "YOUR_DATA_KEY",
    "source": "YOUR_SOURCE",
    "limit": 10,
    "page": 1
}

request_body = {
    'query': query,
    'variables': variables
}

signature_b64 = prepare_signature(private_key_hex, json.dumps(request_body).encode('utf-8'))
client = GraphQLClient("https://sauron.gandalf.network/public/gql")

# Step 3: Add signature header
client.inject_token(signature_b64,'X-Gandalf-Signature')

# Execute the GraphQL query
result = client.execute(query, variables)
print(result)

Every Query or Mutation in the Sauron GraphQL API is accessible in the helper packages as a function/method. You can read about all Queries, Mutations & Types in the Schema Reference.