refactor: migrate to objection.js + knex
This commit is contained in:
parent
e03e6826a8
commit
c9b643fbf0
@ -220,10 +220,11 @@
|
|||||||
)
|
)
|
||||||
v-flex(xs6)
|
v-flex(xs6)
|
||||||
v-text-field(
|
v-text-field(
|
||||||
|
ref='adminPasswordConfirm',
|
||||||
v-model='conf.adminPasswordConfirm',
|
v-model='conf.adminPasswordConfirm',
|
||||||
label='Confirm Password',
|
label='Confirm Password',
|
||||||
hint='Verify your password again.',
|
hint='Verify your password again.',
|
||||||
v-validate='{ required: true, confirmed: `$adminPassword` }',
|
v-validate='{ required: true, min: 8 }',
|
||||||
data-vv-name='adminPasswordConfirm',
|
data-vv-name='adminPasswordConfirm',
|
||||||
data-vv-as='Confirm Password',
|
data-vv-as='Confirm Password',
|
||||||
data-vv-scope='admin',
|
data-vv-scope='admin',
|
||||||
@ -308,10 +309,6 @@ export default {
|
|||||||
wikiVersion: {
|
wikiVersion: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true
|
required: true
|
||||||
},
|
|
||||||
langs: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@ -394,7 +391,7 @@ export default {
|
|||||||
async proceedToUpgrade () {
|
async proceedToUpgrade () {
|
||||||
if (this.state < 5) {
|
if (this.state < 5) {
|
||||||
const validationSuccess = await this.$validator.validateAll('admin')
|
const validationSuccess = await this.$validator.validateAll('admin')
|
||||||
if (!validationSuccess) {
|
if (!validationSuccess || this.conf.adminPassword !== this.conf.adminPasswordConfirm) {
|
||||||
this.state = 4
|
this.state = 4
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,13 @@ paths:
|
|||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
# Supported Database Engines:
|
# Supported Database Engines:
|
||||||
# - postgres = PostgreSQL 9.5 or later
|
# - postgres = PostgreSQL 9.5 or later
|
||||||
# - mysql = MySQL 5.7.8 or later
|
# - mysql = MySQL 8.0 / MariaDB 10.2.7 or later
|
||||||
|
# - mssql = MS SQL Server 2012 or later
|
||||||
# - sqlite = SQLite 3.9 or later
|
# - sqlite = SQLite 3.9 or later
|
||||||
|
|
||||||
db:
|
db:
|
||||||
type: postgres
|
type: postgres
|
||||||
# PostgreSQL and MySQL only:
|
# PostgreSQL / MySQL / MariaDB / MS SQL Server only:
|
||||||
host: localhost
|
host: localhost
|
||||||
port: 5432
|
port: 5432
|
||||||
user: wikijs
|
user: wikijs
|
||||||
|
54
package.json
54
package.json
@ -9,7 +9,6 @@
|
|||||||
"restart": "node wiki restart",
|
"restart": "node wiki restart",
|
||||||
"dev": "node wiki dev",
|
"dev": "node wiki dev",
|
||||||
"build": "webpack --profile --config dev/webpack/webpack.prod.js",
|
"build": "webpack --profile --config dev/webpack/webpack.prod.js",
|
||||||
"build:locales": "node dev/tasks/localization",
|
|
||||||
"watch": "webpack --config dev/webpack/webpack.dev.js",
|
"watch": "webpack --config dev/webpack/webpack.dev.js",
|
||||||
"test": "eslint --format codeframe --ext .js,.vue . && pug-lint server/views && jest"
|
"test": "eslint --format codeframe --ext .js,.vue . && pug-lint server/views && jest"
|
||||||
},
|
},
|
||||||
@ -43,9 +42,9 @@
|
|||||||
"axios": "0.18.0",
|
"axios": "0.18.0",
|
||||||
"bcryptjs-then": "1.0.1",
|
"bcryptjs-then": "1.0.1",
|
||||||
"bluebird": "3.5.1",
|
"bluebird": "3.5.1",
|
||||||
"body-parser": "1.18.2",
|
"body-parser": "1.18.3",
|
||||||
"bugsnag": "2.3.1",
|
"bugsnag": "2.3.1",
|
||||||
"bull": "3.4.1",
|
"bull": "3.4.2",
|
||||||
"cheerio": "1.0.0-rc.2",
|
"cheerio": "1.0.0-rc.2",
|
||||||
"child-process-promise": "2.2.1",
|
"child-process-promise": "2.2.1",
|
||||||
"chokidar": "2.0.3",
|
"chokidar": "2.0.3",
|
||||||
@ -61,15 +60,15 @@
|
|||||||
"express-brute": "1.0.1",
|
"express-brute": "1.0.1",
|
||||||
"express-brute-redis": "0.0.1",
|
"express-brute-redis": "0.0.1",
|
||||||
"express-session": "1.15.6",
|
"express-session": "1.15.6",
|
||||||
"file-type": "7.7.1",
|
"file-type": "8.0.0",
|
||||||
"filesize.js": "1.0.2",
|
"filesize.js": "1.0.2",
|
||||||
"follow-redirects": "1.4.1",
|
"follow-redirects": "1.5.0",
|
||||||
"fs-extra": "6.0.1",
|
"fs-extra": "6.0.1",
|
||||||
"getos": "3.1.0",
|
"getos": "3.1.0",
|
||||||
"graphql": "0.13.2",
|
"graphql": "0.13.2",
|
||||||
"graphql-list-fields": "2.0.2",
|
"graphql-list-fields": "2.0.2",
|
||||||
"graphql-tools": "3.0.1",
|
"graphql-tools": "3.0.1",
|
||||||
"i18next": "11.3.1",
|
"i18next": "11.3.2",
|
||||||
"i18next-express-middleware": "1.1.1",
|
"i18next-express-middleware": "1.1.1",
|
||||||
"i18next-localstorage-cache": "1.1.1",
|
"i18next-localstorage-cache": "1.1.1",
|
||||||
"i18next-node-fs-backend": "1.0.0",
|
"i18next-node-fs-backend": "1.0.0",
|
||||||
@ -78,6 +77,7 @@
|
|||||||
"js-yaml": "3.11.0",
|
"js-yaml": "3.11.0",
|
||||||
"jsonwebtoken": "8.2.1",
|
"jsonwebtoken": "8.2.1",
|
||||||
"klaw": "2.1.1",
|
"klaw": "2.1.1",
|
||||||
|
"knex": "0.14.6",
|
||||||
"lodash": "4.17.10",
|
"lodash": "4.17.10",
|
||||||
"markdown-it": "8.4.1",
|
"markdown-it": "8.4.1",
|
||||||
"markdown-it-abbr": "1.0.4",
|
"markdown-it-abbr": "1.0.4",
|
||||||
@ -96,12 +96,14 @@
|
|||||||
"mathjax-node": "2.1.0",
|
"mathjax-node": "2.1.0",
|
||||||
"mime-types": "2.1.18",
|
"mime-types": "2.1.18",
|
||||||
"moment": "2.22.1",
|
"moment": "2.22.1",
|
||||||
"moment-timezone": "0.5.16",
|
"moment-timezone": "0.5.17",
|
||||||
"mongodb": "3.0.7",
|
"mongodb": "3.1.0-beta4",
|
||||||
|
"mssql": "4.1.0",
|
||||||
"multer": "1.3.0",
|
"multer": "1.3.0",
|
||||||
"mysql2": "1.5.3",
|
"mysql2": "1.5.3",
|
||||||
"node-2fa": "1.1.2",
|
"node-2fa": "1.1.2",
|
||||||
"oauth2orize": "1.11.0",
|
"oauth2orize": "1.11.0",
|
||||||
|
"objection": "1.1.8",
|
||||||
"ora": "2.1.0",
|
"ora": "2.1.0",
|
||||||
"passport": "0.4.0",
|
"passport": "0.4.0",
|
||||||
"passport-auth0": "0.6.1",
|
"passport-auth0": "0.6.1",
|
||||||
@ -117,20 +119,18 @@
|
|||||||
"passport-slack": "0.0.7",
|
"passport-slack": "0.0.7",
|
||||||
"passport-twitch": "1.0.3",
|
"passport-twitch": "1.0.3",
|
||||||
"passport-windowslive": "1.0.2",
|
"passport-windowslive": "1.0.2",
|
||||||
"pg": "6.4.2",
|
"pg": "7.4.3",
|
||||||
"pg-hstore": "2.3.2",
|
"pg-hstore": "2.3.2",
|
||||||
"pg-promise": "7.5.3",
|
"pm2": "2.10.4",
|
||||||
"pm2": "2.10.3",
|
|
||||||
"pug": "2.0.3",
|
"pug": "2.0.3",
|
||||||
"qr-image": "3.2.0",
|
"qr-image": "3.2.0",
|
||||||
"raven": "2.6.1",
|
"raven": "2.6.2",
|
||||||
"read-chunk": "2.1.0",
|
"read-chunk": "2.1.0",
|
||||||
"remove-markdown": "0.2.2",
|
"remove-markdown": "0.2.2",
|
||||||
"request": "2.85.0",
|
"request": "2.86.0",
|
||||||
"request-promise": "4.2.2",
|
"request-promise": "4.2.2",
|
||||||
"scim-query-filter-parser": "1.1.0",
|
"scim-query-filter-parser": "1.1.0",
|
||||||
"semver": "5.5.0",
|
"semver": "5.5.0",
|
||||||
"sequelize": "4.37.7",
|
|
||||||
"serve-favicon": "2.5.0",
|
"serve-favicon": "2.5.0",
|
||||||
"sqlite3": "4.0.0",
|
"sqlite3": "4.0.0",
|
||||||
"uuid": "3.2.1",
|
"uuid": "3.2.1",
|
||||||
@ -145,7 +145,7 @@
|
|||||||
"apollo-client-preset": "1.0.8",
|
"apollo-client-preset": "1.0.8",
|
||||||
"apollo-fetch": "0.7.0",
|
"apollo-fetch": "0.7.0",
|
||||||
"apollo-link-batch-http": "1.2.2",
|
"apollo-link-batch-http": "1.2.2",
|
||||||
"autoprefixer": "8.4.1",
|
"autoprefixer": "8.5.0",
|
||||||
"babel-cli": "6.26.0",
|
"babel-cli": "6.26.0",
|
||||||
"babel-core": "6.26.3",
|
"babel-core": "6.26.3",
|
||||||
"babel-eslint": "8.2.3",
|
"babel-eslint": "8.2.3",
|
||||||
@ -169,7 +169,7 @@
|
|||||||
"eslint": "4.19.1",
|
"eslint": "4.19.1",
|
||||||
"eslint-config-requarks": "1.0.7",
|
"eslint-config-requarks": "1.0.7",
|
||||||
"eslint-config-standard": "11.0.0",
|
"eslint-config-standard": "11.0.0",
|
||||||
"eslint-plugin-import": "2.11.0",
|
"eslint-plugin-import": "2.12.0",
|
||||||
"eslint-plugin-node": "6.0.1",
|
"eslint-plugin-node": "6.0.1",
|
||||||
"eslint-plugin-promise": "3.7.0",
|
"eslint-plugin-promise": "3.7.0",
|
||||||
"eslint-plugin-standard": "3.1.0",
|
"eslint-plugin-standard": "3.1.0",
|
||||||
@ -183,8 +183,8 @@
|
|||||||
"html-webpack-pug-plugin": "0.3.0",
|
"html-webpack-pug-plugin": "0.3.0",
|
||||||
"i18next-xhr-backend": "1.5.1",
|
"i18next-xhr-backend": "1.5.1",
|
||||||
"ignore-loader": "0.1.2",
|
"ignore-loader": "0.1.2",
|
||||||
"jest": "22.4.3",
|
"jest": "22.4.4",
|
||||||
"jest-junit": "3.7.0",
|
"jest-junit": "4.0.0",
|
||||||
"js-cookie": "2.2.0",
|
"js-cookie": "2.2.0",
|
||||||
"lodash-webpack-plugin": "0.11.5",
|
"lodash-webpack-plugin": "0.11.5",
|
||||||
"mini-css-extract-plugin": "0.4.0",
|
"mini-css-extract-plugin": "0.4.0",
|
||||||
@ -196,7 +196,7 @@
|
|||||||
"postcss-flexibility": "2.0.0",
|
"postcss-flexibility": "2.0.0",
|
||||||
"postcss-import": "11.1.0",
|
"postcss-import": "11.1.0",
|
||||||
"postcss-loader": "2.1.5",
|
"postcss-loader": "2.1.5",
|
||||||
"postcss-selector-parser": "4.0.0",
|
"postcss-selector-parser": "5.0.0-rc.3",
|
||||||
"pug-lint": "2.5.0",
|
"pug-lint": "2.5.0",
|
||||||
"pug-loader": "2.4.0",
|
"pug-loader": "2.4.0",
|
||||||
"pug-plain-loader": "1.0.0",
|
"pug-plain-loader": "1.0.0",
|
||||||
@ -218,23 +218,23 @@
|
|||||||
"vue-clipboards": "1.2.4",
|
"vue-clipboards": "1.2.4",
|
||||||
"vue-codemirror": "4.0.5",
|
"vue-codemirror": "4.0.5",
|
||||||
"vue-hot-reload-api": "2.3.0",
|
"vue-hot-reload-api": "2.3.0",
|
||||||
"vue-loader": "15.0.10",
|
"vue-loader": "15.1.0",
|
||||||
"vue-material-design-icons": "1.4.0",
|
"vue-material-design-icons": "1.4.0",
|
||||||
"vue-moment": "3.2.0",
|
"vue-moment": "4.0.0-0",
|
||||||
"vue-router": "3.0.1",
|
"vue-router": "3.0.1",
|
||||||
"vue-simple-breakpoints": "1.0.3",
|
"vue-simple-breakpoints": "1.0.3",
|
||||||
"vue-template-compiler": "2.5.16",
|
"vue-template-compiler": "2.5.16",
|
||||||
"vuetify": "1.0.17",
|
"vuetify": "1.0.18",
|
||||||
"vuex": "3.0.1",
|
"vuex": "3.0.1",
|
||||||
"vuex-persistedstate": "2.5.2",
|
"vuex-persistedstate": "2.5.4",
|
||||||
"webpack": "4.8.2",
|
"webpack": "4.8.3",
|
||||||
"webpack-bundle-analyzer": "2.11.2",
|
"webpack-bundle-analyzer": "2.12.0",
|
||||||
"webpack-cli": "2.1.3",
|
"webpack-cli": "2.1.3",
|
||||||
"webpack-dev-middleware": "3.1.3",
|
"webpack-dev-middleware": "3.1.3",
|
||||||
"webpack-hot-middleware": "2.22.1",
|
"webpack-hot-middleware": "2.22.2",
|
||||||
"webpack-merge": "4.1.2",
|
"webpack-merge": "4.1.2",
|
||||||
"whatwg-fetch": "2.0.4",
|
"whatwg-fetch": "2.0.4",
|
||||||
"write-file-webpack-plugin": "4.2.0"
|
"write-file-webpack-plugin": "4.3.2"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
|
|
||||||
passport.deserializeUser(function (id, done) {
|
passport.deserializeUser(function (id, done) {
|
||||||
WIKI.db.User.findById(id).then((user) => {
|
WIKI.db.users.query().findById(id).then((user) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
done(null, user)
|
done(null, user)
|
||||||
} else {
|
} else {
|
||||||
@ -58,57 +58,6 @@ module.exports = {
|
|||||||
WIKI.logger.info(`Authentication Provider ${strategy.title}: [ OK ]`)
|
WIKI.logger.info(`Authentication Provider ${strategy.title}: [ OK ]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create Guest account for first-time
|
|
||||||
|
|
||||||
WIKI.db.User.findOne({
|
|
||||||
where: {
|
|
||||||
provider: 'local',
|
|
||||||
email: 'guest@example.com'
|
|
||||||
}
|
|
||||||
}).then((c) => {
|
|
||||||
if (c < 1) {
|
|
||||||
return WIKI.db.User.create({
|
|
||||||
provider: 'local',
|
|
||||||
email: 'guest@example.com',
|
|
||||||
name: 'Guest',
|
|
||||||
password: '',
|
|
||||||
role: 'guest'
|
|
||||||
}).then(() => {
|
|
||||||
WIKI.logger.info('[AUTH] Guest account created successfully!')
|
|
||||||
return true
|
|
||||||
}).catch((err) => {
|
|
||||||
WIKI.logger.error('[AUTH] An error occured while creating guest account:')
|
|
||||||
WIKI.logger.error(err)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// .then(() => {
|
|
||||||
// if (process.env.WIKI_JS_HEROKU) {
|
|
||||||
// return WIKI.db.User.findOne({ provider: 'local', email: process.env.WIKI_ADMIN_EMAIL }).then((c) => {
|
|
||||||
// if (c < 1) {
|
|
||||||
// // Create root admin account (HEROKU ONLY)
|
|
||||||
|
|
||||||
// return WIKI.db.User.create({
|
|
||||||
// provider: 'local',
|
|
||||||
// email: process.env.WIKI_ADMIN_EMAIL,
|
|
||||||
// name: 'Administrator',
|
|
||||||
// password: '$2a$04$MAHRw785Xe/Jd5kcKzr3D.VRZDeomFZu2lius4gGpZZ9cJw7B7Mna', // admin123 (default)
|
|
||||||
// role: 'admin'
|
|
||||||
// }).then(() => {
|
|
||||||
// WIKI.logger.info('[AUTH] Root admin account created successfully!')
|
|
||||||
// return true
|
|
||||||
// }).catch((err) => {
|
|
||||||
// WIKI.logger.error('[AUTH] An error occured while creating root admin account:')
|
|
||||||
// WIKI.logger.error(err)
|
|
||||||
// return err
|
|
||||||
// })
|
|
||||||
// } else { return true }
|
|
||||||
// })
|
|
||||||
// } else { return true }
|
|
||||||
// })
|
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,17 +59,10 @@ module.exports = {
|
|||||||
subsets = WIKI.data.configNamespaces
|
subsets = WIKI.data.configNamespaces
|
||||||
}
|
}
|
||||||
|
|
||||||
let results = await WIKI.db.Setting.findAll({
|
let results = await WIKI.db.settings.query().select(['key', 'value']).whereIn('key', subsets)
|
||||||
attributes: ['key', 'config'],
|
|
||||||
where: {
|
|
||||||
key: {
|
|
||||||
$in: subsets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (_.isArray(results) && results.length === subsets.length) {
|
if (_.isArray(results) && results.length === subsets.length) {
|
||||||
results.forEach(result => {
|
results.forEach(result => {
|
||||||
WIKI.config[result.key] = result.config
|
WIKI.config[result.key] = result.value
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@ -88,14 +81,18 @@ module.exports = {
|
|||||||
subsets = WIKI.data.configNamespaces
|
subsets = WIKI.data.configNamespaces
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let trx = await WIKI.db.Objection.transaction.start(WIKI.db.knex)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (let set of subsets) {
|
for (let set of subsets) {
|
||||||
await WIKI.db.Setting.upsert({
|
console.info(set)
|
||||||
key: set,
|
await WIKI.db.settings.query(trx).patch({
|
||||||
config: _.get(WIKI.config, set, {})
|
value: _.get(WIKI.config, set, {})
|
||||||
})
|
}).where('key', set)
|
||||||
}
|
}
|
||||||
|
await trx.commit()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
await trx.rollback(err)
|
||||||
WIKI.logger.error(`Failed to save configuration to DB: ${err.message}`)
|
WIKI.logger.error(`Failed to save configuration to DB: ${err.message}`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1,55 +1,18 @@
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const fs = require('fs')
|
const autoload = require('auto-load')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const Promise = require('bluebird')
|
const Promise = require('bluebird')
|
||||||
const Sequelize = require('sequelize')
|
const Knex = require('knex')
|
||||||
|
const Objection = require('objection')
|
||||||
|
|
||||||
/* global WIKI */
|
/* global WIKI */
|
||||||
|
|
||||||
const operatorsAliases = {
|
|
||||||
$eq: Sequelize.Op.eq,
|
|
||||||
$ne: Sequelize.Op.ne,
|
|
||||||
$gte: Sequelize.Op.gte,
|
|
||||||
$gt: Sequelize.Op.gt,
|
|
||||||
$lte: Sequelize.Op.lte,
|
|
||||||
$lt: Sequelize.Op.lt,
|
|
||||||
$not: Sequelize.Op.not,
|
|
||||||
$in: Sequelize.Op.in,
|
|
||||||
$notIn: Sequelize.Op.notIn,
|
|
||||||
$is: Sequelize.Op.is,
|
|
||||||
$like: Sequelize.Op.like,
|
|
||||||
$notLike: Sequelize.Op.notLike,
|
|
||||||
$iLike: Sequelize.Op.iLike,
|
|
||||||
$notILike: Sequelize.Op.notILike,
|
|
||||||
$regexp: Sequelize.Op.regexp,
|
|
||||||
$notRegexp: Sequelize.Op.notRegexp,
|
|
||||||
$iRegexp: Sequelize.Op.iRegexp,
|
|
||||||
$notIRegexp: Sequelize.Op.notIRegexp,
|
|
||||||
$between: Sequelize.Op.between,
|
|
||||||
$notBetween: Sequelize.Op.notBetween,
|
|
||||||
$overlap: Sequelize.Op.overlap,
|
|
||||||
$contains: Sequelize.Op.contains,
|
|
||||||
$contained: Sequelize.Op.contained,
|
|
||||||
$adjacent: Sequelize.Op.adjacent,
|
|
||||||
$strictLeft: Sequelize.Op.strictLeft,
|
|
||||||
$strictRight: Sequelize.Op.strictRight,
|
|
||||||
$noExtendRight: Sequelize.Op.noExtendRight,
|
|
||||||
$noExtendLeft: Sequelize.Op.noExtendLeft,
|
|
||||||
$and: Sequelize.Op.and,
|
|
||||||
$or: Sequelize.Op.or,
|
|
||||||
$any: Sequelize.Op.any,
|
|
||||||
$all: Sequelize.Op.all,
|
|
||||||
$values: Sequelize.Op.values,
|
|
||||||
$col: Sequelize.Op.col
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PostgreSQL DB module
|
* PostgreSQL DB module
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Sequelize,
|
Objection,
|
||||||
Op: Sequelize.Op,
|
knex: null,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize DB
|
* Initialize DB
|
||||||
*
|
*
|
||||||
@ -57,65 +20,63 @@ module.exports = {
|
|||||||
*/
|
*/
|
||||||
init() {
|
init() {
|
||||||
let self = this
|
let self = this
|
||||||
let dbModelsPath = path.join(WIKI.SERVERPATH, 'models')
|
|
||||||
|
|
||||||
// Define Sequelize instance
|
let dbClient = null
|
||||||
|
const dbConfig = (!_.isEmpty(process.env.WIKI_DB_CONNSTR)) ? process.env.WIKI_DB_CONNSTR : {
|
||||||
this.inst = new this.Sequelize(WIKI.config.db.db, WIKI.config.db.user, WIKI.config.db.pass, {
|
|
||||||
host: WIKI.config.db.host,
|
host: WIKI.config.db.host,
|
||||||
|
user: WIKI.config.db.user,
|
||||||
|
password: WIKI.config.db.pass,
|
||||||
|
database: WIKI.config.db.db,
|
||||||
port: WIKI.config.db.port,
|
port: WIKI.config.db.port,
|
||||||
dialect: WIKI.config.db.type,
|
filename: WIKI.config.db.storage
|
||||||
storage: WIKI.config.db.storage,
|
}
|
||||||
pool: {
|
|
||||||
max: 10,
|
switch (WIKI.config.db.type) {
|
||||||
min: 0,
|
case 'postgres':
|
||||||
idle: 10000
|
dbClient = 'pg'
|
||||||
},
|
break
|
||||||
logging: log => { WIKI.logger.log('debug', log) },
|
case 'mysql':
|
||||||
operatorsAliases
|
dbClient = 'mysql2'
|
||||||
|
break
|
||||||
|
case 'mssql':
|
||||||
|
dbClient = 'mssql'
|
||||||
|
break
|
||||||
|
case 'sqlite':
|
||||||
|
dbClient = 'sqlite3'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
WIKI.logger.error('Invalid DB Type')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.knex = Knex({
|
||||||
|
client: dbClient,
|
||||||
|
useNullAsDefault: true,
|
||||||
|
connection: dbConfig,
|
||||||
|
debug: WIKI.IS_DEBUG
|
||||||
})
|
})
|
||||||
|
|
||||||
// Attempt to connect and authenticate to DB
|
Objection.Model.knex(this.knex)
|
||||||
|
|
||||||
this.inst.authenticate().then(() => {
|
|
||||||
WIKI.logger.info(`Database (${WIKI.config.db.type}) connection: [ OK ]`)
|
|
||||||
}).catch(err => {
|
|
||||||
WIKI.logger.error(`Failed to connect to ${WIKI.config.db.type} instance.`)
|
|
||||||
WIKI.logger.error(err)
|
|
||||||
process.exit(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Load DB Models
|
// Load DB Models
|
||||||
|
|
||||||
fs
|
const models = autoload(path.join(WIKI.SERVERPATH, 'db/models'))
|
||||||
.readdirSync(dbModelsPath)
|
|
||||||
.filter(file => {
|
|
||||||
return (file.indexOf('.') !== 0 && file.indexOf('_') !== 0)
|
|
||||||
})
|
|
||||||
.forEach(file => {
|
|
||||||
let modelName = _.upperFirst(_.camelCase(_.split(file, '.')[0]))
|
|
||||||
self[modelName] = self.inst.import(path.join(dbModelsPath, file))
|
|
||||||
})
|
|
||||||
|
|
||||||
// Associate DB Models
|
|
||||||
|
|
||||||
require(path.join(dbModelsPath, '_relations.js'))(self)
|
|
||||||
|
|
||||||
// Set init tasks
|
// Set init tasks
|
||||||
|
|
||||||
let initTasks = {
|
let initTasks = {
|
||||||
// -> Sync DB Schemas
|
// -> Migrate DB Schemas
|
||||||
syncSchemas() {
|
async syncSchemas() {
|
||||||
return self.inst.sync({
|
return self.knex.migrate.latest({
|
||||||
force: false,
|
directory: path.join(WIKI.SERVERPATH, 'db/migrations'),
|
||||||
logging: log => { WIKI.logger.log('debug', log) }
|
tableName: 'migrations'
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// -> Set Connection App Name
|
// -> Set Connection App Name
|
||||||
setAppName() {
|
async setAppName() {
|
||||||
switch (WIKI.config.db.type) {
|
switch (WIKI.config.db.type) {
|
||||||
case 'postgres':
|
case 'postgres':
|
||||||
return self.inst.query(`set application_name = 'WIKI.js'`, { raw: true })
|
return self.knex.raw(`set application_name = 'Wiki.js'`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,6 +92,9 @@ module.exports = {
|
|||||||
|
|
||||||
this.onReady = Promise.each(initTasksQueue, t => t()).return(true)
|
this.onReady = Promise.each(initTasksQueue, t => t()).return(true)
|
||||||
|
|
||||||
return this
|
return {
|
||||||
|
...this,
|
||||||
|
...models
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loadLocale(locale, opts = { silent: false }) {
|
async loadLocale(locale, opts = { silent: false }) {
|
||||||
const res = await WIKI.db.Locale.findOne({
|
const res = await WIKI.db.locales.query().findOne('code', locale)
|
||||||
where: {
|
|
||||||
code: locale
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (res) {
|
if (res) {
|
||||||
if (_.isPlainObject(res.strings)) {
|
if (_.isPlainObject(res.strings)) {
|
||||||
_.forOwn(res.strings, (data, ns) => {
|
_.forOwn(res.strings, (data, ns) => {
|
||||||
|
75
server/db/migrations/2.0.0.js
Normal file
75
server/db/migrations/2.0.0.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
exports.up = knex => {
|
||||||
|
return knex.schema
|
||||||
|
// -------------------------------------
|
||||||
|
// GROUPS
|
||||||
|
// -------------------------------------
|
||||||
|
.createTable('groups', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
|
||||||
|
table.string('name').notNullable()
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// -------------------------------------
|
||||||
|
// LOCALES
|
||||||
|
// -------------------------------------
|
||||||
|
.createTable('locales', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
|
||||||
|
table.string('code', 2).notNullable().unique()
|
||||||
|
table.json('strings')
|
||||||
|
table.boolean('isRTL').notNullable().defaultTo(false)
|
||||||
|
table.string('name').notNullable()
|
||||||
|
table.string('nativeName').notNullable()
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// -------------------------------------
|
||||||
|
// SETTINGS
|
||||||
|
// -------------------------------------
|
||||||
|
.createTable('settings', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
|
||||||
|
table.string('key').notNullable().unique()
|
||||||
|
table.json('value')
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
})
|
||||||
|
// -------------------------------------
|
||||||
|
// USERS
|
||||||
|
// -------------------------------------
|
||||||
|
.createTable('users', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
|
||||||
|
table.string('email').notNullable()
|
||||||
|
table.string('name').notNullable()
|
||||||
|
table.string('provider').notNullable().defaultTo('local')
|
||||||
|
table.string('providerId')
|
||||||
|
table.string('password')
|
||||||
|
table.boolean('tfaIsActive').notNullable().defaultTo(false)
|
||||||
|
table.string('tfaSecret')
|
||||||
|
table.enum('role', ['admin', 'guest', 'user']).notNullable().defaultTo('guest')
|
||||||
|
table.string('createdAt').notNullable()
|
||||||
|
table.string('updatedAt').notNullable()
|
||||||
|
|
||||||
|
table.unique(['provider', 'email'])
|
||||||
|
})
|
||||||
|
// -------------------------------------
|
||||||
|
// USER GROUPS
|
||||||
|
// -------------------------------------
|
||||||
|
.createTable('userGroups', table => {
|
||||||
|
table.increments('id').primary()
|
||||||
|
|
||||||
|
table.integer('userId').unsigned().references('id').inTable('users')
|
||||||
|
table.integer('groupId').unsigned().references('id').inTable('groups')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.down = knex => {
|
||||||
|
return knex.schema
|
||||||
|
.dropTableIfExists('userGroups')
|
||||||
|
.dropTableIfExists('groups')
|
||||||
|
.dropTableIfExists('locales')
|
||||||
|
.dropTableIfExists('settings')
|
||||||
|
.dropTableIfExists('users')
|
||||||
|
}
|
48
server/db/models/groups.js
Normal file
48
server/db/models/groups.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings model
|
||||||
|
*/
|
||||||
|
module.exports = class Group extends Model {
|
||||||
|
static get tableName() { return 'groups' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['name'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
name: {type: 'string'},
|
||||||
|
createdAt: {type: 'string'},
|
||||||
|
updatedAt: {type: 'string'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const User = require('./users')
|
||||||
|
return {
|
||||||
|
users: {
|
||||||
|
relation: Model.ManyToManyRelation,
|
||||||
|
modelClass: User,
|
||||||
|
join: {
|
||||||
|
from: 'groups.id',
|
||||||
|
through: {
|
||||||
|
from: 'userGroups.groupId',
|
||||||
|
to: 'userGroups.userId'
|
||||||
|
},
|
||||||
|
to: 'users.id'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beforeUpdate() {
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
$beforeInsert() {
|
||||||
|
this.createdAt = new Date().toISOString()
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
34
server/db/models/locales.js
Normal file
34
server/db/models/locales.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locales model
|
||||||
|
*/
|
||||||
|
module.exports = class User extends Model {
|
||||||
|
static get tableName() { return 'locales' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['code', 'name'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
code: {type: 'string'},
|
||||||
|
strings: {type: 'object'},
|
||||||
|
isRTL: {type: 'boolean', default: false},
|
||||||
|
name: {type: 'string'},
|
||||||
|
nativeName: {type: 'string'},
|
||||||
|
createdAt: {type: 'string'},
|
||||||
|
updatedAt: {type: 'string'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beforeUpdate() {
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
$beforeInsert() {
|
||||||
|
this.createdAt = new Date().toISOString()
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
31
server/db/models/settings.js
Normal file
31
server/db/models/settings.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const Model = require('objection').Model
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings model
|
||||||
|
*/
|
||||||
|
module.exports = class User extends Model {
|
||||||
|
static get tableName() { return 'settings' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['key', 'value'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
key: {type: 'string'},
|
||||||
|
value: {type: 'object'},
|
||||||
|
createdAt: {type: 'string'},
|
||||||
|
updatedAt: {type: 'string'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beforeUpdate() {
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
$beforeInsert() {
|
||||||
|
this.createdAt = new Date().toISOString()
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
}
|
||||||
|
}
|
235
server/db/models/users.js
Normal file
235
server/db/models/users.js
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/* global WIKI */
|
||||||
|
|
||||||
|
const bcrypt = require('bcryptjs-then')
|
||||||
|
const _ = require('lodash')
|
||||||
|
const tfa = require('node-2fa')
|
||||||
|
const securityHelper = require('../../helpers/security')
|
||||||
|
const Model = require('objection').Model
|
||||||
|
|
||||||
|
const bcryptRegexp = /^\$2[ayb]\$[0-9]{2}\$[A-Za-z0-9./]{53}$/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Users model
|
||||||
|
*/
|
||||||
|
module.exports = class User extends Model {
|
||||||
|
static get tableName() { return 'users' }
|
||||||
|
|
||||||
|
static get jsonSchema () {
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
required: ['email', 'name', 'provider'],
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
id: {type: 'integer'},
|
||||||
|
email: {type: 'string', format: 'email'},
|
||||||
|
name: {type: 'string', minLength: 1, maxLength: 255},
|
||||||
|
provider: {type: 'string', minLength: 1, maxLength: 255},
|
||||||
|
providerId: {type: 'number'},
|
||||||
|
password: {type: 'string'},
|
||||||
|
role: {type: 'string', enum: ['admin', 'guest', 'user']},
|
||||||
|
tfaIsActive: {type: 'boolean', default: false},
|
||||||
|
tfaSecret: {type: 'string'},
|
||||||
|
createdAt: {type: 'string'},
|
||||||
|
updatedAt: {type: 'string'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get relationMappings() {
|
||||||
|
const Group = require('./groups')
|
||||||
|
return {
|
||||||
|
groups: {
|
||||||
|
relation: Model.ManyToManyRelation,
|
||||||
|
modelClass: Group,
|
||||||
|
join: {
|
||||||
|
from: 'users.id',
|
||||||
|
through: {
|
||||||
|
from: 'userGroups.userId',
|
||||||
|
to: 'userGroups.groupId'
|
||||||
|
},
|
||||||
|
to: 'groups.id'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async $beforeUpdate(opt, context) {
|
||||||
|
await super.$beforeUpdate(opt, context)
|
||||||
|
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
|
||||||
|
if (!(opt.patch && this.password === undefined)) {
|
||||||
|
await this.generateHash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async $beforeInsert(context) {
|
||||||
|
await super.$beforeInsert(context)
|
||||||
|
|
||||||
|
this.createdAt = new Date().toISOString()
|
||||||
|
this.updatedAt = new Date().toISOString()
|
||||||
|
|
||||||
|
await this.generateHash()
|
||||||
|
}
|
||||||
|
|
||||||
|
async generateHash() {
|
||||||
|
if (this.password) {
|
||||||
|
if (bcryptRegexp.test(this.password)) { return }
|
||||||
|
this.password = await bcrypt.hash(this.password, 12)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyPassword(pwd) {
|
||||||
|
if (await bcrypt.compare(this.password, pwd) === true) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
throw new WIKI.Error.AuthLoginFailed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async enableTFA() {
|
||||||
|
let tfaInfo = tfa.generateSecret({
|
||||||
|
name: WIKI.config.site.title
|
||||||
|
})
|
||||||
|
return this.$query.patch({
|
||||||
|
tfaIsActive: true,
|
||||||
|
tfaSecret: tfaInfo.secret
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async disableTFA() {
|
||||||
|
return this.$query.patch({
|
||||||
|
tfaIsActive: false,
|
||||||
|
tfaSecret: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyTFA(code) {
|
||||||
|
let result = tfa.verifyToken(this.tfaSecret, code)
|
||||||
|
return (result && _.has(result, 'delta') && result.delta === 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
static async processProfile(profile) {
|
||||||
|
let primaryEmail = ''
|
||||||
|
if (_.isArray(profile.emails)) {
|
||||||
|
let e = _.find(profile.emails, ['primary', true])
|
||||||
|
primaryEmail = (e) ? e.value : _.first(profile.emails).value
|
||||||
|
} else if (_.isString(profile.email) && profile.email.length > 5) {
|
||||||
|
primaryEmail = profile.email
|
||||||
|
} else if (_.isString(profile.mail) && profile.mail.length > 5) {
|
||||||
|
primaryEmail = profile.mail
|
||||||
|
} else if (profile.user && profile.user.email && profile.user.email.length > 5) {
|
||||||
|
primaryEmail = profile.user.email
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(WIKI.lang.t('auth:errors.invaliduseremail')))
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.provider = _.lowerCase(profile.provider)
|
||||||
|
primaryEmail = _.toLower(primaryEmail)
|
||||||
|
|
||||||
|
let user = await WIKI.db.users.query().findOne({
|
||||||
|
email: primaryEmail,
|
||||||
|
provider: profile.provider
|
||||||
|
})
|
||||||
|
if (user) {
|
||||||
|
user.$query().patchAdnFetch({
|
||||||
|
email: primaryEmail,
|
||||||
|
provider: profile.provider,
|
||||||
|
providerId: profile.id,
|
||||||
|
name: profile.displayName || _.split(primaryEmail, '@')[0]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
user = await WIKI.db.users.query().insertAndFetch({
|
||||||
|
email: primaryEmail,
|
||||||
|
provider: profile.provider,
|
||||||
|
providerId: profile.id,
|
||||||
|
name: profile.displayName || _.split(primaryEmail, '@')[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle unregistered accounts
|
||||||
|
// if (!user && profile.provider !== 'local' && (WIKI.config.auth.defaultReadAccess || profile.provider === 'ldap' || profile.provider === 'azure')) {
|
||||||
|
// let nUsr = {
|
||||||
|
// email: primaryEmail,
|
||||||
|
// provider: profile.provider,
|
||||||
|
// providerId: profile.id,
|
||||||
|
// password: '',
|
||||||
|
// name: profile.displayName || profile.name || profile.cn,
|
||||||
|
// rights: [{
|
||||||
|
// role: 'read',
|
||||||
|
// path: '/',
|
||||||
|
// exact: false,
|
||||||
|
// deny: false
|
||||||
|
// }]
|
||||||
|
// }
|
||||||
|
// return WIKI.db.users.query().insert(nUsr)
|
||||||
|
// }
|
||||||
|
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
static async login (opts, context) {
|
||||||
|
if (_.has(WIKI.config.auth.strategies, opts.provider)) {
|
||||||
|
_.set(context.req, 'body.email', opts.username)
|
||||||
|
_.set(context.req, 'body.password', opts.password)
|
||||||
|
|
||||||
|
// Authenticate
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
WIKI.auth.passport.authenticate(opts.provider, async (err, user, info) => {
|
||||||
|
if (err) { return reject(err) }
|
||||||
|
if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) }
|
||||||
|
|
||||||
|
// Is 2FA required?
|
||||||
|
if (user.tfaIsActive) {
|
||||||
|
try {
|
||||||
|
let loginToken = await securityHelper.generateToken(32)
|
||||||
|
await WIKI.redis.set(`tfa:${loginToken}`, user.id, 'EX', 600)
|
||||||
|
return resolve({
|
||||||
|
tfaRequired: true,
|
||||||
|
tfaLoginToken: loginToken
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
WIKI.logger.warn(err)
|
||||||
|
return reject(new WIKI.Error.AuthGenericError())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No 2FA, log in user
|
||||||
|
return context.req.logIn(user, err => {
|
||||||
|
if (err) { return reject(err) }
|
||||||
|
resolve({
|
||||||
|
tfaRequired: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})(context.req, context.res, () => {})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new WIKI.Error.AuthProviderInvalid()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async loginTFA(opts, context) {
|
||||||
|
if (opts.securityCode.length === 6 && opts.loginToken.length === 64) {
|
||||||
|
let result = await WIKI.redis.get(`tfa:${opts.loginToken}`)
|
||||||
|
if (result) {
|
||||||
|
let userId = _.toSafeInteger(result)
|
||||||
|
if (userId && userId > 0) {
|
||||||
|
let user = await WIKI.db.users.query().findById(userId)
|
||||||
|
if (user && user.verifyTFA(opts.securityCode)) {
|
||||||
|
return Promise.fromCallback(clb => {
|
||||||
|
context.req.logIn(user, clb)
|
||||||
|
}).return({
|
||||||
|
succeeded: true,
|
||||||
|
message: 'Login Successful'
|
||||||
|
}).catch(err => {
|
||||||
|
WIKI.logger.warn(err)
|
||||||
|
throw new WIKI.Error.AuthGenericError()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new WIKI.Error.AuthTFAFailed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new WIKI.Error.AuthTFAInvalid()
|
||||||
|
}
|
||||||
|
}
|
11
server/db/seeds/settings.js
Normal file
11
server/db/seeds/settings.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
exports.seed = (knex, Promise) => {
|
||||||
|
return knex('settings')
|
||||||
|
.insert([
|
||||||
|
{ key: 'auth', value: {} },
|
||||||
|
{ key: 'features', value: {} },
|
||||||
|
{ key: 'logging', value: {} },
|
||||||
|
{ key: 'site', value: {} },
|
||||||
|
{ key: 'theme', value: {} },
|
||||||
|
{ key: 'uploads', value: {} }
|
||||||
|
])
|
||||||
|
}
|
@ -32,7 +32,7 @@ module.exports = {
|
|||||||
AuthenticationMutation: {
|
AuthenticationMutation: {
|
||||||
async login(obj, args, context) {
|
async login(obj, args, context) {
|
||||||
try {
|
try {
|
||||||
let authResult = await WIKI.db.User.login(args, context)
|
let authResult = await WIKI.db.users.login(args, context)
|
||||||
return {
|
return {
|
||||||
...authResult,
|
...authResult,
|
||||||
responseResult: graphHelper.generateSuccess('Login success')
|
responseResult: graphHelper.generateSuccess('Login success')
|
||||||
@ -43,7 +43,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
async loginTFA(obj, args, context) {
|
async loginTFA(obj, args, context) {
|
||||||
try {
|
try {
|
||||||
let authResult = await WIKI.db.User.loginTFA(args, context)
|
let authResult = await WIKI.db.users.loginTFA(args, context)
|
||||||
return {
|
return {
|
||||||
...authResult,
|
...authResult,
|
||||||
responseResult: graphHelper.generateSuccess('TFA success')
|
responseResult: graphHelper.generateSuccess('TFA success')
|
||||||
|
@ -13,43 +13,32 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
GroupQuery: {
|
GroupQuery: {
|
||||||
async list(obj, args, context, info) {
|
async list(obj, args, context, info) {
|
||||||
return WIKI.db.Group.findAll({
|
return WIKI.db.groups.query().select(
|
||||||
attributes: {
|
'groups.*',
|
||||||
include: [[WIKI.db.inst.fn('COUNT', WIKI.db.inst.col('users.id')), 'userCount']]
|
WIKI.db.groups.relatedQuery('users').count().as('userCount')
|
||||||
},
|
)
|
||||||
include: [{
|
|
||||||
model: WIKI.db.User,
|
|
||||||
attributes: [],
|
|
||||||
through: {
|
|
||||||
attributes: []
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
raw: true,
|
|
||||||
// TODO: Figure out how to exclude these extra fields...
|
|
||||||
group: ['group.id', 'users->userGroups.createdAt', 'users->userGroups.updatedAt', 'users->userGroups.version', 'users->userGroups.userId', 'users->userGroups.groupId']
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
async single(obj, args, context, info) {
|
async single(obj, args, context, info) {
|
||||||
return WIKI.db.Group.findById(args.id)
|
return WIKI.db.groups.query().findById(args.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GroupMutation: {
|
GroupMutation: {
|
||||||
async assignUser(obj, args) {
|
async assignUser(obj, args) {
|
||||||
const grp = await WIKI.db.Group.findById(args.groupId)
|
const grp = await WIKI.db.groups.query().findById(args.groupId)
|
||||||
if (!grp) {
|
if (!grp) {
|
||||||
throw new gql.GraphQLError('Invalid Group ID')
|
throw new gql.GraphQLError('Invalid Group ID')
|
||||||
}
|
}
|
||||||
const usr = await WIKI.db.User.findById(args.userId)
|
const usr = await WIKI.db.users.query().findById(args.userId)
|
||||||
if (!usr) {
|
if (!usr) {
|
||||||
throw new gql.GraphQLError('Invalid User ID')
|
throw new gql.GraphQLError('Invalid User ID')
|
||||||
}
|
}
|
||||||
await grp.addUser(usr)
|
await grp.$relatedQuery('users').relate(usr.id)
|
||||||
return {
|
return {
|
||||||
responseResult: graphHelper.generateSuccess('User has been assigned to group.')
|
responseResult: graphHelper.generateSuccess('User has been assigned to group.')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async create(obj, args) {
|
async create(obj, args) {
|
||||||
const group = await WIKI.db.Group.create({
|
const group = await WIKI.db.groups.query().insertAndFetch({
|
||||||
name: args.name
|
name: args.name
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
@ -58,36 +47,27 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async delete(obj, args) {
|
async delete(obj, args) {
|
||||||
await WIKI.db.Group.destroy({
|
await WIKI.db.groups.query().deleteById(args.id)
|
||||||
where: {
|
|
||||||
id: args.id
|
|
||||||
},
|
|
||||||
limit: 1
|
|
||||||
})
|
|
||||||
return {
|
return {
|
||||||
responseResult: graphHelper.generateSuccess('Group has been deleted.')
|
responseResult: graphHelper.generateSuccess('Group has been deleted.')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async unassignUser(obj, args) {
|
async unassignUser(obj, args) {
|
||||||
const grp = await WIKI.db.Group.findById(args.groupId)
|
const grp = await WIKI.db.groups.query().findById(args.groupId)
|
||||||
if (!grp) {
|
if (!grp) {
|
||||||
throw new gql.GraphQLError('Invalid Group ID')
|
throw new gql.GraphQLError('Invalid Group ID')
|
||||||
}
|
}
|
||||||
const usr = await WIKI.db.User.findById(args.userId)
|
const usr = await WIKI.db.users.query().findById(args.userId)
|
||||||
if (!usr) {
|
if (!usr) {
|
||||||
throw new gql.GraphQLError('Invalid User ID')
|
throw new gql.GraphQLError('Invalid User ID')
|
||||||
}
|
}
|
||||||
await grp.removeUser(usr)
|
await grp.$relatedQuery('users').unrelate().where('userId', usr.id)
|
||||||
return {
|
return {
|
||||||
responseResult: graphHelper.generateSuccess('User has been unassigned from group.')
|
responseResult: graphHelper.generateSuccess('User has been unassigned from group.')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async update(obj, args) {
|
async update(obj, args) {
|
||||||
await WIKI.db.Group.update({
|
await WIKI.db.groups.query().patch({ name: args.name }).where('id', args.id)
|
||||||
name: args.name
|
|
||||||
}, {
|
|
||||||
where: { id: args.id }
|
|
||||||
})
|
|
||||||
return {
|
return {
|
||||||
responseResult: graphHelper.generateSuccess('Group has been updated.')
|
responseResult: graphHelper.generateSuccess('Group has been updated.')
|
||||||
}
|
}
|
||||||
@ -95,7 +75,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
Group: {
|
Group: {
|
||||||
users(grp) {
|
users(grp) {
|
||||||
return grp.getUsers()
|
return grp.$relatedQuery('users')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,7 @@ module.exports = {
|
|||||||
LocalizationQuery: {
|
LocalizationQuery: {
|
||||||
async locales(obj, args, context, info) {
|
async locales(obj, args, context, info) {
|
||||||
let remoteLocales = await WIKI.redis.get('locales')
|
let remoteLocales = await WIKI.redis.get('locales')
|
||||||
let localLocales = await WIKI.db.Locale.findAll({
|
let localLocales = await WIKI.db.locales.query().select('id', 'code', 'isRTL', 'name', 'nativeName', 'createdAt', 'updatedAt')
|
||||||
attributes: {
|
|
||||||
exclude: ['strings']
|
|
||||||
},
|
|
||||||
raw: true
|
|
||||||
})
|
|
||||||
remoteLocales = (remoteLocales) ? JSON.parse(remoteLocales) : localLocales
|
remoteLocales = (remoteLocales) ? JSON.parse(remoteLocales) : localLocales
|
||||||
return _.map(remoteLocales, rl => {
|
return _.map(remoteLocales, rl => {
|
||||||
let isInstalled = _.some(localLocales, ['code', rl.code])
|
let isInstalled = _.some(localLocales, ['code', rl.code])
|
||||||
|
@ -10,7 +10,8 @@ const path = require('path')
|
|||||||
const dbTypes = {
|
const dbTypes = {
|
||||||
mysql: 'MySQL / MariaDB',
|
mysql: 'MySQL / MariaDB',
|
||||||
postgres: 'PostgreSQL',
|
postgres: 'PostgreSQL',
|
||||||
sqlite: 'SQLite'
|
sqlite: 'SQLite',
|
||||||
|
mssql: 'MS SQL Server'
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@ -28,12 +29,14 @@ module.exports = {
|
|||||||
osLabel = `${os.type()} - ${osInfo.dist} (${osInfo.codename || os.platform()}) ${osInfo.release || os.release()} ${os.arch()}`
|
osLabel = `${os.type()} - ${osInfo.dist} (${osInfo.codename || os.platform()}) ${osInfo.release || os.release()} ${os.arch()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.info(WIKI.db.knex.client)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
configFile: path.join(process.cwd(), 'config.yml'),
|
configFile: path.join(process.cwd(), 'config.yml'),
|
||||||
currentVersion: WIKI.version,
|
currentVersion: WIKI.version,
|
||||||
dbType: _.get(dbTypes, WIKI.config.db.type, 'Unknown DB'),
|
dbType: _.get(dbTypes, WIKI.config.db.type, 'Unknown DB'),
|
||||||
dbVersion: WIKI.db.inst.options.databaseVersion,
|
dbVersion: _.get(WIKI.db, 'knex.client.version', 'Unknown version'),
|
||||||
dbHost: WIKI.db.inst.options.host,
|
dbHost: WIKI.config.db.host,
|
||||||
latestVersion: WIKI.version, // TODO
|
latestVersion: WIKI.version, // TODO
|
||||||
latestVersionReleaseDate: new Date(), // TODO
|
latestVersionReleaseDate: new Date(), // TODO
|
||||||
operatingSystem: osLabel,
|
operatingSystem: osLabel,
|
||||||
|
@ -10,52 +10,35 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
UserQuery: {
|
UserQuery: {
|
||||||
async list(obj, args, context, info) {
|
async list(obj, args, context, info) {
|
||||||
return WIKI.db.User.findAll({
|
return WIKI.db.users.query()
|
||||||
attributes: {
|
.select('id', 'email', 'name', 'provider', 'role', 'createdAt', 'updatedAt')
|
||||||
exclude: ['password', 'tfaSecret']
|
|
||||||
},
|
|
||||||
raw: true
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
async search(obj, args, context, info) {
|
async search(obj, args, context, info) {
|
||||||
return WIKI.db.User.findAll({
|
return WIKI.db.users.query()
|
||||||
where: {
|
.where('email', 'like', `%${args.query}%`)
|
||||||
$or: [
|
.orWhere('name', 'like', `%${args.query}%`)
|
||||||
{ email: { $like: `%${args.query}%` } },
|
.limit(10)
|
||||||
{ name: { $like: `%${args.query}%` } }
|
.select('id', 'email', 'name', 'provider', 'role', 'createdAt', 'updatedAt')
|
||||||
]
|
|
||||||
},
|
|
||||||
limit: 10,
|
|
||||||
attributes: ['id', 'email', 'name', 'provider', 'role', 'createdAt', 'updatedAt'],
|
|
||||||
raw: true
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
async single(obj, args, context, info) {
|
async single(obj, args, context, info) {
|
||||||
return WIKI.db.User.findById(args.id)
|
return WIKI.db.users.query().findById(args.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
UserMutation: {
|
UserMutation: {
|
||||||
create(obj, args) {
|
create(obj, args) {
|
||||||
return WIKI.db.User.create(args)
|
return WIKI.db.users.query().insertAndFetch(args)
|
||||||
},
|
},
|
||||||
delete(obj, args) {
|
delete(obj, args) {
|
||||||
return WIKI.db.User.destroy({
|
return WIKI.db.users.query().deleteById(args.id)
|
||||||
where: {
|
|
||||||
id: args.id
|
|
||||||
},
|
|
||||||
limit: 1
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
update(obj, args) {
|
update(obj, args) {
|
||||||
return WIKI.db.User.update({
|
return WIKI.db.users.query().patch({
|
||||||
email: args.email,
|
email: args.email,
|
||||||
name: args.name,
|
name: args.name,
|
||||||
provider: args.provider,
|
provider: args.provider,
|
||||||
providerId: args.providerId,
|
providerId: args.providerId,
|
||||||
role: args.role
|
role: args.role
|
||||||
}, {
|
}).where('id', args.id)
|
||||||
where: { id: args.id }
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
resetPassword(obj, args) {
|
resetPassword(obj, args) {
|
||||||
return false
|
return false
|
||||||
|
@ -38,7 +38,8 @@ module.exports = async (job) => {
|
|||||||
const locales = await WIKI.redis.get('locales')
|
const locales = await WIKI.redis.get('locales')
|
||||||
if (locales) {
|
if (locales) {
|
||||||
const currentLocale = _.find(JSON.parse(locales), ['code', job.data.locale]) || {}
|
const currentLocale = _.find(JSON.parse(locales), ['code', job.data.locale]) || {}
|
||||||
await WIKI.db.Locale.upsert({
|
await WIKI.db.locales.query().delete().where('code', job.data.locale)
|
||||||
|
await WIKI.db.locales.query().insert({
|
||||||
code: job.data.locale,
|
code: job.data.locale,
|
||||||
strings: lcObj,
|
strings: lcObj,
|
||||||
isRTL: currentLocale.isRTL,
|
isRTL: currentLocale.isRTL,
|
||||||
|
@ -60,13 +60,13 @@ module.exports = async (job) => {
|
|||||||
_.set(lcObj, row.key.replace(':', '.'), row.value)
|
_.set(lcObj, row.key.replace(':', '.'), row.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
await WIKI.db.Locale.upsert({
|
await WIKI.db.locales.query().update({
|
||||||
code: WIKI.config.site.lang,
|
code: WIKI.config.site.lang,
|
||||||
strings: lcObj,
|
strings: lcObj,
|
||||||
isRTL: currentLocale.isRTL,
|
isRTL: currentLocale.isRTL,
|
||||||
name: currentLocale.name,
|
name: currentLocale.name,
|
||||||
nativeName: currentLocale.nativeName
|
nativeName: currentLocale.nativeName
|
||||||
})
|
}).where('code', WIKI.config.site.lang)
|
||||||
}
|
}
|
||||||
|
|
||||||
WIKI.logger.info('Syncing locales with Graph endpoint: [ COMPLETED ]')
|
WIKI.logger.info('Syncing locales with Graph endpoint: [ COMPLETED ]')
|
||||||
|
@ -1,210 +0,0 @@
|
|||||||
/* global WIKI */
|
|
||||||
|
|
||||||
const Promise = require('bluebird')
|
|
||||||
const bcrypt = require('bcryptjs-then')
|
|
||||||
const _ = require('lodash')
|
|
||||||
const tfa = require('node-2fa')
|
|
||||||
const securityHelper = require('../helpers/security')
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Users schema
|
|
||||||
*/
|
|
||||||
module.exports = (sequelize, DataTypes) => {
|
|
||||||
let userSchema = sequelize.define('user', {
|
|
||||||
email: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false,
|
|
||||||
validate: {
|
|
||||||
isEmail: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
provider: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
providerId: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
},
|
|
||||||
password: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
},
|
|
||||||
role: {
|
|
||||||
type: DataTypes.ENUM('admin', 'user', 'guest'),
|
|
||||||
allowNull: false
|
|
||||||
},
|
|
||||||
tfaIsActive: {
|
|
||||||
type: DataTypes.BOOLEAN,
|
|
||||||
allowNull: false,
|
|
||||||
defaultValue: false
|
|
||||||
},
|
|
||||||
tfaSecret: {
|
|
||||||
type: DataTypes.STRING,
|
|
||||||
allowNull: true
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
timestamps: true,
|
|
||||||
version: true,
|
|
||||||
indexes: [
|
|
||||||
{
|
|
||||||
unique: true,
|
|
||||||
fields: ['provider', 'email']
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
|
|
||||||
userSchema.prototype.validatePassword = async function (rawPwd) {
|
|
||||||
if (await bcrypt.compare(rawPwd, this.password) === true) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
throw new WIKI.Error.AuthLoginFailed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.prototype.enableTFA = async function () {
|
|
||||||
let tfaInfo = tfa.generateSecret({
|
|
||||||
name: WIKI.config.site.title
|
|
||||||
})
|
|
||||||
this.tfaIsActive = true
|
|
||||||
this.tfaSecret = tfaInfo.secret
|
|
||||||
return this.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.prototype.disableTFA = async function () {
|
|
||||||
this.tfaIsActive = false
|
|
||||||
this.tfaSecret = ''
|
|
||||||
return this.save()
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.prototype.verifyTFA = function (code) {
|
|
||||||
let result = tfa.verifyToken(this.tfaSecret, code)
|
|
||||||
return (result && _.has(result, 'delta') && result.delta === 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.login = async (opts, context) => {
|
|
||||||
if (_.has(WIKI.config.auth.strategies, opts.provider)) {
|
|
||||||
_.set(context.req, 'body.email', opts.username)
|
|
||||||
_.set(context.req, 'body.password', opts.password)
|
|
||||||
|
|
||||||
// Authenticate
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
WIKI.auth.passport.authenticate(opts.provider, async (err, user, info) => {
|
|
||||||
if (err) { return reject(err) }
|
|
||||||
if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) }
|
|
||||||
|
|
||||||
// Is 2FA required?
|
|
||||||
if (user.tfaIsActive) {
|
|
||||||
try {
|
|
||||||
let loginToken = await securityHelper.generateToken(32)
|
|
||||||
await WIKI.redis.set(`tfa:${loginToken}`, user.id, 'EX', 600)
|
|
||||||
return resolve({
|
|
||||||
tfaRequired: true,
|
|
||||||
tfaLoginToken: loginToken
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
WIKI.logger.warn(err)
|
|
||||||
return reject(new WIKI.Error.AuthGenericError())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No 2FA, log in user
|
|
||||||
return context.req.logIn(user, err => {
|
|
||||||
if (err) { return reject(err) }
|
|
||||||
resolve({
|
|
||||||
tfaRequired: false
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})(context.req, context.res, () => {})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
throw new WIKI.Error.AuthProviderInvalid()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.loginTFA = async (opts, context) => {
|
|
||||||
if (opts.securityCode.length === 6 && opts.loginToken.length === 64) {
|
|
||||||
let result = await WIKI.redis.get(`tfa:${opts.loginToken}`)
|
|
||||||
if (result) {
|
|
||||||
let userId = _.toSafeInteger(result)
|
|
||||||
if (userId && userId > 0) {
|
|
||||||
let user = await WIKI.db.User.findById(userId)
|
|
||||||
if (user && user.verifyTFA(opts.securityCode)) {
|
|
||||||
return Promise.fromCallback(clb => {
|
|
||||||
context.req.logIn(user, clb)
|
|
||||||
}).return({
|
|
||||||
succeeded: true,
|
|
||||||
message: 'Login Successful'
|
|
||||||
}).catch(err => {
|
|
||||||
WIKI.logger.warn(err)
|
|
||||||
throw new WIKI.Error.AuthGenericError()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
throw new WIKI.Error.AuthTFAFailed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new WIKI.Error.AuthTFAInvalid()
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.processProfile = (profile) => {
|
|
||||||
let primaryEmail = ''
|
|
||||||
if (_.isArray(profile.emails)) {
|
|
||||||
let e = _.find(profile.emails, ['primary', true])
|
|
||||||
primaryEmail = (e) ? e.value : _.first(profile.emails).value
|
|
||||||
} else if (_.isString(profile.email) && profile.email.length > 5) {
|
|
||||||
primaryEmail = profile.email
|
|
||||||
} else if (_.isString(profile.mail) && profile.mail.length > 5) {
|
|
||||||
primaryEmail = profile.mail
|
|
||||||
} else if (profile.user && profile.user.email && profile.user.email.length > 5) {
|
|
||||||
primaryEmail = profile.user.email
|
|
||||||
} else {
|
|
||||||
return Promise.reject(new Error(WIKI.lang.t('auth:errors.invaliduseremail')))
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.provider = _.lowerCase(profile.provider)
|
|
||||||
primaryEmail = _.toLower(primaryEmail)
|
|
||||||
|
|
||||||
return WIKI.db.User.findOneAndUpdate({
|
|
||||||
email: primaryEmail,
|
|
||||||
provider: profile.provider
|
|
||||||
}, {
|
|
||||||
email: primaryEmail,
|
|
||||||
provider: profile.provider,
|
|
||||||
providerId: profile.id,
|
|
||||||
name: profile.displayName || _.split(primaryEmail, '@')[0]
|
|
||||||
}, {
|
|
||||||
new: true
|
|
||||||
}).then((user) => {
|
|
||||||
// Handle unregistered accounts
|
|
||||||
if (!user && profile.provider !== 'local' && (WIKI.config.auth.defaultReadAccess || profile.provider === 'ldap' || profile.provider === 'azure')) {
|
|
||||||
let nUsr = {
|
|
||||||
email: primaryEmail,
|
|
||||||
provider: profile.provider,
|
|
||||||
providerId: profile.id,
|
|
||||||
password: '',
|
|
||||||
name: profile.displayName || profile.name || profile.cn,
|
|
||||||
rights: [{
|
|
||||||
role: 'read',
|
|
||||||
path: '/',
|
|
||||||
exact: false,
|
|
||||||
deny: false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
return WIKI.db.User.create(nUsr)
|
|
||||||
}
|
|
||||||
return user || Promise.reject(new Error(WIKI.lang.t('auth:errors:notyetauthorized')))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
userSchema.hashPassword = (rawPwd) => {
|
|
||||||
return bcrypt.hash(rawPwd)
|
|
||||||
}
|
|
||||||
|
|
||||||
return userSchema
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
clientSecret: conf.clientSecret,
|
clientSecret: conf.clientSecret,
|
||||||
callbackURL: conf.callbackURL
|
callbackURL: conf.callbackURL
|
||||||
}, function (accessToken, refreshToken, profile, cb) {
|
}, function (accessToken, refreshToken, profile, cb) {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -24,7 +24,7 @@ module.exports = {
|
|||||||
let waadProfile = jwt.decode(params.id_token)
|
let waadProfile = jwt.decode(params.id_token)
|
||||||
waadProfile.id = waadProfile.oid
|
waadProfile.id = waadProfile.oid
|
||||||
waadProfile.provider = 'azure'
|
waadProfile.provider = 'azure'
|
||||||
WIKI.db.User.processProfile(waadProfile).then((user) => {
|
WIKI.db.users.processProfile(waadProfile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
callbackURL: conf.callbackURL,
|
callbackURL: conf.callbackURL,
|
||||||
scope: 'identify email'
|
scope: 'identify email'
|
||||||
}, function (accessToken, refreshToken, profile, cb) {
|
}, function (accessToken, refreshToken, profile, cb) {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
clientSecret: conf.clientSecret,
|
clientSecret: conf.clientSecret,
|
||||||
callbackURL: conf.callbackURL
|
callbackURL: conf.callbackURL
|
||||||
}, (accessToken, refreshToken, profile, cb) => {
|
}, (accessToken, refreshToken, profile, cb) => {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
callbackURL: conf.callbackURL,
|
callbackURL: conf.callbackURL,
|
||||||
profileFields: ['id', 'displayName', 'email']
|
profileFields: ['id', 'displayName', 'email']
|
||||||
}, function (accessToken, refreshToken, profile, cb) {
|
}, function (accessToken, refreshToken, profile, cb) {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
callbackURL: conf.callbackURL,
|
callbackURL: conf.callbackURL,
|
||||||
scope: ['user:email']
|
scope: ['user:email']
|
||||||
}, (accessToken, refreshToken, profile, cb) => {
|
}, (accessToken, refreshToken, profile, cb) => {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||||||
clientSecret: conf.clientSecret,
|
clientSecret: conf.clientSecret,
|
||||||
callbackURL: conf.callbackURL
|
callbackURL: conf.callbackURL
|
||||||
}, (accessToken, refreshToken, profile, cb) => {
|
}, (accessToken, refreshToken, profile, cb) => {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -33,7 +33,7 @@ module.exports = {
|
|||||||
}, (profile, cb) => {
|
}, (profile, cb) => {
|
||||||
profile.provider = 'ldap'
|
profile.provider = 'ldap'
|
||||||
profile.id = profile.dn
|
profile.id = profile.dn
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -17,14 +17,12 @@ module.exports = {
|
|||||||
usernameField: 'email',
|
usernameField: 'email',
|
||||||
passwordField: 'password'
|
passwordField: 'password'
|
||||||
}, (uEmail, uPassword, done) => {
|
}, (uEmail, uPassword, done) => {
|
||||||
WIKI.db.User.findOne({
|
WIKI.db.users.query().findOne({
|
||||||
where: {
|
email: uEmail,
|
||||||
email: uEmail,
|
provider: 'local'
|
||||||
provider: 'local'
|
|
||||||
}
|
|
||||||
}).then((user) => {
|
}).then((user) => {
|
||||||
if (user) {
|
if (user) {
|
||||||
return user.validatePassword(uPassword).then(() => {
|
return user.verifyPassword(uPassword).then(() => {
|
||||||
return done(null, user) || true
|
return done(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return done(err, null)
|
return done(err, null)
|
||||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||||||
clientSecret: conf.clientSecret,
|
clientSecret: conf.clientSecret,
|
||||||
callbackURL: conf.callbackURL
|
callbackURL: conf.callbackURL
|
||||||
}, function (accessToken, refreshToken, profile, cb) {
|
}, function (accessToken, refreshToken, profile, cb) {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -20,7 +20,7 @@ module.exports = {
|
|||||||
clientSecret: conf.clientSecret,
|
clientSecret: conf.clientSecret,
|
||||||
callbackURL: conf.callbackURL
|
callbackURL: conf.callbackURL
|
||||||
}, (accessToken, refreshToken, profile, cb) => {
|
}, (accessToken, refreshToken, profile, cb) => {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -18,7 +18,7 @@ module.exports = {
|
|||||||
clientSecret: conf.clientSecret,
|
clientSecret: conf.clientSecret,
|
||||||
callbackURL: conf.callbackURL
|
callbackURL: conf.callbackURL
|
||||||
}, (accessToken, refreshToken, profile, cb) => {
|
}, (accessToken, refreshToken, profile, cb) => {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
callbackURL: conf.callbackURL,
|
callbackURL: conf.callbackURL,
|
||||||
scope: 'user_read'
|
scope: 'user_read'
|
||||||
}, function (accessToken, refreshToken, profile, cb) {
|
}, function (accessToken, refreshToken, profile, cb) {
|
||||||
WIKI.db.User.processProfile(profile).then((user) => {
|
WIKI.db.users.processProfile(profile).then((user) => {
|
||||||
return cb(null, user) || true
|
return cb(null, user) || true
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
return cb(err, null) || true
|
return cb(err, null) || true
|
||||||
|
@ -5,7 +5,7 @@ const path = require('path')
|
|||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
WIKI.config.site = {
|
WIKI.config.site = {
|
||||||
path: '',
|
path: '',
|
||||||
title: 'WIKI.js'
|
title: 'Wiki.js'
|
||||||
}
|
}
|
||||||
|
|
||||||
WIKI.system = require('./core/system')
|
WIKI.system = require('./core/system')
|
||||||
@ -298,22 +298,46 @@ module.exports = () => {
|
|||||||
|
|
||||||
// Save config to DB
|
// Save config to DB
|
||||||
WIKI.logger.info('Persisting config to DB...')
|
WIKI.logger.info('Persisting config to DB...')
|
||||||
await WIKI.configSvc.saveToDb()
|
await WIKI.db.settings.query().insert([
|
||||||
|
{ key: 'auth', value: WIKI.config.auth },
|
||||||
|
{ key: 'features', value: WIKI.config.features },
|
||||||
|
{ key: 'logging', value: WIKI.config.logging },
|
||||||
|
{ key: 'site', value: WIKI.config.site },
|
||||||
|
{ key: 'theme', value: WIKI.config.theme },
|
||||||
|
{ key: 'uploads', value: WIKI.config.uploads }
|
||||||
|
])
|
||||||
|
|
||||||
// Create root administrator
|
// Create root administrator
|
||||||
WIKI.logger.info('Creating root administrator...')
|
WIKI.logger.info('Creating root administrator...')
|
||||||
await WIKI.db.User.upsert({
|
await WIKI.db.users.query().insert({
|
||||||
email: req.body.adminEmail,
|
email: req.body.adminEmail,
|
||||||
provider: 'local',
|
provider: 'local',
|
||||||
password: await WIKI.db.User.hashPassword(req.body.adminPassword),
|
password: req.body.adminPassword,
|
||||||
name: 'Administrator',
|
name: 'Administrator',
|
||||||
role: 'admin',
|
role: 'admin',
|
||||||
tfaIsActive: false
|
tfaIsActive: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Create Guest account
|
||||||
|
WIKI.logger.info('Creating root administrator...')
|
||||||
|
const guestUsr = await WIKI.db.users.query().findOne({
|
||||||
|
provider: 'local',
|
||||||
|
email: 'guest@example.com'
|
||||||
|
})
|
||||||
|
if (!guestUsr) {
|
||||||
|
await WIKI.db.users.query().insert({
|
||||||
|
provider: 'local',
|
||||||
|
email: 'guest@example.com',
|
||||||
|
name: 'Guest',
|
||||||
|
password: '',
|
||||||
|
role: 'guest',
|
||||||
|
tfaIsActive: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Create default locale
|
// Create default locale
|
||||||
WIKI.logger.info('Installing default locale...')
|
WIKI.logger.info('Installing default locale...')
|
||||||
await WIKI.db.Locale.upsert({
|
await WIKI.db.locales.query().insert({
|
||||||
code: 'en',
|
code: 'en',
|
||||||
strings: require('./locales/default.json'),
|
strings: require('./locales/default.json'),
|
||||||
isRTL: false,
|
isRTL: false,
|
||||||
@ -330,7 +354,7 @@ module.exports = () => {
|
|||||||
|
|
||||||
WIKI.logger.info('Stopping Setup...')
|
WIKI.logger.info('Stopping Setup...')
|
||||||
WIKI.server.destroy(() => {
|
WIKI.server.destroy(() => {
|
||||||
WIKI.logger.info('Setup stopped. Starting WIKI.js...')
|
WIKI.logger.info('Setup stopped. Starting Wiki.js...')
|
||||||
_.delay(() => {
|
_.delay(() => {
|
||||||
WIKI.kernel.bootMaster()
|
WIKI.kernel.bootMaster()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user