- added api UserController.ts for 2FA
Some checks failed
CI Pipeline / japa-tests (push) Failing after 56s
Some checks failed
CI Pipeline / japa-tests (push) Failing after 56s
- added PersonalTotpSettings.vue vor enablin/disabling 2FA - changed User.ts: added attributes: state, twoFactorSecret and twoFactorRecoveryCodes - added resources/js/utils/toast.ts for notifications - modified start/routes/api.ts - npm updates
This commit is contained in:
parent
18635f77b3
commit
ebc62d9117
82
app/Controllers/Http/Api/UserController.ts
Normal file
82
app/Controllers/Http/Api/UserController.ts
Normal file
|
@ -0,0 +1,82 @@
|
|||
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||
// import TotpSecret from 'App/Models/TotpSecret';
|
||||
import User from 'App/Models/User';
|
||||
import TwoFactorAuthProvider from 'App/Services/TwoFactorAuthProvider';
|
||||
import { StatusCodes } from 'http-status-codes';
|
||||
import { InvalidArgumentException } from 'node-exceptions';
|
||||
import { TotpState } from 'Contracts/enums';
|
||||
|
||||
|
||||
// Here we are generating secret and recovery codes for the user that’s enabling 2FA and storing them to our database.
|
||||
export default class UserController {
|
||||
public async enable({ auth, response, request }: HttpContextContract) {
|
||||
const user = (await User.find(auth.user?.id)) as User;
|
||||
// await user.load('totp_secret');
|
||||
// if (!user.totp_secret) {
|
||||
// let totpSecret = new TotpSecret();
|
||||
// user.related('totp_secret').save(totpSecret);
|
||||
// await user.load('totp_secret');
|
||||
// }
|
||||
|
||||
if (!user) {
|
||||
throw new Error('user not available');
|
||||
}
|
||||
const state: number = request.input('state');
|
||||
|
||||
try {
|
||||
switch (state) {
|
||||
case TotpState.STATE_DISABLED:
|
||||
// user.twoFactorSecret = null;
|
||||
// user.twoFactorRecoveryCodes = null;
|
||||
user.twoFactorSecret = "";
|
||||
user.twoFactorRecoveryCodes = [""];
|
||||
await user.save();
|
||||
|
||||
user.state = TotpState.STATE_DISABLED;
|
||||
await user.save();
|
||||
|
||||
return response.status(StatusCodes.OK).json({
|
||||
state: TotpState.STATE_DISABLED,
|
||||
});
|
||||
case TotpState.STATE_CREATED:
|
||||
user.twoFactorSecret = TwoFactorAuthProvider.generateSecret(user);
|
||||
user.state = TotpState.STATE_CREATED;
|
||||
await user.save();
|
||||
|
||||
let qrcode = await TwoFactorAuthProvider.generateQrCode(user);
|
||||
// throw new InvalidArgumentException('code is missing');
|
||||
return response.status(StatusCodes.OK).json({
|
||||
state: user.state,
|
||||
secret: user.twoFactorSecret,
|
||||
url: qrcode.url,
|
||||
svg: qrcode.svg,
|
||||
});
|
||||
case TotpState.STATE_ENABLED:
|
||||
let code: string = request.input('code');
|
||||
if (!code) {
|
||||
throw new InvalidArgumentException('code is missing');
|
||||
}
|
||||
const success = await TwoFactorAuthProvider.enable(user, code)
|
||||
|
||||
return response.status(StatusCodes.OK).json({
|
||||
state: success ? TotpState.STATE_ENABLED : TotpState.STATE_CREATED,
|
||||
});
|
||||
default:
|
||||
throw new InvalidArgumentException('Invalid TOTP state');
|
||||
}
|
||||
} catch (error) {
|
||||
return response.status(StatusCodes.INTERNAL_SERVER_ERROR).json({
|
||||
message: 'Invalid TOTP state',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// public async fetchRecoveryCodes({ auth, view }) {
|
||||
// const user = auth?.user;
|
||||
|
||||
// return view.render('pages/settings', {
|
||||
// twoFactorEnabled: user.isTwoFactorEnabled,
|
||||
// recoveryCodes: user.twoFactorRecoveryCodes,
|
||||
// });
|
||||
// }
|
||||
}
|
|
@ -22,7 +22,7 @@ export default class UserController {
|
|||
return inertia.render('Auth/AccountInfo', {
|
||||
user: user,
|
||||
twoFactorEnabled: user.isTwoFactorEnabled,
|
||||
code: await TwoFactorAuthProvider.generateQrCode(user),
|
||||
// code: await TwoFactorAuthProvider.generateQrCode(user),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import type { ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm';
|
|||
import Field from 'App/Library/Field';
|
||||
import BaseModel from 'App/Models/BaseModel';
|
||||
import { DateTime } from 'luxon';
|
||||
import { schema, CustomMessages, rules } from '@ioc:Adonis/Core/Validator';
|
||||
import { schema, rules } from '@ioc:Adonis/Core/Validator';
|
||||
|
||||
export default class DatasetsController {
|
||||
public async index({ auth, request, inertia }: HttpContextContract) {
|
||||
|
|
63
app/Models/TotpSecret.ts
Normal file
63
app/Models/TotpSecret.ts
Normal file
|
@ -0,0 +1,63 @@
|
|||
import { column, BaseModel, SnakeCaseNamingStrategy, belongsTo, BelongsTo } from '@ioc:Adonis/Lucid/Orm';
|
||||
import User from './User';
|
||||
import { DateTime } from 'luxon';
|
||||
import dayjs from 'dayjs';
|
||||
import Encryption from '@ioc:Adonis/Core/Encryption';
|
||||
|
||||
export default class TotpSecret extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static table = 'totp_secrets';
|
||||
// public static fillable: string[] = ['value', 'label', 'type', 'relation'];
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public user_id: number;
|
||||
|
||||
// @column()
|
||||
// public twoFactorSecret: string;
|
||||
@column({
|
||||
serializeAs: null,
|
||||
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '{}') : null),
|
||||
prepare: (value: string) => Encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorSecret?: string | null;
|
||||
|
||||
// serializeAs: null removes the model properties from the serialized output.
|
||||
@column({
|
||||
serializeAs: null,
|
||||
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '[]') : []),
|
||||
prepare: (value: string[]) => Encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorRecoveryCodes?: string[] | null;
|
||||
|
||||
@column({})
|
||||
public state: number;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
// return value ? moment(value).format('MMMM Do YYYY, HH:mm:ss') : value;
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
})
|
||||
public created_at: DateTime;
|
||||
|
||||
@column.dateTime({
|
||||
serialize: (value: Date | null) => {
|
||||
return value ? dayjs(value).format('MMMM D YYYY HH:mm a') : value;
|
||||
},
|
||||
autoCreate: true,
|
||||
autoUpdate: true,
|
||||
})
|
||||
public updated_at: DateTime;
|
||||
|
||||
@belongsTo(() => User, {
|
||||
foreignKey: 'user_id',
|
||||
})
|
||||
public user: BelongsTo<typeof User>;
|
||||
|
||||
}
|
|
@ -7,6 +7,8 @@ import Config from '@ioc:Adonis/Core/Config';
|
|||
import Dataset from './Dataset';
|
||||
import BaseModel from './BaseModel';
|
||||
import Encryption from '@ioc:Adonis/Core/Encryption';
|
||||
import { TotpState } from 'Contracts/enums';
|
||||
// import TotpSecret from './TotpSecret';
|
||||
|
||||
// export default interface IUser {
|
||||
// id: number;
|
||||
|
@ -51,7 +53,7 @@ export default class User extends BaseModel {
|
|||
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '{}') : null),
|
||||
prepare: (value: string) => Encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorSecret?: string;
|
||||
public twoFactorSecret?: string | null;
|
||||
|
||||
// serializeAs: null removes the model properties from the serialized output.
|
||||
@column({
|
||||
|
@ -59,7 +61,15 @@ export default class User extends BaseModel {
|
|||
consume: (value: string) => (value ? JSON.parse(Encryption.decrypt(value) ?? '[]') : []),
|
||||
prepare: (value: string[]) => Encryption.encrypt(JSON.stringify(value)),
|
||||
})
|
||||
public twoFactorRecoveryCodes?: string[];
|
||||
public twoFactorRecoveryCodes?: string[] | null;
|
||||
|
||||
@column({})
|
||||
public state: number;
|
||||
|
||||
// @hasOne(() => TotpSecret, {
|
||||
// foreignKey: 'user_id',
|
||||
// })
|
||||
// public totp_secret: HasOne<typeof TotpSecret>;
|
||||
|
||||
@beforeSave()
|
||||
public static async hashPassword(user) {
|
||||
|
@ -68,8 +78,9 @@ export default class User extends BaseModel {
|
|||
}
|
||||
}
|
||||
|
||||
public get isTwoFactorEnabled() {
|
||||
return Boolean(this?.twoFactorSecret);
|
||||
public get isTwoFactorEnabled(): boolean {
|
||||
return Boolean(this?.twoFactorSecret && this.state == TotpState.STATE_ENABLED);
|
||||
// return Boolean(this.totp_secret?.twoFactorSecret);
|
||||
}
|
||||
|
||||
@manyToMany(() => Role, {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import Config from '@ioc:Adonis/Core/Config';
|
||||
import User from 'App/Models/User';
|
||||
import { generateSecret } from 'node-2fa/dist/index';
|
||||
import { generateSecret, verifyToken } from 'node-2fa/dist/index';
|
||||
// import cryptoRandomString from 'crypto-random-string';
|
||||
import QRCode from 'qrcode';
|
||||
import crypto from 'crypto';
|
||||
import { TotpState } from 'Contracts/enums';
|
||||
|
||||
// npm install node-2fa --save
|
||||
// npm install crypto-random-string --save
|
||||
|
@ -73,16 +74,44 @@ class TwoFactorAuthProvider {
|
|||
}
|
||||
}
|
||||
|
||||
public async generateQrCode(user: User) : Promise<{svg: string; url: string; }> {
|
||||
// public async generateQrCode(user: User) : Promise<{svg: string; url: string; secret: string; }> {
|
||||
// const issuer = encodeURIComponent(this.issuer); // 'TethysCloud'
|
||||
// // const userName = encodeURIComponent(user.email); // 'rrqx9472%40tethys.at'
|
||||
// const label = `${this.issuer}:${user.email}`;
|
||||
|
||||
// const algorithm = encodeURIComponent("SHA256");
|
||||
// const query = `?secret=${user.twoFactorSecret}&issuer=${issuer}&algorithm=${algorithm}&digits=6`; // '?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
|
||||
// const url = `otpauth://totp/${label}${query}`; // 'otpauth://totp/rrqx9472%40tethys.at?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
|
||||
// const svg = await QRCode.toDataURL(url);
|
||||
// const secret = user.twoFactorSecret as string;
|
||||
// return { svg, url, secret };
|
||||
// }
|
||||
|
||||
public async generateQrCode(user: User, twoFactorSecret?: string): Promise<{ svg: string; url: string; secret: string }> {
|
||||
const issuer = encodeURIComponent(this.issuer); // 'TethysCloud'
|
||||
// const userName = encodeURIComponent(user.email); // 'rrqx9472%40tethys.at'
|
||||
const label = `${this.issuer}:${user.email}`;
|
||||
|
||||
const algorithm = encodeURIComponent("SHA256");
|
||||
const query = `?secret=${user.twoFactorSecret}&issuer=${issuer}&algorithm=${algorithm}&digits=6`; // '?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
|
||||
// const algorithm = encodeURIComponent('SHA256');
|
||||
const secret = twoFactorSecret ? twoFactorSecret : (user.twoFactorSecret as string);
|
||||
const query = `?secret=${secret}&issuer=${issuer}&digits=6`; // '?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
|
||||
|
||||
const url = `otpauth://totp/${label}${query}`; // 'otpauth://totp/rrqx9472%40tethys.at?secret=FEYCLOSO627CB7SMLX6QQ7BP75L7SJ54&issuer=TethysCloud'
|
||||
const svg = await QRCode.toDataURL(url);
|
||||
return { svg, url };
|
||||
|
||||
return { svg, url, secret };
|
||||
}
|
||||
|
||||
public async enable(user: User, token: string): Promise<boolean> {
|
||||
const isValid = verifyToken(user.twoFactorSecret as string, token, 1);
|
||||
if (!isValid) {
|
||||
return false;
|
||||
}
|
||||
user.state = TotpState.STATE_ENABLED;
|
||||
if (await user.save()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,3 +111,9 @@ export enum IdentifierTypes {
|
|||
url = 'url',
|
||||
urn = 'urn',
|
||||
}
|
||||
|
||||
export enum TotpState {
|
||||
STATE_DISABLED = 0,
|
||||
STATE_CREATED = 1,
|
||||
STATE_ENABLED = 2,
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ export default class Accounts extends BaseSchema {
|
|||
table.timestamp('updated_at');
|
||||
table.text("two_factor_secret").nullable();
|
||||
table.text("two_factor_recovery_codes").nullable();
|
||||
table.smallint('state').nullable();
|
||||
table.bigint('last_counter').nullable();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -39,8 +41,47 @@ export default class Accounts extends BaseSchema {
|
|||
// CONSTRAINT accounts_email_unique UNIQUE (email)
|
||||
// two_factor_secret text COLLATE pg_catalog."default",
|
||||
// two_factor_recovery_codes text COLLATE pg_catalog."default",
|
||||
// state smallint,
|
||||
// last_counter bigint,
|
||||
// )
|
||||
|
||||
// ALTER TABLE gba.accounts
|
||||
// ADD COLUMN two_factor_secret text COLLATE pg_catalog."default",
|
||||
// ADD COLUMN two_factor_recovery_codes text COLLATE pg_catalog."default";
|
||||
// ADD COLUMN two_factor_recovery_codes text COLLATE pg_catalog."default",
|
||||
// ADD COLUMN state smallint,
|
||||
// ADD COLUMN last_counter bigint;
|
||||
|
||||
|
||||
|
||||
|
||||
// CREATE TABLE IF NOT EXISTS gba.totp_secrets
|
||||
// (
|
||||
// id integer NOT NULL,
|
||||
// user_id integer NOT NULL,
|
||||
// state smallint,
|
||||
// last_counter bigint,
|
||||
// two_factor_secret text COLLATE pg_catalog."default",
|
||||
// two_factor_recovery_codes text COLLATE pg_catalog."default",
|
||||
// created_at timestamp(0) without time zone,
|
||||
// updated_at timestamp(0) without time zone,
|
||||
// CONSTRAINT totp_secrets_pkey PRIMARY KEY (id),
|
||||
// CONSTRAINT totp_secrets_user_id_foreign FOREIGN KEY (user_id)
|
||||
// REFERENCES gba.accounts (id) MATCH SIMPLE
|
||||
// ON UPDATE CASCADE
|
||||
// ON DELETE CASCADE
|
||||
// );
|
||||
|
||||
// CREATE SEQUENCE IF NOT EXISTS gba.totp_secrets_id_seq
|
||||
// INCREMENT 1
|
||||
// START 1
|
||||
// MINVALUE 1
|
||||
// MAXVALUE 2147483647
|
||||
// CACHE 1
|
||||
// OWNED BY gba.totp_secrets.id;
|
||||
|
||||
// ALTER SEQUENCE gba.totp_secrets_id_seq
|
||||
// OWNER TO tethys_admin;
|
||||
|
||||
// GRANT ALL ON SEQUENCE gba.totp_secrets_id_seq TO tethys_admin;
|
||||
|
||||
// ALTER TABLE gba.totp_secrets ALTER COLUMN id SET DEFAULT nextval('gba.totp_secrets_id_seq');
|
||||
|
|
437
package-lock.json
generated
437
package-lock.json
generated
|
@ -32,6 +32,7 @@
|
|||
"leaflet": "^1.9.3",
|
||||
"luxon": "^3.2.1",
|
||||
"node-2fa": "^2.0.3",
|
||||
"node-exceptions": "^4.0.1",
|
||||
"notiwind": "^2.0.0",
|
||||
"pg": "^8.9.0",
|
||||
"proxy-addr": "^2.0.7",
|
||||
|
@ -40,6 +41,7 @@
|
|||
"reflect-metadata": "^0.2.1",
|
||||
"saxon-js": "^2.5.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"toastify-js": "^1.12.0",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xmlbuilder2": "^3.1.1"
|
||||
},
|
||||
|
@ -972,9 +974,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz",
|
||||
"integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==",
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz",
|
||||
"integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-compilation-targets": "^7.22.6",
|
||||
|
@ -1197,9 +1199,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.23.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz",
|
||||
"integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==",
|
||||
"version": "7.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.8.tgz",
|
||||
"integrity": "sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.15",
|
||||
|
@ -1723,16 +1725,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-classes": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz",
|
||||
"integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==",
|
||||
"version": "7.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz",
|
||||
"integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-annotate-as-pure": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.22.15",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-environment-visitor": "^7.22.20",
|
||||
"@babel/helper-function-name": "^7.23.0",
|
||||
"@babel/helper-optimise-call-expression": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-replace-supers": "^7.22.20",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
|
@ -2430,9 +2431,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env": {
|
||||
"version": "7.23.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.7.tgz",
|
||||
"integrity": "sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==",
|
||||
"version": "7.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.8.tgz",
|
||||
"integrity": "sha512-lFlpmkApLkEP6woIKprO6DO60RImpatTQKtz4sUcDjVcK8M8mQ4sZsuxaTMNOZf0sqAq/ReYW1ZBHnOQwKpLWA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
|
@ -2468,7 +2469,7 @@
|
|||
"@babel/plugin-transform-block-scoping": "^7.23.4",
|
||||
"@babel/plugin-transform-class-properties": "^7.23.3",
|
||||
"@babel/plugin-transform-class-static-block": "^7.23.4",
|
||||
"@babel/plugin-transform-classes": "^7.23.5",
|
||||
"@babel/plugin-transform-classes": "^7.23.8",
|
||||
"@babel/plugin-transform-computed-properties": "^7.23.3",
|
||||
"@babel/plugin-transform-destructuring": "^7.23.3",
|
||||
"@babel/plugin-transform-dotall-regex": "^7.23.3",
|
||||
|
@ -2572,9 +2573,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.23.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.7.tgz",
|
||||
"integrity": "sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==",
|
||||
"version": "7.23.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz",
|
||||
"integrity": "sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
|
@ -2827,13 +2828,13 @@
|
|||
"integrity": "sha512-qF0aH5UiZvCmneX5orJbVRoc2VTyLTV3X/7laMp03Qt28L+B9tFlZODOGUL64wDWc69YVdi1LeJB0cIgd51lvw=="
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.13",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
|
||||
"integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==",
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^2.0.1",
|
||||
"debug": "^4.1.1",
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.0.5"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2854,9 +2855,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/object-schema": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz",
|
||||
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz",
|
||||
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@inertiajs/core": {
|
||||
|
@ -2871,9 +2872,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@inertiajs/core/node_modules/axios": {
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz",
|
||||
"integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==",
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -3303,9 +3304,9 @@
|
|||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.20",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
|
||||
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz",
|
||||
"integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
|
@ -3460,9 +3461,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@opensearch-project/opensearch": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.4.0.tgz",
|
||||
"integrity": "sha512-r0ZNIlDxAua1ZecOBJ8qOXshf2ZQhNKmfly7o0aNuACf0pDa6Et/8mWMZuaFOu7xlNEeRNB7IjDQUYFy2SPElw==",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.5.0.tgz",
|
||||
"integrity": "sha512-RY5J6Jt/Jbbr2F9XByGY9LJr0VNmXJjgVvvntpKE4NtZa/r9ak3o8YtGK1iey1yHgzMzze25598qq7ZYFk42DA==",
|
||||
"dependencies": {
|
||||
"aws4": "^1.11.0",
|
||||
"debug": "^4.3.1",
|
||||
|
@ -3494,9 +3495,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@pkgr/core": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.0.tgz",
|
||||
"integrity": "sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==",
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
|
||||
"integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
|
||||
|
@ -4039,9 +4040,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.56.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.1.tgz",
|
||||
"integrity": "sha512-18PLWRzhy9glDQp3+wOgfLYRWlhgX0azxgJ63rdpoUHyrC9z0f5CkFburjQx4uD7ZCruw85ZtMt6K+L+R8fLJQ==",
|
||||
"version": "8.56.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz",
|
||||
"integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
|
@ -4205,9 +4206,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.8.tgz",
|
||||
"integrity": "sha512-jYvz8UMLDgy3a5SkGJne8H7VA7zPV2Lwohjx0V8V31+SqAjNmurWMkk9cQhfvlcnXWudBpK9xPM1n4rljOcHYQ=="
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.1.tgz",
|
||||
"integrity": "sha512-m1KQEZZCITtheRhMVq5jDvAl0HwFhunLs7x6tpFFvUTJpKfmewS/Ymg+YA97/s8w1I1nC4pJyi0aAnn+vf3yew=="
|
||||
},
|
||||
"node_modules/@types/md5": {
|
||||
"version": "2.3.5",
|
||||
|
@ -4227,9 +4228,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.10.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz",
|
||||
"integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==",
|
||||
"version": "20.11.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz",
|
||||
"integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
}
|
||||
|
@ -4381,9 +4382,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/validator": {
|
||||
"version": "13.11.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz",
|
||||
"integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q=="
|
||||
"version": "13.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz",
|
||||
"integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ=="
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.5.10",
|
||||
|
@ -4676,49 +4677,49 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/compiler-core": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.4.tgz",
|
||||
"integrity": "sha512-U5AdCN+6skzh2bSJrkMj2KZsVkUpgK8/XlxjSRYQZhNPcvt9/kmgIMpFEiTyK+Dz5E1J+8o8//BEIX+bakgVSw==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.15.tgz",
|
||||
"integrity": "sha512-XcJQVOaxTKCnth1vCxEChteGuwG6wqnUHxAm1DO3gCz0+uXKaJNx8/digSz4dLALCy8n2lKq24jSUs8segoqIw==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@vue/shared": "3.4.4",
|
||||
"@vue/shared": "3.4.15",
|
||||
"entities": "^4.5.0",
|
||||
"estree-walker": "^2.0.2",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-dom": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.4.tgz",
|
||||
"integrity": "sha512-iSwkdDULCN+Vr8z6uwdlL044GJ/nUmECxP9vu7MzEs4Qma0FwDLYvnvRcyO0ZITuu3Os4FptGUDnhi1kOLSaGw==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.15.tgz",
|
||||
"integrity": "sha512-wox0aasVV74zoXyblarOM3AZQz/Z+OunYcIHe1OsGclCHt8RsRm04DObjefaI82u6XDzv+qGWZ24tIsRAIi5MQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-core": "3.4.4",
|
||||
"@vue/shared": "3.4.4"
|
||||
"@vue/compiler-core": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-sfc": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.4.tgz",
|
||||
"integrity": "sha512-OTFcU6vUxUNHBcarzkp4g6d25nvcmDvFDzPRvSrIsByFFPRYN+y3b+j9HxYwt6nlWvGyFCe0roeJdJlfYxbCBg==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.15.tgz",
|
||||
"integrity": "sha512-LCn5M6QpkpFsh3GQvs2mJUOAlBQcCco8D60Bcqmf3O3w5a+KWS5GvYbrrJBkgvL1BDnTp+e8q0lXCLgHhKguBA==",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.23.6",
|
||||
"@vue/compiler-core": "3.4.4",
|
||||
"@vue/compiler-dom": "3.4.4",
|
||||
"@vue/compiler-ssr": "3.4.4",
|
||||
"@vue/shared": "3.4.4",
|
||||
"@vue/compiler-core": "3.4.15",
|
||||
"@vue/compiler-dom": "3.4.15",
|
||||
"@vue/compiler-ssr": "3.4.15",
|
||||
"@vue/shared": "3.4.15",
|
||||
"estree-walker": "^2.0.2",
|
||||
"magic-string": "^0.30.5",
|
||||
"postcss": "^8.4.32",
|
||||
"postcss": "^8.4.33",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/compiler-ssr": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.4.tgz",
|
||||
"integrity": "sha512-1DU9DflSSQlx/M61GEBN+NbT/anUki2ooDo9IXfTckCeKA/2IKNhY8KbG3x6zkd3KGrxzteC7de6QL88vEb41Q==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.15.tgz",
|
||||
"integrity": "sha512-1jdeQyiGznr8gjFDadVmOJqZiLNSsMa5ZgqavkPZ8O2wjHv0tVuAEsw5hTdUoUW4232vpBbL/wJhzVW/JwY1Uw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.4",
|
||||
"@vue/shared": "3.4.4"
|
||||
"@vue/compiler-dom": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/devtools-api": {
|
||||
|
@ -4728,53 +4729,48 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@vue/reactivity": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.4.tgz",
|
||||
"integrity": "sha512-DFsuJBf6sfhd5SYzJmcBTUG9+EKqjF31Gsk1NJtnpJm9liSZ806XwGJUeNBVQIanax7ODV7Lmk/k17BgxXNuTg==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.15.tgz",
|
||||
"integrity": "sha512-55yJh2bsff20K5O84MxSvXKPHHt17I2EomHznvFiJCAZpJTNW8IuLj1xZWMLELRhBK3kkFV/1ErZGHJfah7i7w==",
|
||||
"dependencies": {
|
||||
"@vue/shared": "3.4.4"
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-core": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.4.tgz",
|
||||
"integrity": "sha512-zWWwNQAj5JdxrmOA1xegJm+c4VtyIbDEKgQjSb4va5v7gGTCh0ZjvLI+htGFdVXaO9bs2J3C81p5p+6jrPK8Bw==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.15.tgz",
|
||||
"integrity": "sha512-6E3by5m6v1AkW0McCeAyhHTw+3y17YCOKG0U0HDKDscV4Hs0kgNT5G+GCHak16jKgcCDHpI9xe5NKb8sdLCLdw==",
|
||||
"dependencies": {
|
||||
"@vue/reactivity": "3.4.4",
|
||||
"@vue/shared": "3.4.4"
|
||||
"@vue/reactivity": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.4.tgz",
|
||||
"integrity": "sha512-Nlh2ap1J/eJQ6R0g+AIRyGNwpTJQACN0dk8I8FRLH8Ev11DSvfcPOpn4+Kbg5xAMcuq0cHB8zFYxVrOgETrrvg==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.15.tgz",
|
||||
"integrity": "sha512-EVW8D6vfFVq3V/yDKNPBFkZKGMFSvZrUQmx196o/v2tHKdwWdiZjYUBS+0Ez3+ohRyF8Njwy/6FH5gYJ75liUw==",
|
||||
"dependencies": {
|
||||
"@vue/runtime-core": "3.4.4",
|
||||
"@vue/shared": "3.4.4",
|
||||
"@vue/runtime-core": "3.4.15",
|
||||
"@vue/shared": "3.4.15",
|
||||
"csstype": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/runtime-dom/node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/@vue/server-renderer": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.4.tgz",
|
||||
"integrity": "sha512-+AjoiKcC41k7SMJBYkDO9xs79/Of8DiThS9mH5l2MK+EY0to3psI0k+sElvVqQvsoZTjHMEuMz0AEgvm2T+CwA==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.15.tgz",
|
||||
"integrity": "sha512-3HYzaidu9cHjrT+qGUuDhFYvF/j643bHC6uUN9BgM11DVy+pM6ATsG6uPBLnkwOgs7BpJABReLmpL3ZPAsUaqw==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-ssr": "3.4.4",
|
||||
"@vue/shared": "3.4.4"
|
||||
"@vue/compiler-ssr": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "3.4.4"
|
||||
"vue": "3.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@vue/shared": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.4.tgz",
|
||||
"integrity": "sha512-abSgiVRhfjfl3JALR/cSuBl74hGJ3SePgf1mKzodf1eMWLwHZbfEGxT2cNJSsNiw44jEgrO7bNkhchaWA7RwNw=="
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.15.tgz",
|
||||
"integrity": "sha512-KzfPTxVaWfB+eGcGdbSf4CWdaXcGDqckoeXUh7SB3fZdEtzPCK2Vq9B/lRRL3yutax/LWITz+SwvgyOxz5V75g=="
|
||||
},
|
||||
"node_modules/@vue/tsconfig": {
|
||||
"version": "0.4.0",
|
||||
|
@ -5116,9 +5112,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/acorn-walk": {
|
||||
"version": "8.3.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz",
|
||||
"integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==",
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
|
||||
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
|
@ -5651,9 +5647,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.16",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
|
||||
"integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==",
|
||||
"version": "10.4.17",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz",
|
||||
"integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -5670,9 +5666,9 @@
|
|||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"browserslist": "^4.21.10",
|
||||
"caniuse-lite": "^1.0.30001538",
|
||||
"fraction.js": "^4.3.6",
|
||||
"browserslist": "^4.22.2",
|
||||
"caniuse-lite": "^1.0.30001578",
|
||||
"fraction.js": "^4.3.7",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
|
@ -5912,13 +5908,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.4.7",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz",
|
||||
"integrity": "sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==",
|
||||
"version": "0.4.8",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz",
|
||||
"integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.22.6",
|
||||
"@babel/helper-define-polyfill-provider": "^0.4.4",
|
||||
"@babel/helper-define-polyfill-provider": "^0.5.0",
|
||||
"semver": "^6.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
@ -5947,13 +5943,29 @@
|
|||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-regenerator": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz",
|
||||
"integrity": "sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==",
|
||||
"node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz",
|
||||
"integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-define-polyfill-provider": "^0.4.4"
|
||||
"@babel/helper-compilation-targets": "^7.22.6",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"debug": "^4.1.1",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"resolve": "^1.14.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-regenerator": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz",
|
||||
"integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-define-polyfill-provider": "^0.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
|
||||
|
@ -6131,9 +6143,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/bonjour-service": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.0.tgz",
|
||||
"integrity": "sha512-xdzMA6JGckxyJzZByjEWRcfKmDxXaGXZWVftah3FkCqdlePNS9DjHSUN5zkP4oEfz/t0EXXlro88EIhzwMB4zA==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
|
||||
"integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
|
@ -6372,9 +6384,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001574",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001574.tgz",
|
||||
"integrity": "sha512-BtYEK4r/iHt/txm81KBudCUcTy7t+s9emrIaHqjYurQ10x71zJ5VQ9x1dYPcz/b+pKSp4y/v1xSI67A+LzpNyg==",
|
||||
"version": "1.0.30001579",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
|
||||
"integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -6415,9 +6427,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/chai": {
|
||||
"version": "4.3.10",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz",
|
||||
"integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==",
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz",
|
||||
"integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"assertion-error": "^1.1.0",
|
||||
|
@ -7179,19 +7191,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/css-loader": {
|
||||
"version": "6.8.1",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.8.1.tgz",
|
||||
"integrity": "sha512-xDAXtEVGlD0gJ07iclwWVkLoZOpEvAWaSyf6W18S2pOC//K8+qUDIx8IIT3D+HjnmkJPQeesOPv5aiUaJsCM2g==",
|
||||
"version": "6.9.1",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.9.1.tgz",
|
||||
"integrity": "sha512-OzABOh0+26JKFdMzlK6PY1u5Zx8+Ck7CVRlcGNZoY9qwJjdfu2VWFuprTIpPW+Av5TZTVViYWcFQaEEQURLknQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"icss-utils": "^5.1.0",
|
||||
"postcss": "^8.4.21",
|
||||
"postcss": "^8.4.33",
|
||||
"postcss-modules-extract-imports": "^3.0.0",
|
||||
"postcss-modules-local-by-default": "^4.0.3",
|
||||
"postcss-modules-scope": "^3.0.0",
|
||||
"postcss-modules-local-by-default": "^4.0.4",
|
||||
"postcss-modules-scope": "^3.1.1",
|
||||
"postcss-modules-values": "^4.0.0",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"semver": "^7.3.8"
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
|
@ -7297,6 +7309,12 @@
|
|||
"csstype": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/css-render/node_modules/csstype": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
|
||||
"integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
|
||||
|
@ -7459,10 +7477,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz",
|
||||
"integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==",
|
||||
"dev": true
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/cuid": {
|
||||
"version": "2.1.8",
|
||||
|
@ -8111,9 +8128,9 @@
|
|||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.620",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.620.tgz",
|
||||
"integrity": "sha512-a2fcSHOHrqBJsPNXtf6ZCEZpXrFCcbK1FBxfX3txoqWzNgtEDG1f3M59M98iwxhRW4iMKESnSjbJ310/rkrp0g==",
|
||||
"version": "1.4.639",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.639.tgz",
|
||||
"integrity": "sha512-CkKf3ZUVZchr+zDpAlNLEEy2NJJ9T64ULWaDgy3THXXlPVPkLu3VOs9Bac44nebVtdwl2geSj6AxTtGDOxoXhg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
|
@ -8352,9 +8369,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.2.tgz",
|
||||
"integrity": "sha512-dhlpWc9vOwohcWmClFcA+HjlvUpuyynYs0Rf+L/P6/0iQE6vlHW9l5bkfzN62/Stm9fbq8ku46qzde76T1xlSg==",
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
|
||||
"integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"prettier-linter-helpers": "^1.0.0",
|
||||
|
@ -9164,9 +9181,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.4",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
|
||||
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
|
||||
"version": "1.15.5",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
|
||||
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
|
@ -11849,9 +11866,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mini-css-extract-plugin": {
|
||||
"version": "2.7.6",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz",
|
||||
"integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==",
|
||||
"version": "2.7.7",
|
||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.7.tgz",
|
||||
"integrity": "sha512-+0n11YGyRavUR3IlaOzJ0/4Il1avMvJ1VJfhWfCn24ITQXhRr1gghbhhrda6tgtNcpZaWKdSuwKq20Jb7fnlyw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"schema-utils": "^4.0.0"
|
||||
|
@ -12100,9 +12117,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/naive-ui": {
|
||||
"version": "2.36.0",
|
||||
"resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.36.0.tgz",
|
||||
"integrity": "sha512-r1ydtEm1Ryf/aWpbLCf32mQAGK99jd1eXgpkCtIomcBRZeAtusfy6zCtIpCppoCuIKM3BW5DMafhVxilubk/lQ==",
|
||||
"version": "2.37.3",
|
||||
"resolved": "https://registry.npmjs.org/naive-ui/-/naive-ui-2.37.3.tgz",
|
||||
"integrity": "sha512-aUkHFXVIluSi8Me+npbcsdv1NYhVMj5t9YaruoCESlqmfqspj+R2QHEVXkTtUI1kQwVrABMCtAGq/wountqjZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@css-render/plugin-bem": "^0.15.12",
|
||||
|
@ -12112,6 +12129,7 @@
|
|||
"@types/lodash-es": "^4.17.9",
|
||||
"async-validator": "^4.2.5",
|
||||
"css-render": "^0.15.12",
|
||||
"csstype": "^3.1.3",
|
||||
"date-fns": "^2.30.0",
|
||||
"date-fns-tz": "^2.0.0",
|
||||
"evtd": "^0.2.4",
|
||||
|
@ -12122,7 +12140,7 @@
|
|||
"treemate": "^0.3.11",
|
||||
"vdirs": "^0.1.8",
|
||||
"vooks": "^0.2.12",
|
||||
"vueuc": "^0.4.54"
|
||||
"vueuc": "^0.4.58"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^3.0.0"
|
||||
|
@ -12229,6 +12247,11 @@
|
|||
"lodash": "^4.17.21"
|
||||
}
|
||||
},
|
||||
"node_modules/node-exceptions": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-exceptions/-/node-exceptions-4.0.1.tgz",
|
||||
"integrity": "sha512-KJI+FawYOv74x60H6+zrBPfO2vvp9m0pHZi6SH8BBBuc67Irv11DsqY4Le4EBFq1/T5aXFU3hkLrMgtW7RNXxA=="
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
|
@ -13160,9 +13183,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/pino-pretty/node_modules/sonic-boom": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.7.0.tgz",
|
||||
"integrity": "sha512-IudtNvSqA/ObjN97tfgNmOKyDOs4dNcg4cUUsHDebqsgb8wGBBwb31LIgShNO8fye0dFI52X1+tFoKKI6Rq1Gg==",
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz",
|
||||
"integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==",
|
||||
"dependencies": {
|
||||
"atomic-sleep": "^1.0.0"
|
||||
}
|
||||
|
@ -13358,9 +13381,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.32",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
|
||||
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
|
||||
"version": "8.4.33",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
|
||||
"integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
@ -13686,9 +13709,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-modules-local-by-default": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz",
|
||||
"integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz",
|
||||
"integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"icss-utils": "^5.0.0",
|
||||
|
@ -13703,9 +13726,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss-modules-scope": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.0.tgz",
|
||||
"integrity": "sha512-SaIbK8XW+MZbd0xHPf7kdfA/3eOt7vxJ72IRecn3EzuZVLr1r0orzf0MX/pN8m+NMDoo6X/SQd8oeKqGZd8PXg==",
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz",
|
||||
"integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
|
@ -14026,9 +14049,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
|
||||
"integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz",
|
||||
"integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
|
@ -14789,9 +14812,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/saxon-js/node_modules/axios": {
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz",
|
||||
"integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==",
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -14958,9 +14981,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/serialize-javascript": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
|
||||
"integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
|
||||
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"randombytes": "^2.1.0"
|
||||
|
@ -15070,14 +15093,15 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz",
|
||||
"integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz",
|
||||
"integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==",
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.1.1",
|
||||
"get-intrinsic": "^1.2.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-intrinsic": "^1.2.2",
|
||||
"gopd": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0"
|
||||
"has-property-descriptors": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
|
@ -15752,9 +15776,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/style-loader": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz",
|
||||
"integrity": "sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==",
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.4.tgz",
|
||||
"integrity": "sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 12.13.0"
|
||||
|
@ -15894,13 +15918,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/supertest": {
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz",
|
||||
"integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==",
|
||||
"version": "6.3.4",
|
||||
"resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz",
|
||||
"integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"methods": "^1.1.2",
|
||||
"superagent": "^8.0.5"
|
||||
"superagent": "^8.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.4.0"
|
||||
|
@ -16138,9 +16162,9 @@
|
|||
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.0.tgz",
|
||||
"integrity": "sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==",
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||
"integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
|
@ -16212,9 +16236,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.26.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz",
|
||||
"integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==",
|
||||
"version": "5.27.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz",
|
||||
"integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
|
@ -16446,6 +16470,11 @@
|
|||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/toastify-js": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.12.0.tgz",
|
||||
"integrity": "sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ=="
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
|
@ -16997,15 +17026,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vue": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.4.tgz",
|
||||
"integrity": "sha512-suZXgDVT8lRNhKmxdkwOsR0oyUi8is7mtqI18qW97JLoyorEbE9B2Sb4Ws/mR/+0AgA/JUtsv1ytlRSH3/pDIA==",
|
||||
"version": "3.4.15",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.4.15.tgz",
|
||||
"integrity": "sha512-jC0GH4KkWLWJOEQjOpkqU1bQsBwf4R1rsFtw5GQJbjHVKWDzO6P0nWWBTmjp1xSemAioDFj1jdaK1qa3DnMQoQ==",
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.4.4",
|
||||
"@vue/compiler-sfc": "3.4.4",
|
||||
"@vue/runtime-dom": "3.4.4",
|
||||
"@vue/server-renderer": "3.4.4",
|
||||
"@vue/shared": "3.4.4"
|
||||
"@vue/compiler-dom": "3.4.15",
|
||||
"@vue/compiler-sfc": "3.4.15",
|
||||
"@vue/runtime-dom": "3.4.15",
|
||||
"@vue/server-renderer": "3.4.15",
|
||||
"@vue/shared": "3.4.15"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "*"
|
||||
|
@ -17675,9 +17704,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/xslt3/node_modules/axios": {
|
||||
"version": "1.6.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.4.tgz",
|
||||
"integrity": "sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==",
|
||||
"version": "1.6.5",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
|
||||
"integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.4",
|
||||
|
|
|
@ -91,6 +91,7 @@
|
|||
"leaflet": "^1.9.3",
|
||||
"luxon": "^3.2.1",
|
||||
"node-2fa": "^2.0.3",
|
||||
"node-exceptions": "^4.0.1",
|
||||
"notiwind": "^2.0.0",
|
||||
"pg": "^8.9.0",
|
||||
"proxy-addr": "^2.0.7",
|
||||
|
@ -99,6 +100,7 @@
|
|||
"reflect-metadata": "^0.2.1",
|
||||
"saxon-js": "^2.5.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"toastify-js": "^1.12.0",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"xmlbuilder2": "^3.1.1"
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@
|
|||
"assets/fonts/inter-vietnamese-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.5952d3d3.woff2",
|
||||
"assets/images/marker-icon.png": "http://localhost:8080/assets/images/marker-icon.2b3e1faf.png",
|
||||
"assets/images/layers-2x.png": "http://localhost:8080/assets/images/layers-2x.8f2c4d11.png",
|
||||
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png"
|
||||
"assets/images/layers.png": "http://localhost:8080/assets/images/layers.416d9136.png",
|
||||
"assets/images/Close.svg": "http://localhost:8080/assets/images/Close.e4887675.svg"
|
||||
}
|
246
resources/js/Components/PersonalTotpSettings.vue
Normal file
246
resources/js/Components/PersonalTotpSettings.vue
Normal file
|
@ -0,0 +1,246 @@
|
|||
<template>
|
||||
<!-- <div id="twofactor-totp-settings">
|
||||
<template v-if="loading">
|
||||
<span class="icon-loading-small totp-loading" />
|
||||
<span> {{ t('twofactor_totp', 'Enable TOTP') }} </span>
|
||||
</template>
|
||||
<div v-else>
|
||||
<input id="totp-enabled" v-model="enabled" type="checkbox" class="checkbox" :disabled="loading"
|
||||
@change="toggleEnabled">
|
||||
<label for="totp-enabled">{{
|
||||
t('twofactor_totp', 'Enable TOTP')
|
||||
}}</label>
|
||||
</div>
|
||||
|
||||
<SetupConfirmation v-if="secret" :secret="secret" :qr-url="qrUrl" :loading="loadingConfirmation"
|
||||
:confirmation.sync="confirmation" @confirm="enableTOTP" />
|
||||
</div> -->
|
||||
<CardBox :icon="mdiTwoFactorAuthentication" id="twofactor-totp-settings" title="Two-Factor Authentication" form>
|
||||
<template v-if="loading">
|
||||
<!-- <span class="icon-loading-small totp-loading" /> -->
|
||||
<div class="relative inline-flex">
|
||||
<div class="w-6 h-6 bg-blue-500 rounded-full"></div>
|
||||
<div class="w-6 h-6 bg-blue-500 rounded-full absolute top-0 left-0 animate-ping"></div>
|
||||
<div class="w-6 h-6 bg-blue-500 rounded-full absolute top-0 left-0 animate-pulse"></div>
|
||||
<span class="ml-4 max-w-xl text-sm text-gray-600">Enabling TOTP...</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else>
|
||||
<!-- <div class="text-lg font-medium text-gray-900">
|
||||
You have not enabled two factor authentication.
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">
|
||||
When two factor authentication is enabled, you will be prompted for a secure,
|
||||
random token during authentication. You may retrieve this token from your phone's
|
||||
Google Authenticator application.
|
||||
</div> -->
|
||||
<input id="totp-enabled" v-model="enabled" type="checkbox" class="checkbox" :disabled="loading"
|
||||
@change="toggleEnabled" />
|
||||
<!-- <label for="totp-enabled"> Enable TOTP </label> -->
|
||||
<label for="totp-enabled">{{ checkboxLabel }}</label>
|
||||
</div>
|
||||
|
||||
<!-- <SetupConfirmation v-if="secret" :secret="secret" :qr-url="qrUrl" :loading="loadingConfirmation"
|
||||
:confirmation.sync="confirmation" @confirm="enableTOTP" /> -->
|
||||
<div v-if="qrSecret != ''">
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600">
|
||||
<!-- <p class="font-semibold">
|
||||
Two factor authentication is now enabled.
|
||||
</p> -->
|
||||
<p>Your new TOTP secret is: {{ qrSecret }}</p>
|
||||
<p>For quick setup, scan this QR code with your phone's authenticator application (TOTP):</p>
|
||||
<div class="mt-4">
|
||||
<img :src="qrSvg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="mt-4 max-w-xl text-sm text-gray-600">
|
||||
<p>
|
||||
After you configured your app, enter a test code below to ensure everything works correctly:
|
||||
</p>
|
||||
|
||||
</div> -->
|
||||
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600">
|
||||
<p>After you configured your app, enter a test code below to ensure everything works correctly:</p>
|
||||
<!-- :disabled="loading" -->
|
||||
<input id="totp-confirmation" :disabled="loadingConfirmation" v-model="confirmationCode" type="tel"
|
||||
minlength="6" maxlength="10" autocomplete="off" autocapitalize="off"
|
||||
:placeholder="'Authentication code'" @keydown="onConfirmKeyDown" />
|
||||
|
||||
<!-- <input id="totp-confirmation-submit" type="button" :disabled="loading" :value="'Verify'"
|
||||
@click="enableTOTP"> -->
|
||||
|
||||
<!-- <BaseButtons>
|
||||
<BaseButton :icon="mdiContentSaveCheck" type="button" :disabled="loadingConfirmation" color="info"
|
||||
label="Verify" @click="enableTOTP" />
|
||||
</BaseButtons> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<BaseButtons v-if="qrSecret != ''">
|
||||
<BaseButton :icon="mdiContentSaveCheck" type="button" :disabled="loadingConfirmation" color="info"
|
||||
label="Verify" @click="enableTOTP" />
|
||||
</BaseButtons>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { MainService, State } from '@/Stores/main';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import Notification from '@/utils/toast';
|
||||
import { mdiContentSaveCheck, mdiTwoFactorAuthentication } from '@mdi/js';
|
||||
|
||||
const mainService = MainService();
|
||||
const emit = defineEmits(['confirm', 'update:confirmation']);
|
||||
|
||||
const props = defineProps({
|
||||
// user will be returned from controller action
|
||||
// user: {
|
||||
// type: Object,
|
||||
// default: () => ({}),
|
||||
// },
|
||||
twoFactorEnabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// // code: {
|
||||
// // type: Object,
|
||||
// // },
|
||||
// // recoveryCodes: {
|
||||
// // type: Array<string>,
|
||||
// // default: () => [],
|
||||
// // },
|
||||
// // errors: {
|
||||
// // type: Object,
|
||||
// // default: () => ({}),
|
||||
// // },
|
||||
});
|
||||
let loading = ref(false);
|
||||
let loadingConfirmation = ref(false);
|
||||
let test;
|
||||
if (props.twoFactorEnabled) {
|
||||
test = State.STATE_ENABLED;
|
||||
} else {
|
||||
test = State.STATE_DISABLED;
|
||||
}
|
||||
mainService.setState(test);
|
||||
|
||||
const enabled = ref(mainService.totpState == State.STATE_ENABLED);
|
||||
|
||||
let qrSecret = ref('');
|
||||
let qrUrl = ref('');
|
||||
let qrSvg = ref('');
|
||||
|
||||
const confirmationCode = ref('');
|
||||
|
||||
const confirm = () => {
|
||||
emit('update:confirmation', confirmationCode.value);
|
||||
emit('confirm');
|
||||
};
|
||||
|
||||
const onConfirmKeyDown = (e) => {
|
||||
if (e.which === 13) {
|
||||
confirm();
|
||||
}
|
||||
};
|
||||
|
||||
const state = computed(() => mainService.totpState);
|
||||
const checkboxLabel = computed(() => {
|
||||
if (enabled.value == true) {
|
||||
return ' Disable TOTP';
|
||||
} else {
|
||||
return ' Enable TOTP';
|
||||
}
|
||||
});
|
||||
|
||||
const toggleEnabled = async () => {
|
||||
if (loading.value == true) {
|
||||
// Ignore event
|
||||
// Logger.debug('still loading -> ignoring event')
|
||||
return;
|
||||
}
|
||||
|
||||
if (enabled.value) {
|
||||
return await createTOTP();
|
||||
} else {
|
||||
return await disableTOTP();
|
||||
}
|
||||
};
|
||||
|
||||
const createTOTP = async () => {
|
||||
// Show loading spinner
|
||||
loading.value = true;
|
||||
// Logger.debug('starting setup')
|
||||
|
||||
try {
|
||||
const { url, secret, svg } = await mainService.create();
|
||||
qrSecret.value = secret;
|
||||
qrUrl.value = url;
|
||||
qrSvg.value = svg;
|
||||
// If the stat could be changed, keep showing the loading
|
||||
// spinner until the user has finished the registration
|
||||
// if state isCretaed, show loading:
|
||||
loading.value = state.value === State.STATE_CREATED;
|
||||
} catch (e) {
|
||||
Notification.showWarning('Could not enable TOTP');
|
||||
// Logger.error('Could not enable TOTP', e)
|
||||
console.log('Could not create TOTP', e.message);
|
||||
|
||||
// Restore on error
|
||||
loading.value = false;
|
||||
enabled.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const disableTOTP = async () => {
|
||||
loading.value = false;
|
||||
// Logger.debug('starting disable');
|
||||
|
||||
await mainService.disable();
|
||||
enabled.value = false;
|
||||
loading.value = false;
|
||||
Notification.showSuccess('TOTP disabled!');
|
||||
};
|
||||
|
||||
const enableTOTP = async () => {
|
||||
loading.value = true;
|
||||
loadingConfirmation.value = true;
|
||||
|
||||
try {
|
||||
await mainService.confirm(confirmationCode.value);
|
||||
if (mainService.totpState === State.STATE_ENABLED) {
|
||||
// Success
|
||||
loading.value = false;
|
||||
enabled.value = true;
|
||||
qrUrl.value = '';
|
||||
qrSecret.value = '';
|
||||
Notification.showSuccess('two factor authentication enabled');
|
||||
} else {
|
||||
Notification.showWarning('Could not verify your key. Please try again');
|
||||
console.log('Could not verify your key. Please try again');
|
||||
}
|
||||
confirmationCode.value = '';
|
||||
loadingConfirmation.value = false;
|
||||
} catch (e) {
|
||||
console.log('Could not enable TOTP', e.message);
|
||||
Notification.showWarning('Could not enable TOTP ' + e.message);
|
||||
confirmationCode.value = '';
|
||||
loadingConfirmation.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.totp-loading {
|
||||
display: inline-block;
|
||||
vertical-align: sub;
|
||||
margin-left: -2px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
// import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
|
||||
import { useForm, router } from '@inertiajs/vue3';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
// import { ref } from 'vue';
|
||||
// import { reactive } from 'vue';
|
||||
import {
|
||||
mdiAccount,
|
||||
|
@ -11,7 +12,6 @@ import {
|
|||
mdiFormTextboxPassword,
|
||||
mdiArrowLeftBoldOutline,
|
||||
mdiAlertBoxOutline,
|
||||
mdiInformation
|
||||
} from '@mdi/js';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
|
@ -28,10 +28,13 @@ import { stardust } from '@eidellev/adonis-stardust/client';
|
|||
import { computed, Ref } from 'vue';
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
import FormValidationErrors from '@/Components/FormValidationErrors.vue';
|
||||
// import { Inertia } from '@inertiajs/inertia';
|
||||
import PersonalTotpSettings from '@/Components/PersonalTotpSettings.vue';
|
||||
// import { MainService } from '@/Stores/main';
|
||||
// const mainService = MainService();
|
||||
|
||||
const emit = defineEmits(['confirm', 'update:confirmation'])
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
// user will be returned from controller action
|
||||
user: {
|
||||
type: Object,
|
||||
|
@ -58,12 +61,12 @@ const props = defineProps({
|
|||
// login: props.user.login,
|
||||
// email: props.user.email,
|
||||
// });
|
||||
const enableTwoFactorAuthentication = async () => {
|
||||
await router.post(stardust.route('account.password.enable2fa'));
|
||||
};
|
||||
const disableTwoFactorAuthentication = async () => {
|
||||
await router.post(stardust.route('account.password.disable2fa'));
|
||||
};
|
||||
// const enableTwoFactorAuthentication = async () => {
|
||||
// await router.post(stardust.route('account.password.enable2fa'));
|
||||
// };
|
||||
// const disableTwoFactorAuthentication = async () => {
|
||||
// await router.post(stardust.route('account.password.disable2fa'));
|
||||
// };
|
||||
|
||||
|
||||
const passwordForm = useForm({
|
||||
|
@ -84,6 +87,28 @@ const passwordSubmit = async () => {
|
|||
const flash: Ref<any> = computed(() => {
|
||||
return usePage().props.flash;
|
||||
});
|
||||
|
||||
// const confirmationCode = ref('');
|
||||
|
||||
// const confirm = () => {
|
||||
// emit('update:confirmation', confirmationCode);
|
||||
// emit('confirm');
|
||||
// };
|
||||
|
||||
// const onConfirmKeyDown = (e) => {
|
||||
// if (e.which === 13) {
|
||||
// confirm()
|
||||
// }
|
||||
// };
|
||||
|
||||
// const generateSecretCode = (user) => {
|
||||
// const secret = generateSecret({
|
||||
// name: 'TethysCloud',
|
||||
// account: user.email,
|
||||
// });
|
||||
// return secret.secret;
|
||||
// }
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -101,8 +126,8 @@ const flash: Ref<any> = computed(() => {
|
|||
{{ $page.props.flash.message }}
|
||||
</NotificationBar> -->
|
||||
|
||||
<!-- <div class="grid grid-cols-1 lg:grid-cols-2 gap-6"> -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-1 gap-6">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- <div class="grid grid-cols-1 lg:grid-cols-1 gap-6"> -->
|
||||
|
||||
<!-- password form -->
|
||||
<!-- <CardBox title="Edit Profile" :icon="mdiAccountCircle" form @submit.prevent="profileForm.post(route('admin.account.info.store'))"> -->
|
||||
|
@ -186,24 +211,9 @@ const flash: Ref<any> = computed(() => {
|
|||
|
||||
|
||||
|
||||
<!-- <CardBox title="Edit Profile" :icon="mdiAccountCircle" form @submit.prevent="profileForm.post(route('admin.account.info.store'))"> -->
|
||||
<CardBox v-if="!props.twoFactorEnabled" title="Two-Factor Authentication" :icon="mdiInformation" form
|
||||
<PersonalTotpSettings :twoFactorEnabled="twoFactorEnabled"/>
|
||||
<!-- <CardBox v-if="!props.twoFactorEnabled" title="Two-Factor Authentication" :icon="mdiInformation" form
|
||||
@submit.prevent="enableTwoFactorAuthentication()">
|
||||
<!-- <FormField label="Login" help="Required. Your login name" :class="{ 'text-red-400': errors.login }">
|
||||
<FormControl v-model="factorForm.login" v-bind:icon="mdiAccount" name="login" required :error="errors.login">
|
||||
<div class="text-red-400 text-sm" v-if="errors.login">
|
||||
{{ errors.login }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField label="Email" help="Required. Your e-mail" :class="{ 'text-red-400': errors.email }">
|
||||
<FormControl v-model="factorForm.email" :icon="mdiMail" type="email" name="email" required :error="errors.email">
|
||||
<div class="text-red-400 text-sm" v-if="errors.email">
|
||||
{{ errors.email }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField> -->
|
||||
|
||||
<div class="text-lg font-medium text-gray-900">
|
||||
You have not enabled two factor authentication.
|
||||
</div>
|
||||
|
@ -218,70 +228,9 @@ const flash: Ref<any> = computed(() => {
|
|||
<BaseButton color="info" type="submit" label="Enable" />
|
||||
</BaseButtons>
|
||||
</template>
|
||||
</CardBox>
|
||||
</CardBox> -->
|
||||
|
||||
<CardBox v-else-if="props.twoFactorEnabled" title="Two-Factor Authentication" :icon="mdiInformation" form @submit.prevent="disableTwoFactorAuthentication()">
|
||||
<!-- <div class="w-1/2 space-y-4 bg-gray-100 p-8"> -->
|
||||
<h3 class="text-lg font-medium text-gray-900">
|
||||
You have enabled two factor authentication.
|
||||
</h3>
|
||||
<div class="mt-3 max-w-xl text-sm text-gray-600">
|
||||
<p>
|
||||
When two factor authentication is enabled, you will be prompted for a secure, random
|
||||
token during authentication. You may retrieve this token from your phone's Google
|
||||
Authenticator application.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="code">
|
||||
<div class="mt-4 max-w-xl text-sm text-gray-600">
|
||||
<p class="font-semibold">
|
||||
Two factor authentication is now enabled. Scan the following QR code using your
|
||||
phone's authenticator application.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<img :src="code?.svg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- @if(recoveryCodes) -->
|
||||
<div v-if="recoveryCodes" class="mt-4 max-w-xl text-sm text-gray-600">
|
||||
<p class="font-semibold">
|
||||
Store these recovery codes in a secure password manager. They can be used to recover
|
||||
access to your account if your two factor authentication device is lost.
|
||||
</p>
|
||||
</div>
|
||||
<!-- <div class="mt-4 grid max-w-xl gap-1 rounded-lg bg-gray-100 px-4 py-4 font-mono text-sm">
|
||||
@each(code in recoveryCodes)
|
||||
<div>
|
||||
{{ code }}
|
||||
</div>
|
||||
@endeach
|
||||
</div> -->
|
||||
<!-- @endif -->
|
||||
|
||||
<div class="flex justify-between">
|
||||
<!-- <form action="{{ route('UserController.fetchRecoveryCodes') }}" method="GET">
|
||||
<button type="submit" class="px-auto items-center rounded border border-gray-300 bg-white px-2.5 py-1.5 text-xs
|
||||
font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none
|
||||
">
|
||||
Show Recovery Codes
|
||||
</button>
|
||||
</form>
|
||||
<form action="{{ route('UserController.disableTwoFactorAuthentication') }}" method="POST">
|
||||
<button type="submit" class="px-auto items-center rounded border border-gray-300 bg-white px-2.5 py-1.5 text-xs
|
||||
font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none
|
||||
">
|
||||
Disable
|
||||
</button>
|
||||
</form> -->
|
||||
<BaseButton color="info" type="submit" label="Disable" />
|
||||
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
</CardBox>
|
||||
|
||||
</div>
|
||||
</SectionMain>
|
||||
|
|
|
@ -22,6 +22,26 @@ interface TransactionItem {
|
|||
business: string;
|
||||
}
|
||||
|
||||
export enum State {
|
||||
STATE_DISABLED = 0,
|
||||
STATE_CREATED = 1,
|
||||
STATE_ENABLED = 2,
|
||||
}
|
||||
|
||||
export const saveState = async (data) => {
|
||||
const url = '/api/twofactor_totp/settings/enable';
|
||||
|
||||
const resp = await axios.post(url, data);
|
||||
return resp.data;
|
||||
};
|
||||
|
||||
// Anfrage staet : 1
|
||||
|
||||
// ANtwort json:
|
||||
// state: 1
|
||||
// secret:"OX7IQ4OI3GXGFPHY"
|
||||
// qUrl:"https://odysseus.geologie.ac.at/apps/twofactor_totp/settings/enable"
|
||||
|
||||
export const MainService = defineStore('main', {
|
||||
state: () => ({
|
||||
/* User */
|
||||
|
@ -45,6 +65,8 @@ export const MainService = defineStore('main', {
|
|||
dataset: {} as Dataset,
|
||||
|
||||
menu: menu,
|
||||
|
||||
totpState: 0,
|
||||
}),
|
||||
actions: {
|
||||
// payload = authenticated user
|
||||
|
@ -113,6 +135,36 @@ export const MainService = defineStore('main', {
|
|||
});
|
||||
},
|
||||
|
||||
setState(state) {
|
||||
this.totpState = state;
|
||||
},
|
||||
|
||||
async create(): Promise<{ url: any; secret: any; svg: any }> {
|
||||
const { state, secret, url, svg } = await saveState({ state: State.STATE_CREATED });
|
||||
this.totpState = state;
|
||||
return { url, secret, svg };
|
||||
// .then(({ state, secret, qrUrl }) => {
|
||||
// this.totpState = state;
|
||||
// return { qrUrl, secret };
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// alert(error.message);
|
||||
// });
|
||||
},
|
||||
|
||||
async disable() {
|
||||
const { state } = await saveState({ state: State.STATE_DISABLED });
|
||||
this.totpState = state;
|
||||
},
|
||||
|
||||
async confirm(code: string) {
|
||||
const { state } = await saveState({
|
||||
state: State.STATE_ENABLED,
|
||||
code,
|
||||
});
|
||||
this.totpState = state;
|
||||
},
|
||||
|
||||
// fetchfiles(id) {
|
||||
// // sampleDataKey= authors or datasets
|
||||
// axios
|
||||
|
|
3
resources/js/utils/Close.svg
Normal file
3
resources/js/utils/Close.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16">
|
||||
<path d="M14 12.3L12.3 14 8 9.7 3.7 14 2 12.3 6.3 8 2 3.7 3.7 2 8 6.3 12.3 2 14 3.7 9.7 8z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 170 B |
103
resources/js/utils/toast.css
Normal file
103
resources/js/utils/toast.css
Normal file
|
@ -0,0 +1,103 @@
|
|||
|
||||
/* remember to import this scss file into your app */
|
||||
.toastify.dialogs {
|
||||
min-width: 200px;
|
||||
background: none;
|
||||
background-color: var(--color-main-background);
|
||||
color: var(--color-main-text);
|
||||
box-shadow: 0 0 6px 0 var(--color-box-shadow);
|
||||
padding: 0 12px;
|
||||
margin-top: 45px;
|
||||
position: fixed;
|
||||
z-index: 10100;
|
||||
border-radius: var(--border-radius);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.toast-undo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.toast-undo-button,
|
||||
.toast-close {
|
||||
position: static;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
min-width: 44px;
|
||||
height: 100%;
|
||||
padding: 12px;
|
||||
white-space: nowrap;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: transparent;
|
||||
min-height: 0;
|
||||
|
||||
/* icon styling */
|
||||
&.toast-close {
|
||||
text-indent: 0;
|
||||
opacity: 0.4;
|
||||
border: none;
|
||||
min-height: 44px;
|
||||
margin-left: 10px;
|
||||
font-size: 0;
|
||||
|
||||
/* dark theme overrides for Nextcloud 25 and later */
|
||||
&::before {
|
||||
background-image: url('./Close.svg');
|
||||
content: ' ';
|
||||
filter: var(--background-invert-if-dark);
|
||||
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.toast-undo-button {
|
||||
/* $margin: 3px; */
|
||||
/* margin: $margin; */
|
||||
/* height: calc(100% - 2 * #{$margin}); */
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&.toastify-top {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
/* Toast with onClick callback */
|
||||
&.toast-with-click {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Various toasts types */
|
||||
&.toast-error {
|
||||
border-left: 3px solid var(--color-error);
|
||||
}
|
||||
|
||||
&.toast-info {
|
||||
border-left: 3px solid var(--color-primary);
|
||||
}
|
||||
|
||||
&.toast-warning {
|
||||
border-left: 3px solid var(--color-warning);
|
||||
}
|
||||
|
||||
&.toast-success {
|
||||
border-left: 3px solid var(--color-success);
|
||||
}
|
||||
|
||||
&.toast-undo {
|
||||
border-left: 3px solid var(--color-success);
|
||||
}
|
||||
}
|
||||
|
||||
|
216
resources/js/utils/toast.ts
Normal file
216
resources/js/utils/toast.ts
Normal file
|
@ -0,0 +1,216 @@
|
|||
import Toastify from 'toastify-js';
|
||||
// import { t } from './utils/l10n.js';
|
||||
import './toast.css';
|
||||
|
||||
/**
|
||||
* Enum of available Toast types
|
||||
*/
|
||||
export enum ToastType {
|
||||
ERROR = 'toast-error',
|
||||
WARNING = 'toast-warning',
|
||||
INFO = 'toast-info',
|
||||
SUCCESS = 'toast-success',
|
||||
PERMANENT = 'toast-error',
|
||||
UNDO = 'toast-undo',
|
||||
}
|
||||
|
||||
/** @deprecated Use ToastAriaLive.OFF */
|
||||
export const TOAST_ARIA_LIVE_OFF = 'off';
|
||||
/** @deprecated Use ToastAriaLive.POLITE */
|
||||
export const TOAST_ARIA_LIVE_POLITE = 'polite';
|
||||
/** @deprecated Use ToastAriaLive.ASSERTIVE */
|
||||
export const TOAST_ARIA_LIVE_ASSERTIVE = 'assertive';
|
||||
|
||||
export enum ToastAriaLive {
|
||||
OFF = TOAST_ARIA_LIVE_OFF,
|
||||
POLITE = TOAST_ARIA_LIVE_POLITE,
|
||||
ASSERTIVE = TOAST_ARIA_LIVE_ASSERTIVE,
|
||||
}
|
||||
|
||||
/** Timeout in ms of a undo toast */
|
||||
export const TOAST_UNDO_TIMEOUT = 10000;
|
||||
/** Default timeout in ms of toasts */
|
||||
export const TOAST_DEFAULT_TIMEOUT = 4000;
|
||||
/** Timeout value to show a toast permanently */
|
||||
export const TOAST_PERMANENT_TIMEOUT = -1;
|
||||
|
||||
/**
|
||||
* Type of a toast
|
||||
* @see https://apvarun.github.io/toastify-js/
|
||||
* @notExported
|
||||
*/
|
||||
type Toast = ReturnType<typeof Toastify>;
|
||||
|
||||
export interface ToastOptions {
|
||||
/**
|
||||
* Defines the timeout in milliseconds after which the toast is closed. Set to -1 to have a persistent toast.
|
||||
*/
|
||||
timeout?: number;
|
||||
|
||||
/**
|
||||
* Set to true to allow HTML content inside of the toast text
|
||||
* @default false
|
||||
*/
|
||||
isHTML?: boolean;
|
||||
|
||||
/**
|
||||
* Set a type of {ToastType} to style the modal
|
||||
*/
|
||||
type?: ToastType;
|
||||
|
||||
/**
|
||||
* Provide a function that is called after the toast is removed
|
||||
*/
|
||||
onRemove?: () => void;
|
||||
|
||||
/**
|
||||
* Provide a function that is called when the toast is clicked
|
||||
*/
|
||||
onClick?: () => void;
|
||||
|
||||
/**
|
||||
* Make the toast closable
|
||||
*/
|
||||
close?: boolean;
|
||||
|
||||
/**
|
||||
* Specify the element to attach the toast element to (for testing)
|
||||
*/
|
||||
selector?: string;
|
||||
|
||||
/**
|
||||
* Whether the messages should be announced to screen readers.
|
||||
* See the following docs for an explanation when to use which:
|
||||
* https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions
|
||||
*
|
||||
* By default, errors are announced assertive and other messages "polite".
|
||||
*/
|
||||
ariaLive?: ToastAriaLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a toast message
|
||||
*
|
||||
* @param data Message to be shown in the toast, any HTML is removed by default
|
||||
* @param options
|
||||
*/
|
||||
export function showMessage(data: string | Node, options?: ToastOptions): Toast {
|
||||
options = Object.assign(
|
||||
{
|
||||
timeout: TOAST_DEFAULT_TIMEOUT,
|
||||
isHTML: false,
|
||||
type: undefined,
|
||||
// An undefined selector defaults to the body element
|
||||
selector: undefined,
|
||||
onRemove: () => {},
|
||||
onClick: undefined,
|
||||
close: true,
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
if (typeof data === 'string' && !options.isHTML) {
|
||||
// fime mae sure that text is extracted
|
||||
const element = document.createElement('div');
|
||||
element.innerHTML = data;
|
||||
data = element.innerText;
|
||||
}
|
||||
let classes = options.type ?? '';
|
||||
|
||||
if (typeof options.onClick === 'function') {
|
||||
classes += ' toast-with-click ';
|
||||
}
|
||||
|
||||
const isNode = data instanceof Node;
|
||||
|
||||
let ariaLive: ToastAriaLive = ToastAriaLive.POLITE;
|
||||
if (options.ariaLive) {
|
||||
ariaLive = options.ariaLive;
|
||||
} else if (options.type === ToastType.ERROR || options.type === ToastType.UNDO) {
|
||||
ariaLive = ToastAriaLive.ASSERTIVE;
|
||||
}
|
||||
|
||||
const toast = Toastify({
|
||||
[!isNode ? 'text' : 'node']: data,
|
||||
duration: options.timeout,
|
||||
callback: options.onRemove,
|
||||
onClick: options.onClick,
|
||||
close: options.close,
|
||||
gravity: 'top',
|
||||
selector: options.selector,
|
||||
position: 'right',
|
||||
backgroundColor: '',
|
||||
className: 'dialogs ' + classes,
|
||||
escapeMarkup: !options.isHTML,
|
||||
ariaLive,
|
||||
});
|
||||
|
||||
toast.showToast();
|
||||
|
||||
return toast;
|
||||
}
|
||||
|
||||
export default {
|
||||
updatableNotification: null,
|
||||
|
||||
getDefaultNotificationFunction: null,
|
||||
|
||||
/**
|
||||
* Shows a notification that disappears after x seconds, default is
|
||||
* 7 seconds
|
||||
*
|
||||
* @param {string} text Message to show
|
||||
* @param {Array} [options] options array
|
||||
* @param {number} [options.timeout=7] timeout in seconds, if this is 0 it will show the message permanently
|
||||
* @param {boolean} [options.isHTML=false] an indicator for HTML notifications (true) or text (false)
|
||||
* @param {string} [options.type] notification type
|
||||
* @return {JQuery} the toast element
|
||||
*/
|
||||
showTemporary(text, options = { timeout: 3000 }) {
|
||||
options = options || {};
|
||||
options.timeout = options.timeout || TOAST_DEFAULT_TIMEOUT;
|
||||
const toast = showMessage(text, options);
|
||||
toast.toastElement.toastify = toast;
|
||||
// return $(toast.toastElement)
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a toast message with error styling
|
||||
*
|
||||
* @param text Message to be shown in the toast, any HTML is removed by default
|
||||
* @param options
|
||||
*/
|
||||
showError(text: string, options?: ToastOptions): Toast {
|
||||
return showMessage(text, { ...options, type: ToastType.ERROR });
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a toast message with warning styling
|
||||
*
|
||||
* @param text Message to be shown in the toast, any HTML is removed by default
|
||||
* @param options
|
||||
*/
|
||||
showWarning(text: string, options?: ToastOptions): Toast {
|
||||
return showMessage(text, { ...options, type: ToastType.WARNING });
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a toast message with info styling
|
||||
*
|
||||
* @param text Message to be shown in the toast, any HTML is removed by default
|
||||
* @param options
|
||||
*/
|
||||
showInfo(text: string, options?: ToastOptions): Toast {
|
||||
return showMessage(text, { ...options, type: ToastType.INFO });
|
||||
},
|
||||
|
||||
/**
|
||||
* Show a toast message with success styling
|
||||
*
|
||||
* @param text Message to be shown in the toast, any HTML is removed by default
|
||||
* @param options
|
||||
*/
|
||||
showSuccess(text: string, options?: ToastOptions): Toast {
|
||||
return showMessage(text, { ...options, type: ToastType.SUCCESS });
|
||||
},
|
||||
};
|
|
@ -19,7 +19,10 @@ Route.group(() => {
|
|||
|
||||
Route.get('/download/:id', 'FileController.findOne').as('file.findOne');
|
||||
|
||||
Route.get('/avatar/:name/:background?/:textColor?/:size?', 'AvatarController.generateAvatar')
|
||||
Route.get('/avatar/:name/:background?/:textColor?/:size?', 'AvatarController.generateAvatar');
|
||||
|
||||
|
||||
Route.post('/twofactor_totp/settings/enable/:state/:code?', 'UserController.enable').as('apps.twofactor_totp.enable') .middleware(['auth']);;
|
||||
});
|
||||
// .middleware("auth:api");
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue
Block a user