Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check whether a person has a verified email #2

Merged
merged 3 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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