Skip to content

Commit ac4eec7

Browse files
author
CI Fix
committed
ESM Migration: Convert main lib files and lib/api to ESM
- Create ESM versions (.mjs) for 7 main lib files: - capability-discovery.mjs - ldp-container.mjs - ldp.mjs (large 632-line file) - payment-pointer-discovery.mjs - rdf-notification-template.mjs - resource-mapper.mjs (227 lines) - server-config.mjs - Convert lib/api/ directory to ESM: - index.mjs - accounts/user-accounts.mjs - authn/index.mjs - authn/force-user.mjs - All files maintain dual CommonJS/ESM compatibility - Proper import/export conversions with createRequire for CommonJS deps - No errors detected in new ESM modules - Total: 18 .mjs files now available in lib/ directory
1 parent 5b65f43 commit ac4eec7

File tree

11 files changed

+1492
-0
lines changed

11 files changed

+1492
-0
lines changed

lib/api/accounts/user-accounts.mjs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import express from 'express'
2+
import { urlencoded } from 'body-parser'
3+
const bodyParser = urlencoded({ extended: false })
4+
import debug from '../../debug.mjs'
5+
const debugAccounts = debug.accounts
6+
7+
import restrictToTopDomain from '../../handlers/restrict-to-top-domain.mjs'
8+
9+
import CreateAccountRequest from '../../requests/create-account-request.mjs'
10+
import AddCertificateRequest from '../../requests/add-cert-request.mjs'
11+
import DeleteAccountRequest from '../../requests/delete-account-request.mjs'
12+
import DeleteAccountConfirmRequest from '../../requests/delete-account-confirm-request.mjs'
13+
14+
/**
15+
* Returns an Express middleware handler for checking if a particular account
16+
* exists (used by Signup apps).
17+
*
18+
* @param accountManager {AccountManager}
19+
*
20+
* @return {Function}
21+
*/
22+
export function checkAccountExists (accountManager) {
23+
return (req, res, next) => {
24+
const accountUri = req.hostname
25+
26+
accountManager.accountUriExists(accountUri)
27+
.then(found => {
28+
if (!found) {
29+
debugAccounts(`Account ${accountUri} is available (for ${req.originalUrl})`)
30+
return res.sendStatus(404)
31+
}
32+
debugAccounts(`Account ${accountUri} is not available (for ${req.originalUrl})`)
33+
next()
34+
})
35+
.catch(next)
36+
}
37+
}
38+
39+
/**
40+
* Returns an Express middleware handler for adding a new certificate to an
41+
* existing account (POST to /api/accounts/cert).
42+
*
43+
* @param accountManager
44+
*
45+
* @return {Function}
46+
*/
47+
export function newCertificate (accountManager) {
48+
return (req, res, next) => {
49+
return AddCertificateRequest.handle(req, res, accountManager)
50+
.catch(err => {
51+
err.status = err.status || 400
52+
next(err)
53+
})
54+
}
55+
}
56+
57+
/**
58+
* Returns an Express router for providing user account related middleware
59+
* handlers.
60+
*
61+
* @param accountManager {AccountManager}
62+
*
63+
* @return {Router}
64+
*/
65+
export function middleware (accountManager) {
66+
const router = express.Router('/')
67+
68+
router.get('/', checkAccountExists(accountManager))
69+
70+
router.post('/api/accounts/new', restrictToTopDomain, bodyParser, CreateAccountRequest.post)
71+
router.get(['/register', '/api/accounts/new'], restrictToTopDomain, CreateAccountRequest.get)
72+
73+
router.post('/api/accounts/cert', restrictToTopDomain, bodyParser, newCertificate(accountManager))
74+
75+
router.get('/account/delete', restrictToTopDomain, DeleteAccountRequest.get)
76+
router.post('/account/delete', restrictToTopDomain, bodyParser, DeleteAccountRequest.post)
77+
78+
router.get('/account/delete/confirm', restrictToTopDomain, DeleteAccountConfirmRequest.get)
79+
router.post('/account/delete/confirm', restrictToTopDomain, bodyParser, DeleteAccountConfirmRequest.post)
80+
81+
return router
82+
}
83+
84+
export default {
85+
middleware,
86+
checkAccountExists,
87+
newCertificate
88+
}

lib/api/authn/force-user.mjs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import debug from '../../debug.mjs'
2+
const debugAuth = debug.authentication
3+
4+
/**
5+
* Enforces the `--force-user` server flag, hardcoding a webid for all requests,
6+
* for testing purposes.
7+
*/
8+
export function initialize (app, argv) {
9+
const forceUserId = argv.forceUser
10+
app.use('/', (req, res, next) => {
11+
debugAuth(`Identified user (override): ${forceUserId}`)
12+
req.session.userId = forceUserId
13+
if (argv.auth === 'tls') {
14+
res.set('User', forceUserId)
15+
}
16+
next()
17+
})
18+
}
19+
20+
export default {
21+
initialize
22+
}

lib/api/authn/index.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export { default as oidc } from './webid-oidc.mjs'
2+
export { default as tls } from './webid-tls.mjs'
3+
export { default as forceUser } from './force-user.mjs'
4+
5+
export default {
6+
oidc: (await import('./webid-oidc.mjs')).default,
7+
tls: (await import('./webid-tls.mjs')).default,
8+
forceUser: (await import('./force-user.mjs')).default
9+
}

lib/api/index.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as authn } from './authn/index.mjs'
2+
export { default as accounts } from './accounts/user-accounts.mjs'

lib/capability-discovery.mjs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* @module capability-discovery
3+
*/
4+
import express from 'express'
5+
import { URL } from 'url'
6+
7+
/**
8+
* Returns a set of routes to deal with server capability discovery
9+
* @method capabilityDiscovery
10+
* @return {Router} Express router
11+
*/
12+
export default function capabilityDiscovery () {
13+
const router = express.Router('/')
14+
15+
// Advertise the server capability discover endpoint
16+
router.get('/.well-known/solid', serviceCapabilityDocument())
17+
return router
18+
}
19+
20+
/**
21+
* Serves the service capability document (containing server root URL, including
22+
* any base path the user specified in config, server API endpoints, etc).
23+
* @method serviceCapabilityDocument
24+
* @param req
25+
* @param res
26+
* @param next
27+
*/
28+
function serviceCapabilityDocument () {
29+
return (req, res) => {
30+
const ldp = req.app.locals.ldp
31+
res.json({
32+
// Add the server root url
33+
root: ldp.resourceMapper.resolveUrl(req.hostname, req.path),
34+
// Add the 'apps' urls section
35+
apps: req.app.locals.appUrls,
36+
api: {
37+
accounts: {
38+
// 'changePassword': '/api/account/changePassword',
39+
// 'delete': '/api/accounts/delete',
40+
41+
// Create new user (see IdentityProvider.post() in identity-provider.js)
42+
new: new URL('/api/accounts/new', ldp.serverUri),
43+
recover: new URL('/api/accounts/recover', ldp.serverUri),
44+
signin: ldp.resourceMapper.resolveUrl(req.hostname, '/login'),
45+
signout: ldp.resourceMapper.resolveUrl(req.hostname, '/logout'),
46+
validateToken: new URL('/api/accounts/validateToken', ldp.serverUri)
47+
}
48+
}
49+
})
50+
}
51+
}

lib/ldp-container.mjs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import { createRequire } from 'module'
2+
const require = createRequire(import.meta.url)
3+
4+
const $rdf = require('rdflib')
5+
import debug from './debug.mjs'
6+
import error from './http-error.mjs'
7+
import fs from 'fs'
8+
const ns = require('solid-namespace')($rdf)
9+
const mime = require('mime-types')
10+
import path from 'path'
11+
12+
export { addContainerStats, addFile, addStats, readdir }
13+
14+
async function addContainerStats (ldp, reqUri, filename, resourceGraph) {
15+
const containerStats = await ldp.stat(filename)
16+
addStats(resourceGraph, reqUri, containerStats, filename)
17+
const storage = new URL(reqUri)
18+
if (reqUri === storage.origin + '/') {
19+
resourceGraph.add(
20+
resourceGraph.sym(reqUri),
21+
ns.rdf('type'),
22+
ns.space('Storage')
23+
)
24+
}
25+
resourceGraph.add(
26+
resourceGraph.sym(reqUri),
27+
ns.rdf('type'),
28+
ns.ldp('BasicContainer'))
29+
resourceGraph.add(
30+
resourceGraph.sym(reqUri),
31+
ns.rdf('type'),
32+
ns.ldp('Container'))
33+
}
34+
35+
async function addFile (ldp, resourceGraph, containerUri, reqUri, container, file) {
36+
// Skip .meta and .acl
37+
if (file.endsWith(ldp.suffixMeta) || file.endsWith(ldp.suffixAcl)) {
38+
return null
39+
}
40+
41+
const filePath = path.join(container, file)
42+
43+
// Get file stats
44+
let stats
45+
try {
46+
stats = await ldp.stat(filePath)
47+
} catch (e) {
48+
return null
49+
}
50+
const memberUri = reqUri + (stats.isDirectory() ? '/' : '')
51+
52+
// Add fileStats to resource Graph
53+
addStats(resourceGraph, memberUri, stats, file)
54+
55+
// Add to `contains` list
56+
resourceGraph.add(
57+
resourceGraph.sym(containerUri),
58+
ns.ldp('contains'),
59+
resourceGraph.sym(memberUri))
60+
61+
// Set up a metaFile path
62+
// Earlier code used a .ttl file as its own meta file, which
63+
// caused massive data files to parsed as part of deirectory listings just looking for type triples
64+
const metaFile = containerUri + file + ldp.suffixMeta
65+
66+
let metadataGraph
67+
try {
68+
metadataGraph = await getMetadataGraph(ldp, metaFile, memberUri)
69+
} catch (err) {
70+
metadataGraph = $rdf.graph()
71+
}
72+
73+
// Add Container or BasicContainer types
74+
if (stats.isDirectory()) {
75+
resourceGraph.add(
76+
metadataGraph.sym(memberUri),
77+
ns.rdf('type'),
78+
ns.ldp('BasicContainer'))
79+
80+
resourceGraph.add(
81+
metadataGraph.sym(memberUri),
82+
ns.rdf('type'),
83+
ns.ldp('Container'))
84+
}
85+
// Add generic LDP type
86+
resourceGraph.add(
87+
metadataGraph.sym(memberUri),
88+
ns.rdf('type'),
89+
ns.ldp('Resource'))
90+
91+
// Add type from metadataGraph
92+
metadataGraph
93+
.statementsMatching(
94+
metadataGraph.sym(memberUri),
95+
ns.rdf('type'),
96+
undefined)
97+
.forEach(function (typeStatement) {
98+
// If the current is a file and its type is BasicContainer,
99+
// This is not possible, so do not infer its type!
100+
if (
101+
(
102+
typeStatement.object.uri !== ns.ldp('BasicContainer').uri &&
103+
typeStatement.object.uri !== ns.ldp('Container').uri
104+
) ||
105+
!stats.isFile()
106+
) {
107+
resourceGraph.add(
108+
resourceGraph.sym(reqUri),
109+
typeStatement.predicate,
110+
typeStatement.object)
111+
}
112+
})
113+
114+
return null
115+
}
116+
117+
function addStats (resourceGraph, reqUri, stats, filename) {
118+
resourceGraph.add(
119+
resourceGraph.sym(reqUri),
120+
ns.stat('mtime'), // Deprecate?
121+
stats.mtime.getTime() / 1000)
122+
123+
resourceGraph.add(
124+
resourceGraph.sym(reqUri),
125+
ns.dct('modified'),
126+
stats.mtime) // An actual datetime value from a Date object
127+
128+
resourceGraph.add(
129+
resourceGraph.sym(reqUri),
130+
ns.stat('size'),
131+
stats.size)
132+
133+
if (!reqUri.endsWith('/') && mime.lookup(filename)) { // Is the file has a well-known type,
134+
const type = 'http://www.w3.org/ns/iana/media-types/' + mime.lookup(filename) + '#Resource'
135+
resourceGraph.add(
136+
resourceGraph.sym(reqUri),
137+
ns.rdf('type'), // convert MIME type to RDF
138+
resourceGraph.sym(type)
139+
)
140+
}
141+
}
142+
143+
function readdir (filename) {
144+
debug.handlers('GET -- Reading directory')
145+
return new Promise((resolve, reject) => {
146+
fs.readdir(filename, function (err, files) {
147+
if (err) {
148+
debug.handlers('GET -- Error reading files: ' + err)
149+
return reject(error(err, 'Can\'t read container'))
150+
}
151+
152+
debug.handlers('Files in directory: ' + files.toString().slice(0, 100))
153+
return resolve(files)
154+
})
155+
})
156+
}
157+
158+
async function getMetadataGraph (ldp, metaFile) {
159+
const metaStats = await ldp.stat(metaFile)
160+
if (metaStats && metaStats.isFile()) {
161+
try {
162+
return await ldp.getGraph(metaFile)
163+
} catch (err) {
164+
throw error(err, 'Can\'t parse container metadata')
165+
}
166+
} else {
167+
return $rdf.graph()
168+
}
169+
}

0 commit comments

Comments
 (0)