Merge pull request #88 from immers-space/admin-access
admin api key and user profile attachments
This commit is contained in:
commit
8e9f698140
5 changed files with 66 additions and 7 deletions
|
@ -1,5 +1,11 @@
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Optional `ADMIN_SECRET` env var enables C2S API access with the given bearer token
|
||||||
|
* Optional `USE_ATTACHMENTS` env var to add Mastodon-style user attributes to groups
|
||||||
|
|
||||||
|
## v1.3.0 (2022-12-29)
|
||||||
|
|
||||||
* Change production swarm setup to use nginx for ssl-terminating reverse proxy due to renewal issues with @small-tech/auto-encrypt in in swarm mode
|
* Change production swarm setup to use nginx for ssl-terminating reverse proxy due to renewal issues with @small-tech/auto-encrypt in in swarm mode
|
||||||
* Change swarm node labeling scheme to allow consolidation of all services on one machine
|
* Change swarm node labeling scheme to allow consolidation of all services on one machine
|
||||||
* Update activitypub-express to fix [a spec compliance issue](https://github.com/immers-space/activitypub-express/pull/83)
|
* Update activitypub-express to fix [a spec compliance issue](https://github.com/immers-space/activitypub-express/pull/83)
|
||||||
|
|
|
@ -70,7 +70,9 @@ Additional values can be set in `.env` file
|
||||||
|
|
||||||
| Setting | Description |
|
| Setting | Description |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
|
| ADMIN_SECRET | Sets a bearer token with full C2S API access for all guppe actors
|
||||||
| PROXY_MODE | Enable use behind an SSL-terminating proxy or load balancer, serves over http instead of https and sets Express `trust proxy` setting to the value of `PROXY_MODE` (e.g. `1`, [other options](https://expressjs.com/en/guide/behind-proxies.html)) See note. |
|
| PROXY_MODE | Enable use behind an SSL-terminating proxy or load balancer, serves over http instead of https and sets Express `trust proxy` setting to the value of `PROXY_MODE` (e.g. `1`, [other options](https://expressjs.com/en/guide/behind-proxies.html)) See note. |
|
||||||
|
| USE_ATTACHMENTS | Add Mastodon-style user attributes to groups based on data in `./data/attachments.json`
|
||||||
|
|
||||||
**Notes on use with a reverse proxy**: When setting proxyMode, you must ensure your reverse proxy sets the following headers: X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto (example for nginx below).
|
**Notes on use with a reverse proxy**: When setting proxyMode, you must ensure your reverse proxy sets the following headers: X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto (example for nginx below).
|
||||||
|
|
||||||
|
|
29
data/attachments.json
Normal file
29
data/attachments.json
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": [
|
||||||
|
"Support Guppe"
|
||||||
|
],
|
||||||
|
"value": [
|
||||||
|
"<a href=\"https://opencollective.com/guppe-groups\">https://opencollective.com/guppe-groups</a>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": [
|
||||||
|
"Get support"
|
||||||
|
],
|
||||||
|
"value": [
|
||||||
|
"<span class=\"h-card\"><a href=\"https://a.gup.pe/u/guppegroups\" class=\"u-url mention\">@<span>GuppeGroups@a.gup.pe</span></a></span>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "PropertyValue",
|
||||||
|
"name": [
|
||||||
|
"Admin contact"
|
||||||
|
],
|
||||||
|
"value": [
|
||||||
|
"<span class=\"h-card\"><a href=\"https://social.coop/@datatitian\" class=\"u-url mention\">@<span>datatitian@social.coop</span></a></span>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
5
data/context.json
Normal file
5
data/context.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"@context": {
|
||||||
|
"PropertyValue" : "http://schema.org/#PropertyValue"
|
||||||
|
}
|
||||||
|
}
|
31
index.js
31
index.js
|
@ -11,7 +11,7 @@ const { onShutdown } = require('node-graceful-shutdown')
|
||||||
const ActivitypubExpress = require('activitypub-express')
|
const ActivitypubExpress = require('activitypub-express')
|
||||||
|
|
||||||
const { version } = require('./package.json')
|
const { version } = require('./package.json')
|
||||||
const { DOMAIN, KEY_PATH, CERT_PATH, CA_PATH, PORT_HTTPS, DB_URL, DB_NAME, PROXY_MODE } = process.env
|
const { DOMAIN, KEY_PATH, CERT_PATH, CA_PATH, PORT_HTTPS, DB_URL, DB_NAME, PROXY_MODE, ADMIN_SECRET, USE_ATTACHMENTS } = process.env
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
const client = new MongoClient(DB_URL)
|
const client = new MongoClient(DB_URL)
|
||||||
|
@ -51,11 +51,29 @@ const apex = ActivitypubExpress({
|
||||||
itemsPerPage: 100,
|
itemsPerPage: 100,
|
||||||
// delivery done in workers only in production
|
// delivery done in workers only in production
|
||||||
offlineMode: process.env.NODE_ENV === 'production',
|
offlineMode: process.env.NODE_ENV === 'production',
|
||||||
|
context: require('./data/context.json'),
|
||||||
routes
|
routes
|
||||||
})
|
})
|
||||||
|
|
||||||
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status Accepts ":req[accept]" ":referrer" ":user-agent"'))
|
app.use(
|
||||||
app.use(express.json({ type: apex.consts.jsonldTypes }), apex)
|
morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status Accepts ":req[accept]" ":referrer" ":user-agent"'),
|
||||||
|
express.json({ type: apex.consts.jsonldTypes }),
|
||||||
|
apex,
|
||||||
|
function checkAdminKey (req, res, next) {
|
||||||
|
if (ADMIN_SECRET && req.get('authorization') === `Bearer ${ADMIN_SECRET}`) {
|
||||||
|
res.locals.apex.authorized = true
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
async function createGuppeActor (...args) {
|
||||||
|
const actor = await apex.createActor(...args)
|
||||||
|
if (USE_ATTACHMENTS) {
|
||||||
|
actor.attachment = require('./data/attachments.json')
|
||||||
|
}
|
||||||
|
return actor
|
||||||
|
}
|
||||||
|
|
||||||
// Create new groups on demand whenever someone tries to access one
|
// Create new groups on demand whenever someone tries to access one
|
||||||
async function actorOnDemand (req, res, next) {
|
async function actorOnDemand (req, res, next) {
|
||||||
|
@ -68,7 +86,7 @@ async function actorOnDemand (req, res, next) {
|
||||||
if (!(await apex.store.getObject(actorIRI)) && actor.length <= 255) {
|
if (!(await apex.store.getObject(actorIRI)) && actor.length <= 255) {
|
||||||
console.log(`Creating group: ${actor}`)
|
console.log(`Creating group: ${actor}`)
|
||||||
const summary = `I'm a group about ${actor}. Follow me to get all the group posts. Tag me to share with the group. Create other groups by searching for or tagging @yourGroupName@${DOMAIN}`
|
const summary = `I'm a group about ${actor}. Follow me to get all the group posts. Tag me to share with the group. Create other groups by searching for or tagging @yourGroupName@${DOMAIN}`
|
||||||
const actorObj = await apex.createActor(actor, `${actor} group`, summary, icon, 'Group')
|
const actorObj = await createGuppeActor(actor, `${actor} group`, summary, icon, 'Group')
|
||||||
await apex.store.saveObject(actorObj)
|
await apex.store.saveObject(actorObj)
|
||||||
}
|
}
|
||||||
} catch (err) { return next(err) }
|
} catch (err) { return next(err) }
|
||||||
|
@ -102,8 +120,7 @@ app.route(routes.inbox)
|
||||||
.get(actorOnDemand, apex.net.inbox.get)
|
.get(actorOnDemand, apex.net.inbox.get)
|
||||||
app.route(routes.outbox)
|
app.route(routes.outbox)
|
||||||
.get(actorOnDemand, apex.net.outbox.get)
|
.get(actorOnDemand, apex.net.outbox.get)
|
||||||
// no C2S at present
|
.post(apex.net.outbox.post)
|
||||||
// .post(apex.net.outbox.post)
|
|
||||||
|
|
||||||
// replace apex's target actor validator with our create on demand method
|
// replace apex's target actor validator with our create on demand method
|
||||||
app.get(routes.actor, actorOnDemand, apex.net.actor.get)
|
app.get(routes.actor, actorOnDemand, apex.net.actor.get)
|
||||||
|
@ -228,7 +245,7 @@ client.connect()
|
||||||
})
|
})
|
||||||
apex.systemUser = await apex.store.getObject(apex.utils.usernameToIRI('system_service'), true)
|
apex.systemUser = await apex.store.getObject(apex.utils.usernameToIRI('system_service'), true)
|
||||||
if (!apex.systemUser) {
|
if (!apex.systemUser) {
|
||||||
const systemUser = await apex.createActor('system_service', `${DOMAIN} system service`, `${DOMAIN} system service`, icon, 'Service')
|
const systemUser = await createGuppeActor('system_service', `${DOMAIN} system service`, `${DOMAIN} system service`, icon, 'Service')
|
||||||
await apex.store.saveObject(systemUser)
|
await apex.store.saveObject(systemUser)
|
||||||
apex.systemUser = systemUser
|
apex.systemUser = systemUser
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue