mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
closes #12033 - Added webhooks schemas and definitions. - Added validation checking if integration_id is present when using session auth. This is needed to prevent orphan webhooks. - Integrated webhook schemas into frame's validation layer. - Added isLowerCase ajv keyword support. This is needed to be able to do isLowerCase validation using JSON Schema for webhooks.
170 lines
6.8 KiB
JavaScript
170 lines
6.8 KiB
JavaScript
const should = require('should');
|
|
const supertest = require('supertest');
|
|
const testUtils = require('../../../../utils');
|
|
const config = require('../../../../../core/shared/config');
|
|
const localUtils = require('./utils');
|
|
|
|
const ghost = testUtils.startGhost;
|
|
|
|
describe('Webhooks API (canary)', function () {
|
|
let request;
|
|
|
|
before(function () {
|
|
return ghost()
|
|
.then(function () {
|
|
request = supertest.agent(config.get('url'));
|
|
})
|
|
.then(function () {
|
|
return localUtils.doAuth(request, 'api_keys', 'webhooks');
|
|
});
|
|
});
|
|
|
|
it('Can create a webhook using integration', function () {
|
|
let webhookData = {
|
|
event: 'test.create',
|
|
target_url: 'http://example.com/webhooks/test/extra/canary',
|
|
integration_id: 'ignore_me',
|
|
name: 'test',
|
|
secret: 'thisissecret',
|
|
api_version: 'v3'
|
|
};
|
|
|
|
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
|
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
|
|
.send({webhooks: [webhookData]})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(201)
|
|
.then((res) => {
|
|
should.not.exist(res.headers['x-cache-invalidate']);
|
|
const jsonResponse = res.body;
|
|
|
|
should.exist(jsonResponse);
|
|
should.exist(jsonResponse.webhooks);
|
|
should.exist(jsonResponse.webhooks[0].event);
|
|
should.exist(jsonResponse.webhooks[0].target_url);
|
|
|
|
jsonResponse.webhooks[0].event.should.eql('test.create');
|
|
jsonResponse.webhooks[0].target_url.should.eql('http://example.com/webhooks/test/extra/canary');
|
|
jsonResponse.webhooks[0].integration_id.should.eql(testUtils.DataGenerator.Content.api_keys[0].id);
|
|
jsonResponse.webhooks[0].name.should.eql('test');
|
|
jsonResponse.webhooks[0].secret.should.eql('thisissecret');
|
|
jsonResponse.webhooks[0].api_version.should.eql('v3');
|
|
|
|
localUtils.API.checkResponse(jsonResponse.webhooks[0], 'webhook');
|
|
});
|
|
});
|
|
|
|
it('Fails validation for when integration_id is missing', function () {
|
|
let webhookData = {
|
|
event: 'test.create',
|
|
target_url: 'http://example.com/webhooks/test/extra/1',
|
|
name: 'test',
|
|
secret: 'thisissecret',
|
|
api_version: 'v2'
|
|
};
|
|
|
|
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({webhooks: [webhookData]})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(422);
|
|
});
|
|
|
|
it('Fails validation for non-lowercase event name', function () {
|
|
let webhookData = {
|
|
event: 'tEst.evenT',
|
|
target_url: 'http://example.com/webhooks/test/extra/1',
|
|
name: 'test',
|
|
secret: 'thisissecret',
|
|
api_version: 'v2'
|
|
};
|
|
|
|
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({webhooks: [webhookData]})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(422);
|
|
});
|
|
|
|
it('Fails validation when required fields are not present', function () {
|
|
let webhookData = {
|
|
api_version: 'v2',
|
|
integration_id: 'dummy'
|
|
};
|
|
|
|
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({webhooks: [webhookData]})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(422);
|
|
});
|
|
|
|
it('Integration cannot edit or delete other integration\'s webhook', function () {
|
|
let createdIntegration;
|
|
let createdWebhook;
|
|
|
|
return Promise.resolve()
|
|
.then(() => {
|
|
return request.post(localUtils.API.getApiQuery('integrations/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
integrations: [{
|
|
name: 'Rubbish Integration Name'
|
|
}]
|
|
})
|
|
.expect(201)
|
|
.then(({body}) => {
|
|
[createdIntegration] = body.integrations;
|
|
|
|
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
|
.set('Origin', config.get('url'))
|
|
.send({
|
|
webhooks: [{
|
|
name: 'Testing',
|
|
event: 'site.changed',
|
|
target_url: 'https://example.com/rebuild',
|
|
integration_id: createdIntegration.id
|
|
}]
|
|
})
|
|
.expect(201);
|
|
});
|
|
})
|
|
.then(({body}) => {
|
|
[createdWebhook] = body.webhooks;
|
|
|
|
return request.put(localUtils.API.getApiQuery(`webhooks/${createdWebhook.id}/`))
|
|
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
|
|
.send({
|
|
webhooks: [{
|
|
name: 'Edit Test',
|
|
event: 'subscriber.added',
|
|
target_url: 'https://example.com/new-subscriber'
|
|
}]
|
|
})
|
|
.expect(403);
|
|
})
|
|
.then(() => {
|
|
return request.del(localUtils.API.getApiQuery(`webhooks/${createdWebhook.id}/`))
|
|
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[0])}`)
|
|
.expect(403);
|
|
});
|
|
});
|
|
|
|
it('Cannot edit webhooks using content api keys', function () {
|
|
let webhookData = {
|
|
event: 'post.create',
|
|
target_url: 'http://example.com/webhooks/test/extra/2'
|
|
};
|
|
|
|
return request.post(localUtils.API.getApiQuery('webhooks/'))
|
|
.set('Authorization', `Ghost ${localUtils.getValidAdminToken('/canary/admin/', testUtils.DataGenerator.Content.api_keys[1])}`)
|
|
.send({webhooks: [webhookData]})
|
|
.expect('Content-Type', /json/)
|
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
|
.expect(401);
|
|
});
|
|
});
|