From 097833d77af5c3284836f0051872c78f38a94527 Mon Sep 17 00:00:00 2001 From: Nicolas Giard Date: Mon, 29 Aug 2022 04:59:15 +0000 Subject: [PATCH] feat: login page + auth panel + various improvements --- server/controllers/common.js | 7 +- server/core/auth.js | 13 +- server/db/migrations/3.0.0.js | 19 +- server/graph/resolvers/authentication.js | 42 +- server/graph/schemas/authentication.graphql | 15 +- server/graph/schemas/user.graphql | 5 - server/helpers/error.js | 180 ++-- server/helpers/graph.js | 2 +- server/models/authentication.js | 5 +- server/models/pages.js | 14 +- server/models/userKeys.js | 10 +- server/models/users.js | 77 +- .../authentication/local/authentication.js | 20 +- server/views/base.pug | 14 +- server/views/error.pug | 89 +- ux/package.json | 21 +- ux/public/_assets/logo-wikijs-full.svg | 159 ++++ ux/quasar.config.js | 3 +- ux/src/components/AuthLoginPanel.vue | 788 ++++++++++++++++++ ux/src/css/app.scss | 8 +- ux/src/i18n/locales/en.json | 45 +- ux/src/pages/AdminLocale.vue | 2 +- ux/src/pages/Login.vue | 132 +-- ux/yarn.lock | 573 ++++++++----- 24 files changed, 1590 insertions(+), 653 deletions(-) create mode 100644 ux/public/_assets/logo-wikijs-full.svg create mode 100644 ux/src/components/AuthLoginPanel.vue diff --git a/server/controllers/common.js b/server/controllers/common.js index 01b7a5ee..b46e82de 100644 --- a/server/controllers/common.js +++ b/server/controllers/common.js @@ -430,8 +430,7 @@ router.get('/*', async (req, res, next) => { const page = await WIKI.models.pages.getPage({ path: pageArgs.path, locale: pageArgs.locale, - userId: req.user.id, - isPrivate: false + userId: req.user.id }) pageArgs.tags = _.get(page, 'tags', []) @@ -440,12 +439,12 @@ router.get('/*', async (req, res, next) => { // -> Check User Access if (!effectivePermissions.pages.read) { - if (req.user.id === 2) { + if (req.user.id === WIKI.auth.guest.id) { res.cookie('loginRedirect', req.path, { 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(`/_error/unauthorized?from=${req.path}`) diff --git a/server/core/auth.js b/server/core/auth.js index 37bd2cf1..2c96e9ac 100644 --- a/server/core/auth.js +++ b/server/core/auth.js @@ -75,9 +75,8 @@ module.exports = { })) // Load enabled strategies - const enabledStrategies = await WIKI.models.authentication.getStrategies() - for (const idx in enabledStrategies) { - const stg = enabledStrategies[idx] + const enabledStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true }) + for (const stg of enabledStrategies) { try { const strategy = require(`../modules/authentication/${stg.module}/authentication.js`) @@ -146,7 +145,7 @@ module.exports = { try { const newToken = await WIKI.models.users.refreshToken(jwtPayload.id) user = newToken.user - user.permissions = user.getGlobalPermissions() + user.permissions = user.getPermissions() user.groups = user.getGroups() req.user = user @@ -186,7 +185,7 @@ module.exports = { localeCode: 'en', permissions: _.get(WIKI.auth.groups, `${user.grp}.permissions`, []), groups: [user.grp], - getGlobalPermissions () { + getPermissions () { return req.user.permissions }, getGroups () { @@ -215,7 +214,7 @@ module.exports = { * @param {String|Boolean} path */ checkAccess(user, permissions = [], page = false) { - const userPermissions = user.permissions ? user.permissions : user.getGlobalPermissions() + const userPermissions = user.permissions ? user.permissions : user.getPermissions() // System Admin if (_.includes(userPermissions, 'manage:system')) { @@ -298,7 +297,7 @@ module.exports = { * @param {Array} excludePermissions */ checkExclusiveAccess(user, includePermissions = [], excludePermissions = []) { - const userPermissions = user.permissions ? user.permissions : user.getGlobalPermissions() + const userPermissions = user.permissions ? user.permissions : user.getPermissions() // Check Inclusion Permissions if (_.intersection(userPermissions, includePermissions).length < 1) { diff --git a/server/db/migrations/3.0.0.js b/server/db/migrations/3.0.0.js index cde09b84..063114af 100644 --- a/server/db/migrations/3.0.0.js +++ b/server/db/migrations/3.0.0.js @@ -17,6 +17,13 @@ exports.up = async knex => { // ===================================== // 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 --------------------------- .createTable('analytics', table => { table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()')) @@ -236,6 +243,7 @@ exports.up = async knex => { table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()')) table.string('kind').notNullable() table.string('token').notNullable() + table.jsonb('meta').notNullable().defaultTo('{}') table.timestamp('validUntil').notNullable() table.timestamp('createdAt').notNullable().defaultTo(knex.fn.now()) }) @@ -244,10 +252,9 @@ exports.up = async knex => { table.uuid('id').notNullable().primary().defaultTo(knex.raw('gen_random_uuid()')) table.string('email').notNullable() table.string('name').notNullable() - table.jsonb('auth') - table.jsonb('tfa') - table.jsonb('meta') - table.jsonb('prefs') + table.jsonb('auth').notNullable().defaultTo('{}') + table.jsonb('meta').notNullable().defaultTo('{}') + table.jsonb('prefs').notNullable().defaultTo('{}') table.string('pictureUrl') table.boolean('isSystem').notNullable().defaultTo(false) table.boolean('isActive').notNullable().defaultTo(false) @@ -274,6 +281,9 @@ exports.up = async knex => { // ===================================== // REFERENCES // ===================================== + .table('activityLogs', table => { + table.uuid('userId').notNullable().references('id').inTable('users') + }) .table('analytics', table => { table.uuid('siteId').notNullable().references('id').inTable('sites') }) @@ -471,6 +481,7 @@ exports.up = async knex => { index: true, follow: true }, + authStrategies: [{ id: authModuleId, order: 0, isVisible: true }], locale: 'en', localeNamespacing: false, localeNamespaces: [], diff --git a/server/graph/resolvers/authentication.js b/server/graph/resolvers/authentication.js index 8ade02f1..f4810a40 100644 --- a/server/graph/resolvers/authentication.js +++ b/server/graph/resolvers/authentication.js @@ -1,6 +1,4 @@ const _ = require('lodash') -const fs = require('fs-extra') -const path = require('path') const graphHelper = require('../../helpers/graph') /* global WIKI */ @@ -28,6 +26,9 @@ module.exports = { apiState () { return WIKI.config.api.isEnabled }, + /** + * Fetch authentication strategies + */ async authStrategies () { return WIKI.data.authentication.map(stg => ({ ...stg, @@ -38,33 +39,23 @@ module.exports = { * Fetch active authentication strategies */ async authActiveStrategies (obj, args, context) { - return WIKI.models.authentication.getStrategies() + return WIKI.models.authentication.getStrategies({ enabledOnly: args.enabledOnly }) }, /** * Fetch site authentication strategies */ async authSiteStrategies (obj, args, context, info) { - let strategies = await WIKI.models.authentication.getStrategies() - strategies = strategies.map(stg => { - const strategyInfo = _.find(WIKI.data.authentication, ['key', stg.strategyKey]) || {} + const site = await WIKI.models.sites.query().findById(args.siteId) + const activeStrategies = await WIKI.models.authentication.getStrategies({ enabledOnly: true }) + return activeStrategies.map(str => { + const siteAuth = _.find(site.config.authStrategies, ['id', str.id]) || {} return { - ...stg, - strategy: strategyInfo, - config: _.sortBy(_.transform(stg.config, (res, value, key) => { - const configData = _.get(strategyInfo.props, key, false) - if (configData) { - res.push({ - key, - value: JSON.stringify({ - ...configData, - value - }) - }) - } - }, []), 'key') + id: str.id, + activeStrategy: str, + order: siteAuth.order ?? 0, + isVisible: siteAuth.isVisible ?? false } }) - return args.enabledOnly ? _.filter(strategies, 'isEnabled') : strategies } }, Mutation: { @@ -93,13 +84,14 @@ module.exports = { const authResult = await WIKI.models.users.login(args, context) return { ...authResult, - responseResult: graphHelper.generateSuccess('Login success') + operation: graphHelper.generateSuccess('Login success') } } catch (err) { // LDAP Debug Flag if (args.strategy === 'ldap' && WIKI.config.flags.ldapdebug) { WIKI.logger.warn('LDAP LOGIN ERROR (c1): ', err) } + console.error(err) return graphHelper.generateError(err) } @@ -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 { const authResult = await WIKI.models.users.loginChangePassword(args, context) return { @@ -133,7 +125,7 @@ module.exports = { } }, /** - * Perform Mandatory Password Change after Login + * Perform Forget Password */ async forgotPassword (obj, args, context) { try { diff --git a/server/graph/schemas/authentication.graphql b/server/graph/schemas/authentication.graphql index 7875283e..778a9f39 100644 --- a/server/graph/schemas/authentication.graphql +++ b/server/graph/schemas/authentication.graphql @@ -9,7 +9,9 @@ extend type Query { authStrategies: [AuthenticationStrategy] - authActiveStrategies: [AuthenticationActiveStrategy] + authActiveStrategies( + enabledOnly: Boolean + ): [AuthenticationActiveStrategy] authSiteStrategies( siteId: UUID! @@ -27,7 +29,8 @@ extend type Mutation { login( username: String! password: String! - strategy: String! + strategyId: UUID! + siteId: UUID ): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60) loginTFA( @@ -36,9 +39,13 @@ extend type Mutation { setup: Boolean ): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60) - loginChangePassword( - continuationToken: String! + changePassword( + userId: UUID + continuationToken: String + currentPassword: String newPassword: String! + strategyId: UUID! + siteId: UUID ): AuthenticationLoginResponse @rateLimit(limit: 5, duration: 60) forgotPassword( diff --git a/server/graph/schemas/user.graphql b/server/graph/schemas/user.graphql index 4cc5fb15..d1e74818 100644 --- a/server/graph/schemas/user.graphql +++ b/server/graph/schemas/user.graphql @@ -73,11 +73,6 @@ extend type Mutation { dateFormat: String! appearance: String! ): UserTokenResponse - - changePassword( - current: String! - new: String! - ): UserTokenResponse } # ----------------------------------------------- diff --git a/server/helpers/error.js b/server/helpers/error.js index f9a81779..6bff807a 100644 --- a/server/helpers/error.js +++ b/server/helpers/error.js @@ -2,243 +2,183 @@ const CustomError = require('custom-error-instance') module.exports = { AssetDeleteForbidden: CustomError('AssetDeleteForbidden', { - message: 'You are not authorized to delete this asset.', - code: 2003 + message: 'You are not authorized to delete this asset.' }), AssetFolderExists: CustomError('AssetFolderExists', { - message: 'An asset folder with the same name already exists.', - code: 2002 + message: 'An asset folder with the same name already exists.' }), AssetGenericError: CustomError('AssetGenericError', { - message: 'An unexpected error occured during asset operation.', - code: 2001 + message: 'An unexpected error occured during asset operation.' }), AssetInvalid: CustomError('AssetInvalid', { - message: 'This asset does not exist or is invalid.', - code: 2004 + message: 'This asset does not exist or is invalid.' }), AssetRenameCollision: CustomError('AssetRenameCollision', { - message: 'An asset with the same filename in the same folder already exists.', - code: 2005 + message: 'An asset with the same filename in the same folder already exists.' }), AssetRenameForbidden: CustomError('AssetRenameForbidden', { - message: 'You are not authorized to rename this asset.', - code: 2006 + message: 'You are not authorized to rename this asset.' }), AssetRenameInvalid: CustomError('AssetRenameInvalid', { - message: 'The new asset filename is invalid.', - code: 2007 + message: 'The new asset filename is invalid.' }), AssetRenameInvalidExt: CustomError('AssetRenameInvalidExt', { - message: 'The file extension cannot be changed on an existing asset.', - code: 2008 + message: 'The file extension cannot be changed on an existing asset.' }), AssetRenameTargetForbidden: CustomError('AssetRenameTargetForbidden', { - message: 'You are not authorized to rename this asset to the requested name.', - code: 2009 + message: 'You are not authorized to rename this asset to the requested name.' }), AuthAccountBanned: CustomError('AuthAccountBanned', { - message: 'Your account has been disabled.', - code: 1013 + message: 'Your account has been disabled.' }), AuthAccountAlreadyExists: CustomError('AuthAccountAlreadyExists', { - message: 'An account already exists using this email address.', - code: 1004 + message: 'An account already exists using this email address.' }), AuthAccountNotVerified: CustomError('AuthAccountNotVerified', { - message: 'You must verify your account before your can login.', - code: 1014 + message: 'You must verify your account before your can login.' }), AuthGenericError: CustomError('AuthGenericError', { - message: 'An unexpected error occured during login.', - code: 1001 + message: 'An unexpected error occured during login.' }), AuthLoginFailed: CustomError('AuthLoginFailed', { - message: 'Invalid email / username or password.', - code: 1002 + message: 'Invalid email / username or password.' }), AuthPasswordInvalid: CustomError('AuthPasswordInvalid', { - message: 'Password is incorrect.', - code: 1020 + message: 'Password is incorrect.' }), AuthProviderInvalid: CustomError('AuthProviderInvalid', { - message: 'Invalid authentication provider.', - code: 1003 + message: 'Invalid authentication provider.' }), AuthRegistrationDisabled: CustomError('AuthRegistrationDisabled', { - message: 'Registration is disabled. Contact your system administrator.', - code: 1010 + message: 'Registration is disabled. Contact your system administrator.' }), AuthRegistrationDomainUnauthorized: CustomError('AuthRegistrationDomainUnauthorized', { - message: 'You are not authorized to register. Your domain is not whitelisted.', - code: 1011 + message: 'You are not authorized to register. Your domain is not whitelisted.' }), AuthRequired: CustomError('AuthRequired', { - message: 'You must be authenticated to access this resource.', - code: 1019 + message: 'You must be authenticated to access this resource.' }), AuthTFAFailed: CustomError('AuthTFAFailed', { - message: 'Incorrect TFA Security Code.', - code: 1005 + message: 'Incorrect TFA Security Code.' }), AuthTFAInvalid: CustomError('AuthTFAInvalid', { - message: 'Invalid TFA Security Code or Login Token.', - code: 1006 + message: 'Invalid TFA Security Code or Login Token.' }), AuthValidationTokenInvalid: CustomError('AuthValidationTokenInvalid', { - message: 'Invalid validation token.', - code: 1015 + message: 'Invalid validation token.' }), BruteInstanceIsInvalid: CustomError('BruteInstanceIsInvalid', { - message: 'Invalid Brute Force Instance.', - code: 1007 + message: 'Invalid Brute Force Instance.' }), BruteTooManyAttempts: CustomError('BruteTooManyAttempts', { - message: 'Too many attempts! Try again later.', - code: 1008 + message: 'Too many attempts! Try again later.' }), CommentContentMissing: CustomError('CommentContentMissing', { - message: 'Comment content is missing or too short.', - code: 8003 + message: 'Comment content is missing or too short.' }), CommentGenericError: CustomError('CommentGenericError', { - message: 'An unexpected error occured.', - code: 8001 + message: 'An unexpected error occured.' }), CommentManageForbidden: CustomError('CommentManageForbidden', { - message: 'You are not authorized to manage comments on this page.', - code: 8004 + message: 'You are not authorized to manage comments on this page.' }), CommentNotFound: CustomError('CommentNotFound', { - message: 'This comment does not exist.', - code: 8005 + message: 'This comment does not exist.' }), CommentPostForbidden: CustomError('CommentPostForbidden', { - message: 'You are not authorized to post a comment on this page.', - code: 8002 + message: 'You are not authorized to post a comment on this page.' }), CommentViewForbidden: CustomError('CommentViewForbidden', { - message: 'You are not authorized to view comments for this page.', - code: 8006 + message: 'You are not authorized to view comments for this page.' }), InputInvalid: CustomError('InputInvalid', { - message: 'Input data is invalid.', - code: 1012 + message: 'Input data is invalid.' }), LocaleGenericError: CustomError('LocaleGenericError', { - message: 'An unexpected error occured during locale operation.', - code: 5001 + message: 'An unexpected error occured during locale operation.' }), LocaleInvalidNamespace: CustomError('LocaleInvalidNamespace', { - message: 'Invalid locale or namespace.', - code: 5002 + message: 'Invalid locale or namespace.' }), MailGenericError: CustomError('MailGenericError', { - message: 'An unexpected error occured during mail operation.', - code: 3001 + message: 'An unexpected error occured during mail operation.' }), MailInvalidRecipient: CustomError('MailInvalidRecipient', { - message: 'The recipient email address is invalid.', - code: 3004 + message: 'The recipient email address is invalid.' }), MailNotConfigured: CustomError('MailNotConfigured', { - message: 'The mail configuration is incomplete or invalid.', - code: 3002 + message: 'The mail configuration is incomplete or invalid.' }), MailTemplateFailed: CustomError('MailTemplateFailed', { - message: 'Mail template failed to load.', - code: 3003 + message: 'Mail template failed to load.' }), PageCreateForbidden: CustomError('PageCreateForbidden', { - message: 'You are not authorized to create this page.', - code: 6008 + message: 'You are not authorized to create this page.' }), PageDeleteForbidden: CustomError('PageDeleteForbidden', { - message: 'You are not authorized to delete this page.', - code: 6010 + message: 'You are not authorized to delete this page.' }), PageGenericError: CustomError('PageGenericError', { - message: 'An unexpected error occured during a page operation.', - code: 6001 + message: 'An unexpected error occured during a page operation.' }), PageDuplicateCreate: CustomError('PageDuplicateCreate', { - message: 'Cannot create this page because an entry already exists at the same path.', - code: 6002 + message: 'Cannot create this page because an entry already exists at the same path.' }), PageEmptyContent: CustomError('PageEmptyContent', { - message: 'Page content cannot be empty.', - code: 6004 + message: 'Page content cannot be empty.' }), PageHistoryForbidden: CustomError('PageHistoryForbidden', { - message: 'You are not authorized to view the history of this page.', - code: 6012 + message: 'You are not authorized to view the history of this page.' }), PageIllegalPath: CustomError('PageIllegalPath', { - message: 'Page path cannot contains illegal characters.', - code: 6005 + message: 'Page path cannot contains illegal characters.' }), PageMoveForbidden: CustomError('PageMoveForbidden', { - message: 'You are not authorized to move this page.', - code: 6007 + message: 'You are not authorized to move this page.' }), PageNotFound: CustomError('PageNotFound', { - message: 'This page does not exist.', - code: 6003 + message: 'This page does not exist.' }), PagePathCollision: CustomError('PagePathCollision', { - message: 'Destination page path already exists.', - code: 6006 + message: 'Destination page path already exists.' }), PageRestoreForbidden: CustomError('PageRestoreForbidden', { - message: 'You are not authorized to restore this page version.', - code: 6011 + message: 'You are not authorized to restore this page version.' }), PageUpdateForbidden: CustomError('PageUpdateForbidden', { - message: 'You are not authorized to update this page.', - code: 6009 + message: 'You are not authorized to update this page.' }), PageViewForbidden: CustomError('PageViewForbidden', { - message: 'You are not authorized to view this page.', - code: 6013 + message: 'You are not authorized to view this page.' }), SearchActivationFailed: CustomError('SearchActivationFailed', { - message: 'Search Engine activation failed.', - code: 4002 + message: 'Search Engine activation failed.' }), SearchGenericError: CustomError('SearchGenericError', { - message: 'An unexpected error occured during search operation.', - code: 4001 + message: 'An unexpected error occured during search operation.' }), SystemGenericError: CustomError('SystemGenericError', { - message: 'An unexpected error occured.', - code: 7001 + message: 'An unexpected error occured.' }), SystemSSLDisabled: CustomError('SystemSSLDisabled', { - message: 'SSL is not enabled.', - code: 7002 + message: 'SSL is not enabled.' }), SystemSSLLEUnavailable: CustomError('SystemSSLLEUnavailable', { - message: 'Let\'s Encrypt is not initialized.', - code: 7004 + message: 'Let\'s Encrypt is not initialized.' }), SystemSSLRenewInvalidProvider: CustomError('SystemSSLRenewInvalidProvider', { - message: 'Current provider does not support SSL certificate renewal.', - code: 7003 + message: 'Current provider does not support SSL certificate renewal.' }), UserCreationFailed: CustomError('UserCreationFailed', { - message: 'An unexpected error occured during user creation.', - code: 1009 + message: 'An unexpected error occured during user creation.' }), UserDeleteForeignConstraint: CustomError('UserDeleteForeignConstraint', { - message: 'Cannot delete user because of content relational constraints.', - code: 1017 + message: 'Cannot delete user because of content relational constraints.' }), UserDeleteProtected: CustomError('UserDeleteProtected', { - message: 'Cannot delete a protected system account.', - code: 1018 + message: 'Cannot delete a protected system account.' }), UserNotFound: CustomError('UserNotFound', { - message: 'This user does not exist.', - code: 1016 + message: 'This user does not exist.' }) } diff --git a/server/helpers/graph.js b/server/helpers/graph.js index 0c6de75c..46eb1e27 100644 --- a/server/helpers/graph.js +++ b/server/helpers/graph.js @@ -16,6 +16,6 @@ module.exports = { slug: err.name, message: err.message || 'An unexpected error occured.' } - return (complete) ? { responseResult: error } : error + return (complete) ? { operation: error } : error } } diff --git a/server/models/authentication.js b/server/models/authentication.js index 1577ea3b..987fd065 100644 --- a/server/models/authentication.js +++ b/server/models/authentication.js @@ -21,6 +21,7 @@ module.exports = class Authentication extends Model { properties: { id: { type: 'string' }, module: { type: 'string' }, + isEnabled: { type: 'boolean' }, selfRegistration: {type: 'boolean'} } } @@ -34,8 +35,8 @@ module.exports = class Authentication extends Model { return WIKI.models.authentication.query().findOne({ key }) } - static async getStrategies() { - const strategies = await WIKI.models.authentication.query() + static async getStrategies({ enabledOnly = false } = {}) { + const strategies = await WIKI.models.authentication.query().where(enabledOnly ? { isEnabled: true } : {}) return strategies.map(str => ({ ...str, domainWhitelist: _.get(str.domainWhitelist, 'v', []), diff --git a/server/models/pages.js b/server/models/pages.js index ef76c810..897927b0 100644 --- a/server/models/pages.js +++ b/server/models/pages.js @@ -42,7 +42,6 @@ module.exports = class Page extends Model { title: {type: 'string'}, description: {type: 'string'}, publishState: {type: 'string'}, - privateNS: {type: 'string'}, publishStartDate: {type: 'string'}, publishEndDate: {type: 'string'}, content: {type: 'string'}, @@ -773,7 +772,7 @@ module.exports = class Page extends Model { * @returns {Promise} Promise with no value */ 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) { throw new WIKI.Error.PageNotFound() } @@ -1011,14 +1010,6 @@ module.exports = class Page extends Model { // '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() } catch (err) { WIKI.logger.warn(err) @@ -1074,8 +1065,7 @@ module.exports = class Page extends Model { return { ...page, path: opts.path, - localeCode: opts.locale, - isPrivate: opts.isPrivate + localeCode: opts.locale } } catch (err) { if (err.code === 'ENOENT') { diff --git a/server/models/userKeys.js b/server/models/userKeys.js index 12afa340..689b7072 100644 --- a/server/models/userKeys.js +++ b/server/models/userKeys.js @@ -16,7 +16,7 @@ module.exports = class UserKey extends Model { required: ['kind', 'token', 'validUntil'], properties: { - id: {type: 'integer'}, + id: {type: 'string'}, kind: {type: 'string'}, token: {type: 'string'}, createdAt: {type: 'string'}, @@ -44,11 +44,12 @@ module.exports = class UserKey extends Model { this.createdAt = DateTime.utc().toISO() } - static async generateToken ({ userId, kind }, context) { + static async generateToken ({ userId, kind, meta }, context) { const token = await nanoid() await WIKI.models.userKeys.query().insert({ kind, token, + meta, validUntil: DateTime.utc().plus({ days: 1 }).toISO(), userId }) @@ -64,7 +65,10 @@ module.exports = class UserKey extends Model { if (DateTime.utc() > DateTime.fromISO(res.validUntil)) { throw new WIKI.Error.AuthValidationTokenInvalid() } - return res.user + return { + ...res.meta, + user: res.user + } } else { throw new WIKI.Error.AuthValidationTokenInvalid() } diff --git a/server/models/users.js b/server/models/users.js index 490ea3ea..ff3ab88a 100644 --- a/server/models/users.js +++ b/server/models/users.js @@ -1,6 +1,5 @@ /* global WIKI */ -const bcrypt = require('bcryptjs-then') const _ = require('lodash') const tfa = require('node-2fa') const jwt = require('jsonwebtoken') @@ -22,15 +21,9 @@ module.exports = class User extends Model { required: ['email'], properties: { - id: {type: 'integer'}, + id: {type: 'string'}, email: {type: 'string', format: 'email'}, 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'}, isSystem: {type: 'boolean'}, isActive: {type: 'boolean'}, @@ -41,6 +34,10 @@ module.exports = class User extends Model { } } + static get jsonAttributes() { + return ['auth', 'meta', 'prefs'] + } + static get relationMappings() { return { groups: { @@ -55,22 +52,6 @@ module.exports = class User extends Model { 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: { relation: Model.BelongsToOneRelation, modelClass: require('./locales'), @@ -104,21 +85,6 @@ module.exports = class User extends Model { // 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() { let tfaInfo = tfa.generateSecret({ name: WIKI.config.title, @@ -150,7 +116,7 @@ module.exports = class User extends Model { return (result && _.has(result, 'delta') && result.delta === 0) } - getGlobalPermissions() { + getPermissions() { return _.uniq(_.flatten(_.map(this.groups, 'permissions'))) } @@ -297,7 +263,7 @@ module.exports = class User extends Model { 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 if (strInfo.useForm) { @@ -308,7 +274,7 @@ module.exports = class User extends Model { // Authenticate return new Promise((resolve, reject) => { - WIKI.auth.passport.authenticate(selStrategy.key, { + WIKI.auth.passport.authenticate(selStrategy.id, { session: !strInfo.useForm, scope: strInfo.scopes ? strInfo.scopes : null }, async (err, user, info) => { @@ -316,7 +282,7 @@ module.exports = class User extends Model { if (!user) { return reject(new WIKI.Error.AuthLoginFailed()) } try { - const resp = await WIKI.models.users.afterLoginChecks(user, context, { + const resp = await WIKI.models.users.afterLoginChecks(user, selStrategy.id, context, { skipTFA: !strInfo.useForm, skipChangePwd: !strInfo.useForm }) @@ -334,7 +300,7 @@ module.exports = class User extends Model { /** * 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 user.groups = await user.$relatedQuery('groups').select('groups.id', 'permissions', 'redirectOnLogin') let redirect = '/' @@ -347,9 +313,12 @@ module.exports = class User extends Model { } } + // Get auth strategy flags + const authStr = user.auth[strategyId] || {} + // Is 2FA required? if (!skipTFA) { - if (user.tfaIsActive && user.tfaSecret) { + if (authStr.tfaRequired && authStr.tfaSecret) { try { const tfaToken = await WIKI.models.userKeys.generateToken({ kind: 'tfa', @@ -364,7 +333,7 @@ module.exports = class User extends Model { WIKI.logger.warn(errc) 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 { const tfaQRImage = await user.generateTFA() const tfaToken = await WIKI.models.userKeys.generateToken({ @@ -385,7 +354,7 @@ module.exports = class User extends Model { } // Must Change Password? - if (!skipChangePwd && user.mustChangePwd) { + if (!skipChangePwd && authStr.mustChangePwd) { try { const pwdChangeToken = await WIKI.models.userKeys.generateToken({ kind: 'changePwd', @@ -440,18 +409,10 @@ module.exports = class User extends Model { token: jwt.sign({ id: user.id, 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() }, { - key: WIKI.config.certs.private, - passphrase: WIKI.config.sessionSecret + key: WIKI.config.auth.certs.private, + passphrase: WIKI.config.auth.secret }, { algorithm: 'RS256', expiresIn: WIKI.config.auth.tokenExpiration, @@ -877,7 +838,7 @@ module.exports = class User extends Model { WIKI.logger.error('CRITICAL ERROR: Guest user is missing!') process.exit(1) } - user.permissions = user.getGlobalPermissions() + user.permissions = user.getPermissions() return user } diff --git a/server/modules/authentication/local/authentication.js b/server/modules/authentication/local/authentication.js index e6fa75d3..98536cc4 100644 --- a/server/modules/authentication/local/authentication.js +++ b/server/modules/authentication/local/authentication.js @@ -1,4 +1,5 @@ /* global WIKI */ +const bcrypt = require('bcryptjs-then') // ------------------------------------ // Local Account @@ -8,27 +9,30 @@ const LocalStrategy = require('passport-local').Strategy module.exports = { init (passport, conf) { - passport.use('local', + passport.use(conf.key, new LocalStrategy({ usernameField: 'email', passwordField: 'password' }, async (uEmail, uPassword, done) => { try { const user = await WIKI.models.users.query().findOne({ - email: uEmail.toLowerCase(), - providerKey: 'local' + email: uEmail.toLowerCase() }) if (user) { - await user.verifyPassword(uPassword) - if (!user.isActive) { - done(new WIKI.Error.AuthAccountBanned(), null) + const authStrategyData = user.auth[conf.key] + if (!authStrategyData) { + 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) { - done(new WIKI.Error.AuthAccountNotVerified(), null) + throw new WIKI.Error.AuthAccountNotVerified() } else { done(null, user) } } else { - done(new WIKI.Error.AuthLoginFailed(), null) + throw new WIKI.Error.AuthLoginFailed() } } catch (err) { done(err, null) diff --git a/server/views/base.pug b/server/views/base.pug index b5d2dd8c..87a39f78 100644 --- a/server/views/base.pug +++ b/server/views/base.pug @@ -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='theme-color', 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 @@ -20,12 +20,12 @@ html(lang=siteConfig.lang) meta(property='og:site_name', content=config.title) //- Favicon - link(rel='apple-touch-icon', sizes='180x180', href='/_assets/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='32x32', href='/_assets/favicons/favicon-32x32.png') - link(rel='icon', type='image/png', sizes='16x16', href='/_assets/favicons/favicon-16x16.png') - link(rel='mask-icon', href='/_assets/favicons/safari-pinned-tab.svg', color='#1976d2') - link(rel='manifest', href='/_assets/manifest.json') + 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-legacy/favicons/android-chrome-192x192.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-legacy/favicons/favicon-16x16.png') + link(rel='mask-icon', href='/_assets-legacy/favicons/safari-pinned-tab.svg', color='#1976d2') + link(rel='manifest', href='/_assets-legacy/manifest.json') //- Site Properties script. diff --git a/server/views/error.pug b/server/views/error.pug index 27d45321..f6889d72 100644 --- a/server/views/error.pug +++ b/server/views/error.pug @@ -1,12 +1,77 @@ -extends base.pug - -block body - #root.is-fullscreen - .app-error - a(href='/') - img(src='/_assets/svg/logo-wikijs.svg') - strong Oops, something went wrong... - span= message - - if error.stack - pre: code #{error.stack} +doctype html +html + head + meta(charset="UTF-8") + link(rel="icon" href="/favicon.ico") + meta(name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width") + title Wiki.js + link(href="/_assets/fonts/roboto/roboto.css" rel="stylesheet") + style(lang='text/scss'). + body { + margin: 0; + 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} diff --git a/ux/package.json b/ux/package.json index b531e379..cf2c4c2d 100644 --- a/ux/package.json +++ b/ux/package.json @@ -32,7 +32,7 @@ "@codemirror/tooltip": "0.19.16", "@codemirror/view": "6.0.2", "@lezer/common": "1.0.0", - "@quasar/extras": "1.15.0", + "@quasar/extras": "1.15.1", "@tiptap/core": "2.0.0-beta.176", "@tiptap/extension-code-block": "2.0.0-beta.37", "@tiptap/extension-code-block-lowlight": "2.0.0-beta.68", @@ -63,31 +63,32 @@ "codemirror": "6.0.1", "filesize": "9.0.11", "filesize-parser": "1.5.0", - "graphql": "16.5.0", + "graphql": "16.6.0", "graphql-tag": "2.12.6", "js-cookie": "3.0.1", "jwt-decode": "3.1.2", "lodash-es": "4.17.21", "luxon": "3.0.1", - "pinia": "2.0.17", + "pinia": "2.0.20", "pug": "3.0.2", - "quasar": "2.7.5", + "quasar": "2.7.7", "tippy.js": "6.3.7", "uuid": "8.3.2", - "v-network-graph": "0.6.5", + "v-network-graph": "0.6.6", "vue": "3.2.37", "vue-codemirror": "6.0.2", - "vue-i18n": "9.1.10", + "vue-i18n": "9.2.2", "vue-router": "4.1.3", + "vue3-otp-input": "0.3.6", "vuedraggable": "4.1.0", "zxcvbn": "4.4.2" }, "devDependencies": { - "@intlify/vite-plugin-vue-i18n": "5.0.1", - "@quasar/app-vite": "1.0.5", - "@types/lodash": "4.14.182", + "@intlify/vite-plugin-vue-i18n": "6.0.1", + "@quasar/app-vite": "1.0.6", + "@types/lodash": "4.14.184", "browserlist": "latest", - "eslint": "8.20.0", + "eslint": "8.22.0", "eslint-config-standard": "17.0.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-n": "15.2.4", diff --git a/ux/public/_assets/logo-wikijs-full.svg b/ux/public/_assets/logo-wikijs-full.svg new file mode 100644 index 00000000..1e8b120f --- /dev/null +++ b/ux/public/_assets/logo-wikijs-full.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ux/quasar.config.js b/ux/quasar.config.js index c580e478..1266940c 100644 --- a/ux/quasar.config.js +++ b/ux/quasar.config.js @@ -112,7 +112,8 @@ module.exports = configure(function (/* ctx */) { delay: 500, spinner: 'QSpinnerGrid', spinnerSize: 32, - spinnerColor: 'white' + spinnerColor: 'white', + customClass: 'loading-darker' }, loadingBar: { color: 'primary', diff --git a/ux/src/components/AuthLoginPanel.vue b/ux/src/components/AuthLoginPanel.vue new file mode 100644 index 00000000..c95a9b0d --- /dev/null +++ b/ux/src/components/AuthLoginPanel.vue @@ -0,0 +1,788 @@ + + + + + diff --git a/ux/src/css/app.scss b/ux/src/css/app.scss index 927df2ff..9fc46628 100644 --- a/ux/src/css/app.scss +++ b/ux/src/css/app.scss @@ -117,7 +117,7 @@ body::-webkit-scrollbar-thumb { } &:hover .q-focus-helper { - opacity: .3; + opacity: .3 !important; } } @@ -210,6 +210,12 @@ body::-webkit-scrollbar-thumb { } } +.loading-darker { + .q-loading__backdrop { + opacity: .75; + } +} + // ------------------------------------------------------------------ // IMPORTS // ------------------------------------------------------------------ diff --git a/ux/src/i18n/locales/en.json b/ux/src/i18n/locales/en.json index 7bfce715..5fef7648 100644 --- a/ux/src/i18n/locales/en.json +++ b/ux/src/i18n/locales/en.json @@ -919,8 +919,9 @@ "auth.actions.register": "Register", "auth.changePwd.instructions": "You must choose a new password:", "auth.changePwd.loading": "Changing password...", - "auth.changePwd.newPasswordPlaceholder": "New Password", - "auth.changePwd.newPasswordVerifyPlaceholder": "Verify New Password", + "auth.changePwd.currentPassword": "Current Password", + "auth.changePwd.newPassword": "New Password", + "auth.changePwd.newPasswordVerify": "Verify New Password", "auth.changePwd.proceed": "Change Password", "auth.changePwd.subtitle": "Choose a new password", "auth.enterCredentials": "Enter your credentials", @@ -932,6 +933,20 @@ "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.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.emailUser": "Email / Username", "auth.fields.name": "Name", @@ -939,7 +954,7 @@ "auth.fields.username": "Username", "auth.fields.verifyPassword": "Verify Password", "auth.forgotPasswordCancel": "Cancel", - "auth.forgotPasswordLink": "Forgot your password?", + "auth.forgotPasswordLink": "Forgot Password", "auth.forgotPasswordLoading": "Requesting password reset...", "auth.forgotPasswordSubtitle": "Enter your email address to receive the instructions to reset your password:", "auth.forgotPasswordSuccess": "Check your emails for password reset instructions!", @@ -960,29 +975,17 @@ "auth.passwordNotMatch": "Both passwords do not match.", "auth.passwordTooShort": "Password is too short.", "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.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.registerTitle": "Create an account", "auth.registering": "Creating account...", - "auth.selectAuthProvider": "Select Authentication Provider", + "auth.selectAuthProvider": "Sign in with", "auth.sendResetPassword": "Reset Password", "auth.signingIn": "Signing In...", - "auth.switchToLogin.link": "Login instead", - "auth.switchToLogin.text": "Already have an account? {link}", - "auth.switchToRegister.link": "Create an account", - "auth.switchToRegister.text": "Don't have an account yet? {link}", - "auth.tfa.placeholder": "XXXXXX", + "auth.switchToLogin.link": "Back to Login", + "auth.switchToRegister.link": "Create an Account", "auth.tfa.subtitle": "Security code required:", - "auth.tfa.title": "Two Factor Authentication", "auth.tfa.verifyToken": "Verify", "auth.tfaFormTitle": "Enter the security code generated from your trusted device:", "auth.tfaSetupInstrFirst": "1) Scan the QR code below from your mobile 2FA application:", @@ -1147,11 +1150,11 @@ "common.pageSelector.pages": "Pages", "common.pageSelector.selectTitle": "Select a Page", "common.pageSelector.virtualFolders": "Virtual Folders", + "common.password.good": "Good", "common.password.average": "Average", "common.password.strong": "Strong", - "common.password.veryStrong": "Very Strong", - "common.password.veryWeak": "Very Weak", "common.password.weak": "Weak", + "common.password.poor": "Poor", "common.sidebar.browse": "Browse", "common.sidebar.currentDirectory": "Current Directory", "common.sidebar.mainMenu": "Main Menu", diff --git a/ux/src/pages/AdminLocale.vue b/ux/src/pages/AdminLocale.vue index e1e1afa8..28dad517 100644 --- a/ux/src/pages/AdminLocale.vue +++ b/ux/src/pages/AdminLocale.vue @@ -20,7 +20,7 @@ q-page.admin-locale icon='las la-question-circle' flat color='grey' - :href='siteStore.docsBase + `/admin/locale`' + :href='siteStore.docsBase + `/admin/localisation`' target='_blank' type='a' ) diff --git a/ux/src/pages/Login.vue b/ux/src/pages/Login.vue index 8c28805a..7fc6857c 100644 --- a/ux/src/pages/Login.vue +++ b/ux/src/pages/Login.vue @@ -5,79 +5,7 @@ img(src='/_assets/logo-wikijs.svg' :alt='siteStore.title') h2.auth-site-title {{ siteStore.title }} p.text-grey-7 Login to continue - template(v-if='state.strategies?.length > 1 || true') - 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-login-panel .auth-bg(aria-hidden="true") img(src='https://docs.requarks.io/_assets/img/splash/1.jpg' alt='') @@ -91,8 +19,9 @@ import { useI18n } from 'vue-i18n' import { useMeta, useQuasar } from 'quasar' import { onMounted, reactive, watch } from 'vue' +import AuthLoginPanel from 'src/components/AuthLoginPanel.vue' + import { useSiteStore } from 'src/stores/site' -import { useDataStore } from 'src/stores/data' // QUASAR @@ -101,7 +30,6 @@ const $q = useQuasar() // STORES const siteStore = useSiteStore() -const dataStore = useDataStore() // I18N @@ -116,27 +44,6 @@ useMeta({ // DATA 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' }) @@ -186,37 +93,6 @@ const state = reactive({ // 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 */ @@ -531,7 +407,7 @@ function handleLoginResponse (respObj) { } onMounted(() => { - fetchStrategies() + // fetchStrategies() }) diff --git a/ux/yarn.lock b/ux/yarn.lock index f8374f9c..f8b6c5d7 100644 --- a/ux/yarn.lock +++ b/ux/yarn.lock @@ -512,10 +512,10 @@ __metadata: languageName: node linkType: hard -"@dash14/svg-pan-zoom@npm:^3.6.8": - version: 3.6.8 - resolution: "@dash14/svg-pan-zoom@npm:3.6.8" - checksum: ae0e8f5cd033e8f35fded286abe2c0b20d82edc2bab9b8717bac5ae85ab61fc0e13802681c02c1abddfdf07445a78b29cea494d7e4fe89de7101f506ba6e67df +"@dash14/svg-pan-zoom@npm:^3.6.9": + version: 3.6.9 + resolution: "@dash14/svg-pan-zoom@npm:3.6.9" + checksum: ca63a82c2bf67b725a3b423b2c62600da6a5093ba4e1c309e21c522da66121311b6a50103246dc952e4c7091061c09620e6634015c0a7e1058035fa4c0431897 languageName: node linkType: hard @@ -552,14 +552,21 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.9.2": - version: 0.9.5 - resolution: "@humanwhocodes/config-array@npm:0.9.5" +"@humanwhocodes/config-array@npm:^0.10.4": + version: 0.10.4 + resolution: "@humanwhocodes/config-array@npm:0.10.4" dependencies: "@humanwhocodes/object-schema": ^1.2.1 debug: ^4.1.1 minimatch: ^3.0.4 - checksum: 8ba6281bc0590f6c6eadeefc14244b5a3e3f5903445aadd1a32099ed80e753037674026ce1b3c945ab93561bea5eb29e3c5bff67060e230c295595ba517a3492 + checksum: d480e5d57e6d787565b6cff78e27c3d1b380692d4ffb0ada7d7f5957a56c9032f034da05a3e443065dbd0671ebf4d859036ced34e96b325bbc1badbae3c05300 + languageName: node + linkType: hard + +"@humanwhocodes/gitignore-to-minimatch@npm:^1.0.2": + version: 1.0.2 + resolution: "@humanwhocodes/gitignore-to-minimatch@npm:1.0.2" + checksum: aba5c40c9e3770ed73a558b0bfb53323842abfc2ce58c91d7e8b1073995598e6374456d38767be24ab6176915f0a8d8b23eaae5c85e2b488c0dccca6d795e2ad languageName: node linkType: hard @@ -588,37 +595,34 @@ __metadata: languageName: node linkType: hard -"@intlify/core-base@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/core-base@npm:9.1.10" +"@intlify/core-base@npm:9.2.2": + version: 9.2.2 + resolution: "@intlify/core-base@npm:9.2.2" dependencies: - "@intlify/devtools-if": 9.1.10 - "@intlify/message-compiler": 9.1.10 - "@intlify/message-resolver": 9.1.10 - "@intlify/runtime": 9.1.10 - "@intlify/shared": 9.1.10 - "@intlify/vue-devtools": 9.1.10 - checksum: 5e4407753be014c4c428be546ce3487ad92f6d14b4ab9fb2324a3e67a9bf2d9a3c907300fd3eab076c0c8eeb836e9b7d26c81bf972d38f10f04aec3702e76570 + "@intlify/devtools-if": 9.2.2 + "@intlify/message-compiler": 9.2.2 + "@intlify/shared": 9.2.2 + "@intlify/vue-devtools": 9.2.2 + checksum: 51f9c803d3d25e85561efef26ec1314d87c67e2ac15c4ac1fba946ea54a0b77b2357f1c158f94df5cfa90b200ab2ce78284421da7fdd360bc96d2231e8d342b9 languageName: node linkType: hard -"@intlify/devtools-if@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/devtools-if@npm:9.1.10" +"@intlify/devtools-if@npm:9.2.2": + version: 9.2.2 + resolution: "@intlify/devtools-if@npm:9.2.2" dependencies: - "@intlify/shared": 9.1.10 - checksum: f09cb81d016e30e8cecbc18ae345529ed541c3ab1844e634ab2cad900d72e860a8d0459e0257833f36ba212899f5e4db75f0e2ad9eacb751d7b62fb1204ba470 + "@intlify/shared": 9.2.2 + checksum: ac4217b1753c42845a4c91d64d706a154014e802647244b3d38ccea7fe7e7935f2b305a162cecdab6d5b7b028b1af0e7af1b61832b89a2c4fdabff27c375252c languageName: node linkType: hard -"@intlify/message-compiler@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/message-compiler@npm:9.1.10" +"@intlify/message-compiler@npm:9.2.2": + version: 9.2.2 + resolution: "@intlify/message-compiler@npm:9.2.2" dependencies: - "@intlify/message-resolver": 9.1.10 - "@intlify/shared": 9.1.10 + "@intlify/shared": 9.2.2 source-map: 0.6.1 - checksum: bd62f9212ca4ab0134976208b7c8bde40e1f1f662468e05aefd798f63330c6f341e816d5ce2f04d37d08f55d40278f08a0c67315c23e99c92078e1a02db177d4 + checksum: 309384c0361e52f2c784759c85c3bf54b2f53ea50bf62a09684196c34ea6cfcb46da1a53e6de42b5802616c726f7ab8166ef2c284c9f7155d83c2ca6f5a224ef languageName: node linkType: hard @@ -632,31 +636,6 @@ __metadata: languageName: node linkType: hard -"@intlify/message-resolver@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/message-resolver@npm:9.1.10" - checksum: dcd9c66dcedb18f54fd7a086801fb3883ff6e898bf70429ecd898d487a883a64a4d5338e8ff306eb710c951c5166936e9fecd40e8e67855195ac560d32043a80 - languageName: node - linkType: hard - -"@intlify/runtime@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/runtime@npm:9.1.10" - dependencies: - "@intlify/message-compiler": 9.1.10 - "@intlify/message-resolver": 9.1.10 - "@intlify/shared": 9.1.10 - checksum: 166989a2e432fa4ee65d856fe791ef68e87d59ac8bb17c044c91c857ae3c19721d96da1450fc6a3bbdffd250cc56694a5f7d901401cc0b71714ca932d0da56f1 - languageName: node - linkType: hard - -"@intlify/shared@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/shared@npm:9.1.10" - checksum: b4305cb755fdd031834d312712ac2d27d9e6e94318a6dae36aa0740f1e30bbd3c6fd3164eec7ddd62ae1b0f691402c25609cf3ffc6f2e2b7664023f69af74255 - languageName: node - linkType: hard - "@intlify/shared@npm:9.2.0-beta.40, @intlify/shared@npm:next": version: 9.2.0-beta.40 resolution: "@intlify/shared@npm:9.2.0-beta.40" @@ -664,9 +643,16 @@ __metadata: languageName: node linkType: hard -"@intlify/vite-plugin-vue-i18n@npm:5.0.1": - version: 5.0.1 - resolution: "@intlify/vite-plugin-vue-i18n@npm:5.0.1" +"@intlify/shared@npm:9.2.2": + version: 9.2.2 + resolution: "@intlify/shared@npm:9.2.2" + checksum: 3aad616c66c6ec479f78750e32a6f2d2f20fb7a32b4b634c2c81c58de52ca4f9c5ebfcb347411f5a719e08bd80cbcb86f13a66ad7a1a3faae45877d7ba789250 + languageName: node + linkType: hard + +"@intlify/vite-plugin-vue-i18n@npm:6.0.1": + version: 6.0.1 + resolution: "@intlify/vite-plugin-vue-i18n@npm:6.0.1" dependencies: "@intlify/bundle-utils": next "@intlify/shared": next @@ -685,18 +671,17 @@ __metadata: optional: true vue-i18n: optional: true - checksum: ba7561ea1be2cba4cbd738064bf1b2944b7487364b83e8e8af705d8b05e39467ada16008560c7564a532c2d59cf95be83401fe8f3e6e0b3e01ecad11f42d6fa0 + checksum: 4482ca3ff3003d3eb44ed4d045656caf34f8946be3d98ef599016faffc15dbbd088e0515bfa874b10daa667615de01ff25ea94429e06632a65892f97a0c5a8c5 languageName: node linkType: hard -"@intlify/vue-devtools@npm:9.1.10": - version: 9.1.10 - resolution: "@intlify/vue-devtools@npm:9.1.10" +"@intlify/vue-devtools@npm:9.2.2": + version: 9.2.2 + resolution: "@intlify/vue-devtools@npm:9.2.2" dependencies: - "@intlify/message-resolver": 9.1.10 - "@intlify/runtime": 9.1.10 - "@intlify/shared": 9.1.10 - checksum: 41af5d9a578439b05b0fd6a89321de6549119c37f92ed026988590685a5581cbe5c409853c7cfacb0dab7b5d22a9020af5ce95d353a663a4b53d1905f7a805ae + "@intlify/core-base": 9.2.2 + "@intlify/shared": 9.2.2 + checksum: 12b7743337184bea915cb15e8a2e338ba02ca6d90127af21213b096fa1d83171b88f7650c05d45a1b13e13561daec841ae5ff497629450df47975c447a2b17ab languageName: node linkType: hard @@ -877,12 +862,12 @@ __metadata: languageName: node linkType: hard -"@quasar/app-vite@npm:1.0.5": - version: 1.0.5 - resolution: "@quasar/app-vite@npm:1.0.5" +"@quasar/app-vite@npm:1.0.6": + version: 1.0.6 + resolution: "@quasar/app-vite@npm:1.0.6" dependencies: "@quasar/fastclick": 1.1.5 - "@quasar/vite-plugin": ^1.0.9 + "@quasar/vite-plugin": ^1.1.1 "@rollup/pluginutils": ^4.1.2 "@types/chrome": ^0.0.191 "@types/compression": ^1.7.2 @@ -896,7 +881,7 @@ __metadata: cross-spawn: ^7.0.3 dot-prop: 6.0.1 elementtree: 0.1.7 - esbuild: 0.14.47 + esbuild: 0.14.51 express: ^4.17.3 fast-glob: 3.2.11 fs-extra: ^10.0.1 @@ -915,7 +900,7 @@ __metadata: semver: ^7.3.5 serialize-javascript: ^6.0.0 table: ^6.8.0 - vite: 2.9.13 + vite: ^2.9.13 webpack-merge: ^5.8.0 peerDependencies: electron-builder: ^22.0.0 @@ -942,14 +927,14 @@ __metadata: optional: true bin: quasar: bin/quasar - checksum: 15b5afdadb0668aa9bc7a89c5aed3d92e31c16296fab52a09f15959f60745d2d380d40414f4a8a9f843eec3bfa994bf9cd5d530db0a130054210bb441e5ab3d7 + checksum: 4c1df0f3a78209a4eca5030151d9b3eeedf856e98993956c79d617e4bef9fb9ac066e67551806c61811e88586c36cbc5d599047043935c3e1b935c319d6208be languageName: node linkType: hard -"@quasar/extras@npm:1.15.0": - version: 1.15.0 - resolution: "@quasar/extras@npm:1.15.0" - checksum: 2fb3274f441ef4db6b0925a9d72bc80845793ac3ca07b7929a89978922236e8c09667bf2f633a8103ba197d0535a757c66fc4d5337664138b8c6f35418ae9ea2 +"@quasar/extras@npm:1.15.1": + version: 1.15.1 + resolution: "@quasar/extras@npm:1.15.1" + checksum: 70f96c8128cfa998220f700057067c51ad9d487bcada1c56c10663321793daa9ee9ea6a5f821df19b765bbdcef581a1d731320793b422fe9f5472a24f57c5dc9 languageName: node linkType: hard @@ -960,14 +945,14 @@ __metadata: languageName: node linkType: hard -"@quasar/vite-plugin@npm:^1.0.9": - version: 1.0.9 - resolution: "@quasar/vite-plugin@npm:1.0.9" +"@quasar/vite-plugin@npm:^1.1.1": + version: 1.1.1 + resolution: "@quasar/vite-plugin@npm:1.1.1" peerDependencies: quasar: ^2.0.0 - vite: ^2.0.0 + vite: ^2.0.0 || ^3.0.0 vue: ^3.0.0 - checksum: a6750c6ecb5ec62efeda354887985b54b5a1078334153b9f3200421eb56de147152131fc54085a20b427c2b645d2e4724a7c6d1b3bc0077e38012a054157eea7 + checksum: 69b5c752f1684a3ead2a5ee9f9aa81fd393405cc9bae159f5f7a9694776f3922ff4f6306e59c34c1e0ff601650e1021aa3d6c707013090f92786af9f9291ce1c languageName: node linkType: hard @@ -1542,10 +1527,10 @@ __metadata: languageName: node linkType: hard -"@types/lodash@npm:4.14.182": - version: 4.14.182 - resolution: "@types/lodash@npm:4.14.182" - checksum: 7dd137aa9dbabd632408bd37009d984655164fa1ecc3f2b6eb94afe35bf0a5852cbab6183148d883e9c73a958b7fec9a9bcf7c8e45d41195add6a18c34958209 +"@types/lodash@npm:4.14.184": + version: 4.14.184 + resolution: "@types/lodash@npm:4.14.184" + checksum: 6d9a4d67f7f9d0ec3fd21174f3dd3d00629dc1227eb469450eace53adbc1f7e2330699c28d0fe093e5f0fef0f0e763098be1f779268857213224af082b62be21 languageName: node linkType: hard @@ -1764,7 +1749,7 @@ __metadata: languageName: node linkType: hard -"@vue/devtools-api@npm:^6.0.0-beta.7, @vue/devtools-api@npm:^6.1.4": +"@vue/devtools-api@npm:^6.1.4": version: 6.1.4 resolution: "@vue/devtools-api@npm:6.1.4" checksum: 027bb138b03ec7147dd15e5d0ef28d5b72c822530396cc8a86bc6fdb049dc6850314b9e897e497064e3ed47fad229a18141f56b8b8ca3d41092a576dc5b6538d @@ -1911,6 +1896,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.8.0": + version: 8.8.0 + resolution: "acorn@npm:8.8.0" + bin: + acorn: bin/acorn + checksum: 7270ca82b242eafe5687a11fea6e088c960af712683756abf0791b68855ea9cace3057bd5e998ffcef50c944810c1e0ca1da526d02b32110e13c722aa959afdc + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -2098,6 +2092,13 @@ __metadata: languageName: node linkType: hard +"array-union@npm:^2.1.0": + version: 2.1.0 + resolution: "array-union@npm:2.1.0" + checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d + languageName: node + linkType: hard + "array.prototype.flat@npm:^1.2.5": version: 1.2.5 resolution: "array.prototype.flat@npm:1.2.5" @@ -2833,6 +2834,15 @@ __metadata: languageName: node linkType: hard +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: ^4.0.0 + checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 + languageName: node + linkType: hard + "doctrine@npm:^2.1.0": version: 2.1.0 resolution: "doctrine@npm:2.1.0" @@ -2982,9 +2992,9 @@ __metadata: languageName: node linkType: hard -"esbuild-android-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-android-64@npm:0.14.47" +"esbuild-android-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-android-64@npm:0.14.51" conditions: os=android & cpu=x64 languageName: node linkType: hard @@ -2996,9 +3006,9 @@ __metadata: languageName: node linkType: hard -"esbuild-android-arm64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-android-arm64@npm:0.14.47" +"esbuild-android-arm64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-android-arm64@npm:0.14.51" conditions: os=android & cpu=arm64 languageName: node linkType: hard @@ -3010,9 +3020,9 @@ __metadata: languageName: node linkType: hard -"esbuild-darwin-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-darwin-64@npm:0.14.47" +"esbuild-darwin-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-darwin-64@npm:0.14.51" conditions: os=darwin & cpu=x64 languageName: node linkType: hard @@ -3024,9 +3034,9 @@ __metadata: languageName: node linkType: hard -"esbuild-darwin-arm64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-darwin-arm64@npm:0.14.47" +"esbuild-darwin-arm64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-darwin-arm64@npm:0.14.51" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard @@ -3038,9 +3048,9 @@ __metadata: languageName: node linkType: hard -"esbuild-freebsd-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-freebsd-64@npm:0.14.47" +"esbuild-freebsd-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-freebsd-64@npm:0.14.51" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard @@ -3052,9 +3062,9 @@ __metadata: languageName: node linkType: hard -"esbuild-freebsd-arm64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-freebsd-arm64@npm:0.14.47" +"esbuild-freebsd-arm64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-freebsd-arm64@npm:0.14.51" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard @@ -3066,9 +3076,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-32@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-32@npm:0.14.47" +"esbuild-linux-32@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-32@npm:0.14.51" conditions: os=linux & cpu=ia32 languageName: node linkType: hard @@ -3080,9 +3090,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-64@npm:0.14.47" +"esbuild-linux-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-64@npm:0.14.51" conditions: os=linux & cpu=x64 languageName: node linkType: hard @@ -3094,9 +3104,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-arm64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-arm64@npm:0.14.47" +"esbuild-linux-arm64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-arm64@npm:0.14.51" conditions: os=linux & cpu=arm64 languageName: node linkType: hard @@ -3108,9 +3118,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-arm@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-arm@npm:0.14.47" +"esbuild-linux-arm@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-arm@npm:0.14.51" conditions: os=linux & cpu=arm languageName: node linkType: hard @@ -3122,9 +3132,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-mips64le@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-mips64le@npm:0.14.47" +"esbuild-linux-mips64le@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-mips64le@npm:0.14.51" conditions: os=linux & cpu=mips64el languageName: node linkType: hard @@ -3136,9 +3146,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-ppc64le@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-ppc64le@npm:0.14.47" +"esbuild-linux-ppc64le@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-ppc64le@npm:0.14.51" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard @@ -3150,9 +3160,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-riscv64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-riscv64@npm:0.14.47" +"esbuild-linux-riscv64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-riscv64@npm:0.14.51" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard @@ -3164,9 +3174,9 @@ __metadata: languageName: node linkType: hard -"esbuild-linux-s390x@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-linux-s390x@npm:0.14.47" +"esbuild-linux-s390x@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-linux-s390x@npm:0.14.51" conditions: os=linux & cpu=s390x languageName: node linkType: hard @@ -3178,9 +3188,9 @@ __metadata: languageName: node linkType: hard -"esbuild-netbsd-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-netbsd-64@npm:0.14.47" +"esbuild-netbsd-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-netbsd-64@npm:0.14.51" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard @@ -3192,9 +3202,9 @@ __metadata: languageName: node linkType: hard -"esbuild-openbsd-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-openbsd-64@npm:0.14.47" +"esbuild-openbsd-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-openbsd-64@npm:0.14.51" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard @@ -3206,9 +3216,9 @@ __metadata: languageName: node linkType: hard -"esbuild-sunos-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-sunos-64@npm:0.14.47" +"esbuild-sunos-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-sunos-64@npm:0.14.51" conditions: os=sunos & cpu=x64 languageName: node linkType: hard @@ -3220,9 +3230,9 @@ __metadata: languageName: node linkType: hard -"esbuild-windows-32@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-windows-32@npm:0.14.47" +"esbuild-windows-32@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-windows-32@npm:0.14.51" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard @@ -3234,9 +3244,9 @@ __metadata: languageName: node linkType: hard -"esbuild-windows-64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-windows-64@npm:0.14.47" +"esbuild-windows-64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-windows-64@npm:0.14.51" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -3248,37 +3258,37 @@ __metadata: languageName: node linkType: hard -"esbuild-windows-arm64@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild-windows-arm64@npm:0.14.47" +"esbuild-windows-arm64@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild-windows-arm64@npm:0.14.51" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"esbuild@npm:0.14.47": - version: 0.14.47 - resolution: "esbuild@npm:0.14.47" - dependencies: - esbuild-android-64: 0.14.47 - esbuild-android-arm64: 0.14.47 - esbuild-darwin-64: 0.14.47 - esbuild-darwin-arm64: 0.14.47 - esbuild-freebsd-64: 0.14.47 - esbuild-freebsd-arm64: 0.14.47 - esbuild-linux-32: 0.14.47 - esbuild-linux-64: 0.14.47 - esbuild-linux-arm: 0.14.47 - esbuild-linux-arm64: 0.14.47 - esbuild-linux-mips64le: 0.14.47 - esbuild-linux-ppc64le: 0.14.47 - esbuild-linux-riscv64: 0.14.47 - esbuild-linux-s390x: 0.14.47 - esbuild-netbsd-64: 0.14.47 - esbuild-openbsd-64: 0.14.47 - esbuild-sunos-64: 0.14.47 - esbuild-windows-32: 0.14.47 - esbuild-windows-64: 0.14.47 - esbuild-windows-arm64: 0.14.47 +"esbuild@npm:0.14.51": + version: 0.14.51 + resolution: "esbuild@npm:0.14.51" + dependencies: + esbuild-android-64: 0.14.51 + esbuild-android-arm64: 0.14.51 + esbuild-darwin-64: 0.14.51 + esbuild-darwin-arm64: 0.14.51 + esbuild-freebsd-64: 0.14.51 + esbuild-freebsd-arm64: 0.14.51 + esbuild-linux-32: 0.14.51 + esbuild-linux-64: 0.14.51 + esbuild-linux-arm: 0.14.51 + esbuild-linux-arm64: 0.14.51 + esbuild-linux-mips64le: 0.14.51 + esbuild-linux-ppc64le: 0.14.51 + esbuild-linux-riscv64: 0.14.51 + esbuild-linux-s390x: 0.14.51 + esbuild-netbsd-64: 0.14.51 + esbuild-openbsd-64: 0.14.51 + esbuild-sunos-64: 0.14.51 + esbuild-windows-32: 0.14.51 + esbuild-windows-64: 0.14.51 + esbuild-windows-arm64: 0.14.51 dependenciesMeta: esbuild-android-64: optional: true @@ -3322,7 +3332,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 77a8bff8c3fe52dc9d2823448843b0f53c9a9f3701e3637a54e396270c9ca04cc46a4b08ef86cbaa8d202854e02c790f61683bfa75ebff540b1e24414f536e91 + checksum: 0fa8a52dd1dc7b231f7b02448aae5ee71ff2fe26ee67f6c97945a6dd128806be6eb2c73be7b49c7b25f831d646edd3da245faf31ede136f4aa0934abd7206e4b languageName: node linkType: hard @@ -3587,12 +3597,13 @@ __metadata: languageName: node linkType: hard -"eslint@npm:8.20.0": - version: 8.20.0 - resolution: "eslint@npm:8.20.0" +"eslint@npm:8.22.0": + version: 8.22.0 + resolution: "eslint@npm:8.22.0" dependencies: "@eslint/eslintrc": ^1.3.0 - "@humanwhocodes/config-array": ^0.9.2 + "@humanwhocodes/config-array": ^0.10.4 + "@humanwhocodes/gitignore-to-minimatch": ^1.0.2 ajv: ^6.10.0 chalk: ^4.0.0 cross-spawn: ^7.0.2 @@ -3602,14 +3613,17 @@ __metadata: eslint-scope: ^7.1.1 eslint-utils: ^3.0.0 eslint-visitor-keys: ^3.3.0 - espree: ^9.3.2 + espree: ^9.3.3 esquery: ^1.4.0 esutils: ^2.0.2 fast-deep-equal: ^3.1.3 file-entry-cache: ^6.0.1 + find-up: ^5.0.0 functional-red-black-tree: ^1.0.1 glob-parent: ^6.0.1 globals: ^13.15.0 + globby: ^11.1.0 + grapheme-splitter: ^1.0.4 ignore: ^5.2.0 import-fresh: ^3.0.0 imurmurhash: ^0.1.4 @@ -3628,7 +3642,7 @@ __metadata: v8-compile-cache: ^2.0.3 bin: eslint: bin/eslint.js - checksum: a31adf390d71d916925586bc8467b48f620e93dd0416bc1e897d99265af88b48d4eba3985b5ff4653ae5cc46311a360d373574002277e159bb38a4363abf9228 + checksum: 2d84a7a2207138cdb250759b047fdb05a57fede7f87b7a039d9370edba7f26e23a873a208becfd4b2c9e4b5499029f3fc3b9318da3290e693d25c39084119c80 languageName: node linkType: hard @@ -3654,6 +3668,17 @@ __metadata: languageName: node linkType: hard +"espree@npm:^9.3.3": + version: 9.3.3 + resolution: "espree@npm:9.3.3" + dependencies: + acorn: ^8.8.0 + acorn-jsx: ^5.3.2 + eslint-visitor-keys: ^3.3.0 + checksum: 33e8a36fc15d082e68672e322e22a53856b564d60aad8f291a667bfc21b2c900c42412d37dd3c7a0f18b9d0d8f8858dabe8776dbd4b4c2f72c5cf4d6afeabf65 + languageName: node + linkType: hard + "esquery@npm:^1.4.0": version: 1.4.0 resolution: "esquery@npm:1.4.0" @@ -3763,7 +3788,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:3.2.11, fast-glob@npm:^3.2.5": +"fast-glob@npm:3.2.11, fast-glob@npm:^3.2.5, fast-glob@npm:^3.2.9": version: 3.2.11 resolution: "fast-glob@npm:3.2.11" dependencies: @@ -3873,6 +3898,16 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: ^6.0.0 + path-exists: ^4.0.0 + checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.0.4 resolution: "flat-cache@npm:3.0.4" @@ -4077,6 +4112,20 @@ __metadata: languageName: node linkType: hard +"globby@npm:^11.1.0": + version: 11.1.0 + resolution: "globby@npm:11.1.0" + dependencies: + array-union: ^2.1.0 + dir-glob: ^3.0.1 + fast-glob: ^3.2.9 + ignore: ^5.2.0 + merge2: ^1.4.1 + slash: ^3.0.0 + checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + languageName: node + linkType: hard + "good-listener@npm:^1.2.2": version: 1.2.2 resolution: "good-listener@npm:1.2.2" @@ -4093,6 +4142,13 @@ __metadata: languageName: node linkType: hard +"grapheme-splitter@npm:^1.0.4": + version: 1.0.4 + resolution: "grapheme-splitter@npm:1.0.4" + checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 + languageName: node + linkType: hard + "graphql-tag@npm:2.12.6, graphql-tag@npm:^2.12.6": version: 2.12.6 resolution: "graphql-tag@npm:2.12.6" @@ -4104,10 +4160,10 @@ __metadata: languageName: node linkType: hard -"graphql@npm:16.5.0": - version: 16.5.0 - resolution: "graphql@npm:16.5.0" - checksum: a82a926d085818934d04fdf303a269af170e79de943678bd2726370a96194f9454ade9d6d76c2de69afbd7b9f0b4f8061619baecbbddbe82125860e675ac219e +"graphql@npm:16.6.0": + version: 16.6.0 + resolution: "graphql@npm:16.6.0" + checksum: bf1d9e3c1938ce3c1a81e909bd3ead1ae4707c577f91cff1ca2eca474bfbc7873d5d7b942e1e9777ff5a8304421dba57a4b76d7a29eb19de8711cb70e3c2415e languageName: node linkType: hard @@ -4787,6 +4843,15 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: ^5.0.0 + checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a + languageName: node + linkType: hard + "lodash-es@npm:4.17.21": version: 4.17.21 resolution: "lodash-es@npm:4.17.21" @@ -4965,7 +5030,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0": +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 @@ -5425,6 +5490,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^3.0.2": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: ^0.1.0 + checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 + languageName: node + linkType: hard + "p-locate@npm:^2.0.0": version: 2.0.0 resolution: "p-locate@npm:2.0.0" @@ -5434,6 +5508,15 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: ^3.0.2 + checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -5482,6 +5565,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 + languageName: node + linkType: hard + "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -5510,6 +5600,13 @@ __metadata: languageName: node linkType: hard +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 + languageName: node + linkType: hard + "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" @@ -5524,9 +5621,9 @@ __metadata: languageName: node linkType: hard -"pinia@npm:2.0.17": - version: 2.0.17 - resolution: "pinia@npm:2.0.17" +"pinia@npm:2.0.20": + version: 2.0.20 + resolution: "pinia@npm:2.0.20" dependencies: "@vue/devtools-api": ^6.2.1 vue-demi: "*" @@ -5539,7 +5636,7 @@ __metadata: optional: true typescript: optional: true - checksum: d308c6358570242b6c8126d990d756a224d1a77dfa375db5069da7f1c350372bf4e07feb4efce0d924dfc1b39f39d533234cdecf3594c4a2876de30477f6f978 + checksum: 09fe9a6983195a29b856c9680e9e009fa98e253f5cf2dfe6db5f1b855b0897ea8fa3e31ae60d10cd1b59400d81acd5ae03ba7f69e19cfd1b3af683f8cfb78151 languageName: node linkType: hard @@ -5901,10 +5998,10 @@ __metadata: languageName: node linkType: hard -"quasar@npm:2.7.5": - version: 2.7.5 - resolution: "quasar@npm:2.7.5" - checksum: 0ed975f2051ffbb7dd4180a6a9c3b2da7b4696df1896407ea4ec71da3168b9fcde3d43f96323caf7f4fea8cd7d89f03b6426e628c4b718b2b238d330a5f5054d +"quasar@npm:2.7.7": + version: 2.7.7 + resolution: "quasar@npm:2.7.7" + checksum: cabbd30d47e476e0c39c75a4ea7f8b03ca8857a085d4f466ee31d8f64788acb5b145d94f7fab167fa875ac0794c78f7df4a9d8da0d01726da6e8592f3a1eed6f languageName: node linkType: hard @@ -6127,6 +6224,20 @@ __metadata: languageName: node linkType: hard +"rollup@npm:>=2.59.0 <2.78.0": + version: 2.77.3 + resolution: "rollup@npm:2.77.3" + dependencies: + fsevents: ~2.3.2 + dependenciesMeta: + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: b179c68249584565ddb5664a241e8e48c293b2207718d885b08ee25797d98857a383f06b544bb89819407da5a71557f4713309a278f61c4778bb32b1d3321a1c + languageName: node + linkType: hard + "rollup@npm:^2.59.0": version: 2.70.1 resolution: "rollup@npm:2.70.1" @@ -6349,6 +6460,13 @@ __metadata: languageName: node linkType: hard +"slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c + languageName: node + linkType: hard + "slice-ansi@npm:^4.0.0": version: 4.0.0 resolution: "slice-ansi@npm:4.0.0" @@ -6836,10 +6954,10 @@ __metadata: "@codemirror/state": 6.0.1 "@codemirror/tooltip": 0.19.16 "@codemirror/view": 6.0.2 - "@intlify/vite-plugin-vue-i18n": 5.0.1 + "@intlify/vite-plugin-vue-i18n": 6.0.1 "@lezer/common": 1.0.0 - "@quasar/app-vite": 1.0.5 - "@quasar/extras": 1.15.0 + "@quasar/app-vite": 1.0.6 + "@quasar/extras": 1.15.1 "@tiptap/core": 2.0.0-beta.176 "@tiptap/extension-code-block": 2.0.0-beta.37 "@tiptap/extension-code-block-lowlight": 2.0.0-beta.68 @@ -6864,13 +6982,13 @@ __metadata: "@tiptap/extension-typography": 2.0.0-beta.20 "@tiptap/starter-kit": 2.0.0-beta.185 "@tiptap/vue-3": 2.0.0-beta.91 - "@types/lodash": 4.14.182 + "@types/lodash": 4.14.184 apollo-upload-client: 17.0.0 browser-fs-access: 0.31.0 browserlist: latest clipboard: 2.0.11 codemirror: 6.0.1 - eslint: 8.20.0 + eslint: 8.22.0 eslint-config-standard: 17.0.0 eslint-plugin-import: 2.26.0 eslint-plugin-n: 15.2.4 @@ -6878,37 +6996,38 @@ __metadata: eslint-plugin-vue: 9.3.0 filesize: 9.0.11 filesize-parser: 1.5.0 - graphql: 16.5.0 + graphql: 16.6.0 graphql-tag: 2.12.6 js-cookie: 3.0.1 jwt-decode: 3.1.2 lodash-es: 4.17.21 luxon: 3.0.1 - pinia: 2.0.17 + pinia: 2.0.20 pug: 3.0.2 - quasar: 2.7.5 + quasar: 2.7.7 tippy.js: 6.3.7 uuid: 8.3.2 - v-network-graph: 0.6.5 + v-network-graph: 0.6.6 vue: 3.2.37 vue-codemirror: 6.0.2 - vue-i18n: 9.1.10 + vue-i18n: 9.2.2 vue-router: 4.1.3 + vue3-otp-input: 0.3.6 vuedraggable: 4.1.0 zxcvbn: 4.4.2 languageName: unknown linkType: soft -"v-network-graph@npm:0.6.5": - version: 0.6.5 - resolution: "v-network-graph@npm:0.6.5" +"v-network-graph@npm:0.6.6": + version: 0.6.6 + resolution: "v-network-graph@npm:0.6.6" dependencies: - "@dash14/svg-pan-zoom": ^3.6.8 + "@dash14/svg-pan-zoom": ^3.6.9 mitt: ^3.0.0 peerDependencies: d3-force: ^3.0.0 vue: ^3.2.31 - checksum: a6312014cd424cc6747dafd8b05eef5bfd3f1a1a01ca67363ca1d17553d1c493b4a80f5d3d0bbd9c45b709ff78618f596f3a12673c9518086b303b39c6e7b5dd + checksum: a1a99b4160c50138398e3243d9c6e0f11803b7d4062dc5eb9120c204099c8e40c24f9e1e0ba24d550fe300088f69b55e9c8323197c32dffb7d85f56e63298c0e languageName: node linkType: hard @@ -6955,15 +7074,15 @@ __metadata: languageName: node linkType: hard -"vite@npm:2.9.13": - version: 2.9.13 - resolution: "vite@npm:2.9.13" +"vite@npm:^2.9.13": + version: 2.9.15 + resolution: "vite@npm:2.9.15" dependencies: esbuild: ^0.14.27 fsevents: ~2.3.2 postcss: ^8.4.13 resolve: ^1.22.0 - rollup: ^2.59.0 + rollup: ">=2.59.0 <2.78.0" peerDependencies: less: "*" sass: "*" @@ -6980,7 +7099,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: a5e501b920a448c352e9b3836019dea56c523535f8e8540160708c2e164d84da6655ae39abbba1e2888092f5c6cd03dd06279852422359b51be601914645f49f + checksum: 5edf8afc132a598f82a1339aa503514a0e86f6264babe94531b9000d801f157c9a32ae022542404678acca43ee260ade04c4763c4b7b8d381a6b50511b4a1447 languageName: node linkType: hard @@ -7040,17 +7159,17 @@ __metadata: languageName: node linkType: hard -"vue-i18n@npm:9.1.10": - version: 9.1.10 - resolution: "vue-i18n@npm:9.1.10" +"vue-i18n@npm:9.2.2": + version: 9.2.2 + resolution: "vue-i18n@npm:9.2.2" dependencies: - "@intlify/core-base": 9.1.10 - "@intlify/shared": 9.1.10 - "@intlify/vue-devtools": 9.1.10 - "@vue/devtools-api": ^6.0.0-beta.7 + "@intlify/core-base": 9.2.2 + "@intlify/shared": 9.2.2 + "@intlify/vue-devtools": 9.2.2 + "@vue/devtools-api": ^6.2.1 peerDependencies: vue: ^3.0.0 - checksum: ae58af1d45aa39334066606228d7daae0376631c8462bdb22d588021745211ff1098e5a46c46720ea9cd33632fcd8d7601f32effd2fd603e75955919c7aa8024 + checksum: 513b82d701674816d01ce085cbf4e21813bcfb65636dbef0f8df4ce94add272d49df8eca122863349dff0eb7046ab0379852386602dd752b48d16b2b2178c735 languageName: node linkType: hard @@ -7065,6 +7184,15 @@ __metadata: languageName: node linkType: hard +"vue3-otp-input@npm:0.3.6": + version: 0.3.6 + resolution: "vue3-otp-input@npm:0.3.6" + peerDependencies: + vue: ^3.0.* + checksum: 70ba2dcc6aa73d2ca1748a80cbf5f5d190141385e6253bf4c0e05897d8fcbe963f5a2df29e0c59b2a0826777bcf462eb7b264b85fa1252b0760561452a8def5d + languageName: node + linkType: hard + "vue@npm:3.2.37": version: 3.2.37 resolution: "vue@npm:3.2.37" @@ -7253,6 +7381,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 + languageName: node + linkType: hard + "zen-observable-ts@npm:^1.2.5": version: 1.2.5 resolution: "zen-observable-ts@npm:1.2.5"