refactor: migrate to objection.js + knex

This commit is contained in:
NGPixel committed 2018-05-19 16:40:07 -04:00
1 parent e03e6826a8
commit c9b643fbf0
46 files changed
+611 -499

No files matched your search

+3 -6
View File
@@ -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
} }
+3 -2
View File
@@ -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
+27 -27
View File
@@ -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%",
+1 -52
View File
@@ -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
} }
} }
+10 -13
View File
@@ -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
} }
+48 -84
View File
@@ -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,
min: 0,
idle: 10000
},
logging: log => { WIKI.logger.log('debug', log) },
operatorsAliases
})
// Attempt to connect and authenticate to DB switch (WIKI.config.db.type) {
case 'postgres':
this.inst.authenticate().then(() => { dbClient = 'pg'
WIKI.logger.info(`Database (${WIKI.config.db.type}) connection: [ OK ]`) break
}).catch(err => { case 'mysql':
WIKI.logger.error(`Failed to connect to ${WIKI.config.db.type} instance.`) dbClient = 'mysql2'
WIKI.logger.error(err) break
case 'mssql':
dbClient = 'mssql'
break
case 'sqlite':
dbClient = 'sqlite3'
break
default:
WIKI.logger.error('Invalid DB Type')
process.exit(1) process.exit(1)
}
this.knex = Knex({
client: dbClient,
useNullAsDefault: true,
connection: dbConfig,
debug: WIKI.IS_DEBUG
}) })
Objection.Model.knex(this.knex)
// 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
}
} }
} }
+1 -5
View File
@@ -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
View 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
View 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
View 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
View 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
View 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
View 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: {} }
])
}
+2 -2
View File
@@ -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')
+15 -35
View File
@@ -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')
} }
} }
} }
+1 -6
View File
@@ -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])
+6 -3
View File
@@ -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,
+12 -29
View File
@@ -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
+2 -1
View File
@@ -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,
+2 -2
View File
@@ -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 ]')
-210
View File
@@ -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
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+2 -4
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+30 -6
View File
@@ -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)
BIN
View File
Binary file not shown.