feat: login page + auth panel + various improvements

parent 82ebac2d
...@@ -430,8 +430,7 @@ router.get('/*', async (req, res, next) => { ...@@ -430,8 +430,7 @@ router.get('/*', async (req, res, next) => {
const page = await WIKI.models.pages.getPage({ const page = await WIKI.models.pages.getPage({
path: pageArgs.path, path: pageArgs.path,
locale: pageArgs.locale, locale: pageArgs.locale,
userId: req.user.id, userId: req.user.id
isPrivate: false
}) })
pageArgs.tags = _.get(page, 'tags', []) pageArgs.tags = _.get(page, 'tags', [])
...@@ -440,12 +439,12 @@ router.get('/*', async (req, res, next) => { ...@@ -440,12 +439,12 @@ router.get('/*', async (req, res, next) => {
// -> Check User Access // -> Check User Access
if (!effectivePermissions.pages.read) { if (!effectivePermissions.pages.read) {
if (req.user.id === 2) { if (req.user.id === WIKI.auth.guest.id) {
res.cookie('loginRedirect', req.path, { res.cookie('loginRedirect', req.path, {
maxAge: 15 * 60 * 1000 maxAge: 15 * 60 * 1000
}) })
} }
if (pageArgs.path === 'home' && req.user.id === 2) { if (pageArgs.path === 'home' && req.user.id === WIKI.auth.guest.id) {
return res.redirect('/login') return res.redirect('/login')
} }
return res.redirect(`/_error/unauthorized?from=${req.path}`) return res.redirect(`/_error/unauthorized?from=${req.path}`)
......
...@@ -75,9 +75,8 @@ module.exports = { ...@@ -75,9 +75,8 @@ module.exports = {
})) }))
// Load enabled strategies // Load enabled strategies
const enabledStrategies = await WIKI.models.authentication.getStrategies() const enabledStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true })
for (const idx in enabledStrategies) { for (const stg of enabledStrategies) {
const stg = enabledStrategies[idx]
try { try {
const strategy = require(`../modules/authentication/${stg.module}/authentication.js`) const strategy = require(`../modules/authentication/${stg.module}/authentication.js`)
...@@ -146,7 +145,7 @@ module.exports = { ...@@ -146,7 +145,7 @@ module.exports = {
try { try {
const newToken = await WIKI.models.users.refreshToken(jwtPayload.id) const newToken = await WIKI.models.users.refreshToken(jwtPayload.id)
user = newToken.user user = newToken.user
user.permissions = user.getGlobalPermissions() user.permissions = user.getPermissions()
user.groups = user.getGroups() user.groups = user.getGroups()
req.user = user req.user = user
...@@ -186,7 +185,7 @@ module.exports = { ...@@ -186,7 +185,7 @@ module.exports = {
localeCode: 'en', localeCode: 'en',
permissions: _.get(WIKI.auth.groups, `${user.grp}.permissions`, []), permissions: _.get(WIKI.auth.groups, `${user.grp}.permissions`, []),
groups: [user.grp], groups: [user.grp],
getGlobalPermissions () { getPermissions () {
return req.user.permissions return req.user.permissions
}, },
getGroups () { getGroups () {
...@@ -215,7 +214,7 @@ module.exports = { ...@@ -215,7 +214,7 @@ module.exports = {
* @param {String|Boolean} path * @param {String|Boolean} path
*/ */
checkAccess(user, permissions = [], page = false) { checkAccess(user, permissions = [], page = false) {
const userPermissions = user.permissions ? user.permissions : user.getGlobalPermissions() const userPermissions = user.permissions ? user.permissions : user.getPermissions()
// System Admin // System Admin
if (_.includes(userPermissions, 'manage:system')) { if (_.includes(userPermissions, 'manage:system')) {
...@@ -298,7 +297,7 @@ module.exports = { ...@@ -298,7 +297,7 @@ module.exports = {
* @param {Array<String>} excludePermissions * @param {Array<String>} excludePermissions
*/ */
checkExclusiveAccess(user, includePermissions = [], excludePermissions = []) { checkExclusiveAccess(user, includePermissions = [], excludePermissions = []) {
const userPermissions = user.permissions ? user.permissions : user.getGlobalPermissions() const userPermissions = user.permissions ? user.permissions : user.getPermissions()
// Check Inclusion Permissions // Check Inclusion Permissions
if (_.intersection(userPermissions, includePermissions).length < 1) { if (_.intersection(userPermissions, includePermissions).length < 1) {
......
...@@ -17,6 +17,13 @@ exports.up = async knex => { ...@@ -17,6 +17,13 @@ exports.up = async knex => {
// ===================================== // =====================================
// MODEL TABLES // MODEL TABLES
// ===================================== // =====================================
// ACTIVITY LOGS -----------------------
.createTable('activityLogs', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.timestamp('ts').notNullable().defaultTo(knex.fn.now())
table.string('action').notNullable()
table.jsonb('meta').notNullable()
})
// ANALYTICS --------------------------- // ANALYTICS ---------------------------
.createTable('analytics', table => { .createTable('analytics', table => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()')) table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
...@@ -236,6 +243,7 @@ exports.up = async knex => { ...@@ -236,6 +243,7 @@ exports.up = async knex => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()')) table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('kind').notNullable() table.string('kind').notNullable()
table.string('token').notNullable() table.string('token').notNullable()
table.jsonb('meta').notNullable().defaultTo('{}')
table.timestamp('validUntil').notNullable() table.timestamp('validUntil').notNullable()
table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now()) table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now())
}) })
...@@ -244,10 +252,9 @@ exports.up = async knex => { ...@@ -244,10 +252,9 @@ exports.up = async knex => {
table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()')) table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()'))
table.string('email').notNullable() table.string('email').notNullable()
table.string('name').notNullable() table.string('name').notNullable()
table.jsonb('auth') table.jsonb('auth').notNullable().defaultTo('{}')
table.jsonb('tfa') table.jsonb('meta').notNullable().defaultTo('{}')
table.jsonb('meta') table.jsonb('prefs').notNullable().defaultTo('{}')
table.jsonb('prefs')
table.string('pictureUrl') table.string('pictureUrl')
table.boolean('isSystem').notNullable().defaultTo(false) table.boolean('isSystem').notNullable().defaultTo(false)
table.boolean('isActive').notNullable().defaultTo(false) table.boolean('isActive').notNullable().defaultTo(false)
...@@ -274,6 +281,9 @@ exports.up = async knex => { ...@@ -274,6 +281,9 @@ exports.up = async knex => {
// ===================================== // =====================================
// REFERENCES // REFERENCES
// ===================================== // =====================================
.table('activityLogs', table => {
table.uuid('userId').notNullable().references('id').inTable('users')
})
.table('analytics', table => { .table('analytics', table => {
table.uuid('siteId').notNullable().references('id').inTable('sites') table.uuid('siteId').notNullable().references('id').inTable('sites')
}) })
...@@ -471,6 +481,7 @@ exports.up = async knex => { ...@@ -471,6 +481,7 @@ exports.up = async knex => {
index: true, index: true,
follow: true follow: true
}, },
authStrategies: [{ id: authModuleId, order: 0, isVisible: true }],
locale: 'en', locale: 'en',
localeNamespacing: false, localeNamespacing: false,
localeNamespaces: [], localeNamespaces: [],
......
const _ = require('lodash') const _ = require('lodash')
const fs = require('fs-extra')
const path = require('path')
const graphHelper = require('../../helpers/graph') const graphHelper = require('../../helpers/graph')
/* global WIKI */ /* global WIKI */
...@@ -28,6 +26,9 @@ module.exports = { ...@@ -28,6 +26,9 @@ module.exports = {
apiState () { apiState () {
return WIKI.config.api.isEnabled return WIKI.config.api.isEnabled
}, },
/**
* Fetch authentication strategies
*/
async authStrategies () { async authStrategies () {
return WIKI.data.authentication.map(stg => ({ return WIKI.data.authentication.map(stg => ({
...stg, ...stg,
...@@ -38,33 +39,23 @@ module.exports = { ...@@ -38,33 +39,23 @@ module.exports = {
* Fetch active authentication strategies * Fetch active authentication strategies
*/ */
async authActiveStrategies (obj, args, context) { async authActiveStrategies (obj, args, context) {
return WIKI.models.authentication.getStrategies() return WIKI.models.authentication.getStrategies({ enabledOnly: args.enabledOnly })
}, },
/** /**
* Fetch site authentication strategies * Fetch site authentication strategies
*/ */
async authSiteStrategies (obj, args, context, info) { async authSiteStrategies (obj, args, context, info) {
let strategies = await WIKI.models.authentication.getStrategies() const site = await WIKI.models.sites.query().findById(args.siteId)
strategies = strategies.map(stg => { const activeStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true })
const strategyInfo = _.find(WIKI.data.authentication, ['key', stg.strategyKey]) || {} return activeStrategies.map(str => {
const siteAuth = _.find(site.config.authStrategies, ['id', str.id]) || {}
return { return {
...stg, id: str.id,
strategy: strategyInfo, activeStrategy: str,
config: _.sortBy(_.transform(stg.config, (res, value, key) => { order: siteAuth.order ?? 0,
const configData = _.get(strategyInfo.props, key, false) isVisible: siteAuth.isVisible ?? false
if (configData) {
res.push({
key,
value: JSON.stringify({
...configData,
value
})
})
}
}, []), 'key')
} }
}) })
return args.enabledOnly ? _.filter(strategies, 'isEnabled') : strategies
} }
}, },
Mutation: { Mutation: {
...@@ -93,13 +84,14 @@ module.exports = { ...@@ -93,13 +84,14 @@ module.exports = {
const authResult = await WIKI.models.users.login(args, context) const authResult = await WIKI.models.users.login(args, context)
return { return {
...authResult, ...authResult,
responseResult: graphHelper.generateSuccess('Login success') operation: graphHelper.generateSuccess('Login success')
} }
} catch (err) { } catch (err) {
// LDAP Debug Flag // LDAP Debug Flag
if (args.strategy === 'ldap' && WIKI.config.flags.ldapdebug) { if (args.strategy === 'ldap' && WIKI.config.flags.ldapdebug) {
WIKI.logger.warn('LDAP LOGIN ERROR (c1): ', err) WIKI.logger.warn('LDAP LOGIN ERROR (c1): ', err)
} }
console.error(err)
return graphHelper.generateError(err) return graphHelper.generateError(err)
} }
...@@ -119,9 +111,9 @@ module.exports = { ...@@ -119,9 +111,9 @@ module.exports = {
} }
}, },
/** /**
* Perform Mandatory Password Change after Login * Perform Password Change
*/ */
async loginChangePassword (obj, args, context) { async changePassword (obj, args, context) {
try { try {
const authResult = await WIKI.models.users.loginChangePassword(args, context) const authResult = await WIKI.models.users.loginChangePassword(args, context)
return { return {
...@@ -133,7 +125,7 @@ module.exports = { ...@@ -133,7 +125,7 @@ module.exports = {
} }
}, },
/** /**
* Perform Mandatory Password Change after Login * Perform Forget Password
*/ */
async forgotPassword (obj, args, context) { async forgotPassword (obj, args, context) {
try { try {
......
...@@ -9,7 +9,9 @@ extend type Query { ...@@ -9,7 +9,9 @@ extend type Query {
authStrategies: [AuthenticationStrategy] authStrategies: [AuthenticationStrategy]
authActiveStrategies: [AuthenticationActiveStrategy] authActiveStrategies(
enabledOnly: Boolean
): [AuthenticationActiveStrategy]
authSiteStrategies( authSiteStrategies(
siteId: UUID! siteId: UUID!
...@@ -27,7 +29,8 @@ extend type Mutation { ...@@ -27,7 +29,8 @@ extend type Mutation {
login( login(
username: String! username: String!
password: String! password: String!
strategy: String! strategyId: UUID!
siteId: UUID
): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60) ): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60)
loginTFA( loginTFA(
...@@ -36,9 +39,13 @@ extend type Mutation { ...@@ -36,9 +39,13 @@ extend type Mutation {
setup: Boolean setup: Boolean
): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60) ): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60)
loginChangePassword( changePassword(
continuationToken: String! userId: UUID
continuationToken: String
currentPassword: String
newPassword: String! newPassword: String!
strategyId: UUID!
siteId: UUID
): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60) ): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60)
forgotPassword( forgotPassword(
......
...@@ -73,11 +73,6 @@ extend type Mutation { ...@@ -73,11 +73,6 @@ extend type Mutation {
dateFormat: String! dateFormat: String!
appearance: String! appearance: String!
): UserTokenResponse ): UserTokenResponse
changePassword(
current: String!
new: String!
): UserTokenResponse
} }
# ----------------------------------------------- # -----------------------------------------------
......
...@@ -16,6 +16,6 @@ module.exports = { ...@@ -16,6 +16,6 @@ module.exports = {
slug: err.name, slug: err.name,
message: err.message || 'An unexpected error occured.' message: err.message || 'An unexpected error occured.'
} }
return (complete) ? { responseResult: error } : error return (complete) ? { operation: error } : error
} }
} }
...@@ -21,6 +21,7 @@ module.exports = class Authentication extends Model { ...@@ -21,6 +21,7 @@ module.exports = class Authentication extends Model {
properties: { properties: {
id: { type: 'string' }, id: { type: 'string' },
module: { type: 'string' }, module: { type: 'string' },
isEnabled: { type: 'boolean' },
selfRegistration: {type: 'boolean'} selfRegistration: {type: 'boolean'}
} }
} }
...@@ -34,8 +35,8 @@ module.exports = class Authentication extends Model { ...@@ -34,8 +35,8 @@ module.exports = class Authentication extends Model {
return WIKI.models.authentication.query().findOne({ key }) return WIKI.models.authentication.query().findOne({ key })
} }
static async getStrategies() { static async getStrategies({ enabledOnly = false } = {}) {
const strategies = await WIKI.models.authentication.query() const strategies = await WIKI.models.authentication.query().where(enabledOnly ? { isEnabled: true } : {})
return strategies.map(str => ({ return strategies.map(str => ({
...str, ...str,
domainWhitelist: _.get(str.domainWhitelist, 'v', []), domainWhitelist: _.get(str.domainWhitelist, 'v', []),
......
...@@ -42,7 +42,6 @@ module.exports = class Page extends Model { ...@@ -42,7 +42,6 @@ module.exports = class Page extends Model {
title: {type: 'string'}, title: {type: 'string'},
description: {type: 'string'}, description: {type: 'string'},
publishState: {type: 'string'}, publishState: {type: 'string'},
privateNS: {type: 'string'},
publishStartDate: {type: 'string'}, publishStartDate: {type: 'string'},
publishEndDate: {type: 'string'}, publishEndDate: {type: 'string'},
content: {type: 'string'}, content: {type: 'string'},
...@@ -773,7 +772,7 @@ module.exports = class Page extends Model { ...@@ -773,7 +772,7 @@ module.exports = class Page extends Model {
* @returns {Promise} Promise with no value * @returns {Promise} Promise with no value
*/ */
static async deletePage(opts) { static async deletePage(opts) {
const page = await WIKI.models.pages.getPageFromDb(_.has(opts, 'id') ? opts.id : opts); const page = await WIKI.models.pages.getPageFromDb(_.has(opts, 'id') ? opts.id : opts)
if (!page) { if (!page) {
throw new WIKI.Error.PageNotFound() throw new WIKI.Error.PageNotFound()
} }
...@@ -1011,14 +1010,6 @@ module.exports = class Page extends Model { ...@@ -1011,14 +1010,6 @@ module.exports = class Page extends Model {
// 'pages.authorId': opts.userId // 'pages.authorId': opts.userId
// }) // })
// }) // })
// .andWhere(builder => {
// if (queryModeID) return
// if (opts.isPrivate) {
// builder.where({ 'pages.isPrivate': true, 'pages.privateNS': opts.privateNS })
// } else {
// builder.where({ 'pages.isPrivate': false })
// }
// })
.first() .first()
} catch (err) { } catch (err) {
WIKI.logger.warn(err) WIKI.logger.warn(err)
...@@ -1074,8 +1065,7 @@ module.exports = class Page extends Model { ...@@ -1074,8 +1065,7 @@ module.exports = class Page extends Model {
return { return {
...page, ...page,
path: opts.path, path: opts.path,
localeCode: opts.locale, localeCode: opts.locale
isPrivate: opts.isPrivate
} }
} catch (err) { } catch (err) {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
......
...@@ -16,7 +16,7 @@ module.exports = class UserKey extends Model { ...@@ -16,7 +16,7 @@ module.exports = class UserKey extends Model {
required: ['kind', 'token', 'validUntil'], required: ['kind', 'token', 'validUntil'],
properties: { properties: {
id: {type: 'integer'}, id: {type: 'string'},
kind: {type: 'string'}, kind: {type: 'string'},
token: {type: 'string'}, token: {type: 'string'},
createdAt: {type: 'string'}, createdAt: {type: 'string'},
...@@ -44,11 +44,12 @@ module.exports = class UserKey extends Model { ...@@ -44,11 +44,12 @@ module.exports = class UserKey extends Model {
this.createdAt = DateTime.utc().toISO() this.createdAt = DateTime.utc().toISO()
} }
static async generateToken ({ userId, kind }, context) { static async generateToken ({ userId, kind, meta }, context) {
const token = await nanoid() const token = await nanoid()
await WIKI.models.userKeys.query().insert({ await WIKI.models.userKeys.query().insert({
kind, kind,
token, token,
meta,
validUntil: DateTime.utc().plus({ days: 1 }).toISO(), validUntil: DateTime.utc().plus({ days: 1 }).toISO(),
userId userId
}) })
...@@ -64,7 +65,10 @@ module.exports = class UserKey extends Model { ...@@ -64,7 +65,10 @@ module.exports = class UserKey extends Model {
if (DateTime.utc() > DateTime.fromISO(res.validUntil)) { if (DateTime.utc() > DateTime.fromISO(res.validUntil)) {
throw new WIKI.Error.AuthValidationTokenInvalid() throw new WIKI.Error.AuthValidationTokenInvalid()
} }
return res.user return {
...res.meta,
user: res.user
}
} else { } else {
throw new WIKI.Error.AuthValidationTokenInvalid() throw new WIKI.Error.AuthValidationTokenInvalid()
} }
......
/* global WIKI */ /* global WIKI */
const bcrypt = require('bcryptjs-then')
const _ = require('lodash') const _ = require('lodash')
const tfa = require('node-2fa') const tfa = require('node-2fa')
const jwt = require('jsonwebtoken') const jwt = require('jsonwebtoken')
...@@ -22,15 +21,9 @@ module.exports = class User extends Model { ...@@ -22,15 +21,9 @@ module.exports = class User extends Model {
required: ['email'], required: ['email'],
properties: { properties: {
id: {type: 'integer'}, id: {type: 'string'},
email: {type: 'string', format: 'email'}, email: {type: 'string', format: 'email'},
name: {type: 'string', minLength: 1, maxLength: 255}, name: {type: 'string', minLength: 1, maxLength: 255},
providerId: {type: 'string'},
password: {type: 'string'},
tfaIsActive: {type: 'boolean', default: false},
tfaSecret: {type: ['string', null]},
jobTitle: {type: 'string'},
location: {type: 'string'},
pictureUrl: {type: 'string'}, pictureUrl: {type: 'string'},
isSystem: {type: 'boolean'}, isSystem: {type: 'boolean'},
isActive: {type: 'boolean'}, isActive: {type: 'boolean'},
...@@ -41,6 +34,10 @@ module.exports = class User extends Model { ...@@ -41,6 +34,10 @@ module.exports = class User extends Model {
} }
} }
static get jsonAttributes() {
return ['auth', 'meta', 'prefs']
}
static get relationMappings() { static get relationMappings() {
return { return {
groups: { groups: {
...@@ -55,22 +52,6 @@ module.exports = class User extends Model { ...@@ -55,22 +52,6 @@ module.exports = class User extends Model {
to: 'groups.id' to: 'groups.id'
} }
}, },
provider: {
relation: Model.BelongsToOneRelation,
modelClass: require('./authentication'),
join: {
from: 'users.providerKey',
to: 'authentication.key'
}
},
defaultEditor: {
relation: Model.BelongsToOneRelation,
modelClass: require('./editors'),
join: {
from: 'users.editorKey',
to: 'editors.key'
}
},
locale: { locale: {
relation: Model.BelongsToOneRelation, relation: Model.BelongsToOneRelation,
modelClass: require('./locales'), modelClass: require('./locales'),
...@@ -104,21 +85,6 @@ module.exports = class User extends Model { ...@@ -104,21 +85,6 @@ module.exports = class User extends Model {
// Instance Methods // Instance Methods
// ------------------------------------------------ // ------------------------------------------------
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(pwd, this.password) === true) {
return true
} else {
throw new WIKI.Error.AuthLoginFailed()
}
}
async generateTFA() { async generateTFA() {
let tfaInfo = tfa.generateSecret({ let tfaInfo = tfa.generateSecret({
name: WIKI.config.title, name: WIKI.config.title,
...@@ -150,7 +116,7 @@ module.exports = class User extends Model { ...@@ -150,7 +116,7 @@ module.exports = class User extends Model {
return (result && _.has(result, 'delta') && result.delta === 0) return (result && _.has(result, 'delta') && result.delta === 0)
} }
getGlobalPermissions() { getPermissions() {
return _.uniq(_.flatten(_.map(this.groups, 'permissions'))) return _.uniq(_.flatten(_.map(this.groups, 'permissions')))
} }
...@@ -297,7 +263,7 @@ module.exports = class User extends Model { ...@@ -297,7 +263,7 @@ module.exports = class User extends Model {
throw new WIKI.Error.AuthProviderInvalid() throw new WIKI.Error.AuthProviderInvalid()
} }
const strInfo = _.find(WIKI.data.authentication, ['key', selStrategy.strategyKey]) const strInfo = _.find(WIKI.data.authentication, ['key', selStrategy.module])
// Inject form user/pass // Inject form user/pass
if (strInfo.useForm) { if (strInfo.useForm) {
...@@ -308,7 +274,7 @@ module.exports = class User extends Model { ...@@ -308,7 +274,7 @@ module.exports = class User extends Model {
// Authenticate // Authenticate
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
WIKI.auth.passport.authenticate(selStrategy.key, { WIKI.auth.passport.authenticate(selStrategy.id, {
session: !strInfo.useForm, session: !strInfo.useForm,
scope: strInfo.scopes ? strInfo.scopes : null scope: strInfo.scopes ? strInfo.scopes : null
}, async (err, user, info) => { }, async (err, user, info) => {
...@@ -316,7 +282,7 @@ module.exports = class User extends Model { ...@@ -316,7 +282,7 @@ module.exports = class User extends Model {
if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) } if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) }
try { try {
const resp = await WIKI.models.users.afterLoginChecks(user, context, { const resp = await WIKI.models.users.afterLoginChecks(user, selStrategy.id, context, {
skipTFA: !strInfo.useForm, skipTFA: !strInfo.useForm,
skipChangePwd: !strInfo.useForm skipChangePwd: !strInfo.useForm
}) })
...@@ -334,7 +300,7 @@ module.exports = class User extends Model { ...@@ -334,7 +300,7 @@ module.exports = class User extends Model {
/** /**
* Perform post-login checks * Perform post-login checks
*/ */
static async afterLoginChecks (user, context, { skipTFA, skipChangePwd } = { skipTFA: false, skipChangePwd: false }) { static async afterLoginChecks (user, strategyId, context, { skipTFA, skipChangePwd } = { skipTFA: false, skipChangePwd: false }) {
// Get redirect target // Get redirect target
user.groups = await user.$relatedQuery('groups').select('groups.id', 'permissions', 'redirectOnLogin') user.groups = await user.$relatedQuery('groups').select('groups.id', 'permissions', 'redirectOnLogin')
let redirect = '/' let redirect = '/'
...@@ -347,9 +313,12 @@ module.exports = class User extends Model { ...@@ -347,9 +313,12 @@ module.exports = class User extends Model {
} }
} }
// Get auth strategy flags
const authStr = user.auth[strategyId] || {}
// Is 2FA required? // Is 2FA required?
if (!skipTFA) { if (!skipTFA) {
if (user.tfaIsActive && user.tfaSecret) { if (authStr.tfaRequired && authStr.tfaSecret) {
try { try {
const tfaToken = await WIKI.models.userKeys.generateToken({ const tfaToken = await WIKI.models.userKeys.generateToken({
kind: 'tfa', kind: 'tfa',
...@@ -364,7 +333,7 @@ module.exports = class User extends Model { ...@@ -364,7 +333,7 @@ module.exports = class User extends Model {
WIKI.logger.warn(errc) WIKI.logger.warn(errc)
throw new WIKI.Error.AuthGenericError() throw new WIKI.Error.AuthGenericError()
} }
} else if (WIKI.config.auth.enforce2FA || (user.tfaIsActive && !user.tfaSecret)) { } else if (WIKI.config.auth.enforce2FA || (authStr.tfaIsActive && !authStr.tfaSecret)) {
try { try {
const tfaQRImage = await user.generateTFA() const tfaQRImage = await user.generateTFA()
const tfaToken = await WIKI.models.userKeys.generateToken({ const tfaToken = await WIKI.models.userKeys.generateToken({
...@@ -385,7 +354,7 @@ module.exports = class User extends Model { ...@@ -385,7 +354,7 @@ module.exports = class User extends Model {
} }
// Must Change Password? // Must Change Password?
if (!skipChangePwd && user.mustChangePwd) { if (!skipChangePwd && authStr.mustChangePwd) {
try { try {
const pwdChangeToken = await WIKI.models.userKeys.generateToken({ const pwdChangeToken = await WIKI.models.userKeys.generateToken({
kind: 'changePwd', kind: 'changePwd',
...@@ -440,18 +409,10 @@ module.exports = class User extends Model { ...@@ -440,18 +409,10 @@ module.exports = class User extends Model {
token: jwt.sign({ token: jwt.sign({
id: user.id, id: user.id,
email: user.email, email: user.email,
name: user.name,
av: user.pictureUrl,
tz: user.timezone,
lc: user.localeCode,
df: user.dateFormat,
ap: user.appearance,
// defaultEditor: user.defaultEditor,
permissions: user.getGlobalPermissions(),
groups: user.getGroups() groups: user.getGroups()
}, { }, {
key: WIKI.config.certs.private, key: WIKI.config.auth.certs.private,
passphrase: WIKI.config.sessionSecret passphrase: WIKI.config.auth.secret
}, { }, {
algorithm: 'RS256', algorithm: 'RS256',
expiresIn: WIKI.config.auth.tokenExpiration, expiresIn: WIKI.config.auth.tokenExpiration,
...@@ -877,7 +838,7 @@ module.exports = class User extends Model { ...@@ -877,7 +838,7 @@ module.exports = class User extends Model {
WIKI.logger.error('CRITICAL ERROR: Guest user is missing!') WIKI.logger.error('CRITICAL ERROR: Guest user is missing!')
process.exit(1) process.exit(1)
} }
user.permissions = user.getGlobalPermissions() user.permissions = user.getPermissions()
return user return user
} }
......
/* global WIKI */ /* global WIKI */
const bcrypt = require('bcryptjs-then')
// ------------------------------------ // ------------------------------------
// Local Account // Local Account
...@@ -8,27 +9,30 @@ const LocalStrategy = require('passport-local').Strategy ...@@ -8,27 +9,30 @@ const LocalStrategy = require('passport-local').Strategy
module.exports = { module.exports = {
init (passport, conf) { init (passport, conf) {
passport.use('local', passport.use(conf.key,
new LocalStrategy({ new LocalStrategy({
usernameField: 'email', usernameField: 'email',
passwordField: 'password' passwordField: 'password'
}, async (uEmail, uPassword, done) => { }, async (uEmail, uPassword, done) => {
try { try {
const user = await WIKI.models.users.query().findOne({ const user = await WIKI.models.users.query().findOne({
email: uEmail.toLowerCase(), email: uEmail.toLowerCase()
providerKey: 'local'
}) })
if (user) { if (user) {
await user.verifyPassword(uPassword) const authStrategyData = user.auth[conf.key]
if (!user.isActive) { if (!authStrategyData) {
done(new WIKI.Error.AuthAccountBanned(), null) throw new WIKI.Error.AuthLoginFailed()
} else if (await bcrypt.compare(uPassword, authStrategyData.password) !== true) {
throw new WIKI.Error.AuthLoginFailed()
} else if (!user.isActive) {
throw new WIKI.Error.AuthAccountBanned()
} else if (!user.isVerified) { } else if (!user.isVerified) {
done(new WIKI.Error.AuthAccountNotVerified(), null) throw new WIKI.Error.AuthAccountNotVerified()
} else { } else {
done(null, user) done(null, user)
} }
} else { } else {
done(new WIKI.Error.AuthLoginFailed(), null) throw new WIKI.Error.AuthLoginFailed()
} }
} catch (err) { } catch (err) {
done(err, null) done(err, null)
......
...@@ -6,7 +6,7 @@ html(lang=siteConfig.lang) ...@@ -6,7 +6,7 @@ html(lang=siteConfig.lang)
meta(name='viewport', content='user-scalable=yes, width=device-width, initial-scale=1, maximum-scale=5') meta(name='viewport', content='user-scalable=yes, width=device-width, initial-scale=1, maximum-scale=5')
meta(name='theme-color', content='#1976d2') meta(name='theme-color', content='#1976d2')
meta(name='msapplication-TileColor', content='#1976d2') meta(name='msapplication-TileColor', content='#1976d2')
meta(name='msapplication-TileImage', content='/_assets/favicons/mstile-150x150.png') meta(name='msapplication-TileImage', content='/_assets-legacy/favicons/mstile-150x150.png')
title= pageMeta.title + ' | ' + config.title title= pageMeta.title + ' | ' + config.title
...@@ -20,12 +20,12 @@ html(lang=siteConfig.lang) ...@@ -20,12 +20,12 @@ html(lang=siteConfig.lang)
meta(property='og:site_name', content=config.title) meta(property='og:site_name', content=config.title)
//- Favicon //- Favicon
link(rel='apple-touch-icon', sizes='180x180', href='/_assets/favicons/apple-touch-icon.png') link(rel='apple-touch-icon', sizes='180x180', href='/_assets-legacy/favicons/apple-touch-icon.png')
link(rel='icon', type='image/png', sizes='192x192', href='/_assets/favicons/android-chrome-192x192.png') link(rel='icon', type='image/png', sizes='192x192', href='/_assets-legacy/favicons/android-chrome-192x192.png')
link(rel='icon', type='image/png', sizes='32x32', href='/_assets/favicons/favicon-32x32.png') link(rel='icon', type='image/png', sizes='32x32', href='/_assets-legacy/favicons/favicon-32x32.png')
link(rel='icon', type='image/png', sizes='16x16', href='/_assets/favicons/favicon-16x16.png') link(rel='icon', type='image/png', sizes='16x16', href='/_assets-legacy/favicons/favicon-16x16.png')
link(rel='mask-icon', href='/_assets/favicons/safari-pinned-tab.svg', color='#1976d2') link(rel='mask-icon', href='/_assets-legacy/favicons/safari-pinned-tab.svg', color='#1976d2')
link(rel='manifest', href='/_assets/manifest.json') link(rel='manifest', href='/_assets-legacy/manifest.json')
//- Site Properties //- Site Properties
script. script.
......
extends base.pug doctype html
html
block body head
#root.is-fullscreen meta(charset="UTF-8")
.app-error link(rel="icon" href="/favicon.ico")
a(href='/') meta(name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width")
img(src='/_assets/svg/logo-wikijs.svg') title Wiki.js
strong Oops, something went wrong... link(href="/_assets/fonts/roboto/roboto.css" rel="stylesheet")
span= message style(lang='text/scss').
body {
if error.stack margin: 0;
pre: code #{error.stack} font-family: "Roboto", "-apple-system", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}
.errorpage {
background:#070a0d radial-gradient(ellipse,#161b22,#070a0d);
color:#fff;
height:100vh;
}
.errorpage-bg {
position:absolute;
top:50%;
left:50%;
width:320px;
height:320px;
background:linear-gradient(0,transparent 50%,#c62828 50%);
border-radius:50%;
filter:blur(80px);
transform:translate(-50%,-50%);
visibility:hidden;
}
.errorpage-content {
position:absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
.errorpage-code {
font-size:12rem;
line-height:12rem;
font-weight:700;
background:linear-gradient(45deg,#c62828,#ef9a9a);
-webkit-background-clip:text;
background-clip:text;
-webkit-text-fill-color:transparent;
-webkit-user-select:none;
user-select:none;
}
.errorpage-title {
font-size:80px;
font-weight:500;
line-height:80px;
}
.errorpage-hint {
font-size:1.2rem;
font-weight:500;
color:#ef9a9a;
line-height:1.2rem;
margin-top:1rem;
}
.errorpage-pre {
margin-top: 28px;
color: rgba(255,255,255,.5);
}
body
.errorpage
.errorpage-bg
.errorpage-content
.errorpage-code 500
.errorpage-title Server Error
.errorpage-hint= message
if error.stack
pre.errorpage-pre: code #{error.stack}
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
"@codemirror/tooltip": "0.19.16", "@codemirror/tooltip": "0.19.16",
"@codemirror/view": "6.0.2", "@codemirror/view": "6.0.2",
"@lezer/common": "1.0.0", "@lezer/common": "1.0.0",
"@quasar/extras": "1.15.0", "@quasar/extras": "1.15.1",
"@tiptap/core": "2.0.0-beta.176", "@tiptap/core": "2.0.0-beta.176",
"@tiptap/extension-code-block": "2.0.0-beta.37", "@tiptap/extension-code-block": "2.0.0-beta.37",
"@tiptap/extension-code-block-lowlight": "2.0.0-beta.68", "@tiptap/extension-code-block-lowlight": "2.0.0-beta.68",
...@@ -63,31 +63,32 @@ ...@@ -63,31 +63,32 @@
"codemirror": "6.0.1", "codemirror": "6.0.1",
"filesize": "9.0.11", "filesize": "9.0.11",
"filesize-parser": "1.5.0", "filesize-parser": "1.5.0",
"graphql": "16.5.0", "graphql": "16.6.0",
"graphql-tag": "2.12.6", "graphql-tag": "2.12.6",
"js-cookie": "3.0.1", "js-cookie": "3.0.1",
"jwt-decode": "3.1.2", "jwt-decode": "3.1.2",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"luxon": "3.0.1", "luxon": "3.0.1",
"pinia": "2.0.17", "pinia": "2.0.20",
"pug": "3.0.2", "pug": "3.0.2",
"quasar": "2.7.5", "quasar": "2.7.7",
"tippy.js": "6.3.7", "tippy.js": "6.3.7",
"uuid": "8.3.2", "uuid": "8.3.2",
"v-network-graph": "0.6.5", "v-network-graph": "0.6.6",
"vue": "3.2.37", "vue": "3.2.37",
"vue-codemirror": "6.0.2", "vue-codemirror": "6.0.2",
"vue-i18n": "9.1.10", "vue-i18n": "9.2.2",
"vue-router": "4.1.3", "vue-router": "4.1.3",
"vue3-otp-input": "0.3.6",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"zxcvbn": "4.4.2" "zxcvbn": "4.4.2"
}, },
"devDependencies": { "devDependencies": {
"@intlify/vite-plugin-vue-i18n": "5.0.1", "@intlify/vite-plugin-vue-i18n": "6.0.1",
"@quasar/app-vite": "1.0.5", "@quasar/app-vite": "1.0.6",
"@types/lodash": "4.14.182", "@types/lodash": "4.14.184",
"browserlist": "latest", "browserlist": "latest",
"eslint": "8.20.0", "eslint": "8.22.0",
"eslint-config-standard": "17.0.0", "eslint-config-standard": "17.0.0",
"eslint-plugin-import": "2.26.0", "eslint-plugin-import": "2.26.0",
"eslint-plugin-n": "15.2.4", "eslint-plugin-n": "15.2.4",
......
...@@ -112,7 +112,8 @@ module.exports = configure(function (/* ctx */) { ...@@ -112,7 +112,8 @@ module.exports = configure(function (/* ctx */) {
delay: 500, delay: 500,
spinner: 'QSpinnerGrid', spinner: 'QSpinnerGrid',
spinnerSize: 32, spinnerSize: 32,
spinnerColor: 'white' spinnerColor: 'white',
customClass: 'loading-darker'
}, },
loadingBar: { loadingBar: {
color: 'primary', color: 'primary',
......
...@@ -117,7 +117,7 @@ body::-webkit-scrollbar-thumb { ...@@ -117,7 +117,7 @@ body::-webkit-scrollbar-thumb {
} }
&:hover .q-focus-helper { &:hover .q-focus-helper {
opacity: .3; opacity: .3 !important;
} }
} }
...@@ -210,6 +210,12 @@ body::-webkit-scrollbar-thumb { ...@@ -210,6 +210,12 @@ body::-webkit-scrollbar-thumb {
} }
} }
.loading-darker {
.q-loading__backdrop {
opacity: .75;
}
}
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// IMPORTS // IMPORTS
// ------------------------------------------------------------------ // ------------------------------------------------------------------
......
...@@ -919,8 +919,9 @@ ...@@ -919,8 +919,9 @@
"auth.actions.register": "Register", "auth.actions.register": "Register",
"auth.changePwd.instructions": "You must choose a new password:", "auth.changePwd.instructions": "You must choose a new password:",
"auth.changePwd.loading": "Changing password...", "auth.changePwd.loading": "Changing password...",
"auth.changePwd.newPasswordPlaceholder": "New Password", "auth.changePwd.currentPassword": "Current Password",
"auth.changePwd.newPasswordVerifyPlaceholder": "Verify New Password", "auth.changePwd.newPassword": "New Password",
"auth.changePwd.newPasswordVerify": "Verify New Password",
"auth.changePwd.proceed": "Change Password", "auth.changePwd.proceed": "Change Password",
"auth.changePwd.subtitle": "Choose a new password", "auth.changePwd.subtitle": "Choose a new password",
"auth.enterCredentials": "Enter your credentials", "auth.enterCredentials": "Enter your credentials",
...@@ -932,6 +933,20 @@ ...@@ -932,6 +933,20 @@
"auth.errors.tooManyAttempts": "Too many attempts!", "auth.errors.tooManyAttempts": "Too many attempts!",
"auth.errors.tooManyAttemptsMsg": "You've made too many failed attempts in a short period of time, please try again {time}.", "auth.errors.tooManyAttemptsMsg": "You've made too many failed attempts in a short period of time, please try again {time}.",
"auth.errors.userNotFound": "User not found", "auth.errors.userNotFound": "User not found",
"auth.errors.missingName": "Name is missing.",
"auth.errors.invalidName": "Name is invalid.",
"auth.errors.missingEmail": "Email is missing.",
"auth.errors.invalidEmail": "Email is invalid.",
"auth.errors.missingPassword": "Password is missing.",
"auth.errors.passwordTooShort": "Password is too short.",
"auth.errors.missingVerifyPassword": "Password Verification is missing.",
"auth.errors.passwordsNotMatch": "Passwords do not match.",
"auth.errors.missingUsername": "Username is missing.",
"auth.errors.register": "One or more fields are invalid.",
"auth.errors.login": "Missing or invalid login fields.",
"auth.errors.forgotPassword": "Missing or invalid email address.",
"auth.errors.tfaMissing": "Missing or incomplete security code.",
"auth.login.title": "Login",
"auth.fields.email": "Email Address", "auth.fields.email": "Email Address",
"auth.fields.emailUser": "Email / Username", "auth.fields.emailUser": "Email / Username",
"auth.fields.name": "Name", "auth.fields.name": "Name",
...@@ -939,7 +954,7 @@ ...@@ -939,7 +954,7 @@
"auth.fields.username": "Username", "auth.fields.username": "Username",
"auth.fields.verifyPassword": "Verify Password", "auth.fields.verifyPassword": "Verify Password",
"auth.forgotPasswordCancel": "Cancel", "auth.forgotPasswordCancel": "Cancel",
"auth.forgotPasswordLink": "Forgot your password?", "auth.forgotPasswordLink": "Forgot Password",
"auth.forgotPasswordLoading": "Requesting password reset...", "auth.forgotPasswordLoading": "Requesting password reset...",
"auth.forgotPasswordSubtitle": "Enter your email address to receive the instructions to reset your password:", "auth.forgotPasswordSubtitle": "Enter your email address to receive the instructions to reset your password:",
"auth.forgotPasswordSuccess": "Check your emails for password reset instructions!", "auth.forgotPasswordSuccess": "Check your emails for password reset instructions!",
...@@ -960,29 +975,17 @@ ...@@ -960,29 +975,17 @@
"auth.passwordNotMatch": "Both passwords do not match.", "auth.passwordNotMatch": "Both passwords do not match.",
"auth.passwordTooShort": "Password is too short.", "auth.passwordTooShort": "Password is too short.",
"auth.pleaseWait": "Please wait", "auth.pleaseWait": "Please wait",
"auth.providers.azure": "Azure Active Directory",
"auth.providers.facebook": "Facebook",
"auth.providers.github": "GitHub",
"auth.providers.google": "Google ID",
"auth.providers.ldap": "LDAP / Active Directory",
"auth.providers.local": "Local",
"auth.providers.slack": "Slack",
"auth.providers.windowslive": "Microsoft Account",
"auth.registerCheckEmail": "Check your emails to activate your account.", "auth.registerCheckEmail": "Check your emails to activate your account.",
"auth.registerSubTitle": "Fill-in the form below to create your account.", "auth.registerSubTitle": "Fill-in the form below to create an account.",
"auth.registerSuccess": "Account created successfully!", "auth.registerSuccess": "Account created successfully!",
"auth.registerTitle": "Create an account", "auth.registerTitle": "Create an account",
"auth.registering": "Creating account...", "auth.registering": "Creating account...",
"auth.selectAuthProvider": "Select Authentication Provider", "auth.selectAuthProvider": "Sign in with",
"auth.sendResetPassword": "Reset Password", "auth.sendResetPassword": "Reset Password",
"auth.signingIn": "Signing In...", "auth.signingIn": "Signing In...",
"auth.switchToLogin.link": "Login instead", "auth.switchToLogin.link": "Back to Login",
"auth.switchToLogin.text": "Already have an account? {link}", "auth.switchToRegister.link": "Create an Account",
"auth.switchToRegister.link": "Create an account",
"auth.switchToRegister.text": "Don't have an account yet? {link}",
"auth.tfa.placeholder": "XXXXXX",
"auth.tfa.subtitle": "Security code required:", "auth.tfa.subtitle": "Security code required:",
"auth.tfa.title": "Two Factor Authentication",
"auth.tfa.verifyToken": "Verify", "auth.tfa.verifyToken": "Verify",
"auth.tfaFormTitle": "Enter the security code generated from your trusted device:", "auth.tfaFormTitle": "Enter the security code generated from your trusted device:",
"auth.tfaSetupInstrFirst": "1) Scan the QR code below from your mobile 2FA application:", "auth.tfaSetupInstrFirst": "1) Scan the QR code below from your mobile 2FA application:",
...@@ -1147,11 +1150,11 @@ ...@@ -1147,11 +1150,11 @@
"common.pageSelector.pages": "Pages", "common.pageSelector.pages": "Pages",
"common.pageSelector.selectTitle": "Select a Page", "common.pageSelector.selectTitle": "Select a Page",
"common.pageSelector.virtualFolders": "Virtual Folders", "common.pageSelector.virtualFolders": "Virtual Folders",
"common.password.good": "Good",
"common.password.average": "Average", "common.password.average": "Average",
"common.password.strong": "Strong", "common.password.strong": "Strong",
"common.password.veryStrong": "Very Strong",
"common.password.veryWeak": "Very Weak",
"common.password.weak": "Weak", "common.password.weak": "Weak",
"common.password.poor": "Poor",
"common.sidebar.browse": "Browse", "common.sidebar.browse": "Browse",
"common.sidebar.currentDirectory": "Current Directory", "common.sidebar.currentDirectory": "Current Directory",
"common.sidebar.mainMenu": "Main Menu", "common.sidebar.mainMenu": "Main Menu",
......
...@@ -20,7 +20,7 @@ q-page.admin-locale ...@@ -20,7 +20,7 @@ q-page.admin-locale
icon='las la-question-circle' icon='las la-question-circle'
flat flat
color='grey' color='grey'
:href='siteStore.docsBase + `/admin/locale`' :href='siteStore.docsBase + `/admin/localisation`'
target='_blank' target='_blank'
type='a' type='a'
) )
......
...@@ -5,79 +5,7 @@ ...@@ -5,79 +5,7 @@
img(src='/_assets/logo-wikijs.svg' :alt='siteStore.title') img(src='/_assets/logo-wikijs.svg' :alt='siteStore.title')
h2.auth-site-title {{ siteStore.title }} h2.auth-site-title {{ siteStore.title }}
p.text-grey-7 Login to continue p.text-grey-7 Login to continue
template(v-if='state.strategies?.length > 1 || true') auth-login-panel
p Sign in with
.auth-strategies
q-btn(
label='GitHub'
icon='lab la-github'
push
no-caps
:color='$q.dark.isActive ? `blue-grey-9` : `grey-1`'
:text-color='$q.dark.isActive ? `white` : `blue-grey-9`'
)
q-btn(
label='Google'
icon='lab la-google-plus'
push
no-caps
:color='$q.dark.isActive ? `blue-grey-9` : `grey-1`'
:text-color='$q.dark.isActive ? `white` : `blue-grey-9`'
)
q-btn(
label='Twitter'
icon='lab la-twitter'
push
no-caps
:color='$q.dark.isActive ? `blue-grey-9` : `grey-1`'
:text-color='$q.dark.isActive ? `white` : `blue-grey-9`'
)
q-btn(
label='Local'
icon='las la-seedling'
push
color='primary'
no-caps
)
q-form.q-mt-md
q-input(
outlined
label='Email Address'
autocomplete='email'
)
template(#prepend)
i.las.la-user
q-input.q-mt-sm(
outlined
label='Password'
type='password'
autocomplete='current-password'
)
template(#prepend)
i.las.la-key
q-btn.full-width.q-mt-sm(
push
color='primary'
label='Login'
no-caps
icon='las la-sign-in-alt'
)
template(v-if='true')
q-separator.q-my-md
q-btn.acrylic-btn.full-width(
flat
color='primary'
label='Create an Account'
no-caps
icon='las la-user-plus'
)
q-btn.acrylic-btn.full-width.q-mt-sm(
flat
color='primary'
label='Forgot Password'
no-caps
icon='las la-life-ring'
)
.auth-bg(aria-hidden="true") .auth-bg(aria-hidden="true")
img(src='https://docs.requarks.io/_assets/img/splash/1.jpg' alt='') img(src='https://docs.requarks.io/_assets/img/splash/1.jpg' alt='')
</template> </template>
...@@ -91,8 +19,9 @@ import { useI18n } from 'vue-i18n' ...@@ -91,8 +19,9 @@ import { useI18n } from 'vue-i18n'
import { useMeta, useQuasar } from 'quasar' import { useMeta, useQuasar } from 'quasar'
import { onMounted, reactive, watch } from 'vue' import { onMounted, reactive, watch } from 'vue'
import AuthLoginPanel from 'src/components/AuthLoginPanel.vue'
import { useSiteStore } from 'src/stores/site' import { useSiteStore } from 'src/stores/site'
import { useDataStore } from 'src/stores/data'
// QUASAR // QUASAR
...@@ -101,7 +30,6 @@ const $q = useQuasar() ...@@ -101,7 +30,6 @@ const $q = useQuasar()
// STORES // STORES
const siteStore = useSiteStore() const siteStore = useSiteStore()
const dataStore = useDataStore()
// I18N // I18N
...@@ -116,27 +44,6 @@ useMeta({ ...@@ -116,27 +44,6 @@ useMeta({
// DATA // DATA
const state = reactive({ const state = reactive({
error: false,
strategies: [],
selectedStrategyKey: 'unselected',
selectedStrategy: { key: 'unselected', strategy: { useForm: false, usernameType: 'email' } },
screen: 'login',
username: '',
password: '',
hidePassword: true,
securityCode: '',
continuationToken: '',
isLoading: false,
loaderColor: 'grey darken-4',
loaderTitle: 'Working...',
isShown: false,
newPassword: '',
newPasswordVerify: '',
isTFAShown: false,
isTFASetupShown: false,
tfaQRImage: '',
errorShown: false,
errorMessage: '',
bgUrl: '_assets/bg/login-v3.jpg' bgUrl: '_assets/bg/login-v3.jpg'
}) })
...@@ -186,37 +93,6 @@ const state = reactive({ ...@@ -186,37 +93,6 @@ const state = reactive({
// METHODS // METHODS
async function fetchStrategies () {
const resp = await APOLLO_CLIENT.query({
query: gql`
query loginFetchSiteStrategies(
$siteId: UUID!
) {
authSiteStrategies(
siteId: $siteId
enabledOnly: true
) {
key
strategy {
key
logo
color
icon
useForm
usernameType
}
displayName
order
selfRegistration
}
}
`,
variables: {
siteId: siteStore.id
}
})
}
/** /**
* LOGIN * LOGIN
*/ */
...@@ -531,7 +407,7 @@ function handleLoginResponse (respObj) { ...@@ -531,7 +407,7 @@ function handleLoginResponse (respObj) {
} }
onMounted(() => { onMounted(() => {
fetchStrategies() // fetchStrategies()
}) })
</script> </script>
......
This diff was suppressed by a .gitattributes entry.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment