Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add request id and user agent to client headers #737

Merged
merged 1 commit into from
Dec 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions lambda/alexa/smarthome/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/

import { AxiosError } from 'axios';
import config from '#root/config.js';
import log from '#root/log.js';
import OpenHAB from '#openhab/index.js';
import AlexaDirective from './directive.js';
Expand All @@ -22,13 +21,14 @@ import { AlexaError, InvalidDirectiveError } from './errors.js';
/**
* Handles alexa smart home skill request
* @param {Object} request
* @param {Object} context
* @return {Promise}
*/
export const handleRequest = async (request) => {
export const handleRequest = async (request, context) => {
// Initialize directive object
const directive = new AlexaDirective(request.directive);
// Initialize openhab object
const openhab = new OpenHAB(config.openhab, directive.auth.token, AlexaResponse.TIMEOUT);
const openhab = new OpenHAB(context.awsRequestId, directive.auth.token, AlexaResponse.TIMEOUT);

let response;

Expand Down
5 changes: 3 additions & 2 deletions lambda/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ import { handleRequest } from './alexa/smarthome/index.js';
/**
* Defines skill event handler
* @param {Object} event
* @param {Object} context
* @return {Promise}
*/
export const handler = async (event) => {
export const handler = async (event, context) => {
log.info('Received event:', event);

if (event.directive?.header.payloadVersion === '3') {
return handleRequest(event);
return handleRequest(event, context);
}

log.warn('Unsupported event:', event);
Expand Down
16 changes: 11 additions & 5 deletions lambda/openhab/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ import fs from 'node:fs';
import axios from 'axios';
import { HttpsAgent } from 'agentkeepalive';
import { validate as uuidValidate } from 'uuid';
import config from '#root/config.js';
import { ItemType, ItemValue, UnitSymbol } from './constants.js';

const packageInfo = JSON.parse(fs.readFileSync('./package.json'));

/**
* Defines openHAB class
*/
Expand All @@ -30,12 +33,12 @@ export default class OpenHAB {

/**
* Constructor
* @param {Object} config
* @param {String} requestId
* @param {String} token
* @param {Number} timeout
*/
constructor(config, token, timeout) {
this._client = OpenHAB.createClient(config, token, timeout);
constructor(requestId, token, timeout) {
this._client = OpenHAB.createClient(config.openhab, requestId, token, timeout);
}

/**
Expand Down Expand Up @@ -205,16 +208,19 @@ export default class OpenHAB {
/**
* Returns request client
* @param {Object} config
* @param {String} requestId
* @param {String} token
* @param {Number} timeout
* @return {Object}
*/
static createClient(config, token, timeout) {
static createClient(config, requestId, token, timeout) {
const client = axios.create({
baseURL: config.baseURL,
headers: {
common: {
'Cache-Control': 'no-cache'
'Cache-Control': 'no-cache',
'User-Agent': `${packageInfo.name}/${packageInfo.version}`,
'X-Amzn-RequestId': requestId
}
},
httpsAgent: new HttpsAgent({
Expand Down
7 changes: 5 additions & 2 deletions lambda/test/alexa/smarthome.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ use(chaiCustom);

/* eslint-disable mocha/no-setup-in-describe */
describe('Alexa Smart Home Tests', function () {
// set default environment
const context = { awsRequestId: 'request-id' };

let commandStub, updateStub;

beforeEach(function () {
Expand Down Expand Up @@ -56,7 +59,7 @@ describe('Alexa Smart Home Tests', function () {
sinon.stub(OpenHAB.prototype, 'getAllItems').resolves(items);
sinon.stub(OpenHAB.prototype, 'getServerSettings').resolves(settings);
// run test
const response = await handleRequest({ directive });
const response = await handleRequest({ directive }, context);
expect(commandStub.called).to.be.false;
expect(updateStub.called).to.be.false;
expect(response)
Expand Down Expand Up @@ -86,7 +89,7 @@ describe('Alexa Smart Home Tests', function () {
sinon.stub(log, 'error');
}
// run test
const response = await handleRequest({ directive });
const response = await handleRequest({ directive }, context);
expect(commandStub.callCount).to.equal(expected.openhab.commands.length);
expect(commandStub.args.map(([name, value]) => ({ name, value }))).to.deep.equal(expected.openhab.commands);
expect(updateStub.callCount).to.equal(expected.openhab.updates.length);
Expand Down
35 changes: 29 additions & 6 deletions lambda/test/openhab.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,25 @@
import fs from 'node:fs';
import { AxiosError } from 'axios';
import { v4 as uuidv4 } from 'uuid';
import config from '#root/config.js';
import OpenHAB from '#openhab/index.js';

const packageInfo = JSON.parse(fs.readFileSync('./package.json'));

describe('OpenHAB Tests', function () {
// set default environment
const baseURL = 'https://foobar';
const requestId = 'request-id';
const token = 'token';

Check failure

Code scanning / CodeQL

Hard-coded credentials Critical test

The hard-coded value "token" is used as
authorization header
.
const timeout = 42;

let openhab;

beforeEach(function () {
// set stub environment
sinon.stub(config.openhab, 'baseURL').value(baseURL);
// create new openhab instance
openhab = new OpenHAB({ baseURL }, token, timeout);
openhab = new OpenHAB(requestId, token, timeout);
});

afterEach(function () {
Expand All @@ -43,20 +49,37 @@
it('https oauth2 token', async function () {
// set environment
sinon.stub(fs, 'existsSync').returns(false);
nock(baseURL).get('/').matchHeader('Authorization', `Bearer ${token}`).reply(200);
nock(baseURL)
.get('/')
.matchHeader('Authorization', `Bearer ${token}`)
.reply(200)
.on('request', ({ headers }) => {
expect(headers).to.include({
authorization: `Bearer ${token}`,
'user-agent': `${packageInfo.name}/${packageInfo.version}`,
'x-amzn-requestid': requestId
});
});
// run test
await OpenHAB.createClient({ baseURL }, token, timeout).get('/');
await OpenHAB.createClient({ baseURL }, requestId, token, timeout).get('/');
expect(nock.isDone()).to.be.true;
});

it('https basic auth', async function () {
// set environment
const user = 'username';
const pass = 'password';
const token = Buffer.from(`${user}:${pass}`).toString('base64');
sinon.stub(fs, 'existsSync').returns(false);
nock(baseURL).get('/').basicAuth({ user, pass }).reply(200);
nock(baseURL)
.get('/')
.basicAuth({ user, pass })
.reply(200)
.on('request', ({ headers }) => {
expect(headers).to.include({ authorization: `Basic ${token}` });
});
// run test
await OpenHAB.createClient({ baseURL, user, pass }, token, timeout).get('/');
await OpenHAB.createClient({ baseURL, user, pass }, requestId, token, timeout).get('/');
expect(nock.isDone()).to.be.true;
});

Expand All @@ -76,7 +99,7 @@
expect(socket).to.include({ timeout });
});
// run test
await OpenHAB.createClient({ baseURL, certFile, certPass }, token, timeout).get('/');
await OpenHAB.createClient({ baseURL, certFile, certPass }, requestId, token, timeout).get('/');
expect(nock.isDone()).to.be.true;
});

Expand Down
9 changes: 6 additions & 3 deletions lambda/test/skill.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import esmock from 'esmock';
import log from '#root/log.js';

describe('Skill Event Tests', function () {
// set default environment
const context = { awsRequestId: 'request-id' };

let smarthomeStub, skill;

beforeEach(async function () {
Expand Down Expand Up @@ -47,9 +50,9 @@ describe('Skill Event Tests', function () {
}
};
// run test
await skill.handler(event);
await skill.handler(event, context);
expect(smarthomeStub.called).to.be.true;
expect(smarthomeStub.firstCall.args).to.deep.equal([event]);
expect(smarthomeStub.firstCall.args).to.deep.equal([event, context]);
});

it('payload version 2', async function () {
Expand All @@ -63,7 +66,7 @@ describe('Skill Event Tests', function () {
};
const logWarn = sinon.stub(log, 'warn');
// run test
await skill.handler(event);
await skill.handler(event, context);
expect(smarthomeStub.called).to.be.false;
expect(logWarn.called).to.be.true;
expect(logWarn.firstCall.args).to.deep.equal(['Unsupported event:', event]);
Expand Down
Loading