wiki-server 0.26.0-rc.0 → 0.26.0-rc.1
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/lib/page.js +53 -66
- package/lib/plugins.js +6 -6
- package/lib/search.js +5 -5
- package/lib/security.js +2 -2
- package/lib/server.js +65 -80
- package/lib/sitemap.js +6 -6
- package/package.json +2 -4
package/lib/page.js
CHANGED
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
const fs = require('fs')
|
|
14
14
|
const path = require('path')
|
|
15
15
|
const events = require('events')
|
|
16
|
-
const glob = require('glob')
|
|
17
16
|
|
|
18
17
|
const async = require('async')
|
|
19
18
|
|
|
@@ -35,6 +34,25 @@ module.exports = exports = argv => {
|
|
|
35
34
|
if (e) throw e
|
|
36
35
|
})
|
|
37
36
|
|
|
37
|
+
// create a list of plugin pages.
|
|
38
|
+
const pluginPages = new Map()
|
|
39
|
+
Object.keys(require.main.require('./package').dependencies)
|
|
40
|
+
.filter(depend => depend.startsWith('wiki-plugin'))
|
|
41
|
+
.forEach(plugin => {
|
|
42
|
+
const pagesPath = path.join(
|
|
43
|
+
path.dirname(require.resolve(`${plugin}/package`, { paths: require.main.paths })),
|
|
44
|
+
'pages',
|
|
45
|
+
)
|
|
46
|
+
fs.readdir(pagesPath, { withFileTypes: true }, (err, entries) => {
|
|
47
|
+
if (err) return
|
|
48
|
+
entries.forEach(entry => {
|
|
49
|
+
if (entry.isFile() && !pluginPages.has(entry.name)) {
|
|
50
|
+
pluginPages.set(entry.name, { pluginName: plugin, pluginPath: entry.parentPath })
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
38
56
|
// #### Private utility methods. ####
|
|
39
57
|
const load_parse = (loc, cb, annotations = {}) => {
|
|
40
58
|
let page
|
|
@@ -46,14 +64,13 @@ module.exports = exports = argv => {
|
|
|
46
64
|
const errorPage = path.basename(loc)
|
|
47
65
|
const errorPagePath = path.dirname(loc)
|
|
48
66
|
const recyclePage = path.resolve(errorPagePath, '..', 'recycle', errorPage)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (exists) {
|
|
67
|
+
fs.access(path.dirname(recyclePage), fs.constants.F_OK, err => {
|
|
68
|
+
if (!err) {
|
|
52
69
|
fs.rename(loc, recyclePage, err => {
|
|
53
70
|
if (err) {
|
|
54
|
-
console.log(
|
|
71
|
+
console.log(`ERROR: moving problem page ${loc} to recycler`, err)
|
|
55
72
|
} else {
|
|
56
|
-
console.log(
|
|
73
|
+
console.log(`ERROR: problem page ${loc} moved to recycler`)
|
|
57
74
|
}
|
|
58
75
|
})
|
|
59
76
|
} else {
|
|
@@ -63,9 +80,9 @@ module.exports = exports = argv => {
|
|
|
63
80
|
} else {
|
|
64
81
|
fs.rename(loc, recyclePage, err => {
|
|
65
82
|
if (err) {
|
|
66
|
-
console.log(
|
|
83
|
+
console.log(`ERROR: moving problem page ${loc} to recycler`, err)
|
|
67
84
|
} else {
|
|
68
|
-
console.log(
|
|
85
|
+
console.log(`ERROR: problem page ${loc} moved to recycler`)
|
|
69
86
|
}
|
|
70
87
|
})
|
|
71
88
|
}
|
|
@@ -104,9 +121,8 @@ module.exports = exports = argv => {
|
|
|
104
121
|
const tryDefaults = (file, cb) => {
|
|
105
122
|
const lastDefault = cb => {
|
|
106
123
|
const defloc = path.join(argv.root, 'default-data', 'pages', file)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (exists) {
|
|
124
|
+
fs.access(defloc, fs.constants.F_OK, err => {
|
|
125
|
+
if (!err) {
|
|
110
126
|
cb(defloc)
|
|
111
127
|
} else {
|
|
112
128
|
cb(null)
|
|
@@ -115,10 +131,8 @@ module.exports = exports = argv => {
|
|
|
115
131
|
}
|
|
116
132
|
if (argv.defaults) {
|
|
117
133
|
const defloc = path.join(argv.data, '..', argv.defaults, 'pages', file)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
fs.exists(defloc, exists => {
|
|
121
|
-
if (exists) {
|
|
134
|
+
fs.access(defloc, fs.constants.F_OK, err => {
|
|
135
|
+
if (!err) {
|
|
122
136
|
cb(defloc)
|
|
123
137
|
} else {
|
|
124
138
|
lastDefault(cb)
|
|
@@ -138,22 +152,19 @@ module.exports = exports = argv => {
|
|
|
138
152
|
case 'delete':
|
|
139
153
|
if (file.startsWith('recycler/')) {
|
|
140
154
|
// delete from recycler
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
if (exists)
|
|
155
|
+
fs.access(loc, fs.constants.F_OK, err => {
|
|
156
|
+
if (!err)
|
|
144
157
|
fs.unlink(loc, err => {
|
|
145
158
|
cb(err)
|
|
146
159
|
})
|
|
147
160
|
})
|
|
148
161
|
} else {
|
|
149
162
|
// move page to recycler
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (exists) {
|
|
163
|
+
fs.access(loc, fs.constants.F_OK, err => {
|
|
164
|
+
if (!err) {
|
|
153
165
|
const recycleLoc = path.join(argv.recycler, file)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (exists) {
|
|
166
|
+
fs.access(path.dirname(recycleLoc), fs.constants.F_OK, err => {
|
|
167
|
+
if (!err) {
|
|
157
168
|
fs.rename(loc, recycleLoc, err => {
|
|
158
169
|
cb(err)
|
|
159
170
|
})
|
|
@@ -203,13 +214,11 @@ module.exports = exports = argv => {
|
|
|
203
214
|
return
|
|
204
215
|
}
|
|
205
216
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (exists) {
|
|
217
|
+
fs.access(loc, fs.constants.F_OK, err => {
|
|
218
|
+
if (!err) {
|
|
209
219
|
const recycleLoc = path.join(argv.recycler, file)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (exists) {
|
|
220
|
+
fs.access(path.dirname(recycleLoc), fs.constants.F_OK, err => {
|
|
221
|
+
if (!err) {
|
|
213
222
|
copyFile(loc, recycleLoc, err => {
|
|
214
223
|
cb(err)
|
|
215
224
|
})
|
|
@@ -229,42 +238,20 @@ module.exports = exports = argv => {
|
|
|
229
238
|
break
|
|
230
239
|
}
|
|
231
240
|
case 'get':
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (exists) {
|
|
241
|
+
fs.access(loc, fs.constants.F_OK, err => {
|
|
242
|
+
if (!err) {
|
|
235
243
|
load_parse(loc, cb, { plugin: undefined })
|
|
236
244
|
} else {
|
|
237
245
|
tryDefaults(file, defloc => {
|
|
238
246
|
if (defloc) {
|
|
239
247
|
load_parse(defloc, cb)
|
|
240
248
|
} else {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
let count = plugins.length
|
|
250
|
-
const giveUp = () => {
|
|
251
|
-
count -= 1
|
|
252
|
-
if (count === 0) {
|
|
253
|
-
cb(null, 'Page not found', 404)
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
plugins.forEach(plugin => {
|
|
257
|
-
const pluginName = plugin.slice(12, -6)
|
|
258
|
-
const pluginloc = path.join(argv.packageDir, plugin, file)
|
|
259
|
-
fs.exists(pluginloc, exists => {
|
|
260
|
-
if (exists) {
|
|
261
|
-
load_parse(pluginloc, cb, { plugin: pluginName })
|
|
262
|
-
} else {
|
|
263
|
-
giveUp()
|
|
264
|
-
}
|
|
265
|
-
})
|
|
266
|
-
})
|
|
267
|
-
})
|
|
249
|
+
if (pluginPages.has(file)) {
|
|
250
|
+
const { pluginName, pluginPath } = pluginPages.get(file)
|
|
251
|
+
load_parse(path.join(pluginPath, file), cb, { plugin: pluginName.slice(12) })
|
|
252
|
+
} else {
|
|
253
|
+
cb(null, 'Page not found', 404)
|
|
254
|
+
}
|
|
268
255
|
}
|
|
269
256
|
})
|
|
270
257
|
}
|
|
@@ -272,11 +259,11 @@ module.exports = exports = argv => {
|
|
|
272
259
|
break
|
|
273
260
|
case 'put':
|
|
274
261
|
page = JSON.stringify(page, null, 2)
|
|
275
|
-
fs.
|
|
276
|
-
if (
|
|
262
|
+
fs.access(path.dirname(loc), fs.constants.F_OK, err => {
|
|
263
|
+
if (!err) {
|
|
277
264
|
fs.writeFile(loc, page, err => {
|
|
278
265
|
if (err) {
|
|
279
|
-
console.log(
|
|
266
|
+
console.log(`ERROR: write file ${loc} `, err)
|
|
280
267
|
}
|
|
281
268
|
cb(err)
|
|
282
269
|
})
|
|
@@ -285,7 +272,7 @@ module.exports = exports = argv => {
|
|
|
285
272
|
if (err) cb(err)
|
|
286
273
|
fs.writeFile(loc, page, err => {
|
|
287
274
|
if (err) {
|
|
288
|
-
console.log(
|
|
275
|
+
console.log(`ERROR: write file ${loc} `, err)
|
|
289
276
|
}
|
|
290
277
|
cb(err)
|
|
291
278
|
})
|
|
@@ -294,7 +281,7 @@ module.exports = exports = argv => {
|
|
|
294
281
|
})
|
|
295
282
|
break
|
|
296
283
|
default:
|
|
297
|
-
console.log(
|
|
284
|
+
console.log(`pagehandler: unrecognized action ${action}`)
|
|
298
285
|
}
|
|
299
286
|
}
|
|
300
287
|
|
|
@@ -407,7 +394,7 @@ module.exports = exports = argv => {
|
|
|
407
394
|
try {
|
|
408
395
|
pageLinksMap = page.story.reduce(extractPageLinks, new Map())
|
|
409
396
|
} catch (err) {
|
|
410
|
-
console.log(
|
|
397
|
+
console.log(`METADATA *** ${wikiName} reduce to extract links on ${file} failed`, err.message)
|
|
411
398
|
pageLinksMap = []
|
|
412
399
|
}
|
|
413
400
|
//
|
package/lib/plugins.js
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
// support server-side plugins
|
|
10
10
|
|
|
11
11
|
const fs = require('node:fs')
|
|
12
|
-
const glob = require('glob')
|
|
13
12
|
const { pathToFileURL } = require('node:url')
|
|
14
13
|
// forward = require './forward'
|
|
15
14
|
|
|
@@ -24,8 +23,8 @@ module.exports = exports = argv => {
|
|
|
24
23
|
|
|
25
24
|
const startServer = (params, plugin) => {
|
|
26
25
|
const server = `${argv.packageDir}/${plugin}/server/server.js`
|
|
27
|
-
fs.
|
|
28
|
-
if (
|
|
26
|
+
fs.access(server, fs.constants.F_OK, err => {
|
|
27
|
+
if (!err) {
|
|
29
28
|
console.log('starting plugin', plugin)
|
|
30
29
|
import(pathToFileURL(server))
|
|
31
30
|
.then(exported => {
|
|
@@ -43,11 +42,12 @@ module.exports = exports = argv => {
|
|
|
43
42
|
// emitter = new events.EventEmitter()
|
|
44
43
|
// forward.init params.app, emitter
|
|
45
44
|
// params.emitter = emitter
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
|
|
46
|
+
Object.keys(require.main.require('./package').dependencies)
|
|
47
|
+
.filter(depend => depend.startsWith('wiki-plugin'))
|
|
48
|
+
.forEach(plugin => {
|
|
48
49
|
startServer(params, plugin)
|
|
49
50
|
})
|
|
50
|
-
})
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
return { startServers }
|
package/lib/search.js
CHANGED
|
@@ -85,8 +85,8 @@ module.exports = exports = argv => {
|
|
|
85
85
|
|
|
86
86
|
const searchSave = (siteIndex, cb) => {
|
|
87
87
|
// save index to file
|
|
88
|
-
fs.
|
|
89
|
-
if (
|
|
88
|
+
fs.access(argv.status, fs.constants.F_OK, err => {
|
|
89
|
+
if (!err) {
|
|
90
90
|
writeFileAtomic(siteIndexLoc, JSON.stringify(siteIndex), e => {
|
|
91
91
|
if (e) return cb(e)
|
|
92
92
|
touch(indexUpdateFlag, () => {
|
|
@@ -108,8 +108,8 @@ module.exports = exports = argv => {
|
|
|
108
108
|
|
|
109
109
|
const searchRestore = cb => {
|
|
110
110
|
// restore index, or create if it doesn't already exist
|
|
111
|
-
fs.
|
|
112
|
-
if (
|
|
111
|
+
fs.access(siteIndexLoc, fs.constants.F_OK, err => {
|
|
112
|
+
if (!err) {
|
|
113
113
|
fs.readFile(siteIndexLoc, (err, data) => {
|
|
114
114
|
if (err) return cb(err)
|
|
115
115
|
try {
|
|
@@ -250,7 +250,7 @@ module.exports = exports = argv => {
|
|
|
250
250
|
// we save the pagehandler, so we can recreate the site index if it is removed
|
|
251
251
|
searchPageHandler = searchPageHandler ?? pagehandler
|
|
252
252
|
|
|
253
|
-
//timeLabel =
|
|
253
|
+
//timeLabel = `SITE INDEX ${wikiName} : Created`
|
|
254
254
|
//console.time timeLabel
|
|
255
255
|
|
|
256
256
|
pagehandler.slugs((e, slugs) => {
|
package/lib/security.js
CHANGED
|
@@ -41,8 +41,8 @@ module.exports = exports = (log, loga, argv) => {
|
|
|
41
41
|
|
|
42
42
|
// Retrieve owner infomation from identity file in status directory
|
|
43
43
|
security.retrieveOwner = cb => {
|
|
44
|
-
fs.
|
|
45
|
-
if (
|
|
44
|
+
fs.access(idFile, fs.constants.F_OK, err => {
|
|
45
|
+
if (!err) {
|
|
46
46
|
fs.readFile(idFile, (err, data) => {
|
|
47
47
|
if (err) return cb(err)
|
|
48
48
|
owner += data
|
package/lib/server.js
CHANGED
|
@@ -28,7 +28,6 @@ const { pipeline } = require('node:stream/promises')
|
|
|
28
28
|
// From npm
|
|
29
29
|
const express = require('express')
|
|
30
30
|
const hbs = require('express-hbs')
|
|
31
|
-
const glob = require('glob')
|
|
32
31
|
const async = require('async')
|
|
33
32
|
const f = require('flates')
|
|
34
33
|
|
|
@@ -38,8 +37,7 @@ const { JSDOM } = require('jsdom')
|
|
|
38
37
|
const window = new JSDOM('').window
|
|
39
38
|
const DOMPurify = createDOMPurify(window)
|
|
40
39
|
|
|
41
|
-
//
|
|
42
|
-
const fetch = (...args) => import('node-fetch').then(({ default: fetch }) => fetch(...args))
|
|
40
|
+
// Using native fetch API (available in Node.js 18+)
|
|
43
41
|
|
|
44
42
|
// Express 4 middleware
|
|
45
43
|
const logger = require('morgan')
|
|
@@ -163,7 +161,7 @@ module.exports = exports = argv => {
|
|
|
163
161
|
|
|
164
162
|
const remoteGet = (remote, slug, cb) => {
|
|
165
163
|
// assume http, as we know no better at this point and we need to specify a protocol.
|
|
166
|
-
const remoteURL = new URL(
|
|
164
|
+
const remoteURL = new URL(`http://${remote}/${slug}.json`).toString()
|
|
167
165
|
// set a two second timeout
|
|
168
166
|
fetch(remoteURL, { signal: AbortSignal.timeout(2000) })
|
|
169
167
|
.then(res => {
|
|
@@ -271,13 +269,16 @@ module.exports = exports = argv => {
|
|
|
271
269
|
app.use('/assets', cors, express.static(argv.assets))
|
|
272
270
|
|
|
273
271
|
// Add static routes to the plugins client.
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
272
|
+
Object.keys(require.main.require('./package').dependencies)
|
|
273
|
+
.filter(depend => depend.startsWith('wiki-plugin'))
|
|
274
|
+
.forEach(plugin => {
|
|
275
|
+
const clientPath = path.join(
|
|
276
|
+
path.dirname(require.resolve(`${plugin}/package`, { paths: require.main.paths })),
|
|
277
|
+
'client',
|
|
278
|
+
)
|
|
279
|
+
const pluginPath = '/plugins/' + plugin.slice(12)
|
|
280
|
+
app.use(pluginPath, cors, express.static(clientPath, staticPathOptions))
|
|
279
281
|
})
|
|
280
|
-
})
|
|
281
282
|
|
|
282
283
|
// Add static routes to the security client.
|
|
283
284
|
if (argv.security != './security') {
|
|
@@ -387,32 +388,17 @@ module.exports = exports = argv => {
|
|
|
387
388
|
app.get('/system/factories.json', (req, res) => {
|
|
388
389
|
res.status(200)
|
|
389
390
|
res.header('Content-Type', 'application/json')
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (err) {
|
|
399
|
-
return cb()
|
|
400
|
-
}
|
|
401
|
-
try {
|
|
402
|
-
const factory = JSON.parse(data)
|
|
403
|
-
cb(null, factory)
|
|
404
|
-
} catch (err) {
|
|
405
|
-
return cb()
|
|
406
|
-
}
|
|
407
|
-
})
|
|
408
|
-
}
|
|
409
|
-
async.map(files, doFactories, (e, factories) => {
|
|
410
|
-
if (e) {
|
|
411
|
-
res.e(e)
|
|
391
|
+
const factories = []
|
|
392
|
+
Object.keys(require.main.require('./package').dependencies)
|
|
393
|
+
.filter(depend => depend.startsWith('wiki-plugin'))
|
|
394
|
+
.forEach(plugin => {
|
|
395
|
+
try {
|
|
396
|
+
factories.push(require.main.require(`${plugin}/factory`))
|
|
397
|
+
} catch {
|
|
398
|
+
// do nothing if plugin doesn't have a factory category.
|
|
412
399
|
}
|
|
413
|
-
res.end(JSON.stringify(factories))
|
|
414
400
|
})
|
|
415
|
-
|
|
401
|
+
res.end(JSON.stringify(factories))
|
|
416
402
|
})
|
|
417
403
|
|
|
418
404
|
// ###### Json Routes ######
|
|
@@ -444,7 +430,7 @@ module.exports = exports = argv => {
|
|
|
444
430
|
// If themes doesn't exist send 404 and let the client
|
|
445
431
|
// deal with it.
|
|
446
432
|
app.get(/^\/theme\/(\w+\.\w+)$/, cors, (req, res) => {
|
|
447
|
-
res.sendFile(path.join(argv.status, 'theme', req.params[0]), e => {
|
|
433
|
+
res.sendFile(path.join(argv.status, 'theme', req.params[0]), { dotfiles: 'allow' }, e => {
|
|
448
434
|
if (e) {
|
|
449
435
|
// swallow the error if the theme does not exist...
|
|
450
436
|
if (req.path === '/theme/style.css') {
|
|
@@ -462,9 +448,9 @@ module.exports = exports = argv => {
|
|
|
462
448
|
const favLoc = path.join(argv.status, 'favicon.png')
|
|
463
449
|
const defaultFavLoc = path.join(argv.root, 'default-data', 'status', 'favicon.png')
|
|
464
450
|
app.get('/favicon.png', cors, (req, res) => {
|
|
465
|
-
fs.
|
|
466
|
-
if (
|
|
467
|
-
res.sendFile(favLoc)
|
|
451
|
+
fs.access(favLoc, fs.constants.F_OK, err => {
|
|
452
|
+
if (!err) {
|
|
453
|
+
res.sendFile(favLoc, { dotfiles: 'allow' })
|
|
468
454
|
} else {
|
|
469
455
|
res.sendFile(defaultFavLoc)
|
|
470
456
|
}
|
|
@@ -484,9 +470,9 @@ module.exports = exports = argv => {
|
|
|
484
470
|
// save it.
|
|
485
471
|
app.post('/favicon.png', authorized, (req, res) => {
|
|
486
472
|
const favicon = req.body.image.replace(/^data:image\/png;base64,/, '')
|
|
487
|
-
const buf =
|
|
488
|
-
fs.
|
|
489
|
-
if (
|
|
473
|
+
const buf = Buffer.from(favicon, 'base64')
|
|
474
|
+
fs.access(argv.status, fs.constants.F_OK, err => {
|
|
475
|
+
if (!err) {
|
|
490
476
|
fs.writeFile(favLoc, buf, e => {
|
|
491
477
|
if (e) {
|
|
492
478
|
return res.e(e)
|
|
@@ -508,7 +494,7 @@ module.exports = exports = argv => {
|
|
|
508
494
|
|
|
509
495
|
// Redirect remote favicons to the server they are needed from.
|
|
510
496
|
app.get(/^\/remote\/([a-zA-Z0-9:.-]+\/favicon.png)$/, (req, res) => {
|
|
511
|
-
const remotefav =
|
|
497
|
+
const remotefav = `http://${req.params[0]}`
|
|
512
498
|
res.redirect(remotefav)
|
|
513
499
|
})
|
|
514
500
|
|
|
@@ -519,7 +505,7 @@ module.exports = exports = argv => {
|
|
|
519
505
|
// negative space outward pointing arrows nicely indicates that items can be removed
|
|
520
506
|
const recyclerFavLoc = path.join(argv.root, 'default-data', 'status', 'recycler.png')
|
|
521
507
|
app.get('/recycler/favicon.png', authorized, (req, res) => {
|
|
522
|
-
res.sendFile(recyclerFavLoc)
|
|
508
|
+
res.sendFile(recyclerFavLoc, { dotfiles: 'allow' })
|
|
523
509
|
})
|
|
524
510
|
|
|
525
511
|
// Send an array of pages currently in the recycler via json
|
|
@@ -590,21 +576,21 @@ module.exports = exports = argv => {
|
|
|
590
576
|
|
|
591
577
|
// Returns a list of installed plugins. (does this get called anymore!)
|
|
592
578
|
app.get('/system/plugins.json', cors, (req, res) => {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
res.
|
|
600
|
-
}
|
|
579
|
+
try {
|
|
580
|
+
const pluginNames = Object.keys(require.main.require('./package').dependencies)
|
|
581
|
+
.filter(depend => depend.startsWith('wiki-plugin'))
|
|
582
|
+
.map(name => name.slice(12))
|
|
583
|
+
res.send(pluginNames)
|
|
584
|
+
} catch (e) {
|
|
585
|
+
return res.e(e)
|
|
586
|
+
}
|
|
601
587
|
})
|
|
602
588
|
//{
|
|
603
589
|
const sitemapLoc = path.join(argv.status, 'sitemap.json')
|
|
604
590
|
app.get('/system/sitemap.json', cors, (req, res) => {
|
|
605
|
-
fs.
|
|
606
|
-
if (
|
|
607
|
-
res.sendFile(sitemapLoc)
|
|
591
|
+
fs.access(sitemapLoc, fs.constants.F_OK, err => {
|
|
592
|
+
if (!err) {
|
|
593
|
+
res.sendFile(sitemapLoc, { dotfiles: 'allow' })
|
|
608
594
|
} else {
|
|
609
595
|
// only createSitemap if we are not already creating one
|
|
610
596
|
if (!sitemaphandler.isWorking()) {
|
|
@@ -612,7 +598,7 @@ module.exports = exports = argv => {
|
|
|
612
598
|
}
|
|
613
599
|
// wait for the sitemap file to be written, before sending
|
|
614
600
|
sitemaphandler.once('finished', () => {
|
|
615
|
-
res.sendFile(sitemapLoc)
|
|
601
|
+
res.sendFile(sitemapLoc, { dotfiles: 'allow' })
|
|
616
602
|
})
|
|
617
603
|
}
|
|
618
604
|
})
|
|
@@ -620,15 +606,15 @@ module.exports = exports = argv => {
|
|
|
620
606
|
|
|
621
607
|
const xmlSitemapLoc = path.join(argv.status, 'sitemap.xml')
|
|
622
608
|
app.get('/sitemap.xml', cors, (req, res) => {
|
|
623
|
-
fs.
|
|
624
|
-
if (
|
|
625
|
-
res.sendFile(xmlSitemapLoc)
|
|
609
|
+
fs.access(sitemapLoc, fs.constants.F_OK, err => {
|
|
610
|
+
if (!err) {
|
|
611
|
+
res.sendFile(xmlSitemapLoc, { dotfiles: 'allow' })
|
|
626
612
|
} else {
|
|
627
613
|
if (!sitemaphandler.isWorking()) {
|
|
628
614
|
sitemaphandler.createSitemap(pagehandler)
|
|
629
615
|
}
|
|
630
616
|
sitemaphandler.once('finished', () => {
|
|
631
|
-
res.sendFile(xmlSitemapLoc)
|
|
617
|
+
res.sendFile(xmlSitemapLoc, { dotfiles: 'allow' })
|
|
632
618
|
})
|
|
633
619
|
}
|
|
634
620
|
})
|
|
@@ -636,16 +622,16 @@ module.exports = exports = argv => {
|
|
|
636
622
|
|
|
637
623
|
const searchIndexLoc = path.join(argv.status, 'site-index.json')
|
|
638
624
|
app.get('/system/site-index.json', cors, (req, res) => {
|
|
639
|
-
fs.
|
|
640
|
-
if (
|
|
641
|
-
res.sendFile(searchIndexLoc)
|
|
625
|
+
fs.access(searchIndexLoc, fs.constants.F_OK, err => {
|
|
626
|
+
if (!err) {
|
|
627
|
+
res.sendFile(searchIndexLoc, { dotfiles: 'allow' })
|
|
642
628
|
} else {
|
|
643
629
|
// only create index if we are not already creating one
|
|
644
630
|
if (!searchhandler.isWorking()) {
|
|
645
631
|
searchhandler.createIndex(pagehandler)
|
|
646
632
|
}
|
|
647
633
|
searchhandler.once('indexed', () => {
|
|
648
|
-
res.sendFile(searchIndexLoc)
|
|
634
|
+
res.sendFile(searchIndexLoc, { dotfiles: 'allow' })
|
|
649
635
|
})
|
|
650
636
|
}
|
|
651
637
|
})
|
|
@@ -692,32 +678,31 @@ module.exports = exports = argv => {
|
|
|
692
678
|
|
|
693
679
|
app.get('/system/version.json', admin, (req, res) => {
|
|
694
680
|
const versions = {}
|
|
695
|
-
const wikiModule =
|
|
681
|
+
const wikiModule = require.main
|
|
696
682
|
versions[wikiModule.require('./package').name] = wikiModule.require('./package').version
|
|
697
683
|
versions[wikiModule.require('wiki-server/package').name] = wikiModule.require('wiki-server/package').version
|
|
698
684
|
versions[wikiModule.require('wiki-client/package').name] = wikiModule.require('wiki-client/package').version
|
|
685
|
+
|
|
699
686
|
versions['security'] = {}
|
|
700
|
-
|
|
687
|
+
Object.keys(require.main.require('./package').dependencies)
|
|
688
|
+
.filter(depend => depend.startsWith('wiki-security'))
|
|
689
|
+
.forEach(key => {
|
|
690
|
+
versions.security[key] = wikiModule.require(`${key}/package`).version
|
|
691
|
+
})
|
|
701
692
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
).version
|
|
708
|
-
} else {
|
|
709
|
-
versions.plugins[wikiModule.require(plugin + '/package').name] = wikiModule.require(
|
|
710
|
-
plugin + '/package',
|
|
711
|
-
).version
|
|
712
|
-
}
|
|
713
|
-
res.json(versions)
|
|
693
|
+
versions['plugins'] = {}
|
|
694
|
+
Object.keys(require.main.require('./package').dependencies)
|
|
695
|
+
.filter(depend => depend.startsWith('wiki-plugin'))
|
|
696
|
+
.forEach(key => {
|
|
697
|
+
versions.plugins[key] = wikiModule.require(`${key}/package`).version
|
|
714
698
|
})
|
|
715
|
-
|
|
699
|
+
|
|
700
|
+
res.json(versions)
|
|
716
701
|
})
|
|
717
702
|
|
|
718
703
|
// ##### Proxy routes #####
|
|
719
704
|
|
|
720
|
-
app.get('/proxy/*', authorized, (req, res) => {
|
|
705
|
+
app.get('/proxy/*splat', authorized, (req, res) => {
|
|
721
706
|
const pathParts = req.originalUrl.split('/')
|
|
722
707
|
const remoteHost = pathParts[2]
|
|
723
708
|
pathParts.splice(0, 3)
|
|
@@ -731,7 +716,7 @@ module.exports = exports = argv => {
|
|
|
731
716
|
requestURL.endsWith('.jpg') ||
|
|
732
717
|
pathParts[0] === 'plugin'
|
|
733
718
|
) {
|
|
734
|
-
fetch(requestURL, {
|
|
719
|
+
fetch(requestURL, { signal: AbortSignal.timeout(2000) })
|
|
735
720
|
.then(async fetchRes => {
|
|
736
721
|
if (fetchRes.ok) {
|
|
737
722
|
res.set('content-type', fetchRes.headers.get('content-type'))
|
package/lib/sitemap.js
CHANGED
|
@@ -119,8 +119,8 @@ module.exports = exports = argv => {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
const sitemapSave = (sitemap, cb) => {
|
|
122
|
-
fs.
|
|
123
|
-
if (
|
|
122
|
+
fs.access(argv.status, fs.constants.F_OK, err => {
|
|
123
|
+
if (!err) {
|
|
124
124
|
writeFileAtomic(sitemapLoc, JSON.stringify(sitemap), e => {
|
|
125
125
|
if (e) return cb(e)
|
|
126
126
|
cb()
|
|
@@ -136,8 +136,8 @@ module.exports = exports = argv => {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
const sitemapRestore = cb => {
|
|
139
|
-
fs.
|
|
140
|
-
if (
|
|
139
|
+
fs.access(sitemapLoc, fs.constants.F_OK, err => {
|
|
140
|
+
if (!err) {
|
|
141
141
|
fs.readFile(sitemapLoc, (err, data) => {
|
|
142
142
|
if (err) return cb(err)
|
|
143
143
|
try {
|
|
@@ -172,8 +172,8 @@ module.exports = exports = argv => {
|
|
|
172
172
|
const xmlmap = { urlset: { $: { xmlns: 'http://www.sitemaps.org/schemas/sitemap/0.9' }, url: xmlmapPages } }
|
|
173
173
|
const builder = new xml2js.Builder()
|
|
174
174
|
const xml = builder.buildObject(xmlmap)
|
|
175
|
-
fs.
|
|
176
|
-
if (
|
|
175
|
+
fs.access(argv.status, fs.constants.F_OK, err => {
|
|
176
|
+
if (!err) {
|
|
177
177
|
writeFileAtomic(xmlSitemapLoc, xml, e => {
|
|
178
178
|
if (e) return cb(e)
|
|
179
179
|
cb()
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wiki-server",
|
|
3
3
|
"description": "A Federated Wiki Server",
|
|
4
|
-
"version": "0.26.0-rc.
|
|
4
|
+
"version": "0.26.0-rc.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Ward Cunningham",
|
|
7
7
|
"email": "ward@c2.com",
|
|
@@ -37,15 +37,13 @@
|
|
|
37
37
|
"cookie-parser": "^1.4.4",
|
|
38
38
|
"dompurify": "^3.1.0",
|
|
39
39
|
"errorhandler": "^1.5.1",
|
|
40
|
-
"express": "^
|
|
40
|
+
"express": "^5.1.0",
|
|
41
41
|
"express-hbs": "^2.5.0",
|
|
42
42
|
"flates": "0.0.5",
|
|
43
|
-
"glob": "^7.2.3",
|
|
44
43
|
"jsdom": "^26.0.0",
|
|
45
44
|
"method-override": "^3.0.0",
|
|
46
45
|
"minisearch": "^7.1.0",
|
|
47
46
|
"morgan": "^1.9.1",
|
|
48
|
-
"node-fetch": "^3.3.2",
|
|
49
47
|
"write-file-atomic": "^6.0.0",
|
|
50
48
|
"xml2js": "^0.6.2"
|
|
51
49
|
},
|