import https from 'https'
import httpSignature from 'http-signature' // npm install http-signature
import ini from 'ini' // npm install ini
const R3_ACCESS_KEY_ID = 'R3_ACCESS_KEY_ID'
const R3_SECRET_ACCESS_KEY = 'R3_SECRET_ACCESS_KEY'
const CREDENTIALS_FILE = '.remoteit/credentials'
const DEFAULT_PROFILE = 'default'
const SIGNATURE_ALGORITHM = 'hmac-sha256'
const SIGNED_HEADERS = '(request-target) host date content-type content-length'
const APPLICATION_JSON = 'application/json'
const GRAPHQL_HOST = 'api.remote.it'
const GRAPHQL_URL = '/graphql/v1'
function getCredentials(profileName = DEFAULT_PROFILE) {
const file = path.resolve(os.homedir(), CREDENTIALS_FILE)
if (!fs.existsSync(file)) throw new Error(`remote.it credentials file not found: ${file}`)
const credentials = ini.parse(fs.readFileSync(file, 'utf-8'))
const profile = Object.entries(credentials).find(([name]) => name.toUpperCase() === profileName.toUpperCase())
if (!profile) throw new Error(`remote.it profile not found: ${profileName}`)
const [_, section] = profile
const keyId = section[R3_ACCESS_KEY_ID]
if (!keyId) throw new Error(`remote.it credentials missing: ${R3_ACCESS_KEY_ID}`)
const secret = section[R3_SECRET_ACCESS_KEY]
if (!secret) throw new Error(`remote.it credentials missing: ${R3_SECRET_ACCESS_KEY}`)
async function graphql(keyId, secret, query, variables) {
const body = JSON.stringify({query, variables})
'Content-Type': APPLICATION_JSON,
'Content-Length': body.length
return new Promise((resolve, reject) => {
const request = https.request(options, response => {
response.on('data', json => resolve(JSON.parse(json)))
httpSignature.sign(request, {
key: Buffer.from(secret, 'base64'),
algorithm: SIGNATURE_ALGORITHM,
headers: SIGNED_HEADERS.split(/\s+/)
request.on('error', error => reject(error))
const query = 'query TestQuery($id: String!) {' +
id: '80:00:00:00:01:02:03:04'
const {keyId, secret} = getCredentials()
const result = await graphql(keyId, secret, query, variables)
console.log(JSON.stringify(result, null, 2))