Skip to content

Commit

Permalink
Merge 4546c02 into 16fee51
Browse files Browse the repository at this point in the history
  • Loading branch information
wmurphyrd committed Nov 11, 2022
2 parents 16fee51 + 4546c02 commit 3dc0d36
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 2 deletions.
1 change: 0 additions & 1 deletion net/security.js
Expand Up @@ -44,7 +44,6 @@ function verifyAuthorization (req, res, next) {
async function verifySignature (req, res, next) {
const apex = req.app.locals.apex
try {
// support for apps not using signature extension to ActivityPub
if (!req.get('authorization') && !req.get('signature')) {
if (req.app.get('env') !== 'development') {
apex.logger.warn('Request rejected: missing http signature')
Expand Down
54 changes: 54 additions & 0 deletions spec/functional/collections.spec.js
Expand Up @@ -24,6 +24,9 @@ describe('collections', function () {
app.get('/followers/:actor', apex.net.followers.get)
app.get('/following/:actor', apex.net.following.get)
app.get('/liked/:actor', apex.net.liked.get)
app.get('/u/:actor/blocked', apex.net.blocked.get)
app.get('/u/:actor/rejected', apex.net.rejected.get)
app.get('/u/:actor/rejections', apex.net.rejections.get)
app.get('/s/:id/shares', apex.net.shares.get)
app.get('/s/:id/likes', apex.net.likes.get)
app.get('/u/:actor/c/:id', apex.net.collections.get)
Expand Down Expand Up @@ -340,5 +343,56 @@ describe('collections', function () {
const rejected = await apex.getRejected(testUser, Infinity, true)
expect(rejected.orderedItems).toEqual(follows.map(a => a.id).reverse())
})
it('blocked c2s endpoint returns collection', async function (done) {
request(app)
.get('/u/test/blocked')
.set('Accept', 'application/activity+json')
.expect(200)
.end(function (err, res) {
const standard = {
'@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
id: 'https://localhost/u/test/blocked',
type: 'OrderedCollection',
totalItems: 0,
first: 'https://localhost/u/test/blocked?page=true'
}
expect(res.body).toEqual(standard)
done(err)
})
})
it('rejected c2s endpoint returns collection', async function (done) {
request(app)
.get('/u/test/rejected')
.set('Accept', 'application/activity+json')
.expect(200)
.end(function (err, res) {
const standard = {
'@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
id: 'https://localhost/u/test/rejected',
type: 'OrderedCollection',
totalItems: 0,
first: 'https://localhost/u/test/rejected?page=true'
}
expect(res.body).toEqual(standard)
done(err)
})
})
it('rejections c2s endpoint returns collection', async function (done) {
request(app)
.get('/u/test/rejections')
.set('Accept', 'application/activity+json')
.expect(200)
.end(function (err, res) {
const standard = {
'@context': ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1'],
id: 'https://localhost/u/test/rejections',
type: 'OrderedCollection',
totalItems: 0,
first: 'https://localhost/u/test/rejections?page=true'
}
expect(res.body).toEqual(standard)
done(err)
})
})
})
})
72 changes: 71 additions & 1 deletion spec/functional/inbox.spec.js
@@ -1,4 +1,6 @@
/* global describe, beforeAll, beforeEach, it, expect, spyOn */
/* global describe, beforeAll, beforeEach, afterAll, it, expect, spyOn */
const crypto = require('crypto')
const httpSignature = require('http-signature')
const request = require('supertest')
const merge = require('deepmerge')
const nock = require('nock')
Expand Down Expand Up @@ -1218,6 +1220,74 @@ describe('inbox', function () {
.expect(200)
})
})
describe('signature verification', function () {
beforeAll(() => {
app.set('env', 'production')
})
afterAll(function () {
app.set('env', 'development')
})
it('rejects missing signature', function () {
return request(app)
.post('/inbox/test')
.set('Content-Type', 'application/activity+json')
.send(activity)
.expect(401)
})
it('rejects invalid signature', function () {
return request(app)
.post('/inbox/test')
.set('Content-Type', 'application/activity+json')
.set('Date', new Date().toUTCString())
.set('Signature', 'keyId="https://localhost/u/test",algorithm="rsa-sha256",headers="(request-target) host date",signature="asfdlajsflkjasklgja="')
.send(activity)
.expect(403)
})
it('handles unverifiable delete', function () {
const act = merge({}, activity)
act.id = 'https://mocked.com/s/abc123'
act.actor = 'https://mocked.com/u/mocked'
act.object = act.actor
act.type = 'Delete'
nock('https://mocked.com')
.get('/u/mocked')
.reply(404)
return request(app)
.post('/inbox/test')
.set('Content-Type', 'application/activity+json')
.set('Date', new Date().toUTCString())
.set('Signature', 'keyId="https://mocked.com/u/mocked",algorithm="rsa-sha256",headers="(request-target) host date",signature="asfdlajsflkjasklgja="')
.send(act)
.expect(200)
})
it('validates valid signature', async function () {
const recip = await apex.createActor('recipient', 'recipient')
await apex.store.saveObject(recip)
const body = apex.stringifyPublicJSONLD(activity)
const headers = {
digest: crypto.createHash('sha256').update(body).digest('base64'),
host: 'localhost'
}
httpSignature.signRequest({
getHeader: k => headers[k.toLowerCase()],
setHeader: (k, v) => (headers[k.toLowerCase()] = v),
method: 'POST',
path: '/inbox/recipient'
}, {
key: testUser._meta.privateKey,
keyId: testUser.id,
headers: ['(request-target)', 'host', 'date', 'digest'],
authorizationHeaderName: 'Signature'
})
const signedReq = request(app)
.post('/inbox/recipient')
.set('Content-Type', 'application/activity+json')
Object.entries(headers).forEach(([k, v]) => signedReq.set(k, v))
return signedReq
.send(body)
.expect(200)
})
})
})
describe('get', function () {
let inbox
Expand Down
7 changes: 7 additions & 0 deletions spec/functional/outbox.spec.js
Expand Up @@ -107,6 +107,13 @@ describe('outbox', function () {
.send({ actor: 'bob', '@context': 'https://www.w3.org/ns/activitystreams' })
.expect(400, 'Invalid activity', done)
})
it('rejects unauthorized requests', function () {
return request(app)
.post('/outbox/test')
.set('Content-Type', 'application/activity+json')
.send(activity)
.expect(403)
})
// activity getTargetActor
it('errors on unknown actor', function (done) {
request(app)
Expand Down
37 changes: 37 additions & 0 deletions spec/unit/utils.spec.js
Expand Up @@ -19,6 +19,43 @@ describe('utils', function () {
beforeEach(function () {
return global.resetDb(apex, client, testUser)
})
describe('hasMeta util', function () {
it('returns false when object does not have metadata', function () {
const obj = { _meta: { collection: [] } }
expect(apex.hasMeta(obj, 'collection', testUser.inbox[0])).toBe(false)
})
})
describe('removeMeta', function () {
it('returns when object does not have the metadata', function () {
const obj = { _meta: { collection: [] } }
expect(apex.removeMeta(obj, 'collection', testUser.inbox[0])).toBe(undefined)
})
it('removes the medata', function () {
const obj = { _meta: { collection: [testUser.inbox[0]] } }
apex.removeMeta(obj, 'collection', testUser.inbox[0])
expect(obj._meta.collection).toEqual([])
})
})
describe('actorIdFromActivity', function () {
it('returns id from object', function () {
expect(apex.actorIdFromActivity({ actor: [{ id: testUser.id }] }))
.toBe(testUser.id)
})
it('returns href from link', function () {
expect(apex.actorIdFromActivity({ actor: [{ type: 'Link', href: [testUser.id] }] }))
.toBe(testUser.id)
})
})
describe('objectIdFromActivity', function () {
it('returns id from object', function () {
expect(apex.objectIdFromActivity({ object: [{ id: testUser.id }] }))
.toBe(testUser.id)
})
it('returns href from link', function () {
expect(apex.objectIdFromActivity({ object: [{ type: 'Link', href: [testUser.id] }] }))
.toBe(testUser.id)
})
})
describe('jsonld processing', function () {
it('handles context arrays with language tag', async function () {
const processed = await apex.fromJSONLD({
Expand Down

0 comments on commit 3dc0d36

Please sign in to comment.