Skip to content

Commit

Permalink
Check whether a person has a verified email (#2)
Browse files Browse the repository at this point in the history
endpoint GET /status/:webId
  • Loading branch information
mrkvon authored Jan 16, 2024
1 parent 89753f7 commit ed09e46
Show file tree
Hide file tree
Showing 19 changed files with 672 additions and 323 deletions.
4 changes: 4 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ MAILER_IDENTITY_EMAIL=bot@example
MAILER_IDENTITY_PASSWORD=password
MAILER_IDENTITY_PROVIDER=http://localhost:3456
MAILER_IDENTITY_WEBID=http://localhost:3456/bot/profile/card#me
MAILER_IDENTITY_CSS_VERSION=7 # supported versions are 6 and 7

# link to group of users who are allowed to use the service
ALLOWED_GROUPS=
Expand Down Expand Up @@ -50,3 +51,6 @@ DB_PORT=
JWT_KEY=./ecdsa-p256-private.pem
# jwt algorithm
JWT_ALG=ES256

# type index class by which we find settings with email
EMAIL_DISCOVERY_TYPE=http://w3id.org/hospex/ns#PersonalHospexDocument
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
# Simple Solid email notifications

This service sends email from one person within a Solid group to another. It doesn't use native Solid notifications, because there are pods that don't support it.
This service sends email from one person within a Solid group to another. It doesn't use native Solid notifications, because there are pods that don't support them.

## How it works

- It's a bot agent with its own identity, which must be provided by arbitrary CommunitySolidServer pod
- It's a bot agent with its own identity, which must be provided by arbitrary [CommunitySolidServer](https://github.com/CommunitySolidServer/CommunitySolidServer) pod
- It runs on a server
- You can check whether another person in the group has set up email notifications.
- If the other person has set up the notifications, you can send them an email through this service.
- At the beginning, you need to verify your email, save it into your hospitality exchange settings, and give the mailer a permission to read the email; so the email notifier can access the settings when it sends you an email.
- When you want to notify other person, the service will check whether both of you belong to the specified group(s). If you both belong, and the other person has email notifications set up, it will send the other person an email.

### Verified email address discovery

Email address and verification token should be stored in (webId) - space:preferencesFile -> (email settings file) to which the mailer identity has read (and maybe write) access. It can be in the main webId file, or it can be in some document discovered via publicTypeIndex. In case of hospitality exchange, it can be in hospex:PersonalHospexDocument.

1. Go to person's webId
1. Find public type index `(webId) - solid:publicTypeIndex -> (publicTypeIndex)``
1. Find instances of hospex:PersonalHospexDocument
1. Find settings in the relevant instance (webId) - space:preferencesFile -> (settings)
1. In the settings, find (webId) - foaf:mbox -> (email) and (webId) - example:emailVerificationToken -> (JWT)

## Usage

### Configure
Expand Down
39 changes: 14 additions & 25 deletions apidocs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
}
],
"paths": {
"/inbox": {
"/init": {
"post": {
"description": "",
"responses": {
Expand All @@ -26,34 +26,13 @@
"schema": {
"type": "object",
"properties": {
"@context": {
"const": "https://www.w3.org/ns/activitystreams"
},
"@id": {
"type": "string"
},
"@type": {
"const": "Add"
},
"actor": {
"type": "string",
"format": "uri"
},
"object": {
"type": "string",
"format": "uri"
},
"target": {
"email": {
"type": "string",
"format": "email"
}
},
"required": [
"@context",
"@type",
"actor",
"object",
"target"
"email"
],
"additionalProperties": false
}
Expand Down Expand Up @@ -82,9 +61,19 @@
}
}
},
"/status": {
"/status/{webId}": {
"get": {
"description": "",
"parameters": [
{
"name": "webId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"description": ""
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@koa/bodyparser": "^5.0.0",
"@koa/cors": "^4.0.0",
"@koa/router": "^12.0.0",
"@ldhop/core": "^0.0.0-alpha.1",
"@solid/access-token-verifier": "^2.0.5",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
Expand Down
84 changes: 27 additions & 57 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import {
} from './controllers/integration'
import { getStatus } from './controllers/status'
import { webhookReceiver } from './controllers/webhookReceiver'
import { authorizeGroups } from './middlewares/authorizeGroup'
import {
authorizeGroups,
checkParamGroupMembership,
} from './middlewares/authorizeGroup'
import { solidAuth } from './middlewares/solidAuth'
import { validateBody } from './middlewares/validate'

Expand All @@ -21,65 +24,26 @@ app.proxy = isBehindProxy
const router = new Router()

router
// .post(
// '/inbox',
// solidAuth,
// /*
// #swagger.requestBody = {
// required: true,
// content: {
// 'application/json': {
// schema: {
// type: 'object',
// properties: {
// '@context': { const: 'https://www.w3.org/ns/activitystreams' },
// '@id': { type: 'string' },
// '@type': { const: 'Add' },
// actor: { type: 'string', format: 'uri' },
// object: { type: 'string', format: 'uri' },
// target: { type: 'string', format: 'email' },
// },
// required: ['@context', '@type', 'actor', 'object', 'target'],
// additionalProperties: false,
// },
// },
// },
// }
// */
// validateBody({
// type: 'object',
// properties: {
// '@context': { const: 'https://www.w3.org/ns/activitystreams' },
// '@id': { type: 'string' },
// '@type': { const: 'Add' },
// actor: { type: 'string', format: 'uri' },
// object: { type: 'string', format: 'uri' },
// target: { type: 'string', format: 'email' },
// },
// required: ['@context', '@type', 'actor', 'object', 'target'],
// additionalProperties: false,
// }),
// initializeIntegration,
// )
.post(
'/init',
solidAuth,
authorizeGroups(allowedGroups),
// #swagger.requestBody = {
// required: true,
// content: {
// 'application/json': {
// schema: {
// type: 'object',
// properties: {
// email: { type: 'string', format: 'email' },
// },
// required: ['email'],
// additionalProperties: false,
// },
// },
// },
// }
/* #swagger.requestBody = {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
properties: {
email: { type: 'string', format: 'email' },
},
required: ['email'],
additionalProperties: false,
},
},
},
}
*/
validateBody({
type: 'object',
properties: { email: { type: 'string', format: 'email' } },
Expand All @@ -90,7 +54,13 @@ router
)
.get('/verify-email', checkVerificationLink, finishIntegration)
.post('/webhook-receiver', webhookReceiver)
.get('/status', solidAuth, getStatus)
.get(
'/status/:webId',
solidAuth,
authorizeGroups(allowedGroups),
checkParamGroupMembership(allowedGroups, 'webId' as const),
getStatus,
)

app
.use(helmet())
Expand Down
6 changes: 6 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export const mailerCredentials = {
webId:
process.env.MAILER_IDENTITY_WEBID ??
'http://localhost:3456/bot/profile/card#me',
// version of CommunitySolidServer that provides identity for mailer
cssVersion: <6 | 7>+(process.env.MAILER_IDENTITY_CSS_VERSION ?? 7), // 6 or 7
}

const stringToBoolean = (value: string | undefined): boolean => {
Expand Down Expand Up @@ -71,3 +73,7 @@ export const jwt = {
key: process.env.JWT_KEY ?? './ecdsa-p256-private.pem',
alg: process.env.JWT_ALG ?? 'ES256',
}

export const emailDiscoveryType =
process.env.EMAIL_DISCOVERY_TYPE ??
'http://w3id.org/hospex/ns#PersonalHospexDocument'
Loading

0 comments on commit ed09e46

Please sign in to comment.