Skip to content

Commit

Permalink
Merge pull request #79 from steve-bate/base-url
Browse files Browse the repository at this point in the history
Added support for base URL setting.
  • Loading branch information
wmurphyrd committed Jan 18, 2023
2 parents 1195b14 + bb82970 commit b84c7f4
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 26 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,9 @@
## Unreleased

### Added

* new `baseUrl` config option that allows you to specify server origin instead of `domain` which specifies the host but assumes https protocol

## v4.1.2 (2023-01-06)

### Changed
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -148,6 +148,7 @@ Option | Description
**Required** |
name | String. Name of your app to list in nodeinfo
version | String. Version of your app to list in nodeinfo
baseUrl | String. Server URL origin. Also used as URI prefix. Should be the public-facing URL when using a reverse proxy. Overrides `domain` if set
domain | String. Hostname for your app
actorParam | String. Express route parameter used for actor name
objectParam | String. Express route parameter used for object id
Expand Down
30 changes: 19 additions & 11 deletions index.js
Expand Up @@ -24,7 +24,15 @@ module.exports = function (settings) {
}
}
apex.settings = settings
apex.domain = settings.domain
if (settings.baseUrl !== undefined) {
apex.baseUrl = settings.baseUrl
const url = new URL(apex.baseUrl)
apex.domain = url.host
} else {
// Assumes settings.domain is set (backward-compatible)
apex.baseUrl = `https://${settings.domain}`
apex.domain = settings.domain
}
apex.context = settings.context
? pub.consts.ASContext.concat(settings.context)
: pub.consts.ASContext
Expand All @@ -42,16 +50,16 @@ module.exports = function (settings) {
apex.offlineMode = settings.offlineMode
apex.requestTimeout = settings.requestTimeout ?? 5000
apex.utils = {
usernameToIRI: apex.idToIRIFactory(apex.domain, settings.routes.actor, apex.actorParam),
objectIdToIRI: apex.idToIRIFactory(apex.domain, settings.routes.object, apex.objectParam),
activityIdToIRI: apex.idToIRIFactory(apex.domain, settings.routes.activity, apex.activityParam),
userCollectionIdToIRI: apex.userAndIdToIRIFactory(apex.domain, settings.routes.collections, apex.actorParam, apex.collectionParam),
nameToActorStreams: apex.nameToActorStreamsFactory(apex.domain, settings.routes, apex.actorParam),
nameToBlockedIRI: apex.idToIRIFactory(apex.domain, settings.routes.blocked, apex.actorParam),
nameToRejectedIRI: apex.idToIRIFactory(apex.domain, settings.routes.rejected, apex.actorParam),
nameToRejectionsIRI: apex.idToIRIFactory(apex.domain, settings.routes.rejections, apex.actorParam),
idToActivityCollections: apex.idToActivityCollectionsFactory(apex.domain, settings.routes, apex.activityParam),
iriToCollectionInfo: apex.iriToCollectionInfoFactory(apex.domain, settings.routes, apex.actorParam, apex.activityParam, apex.collectionParam)
usernameToIRI: apex.idToIRIFactory(apex.baseUrl, settings.routes.actor, apex.actorParam),
objectIdToIRI: apex.idToIRIFactory(apex.baseUrl, settings.routes.object, apex.objectParam),
activityIdToIRI: apex.idToIRIFactory(apex.baseUrl, settings.routes.activity, apex.activityParam),
userCollectionIdToIRI: apex.userAndIdToIRIFactory(apex.baseUrl, settings.routes.collections, apex.actorParam, apex.collectionParam),
nameToActorStreams: apex.nameToActorStreamsFactory(apex.baseUrl, settings.routes, apex.actorParam),
nameToBlockedIRI: apex.idToIRIFactory(apex.baseUrl, settings.routes.blocked, apex.actorParam),
nameToRejectedIRI: apex.idToIRIFactory(apex.baseUrl, settings.routes.rejected, apex.actorParam),
nameToRejectionsIRI: apex.idToIRIFactory(apex.baseUrl, settings.routes.rejections, apex.actorParam),
idToActivityCollections: apex.idToActivityCollectionsFactory(apex.baseUrl, settings.routes, apex.activityParam),
iriToCollectionInfo: apex.iriToCollectionInfoFactory(apex.baseUrl, settings.routes, apex.actorParam, apex.activityParam, apex.collectionParam)
}

function onFinishedHandler (err, res) {
Expand Down
4 changes: 2 additions & 2 deletions net/well-known.js
Expand Up @@ -28,11 +28,11 @@ function respondNodeInfoLocation (req, res, next) {
links: [
{
rel: 'http://nodeinfo.diaspora.software/ns/schema/2.1',
href: `https://${apex.domain}/nodeinfo/2.1`
href: `${apex.baseUrl}/nodeinfo/2.1`
},
{
rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0',
href: `https://${apex.domain}/nodeinfo/2.0`
href: `${apex.baseUrl}/nodeinfo/2.0`
}
]
})
Expand Down
26 changes: 13 additions & 13 deletions pub/utils.js
Expand Up @@ -91,7 +91,7 @@ function actorIdFromActivity (activity) {
return actor.id
}

function iriToCollectionInfoFactory (domain, routes, pActor, pActivity, pCollection) {
function iriToCollectionInfoFactory (baseUrl, routes, pActor, pActivity, pCollection) {
pActor = `:${pActor}`
pActivity = `:${pActivity}`
pCollection = `:${pCollection}`
Expand All @@ -100,15 +100,15 @@ function iriToCollectionInfoFactory (domain, routes, pActor, pActivity, pCollect
let pattern = this.settings.routes.collections
const isActorFirst = pattern.indexOf(pActor) < pattern.indexOf(pCollection)
pattern = pattern.replace(pActor, '([^/]+)').replace(pCollection, '([^/]+)')
const re = new RegExp(`^https://${this.domain}${pattern}$`)
const re = new RegExp(`^${baseUrl}${pattern}$`)
tests.push(iri => {
const match = re.exec(iri)?.slice(1)
return match && { name: 'collections', actor: match[+!isActorFirst], id: match[+isActorFirst] }
})
// standard actor streams
actorStreamNames.forEach(name => {
const pattern = this.settings.routes[name].replace(pActor, '([^/]+)')
const re = new RegExp(`^https://${this.domain}${pattern}$`)
const re = new RegExp(`^${baseUrl}${pattern}$`)
tests.push(iri => {
const actor = re.exec(iri)?.[1]
return actor && { name, actor }
Expand All @@ -117,7 +117,7 @@ function iriToCollectionInfoFactory (domain, routes, pActor, pActivity, pCollect
// activity object streams
activityStreamNames.forEach(name => {
const pattern = this.settings.routes[name].replace(pActivity, '([^/]+)')
const re = new RegExp(`^https://${this.domain}${pattern}$`)
const re = new RegExp(`^${baseUrl}${pattern}$`)
tests.push(iri => {
const activity = re.exec(iri)?.[1]
return activity && { name, activity }
Expand Down Expand Up @@ -201,24 +201,24 @@ function stringifyPublicJSONLD (obj) {
return JSON.stringify(obj, skipPrivate)
}

function idToIRIFactory (domain, route, param) {
function idToIRIFactory (baseUrl, route, param) {
const colonParam = `:${param}`
return id => {
if (!id) {
id = this.store.generateId()
}
return `https://${domain}${route.replace(colonParam, id)}`.toLowerCase()
return `${baseUrl}${route.replace(colonParam, id)}`.toLowerCase()
}
}

function userAndIdToIRIFactory (domain, route, userParam, param) {
function userAndIdToIRIFactory (baseUrl, route, userParam, param) {
param = `:${param}`
userParam = `:${userParam}`
return (user, id) => {
if (!id) {
id = this.store.generateId()
}
return `https://${domain}${route.replace(param, id).replace(userParam, user)}`.toLowerCase()
return `${baseUrl}${route.replace(param, id).replace(userParam, user)}`.toLowerCase()
}
}

Expand All @@ -229,7 +229,7 @@ function isLocalCollection (object) {
}

function isLocalIRI (id) {
return id.startsWith(`https://${this.domain}`)
return id.startsWith(this.baseUrl)
}

function isPublic (object) {
Expand Down Expand Up @@ -267,11 +267,11 @@ function mergeJSONLD (target, source) {
return merge(target, source, overwriteArrays)
}

function nameToActorStreamsFactory (domain, routes, actorParam) {
function nameToActorStreamsFactory (baseUrl, routes, actorParam) {
const colonParam = `:${actorParam}`
const streamTemplates = {}
actorStreamNames.forEach(s => {
streamTemplates[s] = `https://${domain}${routes[s]}`
streamTemplates[s] = `${baseUrl}${routes[s]}`
})
return name => {
const streams = {}
Expand All @@ -282,11 +282,11 @@ function nameToActorStreamsFactory (domain, routes, actorParam) {
}
}

function idToActivityCollectionsFactory (domain, routes, activityParam) {
function idToActivityCollectionsFactory (baseUrl, routes, activityParam) {
const colonParam = `:${activityParam}`
const streamTemplates = {}
activityStreamNames.forEach(s => {
streamTemplates[s] = `https://${domain}${routes[s]}`
streamTemplates[s] = `${baseUrl}${routes[s]}`
})
return id => {
const streams = {}
Expand Down
51 changes: 51 additions & 0 deletions spec/unit/apex.spec.js
@@ -0,0 +1,51 @@
/* global describe, it, expect */

const ActivitypubExpress = require('../../index')

const routes = {
actor: '/u/:actor',
object: '/o/:id',
activity: '/s/:id',
inbox: '/inbox/:actor',
outbox: '/outbox/:actor',
followers: '/followers/:actor',
following: '/following/:actor',
liked: '/liked/:actor',
shares: '/s/:id/shares',
likes: '/s/:id/likes',
collections: '/u/:actor/c/:id',
blocked: '/u/:actor/blocked',
rejections: '/u/:actor/rejections',
rejected: '/u/:actor/rejected',
nodeinfo: '/nodeinfo'
}

describe('apex', function () {
it('should use base URL if set and no domain', function () {
const apex = ActivitypubExpress({
baseUrl: 'https://localhost',
routes
})
expect(apex.domain).toBe('localhost')
expect(apex.baseUrl).toBe('https://localhost')
})

it('should use domain if set and no base URL', function () {
const apex = ActivitypubExpress({
domain: 'somedomain:4321',
routes
})
expect(apex.domain).toBe('somedomain:4321')
expect(apex.baseUrl).toBe('https://somedomain:4321')
})

it('should prefer baseURL if domain is also set', function () {
const apex = ActivitypubExpress({
domain: 'somedomain',
baseUrl: 'https://someotherdomain:9876',
routes
})
expect(apex.domain).toBe('someotherdomain:9876')
expect(apex.baseUrl).toBe('https://someotherdomain:9876')
})
})

0 comments on commit b84c7f4

Please sign in to comment.