setup.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. const path = require('path')
  2. const uuid = require('uuid/v4')
  3. /* global WIKI */
  4. module.exports = () => {
  5. WIKI.config.site = {
  6. path: '',
  7. title: 'Wiki.js'
  8. }
  9. WIKI.system = require('./core/system')
  10. // ----------------------------------------
  11. // Load modules
  12. // ----------------------------------------
  13. const bodyParser = require('body-parser')
  14. const compression = require('compression')
  15. const express = require('express')
  16. const favicon = require('serve-favicon')
  17. const http = require('http')
  18. const Promise = require('bluebird')
  19. const fs = require('fs-extra')
  20. const _ = require('lodash')
  21. const cfgHelper = require('./helpers/config')
  22. const crypto = Promise.promisifyAll(require('crypto'))
  23. const pem2jwk = require('pem-jwk').pem2jwk
  24. // ----------------------------------------
  25. // Define Express App
  26. // ----------------------------------------
  27. let app = express()
  28. app.use(compression())
  29. // ----------------------------------------
  30. // Public Assets
  31. // ----------------------------------------
  32. app.use(favicon(path.join(WIKI.ROOTPATH, 'assets', 'favicon.ico')))
  33. app.use(express.static(path.join(WIKI.ROOTPATH, 'assets')))
  34. // ----------------------------------------
  35. // View Engine Setup
  36. // ----------------------------------------
  37. app.set('views', path.join(WIKI.SERVERPATH, 'views'))
  38. app.set('view engine', 'pug')
  39. app.use(bodyParser.json())
  40. app.use(bodyParser.urlencoded({ extended: false }))
  41. app.locals.config = WIKI.config
  42. app.locals.data = WIKI.data
  43. app.locals._ = require('lodash')
  44. // ----------------------------------------
  45. // HMR (Dev Mode Only)
  46. // ----------------------------------------
  47. if (global.DEV) {
  48. app.use(global.WP_DEV.devMiddleware)
  49. app.use(global.WP_DEV.hotMiddleware)
  50. }
  51. // ----------------------------------------
  52. // Controllers
  53. // ----------------------------------------
  54. app.get('*', async (req, res) => {
  55. let packageObj = await fs.readJson(path.join(WIKI.ROOTPATH, 'package.json'))
  56. res.render('setup', {
  57. packageObj,
  58. telemetryClientID: WIKI.telemetry.cid
  59. })
  60. })
  61. /**
  62. * Finalize
  63. */
  64. app.post('/finalize', async (req, res) => {
  65. WIKI.telemetry.sendEvent('setup', 'finalize')
  66. try {
  67. // Upgrade from WIKI.js 1.x?
  68. if (req.body.upgrade) {
  69. await WIKI.system.upgradeFromMongo({
  70. mongoCnStr: cfgHelper.parseConfigValue(req.body.upgMongo)
  71. })
  72. }
  73. // Create directory structure
  74. WIKI.logger.info('Creating data directories...')
  75. const dataPath = path.join(process.cwd(), 'data')
  76. await fs.ensureDir(dataPath)
  77. await fs.ensureDir(path.join(dataPath, 'cache'))
  78. await fs.ensureDir(path.join(dataPath, 'uploads'))
  79. // Set config
  80. _.set(WIKI.config, 'defaultEditor', 'markdown')
  81. _.set(WIKI.config, 'graphEndpoint', 'https://graph.requarks.io')
  82. _.set(WIKI.config, 'lang.code', 'en')
  83. _.set(WIKI.config, 'lang.autoUpdate', true)
  84. _.set(WIKI.config, 'lang.namespacing', false)
  85. _.set(WIKI.config, 'lang.namespaces', [])
  86. _.set(WIKI.config, 'public', false)
  87. _.set(WIKI.config, 'sessionSecret', (await crypto.randomBytesAsync(32)).toString('hex'))
  88. _.set(WIKI.config, 'telemetry.isEnabled', req.body.telemetry === 'true')
  89. _.set(WIKI.config, 'telemetry.clientId', WIKI.telemetry.cid)
  90. _.set(WIKI.config, 'theming.theme', 'default')
  91. _.set(WIKI.config, 'theming.darkMode', false)
  92. _.set(WIKI.config, 'title', 'Wiki.js')
  93. // Generate certificates
  94. WIKI.logger.info('Generating certificates...')
  95. const certs = crypto.generateKeyPairSync('rsa', {
  96. modulusLength: 2048,
  97. publicKeyEncoding: {
  98. type: 'pkcs1',
  99. format: 'pem'
  100. },
  101. privateKeyEncoding: {
  102. type: 'pkcs1',
  103. format: 'pem',
  104. cipher: 'aes-256-cbc',
  105. passphrase: WIKI.config.sessionSecret
  106. }
  107. })
  108. _.set(WIKI.config, 'certs.jwk', pem2jwk(certs.publicKey))
  109. _.set(WIKI.config, 'certs.public', certs.publicKey)
  110. _.set(WIKI.config, 'certs.private', certs.privateKey)
  111. // Save config to DB
  112. WIKI.logger.info('Persisting config to DB...')
  113. await WIKI.configSvc.saveToDb([
  114. 'defaultEditor',
  115. 'graphEndpoint',
  116. 'lang',
  117. 'public',
  118. 'sessionSecret',
  119. 'telemetry',
  120. 'theming',
  121. 'title',
  122. 'certs'
  123. ])
  124. // Create default locale
  125. WIKI.logger.info('Installing default locale...')
  126. await WIKI.models.locales.query().insert({
  127. code: 'en',
  128. strings: require('./locales/default.json'),
  129. isRTL: false,
  130. name: 'English',
  131. nativeName: 'English'
  132. })
  133. // Create default groups
  134. WIKI.logger.info('Creating default groups...')
  135. const adminGroup = await WIKI.models.groups.query().insert({
  136. name: 'Administrators',
  137. permissions: JSON.stringify(['manage:system']),
  138. isSystem: true
  139. })
  140. const guestGroup = await WIKI.models.groups.query().insert({
  141. name: 'Guests',
  142. permissions: JSON.stringify(['read:pages']),
  143. isSystem: true
  144. })
  145. // Load authentication strategies + enable local
  146. await WIKI.models.authentication.refreshStrategiesFromDisk()
  147. await WIKI.models.authentication.query().patch({ isEnabled: true }).where('key', 'local')
  148. // Load editors + enable default
  149. await WIKI.models.editors.refreshEditorsFromDisk()
  150. await WIKI.models.editors.query().patch({ isEnabled: true }).where('key', 'markdown')
  151. // Load loggers
  152. await WIKI.models.loggers.refreshLoggersFromDisk()
  153. // Load renderers
  154. await WIKI.models.renderers.refreshRenderersFromDisk()
  155. // Load search engines + enable default
  156. await WIKI.models.searchEngines.refreshSearchEnginesFromDisk()
  157. await WIKI.models.searchEngines.query().patch({ isEnabled: true }).where('key', 'db')
  158. // Load storage targets
  159. await WIKI.models.storage.refreshTargetsFromDisk()
  160. // Create root administrator
  161. WIKI.logger.info('Creating root administrator...')
  162. await WIKI.models.users.query().delete().where({
  163. providerKey: 'local',
  164. email: req.body.adminEmail
  165. })
  166. const adminUser = await WIKI.models.users.query().insert({
  167. email: req.body.adminEmail,
  168. provider: 'local',
  169. password: req.body.adminPassword,
  170. name: 'Administrator',
  171. locale: 'en',
  172. defaultEditor: 'markdown',
  173. tfaIsActive: false
  174. })
  175. await adminUser.$relatedQuery('groups').relate(adminGroup.id)
  176. // Create Guest account
  177. WIKI.logger.info('Creating guest account...')
  178. await WIKI.models.users.query().delete().where({
  179. providerKey: 'local',
  180. email: 'guest@example.com'
  181. })
  182. const guestUser = await WIKI.models.users.query().insert({
  183. provider: 'local',
  184. email: 'guest@example.com',
  185. name: 'Guest',
  186. password: '',
  187. locale: 'en',
  188. defaultEditor: 'markdown',
  189. tfaIsActive: false
  190. })
  191. await guestUser.$relatedQuery('groups').relate(guestGroup.id)
  192. // Create site nav
  193. WIKI.logger.info('Creating default site navigation')
  194. await WIKI.models.navigation.query().delete().where({ key: 'site' })
  195. await WIKI.models.navigation.query().insert({
  196. key: 'site',
  197. config: [
  198. {
  199. id: uuid(),
  200. icon: 'home',
  201. kind: 'link',
  202. label: 'Home',
  203. target: '/',
  204. targetType: 'home'
  205. }
  206. ]
  207. })
  208. WIKI.logger.info('Setup is complete!')
  209. res.json({
  210. ok: true,
  211. redirectPath: '/',
  212. redirectPort: WIKI.config.port
  213. }).end()
  214. WIKI.config.setup = false
  215. WIKI.logger.info('Stopping Setup...')
  216. WIKI.server.destroy(() => {
  217. WIKI.logger.info('Setup stopped. Starting Wiki.js...')
  218. _.delay(() => {
  219. WIKI.kernel.bootMaster()
  220. }, 1000)
  221. })
  222. } catch (err) {
  223. res.json({ ok: false, error: err.message })
  224. }
  225. })
  226. // ----------------------------------------
  227. // Error handling
  228. // ----------------------------------------
  229. app.use(function (req, res, next) {
  230. var err = new Error('Not Found')
  231. err.status = 404
  232. next(err)
  233. })
  234. app.use(function (err, req, res, next) {
  235. res.status(err.status || 500)
  236. res.send({
  237. message: err.message,
  238. error: WIKI.IS_DEBUG ? err : {}
  239. })
  240. WIKI.logger.error(err.message)
  241. WIKI.telemetry.sendError(err)
  242. })
  243. // ----------------------------------------
  244. // Start HTTP server
  245. // ----------------------------------------
  246. WIKI.logger.info(`HTTP Server on port: [ ${WIKI.config.port} ]`)
  247. app.set('port', WIKI.config.port)
  248. WIKI.server = http.createServer(app)
  249. WIKI.server.listen(WIKI.config.port, WIKI.config.bindIP)
  250. var openConnections = []
  251. WIKI.server.on('connection', (conn) => {
  252. let key = conn.remoteAddress + ':' + conn.remotePort
  253. openConnections[key] = conn
  254. conn.on('close', () => {
  255. delete openConnections[key]
  256. })
  257. })
  258. WIKI.server.destroy = (cb) => {
  259. WIKI.server.close(cb)
  260. for (let key in openConnections) {
  261. openConnections[key].destroy()
  262. }
  263. }
  264. WIKI.server.on('error', (error) => {
  265. if (error.syscall !== 'listen') {
  266. throw error
  267. }
  268. switch (error.code) {
  269. case 'EACCES':
  270. WIKI.logger.error('Listening on port ' + WIKI.config.port + ' requires elevated privileges!')
  271. return process.exit(1)
  272. case 'EADDRINUSE':
  273. WIKI.logger.error('Port ' + WIKI.config.port + ' is already in use!')
  274. return process.exit(1)
  275. default:
  276. throw error
  277. }
  278. })
  279. WIKI.server.on('listening', () => {
  280. WIKI.logger.info('HTTP Server: [ RUNNING ]')
  281. WIKI.logger.info('========================================')
  282. WIKI.logger.info(`Browse to http://localhost:${WIKI.config.port}/`)
  283. WIKI.logger.info('========================================')
  284. })
  285. }