Compare commits
No commits in common. "main" and "v0.3.0" have entirely different histories.
25 changed files with 459 additions and 864 deletions
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -12,34 +12,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
|
||||||
## [0.5.0] - 2023-09-29
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- If the browser uses a dark theme, the default theme is also set to dark
|
|
||||||
- Display the navigation bar on every view, except the creation of the first account
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
- The account deletion view is now emphasized the same way it was before
|
|
||||||
|
|
||||||
|
|
||||||
## [0.4.0] - 2023-09-26
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Possibility to set a default account
|
|
||||||
- Dark mode
|
|
||||||
- Use the browser's preferred language if available
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
- The style has been entirely reworked using Bootstrap instead of Bulma
|
|
||||||
- It is now impossible to include the separator in the dedicated name
|
|
||||||
- When adding a new account, error messages are displayed alongside each affected elements whenever possible
|
|
||||||
- By default, the new sub-address form reset button switches to the default account
|
|
||||||
|
|
||||||
## Fixed
|
|
||||||
- Invalid preferences are now automatically corrected
|
|
||||||
- It is now impossible to add the same account twice
|
|
||||||
|
|
||||||
|
|
||||||
## [0.3.0] - 2023-08-25
|
## [0.3.0] - 2023-08-25
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -51,7 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- The local part cannot contain the separator
|
- The local part cannot contain the separator
|
||||||
- The HTML lang attribute is now set to the appropriate language
|
- The HTML lang attribute is now set to the appropriate language
|
||||||
|
|
||||||
|
|
||||||
## [0.2.0] - 2023-08-11
|
## [0.2.0] - 2023-08-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,19 +0,0 @@
|
||||||
Copyright 2023 Rodolphe Bréard
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
13
README.md
13
README.md
|
@ -1,15 +1,6 @@
|
||||||
# Sub-Address KEy (SAKE) app
|
# Sub-Address KEy (SAKE) app
|
||||||
|
|
||||||
Web application that can be used to generate new sub-addresses as defined in the [Sub-Address KEy (SAKE) filter](https://git.what.tf/rodolphe/opensmtpd-filter-sake).
|
Web application that can be used to generate new sub-addresses as defined in the [Sub-Address KEy (SAKE) filter](https://github.com/breard-r/opensmtpd-filter-sake).
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
Download the build from [the latest released version](https://git.what.tf/rodolphe/sake-app/releases). Extract the archive and configure your web server to serve those files.
|
|
||||||
|
|
||||||
That's it. The final build is plain HTML/CSS/JS with a few assets, therefore there is no back-end to configure.
|
|
||||||
|
|
||||||
Alternatively, on ArchLinux you can install the [sake-app](https://aur.archlinux.org/packages/sake-app) package from the AUR. You will find the files in the `/usr/share/webapps/sake-app` directory.
|
|
||||||
|
|
||||||
|
|
||||||
## Project Setup
|
## Project Setup
|
||||||
|
|
||||||
|
@ -34,7 +25,7 @@ npm run build
|
||||||
|
|
||||||
## Can I use this app without self-hosting it?
|
## Can I use this app without self-hosting it?
|
||||||
|
|
||||||
Yes, you can use [https://sake.email/](https://sake.email/). This instance is kept up to date.
|
Unfortunately, although it would be ok, there is currently no known hosted version of this application. This should change in the future.
|
||||||
|
|
||||||
## Can I use this app completely offline?
|
## Can I use this app completely offline?
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="UTF-8">
|
||||||
<link rel="icon" href="favicon.ico">
|
<link rel="icon" href="favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Sub-Address KEy</title>
|
<title>Sub-Address KEy</title>
|
||||||
|
|
486
package-lock.json
generated
486
package-lock.json
generated
|
@ -1,36 +1,34 @@
|
||||||
{
|
{
|
||||||
"name": "sake-app",
|
"name": "sake-app",
|
||||||
"version": "0.5.0",
|
"version": "0.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "sake-app",
|
"name": "sake-app",
|
||||||
"version": "0.5.0",
|
"version": "0.2.0",
|
||||||
"license": "(MIT OR Apache-2.0)",
|
"license": "(MIT OR Apache-2.0)",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "^1.3.1",
|
"@noble/hashes": "^1.3.1",
|
||||||
"@popperjs/core": "^2.11.8",
|
|
||||||
"@vueuse/core": "^10.2.1",
|
"@vueuse/core": "^10.2.1",
|
||||||
"base32-encode": "^2.0.0",
|
"base32-encode": "^2.0.0",
|
||||||
"bootstrap": "^5.3.2",
|
"bulma": "^0.9.4",
|
||||||
"bootswatch": "^5.3.2",
|
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-qrcode-reader": "^5.1.0",
|
"vue-qrcode-reader": "^5.1.0",
|
||||||
"vue-router": "^4.2.4"
|
"vue-router": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@intlify/unplugin-vue-i18n": "^1.2.0",
|
"@intlify/unplugin-vue-i18n": "^0.12.2",
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"sass": "^1.64.1",
|
"sass": "^1.64.1",
|
||||||
"vite": "^4.4.6"
|
"vite": "^4.4.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.23.0",
|
"version": "7.22.11",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz",
|
||||||
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
|
"integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
},
|
},
|
||||||
|
@ -391,21 +389,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/bundle-utils": {
|
"node_modules/@intlify/bundle-utils": {
|
||||||
"version": "7.4.0",
|
"version": "7.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-7.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-7.0.2.tgz",
|
||||||
"integrity": "sha512-AQfjBe2HUxzyN8ignIk3WhhSuVcSuirgzOzkd17nb337rCbI4Gv/t1R60UUyIqFoFdviLb/wLcDUzTD/xXjv9w==",
|
"integrity": "sha512-8wbx9xhbawBFTE5LPTECiK26RRqrNS31jyWSur72ZXZZ4it5jiZTcG6eUJlNirr4+jXYio2DGY299JsGVT4cpw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/message-compiler": "^9.4.0",
|
"@intlify/message-compiler": "9.3.0-beta.24",
|
||||||
"@intlify/shared": "^9.4.0",
|
"@intlify/shared": "9.3.0-beta.24",
|
||||||
"acorn": "^8.8.2",
|
"acorn": "^8.8.2",
|
||||||
"escodegen": "^2.0.0",
|
"escodegen": "^2.0.0",
|
||||||
"estree-walker": "^2.0.2",
|
"estree-walker": "^2.0.2",
|
||||||
"jsonc-eslint-parser": "^2.3.0",
|
"jsonc-eslint-parser": "^1.0.1",
|
||||||
"magic-string": "^0.30.0",
|
"magic-string": "^0.30.0",
|
||||||
"mlly": "^1.2.0",
|
"mlly": "^1.2.0",
|
||||||
"source-map-js": "^1.0.1",
|
"source-map-js": "^1.0.1",
|
||||||
"yaml-eslint-parser": "^1.2.2"
|
"yaml-eslint-parser": "^0.3.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14.16"
|
"node": ">= 14.16"
|
||||||
|
@ -420,26 +418,65 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/core-base": {
|
"node_modules/@intlify/core-base": {
|
||||||
"version": "9.5.0",
|
"version": "9.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz",
|
||||||
"integrity": "sha512-y3ufM1RJbI/DSmJf3lYs9ACq3S/iRvaSsE3rPIk0MGH7fp+JxU6rdryv/EYcwfcr3Y1aHFlCBir6S391hRZ57w==",
|
"integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/message-compiler": "9.5.0",
|
"@intlify/devtools-if": "9.2.2",
|
||||||
"@intlify/shared": "9.5.0"
|
"@intlify/message-compiler": "9.2.2",
|
||||||
|
"@intlify/shared": "9.2.2",
|
||||||
|
"@intlify/vue-devtools": "9.2.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16"
|
"node": ">= 14"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"funding": {
|
"node_modules/@intlify/core-base/node_modules/@intlify/message-compiler": {
|
||||||
"url": "https://github.com/sponsors/kazupon"
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@intlify/shared": "9.2.2",
|
||||||
|
"source-map": "0.6.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@intlify/core-base/node_modules/@intlify/shared": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@intlify/devtools-if": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@intlify/shared": "9.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@intlify/devtools-if/node_modules/@intlify/shared": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/message-compiler": {
|
"node_modules/@intlify/message-compiler": {
|
||||||
"version": "9.5.0",
|
"version": "9.3.0-beta.24",
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.3.0-beta.24.tgz",
|
||||||
"integrity": "sha512-CAhVNfEZcOVFg0/5MNyt+OFjvs4J/ARjCj2b+54/FvFP0EDJI5lIqMTSDBE7k0atMROSP0SvWCkwu/AZ5xkK1g==",
|
"integrity": "sha512-prhHATkgp0mpPqoVgiAtLmUc1JMvs8fMH6w53AVEBn+VF87dLhzanfmWY5FoZWORG51ag54gBDBOoM/VFv3m3A==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/shared": "9.5.0",
|
"@intlify/shared": "9.3.0-beta.24",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -450,9 +487,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/shared": {
|
"node_modules/@intlify/shared": {
|
||||||
"version": "9.5.0",
|
"version": "9.3.0-beta.24",
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.3.0-beta.24.tgz",
|
||||||
"integrity": "sha512-tAxV14LMXZDZbu32XzLMTsowNlgJNmLwWHYzvMUl6L8gvQeoYiZONjY7AUsqZW8TOZDX9lfvF6adPkk9FSRdDA==",
|
"integrity": "sha512-AKxJ8s7eKIQWkNaf4wyyoLRwf4puCuQgjSChlDJm5JBEt6T8HGgnYTJLRXu6LD/JACn3Qwu6hM/XRX1c9yvjmQ==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16"
|
"node": ">= 16"
|
||||||
},
|
},
|
||||||
|
@ -461,13 +499,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@intlify/unplugin-vue-i18n": {
|
"node_modules/@intlify/unplugin-vue-i18n": {
|
||||||
"version": "1.4.0",
|
"version": "0.12.3",
|
||||||
"resolved": "https://registry.npmjs.org/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-0.12.3.tgz",
|
||||||
"integrity": "sha512-RGDchCRBlDTyVVFgPA1C1XC1uD4xYN81Ma+3EnU6GQ8pBEreraX/PWdPXXzOB6k9GWCQHuqii3atYXhcH3rpSg==",
|
"integrity": "sha512-0riPtSfTM58JmGNMmJho/aHD2z3K24BESYAmkLvKlo61/LbaPvnjYU1DbSbJEm6bSjE2oEjUj+di3QaYxXei/w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/bundle-utils": "^7.4.0",
|
"@intlify/bundle-utils": "^7.0.2",
|
||||||
"@intlify/shared": "^9.4.0",
|
"@intlify/shared": "9.3.0-beta.24",
|
||||||
"@rollup/pluginutils": "^5.0.2",
|
"@rollup/pluginutils": "^5.0.2",
|
||||||
"@vue/compiler-sfc": "^3.2.47",
|
"@vue/compiler-sfc": "^3.2.47",
|
||||||
"debug": "^4.3.3",
|
"debug": "^4.3.3",
|
||||||
|
@ -499,6 +537,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@intlify/vue-devtools": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@intlify/core-base": "9.2.2",
|
||||||
|
"@intlify/shared": "9.2.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@intlify/vue-devtools/node_modules/@intlify/shared": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/sourcemap-codec": {
|
"node_modules/@jridgewell/sourcemap-codec": {
|
||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||||
|
@ -550,19 +608,10 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@popperjs/core": {
|
|
||||||
"version": "2.11.8",
|
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/popperjs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@rollup/pluginutils": {
|
"node_modules/@rollup/pluginutils": {
|
||||||
"version": "5.0.4",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.3.tgz",
|
||||||
"integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==",
|
"integrity": "sha512-hfllNN4a80rwNQ9QCxhxuHCGHMAvabXqxNdaChUSSadMre7t4iEUI6fFAhBOn/eIYTgYVhBv7vCLsAJ4u3lf3g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.0",
|
||||||
|
@ -581,13 +630,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@sec-ant/barcode-detector": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@sec-ant/barcode-detector/-/barcode-detector-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-bbw6dq4mZR+dl4kMWDLevMiDUKdFncikvNHMLgoaLf0n16sN011NmpWDYYPjORwZ/tUjF9s8zW7YfSTTEggx5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"@sec-ant/zxing-wasm": "^2.1.2",
|
||||||
|
"@types/dom-webcodecs": "^0.1.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@sec-ant/zxing-wasm": {
|
"node_modules/@sec-ant/zxing-wasm": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@sec-ant/zxing-wasm/-/zxing-wasm-2.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@sec-ant/zxing-wasm/-/zxing-wasm-2.1.2.tgz",
|
||||||
"integrity": "sha512-U8/bq15/qytQ2GOfFeyoL9ItnBLLWlILpG3c0F03iZ3SlEZNJtUWd/DONjDAlbQ90TRzzOFFVw9AQhh75XlANQ==",
|
"integrity": "sha512-IFqipPQNL75RZwL4QkDDGYITGWTIdW967NQufCoblhz1KdLB6YsN+y+3JZAxPUBPw/6GUsnjhPJSeoQQc/Hx9w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/emscripten": "^1.39.7",
|
"@types/emscripten": "^1.39.7",
|
||||||
"zustand": "^4.4.1"
|
"zustand": "^4.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/dom-webcodecs": {
|
"node_modules/@types/dom-webcodecs": {
|
||||||
|
@ -596,14 +654,14 @@
|
||||||
"integrity": "sha512-KThTPaGQJLITk8Q0XkEkz+GqFdoWDyQfbyeJmfEUagB15TZQdNx5AqP2b7GP6vkVM6X/6T1Z8EHxA8RgHfY9BA=="
|
"integrity": "sha512-KThTPaGQJLITk8Q0XkEkz+GqFdoWDyQfbyeJmfEUagB15TZQdNx5AqP2b7GP6vkVM6X/6T1Z8EHxA8RgHfY9BA=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/emscripten": {
|
"node_modules/@types/emscripten": {
|
||||||
"version": "1.39.8",
|
"version": "1.39.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.7.tgz",
|
||||||
"integrity": "sha512-Rk0HKcMXFUuqT32k1kXHZWgxiMvsyYsmlnjp0rLKa0MMoqXLE3T9dogDBTRfuc3SAsXu97KD3k4SKR1lHqd57w=="
|
"integrity": "sha512-tLqYV94vuqDrXh515F/FOGtBcRMTPGvVV1LzLbtYDcQmmhtpf/gLYf+hikBbQk8MzOHNz37wpFfJbYAuSn8HqA=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz",
|
||||||
"integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==",
|
"integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/web-bluetooth": {
|
"node_modules/@types/web-bluetooth": {
|
||||||
|
@ -612,9 +670,9 @@
|
||||||
"integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA=="
|
"integrity": "sha512-4p9vcSmxAayx72yn70joFoL44c9MO/0+iVEBIQXe3v2h2SiAsEIo/G5v6ObFWvNKRFjbrVadNf9LqEEZeQPzdA=="
|
||||||
},
|
},
|
||||||
"node_modules/@vitejs/plugin-vue": {
|
"node_modules/@vitejs/plugin-vue": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.3.3.tgz",
|
||||||
"integrity": "sha512-ciXNIHKPriERBisHFBvnTbfKa6r9SAesOYXeGDzgegcvy9Q4xdScSHAmKbNT0M3O0S9LKhIf5/G+UYG4NnnzYw==",
|
"integrity": "sha512-ssxyhIAZqB0TrpUg6R0cBpCuMk9jTIlO1GNSKKQD6S8VjnXi6JXKfUXjSsxey9IwQiaRGsO1WnW9Rkl1L6AJVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^14.18.0 || >=16.0.0"
|
"node": "^14.18.0 || >=16.0.0"
|
||||||
|
@ -732,13 +790,13 @@
|
||||||
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
"integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/core": {
|
"node_modules/@vueuse/core": {
|
||||||
"version": "10.4.1",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.3.0.tgz",
|
||||||
"integrity": "sha512-DkHIfMIoSIBjMgRRvdIvxsyboRZQmImofLyOHADqiVbQVilP8VVHDhBX2ZqoItOgu7dWa8oXiNnScOdPLhdEXg==",
|
"integrity": "sha512-BEM5yxcFKb5btFjTSAFjTu5jmwoW66fyV9uJIP4wUXXU8aR5Hl44gndaaXp7dC5HSObmgbnR2RN+Un1p68Mf5Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/web-bluetooth": "^0.0.17",
|
"@types/web-bluetooth": "^0.0.17",
|
||||||
"@vueuse/metadata": "10.4.1",
|
"@vueuse/metadata": "10.3.0",
|
||||||
"@vueuse/shared": "10.4.1",
|
"@vueuse/shared": "10.3.0",
|
||||||
"vue-demi": ">=0.14.5"
|
"vue-demi": ">=0.14.5"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
|
@ -746,9 +804,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/core/node_modules/vue-demi": {
|
"node_modules/@vueuse/core/node_modules/vue-demi": {
|
||||||
"version": "0.14.6",
|
"version": "0.14.5",
|
||||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz",
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
|
||||||
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
|
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
@ -771,17 +829,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/metadata": {
|
"node_modules/@vueuse/metadata": {
|
||||||
"version": "10.4.1",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.3.0.tgz",
|
||||||
"integrity": "sha512-2Sc8X+iVzeuMGHr6O2j4gv/zxvQGGOYETYXEc41h0iZXIRnRbJZGmY/QP8dvzqUelf8vg0p/yEA5VpCEu+WpZg==",
|
"integrity": "sha512-Ema3YhNOa4swDsV0V7CEY5JXvK19JI/o1szFO1iWxdFg3vhdFtCtSTP26PCvbUpnUtNHBY2wx5y3WDXND5Pvnw==",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/antfu"
|
"url": "https://github.com/sponsors/antfu"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/shared": {
|
"node_modules/@vueuse/shared": {
|
||||||
"version": "10.4.1",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.3.0.tgz",
|
||||||
"integrity": "sha512-vz5hbAM4qA0lDKmcr2y3pPdU+2EVw/yzfRsBdu+6+USGa4PxqSQRYIUC9/NcT06y+ZgaTsyURw2I9qOFaaXHAg==",
|
"integrity": "sha512-kGqCTEuFPMK4+fNWy6dUOiYmxGcUbtznMwBZLC1PubidF4VZY05B+Oht7Jh7/6x4VOWGpvu3R37WHi81cKpiqg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vue-demi": ">=0.14.5"
|
"vue-demi": ">=0.14.5"
|
||||||
},
|
},
|
||||||
|
@ -790,9 +848,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vueuse/shared/node_modules/vue-demi": {
|
"node_modules/@vueuse/shared/node_modules/vue-demi": {
|
||||||
"version": "0.14.6",
|
"version": "0.14.5",
|
||||||
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz",
|
"resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz",
|
||||||
"integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==",
|
"integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"vue-demi-fix": "bin/vue-demi-fix.js",
|
"vue-demi-fix": "bin/vue-demi-fix.js",
|
||||||
|
@ -854,15 +912,6 @@
|
||||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/barcode-detector": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-2.0.3.tgz",
|
|
||||||
"integrity": "sha512-4d6KAcnsL5SuXhxtz0Z+7qjKqPi6bqrgE2QdocKKWTA33MMR+s2Dx1+YfGEhQ++/sM/MrXT/hTBzgG8XL4dAgg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@sec-ant/zxing-wasm": "2.1.5",
|
|
||||||
"@types/dom-webcodecs": "^0.1.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/base32-encode": {
|
"node_modules/base32-encode": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/base32-encode/-/base32-encode-2.0.0.tgz",
|
||||||
|
@ -883,29 +932,6 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bootstrap": {
|
|
||||||
"version": "5.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz",
|
|
||||||
"integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==",
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"type": "github",
|
|
||||||
"url": "https://github.com/sponsors/twbs"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/bootstrap"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"peerDependencies": {
|
|
||||||
"@popperjs/core": "^2.11.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/bootswatch": {
|
|
||||||
"version": "5.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.3.2.tgz",
|
|
||||||
"integrity": "sha512-r05xOSLSx7MJvjpk/uoU8wPYgkPHWLV+uenLaRsS7yBsqSUcWYPjeUkz+tmrRv6s1eFxkF08NvQfBSSPCTyYaA=="
|
|
||||||
},
|
|
||||||
"node_modules/braces": {
|
"node_modules/braces": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
|
@ -918,6 +944,11 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/bulma": {
|
||||||
|
"version": "0.9.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.4.tgz",
|
||||||
|
"integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ=="
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||||
|
@ -1025,33 +1056,54 @@
|
||||||
"source-map": "~0.6.1"
|
"source-map": "~0.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-visitor-keys": {
|
"node_modules/eslint-utils": {
|
||||||
"version": "3.4.3",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
|
||||||
"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
|
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"eslint-visitor-keys": "^1.1.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": ">=6"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://github.com/sponsors/mysticatea"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eslint-visitor-keys": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "9.6.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
||||||
"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
|
"integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.9.0",
|
"acorn": "^7.1.1",
|
||||||
"acorn-jsx": "^5.3.2",
|
"acorn-jsx": "^5.2.0",
|
||||||
"eslint-visitor-keys": "^3.4.1"
|
"eslint-visitor-keys": "^1.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"funding": {
|
"node_modules/espree/node_modules/acorn": {
|
||||||
"url": "https://opencollective.com/eslint"
|
"version": "7.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
|
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/esprima": {
|
"node_modules/esprima": {
|
||||||
|
@ -1154,9 +1206,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/immutable": {
|
"node_modules/immutable": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.3.tgz",
|
||||||
"integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==",
|
"integrity": "sha512-808ZFYMsIRAjLAu5xkKo0TsbY9LBy9H5MazTKIEHerNkg0ymgilGfBPMR/3G7d/ihGmuK2Hw8S1izY2d3kd3wA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/is-binary-path": {
|
"node_modules/is-binary-path": {
|
||||||
|
@ -1232,21 +1284,31 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jsonc-eslint-parser": {
|
"node_modules/jsonc-eslint-parser": {
|
||||||
"version": "2.3.0",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-1.4.1.tgz",
|
||||||
"integrity": "sha512-9xZPKVYp9DxnM3sd1yAsh/d59iIaswDkai8oTxbursfKYbg/ibjX0IzFt35+VZ8iEW453TVTXztnRvYUQlAfUQ==",
|
"integrity": "sha512-hXBrvsR1rdjmB2kQmUjf1rEIa+TqHBGMge8pwi++C+Si1ad7EjZrJcpgwym+QGK/pqTx+K7keFAtLlVNdLRJOg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.5.0",
|
"acorn": "^7.4.1",
|
||||||
"eslint-visitor-keys": "^3.0.0",
|
"eslint-utils": "^2.1.0",
|
||||||
"espree": "^9.0.0",
|
"eslint-visitor-keys": "^1.3.0",
|
||||||
"semver": "^7.3.5"
|
"espree": "^6.0.0",
|
||||||
|
"semver": "^6.3.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": ">=8.10.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"funding": {
|
"node_modules/jsonc-eslint-parser/node_modules/acorn": {
|
||||||
"url": "https://github.com/sponsors/ota-meshi"
|
"version": "7.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
|
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"acorn": "bin/acorn"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jsonc-parser": {
|
"node_modules/jsonc-parser": {
|
||||||
|
@ -1273,22 +1335,10 @@
|
||||||
"loose-envify": "cli.js"
|
"loose-envify": "cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lru-cache": {
|
|
||||||
"version": "6.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
|
||||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"yallist": "^4.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/magic-string": {
|
"node_modules/magic-string": {
|
||||||
"version": "0.30.4",
|
"version": "0.30.3",
|
||||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.4.tgz",
|
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
|
||||||
"integrity": "sha512-Q/TKtsC5BPm0kGqgBIF9oXAs/xEf2vRKiIB4wCRQTJOQIByZ1d+NnUOotvJOvNpi5RNIgVOMC3pOuaP1ZTDlVg==",
|
"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||||
},
|
},
|
||||||
|
@ -1319,15 +1369,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mlly": {
|
"node_modules/mlly": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz",
|
||||||
"integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==",
|
"integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.10.0",
|
"acorn": "^8.9.0",
|
||||||
"pathe": "^1.1.1",
|
"pathe": "^1.1.1",
|
||||||
"pkg-types": "^1.0.3",
|
"pkg-types": "^1.0.3",
|
||||||
"ufo": "^1.3.0"
|
"ufo": "^1.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
|
@ -1397,9 +1447,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.31",
|
"version": "8.4.28",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
|
||||||
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
"integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
@ -1478,9 +1528,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "3.29.4",
|
"version": "3.28.1",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz",
|
||||||
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
|
"integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
|
@ -1517,9 +1567,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/sass": {
|
"node_modules/sass": {
|
||||||
"version": "1.68.0",
|
"version": "1.66.1",
|
||||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz",
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.66.1.tgz",
|
||||||
"integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==",
|
"integrity": "sha512-50c+zTsZOJVgFfTgwwEzkjA3/QACgdNsKueWPyAR0mRINIvLAStVQBbPg14iuqEQ74NPDbXzJARJ/O4SI1zftA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": ">=3.0.0 <4.0.0",
|
"chokidar": ">=3.0.0 <4.0.0",
|
||||||
|
@ -1539,26 +1589,18 @@
|
||||||
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
|
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
|
||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "7.5.4",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
|
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
|
||||||
"lru-cache": "^6.0.0"
|
|
||||||
},
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true,
|
|
||||||
"optional": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
@ -1592,18 +1634,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ufo": {
|
"node_modules/ufo": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.0.tgz",
|
||||||
"integrity": "sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==",
|
"integrity": "sha512-bRn3CsoojyNStCZe0BG0Mt4Nr/4KF+rhFlnNXybgqt5pXHNFRlqinSoQaTrGyzE4X8aHplSb+TorH+COin9Yxw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/unplugin": {
|
"node_modules/unplugin": {
|
||||||
"version": "1.5.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.4.0.tgz",
|
||||||
"integrity": "sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==",
|
"integrity": "sha512-5x4eIEL6WgbzqGtF9UV8VEC/ehKptPXDS6L2b0mv4FRMkJxRtjaJfOWDd6a8+kYbqsjklix7yWP0N3SUepjXcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acorn": "^8.10.0",
|
"acorn": "^8.9.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"webpack-sources": "^3.2.3",
|
"webpack-sources": "^3.2.3",
|
||||||
"webpack-virtual-modules": "^0.5.0"
|
"webpack-virtual-modules": "^0.5.0"
|
||||||
|
@ -1685,40 +1727,46 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-i18n": {
|
"node_modules/vue-i18n": {
|
||||||
"version": "9.5.0",
|
"version": "9.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz",
|
||||||
"integrity": "sha512-NiI3Ph1qMstNf7uhYh8trQBOBFLxeJgcOxBq51pCcZ28Vs18Y7BDS58r8HGDKCYgXdLUYqPDXdKatIF4bvBVZg==",
|
"integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@intlify/core-base": "9.5.0",
|
"@intlify/core-base": "9.2.2",
|
||||||
"@intlify/shared": "9.5.0",
|
"@intlify/shared": "9.2.2",
|
||||||
"@vue/devtools-api": "^6.5.0"
|
"@intlify/vue-devtools": "9.2.2",
|
||||||
|
"@vue/devtools-api": "^6.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16"
|
"node": ">= 14"
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/kazupon"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "^3.0.0"
|
"vue": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-i18n/node_modules/@intlify/shared": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-qrcode-reader": {
|
"node_modules/vue-qrcode-reader": {
|
||||||
"version": "5.3.6",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/vue-qrcode-reader/-/vue-qrcode-reader-5.3.0.tgz",
|
||||||
"integrity": "sha512-LBhP3bgYUde6hRNFcIoTPGs26zUMDdOmE4bYolKk2SoiCxxg6icCKjv98i7pP2KcHBScAmZ11X2ha8Tovs+O+A==",
|
"integrity": "sha512-PuR9aJvEmoe1xNRT/hRqfR5VRP+SnBy0rvtu7jFZnzLtyqyfxLa78X4/1Xa1EPSrUKC0480jV8qg6OvB7IlYZQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"barcode-detector": "2.0.3",
|
"@sec-ant/barcode-detector": "^1.1.2",
|
||||||
"webrtc-adapter": "^8.2.3"
|
"webrtc-adapter": "^8.2.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-router": {
|
"node_modules/vue-router": {
|
||||||
"version": "4.2.5",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.4.tgz",
|
||||||
"integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==",
|
"integrity": "sha512-9PISkmaCO02OzPVOMq2w82ilty6+xJmQrarYZDkjZBfl4RvYAlt4PKnEX21oW4KTtWfa9OuO/b3qk1Od3AEdCQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-api": "^6.5.0"
|
"@vue/devtools-api": "^6.5.0"
|
||||||
},
|
},
|
||||||
|
@ -1756,36 +1804,24 @@
|
||||||
"npm": ">=3.10.0"
|
"npm": ">=3.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yallist": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
|
||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"node_modules/yaml": {
|
"node_modules/yaml": {
|
||||||
"version": "2.3.2",
|
"version": "1.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||||
"integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==",
|
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 14"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/yaml-eslint-parser": {
|
"node_modules/yaml-eslint-parser": {
|
||||||
"version": "1.2.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-0.3.2.tgz",
|
||||||
"integrity": "sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==",
|
"integrity": "sha512-32kYO6kJUuZzqte82t4M/gB6/+11WAuHiEnK7FreMo20xsCKPeFH5tDBU7iWxR7zeJpNnMXfJyXwne48D0hGrg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eslint-visitor-keys": "^3.0.0",
|
"eslint-visitor-keys": "^1.3.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.20",
|
||||||
"yaml": "^2.0.0"
|
"yaml": "^1.10.0"
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^14.17.0 || >=16.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ota-meshi"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/zustand": {
|
"node_modules/zustand": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "sake-app",
|
"name": "sake-app",
|
||||||
"version": "0.5.0",
|
"version": "0.3.0",
|
||||||
"author": "Rodolphe Bréard <rodolphe@what.tf>",
|
"author": "Rodolphe Bréard <rodolphe@what.tf>",
|
||||||
"license": "(MIT OR Apache-2.0)",
|
"license": "(MIT OR Apache-2.0)",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -15,18 +15,16 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "^1.3.1",
|
"@noble/hashes": "^1.3.1",
|
||||||
"@popperjs/core": "^2.11.8",
|
|
||||||
"@vueuse/core": "^10.2.1",
|
"@vueuse/core": "^10.2.1",
|
||||||
"base32-encode": "^2.0.0",
|
"base32-encode": "^2.0.0",
|
||||||
"bootstrap": "^5.3.2",
|
"bulma": "^0.9.4",
|
||||||
"bootswatch": "^5.3.2",
|
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-i18n": "^9.2.2",
|
"vue-i18n": "^9.2.2",
|
||||||
"vue-qrcode-reader": "^5.1.0",
|
"vue-qrcode-reader": "^5.1.0",
|
||||||
"vue-router": "^4.2.4"
|
"vue-router": "^4.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@intlify/unplugin-vue-i18n": "^1.2.0",
|
"@intlify/unplugin-vue-i18n": "^0.12.2",
|
||||||
"@vitejs/plugin-vue": "^4.2.3",
|
"@vitejs/plugin-vue": "^4.2.3",
|
||||||
"sass": "^1.64.1",
|
"sass": "^1.64.1",
|
||||||
"vite": "^4.4.6"
|
"vite": "^4.4.6"
|
||||||
|
|
10
release.sh
10
release.sh
|
@ -27,13 +27,6 @@ update_app_version()
|
||||||
jq ".version = \"${new_version}\"" "package.json" >"${tmp_file}"
|
jq ".version = \"${new_version}\"" "package.json" >"${tmp_file}"
|
||||||
mv "${tmp_file}" "package.json"
|
mv "${tmp_file}" "package.json"
|
||||||
sed -i "s/## \[Unreleased\]/## \[${new_version}\] - ${current_date}/" "CHANGELOG.md"
|
sed -i "s/## \[Unreleased\]/## \[${new_version}\] - ${current_date}/" "CHANGELOG.md"
|
||||||
update_dependencies
|
|
||||||
}
|
|
||||||
|
|
||||||
update_dependencies()
|
|
||||||
{
|
|
||||||
npm update
|
|
||||||
npm outdated
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_working_directory()
|
check_working_directory()
|
||||||
|
@ -54,8 +47,6 @@ build_assets()
|
||||||
|
|
||||||
npm run --silent build >/dev/null
|
npm run --silent build >/dev/null
|
||||||
cp -r "dist" "${asset_dir}"
|
cp -r "dist" "${asset_dir}"
|
||||||
cp "LICENSE-APACHE-2.0.txt" "${asset_dir}"
|
|
||||||
cp "LICENSE-MIT.txt" "${asset_dir}"
|
|
||||||
rm -f "${asset_dir}/manifest.webmanifest" "${asset_dir}/sw.js"
|
rm -f "${asset_dir}/manifest.webmanifest" "${asset_dir}/sw.js"
|
||||||
|
|
||||||
tar czf "${asset_dir}.tar.gz" "${asset_dir}"
|
tar czf "${asset_dir}.tar.gz" "${asset_dir}"
|
||||||
|
@ -112,7 +103,6 @@ main()
|
||||||
local new_version
|
local new_version
|
||||||
local confirm_release
|
local confirm_release
|
||||||
|
|
||||||
update_dependencies
|
|
||||||
check_working_directory
|
check_working_directory
|
||||||
|
|
||||||
display_app_version
|
display_app_version
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export function sortAccounts(accounts) {
|
export function sortAccounts(accounts) {
|
||||||
accounts.sort((a, b) => {
|
accounts.value.sort((a, b) => {
|
||||||
const va = `${a.localPart}@${a.domain}`;
|
const va = `${a.localPart}@${a.domain}`;
|
||||||
const vb = `${b.localPart}@${b.domain}`;
|
const vb = `${b.localPart}@${b.domain}`;
|
||||||
return va.localeCompare(vb);
|
return va.localeCompare(vb);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
@charset "utf-8"
|
@charset "utf-8"
|
||||||
|
|
||||||
@import "bootswatch/dist/minty/variables"
|
@import "node_modules/bulma/bulma"
|
||||||
@import "variables.scss"
|
|
||||||
@import "bootstrap/scss/bootstrap"
|
a[href]
|
||||||
@import "bootswatch/dist/minty/bootswatch"
|
text-decoration: underline
|
||||||
|
|
||||||
|
.navbar-menu a[class~="navbar-item"]
|
||||||
|
text-decoration: none
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
$container-max-widths: (
|
|
||||||
sm: 600px,
|
|
||||||
md: 700px,
|
|
||||||
lg: 800px,
|
|
||||||
xl: 820px,
|
|
||||||
xxl: 840px
|
|
||||||
);
|
|
||||||
$web-font-path: false;
|
|
|
@ -1,5 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="d-grid gap-2 col-6 mx-auto">
|
|
||||||
<slot></slot>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
|
@ -1,5 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
|
<section class="section">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="columns is-centered">
|
||||||
|
<div class="column is-three-fifths">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { RouterLink } from 'vue-router';
|
import { RouterLink } from 'vue-router';
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
|
||||||
import { Popover } from 'bootstrap';
|
const menuActive = ref(false);
|
||||||
|
const toggleBurger = () => {
|
||||||
|
menuActive.value = !menuActive.value;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<nav class="navbar navbar-expand-lg bg-primary" data-bs-theme="dark">
|
<div class="container">
|
||||||
<div class="container-fluid">
|
<div class="columns is-centered">
|
||||||
<span class="navbar-brand"></span>
|
<div class="column is-three-fifths">
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNavBar" aria-controls="mainNavBar" aria-expanded="false" aria-label="Toggle navigation">
|
<nav class="navbar" role="navigation" aria-label="main navigation">
|
||||||
<span class="navbar-toggler-icon"></span>
|
<div class="navbar-brand">
|
||||||
</button>
|
<a role="button" class="navbar-burger" :class="{ 'is-active': menuActive }" aria-label="menu" aria-expanded="false" @click="toggleBurger">
|
||||||
<div class="collapse navbar-collapse" id="mainNavBar">
|
<span aria-hidden="true"></span>
|
||||||
<LayoutComponent>
|
<span aria-hidden="true"></span>
|
||||||
<ul class="navbar-nav justify-content-end flex-grow-1 pe-3">
|
<span aria-hidden="true"></span>
|
||||||
<li class="nav-item">
|
</a>
|
||||||
<RouterLink to="/add-account" class="nav-link">{{ $t("navbar.addAccount") }}</RouterLink>
|
</div>
|
||||||
</li>
|
<div class="navbar-menu" :class="{ 'is-active': menuActive }">
|
||||||
<li class="nav-item">
|
<div class="navbar-end">
|
||||||
<RouterLink to="/manage-accounts" class="nav-link">{{ $t("navbar.manageAccounts") }}</RouterLink>
|
<RouterLink to="/add-account" class="navbar-item">{{ $t("navbar.addAccount") }}</RouterLink>
|
||||||
</li>
|
<RouterLink to="/manage-accounts" class="navbar-item">{{ $t("navbar.manageAccounts") }}</RouterLink>
|
||||||
<li class="nav-item">
|
<RouterLink to="/config" class="navbar-item">{{ $t("navbar.config") }}</RouterLink>
|
||||||
<RouterLink to="/config" class="nav-link">{{ $t("navbar.config") }}</RouterLink>
|
<RouterLink to="/about" class="navbar-item">{{ $t("navbar.about") }}</RouterLink>
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<RouterLink to="/about" class="nav-link">{{ $t("navbar.about") }}</RouterLink>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</LayoutComponent>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
export const allowedColorModes = [
|
|
||||||
'light',
|
|
||||||
'dark',
|
|
||||||
];
|
|
||||||
export const allowedLocales = [
|
|
||||||
'en',
|
|
||||||
'fr',
|
|
||||||
];
|
|
||||||
export const resetToDefaultAccount = true;
|
|
|
@ -32,11 +32,9 @@
|
||||||
"domainName": "Domain name",
|
"domainName": "Domain name",
|
||||||
"privateKey": "Private key",
|
"privateKey": "Private key",
|
||||||
"scan": "Scan",
|
"scan": "Scan",
|
||||||
"scanTitle": "Scan a QR code",
|
|
||||||
"addAccount": "Add account",
|
"addAccount": "Add account",
|
||||||
"cancel": "@:invariants.controls.cancel",
|
"cancel": "@:invariants.controls.cancel",
|
||||||
"error": {
|
"error": {
|
||||||
"accountAlreadyExists": "You already have an account on this domain that uses this local part.",
|
|
||||||
"invalidBase64": "The key must be a valid base64 string.",
|
"invalidBase64": "The key must be a valid base64 string.",
|
||||||
"invalidKeyLength": "The key's length must be either 128 bits (16 bytes) or 256 bits (32 bytes).",
|
"invalidKeyLength": "The key's length must be either 128 bits (16 bytes) or 256 bits (32 bytes).",
|
||||||
"invalidSeparator": "The separator must be a single character.",
|
"invalidSeparator": "The separator must be a single character.",
|
||||||
|
@ -53,10 +51,6 @@
|
||||||
"config": {
|
"config": {
|
||||||
"title": "Preferences",
|
"title": "Preferences",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"colorMode": "Theme",
|
|
||||||
"resetToDefault": "Switch to the default account when the new sub-address form is reset",
|
|
||||||
"lightTheme": "Light",
|
|
||||||
"darkTheme": "Dark",
|
|
||||||
"close": "@:invariants.controls.close"
|
"close": "@:invariants.controls.close"
|
||||||
},
|
},
|
||||||
"deleteAccount": {
|
"deleteAccount": {
|
||||||
|
@ -77,8 +71,6 @@
|
||||||
},
|
},
|
||||||
"manageAccounts": {
|
"manageAccounts": {
|
||||||
"title": "Accounts",
|
"title": "Accounts",
|
||||||
"isDefault": "default",
|
|
||||||
"setDefault": "Set default",
|
|
||||||
"delete": "@:invariants.controls.delete",
|
"delete": "@:invariants.controls.delete",
|
||||||
"close": "@:invariants.controls.close"
|
"close": "@:invariants.controls.close"
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,14 +32,12 @@
|
||||||
"domainName": "Nom de domaine",
|
"domainName": "Nom de domaine",
|
||||||
"privateKey": "Clé privée",
|
"privateKey": "Clé privée",
|
||||||
"scan": "Scanner",
|
"scan": "Scanner",
|
||||||
"scanTitle": "Scanner un QR code",
|
|
||||||
"addAccount": "Ajouter",
|
"addAccount": "Ajouter",
|
||||||
"cancel": "@:invariants.controls.cancel",
|
"cancel": "@:invariants.controls.cancel",
|
||||||
"error": {
|
"error": {
|
||||||
"accountAlreadyExists": "Vous avez déjà un compte sur ce nom de domaine qui utilise cette partie locale.",
|
|
||||||
"invalidBase64": "La clé doit être une chaîne de caractère en base64.",
|
"invalidBase64": "La clé doit être une chaîne de caractère en base64.",
|
||||||
"invalidKeyLength": "La longueur de la clé doit être de 128 bits (16 bytes) ou de 256 bits (32 bytes).",
|
"invalidKeyLength": "La longueur de la clé doit être de 128 bits (16 bytes) ou de 256 bits (32 bytes).",
|
||||||
"invalidSeparator": "Le séparateur doit être un unique caractère.",
|
"invalidSeparator": "La séparateur doit être un unique caractère.",
|
||||||
"cameraNotAllowed": "L'accès à la caméra n'a pas été autorisé.",
|
"cameraNotAllowed": "L'accès à la caméra n'a pas été autorisé.",
|
||||||
"cameraNotFound": "Aucune caméra détectée.",
|
"cameraNotFound": "Aucune caméra détectée.",
|
||||||
"cameraInsecureContext": "Impossible d'accéder à la caméra depuis une liaison non-sécurisée.",
|
"cameraInsecureContext": "Impossible d'accéder à la caméra depuis une liaison non-sécurisée.",
|
||||||
|
@ -53,10 +51,6 @@
|
||||||
"config": {
|
"config": {
|
||||||
"title": "Préférences",
|
"title": "Préférences",
|
||||||
"language": "Langue",
|
"language": "Langue",
|
||||||
"colorMode": "Thème",
|
|
||||||
"resetToDefault": "Basculer sur le compte par défaut lorsque le formulaire de sous-adresse est réinitialisé",
|
|
||||||
"lightTheme": "Clair",
|
|
||||||
"darkTheme": "Sombre",
|
|
||||||
"close": "@:invariants.controls.close"
|
"close": "@:invariants.controls.close"
|
||||||
},
|
},
|
||||||
"deleteAccount": {
|
"deleteAccount": {
|
||||||
|
@ -77,8 +71,6 @@
|
||||||
},
|
},
|
||||||
"manageAccounts": {
|
"manageAccounts": {
|
||||||
"title": "Comptes",
|
"title": "Comptes",
|
||||||
"isDefault": "défaut",
|
|
||||||
"setDefault": "Définir par défaut",
|
|
||||||
"delete": "@:invariants.controls.delete",
|
"delete": "@:invariants.controls.delete",
|
||||||
"close": "@:invariants.controls.close"
|
"close": "@:invariants.controls.close"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { allowedLocales } from './const';
|
|
||||||
|
|
||||||
const fallBackValue = 'en';
|
|
||||||
|
|
||||||
const getShortLanguageCode = (language) => {
|
|
||||||
language = language.split('-')[0];
|
|
||||||
language = language.split('_')[0];
|
|
||||||
return language;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getDefaultLocale = () => {
|
|
||||||
for (const lang of navigator.languages) {
|
|
||||||
const lang_short = getShortLanguageCode(lang);
|
|
||||||
if (allowedLocales.includes(lang_short)) {
|
|
||||||
return lang_short;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fallBackValue;
|
|
||||||
};
|
|
30
src/main.js
30
src/main.js
|
@ -1,7 +1,5 @@
|
||||||
import './assets/main.sass';
|
import './assets/main.sass';
|
||||||
|
|
||||||
import { allowedColorModes, allowedLocales } from './const';
|
|
||||||
import { getDefaultLocale } from './locales_utils';
|
|
||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import { createI18n } from 'vue-i18n';
|
import { createI18n } from 'vue-i18n';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
|
@ -9,31 +7,17 @@ import App from './App.vue';
|
||||||
import router from './router';
|
import router from './router';
|
||||||
import messages from '@intlify/unplugin-vue-i18n/messages';
|
import messages from '@intlify/unplugin-vue-i18n/messages';
|
||||||
|
|
||||||
const setGlobalAttribute = (attrName, storageName, defaultValue, allowedValues) => {
|
const default_locale = 'en';
|
||||||
const stored_value = useStorage(storageName, '');
|
const stored_locale = useStorage('sake-locale', '');
|
||||||
if (!stored_value.value) {
|
if (!stored_locale.value) {
|
||||||
stored_value.value = defaultValue;
|
stored_locale.value = default_locale;
|
||||||
}
|
}
|
||||||
document.documentElement.setAttribute(attrName, stored_value.value);
|
document.documentElement.setAttribute('lang', stored_locale.value);
|
||||||
if (!allowedValues.includes(stored_value.value)) {
|
|
||||||
stored_value.value = defaultValue;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
'stored': stored_value,
|
|
||||||
'defaultValue': defaultValue,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const getDefaultColorMode = () => {
|
|
||||||
const darkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
||||||
return darkMediaQuery.matches ? 'dark' : 'light';
|
|
||||||
};
|
|
||||||
const locale = setGlobalAttribute('lang', 'sake-locale', getDefaultLocale(), allowedLocales);
|
|
||||||
const colorMode = setGlobalAttribute('data-bs-theme', 'sake-color-mode', getDefaultColorMode(), allowedColorModes);
|
|
||||||
|
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
legacy: false,
|
legacy: false,
|
||||||
locale: locale.stored.value,
|
locale: stored_locale.value,
|
||||||
fallbackLocale: locale.defaultValue,
|
fallbackLocale: default_locale,
|
||||||
messages,
|
messages,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { version } from '../../package.json';
|
import { version } from '../../package.json';
|
||||||
import ButtonGroupComponent from '../components/ButtonGroupComponent.vue';
|
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
import LayoutComponent from '../components/LayoutComponent.vue';
|
||||||
import ExternalLinkComponent from '../components/ExternalLinkComponent.vue';
|
import ExternalLinkComponent from '../components/ExternalLinkComponent.vue';
|
||||||
import NavBarComponent from '../components/NavBarComponent.vue';
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const repoUrl = 'https://git.what.tf/rodolphe/sake-app';
|
const repoUrl = 'https://github.com/breard-r/sake-app';
|
||||||
|
|
||||||
const toMainView = () => {
|
const toMainView = () => {
|
||||||
return router.push('/');
|
return router.push('/');
|
||||||
|
@ -15,11 +13,10 @@ const toMainView = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarComponent />
|
|
||||||
<LayoutComponent>
|
<LayoutComponent>
|
||||||
<h1>{{ $t("about.title") }}</h1>
|
<h1 class="title is-1">{{ $t("about.title") }}</h1>
|
||||||
<h4>{{ $t("about.name") }}</h4>
|
<h4 class="subtitle is-4">{{ $t("about.name") }}</h4>
|
||||||
|
<div class="block">
|
||||||
<i18n-t scope="global" keypath="about.version" tag="p">
|
<i18n-t scope="global" keypath="about.version" tag="p">
|
||||||
<template v-slot:version>{{ version }}</template>
|
<template v-slot:version>{{ version }}</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
|
@ -36,9 +33,11 @@ const toMainView = () => {
|
||||||
<ExternalLinkComponent :url="repoUrl" :name="repoUrl" />
|
<ExternalLinkComponent :url="repoUrl" :name="repoUrl" />
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
|
</div>
|
||||||
<ButtonGroupComponent>
|
<div class="block">
|
||||||
<button type="button" class="btn btn-secondary" @click="toMainView">{{ $t("about.close") }}</button>
|
<div class="buttons is-centered">
|
||||||
</ButtonGroupComponent>
|
<button class="button is-light" @click="toMainView">{{ $t("about.close") }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</LayoutComponent>
|
</LayoutComponent>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, onMounted } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { QrcodeStream, setZXingModuleOverrides } from 'vue-qrcode-reader';
|
import { QrcodeStream, setZXingModuleOverrides } from 'vue-qrcode-reader';
|
||||||
import { sha256 } from '@noble/hashes/sha256';
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
import { Modal } from 'bootstrap';
|
|
||||||
import base32Encode from 'base32-encode';
|
import base32Encode from 'base32-encode';
|
||||||
import ButtonGroupComponent from '../components/ButtonGroupComponent.vue';
|
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
import LayoutComponent from '../components/LayoutComponent.vue';
|
||||||
import NavBarComponent from '../components/NavBarComponent.vue';
|
|
||||||
import wasmFile from "../../node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm?url";
|
import wasmFile from "../../node_modules/@sec-ant/zxing-wasm/dist/reader/zxing_reader.wasm?url";
|
||||||
|
|
||||||
const accounts = useStorage('sake-accounts', []);
|
const accounts = useStorage('sake-accounts', []);
|
||||||
|
@ -17,15 +14,8 @@ const localPart = ref('');
|
||||||
const separator = ref('+');
|
const separator = ref('+');
|
||||||
const domainName = ref('');
|
const domainName = ref('');
|
||||||
const privateKey = ref('');
|
const privateKey = ref('');
|
||||||
const authorizedKeyLengths = [16, 32];
|
|
||||||
const state = reactive({
|
|
||||||
QrCodeModal: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const errorMessageId = ref('');
|
const errorMessageId = ref('');
|
||||||
const separatorErrorMessageId = ref('');
|
const authorizedKeyLengths = [16, 32];
|
||||||
const localPartErrorMessageId = ref('');
|
|
||||||
const addrKeyErrorMessageId = ref('');
|
|
||||||
|
|
||||||
const base64Decode = (str_b64) => {
|
const base64Decode = (str_b64) => {
|
||||||
try {
|
try {
|
||||||
|
@ -53,48 +43,29 @@ const addDisabled = computed(() => {
|
||||||
});
|
});
|
||||||
const addAccount = () => {
|
const addAccount = () => {
|
||||||
if (!addDisabled.value) {
|
if (!addDisabled.value) {
|
||||||
resetErrorMessage();
|
|
||||||
var hasError = false;
|
|
||||||
var key = null;
|
|
||||||
var accountId = null;
|
|
||||||
if (separator.value.length != 1) {
|
|
||||||
hasError = setErrorMessage('addAccount.error.invalidSeparator', separatorErrorMessageId);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
if (separator.value.length != 1) {
|
||||||
|
throw new Error('addAccount.error.invalidSeparator');
|
||||||
|
}
|
||||||
if (localPart.value.includes(separator.value)) {
|
if (localPart.value.includes(separator.value)) {
|
||||||
throw new Error('addAccount.error.localPartSeparator');
|
throw new Error('addAccount.error.localPartSeparator');
|
||||||
}
|
}
|
||||||
accountId = `${localPart.value}@${domainName.value}`;
|
const key = base64Decode(privateKey.value);
|
||||||
for (const acc of accounts.value) {
|
|
||||||
const comp = `${acc.localPart}@${acc.domain}`;
|
|
||||||
if (accountId == comp) {
|
|
||||||
throw new Error('addAccount.error.accountAlreadyExists');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e);
|
|
||||||
hasError = setErrorMessage(e.message, localPartErrorMessageId);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
key = base64Decode(privateKey.value);
|
|
||||||
if (!authorizedKeyLengths.includes(key.length)) {
|
if (!authorizedKeyLengths.includes(key.length)) {
|
||||||
throw new Error('addAccount.error.invalidKeyLength');
|
throw new Error('addAccount.error.invalidKeyLength');
|
||||||
}
|
}
|
||||||
} catch (e) {
|
const hash = sha256(`${localPart.value}@${domainName.value}`);
|
||||||
hasError = setErrorMessage(e.message, addrKeyErrorMessageId);
|
|
||||||
}
|
|
||||||
if (!hasError && key && accountId) {
|
|
||||||
const hash = sha256(accountId);
|
|
||||||
const newAccount = {
|
const newAccount = {
|
||||||
id: base32Encode(hash, 'RFC4648', { padding: false }).toLowerCase(),
|
id: base32Encode(hash, 'RFC4648', { padding: false }).toLowerCase(),
|
||||||
localPart: localPart.value,
|
localPart: localPart.value,
|
||||||
separator: separator.value,
|
separator: separator.value,
|
||||||
domain: domainName.value,
|
domain: domainName.value,
|
||||||
key: key,
|
key: key,
|
||||||
isDefault: false,
|
|
||||||
};
|
};
|
||||||
accounts.value.push(newAccount);
|
accounts.value.push(newAccount);
|
||||||
return toMainView();
|
return toMainView();
|
||||||
|
} catch (e) {
|
||||||
|
errorMessageId.value = e.message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -108,26 +79,17 @@ setZXingModuleOverrides({
|
||||||
return prefix + path;
|
return prefix + path;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
onMounted(() => {
|
|
||||||
state.QrCodeModal = new Modal('#qr-code-modal', {});
|
|
||||||
});
|
|
||||||
const scanQrCode = ref(false);
|
const scanQrCode = ref(false);
|
||||||
const showQrCodeScanner = (data) => {
|
const showQrCodeScanner = (data) => {
|
||||||
state.QrCodeModal.show();
|
|
||||||
scanQrCode.value = true;
|
scanQrCode.value = true;
|
||||||
};
|
};
|
||||||
const hideQrCodeScanner = () => {
|
|
||||||
scanQrCode.value = false;
|
|
||||||
state.QrCodeModal.hide();
|
|
||||||
};
|
|
||||||
const onQrCodeDetected = (result_list) => {
|
const onQrCodeDetected = (result_list) => {
|
||||||
if (result_list.length >= 1) {
|
if (result_list.length >= 1) {
|
||||||
privateKey.value = result_list[0].rawValue;
|
privateKey.value = result_list[0].rawValue;
|
||||||
hideQrCodeScanner();
|
scanQrCode.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const onQrCodeError = (err) => {
|
const onQrCodeError = (err) => {
|
||||||
hideQrCodeScanner();
|
|
||||||
if (err.name === 'NotAllowedError') {
|
if (err.name === 'NotAllowedError') {
|
||||||
setErrorMessage('addAccount.error.cameraNotAllowed');
|
setErrorMessage('addAccount.error.cameraNotAllowed');
|
||||||
} else if (err.name === 'NotFoundError') {
|
} else if (err.name === 'NotFoundError') {
|
||||||
|
@ -155,76 +117,57 @@ const toMainView = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Error message
|
// Error message
|
||||||
const setErrorMessage = (messageId, messageType) => {
|
const setErrorMessage = (messageId) => {
|
||||||
const messageIdClean = messageId.startsWith('addAccount.error.') ? messageId : 'addAccount.error.unknown';
|
if (messageId.startsWith('addAccount.error.')) {
|
||||||
if (messageType) {
|
errorMessageId.value = messageId;
|
||||||
messageType.value = messageIdClean;
|
|
||||||
} else {
|
} else {
|
||||||
errorMessageId.value = messageIdClean;
|
errorMessageId.value = 'addAccount.error.unknown';
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
};
|
|
||||||
const resetFloatingErrorMessage = () => {
|
|
||||||
errorMessageId.value = '';
|
|
||||||
};
|
};
|
||||||
const resetErrorMessage = () => {
|
const resetErrorMessage = () => {
|
||||||
resetFloatingErrorMessage();
|
errorMessageId.value = '';
|
||||||
separatorErrorMessageId.value = '';
|
|
||||||
localPartErrorMessageId.value = '';
|
|
||||||
addrKeyErrorMessageId.value = '';
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarComponent v-if="!cancellDisabled" />
|
|
||||||
<LayoutComponent>
|
<LayoutComponent>
|
||||||
<h1>{{ $t("addAccount.title") }}</h1>
|
<h1 class="title is-1">{{ $t("addAccount.title") }}</h1>
|
||||||
|
<div class="notification is-danger is-light" v-if="errorMessageId">
|
||||||
<div class="alert alert-danger alert-dismissible fade show" role="alert" v-if="errorMessageId">
|
<button class="delete" @click="resetErrorMessage"></button>
|
||||||
{{ $t(errorMessageId) }}
|
{{ $t(errorMessageId) }}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close" @click="resetFloatingErrorMessage"></button>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="container" id="new-account-error-msg-container"></div>
|
||||||
<div class="mb-3">
|
<div class="field">
|
||||||
<label class="form-label" for="new-addr-local-part">{{ $t("addAccount.localPart") }}</label>
|
<label class="label" for="new-addr-local-part">{{ $t("addAccount.localPart") }}</label>
|
||||||
<input :class="{ 'form-control': true, 'is-invalid': localPartErrorMessageId}" type="text" id="new-addr-local-part" v-model="localPart">
|
<div class="control">
|
||||||
<div class="invalid-feedback" v-if="localPartErrorMessageId">{{ $t(localPartErrorMessageId) }}</div>
|
<input class="input" type="text" id="new-addr-local-part" v-model="localPart">
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="new-addr-separator">{{ $t("addAccount.separator") }}</label>
|
|
||||||
<input :class="{ 'form-control': true, 'is-invalid': separatorErrorMessageId}" type="text" id="new-addr-separator" v-model="separator">
|
|
||||||
<div class="invalid-feedback" v-if="separatorErrorMessageId">{{ $t(separatorErrorMessageId) }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="new-addr-domain">{{ $t("addAccount.domainName") }}</label>
|
|
||||||
<input class="form-control" type="text" id="new-addr-domain" placeholder="example.org" v-model="domainName">
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="new-addr-key">{{ $t("addAccount.privateKey") }}</label>
|
|
||||||
<div class="input-group">
|
|
||||||
<input :class="{ 'form-control': true, 'is-invalid': addrKeyErrorMessageId}" type="text" id="new-addr-key" v-model="privateKey">
|
|
||||||
<button class="btn btn-primary" type="button" @click="showQrCodeScanner">{{ $t("addAccount.scan") }}</button>
|
|
||||||
<div class="invalid-feedback" v-if="addrKeyErrorMessageId">{{ $t(addrKeyErrorMessageId) }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
<div class="modal fade" id="qr-code-modal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
|
<label class="label" for="new-addr-separator">{{ $t("addAccount.separator") }}</label>
|
||||||
<div class="modal-dialog">
|
<div class="control">
|
||||||
<div class="modal-content">
|
<input class="input" type="text" id="new-addr-separator" v-model="separator">
|
||||||
<div class="modal-header">
|
</div>
|
||||||
<h1 class="modal-title fs-5" id="staticBackdropLabel">{{ $t("addAccount.scanTitle") }}</h1>
|
</div>
|
||||||
<button type="button" class="btn-close" aria-label="Close" @click="hideQrCodeScanner"></button>
|
<div class="field">
|
||||||
|
<label class="label" for="new-addr-domain">{{ $t("addAccount.domainName") }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" type="text" id="new-addr-domain" placeholder="example.org" v-model="domainName">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<label class="label" for="new-addr-key">{{ $t("addAccount.privateKey") }}</label>
|
||||||
|
<div class="field has-addons">
|
||||||
|
<div class="control is-expanded">
|
||||||
|
<input class="input" type="text" id="new-addr-key" v-model="privateKey">
|
||||||
|
</div>
|
||||||
|
<p class="control">
|
||||||
|
<a class="button is-primary" @click="showQrCodeScanner">{{ $t("addAccount.scan") }}</a>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
|
||||||
<qrcode-stream v-if="scanQrCode" @detect="onQrCodeDetected" @error="onQrCodeError"></qrcode-stream>
|
<qrcode-stream v-if="scanQrCode" @detect="onQrCodeDetected" @error="onQrCodeError"></qrcode-stream>
|
||||||
|
<div class="buttons is-centered">
|
||||||
|
<button class="button is-primary" :disabled="addDisabled" @click="addAccount">{{ $t("addAccount.addAccount") }}</button>
|
||||||
|
<button class="button is-light" v-if="!cancellDisabled" @click="toMainView">{{ $t("addAccount.cancel") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ButtonGroupComponent>
|
|
||||||
<button type="button" class="btn btn-primary" :disabled="addDisabled" @click="addAccount">{{ $t("addAccount.addAccount") }}</button>
|
|
||||||
<button type="button" class="btn btn-secondary" v-if="!cancellDisabled" @click="toMainView">{{ $t("addAccount.cancel") }}</button>
|
|
||||||
</ButtonGroupComponent>
|
|
||||||
</LayoutComponent>
|
</LayoutComponent>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { allowedColorModes, resetToDefaultAccount } from '../const';
|
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import ButtonGroupComponent from '../components/ButtonGroupComponent.vue';
|
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
import LayoutComponent from '../components/LayoutComponent.vue';
|
||||||
import NavBarComponent from '../components/NavBarComponent.vue';
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const stored_locale = useStorage('sake-locale', '');
|
const stored_locale = useStorage('sake-locale', '');
|
||||||
const { t, locale } = useI18n({ useScope: 'global' });
|
const { t, locale } = useI18n({ useScope: 'global' });
|
||||||
const colorMode = useStorage('sake-color-mode');
|
|
||||||
const resetToDefault = useStorage('sake-reset-to-default', resetToDefaultAccount);
|
|
||||||
|
|
||||||
const toMainView = () => {
|
const toMainView = () => {
|
||||||
return router.push('/');
|
return router.push('/');
|
||||||
|
@ -22,38 +17,23 @@ watch(locale, async (newLocale) => {
|
||||||
stored_locale.value = newLocale;
|
stored_locale.value = newLocale;
|
||||||
document.documentElement.setAttribute('lang', newLocale);
|
document.documentElement.setAttribute('lang', newLocale);
|
||||||
});
|
});
|
||||||
watch(colorMode, async (newColorMode) => {
|
|
||||||
console.log(`new color mode: ${newColorMode}`);
|
|
||||||
document.documentElement.setAttribute('data-bs-theme', newColorMode);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarComponent />
|
|
||||||
<LayoutComponent>
|
<LayoutComponent>
|
||||||
<h1>{{ $t("config.title") }}</h1>
|
<h1 class="title is-1">{{ $t("config.title") }}</h1>
|
||||||
|
<div class="field">
|
||||||
<div class="mb-3">
|
<label class="label" for="app-language">{{ $t("config.language") }}</label>
|
||||||
<label class="form-label" for="app-language">{{ $t("config.language") }}</label>
|
<div class="control">
|
||||||
<select class="form-select" id="app-language" v-model="$i18n.locale">
|
<div class="select is-fullwidth">
|
||||||
|
<select id="app-language" v-model="$i18n.locale">
|
||||||
<option v-for="locale_id in $i18n.availableLocales" :key="`locale-${locale_id}`" :value="locale_id">{{ $t("locale_name", 1, { locale: locale_id}) }}</option>
|
<option v-for="locale_id in $i18n.availableLocales" :key="`locale-${locale_id}`" :value="locale_id">{{ $t("locale_name", 1, { locale: locale_id}) }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="app-color-mode">{{ $t("config.colorMode") }}</label>
|
|
||||||
<select class="form-select" id="app-color-mode" v-model="colorMode">
|
|
||||||
<option v-for="mode in allowedColorModes" :key="mode" :value="mode">{{ $t(`config.${mode}Theme`) }}</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<div class="form-check form-switch">
|
|
||||||
<input class="form-check-input" type="checkbox" role="switch" id="app-reset-to-default" v-model="resetToDefault">
|
|
||||||
<label class="form-check-label" for="app-reset-to-default">{{ $t("config.resetToDefault") }}</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="buttons is-centered">
|
||||||
<ButtonGroupComponent>
|
<button class="button is-light" @click="toMainView">{{ $t("config.close") }}</button>
|
||||||
<button type="button" class="btn btn-secondary" @click="toMainView">{{ $t("about.close") }}</button>
|
</div>
|
||||||
</ButtonGroupComponent>
|
|
||||||
</LayoutComponent>
|
</LayoutComponent>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import ButtonGroupComponent from '../components/ButtonGroupComponent.vue';
|
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
import LayoutComponent from '../components/LayoutComponent.vue';
|
||||||
import NavBarComponent from '../components/NavBarComponent.vue';
|
|
||||||
|
|
||||||
const accounts = useStorage('sake-accounts', []);
|
const accounts = useStorage('sake-accounts', []);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -20,17 +18,14 @@ const toMainView = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarComponent />
|
|
||||||
<LayoutComponent>
|
<LayoutComponent>
|
||||||
<h1>{{ $t("deleteAccount.title") }}</h1>
|
<h1 class="title is-1">{{ $t("deleteAccount.title") }}</h1>
|
||||||
|
|
||||||
<p>{{ $t("deleteAccount.account") }}</p>
|
<p>{{ $t("deleteAccount.account") }}</p>
|
||||||
<p class="fw-semibold fs-5">{{ account.localPart }}@{{ account.domain }}</p>
|
<p class="has-text-weight-semibold is-size-5">{{ account.localPart }}@{{ account.domain }}</p>
|
||||||
<p>{{ $t("deleteAccount.confirm") }}</p>
|
<p>{{ $t("deleteAccount.confirm") }}</p>
|
||||||
|
<div class="buttons is-centered">
|
||||||
<ButtonGroupComponent>
|
<button class="button is-danger" @click="deleteAccount">{{ $t("deleteAccount.delete") }}</button>
|
||||||
<button type="button" class="btn btn-danger" @click="deleteAccount">{{ $t("deleteAccount.delete") }}</button>
|
<button class="button is-light" @click="toMainView">{{ $t("deleteAccount.cancel") }}</button>
|
||||||
<button type="button" class="btn btn-secondary" @click="toMainView">{{ $t("deleteAccount.cancel") }}</button>
|
</div>
|
||||||
</ButtonGroupComponent>
|
|
||||||
</LayoutComponent>
|
</LayoutComponent>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,25 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { sortAccounts } from '../accounts';
|
import { sortAccounts } from '../accounts';
|
||||||
import { resetToDefaultAccount } from '../const';
|
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { RouterLink, useRouter } from 'vue-router';
|
import { RouterLink, useRouter } from 'vue-router';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { hmac } from '@noble/hashes/hmac';
|
import { hmac } from '@noble/hashes/hmac';
|
||||||
import { sha256 } from '@noble/hashes/sha256';
|
import { sha256 } from '@noble/hashes/sha256';
|
||||||
import base32Encode from 'base32-encode';
|
import base32Encode from 'base32-encode';
|
||||||
import ButtonGroupComponent from '../components/ButtonGroupComponent.vue';
|
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
import LayoutComponent from '../components/LayoutComponent.vue';
|
||||||
import NavBarComponent from '../components/NavBarComponent.vue';
|
import NavBarComponent from '../components/NavBarComponent.vue';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const accounts = useStorage('sake-accounts', []);
|
const accounts = sortAccounts(useStorage('sake-accounts', []));
|
||||||
const resetToDefault = useStorage('sake-reset-to-default', resetToDefaultAccount);
|
const selectedAccountId = ref(accounts.value[0].id);
|
||||||
const sortedAccounts = computed(() => sortAccounts(accounts.value));
|
|
||||||
const getDefaultAccount = () => {
|
|
||||||
const def = accounts.value.find((a) => a.isDefault);
|
|
||||||
return def ? def.id : accounts.value[0].id;
|
|
||||||
};
|
|
||||||
const selectedAccountId = ref(getDefaultAccount());
|
|
||||||
const subAddrName = ref('');
|
const subAddrName = ref('');
|
||||||
|
|
||||||
const fromRawAccount = (raw_account) => {
|
const fromRawAccount = (raw_account) => {
|
||||||
|
@ -36,10 +28,6 @@ const generatedAddr = computed(() => {
|
||||||
const raw_account = accounts.value.find((e) => e.id == selectedAccountId.value);
|
const raw_account = accounts.value.find((e) => e.id == selectedAccountId.value);
|
||||||
if (raw_account) {
|
if (raw_account) {
|
||||||
const account = fromRawAccount(raw_account);
|
const account = fromRawAccount(raw_account);
|
||||||
if (subAddrName.value.indexOf(account.separator) != -1) {
|
|
||||||
subAddrName.value = subAddrName.value.replaceAll(account.separator, '');
|
|
||||||
}
|
|
||||||
if (subAddrName.value) {
|
|
||||||
var hasher = hmac.create(sha256, account.key);
|
var hasher = hmac.create(sha256, account.key);
|
||||||
hasher.update(account.localPart);
|
hasher.update(account.localPart);
|
||||||
hasher.update(account.separator);
|
hasher.update(account.separator);
|
||||||
|
@ -51,7 +39,6 @@ const generatedAddr = computed(() => {
|
||||||
return `${account.localPart}${account.separator}${subAddrName.value}${account.separator}${code}@${account.domain}`;
|
return `${account.localPart}${account.separator}${subAddrName.value}${account.separator}${code}@${account.domain}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
const copyAddr = () => {
|
const copyAddr = () => {
|
||||||
|
@ -59,37 +46,38 @@ const copyAddr = () => {
|
||||||
};
|
};
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
subAddrName.value = '';
|
subAddrName.value = '';
|
||||||
if (resetToDefault.value) {
|
|
||||||
selectedAccountId.value = getDefaultAccount();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarComponent />
|
<NavBarComponent />
|
||||||
<LayoutComponent>
|
<LayoutComponent>
|
||||||
<h1>{{ $t("main.title") }}</h1>
|
<h1 class="title is-1">{{ $t("main.title") }}</h1>
|
||||||
|
<div class="field">
|
||||||
<div class="mb-3">
|
<label class="label" for="account-name">{{ $t("main.account") }}</label>
|
||||||
<label class="form-label" for="account-name">{{ $t("main.account") }}</label>
|
<div class="control">
|
||||||
<select class="form-select" id="account-name" v-model="selectedAccountId">
|
<div class="select is-fullwidth">
|
||||||
<option v-for="account in sortedAccounts" :key="account.id" :value="account.id">{{ account.localPart }}@{{ account.domain }}</option>
|
<select id="account-name" v-model="selectedAccountId">
|
||||||
|
<option v-for="account in accounts" :key="account.id" :value="account.id">{{ account.localPart }}@{{ account.domain }}</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="sub-addr-name">{{ $t("main.name") }}</label>
|
|
||||||
<input class="form-control" type="text" id="sub-addr-name" :placeholder="$t('main.input')" v-model="subAddrName">
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="generated-addr">{{ $t("main.address") }}</label>
|
|
||||||
<input class="form-control" type="text" id="generated-addr" v-model="generatedAddr" disabled>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="field">
|
||||||
<ButtonGroupComponent>
|
<label class="label" for="sub-addr-name">{{ $t("main.name") }}</label>
|
||||||
<button type="button" class="btn btn-primary" @click="copyAddr">{{ $t("main.copy") }}</button>
|
<div class="control">
|
||||||
<button type="button" class="btn btn-secondary" @click="resetForm">{{ $t("main.reset") }}</button>
|
<input class="input" type="text" id="sub-addr-name" :placeholder="$t('main.input')" v-model="subAddrName">
|
||||||
</ButtonGroupComponent>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label" for="generated-addr">{{ $t("main.address") }}</label>
|
||||||
|
<div class="control">
|
||||||
|
<input class="input" type="text" id="generated-addr" v-model="generatedAddr" disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons is-centered">
|
||||||
|
<button class="button is-primary" @click="copyAddr">{{ $t("main.copy") }}</button>
|
||||||
|
<button class="button is-light" @click="resetForm">{{ $t("main.reset") }}</button>
|
||||||
|
</div>
|
||||||
</LayoutComponent>
|
</LayoutComponent>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,52 +1,41 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { sortAccounts } from '../accounts';
|
import { sortAccounts } from '../accounts';
|
||||||
import { computed } from 'vue';
|
|
||||||
import { RouterLink, useRouter } from 'vue-router';
|
import { RouterLink, useRouter } from 'vue-router';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import ButtonGroupComponent from '../components/ButtonGroupComponent.vue';
|
|
||||||
import LayoutComponent from '../components/LayoutComponent.vue';
|
import LayoutComponent from '../components/LayoutComponent.vue';
|
||||||
import NavBarComponent from '../components/NavBarComponent.vue';
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const accounts = useStorage('sake-accounts', []);
|
const accounts = sortAccounts(useStorage('sake-accounts', []));
|
||||||
const sortedAccounts = computed(() => sortAccounts(accounts.value));
|
|
||||||
|
|
||||||
const deleteAccount = (accountId) => {
|
const deleteAccount = (accountId) => {
|
||||||
return router.push(`/delete-account/${accountId}`);
|
return router.push(`/delete-account/${accountId}`);
|
||||||
};
|
};
|
||||||
const setDefaultAccount = (accountId) => {
|
|
||||||
accounts.value = accounts.value.map((a) => {
|
|
||||||
a.isDefault = a.id === accountId;
|
|
||||||
return a;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const toMainView = () => {
|
const toMainView = () => {
|
||||||
return router.push('/');
|
return router.push('/');
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NavBarComponent />
|
|
||||||
<LayoutComponent>
|
<LayoutComponent>
|
||||||
<h1>{{ $t("manageAccounts.title") }}</h1>
|
<h1 class="title is-1">{{ $t("manageAccounts.title") }}</h1>
|
||||||
|
<div class="block">
|
||||||
<table class="table">
|
<table class="table is-fullwidth">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="account in sortedAccounts">
|
<tr v-for="account in accounts">
|
||||||
<th class="text-end align-middle">
|
<th class="has-text-right is-vcentered">
|
||||||
<span class="badge text-bg-primary" v-if="account.isDefault">{{ $t("manageAccounts.isDefault") }}</span>
|
|
||||||
{{ account.localPart }}@{{ account.domain }}
|
{{ account.localPart }}@{{ account.domain }}
|
||||||
</th>
|
</th>
|
||||||
<th>
|
<th>
|
||||||
<button type="button" class="btn btn-primary me-2" @click="setDefaultAccount(account.id)" v-if="!account.isDefault">{{ $t("manageAccounts.setDefault") }}</button>
|
<button class="button is-danger" @click="deleteAccount(account.id)">{{ $t("manageAccounts.delete") }}</button>
|
||||||
<button type="button" class="btn btn-danger" @click="deleteAccount(account.id)">{{ $t("manageAccounts.delete") }}</button>
|
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
<ButtonGroupComponent>
|
<div class="block">
|
||||||
<button type="button" class="btn btn-secondary" @click="toMainView">{{ $t("manageAccounts.close") }}</button>
|
<div class="buttons is-centered">
|
||||||
</ButtonGroupComponent>
|
<button class="button is-light" @click="toMainView">{{ $t("manageAccounts.close") }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</LayoutComponent>
|
</LayoutComponent>
|
||||||
</template>
|
</template>
|
||||||
|
|
Loading…
Reference in a new issue