feat: turn off 2FA function + switch to pnpm + update dependencies

pull/6775/head
NGPixel 9 months ago
parent 7f9c3511e8
commit a181579746
No known key found for this signature in database
GPG Key ID: B755FB6870B30F63

@ -51,6 +51,9 @@ RUN apt-get update \
# Clean up
&& apt-get autoremove -y && apt-get clean -y && rm -rf /var/lib/apt/lists/* /root/.gnupg /tmp/library-scripts
# Enable PNPM
RUN sudo corepack enable \
&& corepack prepare pnpm@latest --activate
EXPOSE 3000

@ -9,16 +9,14 @@ git config oh-my-zsh.hide-info 1
echo "Waiting for DB container to come online..."
/usr/local/bin/wait-for localhost:5432 -- echo "DB ready"
npm install -g npm-check-updates
echo "Installing dependencies..."
cd server
npm install
pnpm install
cd ../ux
npm install
pnpm install
cd ../blocks
npm install
npm run build
pnpm install
pnpm build
cd ..
echo "Ready!"

1
.gitignore vendored

@ -15,6 +15,7 @@ npm/node_modules
.node_repl_history
npm-debug.log*
/.yarn
/.pnpm-store
# Generated assets
/assets

@ -62,11 +62,11 @@ The current stable release (2.x) is available at https://js.wiki
1. Two terminals will launch in split-screen mode at the bottom of the screen. **Server** on the left and **UX** on the right.
1. In the right-side terminal (UX), run the command:
```sh
npm run build
pnpm build
```
1. In the left-side terminal (Server), run the command:
```sh
npm run start
pnpm start
```
1. Open your browser to `http://localhost:3000`
1. Login using the default administrator user:
@ -80,7 +80,7 @@ The current stable release (2.x) is available at https://js.wiki
From the left-side terminal (Server), run the command:
```sh
npm run dev
pnpm dev
```
This will launch the server and automatically restart upon modification of any server files.
@ -94,7 +94,7 @@ Only precompiled client assets are served in this mode. See the sections below o
If you wish to modify any frontend content (under `/ux`), you need to start the Quasar Dev Server in the right-side terminal (UX):
```sh
npm run dev
pnpm dev
```
You can then access the site at `http://localhost:3001`. Notice the port being `3001` rather than `3000`. The app runs in a SPA (single-page application) mode and automatically hot-reload any modified component. Any requests made to the `/graphql` endpoint are automatically forwarded to the server running on port `3000`, which is why both must be running at the same time.
@ -117,8 +117,9 @@ The server **dev** should already be available under **Servers**. If that's not
### Requirements
- PostgreSQL **11** or later *(**16** or later recommended)*
- Node.js **18.x** or later
- PostgreSQL **11** or later
- [pnpm](https://pnpm.io/installation#using-corepack)
### Usage
@ -128,10 +129,13 @@ The server **dev** should already be available under **Servers**. If that's not
1. Run the following commands to install dependencies and generate the client assets:
```sh
cd server
npm install
pnpm install
cd ../ux
npm install
npm run build
pnpm install
pnpm build
cd ../blocks
pnpm install
pnpm build
cd ..
```
1. Run this command to start the server:

File diff suppressed because it is too large Load Diff

@ -11,14 +11,14 @@
"author": "Nicolas Giard",
"license": "AGPL-3.0",
"dependencies": {
"lit": "^2.8.0"
"lit": "2.8.0"
},
"devDependencies": {
"@rollup/plugin-graphql": "^2.0.3",
"@rollup/plugin-node-resolve": "^15.2.1",
"@rollup/plugin-terser": "^0.4.3",
"glob": "^10.3.4",
"rollup": "^2.79.1",
"rollup-plugin-summary": "^2.0.0"
"@rollup/plugin-graphql": "2.0.4",
"@rollup/plugin-node-resolve": "15.2.2",
"@rollup/plugin-terser": "0.4.4",
"glob": "10.3.10",
"rollup": "3.29.4",
"rollup-plugin-summary": "2.0.0"
}
}

@ -0,0 +1,611 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
lit:
specifier: 2.8.0
version: 2.8.0
devDependencies:
'@rollup/plugin-graphql':
specifier: 2.0.4
version: 2.0.4(graphql@16.8.1)(rollup@3.29.4)
'@rollup/plugin-node-resolve':
specifier: 15.2.2
version: 15.2.2(rollup@3.29.4)
'@rollup/plugin-terser':
specifier: 0.4.4
version: 0.4.4(rollup@3.29.4)
glob:
specifier: 10.3.10
version: 10.3.10
rollup:
specifier: 3.29.4
version: 3.29.4
rollup-plugin-summary:
specifier: 2.0.0
version: 2.0.0(rollup@3.29.4)
packages:
/@colors/colors@1.5.0:
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
engines: {node: '>=0.1.90'}
requiresBuild: true
dev: true
optional: true
/@isaacs/cliui@8.0.2:
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
dependencies:
string-width: 5.1.2
string-width-cjs: /string-width@4.2.3
strip-ansi: 7.1.0
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
dev: true
/@jridgewell/gen-mapping@0.3.3:
resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
engines: {node: '>=6.0.0'}
dependencies:
'@jridgewell/set-array': 1.1.2
'@jridgewell/sourcemap-codec': 1.4.15
'@jridgewell/trace-mapping': 0.3.19
dev: true
/@jridgewell/resolve-uri@3.1.1:
resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
engines: {node: '>=6.0.0'}
dev: true
/@jridgewell/set-array@1.1.2:
resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
engines: {node: '>=6.0.0'}
dev: true
/@jridgewell/source-map@0.3.5:
resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==}
dependencies:
'@jridgewell/gen-mapping': 0.3.3
'@jridgewell/trace-mapping': 0.3.19
dev: true
/@jridgewell/sourcemap-codec@1.4.15:
resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
dev: true
/@jridgewell/trace-mapping@0.3.19:
resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==}
dependencies:
'@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15
dev: true
/@lit-labs/ssr-dom-shim@1.1.1:
resolution: {integrity: sha512-kXOeFbfCm4fFf2A3WwVEeQj55tMZa8c8/f9AKHMobQMkzNUfUj+antR3fRPaZJawsa1aZiP/Da3ndpZrwEe4rQ==}
dev: false
/@lit/reactive-element@1.6.3:
resolution: {integrity: sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==}
dependencies:
'@lit-labs/ssr-dom-shim': 1.1.1
dev: false
/@pkgjs/parseargs@0.11.0:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
dev: true
optional: true
/@rollup/plugin-graphql@2.0.4(graphql@16.8.1)(rollup@3.29.4):
resolution: {integrity: sha512-TfaqbbK71VHodCDCoRbPnv2+Tsnlvad2OsGEviURHFl+ZBUyf5wfXgXc9RqZ+xKxSl87Z3YbPhD0z6eWYjuByw==}
engines: {node: '>=14.0.0'}
peerDependencies:
graphql: '>=0.9.0'
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.0.5(rollup@3.29.4)
graphql: 16.8.1
graphql-tag: 2.12.6(graphql@16.8.1)
rollup: 3.29.4
dev: true
/@rollup/plugin-node-resolve@15.2.2(rollup@3.29.4):
resolution: {integrity: sha512-f64bU4OKqV0yihtxFemmuf0oj37pToCFMISCA+sJbbIAl5wcpbRO9XgWNWb1tDiWQJUcPxo6V0l59hcuZOQ3kw==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^2.78.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@rollup/pluginutils': 5.0.5(rollup@3.29.4)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-builtin-module: 3.2.1
is-module: 1.0.0
resolve: 1.22.6
rollup: 3.29.4
dev: true
/@rollup/plugin-terser@0.4.4(rollup@3.29.4):
resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
rollup: 3.29.4
serialize-javascript: 6.0.1
smob: 1.4.1
terser: 5.21.0
dev: true
/@rollup/pluginutils@5.0.5(rollup@3.29.4):
resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
dependencies:
'@types/estree': 1.0.2
estree-walker: 2.0.2
picomatch: 2.3.1
rollup: 3.29.4
dev: true
/@types/estree@1.0.2:
resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==}
dev: true
/@types/resolve@1.20.2:
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
dev: true
/@types/trusted-types@2.0.4:
resolution: {integrity: sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==}
dev: false
/acorn@8.10.0:
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: true
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
dev: true
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: true
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: true
/brotli-size@4.0.0:
resolution: {integrity: sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==}
engines: {node: '>= 10.16.0'}
dependencies:
duplexer: 0.1.1
dev: true
/buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/builtin-modules@3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'}
dev: true
/cli-table3@0.6.3:
resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==}
engines: {node: 10.* || >= 12.*}
dependencies:
string-width: 4.2.3
optionalDependencies:
'@colors/colors': 1.5.0
dev: true
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: true
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/commander@2.20.3:
resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
dev: true
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
dev: true
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
dev: true
/duplexer@0.1.1:
resolution: {integrity: sha512-sxNZ+ljy+RA1maXoUReeqBBpBC6RLKmg5ewzV+x+mSETmWNoKdZN6vcQjpFROemza23hGFskJtFNoUWUaQ+R4Q==}
dev: true
/duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
dev: true
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/emoji-regex@8.0.0:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
/filesize@10.1.0:
resolution: {integrity: sha512-GTLKYyBSDz3nPhlLVPjPWZCnhkd9TrrRArNcy8Z+J2cqScB7h2McAzR6NBX6nYOoWafql0roY8hrocxnZBv9CQ==}
engines: {node: '>= 10.4.0'}
dev: true
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
engines: {node: '>=14'}
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
dev: true
/fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/glob@10.3.10:
resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==}
engines: {node: '>=16 || 14 >=14.17'}
hasBin: true
dependencies:
foreground-child: 3.1.1
jackspeak: 2.3.6
minimatch: 9.0.3
minipass: 7.0.4
path-scurry: 1.10.1
dev: true
/graphql-tag@2.12.6(graphql@16.8.1):
resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==}
engines: {node: '>=10'}
peerDependencies:
graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
dependencies:
graphql: 16.8.1
tslib: 2.6.2
dev: true
/graphql@16.8.1:
resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==}
engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0}
dev: true
/gzip-size@7.0.0:
resolution: {integrity: sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
duplexer: 0.1.2
dev: true
/has@1.0.4:
resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==}
engines: {node: '>= 0.4.0'}
dev: true
/is-builtin-module@3.2.1:
resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==}
engines: {node: '>=6'}
dependencies:
builtin-modules: 3.3.0
dev: true
/is-core-module@2.13.0:
resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==}
dependencies:
has: 1.0.4
dev: true
/is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
dev: true
/is-module@1.0.0:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
dev: true
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
/jackspeak@2.3.6:
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
engines: {node: '>=14'}
dependencies:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
dev: true
/lit-element@3.3.3:
resolution: {integrity: sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==}
dependencies:
'@lit-labs/ssr-dom-shim': 1.1.1
'@lit/reactive-element': 1.6.3
lit-html: 2.8.0
dev: false
/lit-html@2.8.0:
resolution: {integrity: sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==}
dependencies:
'@types/trusted-types': 2.0.4
dev: false
/lit@2.8.0:
resolution: {integrity: sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==}
dependencies:
'@lit/reactive-element': 1.6.3
lit-element: 3.3.3
lit-html: 2.8.0
dev: false
/lru-cache@10.0.1:
resolution: {integrity: sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==}
engines: {node: 14 || >=16.14}
dev: true
/minimatch@9.0.3:
resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minipass@7.0.4:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
dev: true
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
dev: true
/path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
/path-scurry@1.10.1:
resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==}
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
lru-cache: 10.0.1
minipass: 7.0.4
dev: true
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/randombytes@2.1.0:
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
dependencies:
safe-buffer: 5.2.1
dev: true
/resolve@1.22.6:
resolution: {integrity: sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==}
hasBin: true
dependencies:
is-core-module: 2.13.0
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
dev: true
/rollup-plugin-summary@2.0.0(rollup@3.29.4):
resolution: {integrity: sha512-7Av6DQeCmVNpFmCdkkbMya1CneeGWhjSXXQ3B4yDO+BvN/Kbohqi3IEYXAvgHP3iIafSfMyOw+PBLFUlvf1ViA==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^2.68.0||^3.0.0
dependencies:
brotli-size: 4.0.0
cli-table3: 0.6.3
filesize: 10.1.0
gzip-size: 7.0.0
rollup: 3.29.4
terser: 5.21.0
dev: true
/rollup@3.29.4:
resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
hasBin: true
optionalDependencies:
fsevents: 2.3.3
dev: true
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
/serialize-javascript@6.0.1:
resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==}
dependencies:
randombytes: 2.1.0
dev: true
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
dev: true
/shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
dev: true
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
dev: true
/smob@1.4.1:
resolution: {integrity: sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==}
dev: true
/source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
dependencies:
emoji-regex: 8.0.0
is-fullwidth-code-point: 3.0.0
strip-ansi: 6.0.1
dev: true
/string-width@5.1.2:
resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==}
engines: {node: '>=12'}
dependencies:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
dev: true
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: true
/strip-ansi@7.1.0:
resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==}
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
dev: true
/supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
dev: true
/terser@5.21.0:
resolution: {integrity: sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==}
engines: {node: '>=10'}
hasBin: true
dependencies:
'@jridgewell/source-map': 0.3.5
acorn: 8.10.0
commander: 2.20.3
source-map-support: 0.5.21
dev: true
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
dev: true
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
dev: true
/wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
strip-ansi: 6.0.1
dev: true
/wrap-ansi@8.1.0:
resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==}
engines: {node: '>=12'}
dependencies:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
dev: true

@ -1,9 +1,7 @@
extends:
- requarks
- plugin:vue/strongly-recommended
env:
node: true
jest: true
parserOptions:
parser: babel-eslint
ecmaVersion: 2020
@ -16,9 +14,8 @@ globals:
ignorePatterns:
- '**/node_modules/**'
- '**/*.min.js'
- 'assets/**'
- 'coverage/**'
- 'repo/**'
- 'data/**'
- 'logs/**'
- 'server/locales/**'
- 'locales/**'

@ -122,6 +122,48 @@ export default {
return generateError(err)
}
},
/**
* Deactivate 2FA
*/
async deactivateTFA (obj, args, context) {
try {
const userId = context.req.user?.id
if (!userId) {
throw new Error('ERR_USER_NOT_AUTHENTICATED')
}
const usr = await WIKI.db.users.query().findById(userId)
if (!usr) {
throw new Error('ERR_INVALID_USER')
}
const str = WIKI.auth.strategies[args.strategyId]
if (!str) {
throw new Error('ERR_INVALID_STRATEGY')
}
if (!usr.auth[args.strategyId]) {
throw new Error('ERR_INVALID_STRATEGY')
}
if (!usr.auth[args.strategyId].tfaIsActive) {
throw new Error('ERR_TFA_NOT_ACTIVE')
}
usr.auth[args.strategyId].tfaIsActive = false
usr.auth[args.strategyId].tfaSecret = null
await usr.$query().patch({
auth: usr.auth
})
return {
operation: generateSuccess('TFA deactivated successfully.')
}
} catch (err) {
return generateError(err)
}
},
/**
* Perform Password Change
*/

@ -412,8 +412,8 @@ export default {
strategyIcon: authModule.icon,
config: authStrategy.module === 'local' ? {
isPasswordSet: value.password?.length > 0,
isTfaSetup: value.tfaSecret?.length > 0,
isTfaRequired: value.tfaRequired ?? false,
isTfaSetup: value.tfaIsActive && value.tfaSecret?.length > 0,
isTfaRequired: (value.tfaRequired || authStrategy.config.enforceTfa) ?? false,
mustChangePwd: value.mustChangePwd ?? false,
restrictLogin: value.restrictLogin ?? false
} : value

@ -41,6 +41,10 @@ extend type Mutation {
setup: Boolean
): AuthenticationAuthResponse @rateLimit(limit: 5, duration: 60)
deactivateTFA(
strategyId: UUID!
): DefaultResponse
changePassword(
continuationToken: String
currentPassword: String

@ -1131,6 +1131,7 @@
"auth.changePwd.subtitle": "Choose a new password",
"auth.changePwd.success": "Password updated successfully.",
"auth.enterCredentials": "Enter your credentials",
"auth.errors.fields": "One or more fields are invalid.",
"auth.errors.forgotPassword": "Missing or invalid email address.",
"auth.errors.invalidEmail": "Email is invalid.",
"auth.errors.invalidLogin": "Invalid Login",
@ -1152,7 +1153,6 @@
"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.fields": "One or more fields are invalid.",
"auth.fields.email": "Email Address",
"auth.fields.emailUser": "Email / Username",
"auth.fields.name": "Name",
@ -1748,6 +1748,9 @@
"profile.auth": "Authentication",
"profile.authChangePassword": "Change Password",
"profile.authDisableTfa": "Turn Off 2FA",
"profile.authDisableTfaConfirm": "Are you sure you want to disable Two Factor Authentication?",
"profile.authDisableTfaFailed": "Failed to turn off 2FA.",
"profile.authDisableTfaSuccess": "2FA turned off successfully.",
"profile.authInfo": "Your account is associated with the following authentication methods:",
"profile.authLoadingFailed": "Failed to load authentication methods.",
"profile.authModifyTfa": "Modify 2FA",

10642
server/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -36,18 +36,18 @@
"node": ">=18.0"
},
"dependencies": {
"@apollo/server": "4.9.3",
"@apollo/server": "4.9.4",
"@azure/storage-blob": "12.16.0",
"@exlinc/keycloak-passport": "1.0.2",
"@graphql-tools/schema": "10.0.0",
"@graphql-tools/utils": "10.0.1",
"@graphql-tools/utils": "10.0.6",
"@joplin/turndown-plugin-gfm": "1.0.50",
"@root/csr": "0.8.1",
"@root/keypairs": "0.10.3",
"@root/pem": "1.0.4",
"acme": "3.0.3",
"akismet-api": "6.0.0",
"aws-sdk": "2.1463.0",
"aws-sdk": "2.1472.0",
"bcryptjs": "2.4.3",
"chalk": "5.3.0",
"cheerio": "1.0.0-rc.12",
@ -64,8 +64,8 @@
"custom-error-instance": "2.1.2",
"dependency-graph": "0.11.0",
"diff": "5.1.0",
"diff2html": "3.4.43",
"dompurify": "3.0.5",
"diff2html": "3.4.45",
"dompurify": "3.0.6",
"dotize": "0.3.0",
"emoji-regex": "10.2.1",
"eventemitter2": "6.4.9",
@ -73,7 +73,7 @@
"express-brute": "1.0.1",
"express-session": "1.17.3",
"file-type": "18.5.0",
"filesize": "10.0.12",
"filesize": "10.1.0",
"fs-extra": "11.1.1",
"getos": "3.2.1",
"graphql": "16.8.1",
@ -91,13 +91,13 @@
"js-yaml": "4.1.0",
"jsdom": "22.1.0",
"jsonwebtoken": "9.0.2",
"katex": "0.16.8",
"katex": "0.16.9",
"klaw": "4.1.0",
"knex": "2.5.1",
"knex": "3.0.1",
"lodash": "4.17.21",
"lodash-es": "4.17.21",
"luxon": "3.4.3",
"markdown-it": "13.0.1",
"markdown-it": "13.0.2",
"markdown-it-abbr": "1.0.4",
"markdown-it-attrs": "4.1.6",
"markdown-it-decorate": "1.2.2",
@ -114,13 +114,13 @@
"mathjax": "3.2.2",
"mime-types": "2.1.35",
"ms": "2.1.3",
"multer": "1.4.4",
"multer": "1.4.5-lts.1",
"nanoid": "5.0.1",
"node-2fa": "2.0.3",
"node-cache": "5.1.2",
"nodemailer": "6.9.5",
"objection": "3.1.1",
"octokit": "3.1.0",
"objection": "3.1.2",
"octokit": "3.1.1",
"passport": "0.6.0",
"passport-auth0": "1.4.3",
"passport-azure-ad": "4.3.5",
@ -138,7 +138,7 @@
"passport-oauth2": "1.7.0",
"passport-okta-oauth": "0.0.1",
"passport-openidconnect": "0.1.1",
"passport-saml": "3.2.1",
"passport-saml": "3.2.4",
"passport-slack-oauth2": "1.2.0",
"passport-twitch-strategy": "2.2.0",
"pem-jwk": "2.0.0",
@ -147,9 +147,9 @@
"pg-pubsub": "0.8.1",
"pg-query-stream": "4.5.3",
"pg-tsquery": "8.4.1",
"poolifier": "2.7.1",
"poolifier": "2.7.5",
"punycode": "2.3.0",
"puppeteer-core": "21.3.4",
"puppeteer-core": "21.3.8",
"qr-image": "3.2.0",
"remove-markdown": "0.5.0",
"request": "2.88.2",
@ -160,7 +160,7 @@
"semver": "7.5.4",
"serve-favicon": "2.5.0",
"sharp": "0.32.6",
"simple-git": "3.19.1",
"simple-git": "3.20.0",
"socket.io": "4.7.2",
"striptags": "3.2.0",
"tar-fs": "3.0.4",
@ -173,13 +173,13 @@
"yargs": "17.7.2"
},
"devDependencies": {
"eslint": "8.50.0",
"eslint": "8.51.0",
"eslint-config-requarks": "1.0.7",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "6.1.1",
"eslint-plugin-standard": "4.1.0",
"eslint-plugin-standard": "5.0.0",
"nodemon": "3.0.1"
},
"overrides": {

File diff suppressed because it is too large Load Diff

7898
ux/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -13,10 +13,10 @@
"ncu-u": "ncu -u -x codemirror,codemirror-asciidoc"
},
"dependencies": {
"@apollo/client": "3.8.4",
"@apollo/client": "3.8.5",
"@lezer/common": "1.1.0",
"@mdi/font": "7.2.96",
"@quasar/extras": "1.16.6",
"@mdi/font": "7.3.67",
"@quasar/extras": "1.16.7",
"@tiptap/core": "2.1.11",
"@tiptap/extension-code-block": "2.1.11",
"@tiptap/extension-code-block-lowlight": "2.1.11",
@ -48,7 +48,7 @@
"codemirror": "5.65.11",
"codemirror-asciidoc": "1.0.4",
"dependency-graph": "0.11.0",
"filesize": "10.0.12",
"filesize": "10.1.0",
"filesize-parser": "1.5.0",
"fuse.js": "6.6.2",
"graphql": "16.6.0",
@ -56,11 +56,11 @@
"highlight.js": "11.8.0",
"js-cookie": "3.0.5",
"jwt-decode": "3.1.2",
"katex": "0.16.8",
"katex": "0.16.9",
"lodash-es": "4.17.21",
"lowlight": "3.0.0",
"luxon": "3.4.3",
"markdown-it": "13.0.1",
"markdown-it": "13.0.2",
"markdown-it-abbr": "1.0.4",
"markdown-it-attrs": "4.1.6",
"markdown-it-decorate": "1.2.2",
@ -75,7 +75,7 @@
"markdown-it-sup": "1.0.0",
"markdown-it-task-lists": "2.1.1",
"mitt": "3.0.1",
"monaco-editor": "0.43.0",
"monaco-editor": "0.44.0",
"pako": "2.1.0",
"pinia": "2.1.6",
"prosemirror-commands": "1.5.2",
@ -84,8 +84,8 @@
"prosemirror-model": "1.19.3",
"prosemirror-schema-list": "1.3.0",
"prosemirror-state": "1.4.3",
"prosemirror-transform": "1.7.5",
"prosemirror-view": "1.31.8",
"prosemirror-transform": "1.8.0",
"prosemirror-view": "1.32.0",
"pug": "3.0.2",
"quasar": "2.12.7",
"slugify": "1.6.6",
@ -95,9 +95,9 @@
"tippy.js": "6.3.7",
"twemoji": "14.0.2",
"uuid": "9.0.1",
"v-network-graph": "0.9.8",
"v-network-graph": "0.9.10",
"vue": "3.3.4",
"vue-i18n": "9.4.1",
"vue-i18n": "9.5.0",
"vue-router": "4.2.5",
"vue3-otp-input": "0.4.1",
"vuedraggable": "4.1.0",
@ -105,13 +105,13 @@
"zxcvbn": "4.4.2"
},
"devDependencies": {
"@intlify/unplugin-vue-i18n": "1.2.0",
"@intlify/unplugin-vue-i18n": "1.4.0",
"@quasar/app-vite": "1.6.2",
"@types/lodash": "4.14.199",
"@volar/vue-language-plugin-pug": "1.6.5",
"@vue/language-plugin-pug": "1.8.16",
"autoprefixer": "10.4.16",
"browserlist": "latest",
"eslint": "8.50.0",
"eslint": "8.51.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-n": "16.1.0",

File diff suppressed because it is too large Load Diff

@ -0,0 +1,248 @@
<template lang="pug">
q-dialog(ref='dialogRef', @hide='onDialogHide')
q-card(style='min-width: 650px;')
q-card-section.card-header
q-icon(name='img:/_assets/icons/fluent-password-reset.svg', left, size='sm')
span {{t(`admin.users.changePassword`)}}
q-form.q-py-sm(ref='changeUserPwdForm', @submit='save')
q-item
blueprint-icon(icon='lock')
q-item-section
q-input(
outlined
v-model='state.currentPassword'
dense
:rules='currentPasswordValidation'
hide-bottom-space
:label='t(`auth.changePwd.currentPassword`)'
:aria-label='t(`auth.changePwd.currentPassword`)'
lazy-rules='ondemand'
autofocus
)
q-item
blueprint-icon(icon='password')
q-item-section
q-input(
outlined
v-model='state.newPassword'
dense
:rules='newPasswordValidation'
hide-bottom-space
:label='t(`auth.changePwd.newPassword`)'
:aria-label='t(`auth.changePwd.newPassword`)'
lazy-rules='ondemand'
autofocus
)
template(#append)
.flex.items-center
q-badge(
:color='passwordStrength.color'
:label='passwordStrength.label'
)
q-separator.q-mx-sm(vertical)
q-btn(
flat
dense
padding='none xs'
color='brown'
@click='randomizePassword'
)
q-icon(name='las la-dice-d6')
.q-pl-xs.text-caption: strong Generate
q-item
blueprint-icon(icon='good-pincode')
q-item-section
q-input(
outlined
v-model='state.verifyPassword'
dense
:rules='verifyPasswordValidation'
hide-bottom-space
:label='t(`auth.changePwd.newPasswordVerify`)'
:aria-label='t(`auth.changePwd.newPasswordVerify`)'
lazy-rules='ondemand'
autofocus
)
q-card-actions.card-actions
q-space
q-btn.acrylic-btn(
flat
:label='t(`common.actions.cancel`)'
color='grey'
padding='xs md'
@click='onDialogCancel'
)
q-btn(
unelevated
:label='t(`common.actions.update`)'
color='primary'
padding='xs md'
@click='save'
:loading='state.isLoading'
)
</template>
<script setup>
import gql from 'graphql-tag'
import zxcvbn from 'zxcvbn'
import { sampleSize } from 'lodash-es'
import { useI18n } from 'vue-i18n'
import { useDialogPluginComponent, useQuasar } from 'quasar'
import { computed, reactive, ref } from 'vue'
import { useSiteStore } from 'src/stores/site'
// PROPS
const props = defineProps({
strategyId: {
type: String,
required: true
}
})
// EMITS
defineEmits([
...useDialogPluginComponent.emits
])
// QUASAR
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
const $q = useQuasar()
// STORES
const siteStore = useSiteStore()
// I18N
const { t } = useI18n()
// DATA
const state = reactive({
currentPassword: '',
newPassword: '',
verifyPassword: '',
isLoading: false
})
// REFS
const changeUserPwdForm = ref(null)
// COMPUTED
const passwordStrength = computed(() => {
if (state.newPassword.length < 8) {
return {
color: 'negative',
label: t('admin.users.pwdStrengthWeak')
}
} else {
switch (zxcvbn(state.newPassword).score) {
case 1:
return {
color: 'deep-orange-7',
label: t('admin.users.pwdStrengthPoor')
}
case 2:
return {
color: 'purple-7',
label: t('admin.users.pwdStrengthMedium')
}
case 3:
return {
color: 'blue-7',
label: t('admin.users.pwdStrengthGood')
}
case 4:
return {
color: 'green-7',
label: t('admin.users.pwdStrengthStrong')
}
default:
return {
color: 'negative',
label: t('admin.users.pwdStrengthWeak')
}
}
}
})
// VALIDATION RULES
const currentPasswordValidation = [
val => val.length > 0 || t('auth.errors.missingPassword')
]
const newPasswordValidation = [
val => val.length > 0 || t('auth.errors.missingPassword'),
val => val.length >= 8 || t('auth.errors.passwordTooShort')
]
const verifyPasswordValidation = [
val => val.length > 0 || t('auth.errors.missingVerifyPassword'),
val => val === state.newPassword || t('auth.errors.passwordsNotMatch')
]
// METHODS
function randomizePassword () {
const pwdChars = 'abcdefghkmnpqrstuvwxyzABCDEFHJKLMNPQRSTUVWXYZ23456789_*=?#!()+'
state.newPassword = sampleSize(pwdChars, 16).join('')
}
async function save () {
state.isLoading = true
try {
const isFormValid = await changeUserPwdForm.value.validate(true)
if (!isFormValid) {
throw new Error(t('auth.errors.fields'))
}
const resp = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation changePwd (
$currentPassword: String
$newPassword: String!
$strategyId: UUID!
$siteId: UUID!
) {
changePassword (
currentPassword: $currentPassword
newPassword: $newPassword
strategyId: $strategyId
siteId: $siteId
) {
operation {
succeeded
message
}
}
}
`,
variables: {
currentPassword: state.currentPassword,
newPassword: state.newPassword,
strategyId: props.strategyId,
siteId: siteStore.id
}
})
if (resp?.data?.changePassword?.operation?.succeeded) {
$q.notify({
type: 'positive',
message: t('auth.changePwd.success')
})
onDialogOK()
} else {
throw new Error(resp?.data?.changePassword?.operation?.message || 'An unexpected error occured.')
}
} catch (err) {
$q.notify({
type: 'negative',
message: err.message
})
}
state.isLoading = false
}
</script>

@ -27,7 +27,8 @@ q-page.q-py-md(:style-fn='pageStyle')
unelevated
:label='t(`profile.authDisableTfa`)'
color='negative'
@click=''
@click='disableTfa(auth.authId)'
:disable='auth.config.isTfaRequired'
)
q-item-section(v-else, side)
q-btn(
@ -35,7 +36,7 @@ q-page.q-py-md(:style-fn='pageStyle')
unelevated
:label='t(`profile.authSetTfa`)'
color='primary'
@click=''
@click='setupTfa(auth.authId)'
)
q-item-section(side)
q-btn(
@ -58,6 +59,7 @@ import { onMounted, reactive } from 'vue'
import { useUserStore } from 'src/stores/user'
import ChangePwdDialog from 'src/components/ChangePwdDialog.vue'
import SetupTfaDialog from 'src/components/SetupTfaDialog.vue'
// QUASAR
@ -139,6 +141,62 @@ function changePassword (strategyId) {
})
}
function disableTfa (strategyId) {
$q.dialog({
title: t('common.actions.confirm'),
message: t('profile.authDisableTfaConfirm'),
cancel: true
}).onOk(async () => {
$q.loading.show()
try {
const resp = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation deactivateTfa (
$strategyId: UUID!
) {
deactivateTFA(
strategyId: $strategyId
) {
operation {
succeeded
message
}
}
}
`,
variables: {
strategyId
}
})
if (resp?.data?.deactivateTFA?.operation?.succeeded) {
$q.notify({
type: 'positive',
message: t('profile.authDisableTfaSuccess')
})
} else {
throw new Error(resp?.data?.deactivateTFA?.operation?.message)
}
} catch (err) {
$q.notify({
type: 'negative',
message: t('profile.authDisableTfaFailed'),
caption: err.message ?? 'An unexpected error occured.'
})
}
await fetchAuthMethods()
$q.loading.hide()
})
}
function setupTfa (strategyId) {
// $q.dialog({
// component: SetupTfaDialog,
// componentProps: {
// strategyId
// }
// })
}
// MOUNTED
onMounted(() => {

Loading…
Cancel
Save