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 query to twimlFor, backgroundTrigger, and transitionOut #50

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ coverage/
.grunt

# Editor settings
.vscode
.vscode

.DS_STORE
25 changes: 18 additions & 7 deletions build/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const State = require("./state");
const staticExpiryHelpers_1 = require("./util/staticExpiryHelpers");
const routeCreationHelpers_1 = require("./util/routeCreationHelpers");
const express = require("express");
const bodyParser = require("body-parser");
const path = require("path");
const twilio_1 = require("twilio");
require("./twilioAugments");
const twilio = require("twilio");
const VoiceResponse = twilio.twiml.VoiceResponse;
const twilioWebhook = twilio.webhook;
function default_1(states, config) {
const app = express();
if (config.trustProxy) {
app.set('trust proxy', 1);
}
if (config.session) {
app.use(config.session);
}
app.use(bodyParser.urlencoded({ extended: false }));
const { validate = true } = config.twilio;
app.use(twilio_1.webhook(config.twilio.authToken, { validate: validate }));
app.use(twilioWebhook(config.twilio.authToken, { validate: validate }));
let urlFingerprinter;
if (config.staticFiles) {
const staticFilesMountPath = config.staticFiles.mountPath || "";
Expand All @@ -37,7 +45,11 @@ function default_1(states, config) {
const holdMusicEndpoint = config.staticFiles.holdMusic.endpoint || "/hold-music";
const holdMusicEndpointMounted = path.normalize(staticFilesMountPath + '/' + holdMusicEndpoint);
const holdMusicTwimlFor = config.staticFiles.holdMusic.twimlFor ||
((urlFor) => (new twilio_1.TwimlResponse()).play({ loop: 1000 }, urlFor(path.normalize(staticFilesMountPath + '/' + holdMusicFileUri), { absolute: true })));
((urlFor) => {
const response = new VoiceResponse();
response.play({ loop: 1000 }, urlFor(path.normalize(staticFilesMountPath + '/' + holdMusicFileUri), { absolute: true }));
return response.toString();
});
if (!holdMusicFileUri) {
throw new Error("You must provide a relative uri to your hold music file.");
}
Expand Down Expand Up @@ -80,10 +92,10 @@ function default_1(states, config) {
}
if (State.isNormalState(thisState)) {
app.post(thisState.processTransitionUri, function (req, res, next) {
const nextStatePromise = Promise.resolve(thisState.transitionOut(req.body));
const nextStatePromise = Promise.resolve(thisState.transitionOut(req, req.body));
nextStatePromise
.then(nextState => {
return routeCreationHelpers_1.renderState(nextState, req, urlFingerprinter, undefined);
return routeCreationHelpers_1.renderState(nextState, req, urlFingerprinter, req.body);
})
.then(twiml => { res.send(twiml); })
.catch(next);
Expand All @@ -92,5 +104,4 @@ function default_1(states, config) {
});
return app;
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = default_1;
2 changes: 1 addition & 1 deletion build/lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const debug = require("debug");
const objectValuesEntries_1 = require("./util/objectValuesEntries");
const loggers = {
Expand All @@ -9,5 +10,4 @@ const loggers = {
objectValuesEntries_1.entries(loggers).forEach(([name, logger]) => {
logger.log = console[name].bind(console);
});
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = loggers;
2 changes: 1 addition & 1 deletion build/lib/state.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use strict";
require("./twilioAugments");
Object.defineProperty(exports, "__esModule", { value: true });
function isRoutableState(it) {
return it && it.uri !== undefined;
}
Expand Down
5 changes: 0 additions & 5 deletions build/lib/twilioAugments.js

This file was deleted.

1 change: 1 addition & 0 deletions build/lib/util/objectValuesEntries.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const reduce = Function.bind.call(Function.call, Array.prototype.reduce);
const isEnumerable = Function.bind.call(Function.call, Object.prototype.propertyIsEnumerable);
const concat = Function.bind.call(Function.call, Array.prototype.concat);
Expand Down
16 changes: 8 additions & 8 deletions build/lib/util/routeCreationHelpers.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const logger_1 = require("../logger");
const state_1 = require("../state");
const staticExpiryHelpers_1 = require("./staticExpiryHelpers");
require("../twilioAugments");
const url = require("url");
const state_2 = require("../state");
function resolveBranches(state, inputData) {
function resolveBranches(state, req, inputData) {
if (state_2.isBranchingState(state) && !state_2.isRenderableState(state)) {
return Promise.resolve(state.transitionOut(inputData)).then(nextState => {
return resolveBranches(nextState);
return Promise.resolve(state.transitionOut(req, inputData)).then(nextState => {
return resolveBranches(nextState, req);
});
}
return Promise.resolve(state);
}
exports.resolveBranches = resolveBranches;
function renderState(state, req, furl, inputData) {
const urlForBound = makeUrlFor(req.protocol, req.get('Host'), furl);
const renderableStatePromise = resolveBranches(state, inputData);
const renderableStatePromise = resolveBranches(state, req, inputData);
const inputToRenderWith = state_2.isRenderableState(state) ? inputData : undefined;
const couldNotFindRenderableStateError = Symbol();
return renderableStatePromise.then(stateToRender => {
const stateName = state_1.stateToString(stateToRender);
if (state_2.isAsynchronousState(stateToRender)) {
logger_1.default.info("Began asynchronous processing for " + stateName);
stateToRender.backgroundTrigger(urlForBound, inputToRenderWith);
stateToRender.backgroundTrigger(urlForBound, req, inputToRenderWith);
}
logger_1.default.info("Produced twiml for " + stateName);
return stateToRender.twimlFor(urlForBound, inputToRenderWith);
return stateToRender.twimlFor(urlForBound, req, inputToRenderWith);
}, (e) => {
throw { type: couldNotFindRenderableStateError, origError: e };
}).catch((e) => {
Expand All @@ -42,7 +42,7 @@ function renderState(state, req, furl, inputData) {
}
exports.renderState = renderState;
function makeUrlFor(protocol, host, furl) {
return (path, { query, absolute = false, fingerprint } = {}) => {
return (path, { query = {}, absolute = false, fingerprint } = {}) => {
if (fingerprint && query) {
throw new Error("Can't combine fingerprinting with query parameters.");
}
Expand Down
1 change: 1 addition & 0 deletions build/lib/util/staticExpiryHelpers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const url = require("url");
const path = require("path");
const express = require("express");
Expand Down
6 changes: 4 additions & 2 deletions build/test/fixtures/states.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"use strict";
const twilio_1 = require("twilio");
const emptyTwimlFn = () => new twilio_1.TwimlResponse();
Object.defineProperty(exports, "__esModule", { value: true });
const twilio = require("twilio");
const VoiceResponse = twilio.twiml.VoiceResponse;
const emptyTwimlFn = () => (new VoiceResponse()).toString();
exports.d = {
name: "d",
twimlFor: emptyTwimlFn
Expand Down
1 change: 1 addition & 0 deletions build/test/integration/errorHandlingSpec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const request = require("supertest");
const _1 = require("../../lib/");
describe("error handling (at component integration points)", () => {
Expand Down
1 change: 1 addition & 0 deletions build/test/integration/holdMusicEndpointSpec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const request = require("supertest");
const _1 = require("../../lib/");
Expand Down
16 changes: 13 additions & 3 deletions build/test/integration/requestValidationSpec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const crypto = require("crypto");
const R = require("ramda");
const request = require("supertest");
const _1 = require("../../lib/");
const states = [{
Expand All @@ -25,7 +27,7 @@ describe("request signing", () => {
const agent = request.agent(app);
it("should allow signed requests", () => {
const test = agent.post("/");
const testSig = makeDummySignature(fakeToken, test.url, fakeBody);
const testSig = makeSignature(fakeToken, test.url, fakeBody);
return test
.type('form')
.send(fakeBody)
Expand All @@ -37,13 +39,20 @@ describe("request signing", () => {
.post("/")
.expect(403);
});
it('should reject requests with an invalid signature', () => {
const test = agent.post("/");
const invalidSig = makeInvalidSignature(fakeToken, test.url, fakeBody);
return test
.set('X-Twilio-Signature', invalidSig)
.expect(403);
});
});
describe("validate: false", () => {
const app = _1.default(states, { twilio: { authToken: fakeToken, validate: false } });
const agent = request.agent(app);
it("should allow all requests", () => {
const test = agent.post("/");
const testSig = makeDummySignature(fakeToken, test.url, fakeBody);
const testSig = makeSignature(fakeToken, test.url, fakeBody);
const unsignedRequestAllowed = agent
.post("/")
.expect(200);
Expand All @@ -56,10 +65,11 @@ describe("request signing", () => {
});
});
});
function makeDummySignature(authToken, url, body) {
function makeSignature(authToken, url, body) {
const finalUrl = Object.keys(body).sort().reduce((prev, key) => {
return prev + key + body[key];
}, url);
return crypto.createHmac('sha1', authToken)
.update(new Buffer(finalUrl, 'utf-8')).digest('base64');
}
const makeInvalidSignature = R.pipe(makeSignature, R.split(''), R.map((c) => String.fromCharCode(c.charCodeAt(0) + 1)), R.join(''));
Loading