Skip to content

Add webhookKey support #1920

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

Merged
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
59 changes: 55 additions & 4 deletions spec/ParseHooks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ app.listen(12345);

describe('Hooks', () => {

it("should have some hooks registered", (done) => {
it("should have no hooks registered", (done) => {
Parse.Hooks.getFunctions().then((res) => {
expect(res.constructor).toBe(Array.prototype.constructor);
done();
Expand All @@ -27,7 +27,7 @@ describe('Hooks', () => {
});
});

it("should have some triggers registered", (done) => {
it("should have no triggers registered", (done) => {
Parse.Hooks.getTriggers().then( (res) => {
expect(res.constructor).toBe(Array.prototype.constructor);
done();
Expand Down Expand Up @@ -291,15 +291,15 @@ describe('Hooks', () => {
console.error(err);
fail("Should not fail calling a function");
done();
})
});
});

it("should run the function on the test server", (done) => {

app.post("/SomeFunctionError", function(req, res) {
res.json({error: {code: 1337, error: "hacking that one!"}});
});
// The function is delete as the DB is dropped between calls
// The function is deleted as the DB is dropped between calls
Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/SomeFunctionError").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
Expand All @@ -317,6 +317,57 @@ describe('Hooks', () => {
});
});

it("should provide X-Parse-Webhook-Key when defined", (done) => {
app.post("/ExpectingKey", function(req, res) {
if (req.get('X-Parse-Webhook-Key') === 'hook') {
res.json({success: "correct key provided"});
} else {
res.json({error: "incorrect key provided"});
}
});

Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKey").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
console.error(err);
fail("Should not fail creating a function");
done();
}).then(function(res){
expect(res).toBe("correct key provided");
done();
}, (err) => {
console.error(err);
fail("Should not fail calling a function");
done();
});
});

it("should not pass X-Parse-Webhook-Key if not provided", (done) => {
setServerConfiguration(Object.assign({}, defaultConfiguration, { webhookKey: undefined }));
app.post("/ExpectingKeyAlso", function(req, res) {
if (req.get('X-Parse-Webhook-Key') === 'hook') {
res.json({success: "correct key provided"});
} else {
res.json({error: "incorrect key provided"});
}
});

Parse.Hooks.createFunction("SOME_TEST_FUNCTION", hookServerURL+"/ExpectingKeyAlso").then(function(){
return Parse.Cloud.run("SOME_TEST_FUNCTION")
}, (err) => {
console.error(err);
fail("Should not fail creating a function");
done();
}).then(function(res){
fail("Should not succeed calling that function");
done();
}, (err) => {
expect(err.code).toBe(141);
expect(err.message).toEqual("incorrect key provided");
done();
});
});


it("should run the beforeSave hook on the test server", (done) => {
var triggerCount = 0;
Expand Down
1 change: 1 addition & 0 deletions spec/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ var defaultConfiguration = {
dotNetKey: 'windows',
clientKey: 'client',
restAPIKey: 'rest',
webhookKey: 'hook',
masterKey: 'test',
collectionPrefix: 'test_',
fileKey: 'test',
Expand Down
14 changes: 11 additions & 3 deletions src/Controllers/HooksController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as DatabaseAdapter from "../DatabaseAdapter";
import * as triggers from "../triggers";
import * as Parse from "parse/node";
import * as request from "request";
import { logger } from '../logger';

const DefaultHooksCollectionName = "_Hooks";

Expand All @@ -12,9 +13,10 @@ export class HooksController {
_collectionPrefix:string;
_collection;

constructor(applicationId:string, collectionPrefix:string = '') {
constructor(applicationId:string, collectionPrefix:string = '', webhookKey) {
this._applicationId = applicationId;
this._collectionPrefix = collectionPrefix;
this._webhookKey = webhookKey;
this.database = DatabaseAdapter.getDatabaseConnection(this._applicationId, this._collectionPrefix).WithoutValidation();
}

Expand Down Expand Up @@ -79,7 +81,7 @@ export class HooksController {
}

addHookToTriggers(hook) {
var wrappedFunction = wrapToHTTPRequest(hook);
var wrappedFunction = wrapToHTTPRequest(hook, this._webhookKey);
wrappedFunction.url = hook.url;
if (hook.className) {
triggers.addTrigger(hook.triggerName, hook.className, wrappedFunction, this._applicationId)
Expand Down Expand Up @@ -153,7 +155,7 @@ export class HooksController {
};
}

function wrapToHTTPRequest(hook) {
function wrapToHTTPRequest(hook, key) {
return (req, res) => {
let jsonBody = {};
for (var i in req) {
Expand All @@ -174,6 +176,12 @@ function wrapToHTTPRequest(hook) {
body: JSON.stringify(jsonBody)
};

if (key) {
jsonRequest.headers['X-Parse-Webhook-Key'] = key;
} else {
logger.warn('Making outgoing webhook request without webhookKey being set!');
}

request.post(hook.url, jsonRequest, function (err, httpResponse, body) {
var result;
if (body) {
Expand Down
4 changes: 3 additions & 1 deletion src/ParseServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class ParseServer {
javascriptKey,
dotNetKey,
restAPIKey,
webhookKey,
fileKey = 'invalid-file-key',
facebookAppIds = [],
enableAnonymousUsers = true,
Expand Down Expand Up @@ -166,7 +167,7 @@ class ParseServer {
const filesController = new FilesController(filesControllerAdapter, appId);
const pushController = new PushController(pushControllerAdapter, appId);
const loggerController = new LoggerController(loggerControllerAdapter, appId);
const hooksController = new HooksController(appId, collectionPrefix);
const hooksController = new HooksController(appId, collectionPrefix, webhookKey);
const userController = new UserController(emailControllerAdapter, appId, { verifyUserEmails });
const liveQueryController = new LiveQueryController(liveQuery);
const cacheController = new CacheController(cacheControllerAdapter, appId);
Expand All @@ -179,6 +180,7 @@ class ParseServer {
javascriptKey: javascriptKey,
dotNetKey: dotNetKey,
restAPIKey: restAPIKey,
webhookKey: webhookKey,
fileKey: fileKey,
facebookAppIds: facebookAppIds,
cacheController: cacheController,
Expand Down