Skip to content

Commit c668ad3

Browse files
author
CI Fix
committed
updates to lib/handlers
1 parent beb6dad commit c668ad3

File tree

7 files changed

+162
-244
lines changed

7 files changed

+162
-244
lines changed

lib/handlers/auth-proxy.mjs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// An authentication proxy is a reverse proxy
22
// that sends a logged-in Solid user's details to a backend
33

4-
import { createRequire } from 'module'
5-
const require = createRequire(import.meta.url)
6-
const { createProxyMiddleware } = require('http-proxy-middleware')
4+
import { createProxyMiddleware } from 'http-proxy-middleware'
75
import debug from '../debug.mjs'
86
import allow from './allow.mjs'
97

lib/handlers/cors-proxy.mjs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
/* eslint-disable node/no-deprecated-api */
22

3-
import { createRequire } from 'module'
4-
const require = createRequire(import.meta.url)
5-
const { createProxyMiddleware } = require('http-proxy-middleware')
6-
const cors = require('cors')
3+
import { createProxyMiddleware } from 'http-proxy-middleware'
4+
import cors from 'cors'
75
import debug from '../debug.mjs'
86
import url from 'url'
97
import dns from 'dns'
10-
const isIp = require('is-ip')
11-
const ipRange = require('ip-range-check')
12-
const validUrl = require('valid-url')
8+
import isIp from 'is-ip'
9+
import ipRange from 'ip-range-check'
10+
import validUrl from 'valid-url'
1311

1412
const CORS_SETTINGS = {
1513
methods: 'GET',

lib/handlers/error-pages.mjs

Lines changed: 147 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -1,217 +1,147 @@
1-
import debug from '../debug.mjs'
2-
const debugServer = debug.server
3-
import fs from 'fs'
4-
import util from '../utils.mjs'
5-
import * as Auth from '../api/authn/index.mjs'
6-
import { createRequire } from 'module'
7-
const require = createRequire(import.meta.url)
8-
9-
/**
10-
* Serves as a last-stop error handler for all other middleware.
11-
*
12-
* @param err {Error}
13-
* @param req {IncomingRequest}
14-
* @param res {ServerResponse}
15-
* @param next {Function}
16-
*/
17-
export function handler (err, req, res, next) {
18-
debugServer('Error page because of:', err)
19-
20-
const locals = req.app.locals
21-
const authMethod = locals.authMethod
22-
const ldp = locals.ldp
23-
24-
// If the user specifies this function,
25-
// they can customize the error programmatically
26-
if (ldp.errorHandler) {
27-
debugServer('Using custom error handler')
28-
return ldp.errorHandler(err, req, res, next)
29-
}
30-
31-
const statusCode = statusCodeFor(err, req, authMethod)
32-
switch (statusCode) {
33-
case 401:
34-
setAuthenticateHeader(req, res, err)
35-
renderLoginRequired(req, res, err)
36-
break
37-
case 403:
38-
renderNoPermission(req, res, err)
39-
break
40-
default:
41-
if (ldp.noErrorPages) {
42-
sendErrorResponse(statusCode, res, err)
43-
} else {
44-
sendErrorPage(statusCode, res, err, ldp)
45-
}
46-
}
47-
}
48-
49-
/**
50-
* Returns the HTTP status code for a given request error.
51-
*
52-
* @param err {Error}
53-
* @param req {IncomingRequest}
54-
* @param authMethod {string}
55-
*
56-
* @returns {number}
57-
*/
58-
function statusCodeFor (err, req, authMethod) {
59-
let statusCode = err.status || err.statusCode || 500
60-
61-
if (authMethod === 'oidc') {
62-
statusCode = Auth.oidc.statusCodeOverride(statusCode, req)
63-
}
64-
65-
return statusCode
66-
}
67-
68-
/**
69-
* Dispatches the writing of the `WWW-Authenticate` response header (used for
70-
* 401 Unauthorized responses).
71-
*
72-
* @param req {IncomingRequest}
73-
* @param res {ServerResponse}
74-
* @param err {Error}
75-
*/
76-
export function setAuthenticateHeader (req, res, err) {
77-
const locals = req.app.locals
78-
const authMethod = locals.authMethod
79-
80-
switch (authMethod) {
81-
case 'oidc':
82-
Auth.oidc.setAuthenticateHeader(req, res, err)
83-
break
84-
case 'tls':
85-
Auth.tls.setAuthenticateHeader(req, res)
86-
break
87-
default:
88-
break
89-
}
90-
}
91-
92-
/**
93-
* Sends the HTTP status code and error message in the response.
94-
*
95-
* @param statusCode {number}
96-
* @param res {ServerResponse}
97-
* @param err {Error}
98-
*/
99-
export function sendErrorResponse (statusCode, res, err) {
100-
res.status(statusCode)
101-
res.header('Content-Type', 'text/plain;charset=utf-8')
102-
res.send(err.message + '\n')
103-
}
104-
105-
/**
106-
* Sends the HTTP status code and error message as a custom error page.
107-
*
108-
* @param statusCode {number}
109-
* @param res {ServerResponse}
110-
* @param err {Error}
111-
* @param ldp {LDP}
112-
*/
113-
export function sendErrorPage (statusCode, res, err, ldp) {
114-
const errorPage = ldp.errorPages + statusCode.toString() + '.html'
115-
116-
return new Promise((resolve) => {
117-
fs.readFile(errorPage, 'utf8', (readErr, text) => {
118-
if (readErr) {
119-
// Fall back on plain error response
120-
return resolve(sendErrorResponse(statusCode, res, err))
121-
}
122-
123-
res.status(statusCode)
124-
res.header('Content-Type', 'text/html')
125-
res.send(text)
126-
resolve()
127-
})
128-
})
129-
}
130-
131-
/**
132-
* Renders the databrowser
133-
*
134-
* @param req {IncomingRequest}
135-
* @param res {ServerResponse}
136-
*/
137-
function renderDataBrowser (req, res) {
138-
res.set('Content-Type', 'text/html')
139-
const ldp = req.app.locals.ldp
140-
141-
const defaultDataBrowser = require.resolve('mashlib/dist/databrowser.html')
142-
143-
const dataBrowserPath = ldp.dataBrowserPath === 'default' ? defaultDataBrowser : ldp.dataBrowserPath
144-
debugServer(' sending data browser file: ' + dataBrowserPath)
145-
const dataBrowserHtml = fs.readFileSync(dataBrowserPath, 'utf8')
146-
// Note: This must be done instead of sendFile because the test suite doesn't accept 412 responses
147-
res.set('content-type', 'text/html')
148-
res.send(dataBrowserHtml)
149-
}
150-
151-
/**
152-
* Renders a 401 response explaining that a login is required.
153-
*
154-
* @param req {IncomingRequest}
155-
* @param res {ServerResponse}
156-
*/
157-
function renderLoginRequired (req, res, err) {
158-
const currentUrl = util.fullUrlForReq(req)
159-
debugServer(`Display login-required for ${currentUrl}`)
160-
res.statusMessage = err.message
161-
res.status(401)
162-
if (req.accepts('html')) {
163-
renderDataBrowser(req, res)
164-
} else {
165-
res.send('Not Authenticated')
166-
}
167-
}
168-
169-
/**
170-
* Renders a 403 response explaining that the user has no permission.
171-
*
172-
* @param req {IncomingRequest}
173-
* @param res {ServerResponse}
174-
*/
175-
function renderNoPermission (req, res, err) {
176-
const currentUrl = util.fullUrlForReq(req)
177-
debugServer(`Display no-permission for ${currentUrl}`)
178-
res.statusMessage = err.message
179-
res.status(403)
180-
if (req.accepts('html')) {
181-
renderDataBrowser(req, res)
182-
} else {
183-
res.send('Not Authorized')
184-
}
185-
}
186-
187-
/**
188-
* Returns a response body for redirecting browsers to a Select Provider /
189-
* login workflow page. Uses either a JS location.href redirect or an
190-
* http-equiv type html redirect for no-script conditions.
191-
*
192-
* @param url {string}
193-
*
194-
* @returns {string} Response body
195-
*/
196-
export function redirectBody (url) {
197-
return `<!DOCTYPE HTML>
198-
<meta charset="UTF-8">
199-
<script>
200-
window.location.href = "${url}" + encodeURIComponent(window.location.hash)
201-
</script>
202-
<noscript>
203-
<meta http-equiv="refresh" content="0; url=${url}">
204-
</noscript>
205-
<title>Redirecting...</title>
206-
If you are not redirected automatically,
207-
follow the <a href='${url}'>link to login</a>
208-
`
209-
}
210-
211-
export default {
212-
handler,
213-
redirectBody,
214-
sendErrorPage,
215-
sendErrorResponse,
216-
setAuthenticateHeader
217-
}
1+
import { server as debug } from '../debug.mjs'
2+
import fs from 'fs'
3+
import { fileURLToPath } from 'url'
4+
import * as util from '../utils.mjs'
5+
import Auth from '../api/authn/index.mjs'
6+
7+
function statusCodeFor (err, req, authMethod) {
8+
let statusCode = err.status || err.statusCode || 500
9+
10+
if (authMethod === 'oidc') {
11+
statusCode = Auth.oidc.statusCodeOverride(statusCode, req)
12+
}
13+
14+
return statusCode
15+
}
16+
17+
export function setAuthenticateHeader (req, res, err) {
18+
const locals = req.app.locals
19+
const authMethod = locals.authMethod
20+
21+
switch (authMethod) {
22+
case 'oidc':
23+
Auth.oidc.setAuthenticateHeader(req, res, err)
24+
break
25+
case 'tls':
26+
Auth.tls.setAuthenticateHeader(req, res)
27+
break
28+
default:
29+
break
30+
}
31+
}
32+
33+
export function sendErrorResponse (statusCode, res, err) {
34+
res.status(statusCode)
35+
res.header('Content-Type', 'text/plain;charset=utf-8')
36+
res.send(err.message + '\n')
37+
}
38+
39+
export function sendErrorPage (statusCode, res, err, ldp) {
40+
const errorPage = ldp.errorPages + statusCode.toString() + '.html'
41+
42+
return new Promise((resolve) => {
43+
fs.readFile(errorPage, 'utf8', (readErr, text) => {
44+
if (readErr) {
45+
return resolve(sendErrorResponse(statusCode, res, err))
46+
}
47+
48+
res.status(statusCode)
49+
res.header('Content-Type', 'text/html')
50+
res.send(text)
51+
resolve()
52+
})
53+
})
54+
}
55+
56+
function renderDataBrowser (req, res) {
57+
res.set('Content-Type', 'text/html')
58+
const ldp = req.app.locals.ldp
59+
const defaultDataBrowser = import.meta.resolve('mashlib/dist/databrowser.html')
60+
let dataBrowserPath = ldp.dataBrowserPath === 'default' ? defaultDataBrowser : ldp.dataBrowserPath
61+
debug(' sending data browser file: ' + dataBrowserPath)
62+
// `import.meta.resolve` returns a file:// URL string; convert it to a
63+
// filesystem path for `fs.readFileSync` when necessary.
64+
if (typeof dataBrowserPath === 'string' && dataBrowserPath.startsWith('file://')) {
65+
dataBrowserPath = fileURLToPath(dataBrowserPath)
66+
}
67+
const dataBrowserHtml = fs.readFileSync(dataBrowserPath, 'utf8')
68+
res.set('content-type', 'text/html')
69+
res.send(dataBrowserHtml)
70+
}
71+
72+
export function handler (err, req, res, next) {
73+
debug('Error page because of:', err)
74+
75+
const locals = req.app.locals
76+
const authMethod = locals.authMethod
77+
const ldp = locals.ldp
78+
79+
if (ldp.errorHandler) {
80+
debug('Using custom error handler')
81+
return ldp.errorHandler(err, req, res, next)
82+
}
83+
84+
const statusCode = statusCodeFor(err, req, authMethod)
85+
switch (statusCode) {
86+
case 401:
87+
setAuthenticateHeader(req, res, err)
88+
renderLoginRequired(req, res, err)
89+
break
90+
case 403:
91+
renderNoPermission(req, res, err)
92+
break
93+
default:
94+
if (ldp.noErrorPages) {
95+
sendErrorResponse(statusCode, res, err)
96+
} else {
97+
sendErrorPage(statusCode, res, err, ldp)
98+
}
99+
}
100+
}
101+
102+
function renderLoginRequired (req, res, err) {
103+
const currentUrl = util.fullUrlForReq(req)
104+
debug(`Display login-required for ${currentUrl}`)
105+
res.statusMessage = err.message
106+
res.status(401)
107+
if (req.accepts('html')) {
108+
renderDataBrowser(req, res)
109+
} else {
110+
res.send('Not Authenticated')
111+
}
112+
}
113+
114+
function renderNoPermission (req, res, err) {
115+
const currentUrl = util.fullUrlForReq(req)
116+
debug(`Display no-permission for ${currentUrl}`)
117+
res.statusMessage = err.message
118+
res.status(403)
119+
if (req.accepts('html')) {
120+
renderDataBrowser(req, res)
121+
} else {
122+
res.send('Not Authorized')
123+
}
124+
}
125+
126+
export function redirectBody (url) {
127+
return `<!DOCTYPE HTML>
128+
<meta charset="UTF-8">
129+
<script>
130+
window.location.href = "${url}" + encodeURIComponent(window.location.hash)
131+
</script>
132+
<noscript>
133+
<meta http-equiv="refresh" content="0; url=${url}">
134+
</noscript>
135+
<title>Redirecting...</title>
136+
If you are not redirected automatically,
137+
follow the <a href='${url}'>link to login</a>
138+
`
139+
}
140+
141+
export default {
142+
handler,
143+
redirectBody,
144+
sendErrorPage,
145+
sendErrorResponse,
146+
setAuthenticateHeader
147+
}

0 commit comments

Comments
 (0)