Skip to content

Commit 267a155

Browse files
committed
feat(createProtocol): use more secure protocol handler
from reasonably-secure-electron
1 parent 96b3f26 commit 267a155

File tree

1 file changed

+84
-35
lines changed

1 file changed

+84
-35
lines changed

lib/createProtocol.js

Lines changed: 84 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,90 @@
1+
/*
2+
Slightly modified from:
3+
4+
Reasonably Secure Electron
5+
Copyright (C) 2019 Bishop Fox
6+
This program is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU General Public License
8+
as published by the Free Software Foundation; either version 2
9+
of the License, or (at your option) any later version.
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
You should have received a copy of the GNU General Public License
15+
along with this program; if not, write to the Free Software
16+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
-------------------------------------------------------------------------
18+
Implementing a custom protocol achieves two goals:
19+
1) Allows us to use ES6 modules/targets for Angular
20+
2) Avoids running the app in a file:// origin
21+
*/
22+
123
import { protocol } from 'electron'
24+
import * as fs from 'fs'
225
import * as path from 'path'
3-
import { readFile } from 'fs'
426
import { URL } from 'url'
527

6-
export default (scheme, customProtocol) => {
7-
(customProtocol || protocol).registerBufferProtocol(
8-
scheme,
9-
(request, respond) => {
10-
let pathName = new URL(request.url).pathname
11-
pathName = decodeURI(pathName) // Needed in case URL contains spaces
12-
13-
readFile(path.join(__dirname, pathName), (error, data) => {
14-
if (error) {
15-
console.error(
16-
`Failed to read ${pathName} on ${scheme} protocol`,
17-
error
18-
)
19-
}
20-
const extension = path.extname(pathName).toLowerCase()
21-
let mimeType = ''
22-
23-
if (extension === '.js') {
24-
mimeType = 'text/javascript'
25-
} else if (extension === '.html') {
26-
mimeType = 'text/html'
27-
} else if (extension === '.css') {
28-
mimeType = 'text/css'
29-
} else if (extension === '.svg' || extension === '.svgz') {
30-
mimeType = 'image/svg+xml'
31-
} else if (extension === '.json') {
32-
mimeType = 'application/json'
33-
} else if (extension === '.wasm') {
34-
mimeType = 'application/wasm'
35-
}
36-
37-
respond({ mimeType, data })
28+
const mimeTypes = {
29+
'.js': 'text/javascript',
30+
'.mjs': 'text/javascript',
31+
'.html': 'text/html',
32+
'.htm': 'text/html',
33+
'.json': 'application/json',
34+
'.css': 'text/css',
35+
'.svg': 'application/svg+xml',
36+
'.ico': 'image/vnd.microsoft.icon',
37+
'.png': 'image/png',
38+
'.jpg': 'image/jpeg',
39+
'.map': 'text/plain'
40+
}
41+
42+
function charset (mimeType) {
43+
return ['.html', '.htm', '.js', '.mjs'].some((m) => m === mimeType)
44+
? 'utf-8'
45+
: null
46+
}
47+
48+
function mime (filename) {
49+
const type = mimeTypes[path.extname(`${filename || ''}`).toLowerCase()]
50+
return type || null
51+
}
52+
53+
export default (scheme, customProtocol) =>
54+
(customProtocol || protocol).registerBufferProtocol(scheme, (req, next) => {
55+
const reqUrl = new URL(req.url)
56+
57+
// If the path doesn't start with "/" then path.normalize will not
58+
// resolve all '..' and could lead to path traversal attacks
59+
if (!reqUrl.pathname.startsWith('/')) {
60+
return next({
61+
mimeType: null,
62+
charset: null,
63+
data: null
3864
})
3965
}
40-
)
41-
}
66+
67+
let reqPath = path.normalize(reqUrl.pathname)
68+
if (reqPath === '/') {
69+
reqPath = '/index.html'
70+
}
71+
72+
const reqFilename = path.basename(reqPath)
73+
fs.readFile(path.join(__dirname, reqPath), (err, data) => {
74+
const mimeType = mime(reqFilename)
75+
if (!err && mimeType !== null) {
76+
next({
77+
mimeType: mimeType,
78+
charset: charset(mimeType),
79+
data: data
80+
})
81+
} else {
82+
console.error(err)
83+
next({
84+
mimeType: null,
85+
charset: null,
86+
data: null
87+
})
88+
}
89+
})
90+
})

0 commit comments

Comments
 (0)