const {
agentProvider,
fixtureManager,
mockManager,
dbUtils,
configUtils
} = require('../../utils/e2e-framework');
const models = require('../../../core/server/models');
const assert = require('assert/strict');
const urlUtils = require('../../../core/shared/url-utils');
const nock = require('nock');
const jobsService = require('../../../core/server/services/mentions-jobs');
const DomainEvents = require('@tryghost/domain-events');
async function allSettled() {
await jobsService.allSettled();
await DomainEvents.allSettled();
}
describe('Webmentions (receiving)', function () {
let agent;
before(async function () {
agent = await agentProvider.getWebmentionsAPIAgent();
await fixtureManager.init('posts');
});
beforeEach(async function () {
await allSettled();
mockManager.disableNetwork();
mockManager.mockLabsEnabled('webmentions');
});
afterEach(async function () {
await allSettled();
mockManager.restore();
await dbUtils.truncate('brute');
});
it('can receive a webmention', async function () {
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article/');
const html = `
Test Page
`;
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href,
withExtension: true // test payload recorded
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article/'});
assert(mention);
assert.equal(mention.get('target'), urlUtils.getSiteUrl() + 'integrations/');
assert.ok(mention.get('resource_id'));
assert.equal(mention.get('resource_type'), 'post');
assert.equal(mention.get('source_title'), 'Test Page');
assert.equal(mention.get('source_excerpt'), 'Test description');
assert.equal(mention.get('source_author'), 'John Doe');
assert.equal(mention.get('payload'), JSON.stringify({
withExtension: true
}));
});
it('will update a mentions source metadata', async function () {
const targetUrl = new URL(urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/update-mention-test-1/');
testCreatingTheMention: {
const html = `
Test Page
`;
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-1/'});
assert(mention);
assert.equal(mention.get('source_title'), 'Test Page');
assert.equal(mention.get('source_excerpt'), 'Test description');
assert.equal(mention.get('source_author'), 'John Doe');
break testCreatingTheMention;
}
nock.cleanAll();
testUpdatingTheMention: {
const html = `
New Title
`;
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-1/'});
assert(mention);
assert.equal(mention.get('source_title'), 'New Title');
assert.equal(mention.get('source_excerpt'), 'New Description');
assert.equal(mention.get('source_author'), 'big man with a beard');
break testUpdatingTheMention;
}
});
it('will delete a mention when the target in Ghost was deleted', async function () {
const post = await models.Post.findOne({id: fixtureManager.get('posts', 0).id});
const targetUrl = new URL(urlUtils.getSiteUrl() + post.get('slug') + '/');
const sourceUrl = new URL('http://testpage.com/update-mention-test-2/');
const html = `
Test Page
`;
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
testCreatingTheMention: {
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-2/'});
assert(mention);
assert.equal(mention.get('resource_id'), post.id);
assert.equal(mention.get('source_title'), 'Test Page');
assert.equal(mention.get('source_excerpt'), 'Test description');
assert.equal(mention.get('source_author'), 'John Doe');
break testCreatingTheMention;
}
// Move post to draft and mark page as 404
await models.Post.edit({status: 'draft'}, {id: post.id});
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(404);
testUpdatingTheMention: {
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-2/'});
assert(mention);
// Check resource id was not cleared
assert.equal(mention.get('resource_id'), post.id);
// Check deleted
assert.equal(mention.get('deleted'), true);
break testUpdatingTheMention;
}
});
it('can receive a webmention to homepage', async function () {
const targetUrl = new URL(urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article-2/');
const html = `
Test Page
`;
nock(targetUrl.origin)
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
assert(mention);
assert.equal(mention.get('target'), urlUtils.getSiteUrl());
assert.ok(!mention.get('resource_id'));
assert.equal(mention.get('resource_type'), null);
assert.equal(mention.get('source_title'), 'Test Page');
assert.equal(mention.get('source_excerpt'), 'Test description');
assert.equal(mention.get('source_author'), 'John Doe');
assert.equal(mention.get('payload'), JSON.stringify({}));
});
it('can verify a webmention link', async function () {
const targetUrl = new URL(urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article-2/');
const html = `
Test Pageyour cool website mentioned
`;
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
assert(mention);
assert.equal(mention.get('verified'), true);
});
it('can verify a webmention link to post', async function () {
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article-3/');
const html = `
Test Pageyour cool website mentioned
`;
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: sourceUrl.href});
assert(mention);
assert.equal(mention.get('verified'), true);
});
it('can verify a webmention link to post with tracking parameters', async function () {
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article-4/');
const html = `
Test Pageyour cool website mentioned
`;
nock(targetUrl.origin)
.persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: sourceUrl.href});
assert(mention);
assert.equal(mention.get('verified'), true);
});
it('marks as unverified if url not present on source', async function () {
const targetUrl = new URL('html-ipsum', urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article-not-present/');
const html = `
Test Pageyour cool website mentioned
`;
nock(targetUrl.origin).persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: sourceUrl.toString()});
assert(mention);
assert.equal(mention.get('verified'), false);
});
it('can verify a webmention link', async function () {
const targetUrl = new URL(urlUtils.getSiteUrl());
const sourceUrl = new URL('http://testpage.com/external-article-2/');
const html = `
Test Page
`;
nock(targetUrl.origin).persist()
.head(targetUrl.pathname)
.reply(200);
nock(sourceUrl.origin)
.persist()
.get(sourceUrl.pathname)
.reply(200, html, {'Content-Type': 'text/html'});
await agent.post('/receive')
.body({
source: sourceUrl.href,
target: targetUrl.href
})
.expectStatus(202);
await allSettled();
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
assert(mention);
assert.equal(mention.get('verified'), true);
});
it('can verify a webmention