solid-server 5.6.9-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.acl +10 -0
- package/.github/workflows/ci.yml +47 -0
- package/.nvmrc +1 -0
- package/.snyk +35 -0
- package/.well-known/.acl +15 -0
- package/CHANGELOG.md +198 -0
- package/CONTRIBUTING.md +139 -0
- package/CONTRIBUTORS.md +36 -0
- package/Dockerfile +22 -0
- package/LICENSE.md +23 -0
- package/README.md +453 -0
- package/bin/lib/cli-utils.js +85 -0
- package/bin/lib/cli.js +39 -0
- package/bin/lib/init.js +94 -0
- package/bin/lib/invalidUsernames.js +148 -0
- package/bin/lib/migrateLegacyResources.js +69 -0
- package/bin/lib/options.js +399 -0
- package/bin/lib/start.js +148 -0
- package/bin/lib/updateIndex.js +56 -0
- package/bin/solid +3 -0
- package/bin/solid-test +12 -0
- package/bin/solid.js +3 -0
- package/common/css/solid.css +58 -0
- package/common/fonts/glyphicons-halflings-regular.eot +0 -0
- package/common/fonts/glyphicons-halflings-regular.svg +288 -0
- package/common/fonts/glyphicons-halflings-regular.ttf +0 -0
- package/common/fonts/glyphicons-halflings-regular.woff +0 -0
- package/common/fonts/glyphicons-halflings-regular.woff2 +0 -0
- package/common/img/.gitkeep +0 -0
- package/common/js/auth-buttons.js +65 -0
- package/common/js/solid.js +454 -0
- package/common/well-known/security.txt +2 -0
- package/config/defaults.js +25 -0
- package/config/usernames-blacklist.json +4 -0
- package/config.json-default +22 -0
- package/default-templates/emails/delete-account.js +49 -0
- package/default-templates/emails/invalid-username.js +30 -0
- package/default-templates/emails/reset-password.js +49 -0
- package/default-templates/emails/welcome.js +39 -0
- package/default-templates/new-account/.acl +26 -0
- package/default-templates/new-account/.meta +5 -0
- package/default-templates/new-account/.meta.acl +25 -0
- package/default-templates/new-account/.well-known/.acl +19 -0
- package/default-templates/new-account/favicon.ico +0 -0
- package/default-templates/new-account/favicon.ico.acl +26 -0
- package/default-templates/new-account/inbox/.acl +26 -0
- package/default-templates/new-account/private/.acl +10 -0
- package/default-templates/new-account/profile/.acl +19 -0
- package/default-templates/new-account/profile/card$.ttl +25 -0
- package/default-templates/new-account/public/.acl +19 -0
- package/default-templates/new-account/robots.txt +3 -0
- package/default-templates/new-account/robots.txt.acl +26 -0
- package/default-templates/new-account/settings/.acl +20 -0
- package/default-templates/new-account/settings/prefs.ttl +15 -0
- package/default-templates/new-account/settings/privateTypeIndex.ttl +4 -0
- package/default-templates/new-account/settings/publicTypeIndex.ttl +4 -0
- package/default-templates/new-account/settings/publicTypeIndex.ttl.acl +25 -0
- package/default-templates/new-account/settings/serverSide.ttl.acl +13 -0
- package/default-templates/new-account/settings/serverSide.ttl.inactive +12 -0
- package/default-templates/server/.acl +10 -0
- package/default-templates/server/.well-known/.acl +15 -0
- package/default-templates/server/favicon.ico +0 -0
- package/default-templates/server/favicon.ico.acl +15 -0
- package/default-templates/server/index.html +55 -0
- package/default-templates/server/robots.txt +3 -0
- package/default-templates/server/robots.txt.acl +15 -0
- package/default-views/account/account-deleted.hbs +17 -0
- package/default-views/account/delete-confirm.hbs +51 -0
- package/default-views/account/delete-link-sent.hbs +17 -0
- package/default-views/account/delete.hbs +51 -0
- package/default-views/account/invalid-username.hbs +22 -0
- package/default-views/account/register-disabled.hbs +6 -0
- package/default-views/account/register-form.hbs +132 -0
- package/default-views/account/register.hbs +24 -0
- package/default-views/auth/auth-hidden-fields.hbs +8 -0
- package/default-views/auth/change-password.hbs +58 -0
- package/default-views/auth/goodbye.hbs +23 -0
- package/default-views/auth/login-required.hbs +34 -0
- package/default-views/auth/login-tls.hbs +11 -0
- package/default-views/auth/login-username-password.hbs +28 -0
- package/default-views/auth/login.hbs +55 -0
- package/default-views/auth/no-permission.hbs +29 -0
- package/default-views/auth/password-changed.hbs +27 -0
- package/default-views/auth/reset-link-sent.hbs +21 -0
- package/default-views/auth/reset-password.hbs +52 -0
- package/default-views/auth/sharing.hbs +49 -0
- package/default-views/shared/create-account.hbs +8 -0
- package/default-views/shared/error.hbs +5 -0
- package/docs/how-to-delete-your-account.md +56 -0
- package/docs/login-and-grant-access-to-application.md +32 -0
- package/examples/custom-error-handling.js +31 -0
- package/examples/ldp-with-webid.js +12 -0
- package/examples/simple-express-app.js +20 -0
- package/examples/simple-ldp-server.js +8 -0
- package/favicon.ico +0 -0
- package/favicon.ico.acl +15 -0
- package/index.html +48 -0
- package/index.js +3 -0
- package/lib/acl-checker.js +274 -0
- package/lib/api/accounts/user-accounts.js +88 -0
- package/lib/api/authn/force-user.js +21 -0
- package/lib/api/authn/index.js +5 -0
- package/lib/api/authn/webid-oidc.js +202 -0
- package/lib/api/authn/webid-tls.js +69 -0
- package/lib/api/index.js +6 -0
- package/lib/capability-discovery.js +54 -0
- package/lib/common/fs-utils.js +43 -0
- package/lib/common/template-utils.js +50 -0
- package/lib/common/user-utils.js +28 -0
- package/lib/create-app.js +322 -0
- package/lib/create-server.js +107 -0
- package/lib/debug.js +17 -0
- package/lib/handlers/allow.js +82 -0
- package/lib/handlers/auth-proxy.js +63 -0
- package/lib/handlers/copy.js +39 -0
- package/lib/handlers/cors-proxy.js +95 -0
- package/lib/handlers/delete.js +23 -0
- package/lib/handlers/error-pages.js +212 -0
- package/lib/handlers/get.js +219 -0
- package/lib/handlers/index.js +42 -0
- package/lib/handlers/options.js +33 -0
- package/lib/handlers/patch/n3-patch-parser.js +49 -0
- package/lib/handlers/patch/sparql-update-parser.js +16 -0
- package/lib/handlers/patch.js +203 -0
- package/lib/handlers/post.js +99 -0
- package/lib/handlers/put.js +56 -0
- package/lib/handlers/restrict-to-top-domain.js +13 -0
- package/lib/header.js +136 -0
- package/lib/http-error.js +34 -0
- package/lib/ldp-container.js +161 -0
- package/lib/ldp-copy.js +73 -0
- package/lib/ldp-middleware.js +32 -0
- package/lib/ldp.js +620 -0
- package/lib/lock.js +10 -0
- package/lib/metadata.js +10 -0
- package/lib/models/account-manager.js +603 -0
- package/lib/models/account-template.js +152 -0
- package/lib/models/authenticator.js +333 -0
- package/lib/models/oidc-manager.js +53 -0
- package/lib/models/solid-host.js +131 -0
- package/lib/models/user-account.js +112 -0
- package/lib/models/webid-tls-certificate.js +184 -0
- package/lib/payment-pointer-discovery.js +83 -0
- package/lib/requests/add-cert-request.js +138 -0
- package/lib/requests/auth-request.js +234 -0
- package/lib/requests/create-account-request.js +468 -0
- package/lib/requests/delete-account-confirm-request.js +170 -0
- package/lib/requests/delete-account-request.js +144 -0
- package/lib/requests/login-request.js +205 -0
- package/lib/requests/password-change-request.js +201 -0
- package/lib/requests/password-reset-email-request.js +199 -0
- package/lib/requests/sharing-request.js +259 -0
- package/lib/resource-mapper.js +198 -0
- package/lib/server-config.js +167 -0
- package/lib/services/blacklist-service.js +33 -0
- package/lib/services/email-service.js +162 -0
- package/lib/services/token-service.js +47 -0
- package/lib/utils.js +254 -0
- package/lib/webid/index.js +13 -0
- package/lib/webid/lib/get.js +27 -0
- package/lib/webid/lib/parse.js +12 -0
- package/lib/webid/tls/index.js +185 -0
- package/package.json +172 -0
- package/renovate.json +5 -0
- package/robots.txt +3 -0
- package/robots.txt.acl +15 -0
- package/static/account-recovery.html +78 -0
- package/static/popup-redirect.html +1 -0
- package/static/signup.html +108 -0
- package/static/signup.html.acl +14 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/* eslint-disable node/no-deprecated-api */
|
|
3
|
+
|
|
4
|
+
const url = require('url')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents a Solid user account (created as a result of Signup, etc).
|
|
8
|
+
*/
|
|
9
|
+
class UserAccount {
|
|
10
|
+
/**
|
|
11
|
+
* @constructor
|
|
12
|
+
* @param [options={}] {Object}
|
|
13
|
+
* @param [options.username] {string}
|
|
14
|
+
* @param [options.webId] {string}
|
|
15
|
+
* @param [options.name] {string}
|
|
16
|
+
* @param [options.email] {string}
|
|
17
|
+
* @param [options.externalWebId] {string}
|
|
18
|
+
* @param [options.localAccountId] {string}
|
|
19
|
+
*/
|
|
20
|
+
constructor (options = {}) {
|
|
21
|
+
this.username = options.username
|
|
22
|
+
this.webId = options.webId
|
|
23
|
+
this.name = options.name
|
|
24
|
+
this.email = options.email
|
|
25
|
+
this.externalWebId = options.externalWebId
|
|
26
|
+
this.localAccountId = options.localAccountId
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Factory method, returns an instance of `UserAccount`.
|
|
31
|
+
*
|
|
32
|
+
* @param [options={}] {Object} See `contructor()` docstring.
|
|
33
|
+
*
|
|
34
|
+
* @return {UserAccount}
|
|
35
|
+
*/
|
|
36
|
+
static from (options = {}) {
|
|
37
|
+
return new UserAccount(options)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns the display name for the account.
|
|
42
|
+
*
|
|
43
|
+
* @return {string}
|
|
44
|
+
*/
|
|
45
|
+
get displayName () {
|
|
46
|
+
return this.name || this.username || this.email || 'Solid account'
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Returns the id key for the user account (for use with the user store, for
|
|
51
|
+
* example), consisting of the WebID URI minus the protocol and slashes.
|
|
52
|
+
* Usage:
|
|
53
|
+
*
|
|
54
|
+
* ```
|
|
55
|
+
* userAccount.webId = 'https://alice.example.com/profile/card#me'
|
|
56
|
+
* userAccount.id // -> 'alice.example.com/profile/card#me'
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @return {string}
|
|
60
|
+
*/
|
|
61
|
+
get id () {
|
|
62
|
+
if (!this.webId) { return null }
|
|
63
|
+
|
|
64
|
+
const parsed = url.parse(this.webId)
|
|
65
|
+
let id = parsed.host + parsed.pathname
|
|
66
|
+
if (parsed.hash) {
|
|
67
|
+
id += parsed.hash
|
|
68
|
+
}
|
|
69
|
+
return id
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get accountUri () {
|
|
73
|
+
if (!this.webId) { return null }
|
|
74
|
+
|
|
75
|
+
const parsed = url.parse(this.webId)
|
|
76
|
+
|
|
77
|
+
return parsed.protocol + '//' + parsed.host
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Returns the Uri to the account's Pod
|
|
82
|
+
*
|
|
83
|
+
* @return {string}
|
|
84
|
+
*/
|
|
85
|
+
get podUri () {
|
|
86
|
+
const webIdUrl = url.parse(this.webId)
|
|
87
|
+
const podUrl = `${webIdUrl.protocol}//${webIdUrl.host}`
|
|
88
|
+
return url.format(podUrl)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns the URI of the WebID Profile for this account.
|
|
93
|
+
* Usage:
|
|
94
|
+
*
|
|
95
|
+
* ```
|
|
96
|
+
* // userAccount.webId === 'https://alice.example.com/profile/card#me'
|
|
97
|
+
*
|
|
98
|
+
* userAccount.profileUri // -> 'https://alice.example.com/profile/card'
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @return {string|null}
|
|
102
|
+
*/
|
|
103
|
+
get profileUri () {
|
|
104
|
+
if (!this.webId) { return null }
|
|
105
|
+
|
|
106
|
+
const parsed = url.parse(this.webId)
|
|
107
|
+
// Note that the hash fragment gets dropped
|
|
108
|
+
return parsed.protocol + '//' + parsed.host + parsed.pathname
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = UserAccount
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/* eslint-disable node/no-deprecated-api */
|
|
3
|
+
|
|
4
|
+
const webidTls = require('../webid')('tls')
|
|
5
|
+
const forge = require('node-forge')
|
|
6
|
+
const utils = require('../utils')
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Models a WebID-TLS crypto certificate, as generated at signup from a browser's
|
|
10
|
+
* `<keygen>` element.
|
|
11
|
+
*
|
|
12
|
+
* @class WebIdTlsCertificate
|
|
13
|
+
*/
|
|
14
|
+
class WebIdTlsCertificate {
|
|
15
|
+
/**
|
|
16
|
+
* @param [options={}] {Object}
|
|
17
|
+
* @param [options.spkac] {Buffer<string>}
|
|
18
|
+
* @param [options.date] {Date}
|
|
19
|
+
* @param [options.webId] {string}
|
|
20
|
+
* @param [options.commonName] {string} Certificate name
|
|
21
|
+
* @param [options.issuerName] {string}
|
|
22
|
+
*/
|
|
23
|
+
constructor (options = {}) {
|
|
24
|
+
this.spkac = options.spkac
|
|
25
|
+
this.date = options.date || new Date()
|
|
26
|
+
this.webId = options.webId
|
|
27
|
+
this.commonName = options.commonName
|
|
28
|
+
this.issuer = { commonName: options.issuerName }
|
|
29
|
+
|
|
30
|
+
this.certificate = null // gets initialized in `generateCertificate()`
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Factory method, used to construct a certificate instance from a browser-
|
|
35
|
+
* based signup.
|
|
36
|
+
*
|
|
37
|
+
* @param spkac {string} Signed Public Key and Challenge from a browser's
|
|
38
|
+
* `<keygen>` element.
|
|
39
|
+
* @param userAccount {UserAccount}
|
|
40
|
+
* @param host {SolidHost}
|
|
41
|
+
*
|
|
42
|
+
* @throws {TypeError} If no `spkac` param provided (http 400)
|
|
43
|
+
*
|
|
44
|
+
* @return {WebIdTlsCertificate}
|
|
45
|
+
*/
|
|
46
|
+
static fromSpkacPost (spkac, userAccount, host) {
|
|
47
|
+
if (!spkac) {
|
|
48
|
+
const error = new TypeError('Missing spkac parameter')
|
|
49
|
+
error.status = 400
|
|
50
|
+
throw error
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const date = new Date()
|
|
54
|
+
const commonName = `${userAccount.displayName} [on ${host.serverUri}, created ${date}]`
|
|
55
|
+
|
|
56
|
+
const options = {
|
|
57
|
+
spkac: WebIdTlsCertificate.prepPublicKey(spkac),
|
|
58
|
+
webId: userAccount.webId,
|
|
59
|
+
date,
|
|
60
|
+
commonName,
|
|
61
|
+
issuerName: host.serverUri
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return new WebIdTlsCertificate(options)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Formats a `<keygen>`-generated public key and converts it into a Buffer,
|
|
69
|
+
* to use in TLS certificate generation.
|
|
70
|
+
*
|
|
71
|
+
* @param spkac {string} Signed Public Key and Challenge from a browser's
|
|
72
|
+
* `<keygen>` element.
|
|
73
|
+
*
|
|
74
|
+
* @return {Buffer<string>|null} UTF-8 string buffer of the public key, if one
|
|
75
|
+
* was passed in.
|
|
76
|
+
*/
|
|
77
|
+
static prepPublicKey (spkac) {
|
|
78
|
+
if (!spkac) { return null }
|
|
79
|
+
|
|
80
|
+
spkac = utils.stripLineEndings(spkac)
|
|
81
|
+
spkac = new Buffer(spkac, 'utf-8')
|
|
82
|
+
return spkac
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Generates an X509Certificate from the passed-in `spkac` value.
|
|
87
|
+
*
|
|
88
|
+
* @throws {Error} See `webid` module's `generate()` function.
|
|
89
|
+
*
|
|
90
|
+
* @return {Promise<WebIdTlsCertificate>} Resolves to self (chainable), with
|
|
91
|
+
* the `.certificate` property initialized.
|
|
92
|
+
*/
|
|
93
|
+
generateCertificate () {
|
|
94
|
+
const certOptions = {
|
|
95
|
+
spkac: this.spkac,
|
|
96
|
+
agent: this.webId,
|
|
97
|
+
commonName: this.commonName,
|
|
98
|
+
issuer: this.issuer
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
webidTls.generate(certOptions, (err, certificate) => {
|
|
103
|
+
if (err) {
|
|
104
|
+
reject(err)
|
|
105
|
+
} else {
|
|
106
|
+
this.certificate = certificate
|
|
107
|
+
resolve(this)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Returns the URI (with hash fragment) for this certificate's public key,
|
|
115
|
+
* to be used as a subject of RDF triples in a user's WebID Profile.
|
|
116
|
+
*
|
|
117
|
+
* @throws {TypeError} HTTP 400 error if no `webId` has been set.
|
|
118
|
+
*
|
|
119
|
+
* @return {string}
|
|
120
|
+
*/
|
|
121
|
+
get keyUri () {
|
|
122
|
+
if (!this.webId) {
|
|
123
|
+
const error = new TypeError('Cannot construct key URI, WebID is missing')
|
|
124
|
+
error.status = 400
|
|
125
|
+
throw error
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const profileUri = this.webId.split('#')[0]
|
|
129
|
+
return profileUri + '#key-' + this.date.getTime()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Returns the public key exponent (for adding to a user's WebID Profile)
|
|
134
|
+
*
|
|
135
|
+
* @throws {TypeError} HTTP 400 error if no certificate has been generated.
|
|
136
|
+
*
|
|
137
|
+
* @return {string}
|
|
138
|
+
*/
|
|
139
|
+
get exponent () {
|
|
140
|
+
if (!this.certificate) {
|
|
141
|
+
const error = new TypeError('Cannot return exponent, certificate has not been generated')
|
|
142
|
+
error.status = 400
|
|
143
|
+
throw error
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return this.certificate.publicKey.e.toString()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Returns the public key modulus (for adding to a user's WebID Profile)
|
|
151
|
+
*
|
|
152
|
+
* @throws {TypeError} HTTP 400 error if no certificate has been generated.
|
|
153
|
+
*
|
|
154
|
+
* @return {string}
|
|
155
|
+
*/
|
|
156
|
+
get modulus () {
|
|
157
|
+
if (!this.certificate) {
|
|
158
|
+
const error = new TypeError('Cannot return modulus, certificate has not been generated')
|
|
159
|
+
error.status = 400
|
|
160
|
+
throw error
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return this.certificate.publicKey.n.toString(16).toUpperCase()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Converts the generated cert to DER format and returns it.
|
|
168
|
+
*
|
|
169
|
+
* @return {X509Certificate|null} In DER format
|
|
170
|
+
*/
|
|
171
|
+
toDER () {
|
|
172
|
+
if (!this.certificate) {
|
|
173
|
+
return null
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const certificateAsn = forge.pki.certificateToAsn1(this.certificate)
|
|
177
|
+
// Convert to DER
|
|
178
|
+
const certificateDer = forge.asn1.toDer(certificateAsn).getBytes()
|
|
179
|
+
// new Buffer(der, 'binary')
|
|
180
|
+
return certificateDer
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = WebIdTlsCertificate
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
/**
|
|
3
|
+
* @module payment-pointer-discovery
|
|
4
|
+
*/
|
|
5
|
+
const express = require('express')
|
|
6
|
+
const { promisify } = require('util')
|
|
7
|
+
const fs = require('fs')
|
|
8
|
+
const rdf = require('rdflib')
|
|
9
|
+
|
|
10
|
+
module.exports = paymentPointerDiscovery
|
|
11
|
+
|
|
12
|
+
const PROFILE_PATH = '/profile/card'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns a set of routes to deal with server payment pointer discovery
|
|
16
|
+
* @method paymentPointerDiscovery
|
|
17
|
+
* @return {Router} Express router
|
|
18
|
+
*/
|
|
19
|
+
function paymentPointerDiscovery () {
|
|
20
|
+
const router = express.Router('/')
|
|
21
|
+
|
|
22
|
+
// Advertise the server payment pointer discover endpoint
|
|
23
|
+
router.get('/.well-known/pay', paymentPointerDocument())
|
|
24
|
+
return router
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Serves the service payment pointer document (containing server root URL, including
|
|
29
|
+
* any base path the user specified in config, server API endpoints, etc).
|
|
30
|
+
* @method paymentPointerDocument
|
|
31
|
+
* @param req
|
|
32
|
+
* @param res
|
|
33
|
+
* @param next
|
|
34
|
+
*/
|
|
35
|
+
function paymentPointerDocument () {
|
|
36
|
+
return async (req, res) => {
|
|
37
|
+
try {
|
|
38
|
+
const ldp = req.app.locals.ldp
|
|
39
|
+
const url = ldp.resourceMapper.resolveUrl(req.hostname, PROFILE_PATH)
|
|
40
|
+
const contentType = 'text/turtle'
|
|
41
|
+
const createIfNotExists = false
|
|
42
|
+
const { path } = await ldp.resourceMapper.mapUrlToFile({ url, contentType, createIfNotExists })
|
|
43
|
+
let body
|
|
44
|
+
try {
|
|
45
|
+
// Read the file from disk
|
|
46
|
+
body = await promisify(fs.readFile)(path, { encoding: 'utf8' })
|
|
47
|
+
} catch (e) {
|
|
48
|
+
if (e.message.startsWith('ENOENT: no such file or directory,')) {
|
|
49
|
+
res.json({
|
|
50
|
+
error: `Please create ${PROFILE_PATH} on your pod`
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const webid = rdf.Namespace(`${url}#`)('me')
|
|
55
|
+
const pp = rdf.Namespace('http://paymentpointers.org/ns#')('PaymentPointer')
|
|
56
|
+
let paymentPointer
|
|
57
|
+
try {
|
|
58
|
+
const graph = rdf.graph()
|
|
59
|
+
// Parse the file as Turtle
|
|
60
|
+
rdf.parse(body, graph, url, contentType)
|
|
61
|
+
paymentPointer = graph.any(webid, pp)
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error(e)
|
|
64
|
+
res.json({
|
|
65
|
+
error: `Please make sure ${PROFILE_PATH} contains valid Turtle`
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
if (paymentPointer === null) {
|
|
69
|
+
res.json({ fail: 'Add triple', subject: `<${webid.value}>`, predicate: `<${pp.value}>`, object: '$alice.example' })
|
|
70
|
+
}
|
|
71
|
+
if (paymentPointer.value.startsWith('$')) {
|
|
72
|
+
let suffix = ''
|
|
73
|
+
if (paymentPointer.value.indexOf('/') === -1) {
|
|
74
|
+
suffix = '/.well-known/pay'
|
|
75
|
+
}
|
|
76
|
+
paymentPointer.value = `https://${paymentPointer.value.substring(1)}${suffix}`
|
|
77
|
+
}
|
|
78
|
+
res.redirect(paymentPointer.value)
|
|
79
|
+
} catch (e) {
|
|
80
|
+
res.json({ fail: e.message })
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const WebIdTlsCertificate = require('../models/webid-tls-certificate')
|
|
4
|
+
const debug = require('./../debug').accounts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Represents an 'add new certificate to account' request
|
|
8
|
+
* (a POST to `/api/accounts/cert` endpoint).
|
|
9
|
+
*
|
|
10
|
+
* Note: The account has to exist, and the user must be already logged in,
|
|
11
|
+
* for this to succeed.
|
|
12
|
+
*/
|
|
13
|
+
class AddCertificateRequest {
|
|
14
|
+
/**
|
|
15
|
+
* @param [options={}] {Object}
|
|
16
|
+
* @param [options.accountManager] {AccountManager}
|
|
17
|
+
* @param [options.userAccount] {UserAccount}
|
|
18
|
+
* @param [options.certificate] {WebIdTlsCertificate}
|
|
19
|
+
* @param [options.response] {HttpResponse}
|
|
20
|
+
*/
|
|
21
|
+
constructor (options) {
|
|
22
|
+
this.accountManager = options.accountManager
|
|
23
|
+
this.userAccount = options.userAccount
|
|
24
|
+
this.certificate = options.certificate
|
|
25
|
+
this.response = options.response
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Handles the HTTP request (from an Express route handler).
|
|
30
|
+
*
|
|
31
|
+
* @param req
|
|
32
|
+
* @param res
|
|
33
|
+
* @param accountManager {AccountManager}
|
|
34
|
+
*
|
|
35
|
+
* @throws {TypeError}
|
|
36
|
+
* @throws {Error} HTTP 401 if the user is not logged in (`req.session.userId`
|
|
37
|
+
* does not match the intended account to which the cert is being added).
|
|
38
|
+
*
|
|
39
|
+
* @return {Promise}
|
|
40
|
+
*/
|
|
41
|
+
static handle (req, res, accountManager) {
|
|
42
|
+
let request
|
|
43
|
+
try {
|
|
44
|
+
request = AddCertificateRequest.fromParams(req, res, accountManager)
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return Promise.reject(error)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return AddCertificateRequest.addCertificate(request)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Factory method, returns an initialized instance of `AddCertificateRequest`.
|
|
54
|
+
*
|
|
55
|
+
* @param req
|
|
56
|
+
* @param res
|
|
57
|
+
* @param accountManager {AccountManager}
|
|
58
|
+
*
|
|
59
|
+
* @throws {TypeError} If required parameters missing
|
|
60
|
+
* @throws {Error} HTTP 401 if the user is not logged in (`req.session.userId`
|
|
61
|
+
* does not match the intended account to which the cert is being added).
|
|
62
|
+
*
|
|
63
|
+
* @return {AddCertificateRequest}
|
|
64
|
+
*/
|
|
65
|
+
static fromParams (req, res, accountManager) {
|
|
66
|
+
const userAccount = accountManager.userAccountFrom(req.body)
|
|
67
|
+
const certificate = WebIdTlsCertificate.fromSpkacPost(
|
|
68
|
+
req.body.spkac,
|
|
69
|
+
userAccount,
|
|
70
|
+
accountManager.host)
|
|
71
|
+
|
|
72
|
+
debug(`Adding a new certificate for ${userAccount.webId}`)
|
|
73
|
+
|
|
74
|
+
if (req.session.userId !== userAccount.webId) {
|
|
75
|
+
debug(`Cannot add new certificate: signed in user is "${req.session.userId}"`)
|
|
76
|
+
const error = new Error("You are not logged in, so you can't create a certificate")
|
|
77
|
+
error.status = 401
|
|
78
|
+
throw error
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const options = {
|
|
82
|
+
accountManager,
|
|
83
|
+
userAccount,
|
|
84
|
+
certificate,
|
|
85
|
+
response: res
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return new AddCertificateRequest(options)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Generates a new certificate for a given user account, and adds it to that
|
|
93
|
+
* account's WebID Profile graph.
|
|
94
|
+
*
|
|
95
|
+
* @param request {AddCertificateRequest}
|
|
96
|
+
*
|
|
97
|
+
* @throws {Error} HTTP 400 if there were errors during certificate generation
|
|
98
|
+
*
|
|
99
|
+
* @returns {Promise}
|
|
100
|
+
*/
|
|
101
|
+
static addCertificate (request) {
|
|
102
|
+
const { certificate, userAccount, accountManager } = request
|
|
103
|
+
|
|
104
|
+
return certificate.generateCertificate()
|
|
105
|
+
.catch(err => {
|
|
106
|
+
err.status = 400
|
|
107
|
+
err.message = 'Error generating a certificate: ' + err.message
|
|
108
|
+
throw err
|
|
109
|
+
})
|
|
110
|
+
.then(() => {
|
|
111
|
+
return accountManager.addCertKeyToProfile(certificate, userAccount)
|
|
112
|
+
})
|
|
113
|
+
.catch(err => {
|
|
114
|
+
err.status = 400
|
|
115
|
+
err.message = 'Error adding certificate to profile: ' + err.message
|
|
116
|
+
throw err
|
|
117
|
+
})
|
|
118
|
+
.then(() => {
|
|
119
|
+
request.sendResponse(certificate)
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Sends the generated certificate in the response object.
|
|
125
|
+
*
|
|
126
|
+
* @param certificate {WebIdTlsCertificate}
|
|
127
|
+
*/
|
|
128
|
+
sendResponse (certificate) {
|
|
129
|
+
const { response, userAccount } = this
|
|
130
|
+
response.set('User', userAccount.webId)
|
|
131
|
+
response.status(200)
|
|
132
|
+
|
|
133
|
+
response.set('Content-Type', 'application/x-x509-user-cert')
|
|
134
|
+
response.send(certificate.toDER())
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = AddCertificateRequest
|