initial commit
Rust verification / test (push) Successful in 4m10s

This commit is contained in:
wt committed 2026-10-28 15:59:54 +07:00
commit cf25e28c28
156 files changed
+38669

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
target
.git
data
.env
*.sqlite*
bin
+19
View File
@@ -0,0 +1,19 @@
name: Rust verification
on: [push, pull_request]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- run: cargo fmt --all -- --check
- run: cargo clippy --locked --all-targets -- -D warnings
- run: cargo test --locked
- run: cargo build --locked --release
- run: python3 tests/http_smoke.py target/release/twofauth-rs
- run: python3 -m py_compile tools/inventory.py tools/differential_http.py
- run: docker build -t twofauth-rs:test .
+4
View File
@@ -0,0 +1,4 @@
/target/
/data/
.env
*.sqlite*
Generated
+4128
View File
File diff suppressed because it is too large. Load diff
+65
View File
@@ -0,0 +1,65 @@
[package]
name = "twofauth-rs"
version = "0.3.0"
edition = "2024"
license = "AGPL-3.0-only"
description = "Rust compatibility implementation targeting 2FAuth 8.0.3"
[dependencies]
axum = { version = "0.8", features = ["macros", "multipart"] }
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.8", default-features = false, features = ["runtime-tokio", "sqlite", "chrono"] }
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["preserve_order"] }
serde_urlencoded = "0.7"
anyhow = "1"
thiserror = "2"
chrono = { version = "0.4", features = ["serde"] }
tower = { version = "0.5", features = ["util"] }
tower-http = { version = "0.6", features = ["trace", "limit", "set-header", "fs"] }
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
dotenvy = "0.15"
clap = { version = "4", features = ["derive", "env"] }
hmac = "0.12"
sha1 = "0.10"
sha2 = { version = "0.10", features = ["oid"] }
rsa = "0.9"
md-5 = "0.10"
data-encoding = "2"
url = "2"
percent-encoding = "2"
aes = "0.8"
cbc = { version = "0.1", features = ["alloc", "block-padding"] }
base64 = "0.22"
rand = "0.8"
hex = "0.4"
bcrypt = "0.17"
argon2 = "0.5"
subtle = "2"
zeroize = "1"
qrcode = { version = "0.14", default-features = false, features = ["svg"] }
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "gif", "bmp", "webp", "ico"] }
rqrr = "0.10"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
roxmltree = "0.20"
regex = "1"
pcre2 = "0.2"
chrono-tz = "0.10"
webauthn-rs-core = "=0.5.4"
webauthn-rs = { version = "=0.5.4", default-features = false, features = ["danger-credential-internals", "danger-allow-state-serialisation", "danger-user-presence-only-security-keys"] }
openssl = { version = "0.10", features = ["vendored"] }
serde_cbor_2 = "0.13"
lettre = { version = "0.11", default-features = false, features = ["builder", "smtp-transport", "sendmail-transport", "tokio1-rustls-tls"] }
jsonwebtoken = { version = "9", default-features = false }
[dev-dependencies]
tempfile = "3"
http-body-util = "0.1"
[profile.release]
lto = false
strip = true
+22
View File
@@ -0,0 +1,22 @@
FROM rust:1-bookworm AS build
RUN apt-get update && apt-get install -y --no-install-recommends build-essential perl pkg-config && rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY Cargo.toml Cargo.lock ./
COPY src ./src
COPY public ./public
COPY tests ./tests
COPY compatibility ./compatibility
RUN cargo build --locked --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && rm -rf /var/lib/apt/lists/*
RUN groupadd --gid 10001 twofauth && useradd --uid 10001 --gid twofauth --no-create-home twofauth && mkdir /data && chown twofauth:twofauth /data
WORKDIR /app
COPY --from=build /src/target/release/twofauth-rs /usr/local/bin/twofauth-rs
COPY public ./public
COPY LICENSE NOTICE ./
USER 10001:10001
ENV DATABASE_URL=sqlite:///data/2fauth.sqlite LISTEN_ADDR=0.0.0.0:8080 RUST_PUBLIC_DIR=/app/public STORAGE_PATH=/data/storage PASSPORT_KEY_PATH=/data/storage
EXPOSE 8080
ENTRYPOINT ["twofauth-rs"]
CMD ["serve"]
+661
View File
@@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
+7
View File
@@ -0,0 +1,7 @@
This experimental Rust backend targets Bubka/2FAuth 8.0.3.
Reference source: https://github.com/Bubka/2FAuth
Pinned commit: 3516c776a1fcbd83d234efc007e3a49807d6ed91
Original 2FAuth source and frontend assets remain copyright their respective authors
and are supplied under their original license (see LICENSE and upstream reference source).
This is an independent, incomplete port; it is not an official 2FAuth release.
Do not interpret a passing Rust test suite as proof of replacement compatibility.
+63
View File
@@ -0,0 +1,63 @@
# 2FAuth Rust compatibility implementation — 0.3.0
Targets 2FAuth **8.0.3**, upstream commit `3516c776a1fcbd83d234efc007e3a49807d6ed91`. AGPL-3.0-only; upstream source and frontend provenance are retained. See [README.ru.md](README.ru.md) for deployment/configuration instructions in Russian.
**This is not a certified complete PHP replacement.** Current evidence and remaining gaps are in [compatibility/CURRENT.md](compatibility/CURRENT.md). Never infer total coverage from test counts or from displaying the original Vue frontend.
Implemented areas include OTP/URI/export, Laravel encryption and rotation, account/group CRUD, per-user orders/groups, sharing and ownership, registration/profile/password recovery, Passport RSA bearer/PAT and PHP browser cookie interoperability, migrated WebAuthn credentials, SSO/proxy authentication, imports/icons/QR, preferences/settings, SMTP notifications and authentication/OTP auditing. The original Vue build is served, including subdirectory mounting.
## Build and test
A current stable Rust toolchain, C compiler, make and Perl are required. OpenSSL is vendored for WebAuthn; no external OpenSSL development package is required.
```sh
cargo fmt --all -- --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked --all-targets
cargo build --locked --release
python3 tests/http_smoke.py target/release/twofauth-rs
python3 tests/differential_harness.py
python3 tests/laravel_session_http.py target/release/twofauth-rs
PHP_BINARY=/path/to/php python3 tests/oauth_interop.py target/release/twofauth-rs
PHP_BINARY=/path/to/php python3 tests/device_interop.py target/release/twofauth-rs --output compatibility/device-interop.json
python3 tests/crypto_interop.py --check-php
```
The PHP crypto check requires PHP/OpenSSL. Full reference runs additionally require PHP 8.4+, locked Composer dependencies and the PHP extensions required by the pinned upstream.
```sh
python3 tools/run_reference.py --php /path/to/php \
--source ../upstream --candidate-binary target/release/twofauth-rs \
--candidate-db native --semantic-checks --passport-interop \
--extra-cases compatibility/cases.oauth.json --extra-cases compatibility/cases.device.json --output compatibility/reference-results.native.json
python3 tools/run_reference.py --php /path/to/php \
--source ../upstream --candidate-binary target/release/twofauth-rs \
--candidate-db laravel-copy --semantic-checks --passport-interop \
--extra-cases compatibility/cases.oauth.json --extra-cases compatibility/cases.device.json --output compatibility/reference-results.laravel.json
```
Each run uses disposable databases, credentials, application state and isolated server ports. Semantic login/QR checks precede the extra OAuth error burst because the PHP unnamed OAuth throttle shares its bucket with password login. The Laravel-copy mode runs real PHP migrations, seeds a synthetic user, copies the database through SQLite backup, and invokes `prepare-sqlite`. Do not point differential tests at live services.
`tools/passport_interop.py --help` documents the separate bidirectional Passport and PHP-browser-session upgrade test. It creates disposable fixture material rather than shipping deployment keys.
## Local development
```sh
mkdir -p data
cargo run -- init
RUST_COOKIE_SECURE=false cargo run -- serve
```
Open `http://127.0.0.1:8080`; the first self-registered user becomes administrator. `init` refuses an existing users table. `prepare-sqlite` validates an already migrated Laravel SQLite schema and adds Rust-only session/ceremony metadata. `serve` also creates this metadata if absent after validation; it never runs application migrations or resets user tables.
Preserve original `APP_KEY`, `APP_PREVIOUS_KEYS`, Passport key files and storage. `DATABASE_URL` overrides Laravel `DB_DATABASE`; only SQLite is implemented. `DB_CONNECTION` selecting another driver fails explicitly. All switching exercises must use a backup/copy until complete compatibility is established.
The included Dockerfile/Compose were updated for static assets, vendored cryptography and writable storage. Docker itself was unavailable in the development environment, so image build/run is not claimed verified.
## Laravel sessions and OAuth additions
File and SQLite database Laravel sessions can be imported using the original APP_KEY, SESSION_COOKIE, SESSION_DRIVER, SESSION_TABLE, SESSION_ENCRYPT and STORAGE_PATH. JSON and scalar/array PHP serialization are supported; PHP objects and references are rejected. Both store encryption and remember-me recallers are checked with real pinned PHP fixtures. Native session rotation destroys the imported store; logout rotates remember tokens. Redis, cookie and other session drivers remain outside this implementation.
Standard `/oauth/token` supports authorization-code/PKCE, refresh rotation, client credentials and device authorization/polling using the actual Defuse PHP encrypted wire format and Passport RSA keys. The pinned application registers Passport JSON management routes too late and lacks an authorization view binding. Defaults preserve the observed disabled/broken management and consent behavior. `PASSPORT_JSON_API_ROUTES=true` and `RUST_OAUTH_CONSENT_ENABLED=true` explicitly enable repaired management and consent. These optional routes are extensions, not an assertion that the original defects were absent.
SQLite startup now checks used application columns, primary/unique keys and foreign-key delete actions against the real migrated schema before adding Rust metadata. See compatibility/database-portability.md for the remaining engine-specific work.
+102
View File
@@ -0,0 +1,102 @@
# 2FAuth на Rust — 0.3.0
Целевая версия: **2FAuth 8.0.3**, коммит `3516c776a1fcbd83d234efc007e3a49807d6ed91`.
Это развиваемая реализация совместимости, **пока не подтверждённая как полная замена PHP**. Рабочий сервер пользователя не изменялся. Все сравнения выполняются на отдельных синтетических базах, включая копию БД, созданной настоящими Laravel-миграциями.
## Что реализовано
- HOTP, TOTP и Steam; SHA-1/256/512 и MD5; атомарный HOTP-счётчик; URI и экспорт.
- Шифрование Laravel AES-CBC, `APP_KEY`, предыдущие ключи; транзакционное включение/выключение шифрования данных и иконок.
- Аккаунты, группы, порядок и назначения отдельно для каждого пользователя; общие аккаунты, всеобщие ссылки доступа, передача владельца с подтверждением пароля; запрет выдачи секретов получателям.
- Регистрация, вход, CSRF, профиль, смена/восстановление пароля, ограничения регистрации, последний администратор, управление пользователями.
- Passport 13: настоящие RSA JWT, создание/отзыв PAT, существующие PHP bearer-токены и зашифрованные браузерные `laravel_token`. Действующая PHP-cookie может быть преобразована в Rust-сессию при загрузке интерфейса.
- OAuth: authorization code с PKCE, client credentials, Device Code Flow, ротация refresh-токенов и запрет повторного обмена; формат шифрования Defuse PHP совместим с эталоном.
- Перенос Laravel-сессий из файлов и SQLite: JSON/PHP-сериализация, SESSION_ENCRYPT, проверка cookie/CSRF, remember-me и отзыв при выходе.
- WebAuthn: регистрация, вход, список/переименование/удаление устройств, восстановление; импорт существующих зашифрованных PEM-ключей Laragear P-256/RSA/Ed25519. Проверки используют подписанные данные аутентификатора.
- GitHub/OpenID SSO, PKCE, одноразовый state, проверка OIDC JWT при настройке issuer; reverse-proxy-вход только от доверенного сетевого адреса.
- Импорт 2FAuth, Aegis, 2FAS, Bitwarden, текстовых URI и Google Authenticator; вложенные иконки; QR; официальные и локальные наборы иконок.
- Настройки, предпочтения, журналы входа/OTP, уведомления, SMTP/STARTTLS/TLS/sendmail/log; исходный собранный Vue-интерфейс и размещение в подкаталоге.
Подробные доказательства и ограничения: [compatibility/CURRENT.md](compatibility/CURRENT.md), [compatibility/VERIFICATION.md](compatibility/VERIFICATION.md). Старые разделы аудита в `compatibility/README.md` относятся к исходной версии 0.1.0.
## Готовый бинарный файл
В архиве есть `bin/twofauth-rs` для Linux x86_64 GNU. Он проверен в этой среде; для запуска нужны glibc 2.39 или новее и libgcc_s. Контрольная сумма приведена в `bin/BUILD.txt`. Если система старее или имеет другую архитектуру, соберите проект из исходников либо через Docker.
Запускайте бинарный файл из каталога `rust-server`; соседний каталог `public` определяется автоматически. Для новой установки сначала задайте и сохраните `APP_KEY`, затем используйте команды ниже, заменив `./target/release/twofauth-rs` на `./bin/twofauth-rs`. Для имеющейся установки ключи должны остаться прежними.
## Сборка и отдельная тестовая установка
Нужны современный stable Rust, C-компилятор, make и Perl: OpenSSL собирается из исходников для WebAuthn. Сборка Docker в этой среде не запускалась.
```sh
cargo build --locked --release
mkdir -p data
./target/release/twofauth-rs init
RUST_COOKIE_SECURE=false ./target/release/twofauth-rs serve
```
Откройте `http://127.0.0.1:8080`. На пустой БД доступна регистрация; первый пользователь становится администратором. Отключать Secure-cookie следует только для локального HTTP. Для HTTPS оставьте значение по умолчанию.
Можно создать отдельного тестового пользователя через файл пароля:
```sh
./target/release/twofauth-rs create-user --name Test --email test@example.invalid --password-file /path/password.txt
```
`init` отказывается создавать схему поверх существующих пользователей. `create-user` создаёт обычного пользователя. Файл пароля должен быть доступен только владельцу; для этой CLI-команды требуется 12–72 байта.
## Проверка копии существующей SQLite
Сначала сделайте согласованную копию БД и каталога `storage` средствами SQLite/вашего резервного копирования. Не копируйте только основной файл SQLite при незавершённом WAL.
Настройте окружение на **копию**:
```sh
export DB_CONNECTION=sqlite
export DB_DATABASE=/absolute/path/to/copied/database.sqlite
export APP_URL=https://test.example.invalid
export STORAGE_PATH=/absolute/path/to/copied/storage
export PASSPORT_KEY_PATH=/absolute/path/to/copied/storage
# APP_KEY и APP_PREVIOUS_KEYS должны сохранять исходные значения.
./target/release/twofauth-rs prepare-sqlite
./target/release/twofauth-rs serve
```
`prepare-sqlite` проверяет используемые поля таблиц и добавляет только служебные таблицы Rust. Он не выполняет Laravel-миграции и не меняет историю миграций. Если эти служебные таблицы отсутствуют при запуске, `serve` также проверит схему и создаст их. Исходная БД должна уже быть обновлена до целевого PHP-коммита. Поддержка PostgreSQL/MySQL/SQL Server в этой реализации **ещё отсутствует**.
Сохраняйте исходные ключи Passport `oauth-private.key`/`oauth-public.key`, `APP_KEY`, предыдущие ключи и содержимое хранилища. Не генерируйте новые ключи вместо существующих. Для encrypted WebAuthn-ключей `APP_KEY` нужен даже при выключенном шифровании OTP.
## Конфигурация
`DATABASE_URL=sqlite:///absolute/file.sqlite` имеет приоритет над `DB_DATABASE`. По умолчанию используется `sqlite://data/2fauth.sqlite`. Адрес прослушивания: `LISTEN_ADDR`, по умолчанию `127.0.0.1:8080`.
Применяются исходные `APP_URL`, `APP_NAME`, `APP_KEY`, `APP_PREVIOUS_KEYS`, настройки SMTP `MAIL_*`, параметры `GITHUB_*`, `OPENID_*`, `WEBAUTHN_*`, `AUTH_GUARD`/`AUTHENTICATION_GUARD`, `AUTH_PROXY_HEADER_FOR_*`, `TRUSTED_PROXIES`, предпочтения `USERPREF_DEFAULT__*`/`USERPREF_LOCKED__*`.
Дополнительно:
| Параметр | Назначение |
|---|---|
| `STORAGE_PATH` | Каталог Laravel storage; по умолчанию `storage` |
| `PASSPORT_KEY_PATH` | Каталог ключей Passport; по умолчанию `storage` |
| `RUST_PUBLIC_DIR` | Каталог собранного интерфейса; по умолчанию `public` рядом с исходниками |
| `RUST_COOKIE_SECURE` | `false` только для локального HTTP; по умолчанию Secure |
| `APP_SUBDIRECTORY` | Например `/tools/2fa`; `APP_URL` должен содержать тот же путь |
| `SESSION_DRIVER`, `SESSION_TABLE`, `SESSION_COOKIE`, `SESSION_ENCRYPT` | Чтение исходных Laravel-сессий: `file` или `database`; сохраняйте исходные параметры и `STORAGE_PATH` |
| `PASSPORT_JSON_API_ROUTES` | `true` включает исправленные маршруты управления OAuth-клиентами и токенами; по умолчанию выключено, как в закреплённом PHP-эталоне |
| `RUST_OAUTH_CONSENT_ENABLED` | `true` включает исправленный экран согласия OAuth; это явное расширение относительно дефектного маршрута эталона |
| `OPENID_ISSUER` | Включает discovery и проверку подписанного ID token; без него сохранён upstream-flow с явными URL |
| `OPENID_DISCOVERY_URL`, `OPENID_JWKS_URL` | Необязательные переопределения OIDC endpoints |
В Docker каталог `/data` должен быть доступен UID 10001. В образе `STORAGE_PATH` и `PASSPORT_KEY_PATH` указывают на `/data/storage`. Команды и проверки для разработчиков приведены в английском README.
## Что ещё препятствует полной замене
Другие СУБД; остальные Laravel session-хранилища (Redis, cookie и другие); все варианты конфигурации и переводы ошибок; полное сравнение всех маршрутов и middleware; браузерная проверка всех экранов и реальных SSO/WebAuthn-провайдеров. Некоторые диагностические ответы сознательно описывают Rust, а не PHP. QR-код может иметь другое SVG-представление при том же URI. Отдельные ограничения удалённых иконок и почтовых драйверов описаны в `compatibility/CURRENT.md`.
Прохождение ограниченного набора тестов не означает полной совместимости. Боевой PHP-сервер пока не следует выключать на основании этого архива.
## Особенности закреплённого OAuth-эталона
В исходном PHP-файле AppServiceProvider флаг регистрации JSON-маршрутов Passport устанавливается после загрузки пакета. Поэтому `/oauth/clients` и `/oauth/tokens` по умолчанию возвращают SPA для GET и 405 для изменений. Стандартный GET `/oauth/authorize` также неработоспособен: отсутствует реализация AuthorizationViewResponse. По умолчанию сохранено наблюдаемое поведение. Два явных параметра выше включают рабочее управление и согласие для authorization code; экран подтверждения Device Flow в этой версии сохраняет исходную ошибку привязки представления. Эти расширения не считаются точным воспроизведением дефектов эталона.
+44
View File
@@ -0,0 +1,44 @@
# Current compatibility status — 0.3.0
Target: 2FAuth 8.0.3, source commit `3516c776a1fcbd83d234efc007e3a49807d6ed91`.
This supersedes the implementation-status statements in the original 0.1.0 audit. The static PHP source inventories remain valid. This project is still **not a verified complete replacement**.
## Evidence
The reference really runs PHP 8.4.27 and locked Laravel 13.29.0 dependencies. All 42 PHP migrations succeeded on disposable SQLite. `sqlite-reference-schema.sql` records the resulting application DDL, without fixture rows or deployment secrets.
The differential runner exercises separate synthetic instances with both a native Rust database and a copy of the real migrated PHP database. The fixtures preserve the ordinary user at id 1 and add an administrator and recipient. It raises the generic API fixture throttle to 1000 on both sides to fit the expanded sequence; ordinary deployment defaults are covered separately by limiter tests. No production configuration or database was accessed.
The core raw suites comprise 99 HTTP comparisons: 4 public probes, 12 account/authentication calls, 23 extended account/group/validation calls, and 60 administration/sharing/role-switch calls. Three additional CORS probes bring the core total to 102. Version 0.3.0 adds 29 OAuth and 9 device/default-web probes: 140 comparisons per database mode, of which 129 are exact. Count is not route or configuration coverage. Additional checks assert absent borrowed secrets, RFC HOTP output and counter state, per-user group independence, share counts, encryption transitions and denied operations.
Exact comparisons retain random CSRF values, health-render milliseconds and SVG QR bytes as differences. Supplemental checks require plain CSRF tokens followed by successful login; compare the health page excluding only its numeric rendering time; and render both SVGs and decode them using the PHP QR reader, requiring the same expected otpauth URI. These are explicit semantic checks, not indiscriminate exclusions.
`tools/passport_interop.py` additionally tests actual PHP-created RSA bearer tokens and encrypted browser cookies against Rust, Rust-created PATs against PHP's League ResourceServer, expiry/signature/revocation/CSRF rejection, PHP-browser upgrade at the HTML bootstrap, cookie clearing and logout. Test keys are generated for disposable fixtures.
Rust tests exercise actual WebAuthn signatures and credential migration, not acceptance stubs: PHP-encrypted P-256 PEM, RSA/Ed25519 PEM imports, fresh P-256/Ed25519 registration, origin/handle/signature checks, expiry, replay, device management and password/token recovery. Local fake SSO providers exercise PKCE/state/OIDC verification. Local SMTP tests cover delivery and TLS downgrade rejection.
See `VERIFICATION.md` and the final `reference-results.*.json` files for executed results and binary/case hashes. The earlier `reference-results.json` is retained as a baseline from the old binary.
## Additions in 0.3.0
Real PHP session fixtures cover eight process-level combinations: file/database × JSON/PHP serialization × encrypted/plain storage. They exercise original session CSRF, Passport refresh, HTML bootstrap import, native API use, source-store destruction, logout token rotation and replay through the actual HTML import path.
The device grant uses the pinned `oauth_device_codes` schema, 10-minute device codes, 8-character user codes and the original 5-second polling interval. Its default browser view remains broken like the source binding.
The OAuth wire test uses a PHP-issued encrypted authorization code with S256 PKCE, verifies the Rust JWT signature in PHP, decrypts and re-encrypts Rust refresh tokens in PHP, and checks exchange/replay plus client-credential wildcard scopes. OAuth error contracts are compared separately rather than inferred from successful exchanges. Optional consent stores approval challenges server-side and binds them to one browser session; prompt=login markers are single-use and expire.
Existing SQLite databases are checked read-only for required columns/types, primary and non-partial unique keys, and foreign-key delete actions against the pinned migration DDL. Laravel sessions are required only when the database session driver is configured. Other engine support requires the driver/value/SQL work documented in database-portability.md.
## Remaining gaps before a complete-replacement claim
- **Database engines:** only SQLite is implemented. PostgreSQL, MySQL and SQL Server remain unsupported. `prepare-sqlite` validates an already migrated pinned schema; it does not reproduce all historic Laravel migration paths.
- **Other Laravel session modes:** file and SQLite database stores, JSON/PHP scalar-array serialization, SESSION_ENCRYPT and remember-me import/revocation are implemented and tested. Redis, cookie, Memcached and other backends remain unsupported. Non-ASCII APP_NAME slug defaults, separate session connections and every cookie/multi-process configuration are not certified.
- **OAuth surface:** authorization-code/PKCE, refresh rotation, client credentials, device authorization/polling and the Defuse encrypted format are implemented alongside bearer/PAT/cookies. The pinned source has disabled JSON management routes and a broken consent view binding. Defaults preserve those observed defects; explicit opt-ins enable repaired management and authorization-code consent. Device browser consent retains the original broken view binding; this build does not add a repaired device UI. Other package grant modes and every authorization/configuration edge case are not certified.
- **Validation/localization/configuration:** selected error/status contracts have been compared and corrected. All request validation combinations, translations, guard ordering, proxy chains, cookie settings and the complete environment matrix have not been exhaustively compared. Some date and user-agent formatting is approximate. OAuth/device limiting is checked at 60/minute; all interactions with the PHP unnamed login quota and authenticated-user key switching are not certified.
- **Icons/QR:** SVG encoding differs by QR library while decoded content is checked. SVG sanitization intentionally strips unsupported/executable content; uncommon safe SVG features may change. Remote fetching, proxies, retries, DNS edge cases and checksum-specific QR error messages are not fully identical.
- **Mail:** SMTP, TLS/STARTTLS, sendmail and log are implemented. Every Laravel cloud transport and exact HTML mail layout is not reproduced. Notifications are localized but were not checked through real production mail/providers.
- **Operational surface:** Rust diagnostics identify the actual native runtime; Laravel cache/optimization commands have native equivalents because no PHP template/config cache exists. The complete Artisan command/scheduler/queue operational interface is not reproduced.
- **Acceptance:** no full real-browser UI acceptance, production cutover, physical authenticator matrix or actual GitHub/OpenID provider acceptance was performed. Docker/hosted CI were not executed here.
Keep the PHP deployment available until the remaining requirements relevant to that deployment are implemented and tested. Successful limited fixtures are not a certification of all original functionality.
+116
View File
@@ -0,0 +1,116 @@
> Historical 0.1.0 implementation audit. For current implementation status and real PHP reference results, read [CURRENT.md](CURRENT.md) and [VERIFICATION.md](VERIFICATION.md). The source inventories below remain pinned to the same upstream commit.
# Compatibility audit
Source pinned to **3516c776a1fcbd83d234efc007e3a49807d6ed91** (2FAuth upstream). All source paths below are relative to `upstream/`.
`routes.json` inventories 91 application method/path declarations, including expanded apiResource methods, inherited route middleware, constraints and source lines. GET also accepts HEAD. Kernel global/group/alias/priority declarations are included verbatim. This is static source evidence, not Laravel's effective route list: alias expansion, priority sorting, duplicate removal, package routes, CORS preflight and framework fallback behavior still require a booted reference. The API prefix is `/api/v1`; `settingName` is globally `[a-zA-Z]+` (`app/Providers/RouteServiceProvider.php`). API unknown-route text is literally `unknowkn endpoint`.
`database.json` records all 42 ordered migration sources and hashes, including data backfills. It deliberately does not claim to be a materialized SQL schema. `environment.json` maps 170 literal configuration environment names to source locations without reading deployment values; dynamic preference names are listed separately. Regenerate from the repository root:
```sh
python rust-server/tools/inventory.py
```
## Drop-in requirements and blockers
| Area | Required behavior and evidence | Unverified work before a drop-in claim |
|---|---|---|
| Existing databases | SQLite, MySQL, PostgreSQL and SQL Server configured in `config/database.php`. Users, options, accounts, groups, icons, sharing, per-user assignment/order, authentication/OTP logs, sessions/cache, OAuth and WebAuthn tables are migration-backed. | Apply real migrations against fixture databases for each supported driver, compare types/defaults/nullability/indices/foreign keys and preserve migration history. Static declarations are not sufficient. |
| Schema evolution | 2026 group assignment/order migrations backfill legacy values then drop `twofaccounts.group_id` and `order_column`. Passport 13 migration changes clients to owner morphs/redirect_uris/grant_types and drops oauth_personal_access_clients. WebAuthn 2022 migration uses a helper defined after `down()`. | Inspect full helper source and data transformations, exercise upgrades and use current table shapes. Do not recreate the original 2019 account schema as the current schema. |
| Encryption | `config/app.php` selects AES-256-CBC, APP_KEY and APP_PREVIOUS_KEYS. `app/Models/Traits/CanEncryptField.php` invokes Laravel Crypt encryptString/decryptString conditionally on `useEncryption`; account model applies it to fields and pads secrets as Base32. | Implement and test Laravel ciphertext envelope/MAC, key parsing/rotation and actual encrypted fixtures. Returning stored ciphertext as an OTP secret is not compatible. Preserve key and option state. |
| Authentication | `config/auth.php`: web-guard session, api-guard Passport, reverse-proxy-guard custom remote-user provider. `CustomCreateFreshApiToken` mints the first-party `laravel_token` for authenticated responses. `PreventRequestForgery` enables XSRF cookie with no exclusions. | Verify encrypted/signed cookies, session persistence, CSRF exchange (419), JWT/PAT validation/revocation/scopes, password hashing, reset and recovery brokers and remember-me flows. An arbitrary bearer-token lookup is not Passport compatibility. |
| Authorization and sharing | `app/Policies/{TwoFAccount,Group,User}Policy.php`, sharing middleware and model scoping enforce owner/shared recipient/admin rules. New shares/assignments/orders are per-user. | Exercise cross-user negative tests, ownership transfer, all-user scope, admin-only paths, disabling sharing, SSO-only/demo/proxy modes and settings gates. |
| Middleware | `Kernel.php`, middleware sources and RouteServiceProvider implement trim/empty-to-null, forced JSON Accept, throttling, bindings, language, maintenance/CORS/proxy handling and priority. KickOutInactiveUser returns 418 and updates last_seen_at; bearer/proxy users bypass its inactivity tracking. | Verify actual ordering/status/envelopes/cookies. Preserve `rejectIfReverseProxy`, `rejectIfSsoOnlyAndNotForAdmin`, forceLogout and admin policy behaviors. |
| Frontend | `resources/views/landing.blade.php` injects appSettings/appConfig/urls/defaultPreferences/lockedPreferences/appVersion/isDemoApp/isTestingApp/appLocales, CSRF meta and optional CSP nonce. `SinglePageController` computes visitor-safe settings and subdirectory paths. Existing `public/build/manifest.json` and assets are present. | Reuse existing build plus public assets and reproduce bootstrap shape/CSP/base URLs; an unrelated minimal page is not the existing UI. Source rebuild needs sibling `../2FAuth-Components/packages/{formcontrols,stores,styles,ui}` referenced by package.json. |
| Frontend HTTP contract | `resources/js/services/httpClientFactory.js` uses credentials, JSON, X-Requested-With, web root vs `/api/v1`, retries 419 via refresh-csrf, handles 418/407/401/422/404 distinctly. | Browser login, refresh, page reload, account/group/share/icon workflows and translated validation payloads must be tested. |
| OTP and imports | `app/Models/TwoFAccount.php` supports HOTP/TOTP/Steam, next-password payloads, URI parsing/exports; API controllers/resources/requests and service classes define wire format and validation. | Verify SHA algorithms/digits/period, HOTP increment atomicity, Steam, QR image decode/encode, encrypted import/export variants and field/error envelopes against real source fixtures. |
| Integrations/operations | WebAuthn, Socialite OpenID/GitHub, proxy auth, mail notifications/reset, logo fetch, content policy, scheduled log cleanup, cache/optimization and CLI installation are upstream functionality. | A route that returns an explicit unsupported error is honest partial coverage, not parity. All enabled deployment features need implementation and integration tests. |
## Differential HTTP harness
The stdlib-only `tools/differential_http.py` compares two **separate disposable instances with equivalent fixture data**, reporting only case numbers, status codes, comparison booleans or sanitized exception class names. It never prints response bodies, header values, environment values or URLs. Redirect following and retries are disabled. Body limit is 4 MiB. TLS verification remains enabled. Credentials are supplied by environment variable names referenced by a case file, separately for each instance. Cookies are retained only with the explicit `--sessions --allow-side-effects` flags, in separate in-memory jars per instance; they are never written to disk.
```sh
python rust-server/tools/differential_http.py \
--reference http://127.0.0.1:8000 \
--candidate http://127.0.0.1:8080
```
The four original default probes are GET `/up`, `/manifest.json`, `/api/v1/user/name`, and an unknown API path. Three additional defaults check CORS preflight, a cross-origin unauthenticated GET and the same GET without an Origin header. They can create framework sessions/rate-limit counters; no live production instance should be used. `/up` may differ in the framework-rendered HTML even if status is equivalent; exact body comparison intentionally exposes that difference.
All nondefault paths, authenticated requests and mutations outside the built-in safe probes are skipped unless `--allow-side-effects` is supplied. GET alone does not establish safety: upstream logout, optimize, clear-cache, HOTP and activity tracking can mutate state. The illustrative `cases.example.json` includes a public synthetic OTP secret and a real account-creation mutation. Use it only with disposable fixtures and explicit opt-in:
```sh
python rust-server/tools/differential_http.py \
--reference http://127.0.0.1:8000 \
--candidate http://127.0.0.1:8080 \
--cases rust-server/compatibility/cases.example.json --allow-side-effects
```
Cases support `json`, `headers_env.reference`/`headers_env.candidate`, `ignore_json_pointers` and `compare_headers`. Stateful sequences additionally support `capture_json` (capture name to JSON pointer), `{{capture_name}}` references in later paths/JSON, and `headers_from_cookies` (header name to cookie name, URL-decoded). Captures and cookie values remain separate per instance and are never printed. Missing captures/cookies fail the case. `expected_status` makes matching error responses fail when the scenario expected success. A whole JSON placeholder preserves its type; an embedded placeholder becomes text. Bodies are compared exactly after JSON parsing and replacing each configured base URL with `<BASE>`; explicit JSON pointers can exclude nondeterministic fields. Raw OTPs, timestamps, IDs, localized messages and random HTML CSP/CSRF values can differ. Do not indiscriminately mask these differences. Establish a known clock and matched database IDs/fixtures. Selected headers compare exactly in memory; Set-Cookie parity and browser token exchanges need separate stateful tests.
Exit code is 1 for any executed difference or transport failure, 0 when all executed comparisons match. Skips are reported and are never counted as evidence of coverage. A successful default run is seven transport/probe comparisons, not 91 route coverage and not a drop-in certification.
## Verification performed
The inventory generator and harness syntax/help were checked. The harness was exercised against local deterministic stub servers for matching responses, divergent statuses, redirects, skipped mutation cases and sanitized error reporting. A later isolated Laravel 13.29.0 / PHP 8.4.27 reference boot applied all 42 SQLite migrations and ran four default, twelve basic stateful and 23 extended comparisons against the preexisting release binary. See `reference-results.json` for exact sanitized comparisons, binary hash and limitations. This does not certify the current edited Rust source or production compatibility.
## Pinned frontend reuse implemented
`src/frontend.rs` now serves the unmodified upstream Vue build plus allowlisted public image/CSS/robots assets. `public/UPSTREAM-LICENSE` and `UPSTREAM-NOTICE.txt` retain the upstream provenance/license. `frontend-assets.json` records SHA-256 values for every copied public file. PHP is not copied or served. Three targeted frontend tests passed: malicious inline data escaping, visitor redaction, and actual session/cookie/CSP/static-file bootstrap. The module exposes `routes() -> Router<AppState>` and includes the explicit SPA paths from the upstream Vue router, the root alias, static files and manifest. Unknown API paths do not become HTML.
The HTML bootstrap uses the upstream global names and Vite manifest, default/locked user preferences, locales and visitor-safe settings (all nonvisitor option values become null). Inline JSON escapes HTML delimiters and Unicode line separators; title/theme/attribute values are separately HTML-escaped. A generated nonce protects both scripts under CSP. The HTML handler calls the actual native-session `auth::refresh_csrf`, includes its CSRF token in the meta tag and preserves its session/XSRF cookies. It does not invent a separate frontend authentication token. The copied Axios client reads XSRF-TOKEN and submits its same-origin X-XSRF-TOKEN header; login returns the expected user payload and rotates cookies. The upstream authGuard restores current-user state from GET `/api/v1/user` and then fetches accounts/groups.
`RUST_PUBLIC_DIR` can relocate the public asset directory; it defaults to the crate's `public` directory. `APP_NAME`, default/locked preference variables and `CONTENT_SECURITY_POLICY` affect the bootstrap. Native sessions default to Secure cookies; HTTP localhost development requires the explicit `RUST_COOKIE_SECURE=false` setting from the auth module. Nonempty APP_SUBDIRECTORY fails with 503 because mounting only the HTML subpath would leave auth/API/assets inconsistent. Proxy and SSO provider capabilities are not advertised by the experimental bootstrap because those authentication methods are unimplemented. Interface links can still reach unimplemented backend features; displaying the original UI does not establish drop-in backend compatibility.
## Stateful comparison sequence
`cases.stateful.json` exercises CSRF cookie acquisition, password login, current user, HOTP creation, two OTP generations, counter readback, deletion/readback, logout and rejection after logout. Provision `compat@example.invalid` with the public synthetic password in that file on both **disposable** instances, with equivalent nonadministrator fixture users and matching options. Run with:
```sh
python rust-server/tools/differential_http.py \
--reference http://127.0.0.1:8000 --candidate http://127.0.0.1:8080 \
--cases rust-server/compatibility/cases.stateful.json \
--sessions --allow-side-effects
```
The sequence is a starting fixture, not recorded evidence of parity. Random CSRF response bodies and protocol differences intentionally remain visible; only explicitly listed account IDs are ignored in JSON comparisons while per-side IDs drive subsequent requests. It compares state effects through later API reads, not direct database snapshots. It does not establish database schema, cookie cryptography, token persistence, concurrency or browser parity. Timestamps remain unmasked; a clock control is still needed for time-sensitive responses.
`python rust-server/tests/differential_harness.py` verifies typed/escaped JSON captures, separate cookies/IDs, URL-decoded CSRF header replay, mutation readback and expected-status failure against local deterministic stub servers. These are harness regression tests, not PHP-versus-Rust evidence.
The recorded reference run matched 8/12 complete stateful responses. Both HOTP values and counter readback matched; CSRF/login/error bodies still differ. All 12 expected statuses matched. Default probes matched 0/4 complete responses, including PHP 200 versus Rust 404 on the deprecated-name route. These are limited case results, not route coverage percentages.
`cases.extended.json` adds group create/read/delete, administrator denial, disabled-sharing denial, QR encode and invalid decode, import/invalid-account validation and feature flags. The recorded baseline matched 11/23 complete responses; unimplemented routes and validation differences remain visible.
For a reproducible local run, install the pinned `upstream/composer.lock` dependencies with PHP 8.4+ and all extensions in `composer.json`, then run:
```sh
python tools/run_reference.py --php /path/to/php \
--source ../upstream --candidate-binary target/release/twofauth-rs \
--output compatibility/reference-results.local.json
```
The runner creates a new temporary reference application and two fresh SQLite databases, executes all upstream migrations, creates Passport fixture keys and public synthetic regular/admin/recipient users, then launches both servers and runs 99 core comparisons across the four suites plus three CORS transport probes (102 total). It destroys the fixture directory afterward. Source `vendor` must already contain Composer dependencies; it never installs software or changes the source database/configuration. Generated source config/route caches, environment files and existing session/cache state are excluded. Only PHP runtime environment variables are inherited, so deployment configuration/secrets are not reused. Export `PHPRC` if your PHP runtime needs a custom extension configuration, including for child PHP processes. The result includes the candidate binary SHA-256. Exit 1 means actual compatibility differences; exit 2 means setup failed. No production service is involved.
Use `--candidate-db laravel-copy` to test against a SQLite backup of the real migrated PHP fixture schema. In that mode the runner preserves the PHP user/password record and invokes `prepare-sqlite` to add the Rust authentication sidecars. Use `--candidate-db native` (the default) for the independent development schema. Both modes use new disposable databases; neither accepts a deployment database path.
`sqlite-reference-schema.sql` records the actual SQLite DDL produced by all 42 migrations (22 application tables, 34 explicit indexes), without fixture rows. The DDL was replayed successfully into an empty SQLite database. It documents this driver only; MySQL, PostgreSQL and SQL Server still require real materialization and comparison.
`cases.admin-sharing.json` adds administrator settings/user mutations and multi-user sharing checks. The runner creates a regular user, an administrator and a recipient on both servers, preserving the original regular-user scenarios. It exercises custom setting CRUD, actual encryption on/off with account readback, last-administrator protections, user creation/promotion/demotion, empty PAT revocation, explicit/all-user sharing, secret suppression, export denial, deterministic HOTP, visible counts, independent per-user groups, revocation and self-transfer validation. Role switches explicitly refresh CSRF cookies before login. JSON assertions independently check missing secrets, RFC HOTP, counts and owner group independence. The fixture sets THROTTLE_API=1000 to accommodate the bulk sequence; default rate-limit equivalence is a separate test requirement.
Add `--semantic-checks` to preserve every exact comparison and separately check three nondeterministic representations: health HTML equality after changing only the numeric render duration, textual CSRF token shape plus successful subsequent login, and both rendered QR payloads. QR checks require Node `sharp` and use the reference PHP `Zxing\QrReader` to decode each SVG after rasterization. Both decoded provisioning URIs must match each other and the known synthetic fixture. Render/decode failures are reported explicitly. Raw QR bytes, random CSRF strings and health render times remain visible as exact differences; semantic results never replace them.
Static `headers` are supported for synthetic protocol probes; header values are never printed. `expected_headers`, `expected_json`, `absent_json_pointers` and `expect_text_token` add assertions independently of response equality. The three CORS probes compare status and allow-origin/method/header behavior, assert wildcard origins without credentials and assert the source wildcard header is retained even when Origin is absent. The original 99 core case count is retained separately from these three added transport checks.
## Historical 0.2.0 reference evidence
The 0.2.0 run, retained in `VERIFICATION-0.2.0.md`, used independent native and copied Laravel SQLite fixture schemas. It executed 102 comparisons per schema (99 core cases plus three CORS probes), with 91 exact responses each. The filenames `reference-results.native.json` and `reference-results.laravel.json` now hold the latest release results; see `VERIFICATION.md` for their current counts and hash. All statuses, content types, selected/expected headers and independent scenario assertions matched. CORS preflight, actual cross-origin requests and requests without Origin matched exactly.
The eleven remaining exact body differences per schema are nine independently generated CSRF strings, one health render duration and one QR image encoding. Separate checks passed for health equality after changing only the render-duration number, valid textual CSRF tokens followed by successful login, and both rendered QR images decoding to the same expected synthetic provisioning URI. Raw differences remain recorded. No cases were skipped and no transport/capture errors occurred. These finite fixtures do not certify every route, integration, deployment configuration or supported database driver.
`reference-results.json` preserves the earlier baseline and upstream-suite/DNS limitations; it is not the final release report. Both final reports carry the candidate SHA-256, harness/case hashes and explicit fixture configuration.
+40
View File
@@ -0,0 +1,40 @@
# Verification record — 2026-10-27, version 0.2.0
Target: upstream 2FAuth 8.0.3, commit `3516c776a1fcbd83d234efc007e3a49807d6ed91`.
Tested included Linux x86_64 GNU executable SHA-256:
`878d842c502f35dc1ec078a023dafe9dc23604fda0d01aa0703089bf116ba152`
| Check | Executed result | Scope and limits |
|---|---|---|
| Rust tests, `cargo test --locked --all-targets` | **101 passed, 0 failed** | Includes actual WebAuthn crypto/recovery, sharing, imports, mail, OAuth/OIDC, authentication, settings/encryption, middleware and subdirectory tests. Count is not total route/configuration coverage. |
| Formatting | Passed | `cargo fmt --all -- --check`; source formatted after final changes. |
| Strict Clippy | Passed | `cargo clippy --locked --all-targets -- -D warnings`. |
| Release build | Passed | Linux x86_64 GNU; bundled binary requires glibc 2.39 and libgcc_s. Vendored OpenSSL, optimized non-LTO release. |
| Release HTTP/CLI smoke | Passed | Fresh DB, refusal to re-init, test-user provisioning, HTML/CSP/cookies, login/CSRF, CRUD/secrets, independent HOTP calculations, permissions, logout and process shutdown. |
| Relocated executable/assets | Passed | Copied binary/public to an unrelated folder, ran from a different CWD, HTML and PNG assets loaded without RUST_PUBLIC_DIR. |
| Direct startup of a copied Laravel DB | Passed | No prepare command required; original application DDL, migration rows and user/password rows unchanged; only rust_-prefixed metadata tables added. |
| Real PHP reference | Runs | PHP 8.4.27, locked Laravel 13.29.0; all 42 upstream migrations applied. DDL retained in sqlite-reference-schema.sql. |
| Native Rust database HTTP comparisons | **102 executed**, all statuses/checks match | 91 exact responses; 11 expected dynamic/encoding body differences as detailed below. |
| Copied Laravel database HTTP comparisons | **102 executed**, all statuses/checks match | Same results on real migrated tables and PHP password hashes. |
| Default CORS HTTP comparisons | 3 exact matches in each mode | Preflight, request with Origin, request without Origin; wildcard/default no-credentials policy. |
| Supplemental semantic checks | Passed on both modes | Health differs only by render milliseconds; plain CSRF token followed by successful login; both SVG QR codes rendered and decoded with PHP's reader into the exact same fixture URI. |
| Real Passport interoperability | **11 checks passed** | PHP bearer/cookie accepted by Rust; Rust PAT accepted by actual PHP League ResourceServer; CSRF, tampering and revocation rejected; PHP browser upgraded, legacy cookie cleared, logout prevents subsequent use. |
| Python harness regression tests | **5 passed** | Stateful cookies, headers, captures, normalization, mismatches and sanitized failures. |
| Independent crypto | 6 fixtures passed PHP OpenSSL and Laravel Encrypter | AES-128/256-CBC/HMAC, empty/ASCII/Unicode; both independent Python generation and actual PHP decryptString verification. |
| Upstream PHPUnit reference suite | 1,518 tests, 4,573 assertions; 5 errors, 2 failures | All seven remaining failures involve unavailable real DNS before mocked icon HTTP. This is a reference-environment result, not a claim Rust passed the PHP test suite. |
| Docker / hosted CI / real browser acceptance | Not executed | Files provided; Docker tool/daemon unavailable. No physical authenticator or real external SSO provider acceptance was performed. |
| Production migration/cutover | Not performed | Only disposable synthetic data and copied fixtures were used. |
## Raw differential accounting
Each database mode executes 7 default/CORS probes, 12 basic stateful calls, 23 extended calls and 60 admin/sharing calls. Native and copied-Laravel modes each produce **91/102 exact matches**. All 102 statuses, content types, selected headers, expected statuses, explicit JSON assertions and CSRF shape checks pass. There are no skipped probes, transport errors or unexpected rate-limit responses.
The eleven remaining raw body differences are nine random CSRF tokens, one health render-time number and one SVG QR representation. They remain visible in the raw reports. Their relevant behavior is independently checked; QR pixels or random strings were not simply discarded to claim equality.
The synthetic fixture API quota is raised to 1000 on both instances so the expanded sequence fits one run. Default/API/import limits, expiry, concurrency, trusted proxies and spoofing are separately tested. Raw comparisons and all provenance/case hashes are retained in `reference-results.native.json` and `reference-results.laravel.json`. The old `reference-results.json` is preserved as a baseline.
## What this does not establish
**Full replacement has not been reached.** Other database drivers, full package OAuth endpoints, every Laravel session/remember-me mode, historic migration paths, configuration/localization edge cases and complete browser/provider acceptance still remain. See `CURRENT.md` for precise remaining scope.
+43
View File
@@ -0,0 +1,43 @@
# Verification record — 2026-10-28, version 0.3.0
Target: upstream 2FAuth 8.0.3, commit `3516c776a1fcbd83d234efc007e3a49807d6ed91`.
Historical 0.2.0 results, including its upstream PHPUnit run, are retained in `VERIFICATION-0.2.0.md`; they are not rerun claims for this binary.
## Executed checks
Included Linux x86_64 GNU executable SHA-256: `0e03e978721bf4fcfc65e18e4a98f47b26b71a151c792b380d18996ae467813d`.
| Check | Executed result |
|---|---|
| Rust: cargo test --locked --all-targets | **137 passed, 0 failed** |
| Formatting and strict Clippy | Passed; cargo fmt --all -- --check; cargo clippy --locked --all-targets -- -D warnings |
| Optimized release and CLI/HTTP smoke | Passed; Linux x86_64 GNU, glibc >=2.39; libc/libm/libgcc_s runtime dependencies |
| Native SQLite HTTP comparison | **140 executed: 129 exact, 11 expected raw body differences** |
| Copied migrated Laravel SQLite comparison | **140 executed: 129 exact, 11 expected raw body differences** |
| Additional OAuth/device HTTP cases | **38 exact per database mode**; error/status/hint/cache/challenge and default web CSRF contracts |
| Semantic health, CSRF/login and rendered QR checks | Passed in both database modes |
| Actual PHP Passport interoperability | **11 checks passed in each database mode** |
| PHP authorization-code/refresh/RSA wire checks | **5 passed**; actual PHP Defuse decrypt/encrypt and OpenSSL verification |
| Laravel session process combinations | **8 passed**: file/database × JSON/PHP × plain/encrypted |
| Device grant interoperability | **8 passed**: PHP-issued code, PHP approval, Rust tokens checked by actual PHP ResourceServer; pending/backoff, deny, expiry and replay |
| Python comparison harness | **6 passed, 0 failed** |
| Independent Python/PHP OpenSSL CBC fixtures | **6 passed** |
All 140 statuses, content types, selected headers, explicit JSON assertions and scenario checks match in both database modes. The 11 raw differences are confined to the original core sequence; all 38 new OAuth/device cases are exact. Both runs retain THROTTLE_API=1000 only for the large API fixture sequence. OAuth/default web quotas are not increased. Supplemental login/QR semantics run before the OAuth error burst so the PHP shared unnamed throttle does not invalidate their setup.
Full reports and provenance are in reference-results.native.json, reference-results.laravel.json, interop-results.json, passport-interop-results.json and device-interop.json. Actual PHP protocol observations are retained separately in oauth-php-reference.json, oauth-php-body-reference.json and oauth-device-php-reference.json.
## What this establishes
The original 102-case HTTP sequence runs against both a native Rust SQLite database and an actual migrated PHP database copied with SQLite backup. Eleven raw response body differences are retained: nine random CSRF tokens, the health render duration and SVG QR representation. Supplemental checks verify login after CSRF, health apart from its numeric rendering time, and both rendered QR images decoded with PHP into the expected fixture URI. No random-value or QR exclusions are used to claim byte equality.
Additional OAuth cases compare the actual errors, descriptions, hints, statuses and selected cache/challenge headers. The standard token endpoint accepts form and JSON payloads as Laravel does. Success, PKCE, cryptographic interoperability, refresh replay rejection and client-credential scopes are checked separately using actual PHP Defuse and OpenSSL.
Laravel session HTTP tests cover file/database × JSON/PHP scalar-array serialization × encrypted/plain storage. They verify encrypted XSRF, Passport refresh, source store destruction on HTML bootstrap, native requests after refresh, remember-token rotation, and replay through HTML import after logout. Unit tests also require import to rotate an anonymous native SID and logout to revoke both identities when stale cookies name different users.
## Limits
Full replacement has not been reached. Only SQLite is supported. Redis/cookie/other session drivers, the complete configuration/localization/middleware matrix, historical migration paths and full real-browser/provider acceptance remain unverified or unimplemented. Fixed optional OAuth management/consent behavior is explicitly opt-in because the pinned PHP source has broken/disabled routes. See `CURRENT.md` and `database-portability.md`.
Docker, physical authenticators, production cutover and live GitHub/OpenID providers were not tested in this pass. All process tests use disposable synthetic users, keys, databases and ports.
+715
View File
@@ -0,0 +1,715 @@
[
{
"id": "fresh-csrf",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-admin",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "admin@example.invalid",
"password": "Synthetic-compat-password-4620"
},
"capture_json": {
"admin_id": "/id"
}
},
{
"id": "last-admin-demote-denied",
"path": "/api/v1/users/{{admin_id}}/promote",
"method": "PATCH",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"is_admin": false
}
},
{
"id": "last-admin-delete-denied",
"path": "/api/v1/users/{{admin_id}}",
"method": "DELETE",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "recipient-admin-read",
"path": "/api/v1/users/3",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"capture_json": {
"recipient_id": "/info/id"
},
"ignore_json_pointers": [
"/info/id",
"/info/last_seen_at",
"/info/created_at"
]
},
{
"id": "admin-create-user",
"path": "/api/v1/users",
"method": "POST",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"name": "Managed",
"email": "managed@example.invalid",
"password": "Synthetic-managed-password-4620",
"password_confirmation": "Synthetic-managed-password-4620",
"is_admin": false
},
"capture_json": {
"managed_id": "/info/id"
},
"ignore_json_pointers": [
"/info/id",
"/info/last_seen_at",
"/info/created_at"
]
},
{
"id": "promote-user",
"path": "/api/v1/users/{{managed_id}}/promote",
"method": "PATCH",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"is_admin": true
},
"ignore_json_pointers": [
"/info/id",
"/info/last_seen_at",
"/info/created_at"
]
},
{
"id": "demote-user",
"path": "/api/v1/users/{{managed_id}}/promote",
"method": "PATCH",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"is_admin": false
},
"ignore_json_pointers": [
"/info/id",
"/info/last_seen_at",
"/info/created_at"
]
},
{
"id": "revoke-empty-pats",
"path": "/api/v1/users/{{managed_id}}/pats",
"method": "DELETE",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "delete-managed-user",
"path": "/api/v1/users/{{managed_id}}",
"method": "DELETE",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "custom-setting-create",
"path": "/api/v1/settings",
"method": "POST",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"key": "compatCustom",
"value": "first"
}
},
{
"id": "custom-setting-read",
"path": "/api/v1/settings/compatCustom",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "custom-setting-update",
"path": "/api/v1/settings/compatCustom",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": "second"
}
},
{
"id": "custom-setting-delete",
"path": "/api/v1/settings/compatCustom",
"method": "DELETE",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "custom-setting-deleted",
"path": "/api/v1/settings/compatCustom",
"method": "GET",
"expected_status": 404,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "owner-create-hotp",
"path": "/api/v1/twofaccounts",
"method": "POST",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"service": "compat-sharing",
"account": "fixture@example.invalid",
"otp_type": "hotp",
"secret": "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
"digits": 6,
"algorithm": "sha1",
"counter": 0
},
"capture_json": {
"shared_id": "/id"
},
"ignore_json_pointers": [
"/id"
]
},
{
"id": "setting-useEncryption-True",
"path": "/api/v1/settings/useEncryption",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": true
}
},
{
"id": "encrypted-account-read",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/id"
]
},
{
"id": "setting-useEncryption-False",
"path": "/api/v1/settings/useEncryption",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": false
}
},
{
"id": "decrypted-account-read",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/id"
]
},
{
"id": "setting-enableSharing-True",
"path": "/api/v1/settings/enableSharing",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": true
}
},
{
"id": "setting-enableAllUsersSharingScope-True",
"path": "/api/v1/settings/enableAllUsersSharingScope",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": true
}
},
{
"id": "share-explicit-recipient",
"path": "/api/v1/twofaccounts/{{shared_id}}/shares",
"method": "POST",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"user_ids": [
"{{recipient_id}}"
]
},
"ignore_json_pointers": [
"/twofaccount_id"
]
},
{
"id": "logout-owner",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "refresh-before-recipient",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-recipient",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "recipient@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "recipient-read-secret-hidden",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/id"
],
"absent_json_pointers": [
"/secret"
]
},
{
"id": "recipient-export-denied",
"path": "/api/v1/twofaccounts/export?ids={{shared_id}}",
"method": "GET",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "recipient-hotp",
"path": "/api/v1/twofaccounts/{{shared_id}}/otp",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"expected_json": {
"/password": "755224"
}
},
{
"id": "recipient-visible-count",
"path": "/api/v1/twofaccounts/count",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"expected_json": {
"/owned": 0,
"/shared": 1,
"/total": 1
}
},
{
"id": "recipient-group-create",
"path": "/api/v1/groups",
"method": "POST",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"name": "Borrowed group",
"show_in_chips": true
},
"capture_json": {
"recipient_group": "/id"
},
"ignore_json_pointers": [
"/id"
]
},
{
"id": "recipient-group-assign",
"path": "/api/v1/groups/{{recipient_group}}/assign",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"ids": [
"{{shared_id}}"
]
},
"ignore_json_pointers": [
"/id"
],
"expected_json": {
"/twofaccounts_count": 1
}
},
{
"id": "recipient-group-read",
"path": "/api/v1/groups/{{recipient_group}}",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/id"
],
"expected_json": {
"/twofaccounts_count": 0
}
},
{
"id": "recipient-group-index-count",
"path": "/api/v1/groups",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/1/id"
],
"expected_json": {
"/1/twofaccounts_count": 1
}
},
{
"id": "logout-recipient",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "refresh-before-admin",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-admin",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "admin@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "owner-group-independence",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/id"
],
"expected_json": {
"/group_id": null
}
},
{
"id": "owner-transfer-self-validation",
"path": "/api/v1/twofaccounts/{{shared_id}}/owner",
"method": "PATCH",
"expected_status": 422,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"new_owner_id": "{{admin_id}}",
"confirm_password": "Synthetic-compat-password-4620"
}
},
{
"id": "revoke-explicit-share",
"path": "/api/v1/twofaccounts/{{shared_id}}/shares/{{recipient_id}}",
"method": "DELETE",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "logout-owner",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "refresh-before-recipient",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-recipient",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "recipient@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "recipient-after-revocation",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "GET",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "logout-recipient",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "refresh-before-admin",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-admin",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "admin@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "share-all-scope",
"path": "/api/v1/twofaccounts/{{shared_id}}/shares/all",
"method": "POST",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {},
"ignore_json_pointers": [
"/twofaccount_id"
]
},
{
"id": "logout-owner",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "refresh-before-recipient",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-recipient",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "recipient@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "recipient-all-scope-read",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"ignore_json_pointers": [
"/id"
],
"absent_json_pointers": [
"/secret"
]
},
{
"id": "logout-recipient",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "refresh-before-admin",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login-admin",
"path": "/user/login",
"method": "POST",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "admin@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "revoke-all-shares",
"path": "/api/v1/twofaccounts/{{shared_id}}/shares",
"method": "DELETE",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "delete-shared-account",
"path": "/api/v1/twofaccounts/{{shared_id}}",
"method": "DELETE",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "setting-enableSharing-False",
"path": "/api/v1/settings/enableSharing",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": false
}
},
{
"id": "setting-enableAllUsersSharingScope-False",
"path": "/api/v1/settings/enableAllUsersSharingScope",
"method": "PUT",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"value": false
}
},
{
"id": "logout-admin",
"path": "/user/logout",
"method": "GET",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
}
]
+185
View File
@@ -0,0 +1,185 @@
[
{
"id": "issuer-missing-client",
"path": "/oauth/device/code",
"method": "POST",
"expected_status": 400,
"expected_json": {
"/error": "invalid_request",
"/error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"/hint": "Check the `client_id` parameter"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"form": {}
},
{
"id": "issuer-unknown-client",
"path": "/oauth/device/code",
"method": "POST",
"expected_status": 401,
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"form": {
"client_id": "unknown-device-client"
}
},
{
"id": "GET /oauth/device",
"path": "/oauth/device",
"method": "GET",
"expected_status": 500,
"expected_json": {
"/message": "Server Error"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
}
},
{
"id": "GET /oauth/device/authorize",
"path": "/oauth/device/authorize",
"method": "GET",
"expected_status": 401,
"expected_json": {
"/message": "Unauthenticated."
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
}
},
{
"id": "POST /oauth/device/authorize",
"path": "/oauth/device/authorize",
"method": "POST",
"expected_status": 419,
"expected_json": {
"/message": "CSRF token mismatch."
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"json": {}
},
{
"id": "DELETE /oauth/device/authorize",
"path": "/oauth/device/authorize",
"method": "DELETE",
"expected_status": 419,
"expected_json": {
"/message": "CSRF token mismatch."
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"json": {}
},
{
"id": "POST /oauth/authorize",
"path": "/oauth/authorize",
"method": "POST",
"expected_status": 419,
"expected_json": {
"/message": "CSRF token mismatch."
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"json": {}
},
{
"id": "DELETE /oauth/authorize",
"path": "/oauth/authorize",
"method": "DELETE",
"expected_status": 419,
"expected_json": {
"/message": "CSRF token mismatch."
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"json": {}
},
{
"id": "POST /oauth/token/refresh",
"path": "/oauth/token/refresh",
"method": "POST",
"expected_status": 419,
"expected_json": {
"/message": "CSRF token mismatch."
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null
},
"json": {}
}
]
+8
View File
@@ -0,0 +1,8 @@
[
{"id":"health", "method":"GET", "path":"/up"},
{"id":"authenticated-user", "method":"GET", "path":"/api/v1/user", "side_effects":true,
"headers_env":{"reference":{"Authorization":"COMPAT_REFERENCE_AUTH"},"candidate":{"Authorization":"COMPAT_CANDIDATE_AUTH"}}},
{"id":"create-account-fixture", "method":"POST", "path":"/api/v1/twofaccounts", "side_effects":true,
"headers_env":{"reference":{"Authorization":"COMPAT_REFERENCE_AUTH"},"candidate":{"Authorization":"COMPAT_CANDIDATE_AUTH"}},
"json":{"service":"compat-fixture","account":"fixture@example.invalid","otp_type":"totp","secret":"JBSWY3DPEHPK3PXP","digits":6,"algorithm":"sha1","period":30}}
]
+238
View File
@@ -0,0 +1,238 @@
[
{
"id": "fresh-csrf",
"method": "GET",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login",
"method": "POST",
"path": "/user/login",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "compat@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "current-user",
"method": "GET",
"path": "/api/v1/user",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "create-hotp",
"method": "POST",
"path": "/api/v1/twofaccounts",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"service": "compat-fixture",
"account": "fixture@example.invalid",
"otp_type": "hotp",
"secret": "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
"digits": 6,
"algorithm": "sha1",
"counter": 0
},
"capture_json": {
"account_id": "/id"
},
"ignore_json_pointers": [
"/id"
]
},
{
"id": "read-created",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 200,
"ignore_json_pointers": [
"/id"
],
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "hotp-counter-zero",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}/otp",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "hotp-counter-one",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}/otp",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "read-counter-effect",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 200,
"ignore_json_pointers": [
"/id"
],
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "group-create",
"method": "POST",
"path": "/api/v1/groups",
"json": {
"name": "Compat group"
},
"expected_status": 201,
"capture_json": {
"group_id": "/id"
},
"ignore_json_pointers": [
"/id"
],
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "group-read",
"path": "/api/v1/groups/{{group_id}}",
"expected_status": 200,
"ignore_json_pointers": [
"/id"
],
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "group-delete",
"method": "DELETE",
"path": "/api/v1/groups/{{group_id}}",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "settings-admin-denial",
"path": "/api/v1/settings",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "users-admin-denial",
"path": "/api/v1/users",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "sharing-disabled-denial",
"path": "/api/v1/twofaccounts/{{account_id}}/shares",
"expected_status": 403,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "qr-encode-account",
"path": "/api/v1/twofaccounts/{{account_id}}/qrcode",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "qr-decode-invalid",
"method": "POST",
"path": "/api/v1/qrcode/decode",
"json": {},
"expected_status": 422,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "migration-empty-validation",
"method": "POST",
"path": "/api/v1/twofaccounts/migration",
"json": {},
"expected_status": 422,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "invalid-account-validation",
"method": "POST",
"path": "/api/v1/twofaccounts",
"json": {},
"expected_status": 422,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "feature-flags",
"path": "/api/v1/features",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "delete-created",
"method": "DELETE",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "read-deletion-effect",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 404,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "logout",
"method": "GET",
"path": "/user/logout",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "read-logout-effect",
"method": "GET",
"path": "/api/v1/user",
"expected_status": 401
}
]
+764
View File
@@ -0,0 +1,764 @@
[
{
"id": "missing-grant-type",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "unsupported-grant-empty",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": ""
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "unsupported-grant-bogus",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "bogus"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "unsupported-grant-password",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "password"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "unsupported-grant-implicit",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "implicit"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "unsupported-grant-personal_access",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "personal_access"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "device-grant-missing-client",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "urn:ietf:params:oauth:grant-type:device_code"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_request",
"/error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"/hint": "Check the `client_id` parameter"
}
},
{
"id": "missing-client-client_credentials",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "client_credentials"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_request",
"/error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"/hint": "Check the `client_id` parameter"
}
},
{
"id": "unknown-client-client_credentials",
"path": "/oauth/token",
"method": "POST",
"expected_status": 401,
"form": {
"grant_type": "client_credentials",
"client_id": "999999",
"client_secret": "synthetic-invalid-secret"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
}
},
{
"id": "missing-client-authorization_code",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "authorization_code"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_request",
"/error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"/hint": "Check the `client_id` parameter"
}
},
{
"id": "unknown-client-authorization_code",
"path": "/oauth/token",
"method": "POST",
"expected_status": 401,
"form": {
"grant_type": "authorization_code",
"client_id": "999999",
"client_secret": "synthetic-invalid-secret"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
}
},
{
"id": "missing-client-refresh_token",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "refresh_token"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_request",
"/error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"/hint": "Check the `client_id` parameter"
}
},
{
"id": "unknown-client-refresh_token",
"path": "/oauth/token",
"method": "POST",
"expected_status": 401,
"form": {
"grant_type": "refresh_token",
"client_id": "999999",
"client_secret": "synthetic-invalid-secret"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
}
},
{
"id": "json-unsupported",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"json": {
"grant_type": "bogus"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "json-null-grant",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"json": {
"grant_type": null
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "json-array-grant",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"json": {
"grant_type": [
"client_credentials"
]
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
}
},
{
"id": "json-unknown-client",
"path": "/oauth/token",
"method": "POST",
"expected_status": 401,
"json": {
"grant_type": "client_credentials",
"client_id": 999999,
"client_secret": "synthetic-invalid-secret"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
}
},
{
"id": "malformed-basic-missing-client",
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"form": {
"grant_type": "client_credentials"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_request",
"/error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"/hint": "Check the `client_id` parameter"
},
"headers": {
"Authorization": "Basic not-base64"
}
},
{
"id": "basic-unknown-client",
"path": "/oauth/token",
"method": "POST",
"expected_status": 401,
"form": {
"grant_type": "client_credentials"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": "Basic realm=\"OAuth\"",
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
},
"headers": {
"Authorization": "Basic OTk5OTk5OnN5bnRoZXRpYy1pbnZhbGlkLXNlY3JldA=="
}
},
{
"id": "bearer-header-unknown-client",
"path": "/oauth/token",
"method": "POST",
"expected_status": 401,
"form": {
"grant_type": "client_credentials",
"client_id": "999999"
},
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": "Bearer realm=\"OAuth\"",
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_client",
"/error_description": "Client authentication failed"
},
"headers": {
"Authorization": "Bearer synthetic-invalid"
}
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
},
"id": "json-top-array",
"json": []
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
},
"id": "json-top-number",
"json": 42
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
},
"id": "json-top-nonempty-array",
"json": [
"bogus"
]
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/message": "Bad request."
},
"id": "json-malformed",
"raw": "{",
"headers": {
"Content-Type": "application/json"
}
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/message": "Bad request."
},
"id": "json-top-null",
"raw": "null",
"headers": {
"Content-Type": "application/json"
}
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
},
"id": "json-empty-body",
"raw": "",
"headers": {
"Content-Type": "application/json"
}
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
},
"id": "form-scalar-then-array",
"raw": "grant_type=bogus&grant_type[]=client_credentials",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
}
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "unsupported_grant_type",
"/error_description": "The authorization grant type is not supported by the authorization server.",
"/hint": "Check that all required parameters have been provided"
},
"id": "form-array-then-scalar",
"raw": "grant_type[]=client_credentials&grant_type=bogus",
"headers": {
"Content-Type": "application/x-www-form-urlencoded"
}
},
{
"path": "/oauth/token",
"method": "POST",
"expected_status": 400,
"compare_headers": [
"Cache-Control",
"Pragma",
"WWW-Authenticate",
"X-RateLimit-Limit"
],
"expected_headers": {
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60"
},
"expected_json": {
"/error": "invalid_request",
"/hint": "Check the `client_id` parameter"
},
"id": "unicode-trimmed-grant",
"json": {
"grant_type": " client_credentials"
}
}
]
+130
View File
@@ -0,0 +1,130 @@
[
{
"id": "fresh-csrf",
"method": "GET",
"path": "/refresh-csrf",
"expected_status": 200,
"expect_text_token": true
},
{
"id": "login",
"method": "POST",
"path": "/user/login",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"email": "compat@example.invalid",
"password": "Synthetic-compat-password-4620"
}
},
{
"id": "current-user",
"method": "GET",
"path": "/api/v1/user",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "create-hotp",
"method": "POST",
"path": "/api/v1/twofaccounts",
"expected_status": 201,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
},
"json": {
"service": "compat-fixture",
"account": "fixture@example.invalid",
"otp_type": "hotp",
"secret": "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ",
"digits": 6,
"algorithm": "sha1",
"counter": 0
},
"capture_json": {
"account_id": "/id"
},
"ignore_json_pointers": [
"/id"
]
},
{
"id": "read-created",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 200,
"ignore_json_pointers": [
"/id"
],
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "hotp-counter-zero",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}/otp",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "hotp-counter-one",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}/otp",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "read-counter-effect",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 200,
"ignore_json_pointers": [
"/id"
],
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "delete-created",
"method": "DELETE",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 204,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "read-deletion-effect",
"method": "GET",
"path": "/api/v1/twofaccounts/{{account_id}}",
"expected_status": 404,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "logout",
"method": "GET",
"path": "/user/logout",
"expected_status": 200,
"headers_from_cookies": {
"X-XSRF-TOKEN": "XSRF-TOKEN"
}
},
{
"id": "read-logout-effect",
"method": "GET",
"path": "/api/v1/user",
"expected_status": 401
}
]
+47
View File
@@ -0,0 +1,47 @@
# Database portability audit
The current runtime supports SQLite. PostgreSQL, MySQL/MariaDB and SQL Server are upstream deployment options, but are not implemented by this Rust backend. Changing the connection URL or enabling SQLx features does not establish compatibility.
## Implementation boundary
`AppState` stores `SqlitePool`; handlers expose `SqliteConnection` and `SqliteRow`, and use direct SQLx queries throughout. Introduce a backend-neutral pool/transaction/query boundary with typed bound values and normalized results. Keep native SQLx SQLite/PostgreSQL/MySQL drivers; SQLx 0.8 has no SQL Server driver, so SQL Server needs a separate driver such as Tiberius. Cargo.lock contains SQLx PostgreSQL and MySQL 0.8.6 packages; Cargo.toml currently enables only SQLite. A lockfile entry does not mean a driver is enabled or tested.
Use explicit backend implementations for insert-and-return-ID, upsert, atomic consume-once records and rate-limit increments. Generic placeholder replacement cannot translate these semantics or normalize returned native types. Preserve transaction affinity when retrieving generated IDs.
| Current form | PostgreSQL | MySQL/MariaDB | SQL Server |
| --- | --- | --- | --- |
| `?` binds | `$1`, `$2`, etc. | `?` | `@P1`, `@P2`, etc. |
| `last_insert_rowid()` | `INSERT ... RETURNING id` | insert result ID | `OUTPUT INSERTED.id` |
| `ON CONFLICT ...` | supported with compatible targets | explicit duplicate-key update | transactional update/insert with appropriate locking |
| `DELETE ... RETURNING` | supported | locked read/delete transaction as needed by server/version | `DELETE ... OUTPUT DELETED...` |
| `datetime('now', ...)` | typed UTC timestamp comparisons | typed UTC timestamp comparisons | typed UTC timestamp comparisons |
| `json_each(grant_types)` | native JSON conversion or application decoding | JSON expression or application decoding | JSON expression or application decoding |
| `INSERT OR IGNORE` | conflict-targeted `DO NOTHING` | conflict-specific handling; avoid suppressing unrelated errors | constraint-aware transaction |
| nullable `ip_address IS ?` | `IS NOT DISTINCT FROM` | `<=>` | equality plus explicit both-null condition |
| `LIMIT` | supported | supported | `TOP` or ordered `OFFSET/FETCH` |
| `CAST(id AS TEXT)` | supported | compatible character cast | compatible character cast |
Quote identifiers consistently: `key`, `groups` and `window` can collide with dialect keywords. SQLite `PRAGMA` introspection must become PostgreSQL/MySQL information-schema and SQL Server catalog queries. Rust metadata DDL also needs per-backend generated IDs, bounded indexed strings, timestamp representations and index-existence checks; SQLite `TEXT PRIMARY KEY` and `CREATE INDEX IF NOT EXISTS` are not portable.
## Schema and value normalization
Keep pinned PHP migrations authoritative for application tables. Validate an offline migrated database before creating only Rust-owned metadata tables. Do not attempt to recreate production schemas from the simplified development DDL.
Laravel columns are not uniformly signed 64-bit integers. Users use big IDs; account IDs originate as unsigned integer; digits use unsigned small integer; periods use unsigned integer; counters may be unsigned big integer. PostgreSQL `smallint`/`integer` cannot simply be decoded with SQLx's `i64` implementation. MySQL unsigned-bigint counters can exceed `i64::MAX`; reject unsupported ranges explicitly or retain `u64` through the data path. SQL Server uses its own numeric and bit representations. Real PostgreSQL booleans also require boolean predicates instead of `=0` and `=1`.
Timestamps are native database timestamp columns, although SQLite handlers currently decode them as strings. WebAuthn additionally contains UUID and JSON fields on databases that support those types. Normalize timestamps to UTC, booleans to Rust `bool`, integer widths explicitly, and UUID/JSON values without losing nullability. Do not convert arbitrary database errors into conflict success.
`schema_validation.rs` checks required SQLite application columns, primary keys, non-partial uniqueness and delete actions against the materialized pinned migration DDL. Obsolete `twofaccounts.group_id`/`order_column` and framework cache/migration tables are excluded. Laravel sessions are required only with the database session driver. This validator is a structural prerequisite, not proof of cross-database behavior.
## Required interoperability evidence
For each supported engine, run pinned PHP migrations in a disposable database and seed identical synthetic fixtures. Run the differential HTTP suite against Rust, then reopen records written by Rust with PHP. Include:
- encrypted accounts and key rotation; nullable strings, booleans, timestamps and numeric boundary values;
- Passport clients, tokens and revocation; Laravel session payloads; WebAuthn UUID/JSON/key fields;
- unique usernames, group assignments, per-user account ordering and share targets;
- account/user deletion and foreign-key cascade/set-null behavior;
- simultaneous consume-once challenges, rate-limit increments, registration and HOTP generation;
- failed statements, transaction rollback and connection reuse.
A successful connection or compilation does not demonstrate migrated-schema compatibility. Each engine needs a recorded migrated schema, driver/server versions, HTTP comparison results and PHP read-back results before its support claim can change.
+547
View File
@@ -0,0 +1,547 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"kind": "ordered migration evidence; not a materialized SQL schema",
"drivers": [
"sqlite",
"mysql",
"pgsql",
"sqlsrv"
],
"migrations": [
{
"file": "database/migrations/2014_10_12_000000_create_users_table.php",
"sha256": "9a54cf93367bc7c19790a5c0f8182f733c48692f559a2fc3bc6285caedcc9f2c",
"schema_operations": [
[
"create",
"users"
]
],
"up_source": "<?php\n\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass CreateUsersTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::create('users', function (Blueprint $table) {\n $table->bigIncrements('id');\n $table->string('name');\n $table->string('email')->unique();\n $table->timestamp('email_verified_at')->nullable();\n $table->string('password');\n $table->rememberToken();\n $table->timestamps();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2014_10_12_100000_create_password_resets_table.php",
"sha256": "42824028ead8eb9813f0d568f830def27145d5ac52288021cb7a6337d3810c41",
"schema_operations": [
[
"create",
"password_resets"
]
],
"up_source": "<?php\n\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass CreatePasswordResetsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::create('password_resets', function (Blueprint $table) {\n $table->string('email')->index();\n $table->string('token');\n $table->timestamp('created_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2016_06_01_000001_create_oauth_auth_codes_table.php",
"sha256": "90ab218a2616ba5e7320fbfe57fd0f8cf39a85542300634fecf691a85a6bf6bb",
"schema_operations": [
[
"create",
"oauth_auth_codes"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('oauth_auth_codes', function (Blueprint $table) {\n $table->string('id', 100)->primary();\n $table->unsignedBigInteger('user_id')->index();\n $table->unsignedBigInteger('client_id');\n $table->text('scopes')->nullable();\n $table->boolean('revoked');\n $table->dateTime('expires_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2016_06_01_000002_create_oauth_access_tokens_table.php",
"sha256": "acbeb29866718be6bb0ebf0bf85d4d76f9a34d62b682ca248e82c085a001f2b0",
"schema_operations": [
[
"create",
"oauth_access_tokens"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('oauth_access_tokens', function (Blueprint $table) {\n $table->string('id', 100)->primary();\n $table->unsignedBigInteger('user_id')->nullable()->index();\n $table->unsignedBigInteger('client_id');\n $table->string('name')->nullable();\n $table->text('scopes')->nullable();\n $table->boolean('revoked');\n $table->timestamps();\n $table->dateTime('expires_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2016_06_01_000003_create_oauth_refresh_tokens_table.php",
"sha256": "09a2853433a722f175bb35564576ff1717fc8c54cc6a1e9e7589884098e9a071",
"schema_operations": [
[
"create",
"oauth_refresh_tokens"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('oauth_refresh_tokens', function (Blueprint $table) {\n $table->string('id', 100)->primary();\n $table->string('access_token_id', 100)->index();\n $table->boolean('revoked');\n $table->dateTime('expires_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2016_06_01_000004_create_oauth_clients_table.php",
"sha256": "728b8744edd184b00ed89dfd1e7eca17091819b05a8cb5b5c89b79fde5459b14",
"schema_operations": [
[
"create",
"oauth_clients"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('oauth_clients', function (Blueprint $table) {\n $table->bigIncrements('id');\n $table->unsignedBigInteger('user_id')->nullable()->index();\n $table->string('name');\n $table->string('secret', 100)->nullable();\n $table->string('provider')->nullable();\n $table->text('redirect');\n $table->boolean('personal_access_client');\n $table->boolean('password_client');\n $table->boolean('revoked');\n $table->timestamps();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2016_06_01_000005_create_oauth_personal_access_clients_table.php",
"sha256": "37b718559569e3278bfa6e2f8c6079b68e21bad0a5b7f233f9ef313e357e3318",
"schema_operations": [
[
"create",
"oauth_personal_access_clients"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('oauth_personal_access_clients', function (Blueprint $table) {\n $table->bigIncrements('id');\n $table->unsignedBigInteger('client_id');\n $table->timestamps();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2017_03_03_100000_create_options_table.php",
"sha256": "1afffe540e1bfe170e1aa6193ffe9b7174445ebfbb81f08315af60bf106918e8",
"schema_operations": [
[
"create",
"options"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateOptionsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::create('options', function (Blueprint $table) {\n $table->increments('id');\n $table->string('key')->unique();\n $table->text('value');\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2019_05_16_162730_create_twofaccounts_table.php",
"sha256": "9bae015ba5bbf15559929034c3ec24b3fee876f8ca77f2b22391601441c77baa",
"schema_operations": [
[
"create",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass CreateTwoFAccountsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::create('twofaccounts', function (Blueprint $table) {\n $table->increments('id');\n $table->string('service');\n $table->string('uri');\n $table->string('account')->nullable();\n $table->string('icon')->nullable();\n $table->timestamps();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_03_25_095517_add_order_column_to_twofaccounts_table.php",
"sha256": "edb194adbc45fc94b81f6884b5673cf3445a4ce7a9f6d98e17b4496f93b7529d",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse App\\Models\\TwoFAccount;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass AddOrderColumnToTwofaccountsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->integer('order_column')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_10_05_210557_add_last_seen_to_users_table.php",
"sha256": "9db541b7e488c32e8e8a2029b46e88dcbdf065ea1cbd56515c1bee51be7f5baa",
"schema_operations": [
[
"table",
"users"
]
],
"up_source": "<?php\n\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass AddLastSeenToUsersTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('users', function (Blueprint $table) {\n $table->timestamp('last_seen_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_10_11_202302_add_provider_column_to_oauth_clients_table.php",
"sha256": "2e5693204137ded1fd9bf4816861dde0098468a21a08303339213d6c5a3ac701",
"schema_operations": [
[
"table",
"oauth_clients"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass AddProviderColumnToOauthClientsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('oauth_clients', function (Blueprint $table) {\n if (!Schema::hasColumn('oauth_clients', 'provider')) {\n $table->string('provider')->after('secret')->nullable();\n } \n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_10_20_210129_create_groups_table.php",
"sha256": "cba276718ffc803b04798837635d871e0869ed26dc851c3703b8a399de8ac5f2",
"schema_operations": [
[
"create",
"groups"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateGroupsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::create('groups', function (Blueprint $table) {\n $table->increments('id');\n $table->string('name');\n $table->timestamps();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_10_20_211115_add_group_id_column_to_twofaccounts_table.php",
"sha256": "5c9e50dfc4a879daaaf2014f1f649477095f615601b1b6190ec7ef76e334688b",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass AddGroupIdColumnToTwofaccountsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->unsignedInteger('group_id')\n ->after('id')\n ->nullable();\n\n $table->foreign('group_id')->references('id')->on('groups')->onDelete('set null');\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_12_04_073604_alter_encrypted_columns_to_text.php",
"sha256": "6d8135b35bce5c1ecce23b202f4ce1d4a46b1e37ec9c4f6c66d697cf4f3db311",
"schema_operations": [
[
"table",
"twofaccounts"
],
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass AlterEncryptedColumnsToText extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n $driver = Schema::connection($this->getConnection())->getConnection()->getDriverName();\n\n if ('sqlite' !== $driver) {\n \n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->text('account')->nullable()->change();\n });\n\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->text('uri')->change();\n });\n }\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_12_04_073605_alter_encrypted_columns_to_text_for_sqlite.php",
"sha256": "74a70bcced630cd0fdf47c8953d9f6c9a1f095ef13a71e5864b30c05468a0a67",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass AlterEncryptedColumnsToTextForSqlite extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n $driver = Schema::connection($this->getConnection())->getConnection()->getDriverName();\n\n if ('sqlite' === $driver) {\n \n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->text('account')->nullable()->change();\n });\n }\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2020_12_04_073606_alter_encrypted_columns_to_text_for_sqlite_bis.php",
"sha256": "2b0f52bf20b8a2c76f07d42b7ad34c7d61607cc1d134970e2516055abae6eac1",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass AlterEncryptedColumnsToTextForSqliteBis extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n $driver = Schema::connection($this->getConnection())->getConnection()->getDriverName();\n\n if ('sqlite' === $driver) {\n \n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->text('uri')->change();\n });\n }\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2021_09_08_191139_split_twofaccounts_uri_in_multiple_columns.php",
"sha256": "e947fd2f184dbe47fcd6ad63ca27ee3ae86a08fa227150e3d6c7115f0ea13609",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass SplitTwofaccountsUriInMultipleColumns extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n // as SQLITE disallow to add a not nullable column without default\n // value when altering a table we add all columns as nullable and\n // change them right after to not nullable column\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->string('otp_type', 10)->nullable();\n $table->text('secret')->nullable();\n $table->string('algorithm', 20)->nullable();\n $table->unsignedSmallInteger('digits')->nullable();\n $table->unsignedInteger('period')->nullable();\n $table->unsignedBigInteger('counter')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2021_09_08_191140_rename_uri_to_legacy_uri.php",
"sha256": "3c019abddcec98c3f3acebca764b44a9215e1d8e4b05997be27f52eb1d4f5fad",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass RenameUriToLegacyUri extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->renameColumn('uri', 'legacy_uri');\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2021_09_14_195451_change_nullable_in_twofaccounts_table.php",
"sha256": "f82b9dd27fb6853c3735d7a650a527ca542096ba4ace8d256c723e1af213559a",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse App\\Services\\SettingService;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Support\\Facades\\Crypt;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass ChangeNullableInTwofaccountsTable extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n $settingService = new SettingService;\n $twofaccounts = DB::table('twofaccounts')->select('id', 'legacy_uri')->get();\n\n foreach ($twofaccounts as $twofaccount) {\n try {\n $legacy_uri = $settingService->get('useEncryption') ? Crypt::decryptString($twofaccount->legacy_uri) : $twofaccount->legacy_uri;\n $token = \\OTPHP\\Factory::loadFromProvisioningUri($legacy_uri);\n\n $affected = DB::table('twofaccounts')\n ->where('id', $twofaccount->id)\n ->update([\n 'otp_type' => get_class($token) === 'OTPHP\\TOTP' ? 'totp' : 'hotp',\n 'secret' => $settingService->get('useEncryption') ? Crypt::encryptString($token->getSecret()) : $token->getSecret(),\n 'algorithm' => $token->getDigest(),\n 'digits' => $token->getDigits(),\n 'period' => $token->hasParameter('period') ? $token->getParameter('period') : null,\n 'counter' => $token->hasParameter('counter') ? $token->getParameter('counter') : null\n ]);\n }\n catch(Exception $ex)\n {\n Log::error($ex->getMessage());\n Log::error(\"TwoFAccount with id #\" . $twofaccount->id . \" could not be splited\");\n }\n }\n\n $twofaccounts = DB::table('twofaccounts')\n ->whereNull('account')\n ->orWhereNull('otp_type')\n ->orWhereNull('secret')\n ->orWhereNull('algorithm')\n ->orWhereNull('digits')\n ->get();\n\n foreach ($twofaccounts as $twofaccount) {\n\n $affected = DB::table('twofaccounts')\n ->where('id', $twofaccount->id)\n ->update([\n 'account' => $twofaccount->account === null ? 'account (invalid)' : $twofaccount->account + ' (invalid)',\n 'otp_type' => $twofaccount->otp_type === null ? 'totp' : $twofaccount->otp_type,\n 'secret' => $twofaccount->secret === null ? 'secret' : $twofaccount->secret,\n 'algorithm' => $twofaccount->algorithm === null ? 'sha1' : $twofaccount->algorithm,\n 'digits' => $twofaccount->digits === null ? 6 : $twofaccount->digits,\n ]);\n }\n\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->text('account')->nullable(false)->change();\n $table->string('service')->nullable()->change();\n $table->string('otp_type', 10)->nullable(false)->change();\n $table->text('secret')->nullable(false)->change();\n $table->string('algorithm', 20)->nullable(false)->change();\n $table->unsignedSmallInteger('digits')->nullable(false)->change();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2021_12_03_220140_create_web_authn_tables.php",
"sha256": "8f0263cc66f1104be3687cfe76e1d15e9d353e8fa13c0993d4b9bb3aa2c40d4f",
"schema_operations": [
[
"create",
"web_authn_credentials"
],
[
"create",
"web_authn_recoveries"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nclass CreateWebAuthnTables extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::create('web_authn_credentials', function (Blueprint $table) {\n\n // Limited to 191 to prevent index length issue with MyISAM and utf8mb4_unicode_ci\n // when using WAMP (WAMP uses MyISAM as default engine in place of INNOdb)\n $table->string('id', 191);\n\n // Change accordingly for your users table if you need to.\n $table->unsignedBigInteger('user_id');\n\n $table->string('name')->nullable();\n $table->string('type', 16);\n $table->json('transports');\n $table->string('attestation_type');\n $table->json('trust_path');\n $table->uuid('aaguid');\n $table->binary('public_key');\n $table->unsignedInteger('counter')->default(0);\n\n // This saves the external \"ID\" that identifies the user. We use UUID default\n // since it's very straightforward. You can change this for a plain string.\n // It must be nullable because those old U2F keys do not use user handle.\n $table->uuid('user_handle')->nullable();\n\n $table->timestamps();\n $table->softDeletes('disabled_at');\n\n $table->primary(['id', 'user_id']);\n });\n\n Schema::create('web_authn_recoveries', function (Blueprint $table) {\n $table->string('email')->index();\n $table->string('token');\n $table->timestamp('created_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2022_10_20_122032_create_webauthn_credentials.php",
"sha256": "efbc545fef44d08e60864c13747813e6ec3c7e187526905aec46cbd1dc0a00f6",
"schema_operations": [
[
"create",
"webauthn_credentials"
],
[
"dropIfExists",
"web_authn_credentials"
],
[
"rename",
"web_authn_recoveries"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Support\\Facades\\DB;\n\n/**\n * @see \\Laragear\\WebAuthn\\Models\\WebAuthnCredential\n */\nreturn new class extends Migration {\n\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up(): void\n {\n // We reset the user option 'useWebauthnOnly' to prevent lockout \n DB::table('options')->where('key', 'useWebauthnOnly')->delete();\n\n Schema::create('webauthn_credentials', static function (Blueprint $table): void {\n static::defaultBlueprint($table);\n });\n\n Schema::dropIfExists('web_authn_credentials');\n Schema::rename('web_authn_recoveries', 'webauthn_recoveries');\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2023_02_10_145413_add_is_admin_and_preferences_to_users_table.php",
"sha256": "ac99520222b19b6fb6eb1fee3b9e4fb27f70a1131adf63fe5abe49f6253eb442",
"schema_operations": [
[
"table",
"users"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Arr;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('users', function (Blueprint $table) {\n $table->boolean('is_admin')\n ->after('password')\n ->default(0);\n $table->json('preferences')->nullable();\n });\n\n DB::table('users')->update(['is_admin' => 1]);\n\n // The 'useWebauthnAsDefault' option is replaced by a local storage record\n // so we delete it form the Options table to prevent its conversion to\n // a user preference\n DB::table('options')->where('key', 'useWebauthnAsDefault')->delete();\n\n // User options are converted as user preferences\n $options = DB::table('options')->get();\n $preferences = config('2fauth.preferences');\n\n foreach ($options as $option) {\n if (Arr::has($preferences, $option->key)) {\n DB::table('users')->update(['preferences->'.$option->key => static::restoreType($option->value)]);\n DB::table('options')->where('id', $option->id)->delete();\n }\n }\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2023_02_21_143845_bind_twofaccounts_and_groups_to_users.php",
"sha256": "a8aa4e17c978ded37228bc143bb043258cb122df240529e69d165e61f0c8f75b",
"schema_operations": [
[
"table",
"twofaccounts"
],
[
"table",
"groups"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Illuminate\\Support\\Facades\\DB;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->unsignedBigInteger('user_id')\n ->after('id')\n ->nullable();\n\n $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete();\n });\n\n Schema::table('groups', function (Blueprint $table) {\n $table->unsignedBigInteger('user_id')\n ->after('id')\n ->nullable();\n\n $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete();\n });\n\n if ($legacySingleUser = DB::table('users')->first()) {\n DB::table('twofaccounts')->update(['user_id' => $legacySingleUser->id]);\n DB::table('groups')->update(['user_id' => $legacySingleUser->id]);\n }\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2023_03_13_114928_set_username_unique.php",
"sha256": "1fe7623bb6503d7d783a6fac526513f184dfd934951710c2fc370de5d5879bc2",
"schema_operations": [
[
"table",
"users"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n *\n * @return void\n */\n public function up()\n {\n Schema::table('users', function (Blueprint $table) {\n $table->unique('name');\n });\n }\n\n /**\n * Reverse the migrations.\n *\n * @return void\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2023_12_06_131842_add_oauth_columns_to_user.php",
"sha256": "d7f7996ffee6f499903607b3acbaf131913dcaecacb72ea61bf1f1bb95597f7a",
"schema_operations": [
[
"table",
"users"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::table('users', function (Blueprint $table) {\n $table->string('oauth_provider', 100)\n ->after('id')\n ->nullable();\n $table->string('oauth_id', 200)\n ->after('id')\n ->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_04_14_082519_create_auth_logs_table.php",
"sha256": "bbc10e41c09a374c53a9206c5467b58cd6c8bdf4de57982cadb3f24d2315b06c",
"schema_operations": [
[
"create",
"auth_logs"
]
],
"up_source": "<?php\n\n/**\n * The MIT License (MIT)\n * Copyright (c) 2024 Bubka\n * Copyright (c) 2024 Anthony Rappa\n * Copyright (c) 2017 Yaakov Dahan\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and\n * associated documentation files (the \"Software\"), to deal in the Software without restriction,\n * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,\n * subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial\n * portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\n * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n public function up(): void\n {\n Schema::create('auth_logs', function (Blueprint $table) {\n $table->id();\n $table->morphs('authenticatable');\n $table->string('ip_address', 45)->nullable();\n $table->text('user_agent')->nullable();\n $table->timestamp('login_at')->nullable()->index();\n $table->boolean('login_successful')->default(false)->index();\n $table->timestamp('logout_at')->nullable()->index();\n $table->boolean('cleared_by_user')->default(false);\n $table->string('guard', 40)->nullable();\n $table->string('login_method', 40)->nullable();\n\n $table->foreign('authenticatable_id')->references('id')->on('users')->cascadeOnDelete();\n });\n }\n\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_06_01_000001_create_oauth_device_codes_table.php",
"sha256": "f58e7e0409628118d1808631d8270692e54fdb2f227020365bb30a18b0564336",
"schema_operations": [
[
"create",
"oauth_device_codes"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('oauth_device_codes', function (Blueprint $table) {\n $table->char('id', 80)->primary();\n $table->foreignId('user_id')->nullable()->index();\n $table->foreignUuid('client_id')->index();\n $table->char('user_code', 8)->unique();\n $table->text('scopes');\n $table->boolean('revoked');\n $table->dateTime('user_approved_at')->nullable();\n $table->dateTime('last_polled_at')->nullable();\n $table->dateTime('expires_at')->nullable();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_08_08_133135_alter_twofaccount_service_field_to_text.php",
"sha256": "b33cf9bb4347706c63f0d1df1eae27a6200349e268b007554108fc00850911b9",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->text('service')->nullable()->change();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_08_08_133136_encrypt_twofaccount_service_field.php",
"sha256": "396a7313b4713d7f6b00c411117746a86a6c1b8c02bdb2520c9b29fc818bf935",
"schema_operations": [],
"up_source": "<?php\n\nuse App\\Models\\TwoFAccount;\nuse App\\Services\\SettingService;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n if ($this->dbIsEncrypted() && Schema::getColumnType('twofaccounts', 'service') === 'text') {\n $this->encryptServiceField();\n }\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_09_12_151037_create_session_table.php",
"sha256": "293923a1544ca6a69c25c60c65c1e1fd75f14968820dea122977c0a2d33183ce",
"schema_operations": [
[
"create",
"sessions"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('sessions', function (Blueprint $table) {\n $table->string('id')->primary();\n $table->foreignId('user_id')->nullable()->index();\n $table->string('ip_address', 45)->nullable();\n $table->text('user_agent')->nullable();\n $table->longText('payload');\n $table->integer('last_activity')->index();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_09_12_151132_create_cache_table.php",
"sha256": "fbb4665e5a977e71df4e74ec75b3c06ca4f17ad0de7138fe9786639189978e77",
"schema_operations": [
[
"create",
"cache"
],
[
"create",
"cache_locks"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('cache', function (Blueprint $table) {\n $table->string('key')->primary();\n $table->mediumText('value');\n $table->bigInteger('expiration')->index();\n });\n\n Schema::create('cache_locks', function (Blueprint $table) {\n $table->string('key')->primary();\n $table->string('owner');\n $table->bigInteger('expiration')->index();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2024_09_30_110610_create_icons_table.php",
"sha256": "83f1c5df8f1314f616d09fcf499dcbb9495ecfa95ceae092da877991ea5fc9f0",
"schema_operations": [
[
"create",
"icons"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('icons', function (Blueprint $table) {\n $table->string('name')->primary();\n $table->longText('content');\n $table->timestamps();\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2025_10_29_141837_add_order_column_to_groups_table.php",
"sha256": "88d015dcfde38a46bfab14fa9dfea2551893e9b08289b5ed39856c48e54e9952",
"schema_operations": [
[
"table",
"groups"
]
],
"up_source": "<?php\n\nuse App\\Models\\Group;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::table('groups', function (Blueprint $table) {\n $table->integer('order_column')->nullable();\n });\n\n // The primary index is used to set a default value for the newly\n // created order_column\n foreach (Group::get() as $group) {\n $group->order_column = $group->id;\n $group->save();\n }\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_03_15_000000_create_twofaccount_shares_table.php",
"sha256": "4771490844dc6b0c59a6cfe031de11dfdc0c55578d0f1f3495f849c05bc7d94e",
"schema_operations": [
[
"create",
"twofaccount_shares"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('twofaccount_shares', function (Blueprint $table) {\n $table->id();\n $table->unsignedInteger('twofaccount_id');\n $table->foreign('twofaccount_id')->references('id')->on('twofaccounts')->cascadeOnDelete();\n $table->foreignId('shared_with_user_id')->nullable()->constrained('users')->cascadeOnDelete();\n $table->string('scope', 24);\n $table->foreignId('created_by_user_id')->constrained('users')->cascadeOnDelete();\n $table->timestamps();\n\n $table->index(['twofaccount_id', 'scope']);\n $table->index('shared_with_user_id');\n $table->unique(['twofaccount_id', 'scope', 'shared_with_user_id'], 'twofaccount_shares_unique_target');\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_04_14_000000_create_twofaccount_group_assignments_table.php",
"sha256": "8deb3b22c6eb4f55b9f8e58d483da2922faff2f03ad890b3b10a8710273976d2",
"schema_operations": [
[
"create",
"twofaccount_group_assignments"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('twofaccount_group_assignments', function (Blueprint $table) {\n $table->id();\n $table->unsignedInteger('twofaccount_id');\n $table->unsignedBigInteger('user_id');\n $table->unsignedInteger('group_id');\n $table->timestamps();\n\n $table->foreign('twofaccount_id')->references('id')->on('twofaccounts')->cascadeOnDelete();\n $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete();\n $table->foreign('group_id')->references('id')->on('groups')->cascadeOnDelete();\n\n $table->unique(['twofaccount_id', 'user_id'], 'twofaccount_group_assignments_unique_scope');\n $table->index('group_id');\n $table->index('user_id');\n });\n\n $this->backfillLegacyAssignments();\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_04_14_010000_drop_group_id_from_twofaccounts_table.php",
"sha256": "75ca1423667f8b6cb825cd21841fccd296b9876b7edfabc2f4c8a88ad99dfaba",
"schema_operations": [
[
"table",
"twofaccounts"
],
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n if (DB::getDriverName() === 'sqlite') {\n return;\n }\n\n if (! Schema::hasColumn('twofaccounts', 'group_id')) {\n return;\n }\n\n Schema::table('twofaccounts', function (Blueprint $table) {\n if (DB::getDriverName() !== 'sqlite') {\n $table->dropForeign(['group_id']);\n }\n });\n\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->dropColumn('group_id');\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_04_15_000000_create_twofaccount_user_orders_table.php",
"sha256": "c8acb8a9ab653f3887c00f9912ad4d137e467ba81957b925759382401ed5f7ef",
"schema_operations": [
[
"create",
"twofaccount_user_orders"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('twofaccount_user_orders', function (Blueprint $table) {\n $table->id();\n $table->unsignedBigInteger('user_id');\n $table->unsignedInteger('twofaccount_id');\n $table->unsignedInteger('position');\n $table->timestamps();\n\n $table->foreign('user_id')->references('id')->on('users')->cascadeOnDelete();\n $table->foreign('twofaccount_id')->references('id')->on('twofaccounts')->cascadeOnDelete();\n\n $table->unique(['user_id', 'twofaccount_id'], 'twofaccount_user_orders_unique_scope');\n $table->index(['user_id', 'position']);\n $table->index('twofaccount_id');\n });\n\n $this->backfillLegacyOrderColumnValues();\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_04_15_010000_drop_order_column_from_twofaccounts_table.php",
"sha256": "ceebf07f020664a66531ab8d967b40b5c9e58383e9dbee2d156fe55f683ac5e9",
"schema_operations": [
[
"table",
"twofaccounts"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n if (DB::getDriverName() === 'sqlite') {\n return;\n }\n\n if (! Schema::hasColumn('twofaccounts', 'order_column')) {\n return;\n }\n\n Schema::table('twofaccounts', function (Blueprint $table) {\n $table->dropColumn('order_column');\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_05_16_074427_create_otp_logs_table.php",
"sha256": "19c230dc2ac7b97af06444430820c1afb552f059c08200e82c9c0349612423a3",
"schema_operations": [
[
"create",
"otp_logs"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::create('otp_logs', function (Blueprint $table) {\n $table->id();\n $table->unsignedBigInteger('requester_id')->nullable();\n $table->string('requester_name');\n $table->string('requester_email');\n $table->unsignedBigInteger('owner_id')->nullable();\n $table->string('owner_name');\n $table->string('owner_email');\n $table->unsignedInteger('twofaccount_id');\n $table->string('ip_address', 45);\n $table->string('otp_type', 10);\n $table->unsignedMediumInteger('counter')->nullable();\n $table->timestamp('generated_at');\n\n $table->foreign('requester_id')->references('id')->on('users')->nullOnDelete();\n $table->foreign('owner_id')->references('id')->on('users')->nullOnDelete();\n $table->foreign('twofaccount_id')->references('id')->on('twofaccounts')->cascadeOnDelete();\n\n $table->index('requester_id');\n $table->index('twofaccount_id');\n $table->index('ip_address');\n $table->index('otp_type');\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_06_10_153224_add_show_in_chips_column_to_group.php",
"sha256": "fd4e2f61e2ddf4644a5d3ed0e3c76382745631a5e3d426d49d45733e94ae8c47",
"schema_operations": [
[
"table",
"groups"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::table('groups', function (Blueprint $table) {\n $table->boolean('show_in_chips')\n ->after('name')\n ->default(false);\n });\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
},
{
"file": "database/migrations/2026_08_29_175933_update_oauth_clients_table_for_passport_13.php",
"sha256": "af7bc5f94d94be7ab8a1bd8d2622c8448f6a3e8f16edd40eb30a53b9a6028391",
"schema_operations": [
[
"table",
"oauth_clients"
],
[
"table",
"oauth_clients"
],
[
"dropIfExists",
"oauth_personal_access_clients"
]
],
"up_source": "<?php\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Support\\Facades\\Schema;\nuse Laravel\\Passport\\Passport;\n\nreturn new class extends Migration\n{\n /**\n * Run the migrations.\n */\n public function up(): void\n {\n Schema::table('oauth_clients', function (Blueprint $table) {\n $table->nullableMorphs('owner', after: 'user_id');\n\n $table->after('provider', function (Blueprint $table) {\n $table->text('redirect_uris')->nullable();\n $table->text('grant_types')->nullable();\n });\n });\n\n foreach (Passport::client()->cursor() as $client) {\n Model::withoutTimestamps(fn () => $client->forceFill([\n 'owner_id' => $client->user_id,\n 'owner_type' => $client->user_id\n ? config('auth.providers.'.($client->provider ?: config('auth.guards.api-guard.provider')).'.model')\n : null,\n 'redirect_uris' => $client->redirect_uris,\n 'grant_types' => ['personal_access', 'refresh_token'],\n ])->save());\n }\n\n Schema::table('oauth_clients', function (Blueprint $table) {\n $table->dropIndex('oauth_clients_user_id_index');\n $table->dropColumn(['user_id', 'redirect', 'personal_access_client', 'password_client']);\n\n $table->text('redirect_uris')->nullable(false)->change();\n $table->text('grant_types')->nullable(false)->change();\n });\n\n Schema::dropIfExists('oauth_personal_access_clients');\n }\n\n /**\n * Reverse the migrations.\n */\n ",
"note": "Raw up source includes exact definitions and transformations. Helpers defined after down may need the full source; no SQL schema is inferred."
}
]
}
+16
View File
@@ -0,0 +1,16 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"candidate_sha256": "0e03e978721bf4fcfc65e18e4a98f47b26b71a151c792b380d18996ae467813d",
"php_version": "8.4.27",
"checks": {
"php_issued_device_pending_backoff": true,
"php_approval_rust_token_php_resource_server": true,
"device_code_revocation_replay": true,
"rust_issued_device_php_repository_readable": true,
"rust_device_php_approval_and_token_validation": true,
"php_denied_device_rejected": true,
"expired_device_rejected": true,
"source_database_unchanged": true
},
"passed": true
}
+582
View File
@@ -0,0 +1,582 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"kind": "configuration env names and source references only; no deployment values",
"variables": {
"IS_DEMO_APP": [
"config/2fauth.php:81"
],
"IS_TESTING_APP": [
"config/2fauth.php:82"
],
"TRUSTED_PROXIES": [
"config/2fauth.php:83"
],
"PROXY_FOR_OUTGOING_REQUESTS": [
"config/2fauth.php:84",
"config/services.php:33",
"config/services.php:42"
],
"PROXY_LOGOUT_URL": [
"config/2fauth.php:85"
],
"APP_SUBDIRECTORY": [
"config/2fauth.php:86",
"config/app.php:65"
],
"PROXY_HEADER_FOR_IP": [
"config/2fauth.php:102"
],
"THROTTLE_API": [
"config/2fauth.php:113"
],
"THROTTLE_API_DURING_IMPORT": [
"config/2fauth.php:114"
],
"APP_URL": [
"config/app.php:7",
"config/filesystems.php:44",
"config/filesystems.php:82",
"config/mail.php:50",
"config/services.php:30",
"config/services.php:40"
],
"HEROKU_APP_NAME": [
"config/app.php:7",
"config/app.php:7"
],
"APP_NAME": [
"config/app.php:22",
"config/cache.php:121",
"config/database.php:160",
"config/logging.php:79",
"config/mail.php:124",
"config/session.php:134"
],
"APP_ENV": [
"config/app.php:35"
],
"APP_DEBUG": [
"config/app.php:48"
],
"ASSET_URL": [
"config/app.php:65"
],
"APP_TIMEZONE": [
"config/app.php:78"
],
"APP_LOCALE": [
"config/app.php:91"
],
"APP_FALLBACK_LOCALE": [
"config/app.php:93"
],
"APP_FAKER_LOCALE": [
"config/app.php:95"
],
"APP_KEY": [
"config/app.php:110"
],
"APP_PREVIOUS_KEYS": [
"config/app.php:114"
],
"APP_MAINTENANCE_DRIVER": [
"config/app.php:132"
],
"APP_MAINTENANCE_STORE": [
"config/app.php:133"
],
"LOGIN_THROTTLE": [
"config/auth.php:6"
],
"AUTH_GUARD": [
"config/auth.php:21"
],
"AUTHENTICATION_GUARD": [
"config/auth.php:21"
],
"AUTH_PROXY_HEADER_FOR_USER": [
"config/auth.php:37"
],
"AUTH_PROXY_HEADER_FOR_EMAIL": [
"config/auth.php:38"
],
"AUTH_PASSWORD_TIMEOUT": [
"config/auth.php:154"
],
"BROADCAST_CONNECTION": [
"config/broadcasting.php:18"
],
"REVERB_APP_KEY": [
"config/broadcasting.php:35"
],
"REVERB_APP_SECRET": [
"config/broadcasting.php:36"
],
"REVERB_APP_ID": [
"config/broadcasting.php:37"
],
"REVERB_HOST": [
"config/broadcasting.php:39"
],
"REVERB_PORT": [
"config/broadcasting.php:40"
],
"REVERB_SCHEME": [
"config/broadcasting.php:41",
"config/broadcasting.php:42"
],
"PUSHER_APP_KEY": [
"config/broadcasting.php:51"
],
"PUSHER_APP_SECRET": [
"config/broadcasting.php:52"
],
"PUSHER_APP_ID": [
"config/broadcasting.php:53"
],
"PUSHER_APP_CLUSTER": [
"config/broadcasting.php:55",
"config/broadcasting.php:56"
],
"PUSHER_HOST": [
"config/broadcasting.php:56"
],
"PUSHER_PORT": [
"config/broadcasting.php:57"
],
"PUSHER_SCHEME": [
"config/broadcasting.php:58",
"config/broadcasting.php:60"
],
"ABLY_KEY": [
"config/broadcasting.php:69"
],
"CACHE_STORE": [
"config/cache.php:18"
],
"CACHE_DRIVER": [
"config/cache.php:18"
],
"DB_CACHE_CONNECTION": [
"config/cache.php:44"
],
"DB_CACHE_TABLE": [
"config/cache.php:45"
],
"DB_CACHE_LOCK_CONNECTION": [
"config/cache.php:46"
],
"DB_CACHE_LOCK_TABLE": [
"config/cache.php:47"
],
"CACHE_STORAGE_DISK": [
"config/cache.php:58"
],
"CACHE_STORAGE_PATH": [
"config/cache.php:59"
],
"MEMCACHED_PERSISTENT_ID": [
"config/cache.php:64"
],
"MEMCACHED_USERNAME": [
"config/cache.php:66"
],
"MEMCACHED_PASSWORD": [
"config/cache.php:67"
],
"MEMCACHED_HOST": [
"config/cache.php:74"
],
"MEMCACHED_PORT": [
"config/cache.php:75"
],
"REDIS_CACHE_CONNECTION": [
"config/cache.php:83"
],
"REDIS_CACHE_LOCK_CONNECTION": [
"config/cache.php:84"
],
"AWS_ACCESS_KEY_ID": [
"config/cache.php:89",
"config/filesystems.php:90",
"config/queue.php:58",
"config/services.php:57"
],
"AWS_SECRET_ACCESS_KEY": [
"config/cache.php:90",
"config/filesystems.php:91",
"config/queue.php:59",
"config/services.php:58"
],
"AWS_DEFAULT_REGION": [
"config/cache.php:91",
"config/filesystems.php:92",
"config/queue.php:63",
"config/services.php:59"
],
"DYNAMODB_CACHE_TABLE": [
"config/cache.php:92"
],
"DYNAMODB_ENDPOINT": [
"config/cache.php:93"
],
"CACHE_PREFIX": [
"config/cache.php:121"
],
"DB_URL": [
"config/database.php:37",
"config/database.php:49",
"config/database.php:69",
"config/database.php:89",
"config/database.php:104"
],
"DATABASE_URL": [
"config/database.php:37",
"config/database.php:49",
"config/database.php:69",
"config/database.php:89",
"config/database.php:104"
],
"DB_FOREIGN_KEYS": [
"config/database.php:40",
"config/database.php:121"
],
"DB_PASSWORD": [
"config/database.php:54",
"config/database.php:74",
"config/database.php:94",
"config/database.php:109"
],
"DB_SOCKET": [
"config/database.php:55",
"config/database.php:75"
],
"DB_CHARSET": [
"config/database.php:56",
"config/database.php:76",
"config/database.php:95",
"config/database.php:110"
],
"DB_COLLATION": [
"config/database.php:57",
"config/database.php:77"
],
"MYSQL_ATTR_SSL_CA": [
"config/database.php:63",
"config/database.php:83"
],
"DB_SSLMODE": [
"config/database.php:99"
],
"REDIS_CLIENT": [
"config/database.php:156"
],
"REDIS_CLUSTER": [
"config/database.php:159"
],
"REDIS_PREFIX": [
"config/database.php:160"
],
"REDIS_PERSISTENT": [
"config/database.php:161"
],
"REDIS_URL": [
"config/database.php:165",
"config/database.php:178"
],
"REDIS_HOST": [
"config/database.php:166",
"config/database.php:179"
],
"REDIS_USERNAME": [
"config/database.php:167",
"config/database.php:180"
],
"REDIS_PASSWORD": [
"config/database.php:168",
"config/database.php:181"
],
"REDIS_PORT": [
"config/database.php:169",
"config/database.php:182"
],
"REDIS_DB": [
"config/database.php:170"
],
"REDIS_MAX_RETRIES": [
"config/database.php:171",
"config/database.php:184"
],
"REDIS_BACKOFF_ALGORITHM": [
"config/database.php:172",
"config/database.php:185"
],
"REDIS_BACKOFF_BASE": [
"config/database.php:173",
"config/database.php:186"
],
"REDIS_BACKOFF_CAP": [
"config/database.php:174",
"config/database.php:187"
],
"REDIS_CACHE_DB": [
"config/database.php:183"
],
"FILESYSTEM_DISK": [
"config/filesystems.php:16"
],
"FILESYSTEM_DRIVER": [
"config/filesystems.php:16"
],
"AWS_BUCKET": [
"config/filesystems.php:93"
],
"AWS_URL": [
"config/filesystems.php:94"
],
"AWS_ENDPOINT": [
"config/filesystems.php:95"
],
"AWS_USE_PATH_STYLE_ENDPOINT": [
"config/filesystems.php:96"
],
"HASH_DRIVER": [
"config/hashing.php:18"
],
"BCRYPT_ROUNDS": [
"config/hashing.php:32"
],
"ARGON_MEMORY": [
"config/hashing.php:50"
],
"ARGON_THREADS": [
"config/hashing.php:51"
],
"ARGON_TIME": [
"config/hashing.php:52"
],
"LOG_CHANNEL": [
"config/logging.php:21"
],
"LOG_DEPRECATIONS_CHANNEL": [
"config/logging.php:35"
],
"LOG_DEPRECATIONS_TRACE": [
"config/logging.php:36"
],
"LOG_STACK": [
"config/logging.php:57"
],
"LOG_LEVEL": [
"config/logging.php:64",
"config/logging.php:71",
"config/logging.php:81",
"config/logging.php:87",
"config/logging.php:99",
"config/logging.php:110",
"config/logging.php:117"
],
"LOG_DAILY_DAYS": [
"config/logging.php:72"
],
"LOG_SLACK_WEBHOOK_URL": [
"config/logging.php:78"
],
"LOG_SLACK_USERNAME": [
"config/logging.php:79"
],
"LOG_SLACK_EMOJI": [
"config/logging.php:80"
],
"LOG_PAPERTRAIL_HANDLER": [
"config/logging.php:88"
],
"PAPERTRAIL_URL": [
"config/logging.php:90",
"config/logging.php:92"
],
"PAPERTRAIL_PORT": [
"config/logging.php:91",
"config/logging.php:92"
],
"LOG_STDERR_FORMATTER": [
"config/logging.php:104"
],
"LOG_SYSLOG_FACILITY": [
"config/logging.php:111"
],
"MAIL_MAILER": [
"config/mail.php:17"
],
"MAIL_DRIVER": [
"config/mail.php:17"
],
"MAIL_URL": [
"config/mail.php:43"
],
"MAIL_HOST": [
"config/mail.php:44"
],
"MAIL_PORT": [
"config/mail.php:45"
],
"MAIL_ENCRYPTION": [
"config/mail.php:46"
],
"MAIL_USERNAME": [
"config/mail.php:47"
],
"MAIL_PASSWORD": [
"config/mail.php:48"
],
"MAIL_EHLO_DOMAIN": [
"config/mail.php:50"
],
"MAIL_VERIFY_SSL_PEER": [
"config/mail.php:51"
],
"MAIL_SENDMAIL_PATH": [
"config/mail.php:79"
],
"MAIL_LOG_CHANNEL": [
"config/mail.php:84"
],
"MAIL_FROM_ADDRESS": [
"config/mail.php:123"
],
"MAIL_FROM_NAME": [
"config/mail.php:124"
],
"PASSPORT_PRIVATE_KEY": [
"config/passport.php:31"
],
"PASSPORT_PUBLIC_KEY": [
"config/passport.php:33"
],
"PASSPORT_CONNECTION": [
"config/passport.php:46"
],
"QUEUE_CONNECTION": [
"config/queue.php:16"
],
"DB_QUEUE_CONNECTION": [
"config/queue.php:40"
],
"DB_QUEUE_TABLE": [
"config/queue.php:41"
],
"DB_QUEUE": [
"config/queue.php:42"
],
"DB_QUEUE_RETRY_AFTER": [
"config/queue.php:43"
],
"BEANSTALKD_QUEUE_HOST": [
"config/queue.php:49"
],
"BEANSTALKD_QUEUE": [
"config/queue.php:50"
],
"BEANSTALKD_QUEUE_RETRY_AFTER": [
"config/queue.php:51"
],
"SQS_PREFIX": [
"config/queue.php:60"
],
"SQS_QUEUE": [
"config/queue.php:61"
],
"SQS_SUFFIX": [
"config/queue.php:62"
],
"REDIS_QUEUE_CONNECTION": [
"config/queue.php:69"
],
"REDIS_QUEUE": [
"config/queue.php:70"
],
"REDIS_QUEUE_RETRY_AFTER": [
"config/queue.php:71"
],
"DB_CONNECTION": [
"config/queue.php:106",
"config/queue.php:125"
],
"QUEUE_FAILED_DRIVER": [
"config/queue.php:124"
],
"MAILGUN_DOMAIN": [
"config/services.php:18"
],
"MAILGUN_SECRET": [
"config/services.php:19"
],
"MAILGUN_ENDPOINT": [
"config/services.php:20"
],
"OPENID_TOKEN_URL": [
"config/services.php:25"
],
"OPENID_AUTHORIZE_URL": [
"config/services.php:26"
],
"OPENID_USERINFO_URL": [
"config/services.php:27"
],
"OPENID_CLIENT_ID": [
"config/services.php:28"
],
"OPENID_CLIENT_SECRET": [
"config/services.php:29"
],
"GITHUB_CLIENT_ID": [
"config/services.php:38"
],
"GITHUB_CLIENT_SECRET": [
"config/services.php:39"
],
"POSTMARK_TOKEN": [
"config/services.php:53"
],
"RESEND_KEY": [
"config/services.php:63"
],
"SLACK_BOT_USER_OAUTH_TOKEN": [
"config/services.php:68"
],
"SLACK_BOT_USER_DEFAULT_CHANNEL": [
"config/services.php:69"
],
"SESSION_DRIVER": [
"config/session.php:21"
],
"SESSION_ENCRYPT": [
"config/session.php:52"
],
"SESSION_CONNECTION": [
"config/session.php:78"
],
"SESSION_TABLE": [
"config/session.php:91"
],
"SESSION_STORE": [
"config/session.php:106"
],
"SESSION_PATH": [
"config/session.php:148"
],
"SESSION_DOMAIN": [
"config/session.php:161"
],
"SESSION_SECURE_COOKIE": [
"config/session.php:174"
],
"WEBAUTHN_ORIGINS": [
"config/webauthn.php:35"
]
},
"dynamic_names": [
"USERPREF_DEFAULT__<PREFERENCE>",
"USERPREF_LOCKED__<PREFERENCE>"
]
}
+269
View File
@@ -0,0 +1,269 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"files": [
{
"path": "UPSTREAM-LICENSE",
"sha256": "4df3c306dddaaf4baffdff5ca820cc679ac8cd6dc263c6a74517783e42fa7a3b"
},
{
"path": "UPSTREAM-NOTICE.txt",
"sha256": "cb69c7c5779eb46c28f44146e63c66831eb17ff3af761fc1f09e9c6406c3fe4c"
},
{
"path": "build/assets/About-DlWJhNxo.js",
"sha256": "f3169d1ab17f927108537166c262b5e4cbd60680007376d81b222196ca161c9b"
},
{
"path": "build/assets/Access-BQVm4alb.js",
"sha256": "22b97a5fbc041312bda5a240a93e14a50e6c4d23fced34202f75c0cf1441f762"
},
{
"path": "build/assets/AccessLogViewer-D5ke4CwJ.js",
"sha256": "cb9164252152b509f281ca1d14758ae200c76537bc51c687c28cefac7689c75e"
},
{
"path": "build/assets/Account-CvhJGfLO.js",
"sha256": "d6cbabd0c90d314b39f25af40bc06fa6067b7a97266581b40113c837b13be140"
},
{
"path": "build/assets/AccountSharing-kU7yk02h.js",
"sha256": "e99a6c300fb8c205fa1b6ed205daadf1e4e9c0ca46e6402a5c5c8b7a1f4fb8ff"
},
{
"path": "build/assets/Accounts-znshhaJC.js",
"sha256": "a2d62c76f1760d22f69a05b19d2b455d7943fa873af854ddf3291d238c6ab4e1"
},
{
"path": "build/assets/AppSetup-9GPB7B-I.js",
"sha256": "3fc8954eabf0857e275ea041f93b3c80ad14fff990ce880e80b64a506d2af083"
},
{
"path": "build/assets/Auth-DslSg1a9.js",
"sha256": "19cde7fd5762e9cf47461ea4bb4bedd493d73e6a8ba5234c6d2a772e2e1381a5"
},
{
"path": "build/assets/Capture-BG6QMHLW.js",
"sha256": "37055326ee5e5b9704b09c190550954d8c023b62db0fa56601a458665ff91c83"
},
{
"path": "build/assets/CopyButton-CgxgBp0c.js",
"sha256": "de0d9210a45ca0dcfe42c9c3510e376d6138f46304287dac38dfd705b7fbc980"
},
{
"path": "build/assets/Create-Vv-BwDWf.js",
"sha256": "d7298e06bbd88989a0aadcbcad6ce822f68143479fc7ac304aa0de1afd0bb1bb"
},
{
"path": "build/assets/CreateUpdate-CbOB1O7q.js",
"sha256": "7722a5c1d5e2d54f59f831019dc60d70e254e6301af0d1d88539b900c9afe5a0"
},
{
"path": "build/assets/CreateUpdate-tvLQ26rU.js",
"sha256": "f6080ad4cf80ce4a0d069c37db14cffb73e100d61c01b5d362d065671db938bb"
},
{
"path": "build/assets/Edit-Ba84j7PP.js",
"sha256": "4e9473ca1dcdd023ab7e5971efb7c4037cc7b139f40d3c6d60ebbb188042a9be"
},
{
"path": "build/assets/Error-DG0pgQA2.js",
"sha256": "b0f3daed5256ace1b0cfc107331ea72d83802c02a5b06fbadfd9e9bc93f096ab"
},
{
"path": "build/assets/Form-ZbAUhXmz.js",
"sha256": "fd411a87ff941729cb37f83684348c07a18f36238611f46895f9c7058caeee39"
},
{
"path": "build/assets/Groups-Ccrpwp-O.js",
"sha256": "fe6d8a2b4909a5a9703fb1b397e093920f10339f2397d94322e91cb4bd3455b0"
},
{
"path": "build/assets/Import-C0sC5CLD.js",
"sha256": "3cf1c15584189a7ec24cc62205cf42bded2561ba6d8744b4d78939d639fb9045"
},
{
"path": "build/assets/Login-XfEMUKl8.js",
"sha256": "a43048f07eb40139adc248ecae28d32c9f578a806390db9c92d872a9f52c2d18"
},
{
"path": "build/assets/Manage-B1CTWqgo.js",
"sha256": "d19802c7c40feb225df8e44234c149d69932f02c23e2e130f83dd312c5b470d7"
},
{
"path": "build/assets/OAuth-aXCqlLPs.js",
"sha256": "62945e0e479af1c53092bf8fccb97ed218b16a31516d9ca916215fe20477bbc9"
},
{
"path": "build/assets/Options-Bun4hDR8.js",
"sha256": "4e03854ccd1cc756cb0b9a0bf21c514b1d2c16a9f44443b01c48825963db41f2"
},
{
"path": "build/assets/OtpLogs-CAP6rwu6.js",
"sha256": "752b619ab9eec5433b20ec3d4ea2ebc20cfa44cd408841c65a7c22ecb7d80ecc"
},
{
"path": "build/assets/QRcode-Da_iUmWo.js",
"sha256": "31cd01fbebe9be769dac7b572dcb1f4f058bbf5564c61c0326f16b2e48ca2b98"
},
{
"path": "build/assets/QrContentDisplay-DiIjf7a_.js",
"sha256": "4bb56ee3a4532bc8f8ee5464bef16c1822e9ce40274f550e713fbc4590d3007f"
},
{
"path": "build/assets/Recover-CEob990V.js",
"sha256": "81a968b80924d8771c13df267554975f893e4472c1e94685daa2540bc5258db9"
},
{
"path": "build/assets/Register-DffuLlzx.js",
"sha256": "0143921eedbef6c3c93119cf8c99b1ae663f38107871ee1ad0b464578013627e"
},
{
"path": "build/assets/RequestReset-w8-YSMaH.js",
"sha256": "26eedf6afd5f9fa0311b362e51837ac384d49583de1dba953b5d5ebc8a88d6fe"
},
{
"path": "build/assets/Reset-RiTuOlH9.js",
"sha256": "efda00daaf3e1522870b1112185b220f427ba7c73a35da1dd19577a9328c8680"
},
{
"path": "build/assets/Share-DkTnn1jz.js",
"sha256": "112dcfe57d40a155f642643cc33bd0b131084c37cecb73731d4d44488979f4c5"
},
{
"path": "build/assets/Start-Dnu4qWlC.js",
"sha256": "71307d371a240ae2566646506ac1043c2d5044e4779d4cc0e600f6c4a5148fb9"
},
{
"path": "build/assets/TransferOwnership-BsVNwpBY.js",
"sha256": "5d8d0457fde643dd492c2c8b4996b488a30073c5383a2910f83a571947128b83"
},
{
"path": "build/assets/TwofaccountMedia-DzLyeBxh.js",
"sha256": "0dc08bad96017b22d1319219aee0810919776f61a4a98213b76fd636b22ab92c"
},
{
"path": "build/assets/Users-DyNCDMUg.js",
"sha256": "f4843babe67785c7b490d1d635e9c6d53dbe56a36bc0283c74a49acc7742f4e8"
},
{
"path": "build/assets/WebAuthn-C_HU0Xj8.js",
"sha256": "d4342ce1b35963255a6b4a7df346cd3d40ac75a6148c21258b92fbcd6b6a1dd9"
},
{
"path": "build/assets/app-C6trQ8-_.css",
"sha256": "1c9e625b1b803a2a2b63a6339524de490060ad1e30a14076e7aa1893dd5f2472"
},
{
"path": "build/assets/app-dvJP63FL.js",
"sha256": "535d717468bc495ac963ae84b52549d223c04213f5e5764b2762e463a00cb04e"
},
{
"path": "build/assets/appSettingsUpdater-D1Bq_3WB.js",
"sha256": "2f4dc82c14b2518614612bf1c37f720d5e1899059423ed3bd593e7a83e6728ae"
},
{
"path": "build/assets/breakpoints-CyLcIEOu.js",
"sha256": "43ecba0d19dea8ad828eae4fb460ce85fedfae700c09daa8fe9701214cd986d5"
},
{
"path": "build/assets/bus-ChE1sp8V.js",
"sha256": "d84b9cf19fd6d82135d7bc185f5d200ac2abc2bd85f61c9ba0ff82b2c0d591fb"
},
{
"path": "build/assets/check-CPGWPXZa.js",
"sha256": "3d743579c1e01d29248a6c4c2fa1c3b042aee3f2d97e29ea879a2d5dbf6c736b"
},
{
"path": "build/assets/circle-plus-BM92Iipr.js",
"sha256": "2e5faf55982bf87bf1caf5b6abd2673127ef15b4f56bf3fa330b84457d984afc"
},
{
"path": "build/assets/circle-x-AvUNZzwX.js",
"sha256": "942133c0ee96ec5b0eff01c4f2ff3a2ec76f00d8a126aaf4a29e25b0092e93dd"
},
{
"path": "build/assets/createLucideIcon-DsaEAGzP.js",
"sha256": "67d36796d6e97cd30520b928d535103cd12df14d0ff9ccc0d0d9e39135288a9a"
},
{
"path": "build/assets/external-link-CqpXNovN.js",
"sha256": "b0ea183dd73195135d6874336bfea357f0ef9853c2f815646eb685bc96930042"
},
{
"path": "build/assets/helpers-B2oe4lHy.js",
"sha256": "9f2e0d92e5dcd5ca291a2201b86f07c629e6f66610c32087b5e7f8ef364e2177"
},
{
"path": "build/assets/iconService-rm6LRV4U.js",
"sha256": "45473c427530a0a626666e25c6f22626dcf9ce066b0fbc3d113f1ee03c7bd60e"
},
{
"path": "build/assets/index-BJsmINgd.js",
"sha256": "73c8fd5fe0cfa6e9f2b6813a26e13b5af522217a2a8bbaf71df66ffab21a9ae0"
},
{
"path": "build/assets/qr-code-eSL1bq0j.js",
"sha256": "ef43fa83adaacb9ac9fbde3fb504d0d9723039aedb4c6d0b6cbe245d6e098644"
},
{
"path": "build/assets/shareService-BU7jlLil.js",
"sha256": "5cf418bbe4ebd9e4c4df38ff56328022ab5d96512204c5f5e4a4b922ae87e675"
},
{
"path": "build/assets/tablet-DYUfDfjC.js",
"sha256": "166e691d3fd9bf6c5a2d0d39fdaf878c276b41d22e886b8e2b82c8f0e5468750"
},
{
"path": "build/assets/tabs-BVx9tg1F.js",
"sha256": "a0dc11f6f993d0758ffa532a818d332771403a256ff00a2aa072dcc211c9efe9"
},
{
"path": "build/assets/tabs-Btun2NN0.js",
"sha256": "da0a8a06a9b615727d00cfa2313c35699c220f3691e59ac0732b5004c0585e47"
},
{
"path": "build/assets/useSortable-6hRbxhTj.js",
"sha256": "6f3a264bb228826b5bc77c63452d141e5550c5e7e29cbd4dd0fc66fc8999e2c7"
},
{
"path": "build/assets/users-CLZI37iw.js",
"sha256": "732d20d0eeca849e83a4d2affd0eb07c95ac0538266f93ee19a8a0da0809651f"
},
{
"path": "build/assets/webauthnService-D363et0U.js",
"sha256": "7f98b80530bc3cefa019532e5570e1f4f4f9418ad5882dc9e06366ea9439a5dd"
},
{
"path": "build/assets/x-DQVIq0xP.js",
"sha256": "fdb82d6b42e8ca89a1ac9bc037572e9d6c36b7c568b49cf7435b1a8d7cd6da17"
},
{
"path": "build/manifest.json",
"sha256": "cbf4ab776d021f9fb4778970db9afc3d7b8d32b2edd21e7677dcf18ccf48f7ed"
},
{
"path": "favicon.ico",
"sha256": "844e483a6fc4a33ff86fbf70a4e6321034f4d5d831a8401afed491ac2aa52957"
},
{
"path": "favicon.png",
"sha256": "8dd74a355aa3d9355439b753872e40caf91b3692fedb4560da67c45b38d972ef"
},
{
"path": "favicon_lg.png",
"sha256": "54be08dbaed6b51b78b1fd3e5918e4b071af54f1c8062fbbfb7c59f0970a336b"
},
{
"path": "healthcheck.css",
"sha256": "f6444b55f2879b5d38b41be8562065dcbe190f179dd2306851408ac142ee8250"
},
{
"path": "logo.svg",
"sha256": "11c3a3fb1a688e8cdfde36fb117fc90fc652664398f62e12ffb6a923f19a392d"
},
{
"path": "robots.txt",
"sha256": "e5c4b84484ee4216e9373be99380320c25dd94805f99f0a805846f087636553f"
}
]
}
+55
View File
@@ -0,0 +1,55 @@
{
"version": "0.3.0",
"date": "2026-10-28",
"candidate_sha256": "0e03e978721bf4fcfc65e18e4a98f47b26b71a151c792b380d18996ae467813d",
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"rust_tests": {
"passed": 137,
"failed": 0
},
"strict_clippy": "passed",
"formatting": "passed",
"python_harness_tests": {
"passed": 6,
"failed": 0
},
"php_openssl_fixtures": {
"passed": 6
},
"http_comparisons_per_database": {
"total": 140,
"exact": 129,
"expected_raw_dynamic_bodies": 11,
"unexpected_assertion_failures": 0
},
"process_checks": {
"oauth_wire": {
"php_authorization_code_pkce": "passed",
"rust_jwt_php_signature": "passed",
"rust_refresh_php_decryption": "passed",
"php_refresh_rotation_replay": "passed",
"client_credentials_wildcard": "passed"
},
"laravel_session_http": {
"php_session_browser_migration": "passed",
"cases": [
"file/json/encrypt=False",
"database/json/encrypt=False",
"file/json/encrypt=True",
"database/json/encrypt=True",
"file/php/encrypt=False",
"database/php/encrypt=False",
"file/php/encrypt=True",
"database/php/encrypt=True"
]
},
"cli_http_smoke": {
"cli_init": "passed",
"existing_db_refusal": "passed",
"test_user": "passed",
"http_login_crud_hotp_logout": "passed",
"php_differential": "not_run"
}
},
"device_interop_report": "device-interop.json"
}
@@ -0,0 +1,298 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"php": "8.4.27",
"results": [
{
"case": "issuer-missing-client",
"method": "POST",
"path": "/oauth/device/code",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "59"
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `client_id` parameter"
}
},
{
"case": "issuer-unknown-client",
"method": "POST",
"path": "/oauth/device/code",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "58"
},
"body": {
"error": "invalid_client",
"error_description": "Client authentication failed"
}
},
{
"case": "issuer-unauthorized-client",
"method": "POST",
"path": "/oauth/device/code",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "57"
},
"body": {
"error": "unauthorized_client",
"error_description": "The authenticated client is not authorized to use this authorization grant type."
}
},
{
"case": "issuer-valid",
"method": "POST",
"path": "/oauth/device/code",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "56"
},
"body": {
"verification_uri": "<BASE>/oauth/device",
"expires_in": 599,
"verification_uri_complete": "<BASE>/oauth/device?user_code=<USER_CODE>",
"interval": 5,
"device_code": "<DEVICE_CODE>",
"user_code": "<USER_CODE>",
"device_code_length": 80,
"user_code_length": 8,
"device_code_hex": true,
"user_code_consonants": true
}
},
{
"case": "poll-missing-device-code",
"method": "POST",
"path": "/oauth/token",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "55"
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `device_code` parameter"
}
},
{
"case": "poll-unknown-device-code",
"method": "POST",
"path": "/oauth/token",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "54"
},
"body": {
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": ""
}
},
{
"case": "poll-pending",
"method": "POST",
"path": "/oauth/token",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "53"
},
"body": {
"error": "authorization_pending",
"error_description": "The authorization request is still pending as the end user hasn't yet completed the user interaction steps. The client SHOULD repeat the Access Token Request to the token endpoint",
"hint": ""
}
},
{
"case": "poll-too-soon",
"method": "POST",
"path": "/oauth/token",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "52"
},
"body": {
"error": "slow_down",
"error_description": "The authorization request is still pending and polling should continue, but the interval MUST be increased by 5 seconds for this and all subsequent requests.",
"hint": ""
}
},
{
"case": "GET /oauth/device",
"method": "GET",
"path": "/oauth/device",
"status": 500,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "Server Error"
}
},
{
"case": "GET /oauth/device/authorize",
"method": "GET",
"path": "/oauth/device/authorize",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "Unauthenticated."
}
},
{
"case": "POST /oauth/device/authorize",
"method": "POST",
"path": "/oauth/device/authorize",
"status": 419,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "CSRF token mismatch."
}
},
{
"case": "DELETE /oauth/device/authorize",
"method": "DELETE",
"path": "/oauth/device/authorize",
"status": 419,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "CSRF token mismatch."
}
},
{
"case": "POST /oauth/authorize",
"method": "POST",
"path": "/oauth/authorize",
"status": 419,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "CSRF token mismatch."
}
},
{
"case": "DELETE /oauth/authorize",
"method": "DELETE",
"path": "/oauth/authorize",
"status": 419,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "CSRF token mismatch."
}
},
{
"case": "POST /oauth/token/refresh",
"method": "POST",
"path": "/oauth/token/refresh",
"status": 419,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Location": null,
"X-RateLimit-Limit": null,
"X-RateLimit-Remaining": null
},
"body": {
"message": "CSRF token mismatch."
}
}
],
"composer_lock_sha256": "b1376d21c517d700bc48b196e9dc2b30257caf25774e315ff9d1bf8a2411241a"
}
@@ -0,0 +1,202 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"php": "8.4.27",
"results": [
{
"case": "malformed-json",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "59"
},
"body": {
"message": "Bad request."
}
},
{
"case": "top-json-array",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "58"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "top-json-null",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "57"
},
"body": {
"message": "Bad request."
}
},
{
"case": "empty-json-body",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "56"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "form-scalar-then-array",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "55"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "form-array-then-scalar",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "54"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "top-json-number",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "53"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "top-json-nonempty-array",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "52"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "body-client-id-u2003",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "51"
},
"body": {
"token_type": "Bearer",
"expires_in": 31536000,
"access_token_present": true
}
},
{
"case": "basic-client-id-u2003",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": "Basic realm=\"OAuth\"",
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "50"
},
"body": {
"error": "invalid_client",
"error_description": "Client authentication failed"
}
},
{
"case": "body-client-secret-u2003",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "49"
},
"body": {
"token_type": "Bearer",
"expires_in": 31536000,
"access_token_present": true
}
}
],
"composer_lock_sha256": "b1376d21c517d700bc48b196e9dc2b30257caf25774e315ff9d1bf8a2411241a",
"request_notes": {
"malformed-json": "raw { with Content-Type application/json",
"top-json-array": "raw []",
"top-json-null": "raw null",
"empty-json-body": "zero bytes with Content-Type application/json",
"form-scalar-then-array": "grant_type=bogus&grant_type[]=client_credentials",
"form-array-then-scalar": "grant_type[]=client_credentials&grant_type=bogus",
"top-json-number": "raw 42",
"top-json-nonempty-array": "raw [\"bogus\"]",
"body-client-id-u2003": "valid fixture client ID surrounded by U+2003 in a form field",
"basic-client-id-u2003": "valid fixture client ID surrounded by U+2003 in HTTP Basic username",
"body-client-secret-u2003": "valid fixture client secret surrounded by U+2003 in a form field"
}
}
+188
View File
@@ -0,0 +1,188 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"php": "8.4.27",
"results": [
{
"case": "malformed-json",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "59"
},
"body": {
"message": "Bad request."
}
},
{
"case": "top-json-array",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "58"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "top-json-null",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "57"
},
"body": {
"message": "Bad request."
}
},
{
"case": "empty-json-body",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "56"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "form-scalar-then-array",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "55"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "form-array-then-scalar",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "54"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "top-json-number",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "53"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "top-json-nonempty-array",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "52"
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "body-client-id-u2003",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "51"
},
"body": {
"token_type": "Bearer",
"expires_in": 31536000,
"access_token_present": true
}
},
{
"case": "basic-client-id-u2003",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": "Basic realm=\"OAuth\"",
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "50"
},
"body": {
"error": "invalid_client",
"error_description": "Client authentication failed"
}
},
{
"case": "body-client-secret-u2003",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "49"
},
"body": {
"token_type": "Bearer",
"expires_in": 31536000,
"access_token_present": true
}
}
]
}
+502
View File
@@ -0,0 +1,502 @@
{
"php": "8.4.27",
"framework": "Laravel13.29.0/Passport13.7.6",
"request_format": "application/x-www-form-urlencoded",
"environment": "fresh disposable SQLite migrations and client-credentials fixture",
"results": [
{
"case": "missing-grant-type",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "59",
"Retry-After": null
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "unsupported-grant",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "58",
"Retry-After": null
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "client-credentials-missing-client-id",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "57",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `client_id` parameter"
}
},
{
"case": "unknown-client",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "56",
"Retry-After": null
},
"body": {
"error": "invalid_client",
"error_description": "Client authentication failed"
}
},
{
"case": "wrong-client-secret",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "55",
"Retry-After": null
},
"body": {
"error": "invalid_client",
"error_description": "Client authentication failed"
}
},
{
"case": "unknown-scope",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "54",
"Retry-After": null
},
"body": {
"error": "invalid_scope",
"error_description": "The requested scope is invalid, unknown, or malformed",
"hint": "Check the `__compat_unknown_scope__` scope"
}
},
{
"case": "valid-control",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "53",
"Retry-After": null
},
"body": {
"token_type": "Bearer",
"expires_in": 31536000,
"access_token_present": true,
"refresh_token_present": false
}
},
{
"case": "confidential-missing-secret",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "52",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `client_secret` parameter"
}
},
{
"case": "unauthorized-grant-valid-client",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "51",
"Retry-After": null
},
"body": {
"error": "unauthorized_client",
"error_description": "The authenticated client is not authorized to use this authorization grant type."
}
},
{
"case": "auth-code-missing-code",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "50",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `code` parameter"
}
},
{
"case": "refresh-missing-token",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "49",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `refresh_token` parameter"
}
},
{
"case": "auth-code-invalid-ciphertext",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "48",
"Retry-After": null
},
"body": {
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": "Cannot validate the provided authorization code"
}
},
{
"case": "refresh-invalid-ciphertext",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "47",
"Retry-After": null
},
"body": {
"error": "invalid_grant",
"error_description": "The refresh token is invalid.",
"hint": "Cannot decrypt the refresh token"
}
},
{
"case": "auth-code-malformed-payload",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "46",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Authorization code malformed"
}
},
{
"case": "auth-code-expired",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "45",
"Retry-After": null
},
"body": {
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": "Authorization code has expired"
}
},
{
"case": "auth-code-revoked",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "44",
"Retry-After": null
},
"body": {
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": "Authorization code has been revoked"
}
},
{
"case": "auth-code-wrong-client",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "43",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Authorization code was not issued to this client"
}
},
{
"case": "auth-code-missing-redirect",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "42",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `redirect_uri` parameter"
}
},
{
"case": "auth-code-wrong-redirect",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "41",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Invalid redirect URI"
}
},
{
"case": "pkce-missing-verifier",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "40",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Check the `code_verifier` parameter"
}
},
{
"case": "pkce-invalid-syntax",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "39",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "Code Verifier must follow the specifications of RFC-7636."
}
},
{
"case": "pkce-mismatch",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "38",
"Retry-After": null
},
"body": {
"error": "invalid_grant",
"error_description": "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.",
"hint": "Failed to verify `code_verifier`."
}
},
{
"case": "pkce-downgrade",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "37",
"Retry-After": null
},
"body": {
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
"hint": "code_verifier received when no code_challenge is present"
}
},
{
"case": "wrong-basic-secret",
"status": 401,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": "Basic realm=\"OAuth\"",
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "36",
"Retry-After": null
},
"body": {
"error": "invalid_client",
"error_description": "Client authentication failed"
}
},
{
"case": "json-unsupported-grant",
"status": 400,
"headers": {
"Content-Type": "application/json",
"Cache-Control": "no-cache, private",
"Pragma": null,
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "35",
"Retry-After": null
},
"body": {
"error": "unsupported_grant_type",
"error_description": "The authorization grant type is not supported by the authorization server.",
"hint": "Check that all required parameters have been provided"
}
},
{
"case": "json-valid-control",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=UTF-8",
"Cache-Control": "no-store, private",
"Pragma": "no-cache",
"WWW-Authenticate": null,
"Access-Control-Allow-Origin": null,
"X-RateLimit-Limit": "60",
"X-RateLimit-Remaining": "34",
"Retry-After": null
},
"body": {
"token_type": "Bearer",
"expires_in": 31536000,
"access_token_present": true,
"refresh_token_present": false
}
}
],
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"composer_lock_sha256": "b1376d21c517d700bc48b196e9dc2b30257caf25774e315ff9d1bf8a2411241a"
}
@@ -0,0 +1,23 @@
{
"version": "0.3.0",
"candidate_sha256": "0e03e978721bf4fcfc65e18e4a98f47b26b71a151c792b380d18996ae467813d",
"reference_php": "8.4.27",
"database_modes": [
"native",
"laravel-copy"
],
"checks": {
"php_bearer": 200,
"php_cookie": 200,
"cookie_missing_csrf": 401,
"tampered_bearer": 401,
"php_browser_bootstrap": 200,
"legacy_cookie_cleared": true,
"upgraded_browser_api": 200,
"upgraded_browser_logout": 200,
"browser_api_after_logout": 401,
"php_validated_rust_bearer": true,
"revoked_php_bearer": 401
},
"passed": true
}
+562
View File
@@ -0,0 +1,562 @@
{
"recorded_at_utc": "2026-10-27T02:52:00.131691+00:00",
"reference": {
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"php": "8.4.27",
"laravel": "13.29.0",
"composer_lock_sha256": "b1376d21c517d700bc48b196e9dc2b30257caf25774e315ff9d1bf8a2411241a",
"database": "fresh disposable SQLite, all 42 migrations completed; independent temporary application storage",
"production_dependencies": 110,
"required_extensions_loaded": true,
"composer_dependencies_total_with_dev": 153,
"materialized_sqlite_ddl": "sqlite-reference-schema.sql",
"tables": 22,
"explicit_indexes": 34
},
"candidate": {
"artifact": "preexisting target/release/twofauth-rs, predates current source changes",
"sha256": "e3d2f4435197bad611e2150c128b0edfcf97ce90d61156a430e948f1461438ba"
},
"limits": [
"This is a limited differential result, not replacement certification.",
"Random CSRF output and cookie protocols are not normalized.",
"Only synthetic fixture data was used.",
"Body IDs ignored only for account create/read as specified in cases.stateful.json.",
"State effects checked through API readback, not SQL table comparison.",
"New source changes must be rebuilt and compared again."
],
"results": {
"default": {
"exit_code": 1,
"cases": [
{
"case": 0,
"result": "different",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": false,
"body": false
}
},
{
"case": 1,
"result": "different",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": false
}
},
{
"case": 2,
"result": "different",
"reference_status": 200,
"candidate_status": 404,
"checks": {
"status": false,
"content_type": true,
"body": false
}
},
{
"case": 3,
"result": "different",
"reference_status": 404,
"candidate_status": 404,
"checks": {
"status": true,
"content_type": true,
"body": false
}
}
]
},
"stateful": {
"exit_code": 1,
"cases": [
{
"case": 0,
"result": "different",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": false,
"body": false,
"expected_status": true
}
},
{
"case": 1,
"result": "different",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 2,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 3,
"result": "equal",
"reference_status": 201,
"candidate_status": 201,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 4,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 5,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 6,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 7,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 8,
"result": "equal",
"reference_status": 204,
"candidate_status": 204,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 9,
"result": "different",
"reference_status": 404,
"candidate_status": 404,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 10,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 11,
"result": "different",
"reference_status": 401,
"candidate_status": 401,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
}
]
},
"extended": {
"exit_code": 1,
"cases": [
{
"case": 0,
"result": "different",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": false,
"body": false,
"expected_status": true
}
},
{
"case": 1,
"result": "different",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 2,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 3,
"result": "equal",
"reference_status": 201,
"candidate_status": 201,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 4,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 5,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 6,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 7,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 8,
"result": "different",
"reference_status": 201,
"candidate_status": 201,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 9,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 10,
"result": "equal",
"reference_status": 204,
"candidate_status": 204,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 11,
"result": "different",
"reference_status": 403,
"candidate_status": 403,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 12,
"result": "different",
"reference_status": 403,
"candidate_status": 404,
"checks": {
"status": false,
"content_type": true,
"body": false,
"expected_status": false
}
},
{
"case": 13,
"result": "different",
"reference_status": 403,
"candidate_status": 404,
"checks": {
"status": false,
"content_type": true,
"body": false,
"expected_status": false
}
},
{
"case": 14,
"result": "different",
"reference_status": 200,
"candidate_status": 404,
"checks": {
"status": false,
"content_type": true,
"body": false,
"expected_status": false
}
},
{
"case": 15,
"result": "different",
"reference_status": 422,
"candidate_status": 404,
"checks": {
"status": false,
"content_type": true,
"body": false,
"expected_status": false
}
},
{
"case": 16,
"result": "different",
"reference_status": 422,
"candidate_status": 405,
"checks": {
"status": false,
"content_type": false,
"body": false,
"expected_status": false
}
},
{
"case": 17,
"result": "different",
"reference_status": 422,
"candidate_status": 422,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 18,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 19,
"result": "equal",
"reference_status": 204,
"candidate_status": 204,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 20,
"result": "different",
"reference_status": 404,
"candidate_status": 404,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
},
{
"case": 21,
"result": "equal",
"reference_status": 200,
"candidate_status": 200,
"checks": {
"status": true,
"content_type": true,
"body": true,
"expected_status": true
}
},
{
"case": 22,
"result": "different",
"reference_status": 401,
"candidate_status": 401,
"checks": {
"status": true,
"content_type": true,
"body": false,
"expected_status": true
}
}
]
}
},
"reproduction": "PHPRC=<php.ini path> python tools/run_reference.py --php <php executable or wrapper> --source ../upstream --candidate-binary target/release/twofauth-rs --output <result.json>",
"upstream_suite": {
"command": "PHPRC=<php.ini> PATH=<php runtime>:$PATH php artisan config:clear; php vendor/bin/phpunit",
"tests": 1518,
"assertions": 4573,
"errors": 5,
"failures": 2,
"failure_details": [
{
"test": "Tests.Feature.Models.TwoFAccountModelTest::test_fill_with_custom_totp_uri_returns_correct_value",
"kind": "failure",
"message": "Tests\\Feature\\Models\\TwoFAccountModelTest::test_fill_with_custom_totp_uri_returns_correct_value"
},
{
"test": "Tests.Feature.Models.TwoFAccountModelTest::test_fill_with_custom_hotp_uri_returns_correct_value",
"kind": "failure",
"message": "Tests\\Feature\\Models\\TwoFAccountModelTest::test_fill_with_custom_hotp_uri_returns_correct_value"
},
{
"test": "Tests.Feature.Services.IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"PNG\"",
"kind": "error",
"message": "Tests\\Feature\\Services\\IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"PNG\""
},
{
"test": "Tests.Feature.Services.IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"JPEG\"",
"kind": "error",
"message": "Tests\\Feature\\Services\\IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"JPEG\""
},
{
"test": "Tests.Feature.Services.IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"WEBP\"",
"kind": "error",
"message": "Tests\\Feature\\Services\\IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"WEBP\""
},
{
"test": "Tests.Feature.Services.IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"BPM\"",
"kind": "error",
"message": "Tests\\Feature\\Services\\IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"BPM\""
},
{
"test": "Tests.Feature.Services.IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"SVG\"",
"kind": "error",
"message": "Tests\\Feature\\Services\\IconServiceTest::test_build_from_remote_image_stores_icon_and_returns_name with data set \"SVG\""
}
],
"limitations": [
"All seven remaining failing cases depend on real DNS resolution before mocked HTTP. dns_get_record returned false with a temporary server error for the image hosts.",
"No upstream source was patched to suppress those failures."
]
},
"crypto": {
"php_openssl": "6/6 fixtures passed",
"laravel_encrypter": "Laravel 13.29.0 Encrypter::decryptString accepted 6/6 independent Python envelopes"
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+100
View File
@@ -0,0 +1,100 @@
{
"upstream_commit": "3516c776a1fcbd83d234efc007e3a49807d6ed91",
"coverage_kind": "source-derived requirements plus finite executed fixtures; exhaustive compatibility is not certified",
"frontend": {
"public_build_present": true,
"asset_manifest": "public/build/manifest.json",
"source_rebuild_dependencies": [
"../2FAuth-Components/packages/formcontrols",
"../2FAuth-Components/packages/stores",
"../2FAuth-Components/packages/styles",
"../2FAuth-Components/packages/ui"
],
"bootstrap_globals": [
"appSettings",
"appConfig",
"urls",
"defaultPreferences",
"lockedPreferences",
"appVersion",
"isDemoApp",
"isTestingApp",
"appLocales"
],
"http": {
"api_prefix": "/api/v1",
"web_prefix": "/",
"credentials": true,
"headers": [
"X-Requested-With: XMLHttpRequest",
"Content-Type: application/json"
],
"special_statuses": [
419,
418,
407,
401,
422,
404
]
},
"sources": [
"package.json",
"resources/views/landing.blade.php",
"app/Http/Controllers/SinglePageController.php",
"resources/js/services/httpClientFactory.js"
]
},
"authentication": {
"guards": {
"web-guard": "session",
"api-guard": "passport",
"reverse-proxy-guard": "reverse-proxy"
},
"first_party_cookie": "laravel_token",
"csrf_cookie": "XSRF-TOKEN",
"csrf_exclusions": [],
"password_reset_table": "password_resets",
"webauthn_recovery_table": "webauthn_recoveries",
"sources": [
"config/auth.php",
"app/Http/Middleware/CustomCreateFreshApiToken.php",
"app/Http/Middleware/PreventRequestForgery.php",
"app/Providers/AuthServiceProvider.php"
]
},
"encryption": {
"cipher": "AES-256-CBC",
"key_environment": [
"APP_KEY",
"APP_PREVIOUS_KEYS"
],
"conditional_setting": "useEncryption",
"api": "Laravel Crypt::encryptString/decryptString",
"sources": [
"config/app.php",
"app/Models/Traits/CanEncryptField.php",
"app/Models/TwoFAccount.php"
]
},
"database": {
"drivers": [
"sqlite",
"mysql",
"pgsql",
"sqlsrv"
],
"evidence": "database.json",
"materialized_schema_verified": true,
"verified_schema_scope": "pinned migrations on SQLite only"
},
"differential_coverage": {
"real_upstream_requests_executed": 280,
"default_cases": 7,
"application_method_path_entries": 91,
"comparisons_per_database_mode": 140,
"exact_per_database_mode": 129,
"expected_raw_body_differences_per_mode": 11,
"harness_regression_tests_passed": 6
}
}
File diff suppressed because it is too large. Load diff
+61
View File
@@ -0,0 +1,61 @@
{
"Cargo.lock": "eb74066a33403cef46a1df8ca01f3ddd31c7e76176afae9409f33f11fcc4fea3",
"Cargo.toml": "a3ae8d9be58d210b72c86493777c47add1963c5e07a132ddf9caf051a78fd893",
"compatibility/cases.admin-sharing.json": "5f39b08890a35639098d14d15f83c572540901a07f88878859f7ee1ebeea4f12",
"compatibility/cases.device.json": "d8ce2b996783a392d7b9aaf6f974118f43c1bd020b7b9ee4315a86a0a0728ff2",
"compatibility/cases.example.json": "4b4b3d09016d74110933b8b0cc315804887474942970b88d0828ede2c07c5d6c",
"compatibility/cases.extended.json": "3be56ecb6ecae8a05b781ebcfedb227f3be11f9e08ffc8262d3a9bce85a85dc0",
"compatibility/cases.oauth.json": "c084069e46c12b87f78d0a190016e15db3504f1741c816bf97d98d8ff47b7c04",
"compatibility/cases.stateful.json": "1ed836e1f4cb76d97234065faf415aaba251a070a336977c2b8eaec5e5565e3b",
"src/accounts.rs": "79960cd11029a11cc53e154bc488bc96496a9c8c1e1b85ef8cd1ebf1b1a1019d",
"src/api_limits.rs": "7c3decee88724155448ad54993701188abcc9747139d0e955f0ac399fa9700a0",
"src/auth.rs": "890b3b9adbe8afd52d21694a499bb85cacddf98bc192549be0b4218c967236d3",
"src/auth_audit.rs": "70dfde6ce82641eae24f044e4755af294051459521632a93e50d5d6ad9410f56",
"src/cors.rs": "0058858569b419e3a21c8a89d4aa58f2a0e3f4af499a5bcd42b6e09139508b0a",
"src/crypto.rs": "39bf321d76a4abb9c5bffe5b77993ef393a00628262a8a0a3fa1c88e7c7a0655",
"src/db.rs": "a049dc8069d8d86cb0c9283e1b2897f5c326a35ed6aef138eadcada893aac825",
"src/frontend.rs": "056a75fcfe6a62527535436a06cecdc7a0be4f96be8a56d69135e350dd655f90",
"src/groups.rs": "3cdb3cd1d9077e87099da7fdc291f20cdb15beebb92dcd9aaa3b53c772c2bfc9",
"src/health.html": "ada7ca3391f78faee6e64d23feb69b88cf9a93da9629805c15b96b4a7131869e",
"src/icons.rs": "e36e21a6d08629ab70e23803cb191cc2ff7350a9a11350e312984f35cfe5dcbc",
"src/imports.rs": "245cd921e3cd1c3cd9d99e809b3c677795de0776c67e2225e7036e56ca43cf28",
"src/laravel_sessions.rs": "9d66f36762da5c7107466730add09800346bdad1fc2a11c2580037c9faf10537",
"src/lib.rs": "ad07ecd9fc3fb34fcf8fb0a314d75a3b6a6cca000d9bb9d7f5f616b1d8716831",
"src/mail.rs": "4d9a0fecb0ad0653237a19e302f08055c5783fc2195ab1ba2aa7a911d42c9633",
"src/mail_messages.json": "2950864b85dce65149b3f6b6a237b8d227f4847d2b66e741710b220b1855ac85",
"src/main.rs": "4a90c73375964e9db6e4510ea0ccd2d52c26af200749266ae07282401c4bcdc8",
"src/oauth_device.rs": "e4dd21a3422e083934b68edd5a6b3eb950c0fe3463ce0ebc617851928b7ccd36",
"src/oauth_management.rs": "176cfaf6fc8895e52f8310239c380961508646f0e539be39edca8dab65b421cc",
"src/oauth_server.rs": "9ab85322d905bb11f33f6098f71d6d930fe9e16bc489eced7293b768e0f9c868",
"src/otp.rs": "659e1f61993824bc8c58dca064af5aca0022a1c93ab809b6aca819b54e010bbe",
"src/passport.rs": "fcc2d3a76610c0337d8319bdf2bf115e3e5c1fd027cd19e11f45f1e136c08f8f",
"src/preference_env.json": "acd88981c0bf1464cba7b2e7a88dc34b95b4e32c53845494bf47a48911847fca",
"src/preferences.json": "5582dfc4b9507752c58a75163913d0908415b7843bcbd3e92aa47929a20a84c2",
"src/profile.rs": "98055abf266e4f063c2821fb64aef7f0f65d823cb2799c2479c80087de257c8a",
"src/proxy_auth.rs": "87f0ba8f13e22d41faaa8098d2ebca2e2ab892673d446859274077138a33a0e2",
"src/schema_validation.rs": "8b76dd92d9788bae73b1ec2b8bfdc7a162412c0feab45433302e6de04653c2a7",
"src/settings.json": "733e680c3eb3efbddba11283b2d893fdaaab6c317bc133d285ab65a1ee8d0363",
"src/settings.rs": "42df151a0a0fca7df70be833170a95dd2d00516de483045c92e68cc30e8e510c",
"src/sharing.rs": "8c7436bc3ef7cdb6bdd41d5f21a08bfc0241be3c669ce65df2a235a4e1c1e377",
"src/sso.rs": "54bf97081d43141aecc56cf34f6565506e0ade54c4b4001ff34eec5ea4256ef2",
"src/subdirectory.rs": "eacd89b631a9c1265c8a5199229768cb10dfdf0d2cb309c400311eb6d9f743d1",
"src/system.rs": "e3afe95b83377153f139199e895f18add47517f3b2de254b38476ccd8c2726fb",
"src/users.rs": "d52f54a9e27093db162b50f4863cb48b0a7afa8dd53793d827b0abd545be99ae",
"src/webauthn.rs": "70b2520ff5fa043928a501915b47721bf75bc54bdbd69a8d326e56333aa60246",
"tests/crypto_interop.py": "b2287d8574d10d00693d0912530c1d4c70505dfaddab2aaf387fe0ed195bd5f2",
"tests/device_interop.py": "07d14355ba866b901b89e2792b5569212c3fd8b88c78d3206f1f2423df5059d2",
"tests/differential_harness.py": "3694acaf253935691e715bc38d8fd9bad02219b3ba17624427a38fb3534b6cdf",
"tests/fixtures/generate_laravel_sessions.php": "d82befcb2e6a49add0d4d1adbe826cb22153d5376979aceb7726de5c0a49941f",
"tests/fixtures/laravel_cbc.json": "d5a70db56eb7b3d3503bb51378e6d4bf48cc3f957fc562a2e38e6564292785a8",
"tests/fixtures/laravel_sessions.json": "993edffd9927a0e86854f5f3461890f20e6afeaee1a06a0271df9d6e68c85a1c",
"tests/fixtures/webauthn-php-encrypted.txt": "3d2de57aa15c909f03fb07b84dfa96e4875f8da9ccb323dab09f21e7a9a58d57",
"tests/fixtures/webauthn-private.pem": "a9f0231cb05b09c0d093468c2dc9c45782b776c4904302eefb5b925f71e4999b",
"tests/http_smoke.py": "ea6f98db907fbd865f91aa508a2ab5b14de3dc8d89f050c8b309e7a1632cbb24",
"tests/laravel_session_http.py": "df747bc0f2cb3777e57c525234279c6417b60d8c836c0becbeb2419705e5df6b",
"tests/oauth_interop.py": "07a8c994fb3c4e283bb35cbdead50d4165f9eb1c592063b83670b9ab84fd5a41",
"tools/differential_http.py": "7d8ab01ebfac575777bf65c1738d6e1f4e4317b787903c7be797313568a188e6",
"tools/inventory.py": "c5fecb07767032fa0bc6fdc427f11da6920c2f2c0e377d7b653a332293f2eaeb",
"tools/passport_interop.py": "3e2ccd732916ca0be0153011d233450364d939b28a5fcedb4040c797889ca7ff",
"tools/run_reference.py": "9441072d4b8ba56d55a709443d270ab19f789fb2a3a5200dcbdc7d6c8b924dc6",
"tools/semantic_http.py": "8e7e349d78391786a218a6b577991f6eb8aae5ef24e49119ca1955b6f39162cd"
}
+115
View File
@@ -0,0 +1,115 @@
-- SQLite DDL materialized by pinned upstream Laravel migrations.
-- Upstream 3516c776a1fcbd83d234efc007e3a49807d6ed91; PHP 8.4.27; Laravel 13.29.0.
-- 42 migrations; no data, deployment configuration, keys or sessions included.
CREATE TABLE "auth_logs" ("id" integer primary key autoincrement not null, "authenticatable_type" varchar not null, "authenticatable_id" integer not null, "ip_address" varchar, "user_agent" text, "login_at" datetime, "login_successful" tinyint(1) not null default '0', "logout_at" datetime, "cleared_by_user" tinyint(1) not null default '0', "guard" varchar, "login_method" varchar, foreign key("authenticatable_id") references "users"("id") on delete cascade);
CREATE TABLE "cache" ("key" varchar not null, "value" text not null, "expiration" integer not null, primary key ("key"));
CREATE TABLE "cache_locks" ("key" varchar not null, "owner" varchar not null, "expiration" integer not null, primary key ("key"));
CREATE TABLE "groups" ("id" integer primary key autoincrement not null, "name" varchar not null, "created_at" datetime, "updated_at" datetime, "user_id" integer, "order_column" integer, "show_in_chips" tinyint(1) not null default '0', foreign key("user_id") references "users"("id") on delete cascade);
CREATE TABLE "icons" ("name" varchar not null, "content" text not null, "created_at" datetime, "updated_at" datetime, primary key ("name"));
CREATE TABLE "migrations" ("id" integer primary key autoincrement not null, "migration" varchar not null, "batch" integer not null);
CREATE TABLE "oauth_access_tokens" ("id" varchar not null, "user_id" integer, "client_id" integer not null, "name" varchar, "scopes" text, "revoked" tinyint(1) not null, "created_at" datetime, "updated_at" datetime, "expires_at" datetime, primary key ("id"));
CREATE TABLE "oauth_auth_codes" ("id" varchar not null, "user_id" integer not null, "client_id" integer not null, "scopes" text, "revoked" tinyint(1) not null, "expires_at" datetime, primary key ("id"));
CREATE TABLE "oauth_clients" ("id" integer primary key autoincrement not null, "name" varchar not null, "secret" varchar, "provider" varchar, "revoked" tinyint(1) not null, "created_at" datetime, "updated_at" datetime, "owner_type" varchar, "owner_id" integer, "redirect_uris" text not null, "grant_types" text not null);
CREATE TABLE "oauth_device_codes" ("id" varchar not null, "user_id" integer, "client_id" varchar not null, "user_code" varchar not null, "scopes" text not null, "revoked" tinyint(1) not null, "user_approved_at" datetime, "last_polled_at" datetime, "expires_at" datetime, primary key ("id"));
CREATE TABLE "oauth_refresh_tokens" ("id" varchar not null, "access_token_id" varchar not null, "revoked" tinyint(1) not null, "expires_at" datetime, primary key ("id"));
CREATE TABLE "options" ("id" integer primary key autoincrement not null, "key" varchar not null, "value" text not null);
CREATE TABLE "otp_logs" ("id" integer primary key autoincrement not null, "requester_id" integer, "requester_name" varchar not null, "requester_email" varchar not null, "owner_id" integer, "owner_name" varchar not null, "owner_email" varchar not null, "twofaccount_id" integer not null, "ip_address" varchar not null, "otp_type" varchar not null, "counter" integer, "generated_at" datetime not null, foreign key("requester_id") references "users"("id") on delete set null, foreign key("owner_id") references "users"("id") on delete set null, foreign key("twofaccount_id") references "twofaccounts"("id") on delete cascade);
CREATE TABLE "password_resets" ("email" varchar not null, "token" varchar not null, "created_at" datetime);
CREATE TABLE "sessions" ("id" varchar not null, "user_id" integer, "ip_address" varchar, "user_agent" text, "payload" text not null, "last_activity" integer not null, primary key ("id"));
CREATE TABLE "twofaccount_group_assignments" ("id" integer primary key autoincrement not null, "twofaccount_id" integer not null, "user_id" integer not null, "group_id" integer not null, "created_at" datetime, "updated_at" datetime, foreign key("twofaccount_id") references "twofaccounts"("id") on delete cascade, foreign key("user_id") references "users"("id") on delete cascade, foreign key("group_id") references "groups"("id") on delete cascade);
CREATE TABLE "twofaccount_shares" ("id" integer primary key autoincrement not null, "twofaccount_id" integer not null, "shared_with_user_id" integer, "scope" varchar not null, "created_by_user_id" integer not null, "created_at" datetime, "updated_at" datetime, foreign key("twofaccount_id") references "twofaccounts"("id") on delete cascade, foreign key("shared_with_user_id") references "users"("id") on delete cascade, foreign key("created_by_user_id") references "users"("id") on delete cascade);
CREATE TABLE "twofaccount_user_orders" ("id" integer primary key autoincrement not null, "user_id" integer not null, "twofaccount_id" integer not null, "position" integer not null, "created_at" datetime, "updated_at" datetime, foreign key("user_id") references "users"("id") on delete cascade, foreign key("twofaccount_id") references "twofaccounts"("id") on delete cascade);
CREATE TABLE "twofaccounts" ("id" integer primary key autoincrement not null, "service" text, "legacy_uri" text not null, "account" text not null, "icon" varchar, "created_at" datetime, "updated_at" datetime, "order_column" integer, "group_id" integer, "otp_type" varchar not null, "secret" text not null, "algorithm" varchar not null, "digits" integer not null, "period" integer, "counter" integer, "user_id" integer, foreign key("user_id") references users("id") on delete cascade on update no action, foreign key("group_id") references groups("id") on delete set null on update no action);
CREATE TABLE "users" ("id" integer primary key autoincrement not null, "name" varchar not null, "email" varchar not null, "email_verified_at" datetime, "password" varchar not null, "remember_token" varchar, "created_at" datetime, "updated_at" datetime, "last_seen_at" datetime, "is_admin" tinyint(1) not null default '0', "preferences" text, "oauth_provider" varchar, "oauth_id" varchar);
CREATE TABLE "webauthn_credentials" ("id" varchar not null, "authenticatable_type" varchar not null, "authenticatable_id" integer not null, "user_id" varchar not null, "alias" varchar, "counter" integer, "rp_id" varchar not null, "origin" varchar not null, "transports" text, "aaguid" varchar, "public_key" text not null, "attestation_format" varchar not null default 'none', "certificates" text, "disabled_at" datetime, "created_at" datetime, "updated_at" datetime, primary key ("id"));
CREATE TABLE "webauthn_recoveries" ("email" varchar not null, "token" varchar not null, "created_at" datetime);
CREATE INDEX "auth_logs_authenticatable_type_authenticatable_id_index" on "auth_logs" ("authenticatable_type", "authenticatable_id");
CREATE INDEX "auth_logs_login_at_index" on "auth_logs" ("login_at");
CREATE INDEX "auth_logs_login_successful_index" on "auth_logs" ("login_successful");
CREATE INDEX "auth_logs_logout_at_index" on "auth_logs" ("logout_at");
CREATE INDEX "cache_expiration_index" on "cache" ("expiration");
CREATE INDEX "cache_locks_expiration_index" on "cache_locks" ("expiration");
CREATE INDEX "oauth_access_tokens_user_id_index" on "oauth_access_tokens" ("user_id");
CREATE INDEX "oauth_auth_codes_user_id_index" on "oauth_auth_codes" ("user_id");
CREATE INDEX "oauth_clients_owner_type_owner_id_index" on "oauth_clients" ("owner_type", "owner_id");
CREATE INDEX "oauth_device_codes_client_id_index" on "oauth_device_codes" ("client_id");
CREATE UNIQUE INDEX "oauth_device_codes_user_code_unique" on "oauth_device_codes" ("user_code");
CREATE INDEX "oauth_device_codes_user_id_index" on "oauth_device_codes" ("user_id");
CREATE INDEX "oauth_refresh_tokens_access_token_id_index" on "oauth_refresh_tokens" ("access_token_id");
CREATE UNIQUE INDEX "options_key_unique" on "options" ("key");
CREATE INDEX "otp_logs_ip_address_index" on "otp_logs" ("ip_address");
CREATE INDEX "otp_logs_otp_type_index" on "otp_logs" ("otp_type");
CREATE INDEX "otp_logs_requester_id_index" on "otp_logs" ("requester_id");
CREATE INDEX "otp_logs_twofaccount_id_index" on "otp_logs" ("twofaccount_id");
CREATE INDEX "password_resets_email_index" on "password_resets" ("email");
CREATE INDEX "sessions_last_activity_index" on "sessions" ("last_activity");
CREATE INDEX "sessions_user_id_index" on "sessions" ("user_id");
CREATE INDEX "twofaccount_group_assignments_group_id_index" on "twofaccount_group_assignments" ("group_id");
CREATE UNIQUE INDEX "twofaccount_group_assignments_unique_scope" on "twofaccount_group_assignments" ("twofaccount_id", "user_id");
CREATE INDEX "twofaccount_group_assignments_user_id_index" on "twofaccount_group_assignments" ("user_id");
CREATE INDEX "twofaccount_shares_shared_with_user_id_index" on "twofaccount_shares" ("shared_with_user_id");
CREATE INDEX "twofaccount_shares_twofaccount_id_scope_index" on "twofaccount_shares" ("twofaccount_id", "scope");
CREATE UNIQUE INDEX "twofaccount_shares_unique_target" on "twofaccount_shares" ("twofaccount_id", "scope", "shared_with_user_id");
CREATE INDEX "twofaccount_user_orders_twofaccount_id_index" on "twofaccount_user_orders" ("twofaccount_id");
CREATE UNIQUE INDEX "twofaccount_user_orders_unique_scope" on "twofaccount_user_orders" ("user_id", "twofaccount_id");
CREATE INDEX "twofaccount_user_orders_user_id_position_index" on "twofaccount_user_orders" ("user_id", "position");
CREATE UNIQUE INDEX "users_email_unique" on "users" ("email");
CREATE UNIQUE INDEX "users_name_unique" on "users" ("name");
CREATE INDEX "web_authn_recoveries_email_index" on "webauthn_recoveries" ("email");
CREATE INDEX "webauthn_user_index" on "webauthn_credentials" ("authenticatable_type", "authenticatable_id");
+23
View File
@@ -0,0 +1,23 @@
services:
rust:
build: .
ports:
- "127.0.0.1:8080:8080"
environment:
DATABASE_URL: sqlite:///data/2fauth.sqlite
LISTEN_ADDR: 0.0.0.0:8080
# Only for the local HTTP development port. Use true behind HTTPS.
RUST_COOKIE_SECURE: "false"
RUST_LOG: twofauth_rs=info
volumes:
- rust-dev-data:/data
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
init: true
volumes:
rust-dev-data:
+661
View File
@@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.
+4
View File
@@ -0,0 +1,4 @@
Frontend build and public images copied unchanged from Bubka/2FAuth commit 3516c776a1fcbd83d234efc007e3a49807d6ed91.
Upstream: https://github.com/Bubka/2FAuth
Copyright and license retained in UPSTREAM-LICENSE (AGPL-3.0).
The Rust HTTP service remains an incomplete implementation of the upstream API.
+1
View File
@@ -0,0 +1 @@
import{U as _}from"./index-BJsmINgd.js";import{a as $,d as C,w as r,g as L,f as p,M as N,h as k,i as l,j as o,m as s,t as e,n as u,l as M,k as A,p as n}from"./app-dvJP63FL.js";import{c as d}from"./createLucideIcon-DsaEAGzP.js";const B=[["path",{d:"m18 16 4-4-4-4",key:"1inbqp"}],["path",{d:"m6 8-4 4 4 4",key:"15zrgr"}],["path",{d:"m14.5 4-5 16",key:"e7oirm"}]],V=d("code-xml",B);const z=[["path",{d:"M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2",key:"18mbvz"}],["path",{d:"M6.453 15h11.094",key:"3shlmq"}],["path",{d:"M8.5 2h7",key:"csnxdl"}]],F=d("flask-conical",z);const S=[["path",{d:"M18 19a5 5 0 0 1-5-5v8",key:"sz5oeg"}],["path",{d:"M9 20H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v5",key:"1w6njk"}],["circle",{cx:"13",cy:"12",r:"2",key:"1j92g6"}],["circle",{cx:"20",cy:"19",r:"2",key:"1obnsp"}]],j=d("folder-git-2",S);const w=[["path",{d:"M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z",key:"j76jl0"}],["path",{d:"M22 10v6",key:"1lu8f3"}],["path",{d:"M6 12.5V16a6 3 0 0 0 12 0v-3.5",key:"1r8lef"}]],E=d("graduation-cap",w),G={class:"title"},I={class:"block"},W={key:0},H={class:"title is-5"},R={class:"buttons"},T={class:"icon is-small"},U={class:"icon is-small"},q={class:"icon is-small"},D={class:"icon is-small"},P={class:"title is-5"},Q={__name:"About",setup(X){const m=N("2fauth"),b=$(),c=L(),h=c.options.routes.find(a=>a.path==c.options.history.state.back).name;return(a,t)=>{const f=p("ResponsiveWidthWrapper"),g=p("NavigationButton"),y=p("VueFooter"),v=p("StackLayout");return k(),C(v,null,{content:r(()=>[l(f,null,{default:r(()=>[l(o(_),null,{default:r(({mode:i})=>[s("h1",G,e(a.$t("heading.about")),1),s("p",I,[s("span",{class:u(i=="dark"?"has-text-white":"has-text-black")},[t[1]||(t[1]=s("span",{class:"is-size-5"},"2FAuth",-1)),o(b).isAuthenticated?(k(),M("span",W," v"+e(o(m).version),1)):A("",!0)],2),t[2]||(t[2]=s("br",null,null,-1)),n(" "+e(a.$t("message.2fauth_teaser")),1)]),t[11]||(t[11]=s("img",{class:"about-logo",src:"logo.svg",alt:"2FAuth logo"},null,-1)),t[12]||(t[12]=s("p",{class:"block"},[n(" ©Bubka "),s("a",{class:"is-size-7 is-link",href:"https://github.com/Bubka/2FAuth/blob/master/LICENSE"},"AGPL-3.0 license")],-1)),s("h2",H,e(a.$t("heading.resources")),1),s("div",R,[s("a",{class:u(["button",{"is-dark":i=="dark"}]),href:"https://github.com/Bubka/2FAuth",target:"_blank"},[s("span",T,[l(o(j))]),t[3]||(t[3]=s("span",null,"Github",-1))],2),s("a",{class:u(["button",{"is-dark":i=="dark"}]),href:"https://docs.2fauth.app/",target:"_blank"},[s("span",U,[l(o(E))]),s("span",null,e(a.$t("label.docs")),1)],2),s("a",{class:u(["button",{"is-dark":i=="dark"}]),href:"https://demo.2fauth.app/",target:"_blank"},[s("span",q,[l(o(F))]),s("span",null,e(a.$t("label.demo")),1)],2),s("a",{class:u(["button",{"is-dark":i=="dark"}]),href:"https://docs.2fauth.app/resources/rapidoc.html",target:"_blank"},[s("span",D,[l(o(V))]),s("span",null,e(a.$t("label.api")),1)],2)]),s("h2",P,e(a.$t("heading.credits")),1),s("ul",null,[s("li",null,[n(e(a.$t("message.made_with"))+" ",1),t[4]||(t[4]=s("a",{class:"is-link",href:"https://docs.2fauth.app/credits/"},"Laravel, Bulma CSS, Vue.js and more",-1))]),s("li",null,[n(e(a.$t("message.ui_icons_by"))+" ",1),t[5]||(t[5]=s("a",{class:"is-link",href:"https://lucide.dev/"},"Lucide",-1)),t[6]||(t[6]=n(" ",-1)),t[7]||(t[7]=s("a",{class:"is-size-7 is-link",href:"https://lucide.dev/license"},"(ISC License)",-1))]),s("li",null,[n(e(a.$t("message.logos_by"))+" ",1),t[8]||(t[8]=s("a",{class:"is-link",href:"https://2fa.directory/"},"2FA Directory",-1)),t[9]||(t[9]=n(" ",-1)),t[10]||(t[10]=s("a",{class:"is-size-7 is-link",href:"https://github.com/2factorauth/twofactorauth/blob/master/LICENSE.md"},"(MIT License)",-1))])])]),_:1})]),_:1})]),footer:r(()=>[l(y,null,{default:r(()=>[l(g,{action:"back",onGoback:t[0]||(t[0]=i=>o(c).push({name:o(h)})),"previous-page-title":a.$t("title."+o(h))},null,8,["previous-page-title"])]),_:1})]),_:1})}}};export{Q as default};
+1
View File
@@ -0,0 +1 @@
import{_ as I}from"./AccessLogViewer-D5ke4CwJ.js";import{o as k,e as B,a1 as S,d as $,w as n,f as a,g as b,h as y,i as t,j as r,m as p,t as u}from"./app-dvJP63FL.js";import{u as N}from"./bus-ChE1sp8V.js";import"./index-BJsmINgd.js";import"./tablet-DYUfDfjC.js";import"./createLucideIcon-DsaEAGzP.js";import"./x-DQVIq0xP.js";import"./check-CPGWPXZa.js";const V={class:"title"},W={class:"block is-size-7-mobile"},A={__name:"Access",props:{userId:[Number,String]},setup(m){const d=N(),i=b();k(async()=>{_()});const s=m,c=B(d.username??"");function _(){S.getById(s.userId,{returnError:!0}).then(e=>{c.value=e.data.info.name})}return(e,o)=>{const g=a("ResponsiveWidthWrapper"),l=a("NavigationButton"),f=a("VueFooter"),v=a("StackLayout");return y(),$(v,null,{content:n(()=>[t(g,null,{default:n(()=>[p("h1",V,u(e.$t("heading.access_log")),1),p("div",W,u(e.$t("message.access_log_legend_for_user",{username:r(c)}))+" (#"+u(s.userId)+") ",1),t(I,{userId:s.userId,lastOnly:!1,showSearch:!0,period:1},null,8,["userId"])]),_:1})]),footer:n(()=>[t(f,null,{default:n(()=>[t(l,{action:"back",onGoback:o[0]||(o[0]=h=>r(i).push({name:"admin.manageUser",params:{userId:s.userId}})),"previous-page-title":e.$t("title.admin.manageUser")},null,8,["previous-page-title"]),t(l,{action:"close",onClosed:o[1]||(o[1]=h=>r(i).push({name:"accounts"})),"current-page-title":e.$t("title.admin.logs.access")},null,8,["current-page-title"])]),_:1})]),_:1})}}};export{A as default};
@@ -0,0 +1 @@
import{C as j,M as z,e as p,o as P,a1 as X,f as A,h as l,l as h,d as r,D as H,j as e,X as J,k as B,m as s,n as i,t as a,i as v,F as N,E as R,w as y,p as w,B as q}from"./app-dvJP63FL.js";import{U as G}from"./index-BJsmINgd.js";import{C as K,a as Q,S as W,T as Z,M as tt}from"./tablet-DYUfDfjC.js";import{X as et}from"./x-DQVIq0xP.js";import{C as st}from"./check-CPGWPXZa.js";const ot={key:1,class:"level is-mobile mb-2"},nt={class:"level-item has-text-centered"},lt={class:"buttons"},at=["title"],rt=["title"],it=["title"],dt=["title"],ct=["title"],ht=["title"],ut={key:3,class:"mt-4"},gt={key:4},_t={class:"light-or-darker"},pt={class:"light-or-darker"},yt={class:"light-or-darker"},mt={class:"light-or-darker"},bt={class:"light-or-darker"},kt={class:"light-or-darker"},ft={class:"light-or-darker"},vt={class:"log-icon-wrapper"},wt={key:5,class:"mt-5 pl-3"},At={__name:"AccessLogViewer",props:{userId:[Number,String],lastOnly:Boolean,showSearch:Boolean,period:{type:[Number,String],default:12}},emits:["has-more-entries"],setup(D,{emit:Y}){const L=j(),O=z("2fauth"),u=D,d={aMonth:1,threeMonths:3,halfYear:6,aYear:12},c=p([]),f=p(!1),m=p(""),g=p(u.period),_=p(!0),V=Y,S=q(()=>c.value.filter(t=>JSON.stringify(t).toString().toLowerCase().includes(m.value)));P(()=>{M()});function b(t){g.value=t,M()}function E(){_.value=!1,$()}function $(){c.value.sort((t,n)=>t.id>n.id?1:-1)}function F(){_.value=!0,C()}function C(){c.value.sort((t,n)=>t.id<n.id?1:-1)}function M(){f.value=!0;let t=u.lastOnly?4:!1;X.getauthentications(u.userId,g.value,t,{returnError:!0}).then(n=>{c.value=n.data,c.value.length>3&&u.lastOnly&&(V("has-more-entries"),c.value.pop()),_.value==!0?C():$()}).catch(n=>{L.show(n)}).finally(()=>{f.value=!1})}const I=t=>!t.login_at&&t.logout_at,x=t=>!t.login_successful&&!t.logout_at;return(t,n)=>{const T=A("Spinner"),k=A("i18n-t");return l(),h(N,null,[u.showSearch?(l(),r(e(J),{key:0,keyword:e(m),"onUpdate:keyword":n[0]||(n[0]=o=>H(m)?m.value=o:null),hasNoBackground:!0},null,8,["keyword"])):B("",!0),u.showSearch?(l(),h("nav",ot,[s("div",nt,[s("div",lt,[s("button",{id:"btnShowOneMonth",title:t.$t("tooltip.show_last_month_log"),onClick:n[1]||(n[1]=o=>b(d.aMonth)),class:i([{"has-text-grey":e(g)!==d.aMonth},"button is-ghost p-1"]),type:"button"},a(t.$t("label.one_month")),11,at),s("button",{id:"btnShowThreeMonths",title:t.$t("tooltip.show_three_months_log"),onClick:n[2]||(n[2]=o=>b(d.threeMonths)),class:i([{"has-text-grey":e(g)!==d.threeMonths},"button is-ghost p-1"]),type:"button"},a(t.$t("label.x_month",{x:"3"})),11,rt),s("button",{id:"btnShowSixMonths",title:t.$t("tooltip.show_six_months_log"),onClick:n[3]||(n[3]=o=>b(d.halfYear)),class:i([{"has-text-grey":e(g)!==d.halfYear},"button is-ghost p-1"]),type:"button"},a(t.$t("label.x_month",{x:"6"})),11,it),s("button",{id:"btnShowOneYear",title:t.$t("tooltip.show_one_year_log"),onClick:n[4]||(n[4]=o=>b(d.aYear)),class:i([{"has-text-grey":e(g)!==d.aYear},"button is-ghost p-1 mr-5"]),type:"button"},a(t.$t("label.one_year")),11,dt),s("button",{id:"btnSortLogDesc",onClick:F,title:t.$t("tooltip.sort_by_date_desc"),class:i([{"has-text-grey":!e(_)},"button p-1 is-ghost"]),type:"button"},[v(e(K))],10,ct),s("button",{id:"btnSortLogAsc",onClick:E,title:t.$t("tooltip.sort_by_date_asc"),class:i([{"has-text-grey":e(_)},"button p-1 is-ghost"]),type:"button"},[v(e(Q))],10,ht)])])])):B("",!0),e(f)?(l(),r(T,{key:2,isVisible:!0,type:"list-loading"})):e(c).length==0?(l(),h("div",ut,a(t.$t("message.no_entry_yet")),1)):e(S).length>0?(l(),h("div",gt,[(l(!0),h(N,null,R(e(S),o=>(l(),h("div",{key:o.id,class:"list-item is-size-6 is-size-7-mobile has-text-grey is-flex is-justify-content-space-between"},[v(e(G),null,{default:y(({mode:U})=>[s("div",null,[s("div",null,[x(o)?(l(),r(k,{key:0,keypath:"message.failed_login_on",tag:"span"},{login_at:y(()=>[s("span",_t,a(o.login_at),1)]),_:2},1024)):I(o)?(l(),r(k,{key:1,keypath:"message.successful_logout_on",tag:"span"},{logout_at:y(()=>[s("span",pt,a(o.logout_at),1)]),_:2},1024)):e(O).config.proxyAuth?(l(),r(k,{key:2,keypath:"message.viewed_on",tag:"span"},{login_at:y(()=>[s("span",yt,a(o.login_at),1)]),_:2},1024)):(l(),r(k,{key:3,keypath:"message.successful_login_on",tag:"span"},{login_at:y(()=>[s("span",mt,a(o.login_at),1)]),_:2},1024))]),s("div",null,[w(a(t.$t("label.IP"))+": ",1),s("span",bt,a(o.ip_address),1),w(" - "+a(t.$t("label.browser"))+": ",1),s("span",kt,a(o.browser),1),w(" - "+a(t.$t("label.operating_system_short"))+": ",1),s("span",ft,a(o.platform),1)])]),s("div",{class:i([U=="dark"?"has-text-grey-darker":"has-text-grey-lighter","is-align-self-center"])},[s("div",vt,[o.device=="phone"?(l(),r(e(W),{key:0,class:"log-icon-bg"})):o.device=="tablet"?(l(),r(e(Z),{key:1,class:"log-icon-bg"})):(l(),r(e(tt),{key:2,class:"log-icon-bg"})),x(o)?(l(),r(e(et),{key:3,"stroke-width":"3",class:i(["log-icon-mark","has-text-danger"])})):(l(),r(e(st),{key:4,"stroke-width":"3",class:i(["log-icon-mark","has-text-success-50"])}))])],2)]),_:2},1024)]))),128))])):(l(),h("div",wt,Line truncated
+1
View File
@@ -0,0 +1 @@
import{C as E,u as I,a as j,a8 as H,r as B,af as z,d as Q,w,M as q,f as p,g as G,a7 as k,h as g,i as l,j as s,l as _,m as o,t as i,k as h,H as M,p as J,ak as O,$ as X}from"./app-dvJP63FL.js";import{t as Y}from"./tabs-Btun2NN0.js";import{F}from"./Form-ZbAUhXmz.js";import{u as Z}from"./breakpoints-CyLcIEOu.js";const ee={key:0,class:"pr-5 settings-menu"},se={class:"menu"},te={class:"menu-list"},oe={key:1,class:"notification is-info has-text-centered"},ae={key:0,class:"notification is-warning has-text-centered"},ne={ref:"heading-profile",class:"title is-4"},re={key:0,class:"tag is-warning ml-1"},le=["disabled"],ie=["value"],de=["value"],ue=["disabled"],pe=["value"],me=["value"],ce={class:"field is-size-7-mobile"},fe={class:"block"},we=["disabled"],ve={__name:"Account",setup(ge){const b=E(),{t:y}=I(),c=q("2fauth"),d=j(),u=X(),v=G(),x=H(c.prefix+"returnTo","accounts"),{isLaptop:N}=Z(),n=B(new F({name:d.name,email:d.email,password:""})),r=B(new F({currentPassword:"",password:"",password_confirmation:""})),m=B(new F({password:""}));function S(a){n.put("/user",{returnError:!0}).then(e=>{d.$patch({name:e.data.name,email:e.data.email,isAdmin:e.data.is_admin}),u.success({text:y("notification.profile_saved")})}).catch(e=>{e.response.status===400?u.alert({text:e.response.data.message}):e.response.status!==422&&b.show(e)})}function A(a){r.patch("/user/password",{returnError:!0}).then(e=>{r.password="",r.formPassword="",r.password_confirmation="",u.success({text:e.data.message})}).catch(e=>{e.response.status===400?u.alert({text:e.response.data.message}):e.response.status!==422&&b.show(e)})}function T(a){confirm(y("confirmation.delete_account"))&&m.delete("/user",{returnError:!0}).then(e=>{u.success({text:y("notification.user_account_successfully_deleted")}),v.push({name:"register"})}).catch(e=>{e.response.status===400?u.alert({text:e.response.data.message}):e.response.status!==422&&b.show(e)})}const C=k("heading-profile"),L=k("heading-changePassword"),R=k("heading-deleteAccount"),V=a=>{a&&a.scrollIntoView({behavior:"smooth"})};return z(a=>{!a.name.startsWith("settings.")&&a.name==="login"&&u.clear()}),(a,e)=>{const f=p("FormField"),$=p("FormButtons"),P=p("FormPasswordField"),U=p("ResponsiveWidthWrapper"),D=p("NavigationButton"),K=p("VueFooter"),W=p("StackLayout");return g(),Q(W,null,{header:w(()=>[l(s(O),{tabs:s(Y),"active-tab":"settings.account",onTabSelected:e[0]||(e[0]=t=>s(v).push({name:t}))},null,8,["tabs"])]),content:w(()=>[l(U,null,{default:w(()=>[s(N)&&s(d).preferences.showQuickNavMenus?(g(),_("div",ee,[o("aside",se,[o("ul",te,[o("li",null,[o("button",{onClick:e[1]||(e[1]=t=>V(s(C)))},i(a.$t("heading.profile")),1)]),o("li",null,[o("button",{onClick:e[2]||(e[2]=t=>V(s(L)))},i(a.$t("heading.change_password")),1)]),o("li",null,[o("button",{onClick:e[3]||(e[3]=t=>V(s(R)))},i(a.$t("heading.delete_account")),1)])])])])):h("",!0),s(d).oauth_provider?(g(),_("div",oe,i(a.$t("message.account_linked_to_sso_x_provider",{provider:s(d).oauth_provider})),1)):h("",!0),o("form",{onSubmit:M(S,["prevent"]),onKeydown:e[7]||(e[7]=t=>s(n).onKeydown(t))},[s(c).config.proxyAuth?(g(),_("div",ae,i(a.$t("message.user_account_controlled_by_proxy")+" "+a.$t("message.manage_account_at_proxy_level")),1)):h("",!0),o("h4",ne,[J(i(a.$t("heading.profile"))+" ",1),s(d).isAdmin?(g(),_("span",re,i(a.$t("label.administrator")),1)):h("",!0)],512),o("fieldset",{disabled:s(c).config.proxyAuth||s(d).oauth_provider},[l(f,{modelValue:s(n).name,"onUpdate:modelValue":e[4]||(e[4]=t=>s(n).name=t),fieldName:"name",errorMessage:s(n).errors.get("name"),label:"field.name",maxLength:255,autocomplete:"username",autofocus:""},null,8,["modelValue","errorMessage"]),l(f,{modelValue:s(n).email,"onUpdate:modelValue":e[5]||(e[5]=t=>s(n).email=t),fieldName:"email",errorMessage:s(n).errors.get("email"),inputType:"email",label:"field.email",autocomplete:"email",maxLength:255,autofocus:""},null,8,["modelValue","errorMessage"]),l(f,{modelValue:s(n).password,"onUpdate:modelValue":e[6]||(e[6]=t=>s(n).password=t),fieldName:"password",errorMessage:s(n).errors.get("password"),inputType:"password",label:"field.current_password",autocomplete:"current-password",help:"field.current_password.help"},null,8,["modelValue","errorMessage"]),l($,{isBusy:s(n).isBusy,submitLabel:"label.update"},null,8,["isBusy"])],8,le)],32),o("form",{onSubmit:M(A,["prevent"]),onKeydown:e[11]||(e[11]=t=>s(r).onKeydown(t))},[o("input",{hidden:"",type:"text",name:"name",value:s(n).name,autocomplete:"username"},null,8,ie),o("input",{hidden:"",type:"text",name:"email",value:s(n).email,autocomplete:"email"},null,8,de),o("h4",{ref:"heading-changePassword",class:"title is-4 pt-6"},i(a.$t("heading.change_password")),513),o("fieldset",{disabled:s(c).config.proxyAuth||s(d).oauth_provider},[l(P,{modelValue:s(r).password,"onUpdate:modelValue":e[8]||(e[8]=t=>s(r).password=t),fieldName:"password",errorMessage:s(r).errors.get("password"),idSuffix:"ForUpdate",autocomplete:"new-password",showRules:!0,label:"field.new_password"},nuLine truncated
@@ -0,0 +1 @@
import{u as Q,b as Y,e as f,P as Z,o as x,I as ee,d as I,w as m,a7 as te,f as g,h as n,i as h,j as t,a4 as se,m as s,t as o,p as w,l,F as p,E as L,n as F,k as v,X as ae,D as oe,B as S,$ as ie}from"./app-dvJP63FL.js";import{s as b}from"./shareService-BU7jlLil.js";import{_ as ne}from"./TwofaccountMedia-DzLyeBxh.js";import{a as re}from"./helpers-B2oe4lHy.js";import{U as le}from"./index-BJsmINgd.js";import{C as ce}from"./circle-plus-BM92Iipr.js";import{U as ue}from"./users-CLZI37iw.js";import"./createLucideIcon-DsaEAGzP.js";const he={class:"title"},de={class:"block is-size-7-mobile"},_e={class:"columns is-mobile is-multiline"},fe={class:"column is-narrow"},me={class:"toggle-wrapper has-background-dark p-1"},ge={class:"toggle"},pe={class:"toggle-buttons"},ve=["id","onClick"],Se={class:"pt-2 mb-4"},be={key:0,class:"list-item is-size-6 is-size-7-mobile has-text-grey pt-2"},ke=["onClick","title"],ye={class:"is-block is-family-primary is-size-7 has-text-grey"},we={key:1,class:"list-item is-size-5 is-size-6-mobile"},$e={class:"icon-text"},We={class:"icon"},Ue={class:"is-size-6 is-size-7-mobile has-text-grey pt-2"},ze={key:2,class:"list-item pt-0"},Ne={key:0,class:"is-size-6 is-size-7-mobile has-text-grey pt-2"},Ae={class:"is-size-6 is-size-7-mobile has-text-grey pt-2"},Ce={class:"mt-2 is-size-7 is-pulled-right"},De={__name:"AccountSharing",props:{twofaccountId:[Number,String]},setup(V){const u=V,P=ie(),{t:$}=Q(),T=Y(),U=f(T.items.find(e=>e.id==u.twofaccountId)),k=Z(),W=te("activeScopeRef"),d=f(!1),c=f([]),y=f(""),z=f([]),N=[{id:"ShareWithAll",label:"label.share_with_all"},{id:"NotShared",label:"label.not_shared"},{id:"ShareWithUsers",label:"label.share_with_specific_users"}],i=f("NotShared"),D=S(()=>c.value.filter(e=>e.name.toLowerCase().includes(y.value.toLowerCase()))),A=S(()=>k.enableAllUsersSharingScope?N:N.filter(e=>e.id!="ShareWithAll")),E=S(()=>A.value.find(e=>e.id==i.value).label),M=S(()=>i.value=="ShareWithAll"),X=S(()=>i.value=="ShareWithUsers");x(()=>{d.value=!0,i.value="NotShared",ee.get(u.twofaccountId).then(e=>{U.value=e.data}),b.getShares(u.twofaccountId).then(e=>{k.enableAllUsersSharingScope&&e?.data?.is_shared_with_all?i.value="ShareWithAll":(c.value=re(e?.data?.specific_users),c.value.length>0?i.value="ShareWithUsers":i.value="NotShared")}).finally(()=>{d.value=!1,R(i.value)})});function j(e){confirm($("confirmation.are_you_sure"))===!0&&b.unshareWithUser(u.twofaccountId,e).then(a=>{c.value=c.value.filter(_=>_.id!=e)})}function q(e){(i.value=="NotShared"&&e=="ShareWithUsers"||e=="NotShared"&&i.value=="ShareWithUsers"&&c.value.length==0||confirm($("confirmation.toggle_sharing_setting"))===!0)&&C(e)}function C(e){d.value=!0;let a;switch(e){case"ShareWithAll":a=b.shareWithAll(u.twofaccountId);break;case"NotShared":a=b.unshare(u.twofaccountId);break;case"ShareWithUsers":i.value=="ShareWithAll"?a=b.unshare(u.twofaccountId):a=Promise.resolve(!0);break;default:P.alert({text:$("error.unsupported_sharing_scope")});return}a.then(_=>{i.value=e,e!="ShareWithUsers"&&(c.value=[]),R(e)}).finally(()=>{d.value=!1})}function R(e){const a=z.value.find(_=>_.id=="btn"+e);W.value.style.setProperty("transform",`translateX(${a.offsetLeft}px)`),W.value.textContent=a.textContent}return(e,a)=>{const _=g("RouterLink"),G=g("ResponsiveWidthWrapper"),H=g("NavigationButton"),J=g("VueFooter"),K=g("StackLayout");return n(),I(K,null,{content:m(()=>[h(t(le),null,{default:m(({mode:B})=>[h(G,null,{default:m(()=>[s("h1",he,o(e.$t("heading.sharing_setting")),1),s("div",de,[w(o(e.$t("message.share_account_with_other_users")),1),a[2]||(a[2]=s("br",null,null,-1)),w(" "+o(e.$t("message.shared_account_can_be_viewed_not_full_controlled")),1)]),h(ne,{twofaccount:t(U)},null,8,["twofaccount"]),s("div",_e,[s("div",fe,[s("div",me,[s("div",ge,[s("div",pe,[(n(!0),l(p,null,L(t(A),r=>(n(),l("button",{key:r.id,ref_for:!0,ref_key:"shareButtonRefs",ref:z,id:"btn"+r.id,onClick:O=>q(r.id),class:"button px-3 is-dark"},o(e.$t(r.label)),9,ve))),128))]),s("label",{ref_key:"activeScopeRef",ref:W,class:F([{"is-black":t(i)=="NotShared","is-link":t(i)!="NotShared","is-loading":t(d)},"toggle-active button px-3"])},o(e.$t(t(E))),3)])])])]),t(d)==!1?(n(),l(p,{key:0},[t(X)?(n(),l(p,{key:0},[s("div",Se,[h(_,{class:"is-link",to:{name:"shareAccount",params:{twofaccountId:u.twofaccountId}}},{default:m(()=>[h(t(ce),{class:"mr-2"}),w(" "+o(e.$t("link.add_users")),1)]),_:1},8,["to"])]),t(c).length==0?(n(),l("div",be,o(e.$t("message.add_your_first_user_to_share_this_account_with")),1)):v("",!0),t(c).length>0?(n(),l(p,{key:1},[t(c).length>5?(n(),I(t(ae),{key:0,keyword:t(y),"onUpdate:keyword":a[0]||(a[0]=r=>oe(y)?y.value=r:null),hasNoBackground:!0,isSmall:!0},null,8,["keyword"])):v("",!0),(n(!0),l(p,null,L(t(D),r=>(n(),l("div",{key:r.id,class:"list-item is-size-5 is-size-6-mobile"},[w(o(r.name)+" ",1),s("button",{type:"button",class:F(["button tag is-pulled-right",B=="dark"?"is-dark":"is-white"]),onClick:O=>j(r.id),title:e.$t("tooltip.revoke")},o(e.$t("label.revoke")),11,ke),s("Line truncated
+1
View File
@@ -0,0 +1 @@
import{f as N,h as a,d as M,w as u,i as l,m as i,t as c,j as e,l as d,F as q,E as ue,n as p,k as y,p as U,I as Z,J as qe,e as x,K as Ve,x as ce,L as ve,g as pe,a as Oe,M as De,C as Te,u as Le,N as Re,b as Fe,O as He,P as Ke,v as re,o as je,Q as J,$ as Qe,R as be,S as Xe,D as L,T as R,y as de,U as We,q as Y,H as F,z as we,V as $e,W as Ze,X as Je,Y as Ye,Z as et,_ as tt,a0 as st,a1 as ot,B as nt}from"./app-dvJP63FL.js";import{s as it}from"./shareService-BU7jlLil.js";import{U as ee}from"./index-BJsmINgd.js";import{c as A}from"./createLucideIcon-DsaEAGzP.js";import{T as Ue,M as Me,u as at,m as lt}from"./useSortable-6hRbxhTj.js";import{u as rt}from"./bus-ChE1sp8V.js";import{C as dt,a as ut}from"./circle-x-AvUNZzwX.js";import{U as ct}from"./users-CLZI37iw.js";import{Q as Se}from"./qr-code-eSL1bq0j.js";import{X as pt}from"./x-DQVIq0xP.js";const ht=[["path",{d:"m3 16 4 4 4-4",key:"1co6wj"}],["path",{d:"M7 20V4",key:"1yoxec"}],["path",{d:"M20 8h-5",key:"1vsyxs"}],["path",{d:"M15 10V6.5a2.5 2.5 0 0 1 5 0V10",key:"ag13bf"}],["path",{d:"M15 14h5l-5 6h5",key:"ur5jdg"}]],ft=A("arrow-down-a-z",ht);const mt=[["path",{d:"m3 8 4-4 4 4",key:"11wl7u"}],["path",{d:"M7 4v16",key:"1glfcx"}],["path",{d:"M20 8h-5",key:"1vsyxs"}],["path",{d:"M15 10V6.5a2.5 2.5 0 0 1 5 0V10",key:"ag13bf"}],["path",{d:"M15 14h5l-5 6h5",key:"ur5jdg"}]],kt=A("arrow-up-a-z",mt);const yt=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M17 12h.01",key:"1m0b6t"}],["path",{d:"M12 12h.01",key:"1mp3jc"}],["path",{d:"M7 12h.01",key:"eqddd0"}]],gt=A("circle-ellipsis",yt);const _t=[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],vt=A("eye-off",_t);const bt=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],wt=A("eye",bt);const $t=[["path",{d:"M2 9V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H20a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-1",key:"fm4g5t"}],["path",{d:"M2 13h10",key:"pgb2dq"}],["path",{d:"m9 16 3-3-3-3",key:"6m91ic"}]],Mt=A("folder-input",$t);const St=[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]],Ct=A("history",St);const xt=[["path",{d:"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z",key:"1a0edw"}],["path",{d:"M12 22V12",key:"d0xqtd"}],["polyline",{points:"3.29 7 12 12 20.71 7",key:"ousv84"}],["path",{d:"m7.5 4.27 9 5.15",key:"1c824w"}]],At=A("package",xt);const Ot=[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]],Dt=A("pencil",Ot);const Ut=[["path",{d:"M17 12v4a1 1 0 0 1-1 1h-4",key:"uk4fdo"}],["path",{d:"M17 3h2a2 2 0 0 1 2 2v2",key:"4qcy5o"}],["path",{d:"M17 8V7",key:"q2g9wo"}],["path",{d:"M21 17v2a2 2 0 0 1-2 2h-2",key:"6vwrx8"}],["path",{d:"M3 7V5a2 2 0 0 1 2-2h2",key:"aa7l1z"}],["path",{d:"M7 17h.01",key:"19xn7k"}],["path",{d:"M7 21H5a2 2 0 0 1-2-2v-2",key:"ioqczr"}],["rect",{x:"7",y:"7",width:"5",height:"5",rx:"1",key:"m9kyts"}]],It=A("scan-qr-code",Ut);const Gt=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]],Et=A("square-check",Gt);const Nt=[["path",{d:"m16 11 2 2 4-4",key:"9rsbq5"}],["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],zt=A("user-check",Nt);const Bt=[["path",{d:"M11.5 15H7a4 4 0 0 0-4 4v2",key:"15lzij"}],["path",{d:"M21.378 16.626a1 1 0 0 0-3.004-3.004l-4.01 4.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z",key:"1817ys"}],["circle",{cx:"10",cy:"7",r:"4",key:"e45bow"}]],Ce=A("user-pen",Bt);const Pt=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]],xe=A("user-plus",Pt);const qt=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"17",x2:"22",y1:"8",y2:"13",key:"3nzzx3"}],["line",{x1:"22",x2:"17",y1:"8",y2:"13",key:"1swrse"}]],Vt=A("user-x",qt),Tt={class:"columns is-centered is-multiline m-0 mt-6"},Lt={class:"column is-full has-text-centered"},Rt={class:"column is-one-third-tablet is-one-quarter-desktop is-one-quarter-widescreen is-one-quarter-fullhd"},Ft={class:"columns is-multiline"},Ht={key:0,class:"column is-full"},Kt=["onClick"],jt=Line truncated
+1
View File
@@ -0,0 +1 @@
import{ae as se,P as B,h as d,l as p,m as e,n as T,j as t,t as a,p as h,k as b,d as N,i as o,e as g,C as te,u as ne,a as ae,a8 as le,af as oe,o as ie,w as k,M as re,f as _,a7 as E,a4 as z,F as de,E as ue,ak as ce,$ as pe}from"./app-dvJP63FL.js";import{t as he}from"./tabs-BVx9tg1F.js";import{u as me}from"./appSettingsUpdater-D1Bq_3WB.js";import{C as fe}from"./check-CPGWPXZa.js";import{X as _e}from"./x-DQVIq0xP.js";import{_ as ge}from"./CopyButton-CgxgBp0c.js";import{u as be}from"./breakpoints-CyLcIEOu.js";import{c as ke}from"./createLucideIcon-DsaEAGzP.js";import{E as U}from"./external-link-CqpXNovN.js";const ve=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],ye=ke("send",ve),V=se("web"),I={getSystemInfos(u={}){return V.get("system/infos",{...u})},getLastRelease(u={}){return V.get("system/latestRelease",{...u})},sendTestEmail(u={}){return V.post("system/test-email",{},{...u})},clearCache(u={}){return V.get("system/clear-cache",{...u})},optimize(u={}){return V.get("system/optimize",{...u})}},$e={class:"columns is-mobile is-vcentered"},Se={class:"column is-narrow"},Ce={class:"column has-text-grey"},Ee={key:0,class:"mt-2 has-text-warning"},Ve={class:"is-size-7 is-link",href:"https://github.com/Bubka/2FAuth/releases"},we={key:1},Ie={key:2},Re={__name:"VersionChecker",setup(u){const v=B(),m=g(!1),c=g();async function w(){m.value=!0,c.value=void 0,await I.getLastRelease({returnError:!0}).then(r=>{v.latestRelease=r.data.newRelease,c.value=r.data.newRelease===null?null:r.data.newRelease===!1}).catch(()=>{c.value=null}),m.value=!1}return(r,i)=>(d(),p("div",$e,[e("div",Se,[e("button",{type:"button",class:T([t(m)?"is-loading":"","button is-link is-rounded is-small"]),onClick:w},a(r.$t("label.check_now")),3)]),e("div",Ce,[t(v).latestRelease?(d(),p("span",Ee,[i[0]||(i[0]=e("span",{class:"release-flag"},null,-1)),h(a(r.$t("message.x_is_available",{version:t(v).latestRelease}))+" ",1),e("a",Ve,a(r.$t("link.view_on_github")),1)])):b("",!0),t(c)?(d(),p("span",we,[t(c)?(d(),N(t(fe),{key:0,class:"mr-1 has-text-success inline"})):b("",!0),h(a(r.$t("message.you_are_up_to_date")),1)])):t(c)===null?(d(),p("span",Ie,[o(t(_e),{class:"mr-1 has-text-danger inline"}),h(a(r.$t("error.check_failed_try_later")),1)])):b("",!0)])]))}},Fe={key:0,class:"pr-5 settings-menu"},Ue={class:"menu"},Te={class:"menu-list"},Ne={class:"field"},De={class:"label",for:"btnTestEmail"},Le={class:"help"},ze={class:"help"},Be={class:"is-family-code has-text-info"},Ae={class:"columns is-mobile is-vcentered"},We={class:"column is-narrow"},Me={class:"icon is-small"},Pe={key:0,class:"about-debug box is-family-monospace is-size-7 is-shadowless"},je={class:"field"},He={class:"label",for:"lnkHealthCheck"},Qe={class:"help"},Xe={class:"field mb-5"},qe={class:"help ml-5"},Ge={class:"field mt-4"},Je={id:"lnkSharingDoc",class:"is-link",target:"_blank",href:"https://docs.2fauth.app/usage/2fa-sharing/"},Ke={class:"help"},Oe={class:"field mt-4"},Ye={id:"lnkIconsDoc",class:"is-link",target:"_blank",href:"https://docs.2fauth.app/usage/icons/"},Ze={class:"field"},xe={for:"btnClearCache",class:"label"},es={class:"help"},ss={class:"field mb-5 is-grouped"},ts={class:"control"},ns={class:"field"},as={for:"btnCopyEnvVars",class:"label"},ls={key:1,class:"about-debug box is-family-monospace is-size-7 is-shadowless"},os=["value"],is={class:"has-text-grey"},rs={key:2,class:"about-debug box is-family-monospace is-size-7 has-text-warning-dark is-shadowless"},bs={__name:"AppSetup",setup(u){const v=te(),{t:m}=ne(),c=re("2fauth"),w=ae(),r=pe(),i=B(),A=le(c.prefix+"returnTo","accounts"),{isLaptop:W}=be(),y=g(),D=g(null),R=g(!1),$=g(null),F=g(!1),M=c.config.subdirectory+"/up",P=location.hostname+c.config.subdirectory+"/up",j=E("heading-general"),H=E("heading-sharing"),Q=E("heading-storage"),X=E("heading-security"),q=E("heading-environment"),S=s=>{s&&s.scrollIntoView({behavior:"smooth"})};function G(){R.value=!0,$.value=null,I.sendTestEmail({returnError:!0}).then(s=>{r.success({text:m("notification.test_email_sent")})}).catch(s=>{s.response.status===424?$.value=s.response.data.details:v.show(s)}).finally(()=>{R.value=!1})}function J(){F.value=!0,I.clearCache().then(s=>{r.success({text:m("notification.cache_cleared")})}).finally(()=>{F.value=!1})}async function C(s,n){const{error:f}=await me(s,n);f==null&&r.success({text:m("notification.setting_saved")})}return oe(s=>{s.name.startsWith("admin.")||r.clear()}),ie(async()=>{await i.fetch(),I.getSystemInfos({returnError:!0}).then(s=>{y.value=s.data.common}).catch(()=>{y.value=null})}),(s,n)=>{const f=_("FormCheckbox"),K=_("i18n-t"),O=_("FormFieldError"),Y=_("ResponsiveWidthWrapper"),Z=_("NavigationButton"),x=_("VueFooter"),ee=_("StackLayout");return d(),N(ee,null,{header:k(()=>[o(t(ce),{tabs:t(he),"active-tab":"admin.appSetup",onTabSelected:n[0]||(n[0]=l=>("router"in s?s.router:t(z)).pLine truncated
+1
View File
@@ -0,0 +1 @@
import{C as v,u as w,P as N,a8 as O,af as F,o as L,d as U,w as u,M as C,f as r,h as I,i as a,j as l,a4 as S,m,t as V,ak as W,e as $,al as B,$ as E}from"./app-dvJP63FL.js";import{t as M}from"./tabs-BVx9tg1F.js";import{u as P}from"./appSettingsUpdater-D1Bq_3WB.js";const j={class:"title is-4"},A={class:"title is-4 pt-4"},z={__name:"Auth",setup(T){const R=v(),{t:f}=w(),y=C("2fauth"),p=E(),s=N(),_=O(y.prefix+"returnTo","accounts"),d=$({restrictList:null,restrictRule:null});async function b(o,e){d.value[o]=null,e==""?B.delete(o,{returnError:!0}).then(i=>{s[o]="",p.success({type:"is-success",text:f("notification.setting_saved")})}).catch(i=>{i.response.status!==404&&R.show(i)}):n(o,e)}async function n(o,e){const{error:i}=await P(o,e,!0);i!=null&&Object.prototype.hasOwnProperty.call(d.value,o)?d.value[o]=i.response.data.message:p.success({text:f("notification.setting_saved")})}return F(o=>{o.name.startsWith("admin.")||p.clear()}),L(async()=>{await s.fetch()}),(o,e)=>{const i=r("FormCheckbox"),g=r("FormField"),c=r("FormWrapper"),h=r("NavigationButton"),D=r("VueFooter"),k=r("StackLayout");return I(),U(k,null,{header:u(()=>[a(l(W),{tabs:l(M),"active-tab":"admin.auth",onTabSelected:e[0]||(e[0]=t=>("router"in o?o.router:l(S)).push({name:t}))},null,8,["tabs"])]),content:u(()=>[a(c,null,{default:u(()=>[m("form",null,[m("h4",j,V(o.$t("heading.single_sign_on")),1),a(i,{modelValue:l(s).enableSso,"onUpdate:modelValue":[e[1]||(e[1]=t=>l(s).enableSso=t),e[2]||(e[2]=t=>n("enableSso",t))],fieldName:"enableSso",label:"field.enable_sso",help:"field.enable_sso.help"},null,8,["modelValue"]),a(i,{modelValue:l(s).useSsoOnly,"onUpdate:modelValue":[e[3]||(e[3]=t=>l(s).useSsoOnly=t),e[4]||(e[4]=t=>n("useSsoOnly",t))],fieldName:"useSsoOnly",label:"field.use_sso_only",help:"field.use_sso_only.help",isDisabled:!l(s).enableSso,isIndented:!0},null,8,["modelValue","isDisabled"]),a(i,{modelValue:l(s).allowPatWhileSsoOnly,"onUpdate:modelValue":[e[5]||(e[5]=t=>l(s).allowPatWhileSsoOnly=t),e[6]||(e[6]=t=>n("allowPatWhileSsoOnly",t))],fieldName:"allowPatWhileSsoOnly",label:"field.allow_pat_in_sso_only",help:"field.allow_pat_in_sso_only.help",isDisabled:!l(s).useSsoOnly,isIndented:!0},null,8,["modelValue","isDisabled"]),m("h4",A,V(o.$t("heading.registrations")),1),a(i,{modelValue:l(s).restrictRegistration,"onUpdate:modelValue":[e[7]||(e[7]=t=>l(s).restrictRegistration=t),e[8]||(e[8]=t=>n("restrictRegistration",t))],fieldName:"restrictRegistration",isDisabled:l(s).disableRegistration,label:"field.restrict_registration",help:"field.restrict_registration.help"},null,8,["modelValue","isDisabled"]),a(g,{modelValue:l(s).restrictList,"onUpdate:modelValue":e[9]||(e[9]=t=>l(s).restrictList=t),"onChange:modelValue":e[10]||(e[10]=t=>b("restrictList",t)),errorMessage:l(d).restrictList,fieldName:"restrictList",isDisabled:!l(s).restrictRegistration||l(s).disableRegistration,label:"field.restrict_list",help:"field.restrict_list.help",isIndented:!0},null,8,["modelValue","errorMessage","isDisabled"]),a(g,{modelValue:l(s).restrictRule,"onUpdate:modelValue":e[11]||(e[11]=t=>l(s).restrictRule=t),"onChange:modelValue":e[12]||(e[12]=t=>b("restrictRule",t)),errorMessage:l(d).restrictRule,fieldName:"restrictRule",isDisabled:!l(s).restrictRegistration||l(s).disableRegistration,label:"field.restrict_rule",help:"field.restrict_rule.help",isIndented:!0,leftIcon:"Slash",rightIcon:"Slash"},null,8,["modelValue","errorMessage","isDisabled"]),a(i,{modelValue:l(s).disableRegistration,"onUpdate:modelValue":[e[13]||(e[13]=t=>l(s).disableRegistration=t),e[14]||(e[14]=t=>n("disableRegistration",t))],fieldName:"disableRegistration",label:"field.disable_registration",help:"field.disable_registration.help"},null,8,["modelValue"]),a(i,{modelValue:l(s).keepSsoRegistrationEnabled,"onUpdate:modelValue":[e[15]||(e[15]=t=>l(s).keepSsoRegistrationEnabled=t),e[16]||(e[16]=t=>n("keepSsoRegistrationEnabled",t))],fieldName:"keepSsoRegistrationEnabled",isDisabled:!l(s).enableSso||!l(s).disableRegistration,label:"field.keep_sso_registration_enabled",help:"field.keep_sso_registration_enabled.help",isIndented:!0},null,8,["modelValue","isDisabled"])])]),_:1})]),footer:u(()=>[a(D,null,{default:u(()=>[a(h,{action:"close",onClosed:e[17]||(e[17]=t=>("router"in o?o.router:l(S)).push({name:l(_)})),"current-page-title":o.$t("title.admin.auth")},null,8,["current-page-title"])]),_:1})]),_:1})}}};export{z as default};
+3
View File
@@ -0,0 +1,3 @@
import{s as To,e as ae,v as Be,o as Rr,c as $o,l as ge,m as W,x as So,y as Vt,z as Fr,A as Po,B as Ht,h as he,C as Eo,u as Oo,r as Mo,i as de,w as Nt,j as K,D as _r,F as Ao,E as xo,G as ko,k as Tr,d as Do,f as lt,g as jo,t as Ee,n as $r,H as Ro,$ as Fo}from"./app-dvJP63FL.js";import{F as Io}from"./Form-ZbAUhXmz.js";import{_ as Wo}from"./QrContentDisplay-DiIjf7a_.js";import{u as Uo}from"./bus-ChE1sp8V.js";import{U as Lo}from"./index-BJsmINgd.js";import{c as vt}from"./createLucideIcon-DsaEAGzP.js";import"./external-link-CqpXNovN.js";const Ho=[["path",{d:"M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z",key:"18u6gg"}],["circle",{cx:"12",cy:"13",r:"3",key:"1vg3eu"}]],No=vt("camera",Ho);const Vo=[["rect",{width:"18",height:"11",x:"3",y:"11",rx:"2",ry:"2",key:"1w4ew1"}],["path",{d:"M7 11V7a5 5 0 0 1 10 0v4",key:"fwvmzm"}]],Bo=vt("lock",Vo);const zo=[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]],qo=vt("star",zo);const Go=[["path",{d:"M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196",key:"w8jjjt"}],["path",{d:"M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2",key:"1xawa7"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],Jo=vt("video-off",Go);var Ir=(r,i,a)=>{if(!i.has(r))throw TypeError("Cannot "+a)},Sr=(r,i,a)=>(Ir(r,i,"read from private field"),a?a.call(r):i.get(r)),Yo=(r,i,a)=>{if(i.has(r))throw TypeError("Cannot add the same private member more than once");i instanceof WeakSet?i.add(r):i.set(r,a)},Qo=(r,i,a,c)=>(Ir(r,i,"write to private field"),i.set(r,a),a);const Wr=[["aztec","Aztec"],["code_128","Code128"],["code_39","Code39"],["code_93","Code93"],["codabar","Codabar"],["databar","DataBar"],["databar_expanded","DataBarExpanded"],["data_matrix","DataMatrix"],["dx_film_edge","DXFilmEdge"],["ean_13","EAN-13"],["ean_8","EAN-8"],["itf","ITF"],["maxi_code","MaxiCode"],["micro_qr_code","MicroQRCode"],["pdf417","PDF417"],["qr_code","QRCode"],["rm_qr_code","rMQRCode"],["upc_a","UPC-A"],["upc_e","UPC-E"],["linear_codes","Linear-Codes"],["matrix_codes","Matrix-Codes"]],Xo=[...Wr,["unknown"]].map(r=>r[0]),ft=new Map(Wr);function Ko(r){for(const[i,a]of ft)if(r===a)return i;return"unknown"}function Zo(r){if(Ur(r))return{width:r.naturalWidth,height:r.naturalHeight};if(Lr(r))return{width:r.width.baseVal.value,height:r.height.baseVal.value};if(Hr(r))return{width:r.videoWidth,height:r.videoHeight};if(Vr(r))return{width:r.width,height:r.height};if(zr(r))return{width:r.displayWidth,height:r.displayHeight};if(Nr(r))return{width:r.width,height:r.height};if(Br(r))return{width:r.width,height:r.height};throw new TypeError("The provided value is not of type '(Blob or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or ImageData or OffscreenCanvas or SVGImageElement or VideoFrame)'.")}function Ur(r){try{return r instanceof HTMLImageElement}catch{return!1}}function Lr(r){try{return r instanceof SVGImageElement}catch{return!1}}function Hr(r){try{return r instanceof HTMLVideoElement}catch{return!1}}function Nr(r){try{return r instanceof HTMLCanvasElement}catch{return!1}}function Vr(r){try{return r instanceof ImageBitmap}catch{return!1}}function Br(r){try{return r instanceof OffscreenCanvas}catch{return!1}}function zr(r){try{return r instanceof VideoFrame}catch{return!1}}function qr(r){try{return r instanceof Blob}catch{return!1}}function ei(r){try{return r instanceof ImageData}catch{return!1}}function ti(r,i){try{const a=new OffscreenCanvas(r,i);if(a.getContext("2d")instanceof OffscreenCanvasRenderingContext2D)return a;throw void 0}catch{const c=document.createElement("canvas");return c.width=r,c.height=i,c}}async function Gr(r){if(Ur(r)&&!await oi(r))throw new DOMException("Failed to load or decode HTMLImageElement.","InvalidStateError");if(Lr(r)&&!await ii(r))throw new DOMException("Failed to load or decode SVGImageElement.","InvalidStateError");if(zr(r)&&si(r))throw new DOMException("VideoFrame is closed.","InvalidStateError");if(Hr(r)&&(r.readyState===0||r.readyState===1))throw new DOMException("Invalid element or state.","InvalidStateError");if(Vr(r)&&ui(r))throw new DOMException("The image source is detached.","InvalidStateError");const{width:i,height:a}=Zo(r);if(i===0||a===0)return null;const c=ti(i,a).getContext("2d");c.drawImage(r,0,0);try{return c.getImageData(0,0,i,a)}catch{throw new DOMException("Source would taint origin.","SecurityError")}}async function ri(r){let i;try{if(globalThis.createImageBitmap)i=await createImageBitmap(r);else if(globalThis.Image){i=new Image;let a="";try{a=URL.createObjectURL(r),i.src=a,aLine truncated
`+s.replace(/^Error(:[^\n]*)?\n/,""))});return n.prototype=Object.create(e.prototype),n.prototype.constructor=n,n.prototype.toString=function(){return this.message===void 0?this.name:`${this.name}: ${this.message}`},n},rr,nr=e=>{var t=hr(e),n=Q(t);return ye(t),n},it=(e,t)=>{var n=[],o={};function s(u){if(!o[u]&&!Se[u]){if(et[u]){et[u].forEach(s);return}n.push(u),o[u]=!0}}throw t.forEach(s),new rr(`${e}: `+n.map(nr).join([", "]))},Qn=(e,t,n,o,s,u,l,d,v,w,_,E,O)=>{_=Q(_),u=oe(s,u),d&&(d=oe(l,d)),w&&(w=oe(v,w)),O=oe(E,O);var A=Ln(_);At(A,function(){it(`Cannot construct ${_} due to unbound types`,[o])}),Pe([e,t,n],o?[o]:[],function(H){H=H[0];var z,F;o?(z=H.registeredClass,F=z.instancePrototype):F=nt.prototype;var X=He(_,function(){if(Object.getPrototypeOf(this)!==g)throw new Me("Use 'new' to construct "+_);if(S.constructor_body===void 0)throw new Me(_+" has no accessible constructor");var Cr=S.constructor_body[arguments.length];if(Cr===void 0)throw new Me(`Tried to invoke ctor of ${_} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(S.constructor_body).toString()}) parameters instead!`);return Cr.apply(this,arguments)}),g=Object.create(F,{constructor:{value:X}});X.prototype=g;var S=new Hn(_,X,g,O,z,u,d,w);if(S.baseClass){var q,Y;(Y=(q=S.baseClass).__derivedClasses)!==null&&Y!==void 0||(q.__derivedClasses=[]),S.baseClass.__derivedClasses.push(S)}var Ae=new at(_,S,!0,!1,!1),ut=new at(_+"*",S,!1,!1,!1),br=new at(_+" const*",S,!1,!0,!1);return Xt[e]={pointerType:ut,constPointerType:br},er(A,X),[Ae,ut,br]})},kt=(e,t)=>{for(var n=[],o=0;o<e;o++)n.push(M[t+o*4>>2]);return n};function Xn(e){for(var t=1;t<e.length;++t)if(e[t]!==null&&e[t].destructorFunction===void 0)return!0;return!1}function Dt(e,t,n,o,s,u){var l=t.length;l<2&&j("argTypes array size mismatch! Must at least get return value and 'this' types!");var d=t[1]!==null&&n!==null,v=Xn(t),w=t[0].name!=="void",_=l-2,E=new Array(_),O=[],A=[],H=function(){arguments.length!==_&&j(`function ${e} called with ${arguments.length} arguments, expected ${_}`),A.length=0;var z;O.length=d?2:1,O[0]=s,d&&(z=t[1].toWireType(A,this),O[1]=z);for(var F=0;F<_;++F)E[F]=t[F+2].toWireType(A,arguments[F]),O.push(E[F]);var X=o.apply(null,O);function g(S){if(v)St(A);else for(var q=d?1:2;q<t.length;q++){var Y=q===1?z:E[q-2];t[q].destructorFunction!==null&&t[q].destructorFunction(Y)}if(w)return t[0].fromWireType(S)}return g(X)};return He(e,H)}var Kn=(e,t,n,o,s,u)=>{var l=kt(t,n);s=oe(o,s),Pe([],[e],function(d){d=d[0];var v=`constructor ${d.name}`;if(d.registeredClass.constructor_body===void 0&&(d.registeredClass.constructor_body=[]),d.registeredClass.constructor_body[t-1]!==void 0)throw new Me(`Cannot register multiple constructors with identical number of parameters (${t-1}) for class '${d.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`);return d.registeredClass.constructor_body[t-1]=()=>{it(`Cannot construct ${d.name} due to unbound types`,l)},Pe([],l,w=>(w.splice(1,0,null),d.registeredClass.constructor_body[t-1]=Dt(v,w,null,s,u),[])),[]})},ar=e=>{e=e.trim();const t=e.indexOf("(");return t!==-1?e.substr(0,t):e},Zn=(e,t,n,o,s,u,l,d,v)=>{var w=kt(n,o);t=Q(t),t=ar(t),u=oe(s,u),Pe([],[e],function(_){_=_[0];var E=`${_.name}.${t}`;t.startsWith("@@")&&(t=Symbol[t.substring(2)]),d&&_.registeredClass.pureVirtualFunctions.push(t);function O(){it(`Cannot call ${E} due to unbound types`,w)}var A=_.registeredClass.instancePrototype,H=A[t];return H===void 0||H.overloadTable===void 0&&H.className!==_.name&&H.argCount===n-2?(O.argCount=n-2,O.className=_.name,A[t]=O):(Kt(A,t,E),A[t].overloadTable[n-2]=O),Pe([],w,function(z){var F=Dt(E,z,_,u,l);return A[t].overloadTable===void 0?(F.argCount=n-2,A[t]=F):A[t].overloadTable[n-2]=F,[]}),[]})};function ea(){Object.assign(or.prototype,{get(e){return this.allocated[e]},has(e){return this.allocated[e]!==void 0},allocate(e){var t=this.freelist.pop()||this.allocated.length;return this.allocated[t]=e,t},free(e){this.allocated[e]=void 0,this.freelist.push(e)}})}function or(){this.allocated=[void 0],this.freelist=[]}var ne=new or,jt=e=>{e>=ne.reserved&&--ne.get(e).refcount===0&&ne.free(e)},ta=()=>{for(var e=0,t=ne.reserved;t<ne.allocated.length;++t)ne.allocated[t]!==void 0&&++e;return e},ra=()=>{ne.allocated.push({value:void 0},{value:null},{value:!0},{value:!1}),ne.reserved=ne.allocated.length,a.count_emval_handles=ta},me={toValue:e=>(e||j("Cannot use deleted val. handle = "+e),ne.get(e).value),toHandle:e=>{switch(e){case void 0:return 1;case null:return 2;case!0:return 3;case!1:return 4;default:return ne.allocate({refcount:1,value:e})}}},na=(e,t)=>{t=Q(t),ue(e,{name:t,fromWireType:n=>{var o=me.toValue(n);return jt(n),o},toWireType:(n,o)=>me.toHandle(o),argPackAdvance:le,readValueFromPointer:Pt,destructorFunction:null})},aa=(e,t,n)=>{switch(t){case 1:return n?function(o){return this.fromWireType(I[o>>0])}:function(o){return this.fromWireType(U[o>>0])};case 2:return n?function(o Line truncated
`,"%p":g=>g.tm_hour>=0&&g.tm_hour<12?"AM":"PM","%S":g=>O(g.tm_sec,2),"%t":()=>" ","%u":g=>g.tm_wday||7,"%U":g=>{var S=g.tm_yday+7-g.tm_wday;return O(Math.floor(S/7),2)},"%V":g=>{var S=Math.floor((g.tm_yday+7-(g.tm_wday+6)%7)/7);if((g.tm_wday+371-g.tm_yday-2)%7<=2&&S++,S){if(S==53){var q=(g.tm_wday+371-g.tm_yday)%7;q!=4&&(q!=3||!st(g.tm_year))&&(S=1)}}else{S=52;var Y=(g.tm_wday+7-g.tm_yday-1)%7;(Y==4||Y==5&&st(g.tm_year%400-1))&&S++}return O(S,2)},"%w":g=>g.tm_wday,"%W":g=>{var S=g.tm_yday+7-(g.tm_wday+6)%7;return O(Math.floor(S/7),2)},"%y":g=>(g.tm_year+1900).toString().substring(2),"%Y":g=>g.tm_year+1900,"%z":g=>{var S=g.tm_gmtoff,q=S>=0;return S=Math.abs(S)/60,S=S/60*100+S%60,(q?"+":"-")+("0000"+S).slice(-4)},"%Z":g=>g.tm_zone,"%%":()=>"%"};l=l.replace(/%%/g,"\0\0");for(var v in F)l.includes(v)&&(l=l.replace(new RegExp(v,"g"),F[v](u)));l=l.replace(/\0\0/g,"%");var X=Qa(l);return X.length>t?0:(Xa(X,e),X.length-1)},Za=(e,t,n,o,s)=>Ka(e,t,n,o);qt=a.InternalError=class extends Error{constructor(e){super(e),this.name="InternalError"}},Sn(),Me=a.BindingError=class extends Error{constructor(e){super(e),this.name="BindingError"}},In(),Dn(),zn(),rr=a.UnboundTypeError=Yn(Error,"UnboundTypeError"),ea(),ra();var eo={s:pn,u:vn,b:yn,g:gn,q:wn,J:bn,f:Cn,V:_n,d:mn,da:Tn,Q:$n,_:En,ca:Qn,ba:Kn,w:Zn,Y:na,x:oa,h:ia,L:ca,M:ua,t:da,o:fa,K:va,C:_a,A:Ta,ea:$a,$:Sa,R:Pa,ha:jt,fa:Ma,Z:ja,N:Ra,O:Fa,aa:Ia,B:Wa,X:Ua,W:Na,T:za,U:qa,E:yo,D:oo,F:mo,n:go,a:to,e:so,m:ao,k:uo,H:po,v:fo,G:vo,z:bo,P:_o,l:co,j:io,c:no,p:ro,I:ho,r:wo,i:lo,y:Co,ga:Ga,S:Za},J=hn(),ye=a._free=e=>(ye=a._free=J.ka)(e),Lt=a._malloc=e=>(Lt=a._malloc=J.la)(e),hr=e=>(hr=J.na)(e),L=(e,t)=>(L=J.oa)(e,t),Ve=e=>(Ve=J.pa)(e),V=()=>(V=J.qa)(),B=e=>(B=J.ra)(e),pr=e=>(pr=J.sa)(e),vr=e=>(vr=J.ta)(e),mr=(e,t,n)=>(mr=J.ua)(e,t,n),yr=e=>(yr=J.va)(e);a.dynCall_viijii=(e,t,n,o,s,u,l)=>(a.dynCall_viijii=J.wa)(e,t,n,o,s,u,l);var gr=a.dynCall_jiiii=(e,t,n,o,s)=>(gr=a.dynCall_jiiii=J.xa)(e,t,n,o,s);a.dynCall_iiiiij=(e,t,n,o,s,u,l)=>(a.dynCall_iiiiij=J.ya)(e,t,n,o,s,u,l),a.dynCall_iiiiijj=(e,t,n,o,s,u,l,d,v)=>(a.dynCall_iiiiijj=J.za)(e,t,n,o,s,u,l,d,v),a.dynCall_iiiiiijj=(e,t,n,o,s,u,l,d,v,w)=>(a.dynCall_iiiiiijj=J.Aa)(e,t,n,o,s,u,l,d,v,w);function to(e,t){var n=V();try{return N(e)(t)}catch(o){if(B(n),o!==o+0)throw o;L(1,0)}}function ro(e,t,n,o){var s=V();try{N(e)(t,n,o)}catch(u){if(B(s),u!==u+0)throw u;L(1,0)}}function no(e,t,n){var o=V();try{N(e)(t,n)}catch(s){if(B(o),s!==s+0)throw s;L(1,0)}}function ao(e,t,n,o){var s=V();try{return N(e)(t,n,o)}catch(u){if(B(s),u!==u+0)throw u;L(1,0)}}function oo(e,t,n,o,s){var u=V();try{return N(e)(t,n,o,s)}catch(l){if(B(u),l!==l+0)throw l;L(1,0)}}function io(e,t){var n=V();try{N(e)(t)}catch(o){if(B(n),o!==o+0)throw o;L(1,0)}}function so(e,t,n){var o=V();try{return N(e)(t,n)}catch(s){if(B(o),s!==s+0)throw s;L(1,0)}}function co(e){var t=V();try{N(e)()}catch(n){if(B(t),n!==n+0)throw n;L(1,0)}}function uo(e,t,n,o,s){var u=V();try{return N(e)(t,n,o,s)}catch(l){if(B(u),l!==l+0)throw l;L(1,0)}}function lo(e,t,n,o,s,u,l,d,v,w,_){var E=V();try{N(e)(t,n,o,s,u,l,d,v,w,_)}catch(O){if(B(E),O!==O+0)throw O;L(1,0)}}function fo(e,t,n,o,s,u,l){var d=V();try{return N(e)(t,n,o,s,u,l)}catch(v){if(B(d),v!==v+0)throw v;L(1,0)}}function ho(e,t,n,o,s){var u=V();try{N(e)(t,n,o,s)}catch(l){if(B(u),l!==l+0)throw l;L(1,0)}}function po(e,t,n,o,s,u){var l=V();try{return N(e)(t,n,o,s,u)}catch(d){if(B(l),d!==d+0)throw d;L(1,0)}}function vo(e,t,n,o,s,u,l,d){var v=V();try{return N(e)(t,n,o,s,u,l,d)}catch(w){if(B(v),w!==w+0)throw w;L(1,0)}}function mo(e,t,n,o){var s=V();try{return N(e)(t,n,o)}catch(u){if(B(s),u!==u+0)throw u;L(1,0)}}function yo(e,t,n,o){var s=V();try{return N(e)(t,n,o)}catch(u){if(B(s),u!==u+0)throw u;L(1,0)}}function go(e){var t=V();try{return N(e)()}catch(n){if(B(t),n!==n+0)throw n;L(1,0)}}function wo(e,t,n,o,s,u,l,d){var v=V();try{N(e)(t,n,o,s,u,l,d)}catch(w){if(B(v),w!==w+0)throw w;L(1,0)}}function bo(e,t,n,o,s,u,l,d,v,w,_,E){var O=V();try{return N(e)(t,n,o,s,u,l,d,v,w,_,E)}catch(A){if(B(O),A!==A+0)throw A;L(1,0)}}function Co(e,t,n,o,s,u,l,d,v,w,_,E,O,A,H,z){var F=V();try{N(e)(t,n,o,s,u,l,d,v,w,_,E,O,A,H,z)}catch(X){if(B(F),X!==X+0)throw X;L(1,0)}}function _o(e,t,n,o,s){var u=V();try{return gr(e,t,n,o,s)}catch(l){if(B(u),l!==l+0)throw l;L(1,0)}}var ct;$e=function e(){ct||wr(),ct||($e=e)};function wr(){if(ce>0||(qe(),ce>0))return;function e(){ct||(ct=!0,a.calledRun=!0,!R&&(mt(),c(a),a.onRuntimeInitialized&&a.onRuntimeInitialized(),yt()))}a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1),e()},1)):e()}if(a.preInit)for(typeof a.preInit=="function"&&(a.preInit=[a.preInit]);a.preInit.length>0;)a.preInit.pop()();return wr(),i.ready}})();function Ci(r){return Bt(zt,r)}async function _i(r,i){return wi(zt,r,i)}async function Ti(r,i){return bi(zt,r,i)}var ze;class $i extends EventTarget{constructor(i={}){var a;super(),Yo(this,ze,void 0);try{const c=(a=i?.formats)==null?void 0:a.filter(f=>f!=="unknown");if(c?.length===0)th Line truncated
@@ -0,0 +1 @@
import{u as r,N as p,h as l,l as u,i as y,j as d,H as _,$ as b}from"./app-dvJP63FL.js";import{c as f}from"./createLucideIcon-DsaEAGzP.js";const h=[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]],k=f("copy",h),m=["aria-label","title"],g={__name:"CopyButton",props:{token:String},setup(e){const{t:i}=r(),c=b(),{copy:s}=p({legacy:!0}),n=e;function a(){s(n.token),c.success({text:i("notification.copied_to_clipboard")})}return(t,o)=>(l(),u("button",{type:"button","aria-label":t.$t("label.copy_to_clipboard"),title:t.$t("tooltip.copy_to_clipboard"),class:"button is-like-text is-pulled-right is-text",onClick:o[0]||(o[0]=_(x=>a(),["stop"]))},[y(d(k))],8,m))}};export{g as _};
+1
View File
@@ -0,0 +1 @@
import{u as V,r as b,d as y,w as l,f as r,g as x,h as B,i as t,m as C,j as o,H as M,$ as U}from"./app-dvJP63FL.js";import{F as k}from"./Form-ZbAUhXmz.js";const h={__name:"Create",setup(N){const{t:i}=V(),d=U(),m=x(),e=b(new k({name:"",email:"",password:"",password_confirmation:"",is_admin:!1}));async function u(p){e.password_confirmation=e.password,e.post("/api/v1/users").then(s=>{const n=s.data;d.success({text:i("notification.user_created")}),m.push({name:"admin.manageUser",params:{userId:n.info.id}})})}return(p,s)=>{const n=r("FormField"),c=r("FormPasswordField"),f=r("FormCheckbox"),w=r("FormButtons"),_=r("FormWrapper"),F=r("VueFooter"),g=r("StackLayout");return B(),y(g,null,{content:l(()=>[t(_,{title:"heading.new_user"},{default:l(()=>[C("form",{onSubmit:M(u,["prevent"]),onKeydown:s[5]||(s[5]=a=>o(e).onKeydown(a))},[t(n,{modelValue:o(e).name,"onUpdate:modelValue":s[0]||(s[0]=a=>o(e).name=a),fieldName:"name",errorMessage:o(e).errors.get("name"),inputType:"text",label:"field.name",autocomplete:"username",maxLength:255,autofocus:""},null,8,["modelValue","errorMessage"]),t(n,{modelValue:o(e).email,"onUpdate:modelValue":s[1]||(s[1]=a=>o(e).email=a),fieldName:"email",errorMessage:o(e).errors.get("email"),inputType:"email",label:"field.email",autocomplete:"email",maxLength:255},null,8,["modelValue","errorMessage"]),t(c,{modelValue:o(e).password,"onUpdate:modelValue":s[2]||(s[2]=a=>o(e).password=a),fieldName:"password",errorMessage:o(e).errors.get("password"),showRules:!0,label:"field.password",autocomplete:"new-password"},null,8,["modelValue","errorMessage"]),t(f,{modelValue:o(e).is_admin,"onUpdate:modelValue":s[3]||(s[3]=a=>o(e).is_admin=a),isDanger:!0,fieldName:"is_admin",label:"field.is_admin",help:"field.is_admin.help"},null,8,["modelValue"]),t(w,{isBusy:o(e).isBusy,isDisabled:o(e).isDisabled,showCancelButton:!0,onCancel:s[4]||(s[4]=a=>o(m).push({name:"admin.users"})),submitLabel:"label.create",submitId:"btnCreateUser"},null,8,["isBusy","isDisabled"])],32)]),_:1})]),footer:l(()=>[t(F)]),_:1})}}};export{h as default};
@@ -0,0 +1 @@
import{O as C,a8 as N,r as S,a6 as V,J as k,d as x,w as c,M as I,a2 as M,f as s,g as E,h as L,i as u,j as o,m as O,H as U,B as j}from"./app-dvJP63FL.js";import{F as K}from"./Form-ZbAUhXmz.js";import{u as R}from"./bus-ChE1sp8V.js";const H={__name:"CreateUpdate",props:{groupId:[Number,String]},setup(f){const l=C(),i=E(),h=M(),p=R(),_=I("2fauth"),d=N(_.prefix+"returnTo","groups"),m=f,r=j(()=>m.groupId!=null),e=S(new K({name:"",show_in_chips:!1}));V(()=>{h.name=="editGroup"&&(p.editedGroupName&&(e.name=p.editedGroupName,p.editedGroupName=void 0),k.get(m.groupId).then(n=>{e.name=n.data.name,e.show_in_chips=n.data.show_in_chips}))});function g(){r.value?w():b()}async function b(){e.post("/api/v1/groups").then(n=>{l.addOrEdit(n.data),i.push({name:d.value})})}async function w(){e.put("/api/v1/groups/"+m.groupId).then(n=>{l.addOrEdit(n.data),i.push({name:d.value})})}return(n,t)=>{const B=s("FormField"),F=s("FormCheckbox"),v=s("FormButtons"),y=s("FormWrapper"),G=s("StackLayout");return L(),x(G,null,{content:c(()=>[u(y,{title:o(r)?"heading.edit_group":"heading.new_group"},{default:c(()=>[O("form",{onSubmit:U(g,["prevent"]),onKeydown:t[3]||(t[3]=a=>o(e).onKeydown(a))},[u(B,{modelValue:o(e).name,"onUpdate:modelValue":t[0]||(t[0]=a=>o(e).name=a),fieldName:"name",errorMessage:o(e).errors.get("name"),label:"field.name",autofocus:""},null,8,["modelValue","errorMessage"]),u(F,{modelValue:o(e).show_in_chips,"onUpdate:modelValue":t[1]||(t[1]=a=>o(e).show_in_chips=a),fieldName:"show_in_chips",label:"field.show_in_chips",help:"field.show_in_chips.help"},null,8,["modelValue"]),u(v,{submitId:o(r)?"btnEditGroup":"btnCreateGroup",isBusy:o(e).isBusy,submitLabel:o(r)?"label.save":"label.create",showCancelButton:!0,onCancel:t[2]||(t[2]=a=>o(i).push({name:o(d)}))},null,8,["submitId","isBusy","submitLabel"])],32)]),_:1},8,["title"])]),_:1})}}};export{H as default};
@@ -0,0 +1 @@
import{C as et,u as tt,a as ot,b as at,r as ce,e as u,o as lt,I as x,Q as ue,v as N,d as _,w as g,j as e,a2 as st,M as nt,g as rt,f as y,h as n,i as c,m as s,p as de,t as f,l as p,k as d,D as $,_ as pe,H as W,F as J,E as X,q as Fe,n as q,y as Ie,G as $e,a3 as Ue,B as Te,$ as it,a1 as ct,O as ut}from"./app-dvJP63FL.js";import{F as fe}from"./Form-ZbAUhXmz.js";import{_ as dt}from"./QrContentDisplay-DiIjf7a_.js";import{i as G,R as pt}from"./iconService-rm6LRV4U.js";import{u as ft}from"./bus-ChE1sp8V.js";import{U as vt}from"./index-BJsmINgd.js";import{c as Oe}from"./createLucideIcon-DsaEAGzP.js";import{Q as mt}from"./qr-code-eSL1bq0j.js";import"./external-link-CqpXNovN.js";const ht=[["path",{d:"M10.3 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v10l-3.1-3.1a2 2 0 0 0-2.814.014L6 21",key:"9csbqa"}],["path",{d:"m14 19.5 3-3 3 3",key:"9vmjn0"}],["path",{d:"M17 22v-5.5",key:"1aa6fl"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}]],Le=Oe("image-up",ht);const gt=[["path",{d:"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72",key:"ul74o6"}],["path",{d:"m14 7 3 3",key:"1r5n42"}],["path",{d:"M5 6v4",key:"ilb8ba"}],["path",{d:"M19 14v4",key:"blhpug"}],["path",{d:"M10 2v2",key:"7u0qdc"}],["path",{d:"M7 8H3",key:"zfb6yr"}],["path",{d:"M21 16h-4",key:"1cnmox"}],["path",{d:"M11 3H9",key:"1obp7u"}]],_t=Oe("wand-sparkles",gt),yt={key:1,class:"modal modal-otp is-active"},bt={class:"modal-card is-flex-grow-1"},kt={class:"modal-card-body modal-slot py-0 is-align-content-center has-text-centered"},wt={key:1,for:"filUploadIcon",class:"add-icon-button pt-2"},Vt={key:0,role:"alert",class:"m-3"},xt={class:"field is-grouped is-grouped-centered mt-6"},Pt={class:"control"},Ct={key:0,class:"field is-grouped"},Mt={class:"control"},St=["title"],Ft={class:"file-cta"},It={class:"file-label"},$t={key:2,for:"icon-collection",class:"label"},Ut={key:3,class:"field has-addons"},Tt={class:"control"},Lt={class:"select"},Ot=["disabled"],At=["value"],Et={key:0,class:"control"},Dt={class:"select"},Nt=["disabled"],qt=["value"],Gt=["title"],Bt={class:"field is-grouped"},Ht={class:"control"},Qt={class:"icon is-small"},Kt={class:"control is-flex"},Rt={class:"file-cta"},jt={class:"icon"},zt={class:"file-label"},Wt={class:"is-hidden-mobile ml-1"},Jt=["src","alt"],Xt=["aria-label"],Yt={class:"field"},Zt={key:1,id:"lgdTryMyLuck",class:"help"},eo={key:6},to={key:0},oo={class:"title is-4 mt-5 mb-2"},ao={class:"help mb-4"},lo={class:"control"},so={key:0,class:"control"},ho={__name:"CreateUpdate",props:{twofaccountId:[Number,String]},setup(Ae){const B=et(),{t:v}=tt(),H=nt("2fauth"),P=rt(),Ee=st(),r=ot(),U=at(),Y=ft(),m=it(),o=ce(new fe({service:"",account:"",otp_type:"",icon:"",group_id:Be(),secret:"",algorithm:"",digits:null,counter:null,period:null,image:""})),Q=ce(new fe({qrcode:null})),C=ce(new fe({icon:null})),De=[{text:"selfh.st",value:"selfh",hasVariant:!0},{text:"dashboardicons.com",value:"dashboardicons",hasVariant:!0},{text:"2fa.directory",value:"tfa",hasVariant:!1}],K={selfh:[{text:"label.regular",value:"regular"},{text:"label.light",value:"light"},{text:"label.dark",value:"dark"}],dashboardicons:[{text:"label.regular",value:"regular"},{text:"label.light",value:"light"},{text:"label.dark",value:"dark"}],tfa:[{text:"label.regular",value:"regular"}]},T=u({otp_type:"",account:"",service:"",icon:"",secret:"",digits:null,algorithm:"",period:null,counter:null,image:""}),Ne=[{text:"TOTP",value:"totp"},{text:"HOTP",value:"hotp"},{text:"STEAM",value:"steamtotp"}],qe=[{text:"6",value:6},{text:"7",value:7},{text:"8",value:8},{text:"9",value:9},{text:"10",value:10}],Ge=[{text:"sha1",value:"sha1"},{text:"sha256",value:"sha256"},{text:"sha512",value:"sha512"},{text:"md5",value:"md5"}],M=u(),i=u(""),L=u(!1),S=u(!1),O=u(!1),A=u(!1),k=u(!1),F=u(!1),R=u(!1),w=u(r.preferences.iconCollection),E=u(r.preferences.iconVariant),I=u(r.preferences.iconPack??"/"),V=u([{text:"label.no_available_icon_packs",value:"/"}]),Z=u(!1),ee=u(!1),te=u(null),oe=u(null),j=u(null),ae=u(null),ve=u(null),me=u(null),he=u(null),le=Ae,h=Te(()=>le.twofaccountId!=null),ge=Te(()=>ut().items.map(t=>({text:t.id>0?t.name:"- "+v("label.no_group")+" -",value:t.id})));lt(()=>{Ee.name=="editAccount"?(F.value=!0,x.get(le.twofaccountId).then(t=>{o.fill(t.data),o.group_id==null&&(o.group_id=0),o.setOriginal(),i.value=o.icon,A.value=!0}).finally(()=>{F.value=!1})):Y.decodedUri?(M.value=Y.decodedUri,Y.decodedUri=null,F.value=!0,r.preferences.AutoSaveQrcodedAccount?x.storeFromUri(M.value).then(t=>{Ke(t.data)}).catch(t=>{t.response.data.errors.uri&&(S.value=!0,A.value=!0)}).finally(()=>{F.value=!1}):x.preview(M.value).then(t=>{o.fill(t.data),i.value=t.data.icon?t.data.icon:"",L.value=!0,ue().then(()=>{j.value.show()})}).catch(t=>{t.response.data.errors.uri&&(S.value=!0,A.value=!0)}).finally(()=>{F.value=!1})):A.value=!0,Ce()}),N(w,t=>{E.value=Object.prototype.hasOwnProperty.call(K,t)?K[t][0].value:""}),N(i,t=>{L.value&&uLine truncated
+1
View File
@@ -0,0 +1 @@
import{u as b,r as w,d as v,w as u,f as s,g as F,h as g,i as a,m as B,j as n,H as h,$ as C}from"./app-dvJP63FL.js";import{F as x}from"./Form-ZbAUhXmz.js";const S={__name:"Edit",props:{credentialId:{type:String,default:""}},setup(l){const{t:r}=b(),i=F(),m=C(),e=w(new x({name:r("label.my_device")})),d=l;function c(){e.patch("/webauthn/credentials/"+d.credentialId+"/name").then(()=>{m.success({text:r("notification.device_successfully_registered")}),i.push({name:"settings.webauthn.devices"})})}return(V,t)=>{const p=s("FormField"),f=s("FormButtons"),_=s("FormWrapper"),y=s("StackLayout");return g(),v(y,null,{content:u(()=>[a(_,{title:"heading.rename_device"},{default:u(()=>[B("form",{onSubmit:h(c,["prevent"]),onKeydown:t[2]||(t[2]=o=>n(e).onKeydown(o))},[a(p,{modelValue:n(e).name,"onUpdate:modelValue":t[0]||(t[0]=o=>n(e).name=o),fieldName:"name",errorMessage:n(e).errors.get("name"),inputType:"text",label:"field.new_name",autofocus:""},null,8,["modelValue","errorMessage"]),a(f,{submitId:"btnEditCredential",isBusy:n(e).isBusy,submitLabel:"label.save",showCancelButton:!0,onCancel:t[1]||(t[1]=o=>n(i).push({name:"settings.webauthn.devices"}))},null,8,["isBusy"])],32)]),_:1})]),_:1})}}};export{S as default};
+1
View File
@@ -0,0 +1 @@
import{C as v,v as w,o as M,d as _,w as f,D as C,j as e,a2 as $,e as B,f as b,g as x,h as t,i as F,l as n,m as i,n as d,t as l,k as c,F as N,E as V,p as q,B as D}from"./app-dvJP63FL.js";import{U as E}from"./index-BJsmINgd.js";const R={key:0,class:"error-message"},U={key:1,class:"error-message"},z={key:3,class:"is-size-7 is-family-code pt-3"},L={__name:"Error",setup(j){const s=v(),m=x(),u=$(),g=B(!0),y=D(()=>!1);w(g,r=>{r==!1&&k()}),M(()=>{u.query.err&&(s.message="error."+u.query.err)});function k(){window.history.length>1&&u.name!=="404"&&u.name!=="notFound"&&!u.query.err?m.go(-1):m.push({name:"accounts"})}return(r,a)=>{const h=b("Modal");return t(),_(h,{"is-active":e(g),"onUpdate:isActive":a[0]||(a[0]=o=>C(g)?g.value=o:null)},{default:f(()=>[F(e(E),null,{default:f(({mode:o})=>[r.$route.name=="404"||r.$route.name=="notFound"?(t(),n("div",R,[a[1]||(a[1]=i("p",{class:"error-404"},null,-1)),i("p",{class:d({"has-text-grey":o!="dark"})},l(r.$t("error.resource_not_found")),3)])):(t(),n("div",U,[a[3]||(a[3]=i("p",{class:"error-generic"},null,-1)),i("p",{class:d({"has-text-grey":o!="dark"})},l(r.$t("message.error_occured")),3),e(s).message?(t(),n("p",{key:0,class:d({"has-text-grey-lighter":o=="dark"})},l(r.$t(e(s).message)),3)):c("",!0),e(s).reasons?(t(!0),n(N,{key:1},V(e(s).reasons,p=>(t(),n("p",{key:p,class:d({"has-text-grey-lighter":o=="dark"})},l(p),3))),128)):c("",!0),e(s).originalMessage?(t(),n("p",{key:2,class:d({"has-text-grey-lighter":o=="dark"})},l(r.$t(e(s).originalMessage)),3)):c("",!0),e(y)&&e(s).debug?(t(),n("p",z,[a[2]||(a[2]=i("br",null,null,-1)),q(l(e(s).debug),1)])):c("",!0)]))]),_:1})]),_:1},8,["is-active"])}}};export{L as default};
+1
View File
@@ -0,0 +1 @@
import{ae as u}from"./app-dvJP63FL.js";class l{constructor(){this.errors={}}set(t,s){typeof t=="object"?this.errors=t:this.set({...this.errors,[t]:n(s)})}all(){return this.errors}has(t){return this.errors.hasOwnProperty(t)}hasAny(...t){return t.some(s=>this.has(s))}any(){return Object.keys(this.errors).length>0}get(t){if(this.has(t))return this.getAll(t)[0]}getAll(t){return n(this.errors[t]||[])}only(...t){const s=[];return t.forEach(r=>{const e=this.get(r);e&&s.push(e)}),s}flatten(){return Object.values(this.errors).reduce((t,s)=>t.concat(s),[])}clear(t){const s={};t&&Object.keys(this.errors).forEach(r=>{r!==t&&(s[r]=this.errors[r])}),this.set(s)}}function n(o){return Array.isArray(o)?o:[o]}class i{constructor(t={}){this.axios=u("web"),this.isBusy=!1,this.isDisabled=!1,this.errors=new l,this.originalData=this.deepCopy(t),Object.assign(this,t)}fill(t){this.keys().forEach(s=>{this[s]=t[s]})}setOriginal(){Object.keys(this).filter(t=>!i.ignore.includes(t)).forEach(t=>{this.originalData[t]=this.deepCopy(this[t])})}hasChanged(){return this.keys().some(t=>this[t]!==this.originalData[t])}fillWithKeyValueObject(t){this.keys().forEach(s=>{const r=t.find(e=>e.key===s.toString());r!=null&&(this[s]=r.value)})}data(){return this.keys().reduce((t,s)=>({...t,[s]:this[s]}),{})}keys(){return Object.keys(this).filter(t=>!i.ignore.includes(t))}startProcessing(){this.errors.clear(),this.isBusy=!0}finishProcessing(){this.isBusy=!1}clear(){this.errors.clear()}reset(){Object.keys(this).filter(t=>!i.ignore.includes(t)).forEach(t=>{this[t]=this.deepCopy(this.originalData[t])})}get(t,s={}){return this.submit("get",t,s)}post(t,s={}){return this.submit("post",t,s)}patch(t,s={}){return this.submit("patch",t,s)}put(t,s={}){return this.submit("put",t,s)}delete(t,s={}){return this.submit("delete",t,s)}submit(t,s,r={}){this.startProcessing();const e=t==="get"?{params:this.data()}:this.data();return new Promise((a,c)=>{this.axios.request({url:this.route(s),method:t,data:e,...r}).then(h=>{this.finishProcessing(),a(h)}).catch(h=>{this.isBusy=!1,h.response&&this.errors.set(this.extractErrors(h.response)),h.response?.status!=422&&c(h)})})}upload(t,s={}){return this.startProcessing(),new Promise((r,e)=>{this.axios.post(this.route(t),this.data(),{headers:{"Content-Type":"multipart/form-data"},...s}).then(a=>{this.finishProcessing(),r(a)}).catch(a=>{this.isBusy=!1,a.response&&this.errors.set(this.extractErrors(a.response)),e(a)})})}extractErrors(t){return!t.data||typeof t.data!="object"?{error:i.errorMessage}:t.data.errors?{...t.data.errors}:t.data.message?{error:t.data.message}:{...t.data}}route(t,s={}){let r=t;return i.routes.hasOwnProperty(t)&&(r=decodeURI(i.routes[t])),typeof s!="object"&&(s={id:s}),Object.keys(s).forEach(e=>{r=r.replace(`{${e}}`,s[e])}),r}onKeydown(t){t.target.name&&this.errors.clear(t.target.name)}deepCopy(t){if(t===null||typeof t!="object")return t;const s=Array.isArray(t)?[]:{};return Object.keys(t).forEach(r=>{s[r]=this.deepCopy(t[r])}),s}}i.routes={};i.errorMessage="Something went wrong. Please try again.";i.ignore=["isBusy","isDisabled","errors","originalData","axios"];export{i as F};
+1
View File
@@ -0,0 +1 @@
import{U as V}from"./index-BJsmINgd.js";import{O as N,a as S,v as E,o as L,af as T,d as R,w as i,e as x,f as c,g as A,Q as g,h as u,i as a,j as s,m as o,t as n,p as f,l as m,F,E as M,k as v,n as k}from"./app-dvJP63FL.js";import{u as U}from"./bus-ChE1sp8V.js";import{u as W,m as O,T as j,M as q}from"./useSortable-6hRbxhTj.js";import{C as D}from"./circle-plus-BM92Iipr.js";import{c as P}from"./createLucideIcon-DsaEAGzP.js";const Q=[["path",{d:"M17 3a2 2 0 0 1 2 2v15a1 1 0 0 1-1.496.868l-4.512-2.578a2 2 0 0 0-1.984 0l-4.512 2.578A1 1 0 0 1 5 20V5a2 2 0 0 1 2-2z",key:"oz39mx"}],["path",{d:"m9 10 2 2 4-4",key:"1gnqz4"}]],H=P("bookmark-check",Q),J={class:"title"},K={class:"is-size-7-mobile"},X={class:"mt-3 mb-6"},Y={key:0},Z={id:"dv"},ee={class:"is-flex is-align-items-center"},te={class:"tfa-content is-size-5 is-size-6-mobile pr-2"},se={class:"has-ellipsis"},oe={class:"is-family-primary is-size-6 is-size-7-mobile has-text-grey"},ae={key:0,class:"tfa-cell"},ie={class:"tfa-cell"},ne=["onClick","title"],le={class:"tfa-cell ml-4"},re={class:"mt-2 is-size-7 is-pulled-right"},ge={__name:"Groups",setup(ce){const y=A(),t=N(),b=U(),C=S(),p=x(!1),{start:w,stop:z}=W("#dv",t.withoutTheAllGroup,{animation:200,handle:".drag-handle",onUpdate:e=>{const d=t.withoutTheAllGroup[e.oldIndex].id,l=t.items.findIndex(_=>_.id==d);O(t.items,l,e.newIndex+1,e),g(()=>{t.saveOrder()})}});return E(()=>t.isEmpty,e=>{e==!1?g(()=>{w()}):z()}),L(()=>{p.value=t.isEmpty,t.fetch().finally(()=>{p.value=!1})}),T((e,d)=>{e.name=="editGroup"&&(b.editedGroupName=t.items.find(l=>l.id==e.params.groupId)?.name)}),(e,d)=>{const l=c("RouterLink"),_=c("Spinner"),$=c("ResponsiveWidthWrapper"),G=c("NavigationButton"),B=c("VueFooter"),I=c("StackLayout");return u(),R(I,null,{content:i(()=>[a($,null,{default:i(()=>[o("h1",J,n(e.$t("heading.groups")),1),o("div",K,n(e.$t("message.manage_groups_legend")),1),o("div",X,[a(l,{class:"is-link mt-5",to:{name:"createGroup"}},{default:i(()=>[a(s(D)),f(" "+n(e.$t("link.create_group")),1)]),_:1})]),s(t).isEmpty?v("",!0):(u(),m("div",Y,[a(s(V),null,{default:i(({mode:h})=>[o("span",Z,[(u(!0),m(F,null,M(s(t).withoutTheAllGroup,r=>(u(),m("div",{key:r.id,class:"group-item"},[o("div",ee,[o("div",te,[o("div",se,[f(n(r.name)+" ",1),o("span",oe,n(e.$t("message.x_accounts",{count:r.twofaccounts_count})),1)])]),s(C).preferences.useGroupChips&&r.show_in_chips?(u(),m("div",ae,[a(s(H),{class:"icon mr-2"})])):v("",!0),o("div",ie,[a(l,{to:{name:"editGroup",params:{groupId:r.id}},class:k(["button tag mr-1",h=="dark"?"is-dark":"is-white"]),title:e.$t("tooltip.edit_group")},{default:i(()=>[f(n(e.$t("label.edit")),1)]),_:1},8,["to","class","title"]),o("button",{type:"button",class:k(["button tag",h=="dark"?"is-dark":"is-white"]),onClick:de=>s(t).remove(r.id),title:e.$t("tooltip.delete")},[a(s(j),{class:"icon-size-1"})],10,ne)]),o("div",le,[a(s(q),{class:"drag-handle has-text-grey is-draggable"})])])]))),128))])]),_:1}),o("div",re,n(e.$t("message.deleting_group_does_not_delete_accounts")),1)])),a(_,{isVisible:s(p)&&s(t).isEmpty,type:"list-loading"},null,8,["isVisible"])]),_:1})]),footer:i(()=>[a(B,null,{default:i(()=>[a(G,{action:"close",onClosed:d[0]||(d[0]=h=>s(y).push({name:"accounts"})),"current-page-title":e.$t("title.groups")},null,8,["current-page-title"])]),_:1})]),_:1})}}};export{ge as default};
+1
View File
@@ -0,0 +1 @@
import{u as vt,a as _t,b as gt,r as j,v as kt,o as yt,I as X,d as x,w,j as l,e as g,$ as bt,B as D,M as wt,f as k,h as n,i as a,l as u,m as t,t as o,k as d,a4 as Y,n as $,F as V,E as B,p as h,q as Z,a5 as $t,D as tt,H as Ct,_ as zt,Q as At}from"./app-dvJP63FL.js";import{F as U}from"./Form-ZbAUhXmz.js";import{u as xt}from"./bus-ChE1sp8V.js";import{U as Mt}from"./index-BJsmINgd.js";import{Q as Ft}from"./qr-code-eSL1bq0j.js";import{c as H}from"./createLucideIcon-DsaEAGzP.js";import{C as v}from"./check-CPGWPXZa.js";import{X as et}from"./x-DQVIq0xP.js";import{a as St,C as Nt}from"./circle-x-AvUNZzwX.js";const qt=[["path",{d:"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",key:"1oefj6"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]],Et=H("file-text",qt);const Pt=[["path",{d:"M12 20h-1a2 2 0 0 1-2-2 2 2 0 0 1-2 2H6",key:"1528k5"}],["path",{d:"M13 8h7a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2h-7",key:"13ksps"}],["path",{d:"M5 16H4a2 2 0 0 1-2-2v-4a2 2 0 0 1 2-2h1",key:"1n9rhb"}],["path",{d:"M6 4h1a2 2 0 0 1 2 2 2 2 0 0 1 2-2h1",key:"1mj8rg"}],["path",{d:"M9 6v12",key:"velyjx"}]],Tt=H("text-cursor-input",Pt);const Vt=[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]],Bt=H("triangle-alert",Vt),It={class:"title"},Ot={key:0},jt={class:"block is-size-7-mobile"},Dt={class:"mb-2"},Ut={class:"columns"},Ht={class:"column"},Lt={class:"block"},Rt={class:"card"},Qt={class:"card-content"},Jt={class:"media"},Wt={class:"media-left"},Kt={class:"image is-32x32"},Gt={class:"media-content"},Xt={class:"title is-5 has-text-grey"},Yt={class:"card-footer"},Zt={class:"block"},te={class:"card"},ee={class:"card-content"},se={class:"media"},le={class:"media-left"},ie={class:"image is-32x32"},oe={class:"media-content"},ne={class:"title is-5 has-text-grey"},ae={class:"card-footer"},re={class:"block"},ue={class:"card"},de={class:"card-content"},ce={class:"media"},pe={class:"media-left"},fe={class:"image is-32x32"},me={class:"media-content"},he={class:"title is-5 has-text-grey"},ve={class:"content"},_e={class:"card-footer"},ge={class:"title is-5"},ke={class:"block is-size-7-mobile"},ye={class:"table is-size-7-mobile is-fullwidth"},be={key:1},we={class:"block is-size-7-mobile"},$e={class:"mb-2"},Ce={class:"is-flex is-justify-content-space-between"},ze=["onClick","title"],Ae=["src"],xe={key:1,class:"is-flex-grow-1 has-ellipsis"},Me={key:2,class:"tags is-flex-wrap-nowrap"},Fe=["onClick","title"],Se=["onClick","title"],Ne={key:3,class:"has-nowrap"},qe={key:0,class:"has-text-success"},Ee={key:1,class:"has-text-danger"},Pe={class:"is-size-6 is-size-7-mobile"},Te={class:"is-family-primary has-text-grey"},Ve={key:0,class:"has-text-danger"},Be={key:1,class:"has-text-warning"},Ie={key:2},Oe={key:0,class:"mt-2 is-size-7 is-pulled-right"},je={key:1,class:"mt-2 is-size-7 is-pulled-right"},De={key:0,class:"control"},Ye={__name:"Import",setup(Ue){const{t:c}=vt(),L=wt("2fauth"),f=bt(),R=_t(),I=xt(),Q=gt(),M=g(null),q=g(null),E=g(null),C=g(null),P=g(null),F=j(new U({service:"",account:"",otp_type:"",icon:"",secret:"",algorithm:"",digits:null,counter:null,period:null})),z=j(new U({file:null,withSecret:!0})),y=j(new U({qrcode:null,withSecret:!0})),A=g(!1);c("label.qr_code"),c("label.plain_text");const r=g([]),m=g(!1),S=D(()=>r.value.filter(s=>s.imported==-1&&s.id>-2).length),J=D(()=>r.value.filter(s=>s.id===-1&&s.imported===-1).length),st=D(()=>r.value.filter(s=>s.imported===1).length);kt(A,s=>{s==!1&&M.value?.clearOTP()}),yt(()=>{I.migrationUri&&(O(I.migrationUri),I.migrationUri=null)});async function O(s,e=null){m.value=!0,await X.migrate(s,{returnError:!0}).then(_=>{_.data.forEach(T=>{T.imported=-1,r.value.push(T)}),K(),C.value=P.value=null}).catch(_=>{f.alert({text:c(_.response.data.message)}),e!=null&&_.response.status===422&&(e.clear(),e.errors.set(e.extractErrors(_.response)))}).finally(()=>{m.value=!1})}function lt(){confirm(c("confirmation.discard_duplicates"))&&(f.clear(),M.value?.clearOTP(),r.value=r.value.filter(s=>s.id!==-1))}function it(){confirm(c("confirmation.discard_all"))&&(f.clear(),M.value?.clearOTP(),r.value=[])}function ot(s){confirm(c("confirmation.discard"))&&r.value.splice(s,1)}async function nt(){for(let s=0;s<r.value.length;s++)r.value[s].imported==-1&&await W(s);Q.sortDefault()}async function W(s){F.fill(r.value[s]),await F.post("/api/v1/twofaccounts",{returnError:!0}).then(e=>{r.value[s].imported=1,r.value[s].id=e.data.id,delete e.data.secret,Q.items.push(e.data)}).catch(e=>{r.value[s].imported=0,r.value[s].id=0,r.value[s].errors=F.errors.flatten()})}function at(s){F.fill(r.value[s]),A.value=!0,At().then(()=>{M.value.show()})}function rt(){z.clear(),m.value=!0,z.file=q.value.files[0],z.upload("/api/v1/twofaccounts/migration",{returnError:!0}).Line truncated
+1
View File
@@ -0,0 +1 @@
import{M as T,h as o,l,t as a,j as t,C as q,u as H,a as z,P as G,r as J,a8 as Q,o as X,d as k,w as u,f as v,g as Y,i as _,k as g,m as n,H as j,p as d,q as O,F as $,E as M,n as N,e as Z,$ as x}from"./app-dvJP63FL.js";import{F as ee}from"./Form-ZbAUhXmz.js";import{w as se}from"./webauthnService-D363et0U.js";const te=["id","href"],R={__name:"SsoConnectLink",props:{provider:{type:String,default:"unknown"}},setup(K){const S=T("2fauth"),c=K;return(m,B)=>(o(),l("a",{id:"lnkSignWith"+c.provider,class:"button is-link",href:t(S).config.subdirectory+"/socialite/redirect/"+c.provider},a(m.$t("label."+c.provider)),9,te))}},ne={key:0,class:"notification is-warning has-text-centered"},ae={class:"block"},oe={class:"nav-links"},ie={key:0,class:"mt-4"},le={key:1,class:"columns mt-4 is-variable is-1"},re={class:"column is-narrow py-1"},ue={class:"column py-1"},de={class:"buttons"},me={key:0,class:"notification is-info has-text-centered is-radiusless"},pe={key:1,class:"notification is-warning has-text-centered is-radiusless"},_e={class:"nav-links"},ge={class:""},ce={class:""},fe={key:2,class:"buttons mt-4"},ye={key:3,class:"is-italic"},ve={class:"nav-links"},ke=["href"],we={key:0,class:"notification is-info has-text-centered is-radiusless"},be={key:1,class:"notification is-warning has-text-centered is-radiusless"},he={key:2,class:"notification is-warning has-text-centered"},$e={class:"nav-links"},Se=["aria-label"],Fe={key:0,class:"mt-4"},Le={key:1,class:"columns mt-4 is-variable is-1"},Ve={class:"column is-narrow py-1"},Be={class:"column py-1"},Ae={class:"buttons"},Re={__name:"Login",setup(K){const S=q(),{t:c}=H(),m=T("2fauth"),B=Y(),W=z(),w=x(),p=G(),r=J(new ee({email:"",password:""})),A=Z(!1),f=Q(m.prefix+"activeLoginForm",null);X(()=>{p.enableSso==!0&&p.useSsoOnly==!0?f.value="sso":(f.value==null||f.value=="sso")&&(f.value="legacy")});function b(s){r.clear(),f.value=s}function D(s){w.clear(),r.post("/user/login",{returnError:!0}).then(async e=>{await W.loginAs({id:e.data.id,name:e.data.name,email:e.data.email,oauth_provider:e.data.oauth_provider,authenticated_by_proxy:!1,preferences:e.data.preferences,isAdmin:e.data.is_admin});for(const[h,F]of Object.entries(e?.data?.appSettings||{}))p[h]=F;B.push({name:"accounts"})}).catch(e=>{e.response?.status===401?w.alert({text:c("notification.authentication_failed"),duration:1e4}):e.response?.status!==422&&S.show(e)})}function I(){w.clear(),r.clear(),A.value=!0,se.authenticate(r.email).then(async s=>{await W.loginAs({id:s.data.id,name:s.data.name,email:s.data.email,oauth_provider:s.data.oauth_provider,authenticated_by_proxy:!1,preferences:s.data.preferences,isAdmin:s.data.is_admin});for(const[e,h]of Object.entries(s?.data?.appSettings||{}))p[e]=h;B.push({name:"accounts"})}).catch(s=>{"webauthn"in s?s.name=="is-warning"?w.warn({text:c(s.message)}):w.alert({text:c(s.message)}):s.response.status===401?w.alert({text:c("notification.authentication_failed"),duration:1e4}):s.response.status==422?r.errors.set(r.extractErrors(s.response)):S.show(s)}).finally(()=>{A.value=!1})}return(s,e)=>{const h=v("FormField"),F=v("FormButtons"),L=v("RouterLink"),C=v("FormWrapper"),V=v("i18n-t"),U=v("FormPasswordField"),E=v("VueFooter"),P=v("StackLayout");return o(),k(P,null,{content:u(()=>[t(f)=="webauthn"?(o(),k(C,{key:0,title:"heading.webauthn_login",punchline:"message.welcome_to_2fauth"},{default:u(()=>[t(p).enableSso==!0&&t(p).useSsoOnly==!0?(o(),l("div",ne,a(s.$t("message.sso_only_form_restricted_to_admin")),1)):g("",!0),n("div",ae,a(s.$t("message.use_security_device_to_sign_in")),1),n("form",{id:"frmWebauthnLogin",onSubmit:j(I,["prevent"]),onKeydown:e[1]||(e[1]=i=>t(r).onKeydown(i))},[_(h,{modelValue:t(r).email,"onUpdate:modelValue":e[0]||(e[0]=i=>t(r).email=i),fieldName:"email",errorMessage:t(r).errors.get("email"),inputType:"email",label:"field.email",autofocus:""},null,8,["modelValue","errorMessage"]),_(F,{isBusy:t(A),submitLabel:"label.continue",submitId:"btnContinue"},null,8,["isBusy"])],32),n("div",oe,[n("p",null,[d(a(s.$t("message.lost_your_device"))+"  ",1),_(L,{id:"lnkRecoverAccount",to:{name:"webauthn.lost"},class:"is-link"},{default:u(()=>[d(a(s.$t("link.recover_your_account")),1)]),_:1})]),n("p",null,[d(a(s.$t("message.sign_in_using"))+"  ",1),n("a",{id:"lnkSignWithLegacy",role:"button",class:"is-link",onKeyup:e[2]||(e[2]=O(i=>b("legacy"),["enter"])),onClick:e[3]||(e[3]=i=>b("legacy")),tabindex:"0"},a(s.$t("link.login_and_password")),33)]),t(p).disableRegistration==!1&&t(p).useSsoOnly==!1?(o(),l("p",ie,[d(a(s.$t("message.dont_have_account_yet"))+"  ",1),_(L,{id:"lnkRegister",to:{name:"register"},class:"is-link"},{default:u(()=>[d(a(s.$t("link.register")),1)]),_:1})])):g("",!0),t(p).enableSso==!0&&Object.values(t(m).config.sso).includes(!0)?(o(),l("div",le,[n("div",re,a(s.$t("message.or_continue_with")),1),n("div",ue,[n("div",de,[(o(!0),l($,null,M(t(m).config.sso,(i,y)=>(o(),l($,{key:y},[i?(o(),k(R,{key:0,class:N("is-outlined is-small"),provider:y},null,8,["provider"])):g("",!0)],64))),Line truncated
+1
View File
@@ -0,0 +1 @@
import{_ as se}from"./CopyButton-CgxgBp0c.js";import{_ as te}from"./AccessLogViewer-D5ke4CwJ.js";import{C as ie,u as ne,a as oe,o as ae,a1 as p,d as I,w as m,j as t,e as z,g as re,M as le,a7 as v,f as h,h as a,i as c,m as s,t as n,l as r,k as d,n as g,p as b,F as de,E as ue,Q as B,$ as ce}from"./app-dvJP63FL.js";import{U as _e}from"./index-BJsmINgd.js";import{u as he}from"./bus-ChE1sp8V.js";import{u as fe}from"./breakpoints-CyLcIEOu.js";import{c as pe}from"./createLucideIcon-DsaEAGzP.js";import"./tablet-DYUfDfjC.js";import"./x-DQVIq0xP.js";import"./check-CPGWPXZa.js";const me=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["circle",{cx:"12",cy:"10",r:"3",key:"ilqhr7"}],["path",{d:"M7 21v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2",key:"1m6ac2"}]],ge=pe("square-user",me),ke={key:0,class:"pr-5 settings-menu"},ve={class:"menu"},be={class:"menu-list"},ye={key:0},$e={class:"mt-1"},we={key:1},ze={class:"columns is-mobile is-2"},Ce={class:"column"},xe={class:"has-text-weight-light has-text-grey-dark is-pulled-right"},Ue={class:"subtitle is-6"},Ve={key:0,class:"notification is-dark is-size-7-mobile has-text-centered"},Ie={class:"block is-size-6 is-size-7-mobile has-text-grey"},Se={class:"block"},Ee={key:2,class:"block"},Fe={class:"list-item is-size-6 is-size-6-mobile has-text-grey"},Ne={class:"mb-3 is-flex is-justify-content-space-between"},Be={class:"has-text-weight-bold"},Pe={class:"tags ml-3 is-right"},Re=["title"],Le=["title"],qe={class:"is-size-7 is-size-7-mobile has-text-grey-dark"},Ae={key:0,class:"is-block block"},Me={key:1,class:"is-block block"},Te={key:2,class:"is-block block"},je={class:"is-block block"},We={class:"list-item is-size-6 is-size-6-mobile has-text-grey is-flex is-justify-content-space-between"},Ze={class:"has-text-weight-bold"},De={class:"is-block is-family-primary has-text-grey-dark"},He={key:0},Qe={class:"tags ml-3 is-right"},Ge=["title"],Oe={class:"list-item is-size-6 is-size-6-mobile has-text-grey is-flex is-justify-content-space-between"},Ye={class:"has-text-weight-bold"},Je={class:"is-block has-text-grey-dark"},Ke={key:0},Xe={class:"tags ml-3 is-right"},es=["title"],ss={class:"block"},ts={key:3,class:"block is-size-6 is-size-7-mobile has-text-grey"},is={class:"about-debug box is-family-monospace is-size-7 is-shadowless"},ns=["value"],os={class:"has-text-grey"},as={class:"is-left-bordered-danger"},rs={class:"block is-size-6 is-size-7-mobile"},ls={class:"is-block has-text-grey has-text-weight-bold"},vs={__name:"Manage",props:{userId:[Number,String]},setup(P){const y=ie(),{t:u}=ne(),_=ce(),C=re(),x=oe(),R=he(),U=le("2fauth"),{isLaptop:L}=fe(),$=z(!1),i=z(null),S=z(null),E=z(!1),V=P;ae(async()=>{await q()});async function q(){$.value=!0,p.getById(V.userId,{returnError:!0}).then(e=>{i.value=e.data,R.username=i.value.info.name}).catch(e=>{y.show(e)}).finally(()=>{$.value=!1})}async function A(){if(!w())return!1;confirm(u("confirmation.purge_password_reset_request"))===!0&&(await p.resendPasswordEmail(i.value.info.id),i.value.password_reset=null)}async function M(){if(!w())return!1;confirm(u("confirmation.request_password_reset"))===!0&&p.resetPassword(i.value.info.id,{returnError:!0}).then(e=>{i.value=e.data,_.success({text:u("notification.password_successfully_reset")})}).catch(e=>{e.response.status===400?_.alert({text:e.response.data.reason}):y.show(e)})}function T(e){if(!confirm(u("confirmation.change_admin_role"))){B().then(()=>{i.value.info.is_admin=!e});return}if(e===!1&&i.value.info.id===x.id&&!confirm(u("confirmation.demote_own_account"))){B().then(()=>{i.value.info.is_admin=!0});return}p.promote(i.value.info.id,{is_admin:e},{returnError:!0}).then(o=>{i.value.info.is_admin=o.data.info.is_admin,_.success({text:u("notification.user_role_updated")})}).catch(o=>{o.response.status===403?(_.alert({text:o.response.data.message}),i.value.info.is_admin=!0):y.show(o)})}function j(){if(!w())return!1;confirm(u("confirmation.delete_user"))&&p.delete(i.value.info.id,{returnError:!0}).then(e=>{_.success({text:u("notification.user_account_successfully_deleted")}),C.push({name:"admin.users"})}).catch(e=>{e.response.status===403?_.alert({text:e.response.data.message}):y.show(e)})}function W(){if(!w())return!1;p.revokePATs(i.value.info.id).then(e=>{i.value.valid_personal_access_tokens=0,_.success({text:u("notification.pats_succesfully_revoked")})})}function w(){return!(i.value.info.id===x.id&&!confirm(u("confirmation.edit_own_account")))}const Z=v("heading-user"),D=v("heading-access"),H=v("heading-lastAccesses"),Q=v("heading-preferences"),G=v("heading-dangerZone"),k=e=>{e&&e.scrollIntoView({behavior:"smooth"})};return(e,o)=>{const O=h("FormCheckbox"),Y=h("router-link"),J=h("ResponsiveWidthWrapper"),K=h("Spinner"),F=h("NavigationButton"),X=h("VueFooter"),ee=h("StackLayout");return a(),I(t(_e),null,{default:m(({mode:f})=>[c(ee,null,{content:m(()=>[c(J,null,{default:m(()=>[s("h1",{ref:"heading-user",class:"title mb-6"},n(e.$t("heading.user_management")),513),t(L)&&t(x).preferences.showQuickNaLine truncated
+1
View File
@@ -0,0 +1 @@
import{C as X,u as Y,P as Z,a as ee,a8 as te,N as se,o as oe,r as ae,a1 as N,af as ne,j as t,d as V,w as r,M as ie,e as f,f as p,h as n,i,m as l,H as L,p as b,t as a,a4 as D,l as u,k as m,q as le,F as re,E as ue,n as F,ak as ce,B as de,$ as pe}from"./app-dvJP63FL.js";import{t as me}from"./tabs-Btun2NN0.js";import{F as _e}from"./Form-ZbAUhXmz.js";import{U as fe}from"./index-BJsmINgd.js";import{C as he}from"./circle-plus-BM92Iipr.js";import{C as ve}from"./check-CPGWPXZa.js";import"./createLucideIcon-DsaEAGzP.js";const ge={class:"field is-grouped"},ye={class:"control"},ke={class:"control"},be={key:0,class:"notification is-warning has-text-centered"},we={key:1,class:"notification is-warning has-text-centered"},Te={class:"title is-4"},$e={class:"is-size-7-mobile"},Ce={class:"mt-3"},Se={key:2},xe={class:"tags is-pulled-right"},Ve=["onClick"],Fe=["onClick","title"],ze={key:1,class:"is-family-primary is-size-6 is-size-7-mobile has-text-danger"},Be={key:3,class:"is-size-7-mobile is-size-6 my-3"},Ae={key:4,class:"pat is-family-monospace is-size-6 is-size-7-mobile has-text-success"},Me={class:"mt-2 is-size-7 is-pulled-right"},We={__name:"OAuth",setup(Pe){const E=X(),{t:h}=Y(),w=Z(),K=ie("2fauth"),v=pe(),T=ee(),O=te(K.prefix+"returnTo","accounts"),{copy:U}=se({legacy:!0}),c=f([]),$=f(!1),g=f(!1),y=f(null),C=f(null),S=de(()=>w.enableSso&&w.useSsoOnly&&!w.allowPatWhileSsoOnly||T.authenticated_by_proxy);oe(()=>{z()});const d=ae(new _e({name:""}));function z(){$.value=!0,N.getPersonalAccessTokens({returnError:!0}).then(e=>{c.value=[],e.data.forEach(o=>{o.id===C.value?(o.value=y.value,c.value.unshift(o)):c.value.push(o)})}).catch(e=>{e.response.status===403||E.show(e)}).finally(()=>{$.value=!1,C.value=null,y.value=null})}function B(){j(),S.value?v.warn({text:h("error.unsupported_with_reverseproxy")}):g.value=!0}function W(){d.post("/oauth/personal-access-tokens").then(e=>{y.value=e.data.accessToken,C.value=e.data.accessTokenId,z(),g.value=!1,d.reset()})}function I(e){confirm(h("confirmation.revoke_token"))&&N.deletePersonalAccessToken(e).then(o=>{c.value=c.value.filter(_=>_.id!==e),v.success({text:h("notification.token_revoked")})})}function j(){c.value.forEach(e=>{e.value=null}),y.value=null}function H(e){U(e),v.success({text:h("notification.copied_to_clipboard")})}function q(){g.value=!1,d.reset()}function x(e){const o=new Date(e),_=Date.now(),k=o.getTime()-_;return Math.ceil(k/(1e3*60*60*24))}return ne(e=>{e.name.startsWith("settings.")||v.clear()}),(e,o)=>{const _=p("FormField"),k=p("VueButton"),A=p("FormWrapper"),M=p("StackLayout"),G=p("Spinner"),R=p("NavigationButton"),J=p("VueFooter");return t(g)?(n(),V(M,{key:0},{content:r(()=>[i(A,{title:"heading.new_token"},{default:r(()=>[l("form",{onSubmit:L(W,["prevent"]),onKeydown:o[1]||(o[1]=s=>t(d).onKeydown(s))},[i(_,{modelValue:t(d).name,"onUpdate:modelValue":o[0]||(o[0]=s=>t(d).name=s),fieldName:"name",errorMessage:t(d).errors.get("name"),inputType:"text",label:"field.name",autofocus:""},null,8,["modelValue","errorMessage"]),l("div",ge,[l("div",ye,[i(k,{nativeType:"submit",id:"btnGenerateToken",isLoading:t(d).isBusy},{default:r(()=>[b(a(e.$t("label.generate")),1)]),_:1},8,["isLoading"])]),l("div",ke,[i(k,{onClick:q,nativeType:"button",id:"btnCancel",color:"is-text"},{default:r(()=>[b(a(e.$t("label.cancel")),1)]),_:1})])])],32)]),_:1})]),_:1})):(n(),V(M,{key:1},{header:r(()=>[i(t(ce),{tabs:t(me),"active-tab":"settings.oauth.tokens",onTabSelected:o[2]||(o[2]=s=>("router"in e?e.router:t(D)).push({name:s}))},null,8,["tabs"])]),content:r(()=>[i(A,null,{default:r(()=>[t(S)&&t(T).oauth_provider?(n(),u("div",be,a(e.$t("message.sso_only_x_settings_are_disabled",{auth_method:"OAuth"})),1)):m("",!0),t(S)&&t(T).authenticated_by_proxy?(n(),u("div",we,a(e.$t("message.auth_handled_by_proxy")+" "+e.$t("message.manage_auth_at_proxy_level")),1)):m("",!0),l("h4",Te,a(e.$t("heading.personal_access_tokens")),1),l("div",$e,a(e.$t("message.token_legend")),1),l("div",Ce,[l("a",{tabindex:"0",class:"is-link",onClick:B,onKeyup:le(B,["enter"])},[i(t(he)),b(" "+a(e.$t("link.generate_new_token")),1)],32)]),t(c).length>0?(n(),u("div",Se,[(n(!0),u(re,null,ue(t(c),s=>(n(),u("div",{key:s.id,class:"group-item is-size-5 is-size-6-mobile"},[s.value?(n(),V(t(ve),{key:0,class:"mr-1 has-text-success inline"})):m("",!0),b(a(s.name)+" ",1),l("div",xe,[i(t(fe),null,{default:r(({mode:P})=>[s.value?(n(),u("button",{key:0,type:"button",class:F(["button tag",P!="dark"?"is-link":"is-white"]),onClick:L(Q=>H(s.value),["stop"])},a(e.$t("label.copy")),11,Ve)):m("",!0),l("button",{type:"button",class:F(["button tag",P==="dark"?"is-dark":"is-white"]),onClick:Q=>I(s.id),title:e.$t("tooltip.revoke")},a(e.$t("label.revoke")),11,Fe)]),_:2},1024)]),x(s.expires_at)<0?(n(),u("span",ze,a(e.$t("message.expired_since_x",{expired_at:new Date(s.expires_at).toLocaleDateString()})),1)):(n(),u("span",{key:2,class:F(["is-family-primary is-size-6 is-size-7-mobile has-text-warning",x(s.expires_at)<=7?"has-text-warning":"has-text-grey"])},a(eLine truncated
+1
View File
@@ -0,0 +1 @@
import{u as ce,a as de,O as Ae,P as me,a8 as ve,o as pe,af as fe,d as xe,w as p,M as ge,e as h,f,a7 as x,h as _,i as r,j as a,a4 as D,l as V,m as u,t as c,k as E,p as O,D as ke,n as he,ak as be,B as M,$ as L,a1 as b}from"./app-dvJP63FL.js";import{t as Pe}from"./tabs-Btun2NN0.js";import{i as _e,R as Ce}from"./iconService-rm6LRV4U.js";import{u as ye}from"./breakpoints-CyLcIEOu.js";import{E as T}from"./external-link-CqpXNovN.js";import"./createLucideIcon-DsaEAGzP.js";let Se=[{text:"Africa/Abidjan",value:"Africa/Abidjan"},{text:"Africa/Accra",value:"Africa/Accra"},{text:"Africa/Addis_Ababa",value:"Africa/Addis_Ababa"},{text:"Africa/Algiers",value:"Africa/Algiers"},{text:"Africa/Asmara",value:"Africa/Asmara"},{text:"Africa/Asmera",value:"Africa/Asmera"},{text:"Africa/Bamako",value:"Africa/Bamako"},{text:"Africa/Bangui",value:"Africa/Bangui"},{text:"Africa/Banjul",value:"Africa/Banjul"},{text:"Africa/Bissau",value:"Africa/Bissau"},{text:"Africa/Blantyre",value:"Africa/Blantyre"},{text:"Africa/Brazzaville",value:"Africa/Brazzaville"},{text:"Africa/Bujumbura",value:"Africa/Bujumbura"},{text:"Africa/Cairo",value:"Africa/Cairo"},{text:"Africa/Casablanca",value:"Africa/Casablanca"},{text:"Africa/Ceuta",value:"Africa/Ceuta"},{text:"Africa/Conakry",value:"Africa/Conakry"},{text:"Africa/Dakar",value:"Africa/Dakar"},{text:"Africa/Dar_es_Salaam",value:"Africa/Dar_es_Salaam"},{text:"Africa/Djibouti",value:"Africa/Djibouti"},{text:"Africa/Douala",value:"Africa/Douala"},{text:"Africa/El_Aaiun",value:"Africa/El_Aaiun"},{text:"Africa/Freetown",value:"Africa/Freetown"},{text:"Africa/Gaborone",value:"Africa/Gaborone"},{text:"Africa/Harare",value:"Africa/Harare"},{text:"Africa/Johannesburg",value:"Africa/Johannesburg"},{text:"Africa/Juba",value:"Africa/Juba"},{text:"Africa/Kampala",value:"Africa/Kampala"},{text:"Africa/Khartoum",value:"Africa/Khartoum"},{text:"Africa/Kigali",value:"Africa/Kigali"},{text:"Africa/Kinshasa",value:"Africa/Kinshasa"},{text:"Africa/Lagos",value:"Africa/Lagos"},{text:"Africa/Libreville",value:"Africa/Libreville"},{text:"Africa/Lome",value:"Africa/Lome"},{text:"Africa/Luanda",value:"Africa/Luanda"},{text:"Africa/Lubumbashi",value:"Africa/Lubumbashi"},{text:"Africa/Lusaka",value:"Africa/Lusaka"},{text:"Africa/Malabo",value:"Africa/Malabo"},{text:"Africa/Maputo",value:"Africa/Maputo"},{text:"Africa/Maseru",value:"Africa/Maseru"},{text:"Africa/Mbabane",value:"Africa/Mbabane"},{text:"Africa/Mogadishu",value:"Africa/Mogadishu"},{text:"Africa/Monrovia",value:"Africa/Monrovia"},{text:"Africa/Nairobi",value:"Africa/Nairobi"},{text:"Africa/Ndjamena",value:"Africa/Ndjamena"},{text:"Africa/Niamey",value:"Africa/Niamey"},{text:"Africa/Nouakchott",value:"Africa/Nouakchott"},{text:"Africa/Ouagadougou",value:"Africa/Ouagadougou"},{text:"Africa/Porto-Novo",value:"Africa/Porto-Novo"},{text:"Africa/Sao_Tome",value:"Africa/Sao_Tome"},{text:"Africa/Timbuktu",value:"Africa/Timbuktu"},{text:"Africa/Tripoli",value:"Africa/Tripoli"},{text:"Africa/Tunis",value:"Africa/Tunis"},{text:"Africa/Windhoek",value:"Africa/Windhoek"},{text:"America/Adak",value:"America/Adak"},{text:"America/Anchorage",value:"America/Anchorage"},{text:"America/Anguilla",value:"America/Anguilla"},{text:"America/Antigua",value:"America/Antigua"},{text:"America/Araguaina",value:"America/Araguaina"},{text:"America/Argentina/Buenos_Aires",value:"America/Argentina/Buenos_Aires"},{text:"America/Argentina/Catamarca",value:"America/Argentina/Catamarca"},{text:"America/Argentina/ComodRivadavia",value:"America/Argentina/ComodRivadavia"},{text:"America/Argentina/Cordoba",value:"America/Argentina/Cordoba"},{text:"America/Argentina/Jujuy",value:"America/Argentina/Jujuy"},{text:"America/Argentina/La_Rioja",value:"America/Argentina/La_Rioja"},{text:"America/Argentina/Mendoza",value:"America/Argentina/Mendoza"},{text:"America/Argentina/Rio_Gallegos",value:"America/Argentina/Rio_Gallegos"},{text:"America/Argentina/Salta",value:"America/Argentina/Salta"},{text:"America/Argentina/San_Juan",value:"America/Argentina/San_Juan"},{text:"America/Argentina/San_Luis",value:"America/Argentina/San_Luis"},{text:"America/Argentina/Tucuman",value:"America/Argentina/Tucuman"},{text:"America/Argentina/Ushuaia",value:"America/Argentina/Ushuaia"},{text:"America/Aruba",value:"America/Aruba"},{text:"America/Asuncion",value:"America/Asuncion"},{text:"America/Atikokan",value:"America/Atikokan"},{text:"America/Atka",value:"America/Atka"},{text:"America/Bahia",value:"America/Bahia"},{text:"America/Bahia_Banderas",value:"America/Bahia_Banderas"},{text:"America/Barbados",value:"America/Barbados"},{text:"America/Belem",value:"America/Belem"},{text:"America/Belize",value:"America/Belize"},{text:"America/Blanc-Sablon",value:"America/Blanc-Sablon"},{text:"America/Boa_Vista",value:"America/Boa_Vista"},{text:"America/Bogota",value:"America/Bogota"},{text:"America/Boise",value:"America/Boise"},{text:"America/Buenos_Aires",value:"America/Buenos_Aires"},{text:"America/Cambridge_Bay",value:"America/Cambridge_BLine truncated
+1
View File
@@ -0,0 +1 @@
import{U as x}from"./index-BJsmINgd.js";import{S as Y,T as A,M as F,C as K,a as E}from"./tablet-DYUfDfjC.js";import{X as U}from"./x-DQVIq0xP.js";import{C as j}from"./check-CPGWPXZa.js";import{M as P,f as w,h as a,l as y,i as m,w as d,F as L,m as e,d as c,t as o,j as n,p as S,n as _,k as M,C as R,e as C,o as W,a1 as z,I as X,D as H,X as J,E as G,B as Q,b as Z,g as tt}from"./app-dvJP63FL.js";import{_ as et}from"./TwofaccountMedia-DzLyeBxh.js";import"./createLucideIcon-DsaEAGzP.js";const ot={class:"list-item is-size-6 is-size-7-mobile has-text-grey is-flex is-justify-content-space-between"},st={class:"light-or-darker"},nt={class:"light-or-darker"},at={class:"light-or-darker"},lt={class:"light-or-darker"},rt={class:"light-or-darker"},it={class:"light-or-darker"},ut={class:"light-or-darker"},ct={class:"log-icon-wrapper"},gt={key:1},dt={class:"light-or-darker"},ht={class:"light-or-darker"},pt={class:"light-or-darker"},yt={class:"light-or-darker"},_t={class:"light-or-darker"},mt={__name:"LogItem",props:{log:{type:Object,required:!0},logType:{type:String,required:!0,validator(t,f){return["auth","otp"].includes(t)}}},setup(t){const f=P("2fauth"),k=t,i=l=>!l.login_at&&l.logout_at,u=l=>!l.login_successful&&!l.logout_at;return(l,b)=>{const g=w("i18n-t");return a(),y("div",ot,[m(n(x),null,{default:d(({mode:h})=>[k.logType=="auth"?(a(),y(L,{key:0},[e("div",null,[e("div",null,[u(t.log)?(a(),c(g,{key:0,keypath:"message.failed_login_on",tag:"span"},{login_at:d(()=>[e("span",st,o(t.log.login_at),1)]),_:1})):i(t.log)?(a(),c(g,{key:1,keypath:"message.successful_logout_on",tag:"span"},{logout_at:d(()=>[e("span",nt,o(t.log.logout_at),1)]),_:1})):n(f).config.proxyAuth?(a(),c(g,{key:2,keypath:"message.viewed_on",tag:"span"},{login_at:d(()=>[e("span",at,o(t.log.login_at),1)]),_:1})):(a(),c(g,{key:3,keypath:"message.successful_login_on",tag:"span"},{login_at:d(()=>[e("span",lt,o(t.log.login_at),1)]),_:1}))]),e("div",null,[S(o(l.$t("label.IP"))+": ",1),e("span",rt,o(t.log.ip_address),1),S(" - "+o(l.$t("label.browser"))+": ",1),e("span",it,o(t.log.browser),1),S(" - "+o(l.$t("label.operating_system_short"))+": ",1),e("span",ut,o(t.log.platform),1)])]),e("div",{class:_([h=="dark"?"has-text-grey-darker":"has-text-grey-lighter","is-align-self-center"])},[e("div",ct,[t.log.device=="phone"?(a(),c(n(Y),{key:0,class:"log-icon-bg"})):t.log.device=="tablet"?(a(),c(n(A),{key:1,class:"log-icon-bg"})):(a(),c(n(F),{key:2,class:"log-icon-bg"})),u(t.log)?(a(),c(n(U),{key:3,"stroke-width":"3",class:_(["log-icon-mark","has-text-danger"])})):(a(),c(n(j),{key:4,"stroke-width":"3",class:_(["log-icon-mark","has-text-success-50"])}))])],2)],64)):k.logType=="otp"?(a(),y("div",gt,[m(g,{keypath:"message.otp_generated_by_on",tag:"span"},{otp:d(()=>[e("span",dt,o(t.log.otp_type.toUpperCase()),1)]),requester:d(()=>[e("span",ht,o(t.log.requester_name)+" ("+o(t.log.requester_email)+")",1)]),generated_at:d(()=>[e("span",pt,o(new Date(t.log.generated_at).toLocaleString()),1)]),_:1}),S(" - "+o(l.$t("label.IP"))+": ",1),e("span",yt,o(t.log.ip_address),1),t.log.otp_type=="hotp"?(a(),y(L,{key:0},[S(o(" - "+l.$t("label.counter"))+": ",1),e("span",_t,o(t.log.counter),1)],64)):M("",!0)])):M("",!0)]),_:1})])}}},ft={key:1,class:"level is-mobile mb-2"},kt={class:"level-item has-text-centered"},bt={class:"buttons"},vt=["title"],wt=["title"],$t=["title"],St=["title"],Ct=["title"],It=["title"],Lt={key:3,class:"mt-4"},Mt={key:4},Tt={key:5,class:"mt-5 pl-3"},Nt={__name:"LogViewer",props:{twofaccountId:[Number,String],userId:[Number,String],lastOnly:Boolean,showSearch:Boolean,period:{type:[Number,String],default:12},logType:{type:String,required:!0,validator(t,f){return["auth","otp"].includes(t)}},sortingKey:{type:String,required:!0}},emits:["has-more-entries"],setup(t,{emit:f}){const k=R(),i=t,u={aMonth:1,threeMonths:3,halfYear:6,aYear:12},l=C([]),b=C(!1),g=C(""),h=C(i.period),v=C(!0),T=f,N=Q(()=>l.value.filter(s=>JSON.stringify(s).toString().toLowerCase().includes(g.value)));W(()=>{D()});function I(s){h.value=s,D()}function V(){v.value=!1,B()}function B(){l.value.sort((s,r)=>s[i.sortingKey]>r[i.sortingKey]?1:-1)}function q(){v.value=!0,O()}function O(){l.value.sort((s,r)=>s[i.sortingKey]<r[i.sortingKey]?1:-1)}function D(){b.value=!0;let s=i.lastOnly?4:!1,r;i.logType==="auth"?r=z.getauthentications(i.userId,h.value,s,{returnError:!0}):i.logType==="otp"&&(r=X.getOtpLogs(i.twofaccountId,h.value,s,{returnError:!0})),r.then($=>{l.value=$.data,l.value.length>3&&i.lastOnly&&(T("has-more-entries"),l.value.pop()),v.value==!0?O():B()}).catch($=>{k.show($)}).finally(()=>{b.value=!1})}return(s,r)=>{const $=w("Spinner");return a(),y(L,null,[i.showSearch?(a(),c(n(J),{key:0,keyword:n(g),"onUpdate:keyword":r[0]||(r[0]=p=>H(g)?g.value=p:null),hasNoBackground:!0},null,8,["keyword"])):M("",!0),i.showSearch?(a(),y("nav",ft,[e("div",kt,[e("div",bt,[e("button",{id:"btnShowOneMonth",title:s.$t("tooltip.show_last_month_log"),onClick:r[1]||(r[1]=p=>I(u.aMonth)),class:_([{"has-text-grey":n(h)!==u.aMonth},Line truncated
+1
View File
@@ -0,0 +1 @@
import{a6 as f,I as h,l as r,m as s,j as a,k as v,i as l,w as i,a2 as w,e as y,f as n,g as B,h as c,d as V,p as b,t as N}from"./app-dvJP63FL.js";const x={class:"modal modal-otp is-active"},R={class:"modal-card is-flex-grow-1"},S={class:"modal-card-body modal-slot py-0 is-align-content-center has-text-centered"},$={class:"has-text-centered m-5"},q=["src","alt"],C={key:1},T={__name:"QRcode",setup(Q){const d=B(),u=w(),t=y();f(()=>{_()});async function _(){const{data:e}=await h.getQrcode(u.params.twofaccountId);t.value=e.qrcode}return(e,o)=>{const m=n("Spinner"),p=n("NavigationButton"),g=n("router-link"),k=n("VueFooter");return c(),r("div",x,[o[1]||(o[1]=s("div",{class:"modal-background"},null,-1)),s("div",R,[s("section",S,[s("p",$,[a(t)?(c(),r("img",{key:0,src:a(t),class:"qrcode has-background-light",alt:e.$t("alttext.image_of_qrcode_to_scan")},null,8,q)):v("",!0),l(m,{isVisible:!a(t),type:"raw",rawSize:32},null,8,["isVisible"])])]),l(k,null,{default:i(()=>[l(p,{action:"close",onClosed:o[0]||(o[0]=F=>a(d).push({name:"accounts"})),"current-page-title":e.$t("title.showQRcode")},null,8,["current-page-title"])]),subpart:i(()=>[e.$route.name!="accounts"?(c(),V(g,{key:0,id:"lnkBackToHome",to:{name:"accounts"},class:"has-text-grey"},{default:i(()=>[b(N(e.$t("link.back_to_home")),1)]),_:1})):(c(),r("span",C," "))]),_:1})])])}}};export{T as default};
@@ -0,0 +1 @@
import{N as m,u as v,h as a,l as r,m as n,t as s,H as C,k as l,i as f,j as w,F as y,$ as _}from"./app-dvJP63FL.js";import{E as $}from"./external-link-CqpXNovN.js";const g={class:"block"},h={class:"block mb-6 light-or-darker"},q={key:0,class:"block has-text-link"},E={type:"button",class:"button is-link is-outlined is-rounded"},x={class:"icon is-small"},I={__name:"QrContentDisplay",props:{qrContent:String},setup(o){const{copy:c}=m({legacy:!0}),{t:u}=v(),d=_();function b(e){var t=/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/,i=new RegExp(t);return i.test(e)}function k(e){const t=document.createElement("a");t.setAttribute("href",e),t.dispatchEvent(new MouseEvent("click",{view:window,bubbles:!0,cancelable:!0}))}function p(e){c(e),d.success({text:u("notification.copied_to_clipboard")})}return(e,t)=>(a(),r(y,null,[t[2]||(t[2]=n("div",{class:"too-bad"},null,-1)),n("div",g,s(e.$t("error.data_of_qrcode_is_not_valid_URI")),1),n("div",h,s(o.qrContent?o.qrContent:"["+e.$t("message.nothing")+"]"),1),o.qrContent?(a(),r("div",q,[n("button",{type:"button",class:"button is-link is-outlined is-rounded",onClick:t[0]||(t[0]=C(i=>p(o.qrContent),["stop"]))},s(e.$t("label.copy_to_clipboard")),1)])):l("",!0),b(o.qrContent)?(a(),r("div",{key:1,class:"block has-text-link",onClick:t[1]||(t[1]=i=>k(o.qrContent))},[n("button",E,[n("span",null,s(e.$t("label.open_in_browser")),1),n("span",x,[f(w($))])])])):l("",!0)],64))}};export{I as _};
+1
View File
@@ -0,0 +1 @@
import{C as R,u as C,a8 as $,r as x,af as L,d as N,w as u,M as S,a2 as q,f as t,g as A,h as D,i as r,m as i,j as s,H as M,p,t as m,$ as W}from"./app-dvJP63FL.js";import{F as P}from"./Form-ZbAUhXmz.js";const j={class:"field"},U={__name:"Recover",setup(H){const f=R(),{t:_}=C(),w=S("2fauth"),n=W(),d=A(),c=q(),b=$(w.prefix+"showWebauthnForm",!1),o=x(new P({email:c.query.email,password:"",token:c.query.token,revokeAll:!1}));function h(l){n.clear(),o.post("/webauthn/recover",{returnError:!0}).then(e=>{b.value=!1,d.push({name:"accounts"})}).catch(e=>{e.response.status===401?n.alert({text:_("notification.authentication_failed"),duration:-1}):e.response.status===422?n.alert({text:e.response.data.message,duration:-1}):f.show(e)})}return L(()=>{n.clear()}),(l,e)=>{const v=t("FormCheckbox"),k=t("FormPasswordField"),y=t("RouterLink"),F=t("FormButtons"),g=t("FormWrapper"),V=t("VueFooter"),B=t("StackLayout");return D(),N(B,null,{content:u(()=>[r(g,{title:"heading.account_recovery",punchline:"message.recover_account_instructions"},{default:u(()=>[i("div",null,[i("form",{onSubmit:M(h,["prevent"]),onKeydown:e[3]||(e[3]=a=>s(o).onKeydown(a))},[r(v,{modelValue:s(o).revokeAll,"onUpdate:modelValue":e[0]||(e[0]=a=>s(o).revokeAll=a),fieldName:"revokeAll",label:"field.disable_all_security_devices",help:"field.disable_all_security_devices.help"},null,8,["modelValue"]),r(k,{modelValue:s(o).password,"onUpdate:modelValue":e[1]||(e[1]=a=>s(o).password=a),fieldName:"password",errorMessage:s(o).errors.get("password"),autocomplete:"current-password",showRules:!1,label:"field.current_password",help:"field.current_password.help"},null,8,["modelValue","errorMessage"]),i("div",j,[i("p",null,[p(m(l.$t("message.forgot_your_password"))+"  ",1),r(y,{id:"lnkResetPwd",to:{name:"password.request"},class:"is-link","aria-label":l.$t("label.reset_your_password")},{default:u(()=>[p(m(l.$t("link.request_password_reset")),1)]),_:1},8,["aria-label"])])]),r(F,{submitId:"btnRecover",isBusy:s(o).isBusy,isDisabled:s(o).isDisabled,submitLabel:"label.continue",showCancelButton:!0,onCancel:e[2]||(e[2]=a=>s(d).push({name:"login"}))},null,8,["isBusy","isDisabled"])],32)])]),_:1})]),footer:u(()=>[r(V)]),_:1})}}};export{U as default};
+1
View File
@@ -0,0 +1 @@
import{C as U,u as x,a as P,P as W,r as k,af as j,d as b,w as u,f as r,g as A,h as c,i as n,j as s,m as i,t as d,l as F,p as f,H as V,e as S,$ as H}from"./app-dvJP63FL.js";import{F as B}from"./Form-ZbAUhXmz.js";import{w as O}from"./webauthnService-D363et0U.js";import{C as E}from"./check-CPGWPXZa.js";import"./createLucideIcon-DsaEAGzP.js";const J={class:"block"},Y={key:0,class:"field"},q={id:"lblDeviceRegistrationSuccess",class:"label mb-5"},z={key:1,class:"field is-grouped"},G={class:"control"},Q={class:"control"},X={class:"block"},Z={class:"nav-links"},ie={__name:"Register",setup(ee){const D=U(),{t:R}=x(),y=P(),_=H(),$=A(),w=S(!1),L=W(),g=S(null),t=k(new B({name:"",email:"",password:"",password_confirmation:""})),l=k(new B({name:""}));async function M(a){t.password_confirmation=t.password,t.post("/user").then(e=>{y.$patch({id:e.data.id,name:e.data.name,email:e.data.email,preferences:e.data.preferences,isAdmin:e.data.is_admin??!1}),y.applyTheme();for(const[m,p]of Object.entries(e?.data?.appSettings||{}))L[m]=p;w.value=!0})}function N(){O.register().then(a=>{const e=JSON.parse(a.config.data);g.value=e.id}).catch(a=>{a.response.status===422?_.alert({text:a.response.data.message}):D.show(a)})}function C(a){l.patch("/webauthn/credentials/"+g.value+"/name").then(()=>{_.success({text:R("notification.device_successfully_registered")}),$.push({name:"accounts"})})}return j(()=>{_.clear()}),(a,e)=>{const m=r("FormField"),p=r("FormButtons"),h=r("RouterLink"),v=r("FormWrapper"),T=r("FormPasswordField"),I=r("VueFooter"),K=r("StackLayout");return c(),b(K,null,{content:u(()=>[s(w)?(c(),b(v,{key:0,title:"heading.authentication",punchline:"message.enhance_security_using_webauthn"},{default:u(()=>[i("div",J,d(a.$t("message.webauthn_uses_trusted_devices")),1),s(g)?(c(),F("div",Y,[i("label",q,[f(d(a.$t("notification.device_successfully_registered")),1),n(s(E),{class:"ml-1 inline"})]),i("form",{onSubmit:V(C,["prevent"]),onKeydown:e[1]||(e[1]=o=>s(l).onKeydown(o))},[n(m,{modelValue:s(l).name,"onUpdate:modelValue":e[0]||(e[0]=o=>s(l).name=o),fieldName:"name",errorMessage:s(l).errors.get("name"),inputType:"text",placeholder:"iPhone 12, TouchID, Yubikey 5C",label:"field.name_this_device"},null,8,["modelValue","errorMessage"]),n(p,{isBusy:s(l).isBusy,isDisabled:s(l).isDisabled,submitLabel:"label.continue"},null,8,["isBusy","isDisabled"])],32)])):(c(),F("div",z,[i("div",G,[i("button",{type:"button",id:"btnRegisterNewDevice",onClick:e[2]||(e[2]=o=>N()),class:"button is-link"},d(a.$t("label.register_a_device")),1)]),i("div",Q,[n(h,{id:"btnMaybeLater",to:{name:"accounts"},class:"button is-text"},{default:u(()=>[f(d(a.$t("link.maybe_later")),1)]),_:1})])]))]),_:1})):(c(),b(v,{key:1,title:"heading.register",punchline:"message.welcome_to_2fauth"},{default:u(()=>[i("div",X,d(a.$t("message.you_need_an_account_to_go_further")),1),i("form",{onSubmit:V(M,["prevent"]),onKeydown:e[6]||(e[6]=o=>s(t).onKeydown(o))},[n(m,{modelValue:s(t).name,"onUpdate:modelValue":e[3]||(e[3]=o=>s(t).name=o),fieldName:"name",errorMessage:s(t).errors.get("name"),inputType:"text",label:"field.name",autocomplete:"username",maxLength:255,autofocus:""},null,8,["modelValue","errorMessage"]),n(m,{modelValue:s(t).email,"onUpdate:modelValue":e[4]||(e[4]=o=>s(t).email=o),fieldName:"email",errorMessage:s(t).errors.get("email"),inputType:"email",label:"field.email",autocomplete:"email",maxLength:255},null,8,["modelValue","errorMessage"]),n(T,{modelValue:s(t).password,"onUpdate:modelValue":e[5]||(e[5]=o=>s(t).password=o),fieldName:"password",errorMessage:s(t).errors.get("password"),showRules:!0,autocomplete:"new-password",label:"field.password"},null,8,["modelValue","errorMessage"]),n(p,{isBusy:s(t).isBusy,isDisabled:s(t).isDisabled,submitLabel:"label.register",submitId:"btnRegister"},null,8,["isBusy","isDisabled"])],32),i("div",Z,[i("p",null,[f(d(a.$t("message.already_register"))+" ",1),n(h,{id:"lnkSignIn",to:{name:"login"},class:"is-link"},{default:u(()=>[f(d(a.$t("link.sign_in")),1)]),_:1})])])]),_:1}))]),footer:u(()=>[n(I)]),_:1})}}};export{ie as default};
@@ -0,0 +1 @@
import{C as y,r as F,af as h,d as g,w as i,a2 as B,f as n,h as m,i as u,l as k,t as v,k as V,m as R,j as o,H as C,a4 as L,$ as S}from"./app-dvJP63FL.js";import{F as q}from"./Form-ZbAUhXmz.js";const N={key:0,class:"block"},E={__name:"RequestReset",setup($){const c=y(),a=S(),s=B().name=="webauthn.lost",t=F(new q({email:""}));function d(r){a.clear(),t.post(s?"/webauthn/lost":"/user/password/lost",{returnError:!0}).then(e=>{a.success({text:e.data.message,duration:-1})}).catch(e=>{e.response.data.requestFailed?a.alert({text:e.response.data.requestFailed,duration:-1}):e.response.status!==422&&c.show(e)})}return h(()=>{a.clear()}),(r,e)=>{const p=n("FormField"),_=n("FormButtons"),f=n("FormWrapper"),w=n("VueFooter"),b=n("StackLayout");return m(),g(b,null,{content:i(()=>[u(f,{title:s?"heading.account_recovery":"heading.reset_password",punchline:s?"message.recovery_punchline":"message.reset_punchline"},{default:i(()=>[s?(m(),k("div",N,v(r.$t("message.ensure_you_open_mail_in_trusted_device")),1)):V("",!0),R("form",{onSubmit:C(d,["prevent"]),onKeydown:e[2]||(e[2]=l=>o(t).onKeydown(l))},[u(p,{modelValue:o(t).email,"onUpdate:modelValue":e[0]||(e[0]=l=>o(t).email=l),fieldName:"email",errorMessage:o(t).errors.get("email"),label:"field.email",autofocus:""},null,8,["modelValue","errorMessage"]),u(_,{submitId:"btnSendResetPwd",isBusy:o(t).isBusy,submitLabel:s?"label.send_recovery_link":"label.send_password_reset_link",showCancelButton:!0,onCancel:e[1]||(e[1]=l=>("router"in r?r.router:o(L)).push({name:"login"}))},null,8,["isBusy","submitLabel"])],32)]),_:1},8,["title","punchline"])]),footer:i(()=>[u(w)]),_:1})}}};export{E as default};
+1
View File
@@ -0,0 +1 @@
import{C,r as v,af as L,d as n,w as a,a2 as N,f as t,g as x,h as l,i as u,m as M,j as s,H as P,k as m,p as h,t as S,e as $,$ as E}from"./app-dvJP63FL.js";import{F as q}from"./Form-ZbAUhXmz.js";const U={__name:"Reset",setup(D){const f=C(),i=E(),w=x(),p=N(),d=$(!0),e=v(new q({email:p.query.email,password:"",password_confirmation:"",token:p.query.token}));function _(c){e.password_confirmation=e.password,e.post("/user/password/reset",{returnError:!0}).then(o=>{e.password="",e.password_confirmation="",d.value=!1,i.success({text:o.data.message,duration:-1})}).catch(o=>{o.response.data.resetFailed?i.alert({text:o.response.data.resetFailed,duration:-1}):o.response.status!==422&&f.show(o)})}return L(()=>{i.clear()}),(c,o)=>{const F=t("FormField"),k=t("FormPasswordField"),g=t("FormFieldError"),y=t("FormButtons"),V=t("RouterLink"),b=t("FormWrapper"),B=t("VueFooter"),R=t("StackLayout");return l(),n(R,null,{content:a(()=>[u(b,{title:"heading.new_password"},{default:a(()=>[M("form",{onSubmit:P(_,["prevent"]),onKeydown:o[3]||(o[3]=r=>s(e).onKeydown(r))},[u(F,{modelValue:s(e).email,"onUpdate:modelValue":o[0]||(o[0]=r=>s(e).email=r),isDisabled:!0,fieldName:"email",errorMessage:s(e).errors.get("email"),label:"field.email",autofocus:""},null,8,["modelValue","errorMessage"]),u(k,{modelValue:s(e).password,"onUpdate:modelValue":o[1]||(o[1]=r=>s(e).password=r),fieldName:"password",errorMessage:s(e).errors.get("password"),autocomplete:"new-password",showRules:!0,label:"field.new_password"},null,8,["modelValue","errorMessage"]),s(e).errors.get("token")!=null?(l(),n(g,{key:0,error:s(e).errors.get("token"),field:s(e).token},null,8,["error","field"])):m("",!0),s(d)?(l(),n(y,{key:1,submitId:"btnResetPwd",isBusy:s(e).isBusy,submitLabel:"label.change_password",showCancelButton:!0,onCancel:o[2]||(o[2]=r=>s(w).push({name:"login"}))},null,8,["isBusy"])):m("",!0),s(d)?m("",!0):(l(),n(V,{key:2,id:"btnContinue",to:{name:"accounts"},class:"button is-link"},{default:a(()=>[h(S(c.$t("link.continue")),1)]),_:1}))],32)]),_:1})]),footer:a(()=>[u(B)]),_:1})}}};export{U as default};
+1
View File
@@ -0,0 +1 @@
import{b as Y,a8 as Z,a9 as ee,aa as se,e as d,o as te,I as oe,a6 as ae,ab as ne,v as ie,d as L,w as C,M as re,f as F,g as le,a2 as ce,a7 as ue,h as a,i as p,j as t,m as s,t as i,p as M,H as de,n as _,y as he,D as fe,ac as me,l as r,F as v,E as N,k as pe,B as $}from"./app-dvJP63FL.js";import{s as j}from"./shareService-BU7jlLil.js";import{_ as _e}from"./TwofaccountMedia-DzLyeBxh.js";import{u as ve}from"./bus-ChE1sp8V.js";import{a as ge}from"./helpers-B2oe4lHy.js";import{U as we}from"./index-BJsmINgd.js";import{c as D}from"./createLucideIcon-DsaEAGzP.js";const ke=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],ye=D("loader-circle",ke);const Se=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],be=D("search",Se),Ce={class:"title"},Fe={class:"block is-size-7-mobile"},$e={class:"field"},Be={for:"findUserForShare",class:"label"},Ie={class:"dropdown-trigger"},Te={class:"field"},Ue={class:"control has-icons-right"},Re={class:"icon is-right"},Le=["title"],Me={class:"dropdown-menu",id:"dropdown-menu",role:"menu"},Ne={class:"dropdown-content is-shadowless"},je=["onClick"],De={key:1,class:"dropdown-item has-text-grey"},We={key:0,class:"dropdown-item has-text-grey"},ze={key:1,class:"dropdown-item is-italic"},Ae={class:"help"},Ee={class:"mb-5"},Ve={key:0,class:"field is-grouped is-grouped-multiline"},xe={class:"tags has-addons are-medium"},He=["onClick"],Ke={class:"block is-size-7-mobile has-text-grey"},Ye={__name:"Share",props:{twofaccountId:[Number,String]},setup(W){const z=re("2fauth"),B=le(),A=ce();ve();const E=Y(),I=Z(z.prefix+"returnTo","accountSharing"),h=W;ee("Escape",e=>{e.preventDefault(),y()});const V=ue("findUserForShare"),{focused:x}=se(V),T=d(E.items.find(e=>e.id==h.twofaccountId)),U=d(!1),f=d(!1),g=d(!1),u=d(""),m=d(null),l=d([]),H=$(()=>I.value=="accountSharing"?{name:"accountSharing",params:{twofaccountId:A.params.twofaccountId}}:{name:I.value}),K=$(()=>m.value?.length>0),O=$(()=>l.value.length>0);let w=null,c=null;te(()=>{U.value=!0,oe.get(h.twofaccountId).then(e=>{T.value=e.data}).finally(()=>{U.value=!1})}),ae(()=>{}),ne(()=>{y()}),ie(u,e=>{w&&clearTimeout(w),e.length==0?k():w=setTimeout(()=>{e.length>1&&Q(e)},300)});function Q(e){c?.abort(),c=new AbortController;const o=c,S=setTimeout(()=>{o===c&&(f.value=!0)},250);j.getRecipients(h.twofaccountId,e,{signal:c.signal}).then(b=>{m.value=ge(b.data)}).finally(()=>{clearTimeout(S),o===c&&(f.value=!1)})}function q(e){l.value.some(o=>o.id==e.id)||l.value.push(e),k(),u.value="",x.value=!0}function k(){m.value=null}function G(e){for(var o=0;o<l.value.length;o++)if(l.value[o].id===e.id){l.value.splice(o,1);return}}function y(){c?.abort(),c=null,u.value="",k(),f.value=!1}function J(){g.value=!0,l.value.length>0&&j.shareWithUsers(h.twofaccountId,l.value.map(e=>e.id)).then(e=>{B.push({name:"accountSharing",params:{twofaccountId:h.twofaccountId}})}).finally(()=>{g.value=!1})}return(e,o)=>{const S=F("FormButtons"),b=F("ResponsiveWidthWrapper"),P=F("StackLayout");return a(),L(P,null,{content:C(()=>[p(t(we),null,{default:C(({mode:R})=>[p(b,null,{default:C(()=>[s("h1",Ce,i(e.$t("heading.new_sharing")),1),s("div",Fe,[M(i(e.$t("message.share_account_with_other_users")),1),o[2]||(o[2]=s("br",null,null,-1)),M(" "+i(e.$t("message.this_form_does_not_affect_existing_sharing")),1)]),p(_e,{twofaccount:t(T)},null,8,["twofaccount"]),s("form",{onSubmit:de(J,["prevent"])},[s("div",$e,[s("label",Be,i(e.$t("field.findUserForShare")),1),s("div",{class:_(["control",{"has-icons-left":e.leftIcon,"has-icons-right":e.rightIcon}])},[s("div",{class:_(["dropdown",{"is-active":t(m)||t(f)}])},[s("div",Ie,[s("div",Te,[s("p",Ue,[he(s("input",{ref:"findUserForShare",id:"findUserForShare","onUpdate:modelValue":o[0]||(o[0]=n=>fe(u)?u.value=n:null),type:"text",class:"input",autofocus:""},null,512),[[me,t(u)]]),s("span",Re,[t(u)!=""?(a(),r("button",{key:0,type:"button",id:"btnClearSearch",tabindex:"1",title:e.$t("tooltip.clear_search"),class:"clear-selection delete",onClick:y},null,8,Le)):(a(),L(t(be),{key:1}))])])])]),s("div",Me,[s("div",Ne,[t(K)?(a(!0),r(v,{key:0},N(t(m),n=>(a(),r(v,{key:n.id},[n.is_shared_with?(a(),r("span",De,i(n.name)+" ("+i(e.$t("message.already_shared"))+") ",1)):(a(),r("a",{key:0,onClick:X=>q(n),class:"dropdown-item"},i(n.name),9,je))],64))),128)):(a(),r(v,{key:1},[t(f)?(a(),r("span",We,[p(t(ye),{class:"spinning"})])):(a(),r("span",ze,i(e.$t("message.no_match")),1))],64))])])],2)],2),s("p",Ae,i(e.$t("field.findUserForShare.help")),1)]),s("div",Ee,[t(l).length>0?(a(),r("div",Ve,[(a(!0),r(v,null,N(t(l),n=>(a(),r("div",{key:n.id,class:"control"},[s("div",xe,[s("span",{class:_(["tag",R=="dark"?"is-dark":"is-white"])},i(n.name),3),s("button",{onClick:X=>G(n),class:_(["tag is-delete",R=="dark"?"is-black":"is-dark"])},null,10,He)])]))),128))])):pe("",!0)]),s("div",Ke,i(e.$t("message.keep_in_mind_share_principle")),1),p(S,{isDisabled:!t(O),isBusy:t(g),submitLabel:"label.share",showCancelButton:!0,onCancel:o[1]||(o[1]=n=>t(B).push(Line truncated
+1
View File
@@ -0,0 +1 @@
import{u as D,a as Q,b as K,r as M,o as P,c as T,d as k,w as c,e as b,f as i,$ as j,g as z,h as a,i as $,j as n,k as C,l as _,m as o,n as L,p as r,t as s,q as S}from"./app-dvJP63FL.js";import{F as G}from"./Form-ZbAUhXmz.js";import{u as O}from"./bus-ChE1sp8V.js";const H={key:1,class:"has-text-centered"},J={class:"quick-uploader-wrapper p-0 mt-6 mb-5"},W={class:"quick-uploader-button is-align-content-center"},X={class:"block light-or-darker"},Y={key:0,class:"block has-text-link"},Z={class:"block has-text-link"},ee={class:"block has-text-link"},te={class:"block"},re={__name:"Start",setup(oe){const{t:E}=D(),d=z(),p=Q(),w=O(),B=j(),F=K(),g=b(null),l=b(null),u=M(new G({qrcode:null,inputFormat:"fileUpload"})),v=b(!1),m=b(!1);function y(t){u.clear(),u.qrcode=t??g.value.files[0],u.upload("/api/v1/qrcode/decode",{returnError:!0}).then(e=>{e.data.data.slice(0,33).toLowerCase()==="otpauth-migration://offline?data="?(w.migrationUri=e.data.data,d.push({name:"importAccounts"})):(w.decodedUri=e.data.data,d.push({name:"createAccount"}))}).catch(e=>{e.response.status!==422&&B.alert({text:e.response.data.message})}).finally(()=>{v.value=!1,m.value=!1})}function U(){d.push({name:"capture"})}function h(t){for(let e=0;e<t.clipboardData.files.length;e++){const f=t.clipboardData.files[e];if(f.type.indexOf("image/")!==0)break;v.value=!0,y(f);return}B.warn({text:E("message.no_image_found_in_clipboard")})}function V(){m.value=!0,y()}return P(()=>{p.preferences.useDirectCapture&&p.preferences.defaultCaptureMode==="upload"&&l.value.click(),console.log("mounting",h),document.addEventListener("paste",h)}),T(()=>{document.removeEventListener("paste",h)}),(t,e)=>{const f=i("Spinner"),N=i("FormFieldError"),I=i("RouterLink"),R=i("NavigationButton"),x=i("VueFooter"),A=i("StackLayout");return a(),k(A,{"is-vertical-centered":!0},{content:c(()=>[n(v)?(a(),k(f,{key:0,type:"fullscreen-overlay",isVisible:!0,message:"message.parsing_data"})):(a(),_("div",H,[o("div",{class:L({"is-hidden":n(F).count!==0})},[r(s(t.$t("message.no_account_here")),1),e[4]||(e[4]=o("br",null,null,-1)),r(" "+s(t.$t("message.add_first_account")),1)],2),o("div",J,[e[5]||(e[5]=o("div",{class:"quick-uploader-background"},null,-1)),o("div",W,[n(p).preferences.useBasicQrcodeReader?(a(),_("label",{key:0,role:"button",tabindex:"0",class:L(["button is-link is-medium is-rounded is-main",{"is-loading":n(m)}]),ref_key:"qrcodeInputLabel",ref:l,onKeyup:e[0]||(e[0]=S(q=>n(l).click(),["enter"]))},[o("input",{"aria-hidden":"true",tabindex:"-1",class:"file-input",type:"file",accept:"image/*",onChange:y,ref_key:"qrcodeInput",ref:g},null,544),r(" "+s(t.$t("label.upload_qrcode")),1)],34)):(a(),_("button",{key:1,type:"button",class:"button is-link is-medium is-rounded is-main",onClick:e[1]||(e[1]=q=>U())},s(t.$t("label.scan_qrcode")),1))]),n(u).errors.hasAny("qrcode")?(a(),k(N,{key:0,error:n(u).errors.get("qrcode"),field:"qrcode"},null,8,["error"])):C("",!0)]),o("div",X,s(t.$t("message.alternative_methods")),1),n(p).preferences.useBasicQrcodeReader?C("",!0):(a(),_("div",Y,[o("label",{role:"button",tabindex:"0",class:L(["button is-link is-outlined is-rounded",{"is-loading":n(m)}]),ref_key:"qrcodeInputLabel",ref:l,onKeyup:e[2]||(e[2]=S(q=>n(l).click(),["enter"]))},[o("input",{"aria-hidden":"true",tabindex:"-1",class:"file-input",type:"file",accept:"image/*",onChange:V,ref_key:"qrcodeInput",ref:g},null,544),r(" "+s(t.$t("label.upload_qrcode")),1)],34)])),o("div",Z,[$(I,{class:"button is-link is-outlined is-rounded",to:{name:"createAccount"}},{default:c(()=>[r(s(t.$t("link.use_advanced_form")),1)]),_:1})]),o("div",ee,[$(I,{id:"btnImport",class:"button is-link is-outlined is-rounded",to:{name:"importAccounts"}},{default:c(()=>[r(s(t.$t("label.import")),1)]),_:1})]),o("div",te,[r(s(t.$t("message.you_can_also_paste")),1),e[6]||(e[6]=o("br",null,null,-1))])]))]),footer:c(()=>[$(x,null,{default:c(()=>[n(F).isEmpty?C("",!0):(a(),k(R,{key:0,action:"back",onGoback:e[3]||(e[3]=q=>n(d).push({name:"accounts"})),"previous-page-title":t.$t("title.accounts")},null,8,["previous-page-title"]))]),_:1})]),_:1})}}};export{re as default};
@@ -0,0 +1 @@
import{ad as D,C as P,P as H,b as K,a8 as O,r as W,e as p,o as q,d as G,w as u,M as J,f as a,g as Q,a2 as X,h as y,i as n,j as e,m as d,t as i,p as _,l as Y,F as Z,k as ee,n as F,H as se,B,$ as te}from"./app-dvJP63FL.js";import{F as oe}from"./Form-ZbAUhXmz.js";import{s as ne}from"./shareService-BU7jlLil.js";import{_ as ae}from"./TwofaccountMedia-DzLyeBxh.js";import{a as re}from"./helpers-B2oe4lHy.js";import{U as ie}from"./index-BJsmINgd.js";const ce={class:"block is-size-7-mobile"},le={class:"block is-size-7-mobile"},ue={class:"mb-2"},he={__name:"TransferOwnership",props:{twofaccountId:[Number,String]},setup(I){const{t:c}=D(),$=P(),w=H(),V=J("2fauth"),h=Q(),x=X(),g=te(),m=K(),b=O(V.prefix+"returnTo","accountSharing"),t=W(new oe({new_owner_id:"",confirm_password:""})),l=I,f=p(m.items.find(s=>s.id==l.twofaccountId)),S=p(!1),k=p([]),C=B(()=>b.value=="accountSharing"?{name:"accountSharing",params:{twofaccountId:x.params.twofaccountId}}:{name:b.value}),M=B(()=>f.value.is_shared?c("message.shared_with_specific_users"):w.enableAllUsersSharingScope&&f.value.is_shared_with_all?c("message.shared_with_all"):c("message.not_shared"));q(()=>{N()});function R(){g.clear(),confirm(c("confirmation.you_will_loose_ownership"))&&t.patch(`/api/v1/twofaccounts/${l.twofaccountId}/owner`,{returnError:!0}).then(s=>{m.items.splice(m.items.findIndex(o=>o.id==l.twofaccountId),1),h.push({name:"accounts"})}).catch(s=>{s.response?.status===401?g.alert({text:c("notification.authentication_failed"),duration:1e4}):s.response?.status===422?(t.clear(),t.errors.set(t.extractErrors(s.response))):$.show(s)})}function N(){S.value=!0,ne.getRecipients(l.twofaccountId,"").then(s=>{re(s.data).forEach(o=>{k.value.push({text:o.name,value:o.id})})}).finally(()=>{S.value=!1})}return(s,o)=>{const T=a("RouterLink"),U=a("i18n-t"),L=a("FormSelect"),z=a("FormPasswordField"),A=a("FormButtons"),E=a("FormWrapper"),j=a("StackLayout");return y(),G(j,null,{content:u(()=>[n(e(ie),null,{default:u(({mode:v})=>[n(E,{title:"heading.transfer_ownership"},{default:u(()=>[d("div",ce,i(s.$t("message.ownership_can_be_transferred_legend")),1),n(ae,{twofaccount:e(f)},null,8,["twofaccount"]),d("div",le,[d("p",ue,[_(i(s.$t("message.ownership_can_be_transferred_sharing_legend"))+" ",1),e(w).enableAllUsersSharingScope?(y(),Y(Z,{key:0},[_(i(s.$t("message.ownership_can_be_transferred_sharing_legend_if_with_all")),1)],64)):ee("",!0),_(" "+i(s.$t("message.ownership_can_be_transferred_sharing_legend_if_with_specific_users")),1)]),n(U,{keypath:"message.this_account_is_currently_x",tag:"p",class:F(v=="dark"?"has-text-grey":"has-text-black")},{sharing_status:u(()=>[n(T,{class:"is-link",to:{name:"accountSharing",params:{twofaccountId:l.twofaccountId}}},{default:u(()=>[_(i(e(M)),1)]),_:1},8,["to"])]),_:1},8,["class"])]),d("form",{onSubmit:se(R,["prevent"]),onKeydown:o[3]||(o[3]=r=>e(t).onKeydown(r)),class:"mb-6"},[n(L,{modelValue:e(t).new_owner_id,"onUpdate:modelValue":o[0]||(o[0]=r=>e(t).new_owner_id=r),options:e(k),fieldName:"new_owner_id",errorMessage:e(t).errors.get("new_owner_id"),"is-loading":"isFetchingRecipients",label:"field.new_owner",help:"field.new_owner.help"},null,8,["modelValue","options","errorMessage"]),d("div",{class:F(["is-size-7-mobile mb-3",v=="dark"?"has-text-grey":"has-text-black"])},i(s.$t("message.double_check_new_owner")),3),n(z,{modelValue:e(t).confirm_password,"onUpdate:modelValue":o[1]||(o[1]=r=>e(t).confirm_password=r),fieldName:"confirm_password",errorMessage:e(t).errors.get("confirm_password"),label:"field.current_password",help:"field.current_password.help",autocomplete:"off"},null,8,["modelValue","errorMessage"]),n(A,{isDisabled:!e(t).new_owner_id||!e(t).confirm_password,isBusy:e(t).isBusy,submitLabel:"label.transfer",showCancelButton:!0,onCancel:o[2]||(o[2]=r=>e(h).push(e(C)))},null,8,["isDisabled","isBusy"])],32)]),_:2},1024)]),_:1})]),_:1})}}};export{he as default};
@@ -0,0 +1 @@
import{U as r}from"./index-BJsmINgd.js";import{M as l,h as e,l as o,i as u,w as d,m as s,j as c,k as m,n as f,t as n}from"./app-dvJP63FL.js";const h={class:"columns is-mobile is-2 is-align-items-center"},_={class:"column is-narrow"},g={class:"image is-32x32"},w=["src"],k=["src"],y={class:"column"},b={class:"subtitle is-7"},j={__name:"TwofaccountMedia",props:{twofaccount:{type:Object,required:!0}},setup(t){const a=l("2fauth");return(x,p)=>(e(),o("div",h,[u(c(r),null,{default:d(({mode:i})=>[s("div",_,[s("figure",g,[t.twofaccount.icon?(e(),o("img",{key:0,role:"presentation",src:c(a).config.subdirectory+"/storage/icons/"+t.twofaccount.icon,alt:""},null,8,w)):t.twofaccount.icon==null?(e(),o("img",{key:1,role:"presentation",src:c(a).config.subdirectory+"/storage/noicon.svg",alt:""},null,8,k)):m("",!0)])]),s("div",y,[s("p",{class:f(["title is-5",i=="dark"?"has-text-grey-lighter":"has-text-black"])},n(t.twofaccount.service),3),s("p",b,n(t.twofaccount.account),1)])]),_:1})]))}};export{j as _};
+1
View File
@@ -0,0 +1 @@
import{C as E,a8 as R,o as T,a1 as I,af as M,d as C,w as u,M as O,e as b,f as p,h as c,i as r,j as i,a4 as $,m as s,t as m,p as L,X as W,D,n as g,l as v,F as Z,E as H,k as x,ak as P,B,$ as X}from"./app-dvJP63FL.js";import{t as q}from"./tabs-BVx9tg1F.js";import{U as G}from"./index-BJsmINgd.js";import{C as J}from"./circle-plus-BM92Iipr.js";import"./createLucideIcon-DsaEAGzP.js";const K={class:"title is-4"},Q={class:"is-size-7-mobile"},Y={class:"mb-6 mt-3"},ee={class:"columns"},te={class:"column pb-0"},se={class:"level has-text-centered is-mobile mb-0"},ae={class:"level-item"},oe={id:"groupChips",class:"tags"},ne={key:0},ie={class:"has-ellipsis"},re={class:"is-block has-ellipsis is-family-primary is-size-6 is-size-7-mobile has-text-grey"},le={class:"tags mt-2"},de={class:"ml-3"},ue={key:2,class:"mt-4 pl-3"},ke={__name:"Users",setup(ce){const z=E(),F=O("2fauth"),S=X(),U=R(F.prefix+"returnTo","accounts"),y=b([]),a=b(""),_=b(!1),w=B(()=>y.value.filter(e=>{let t=e.name.toLowerCase().includes(h.value.keywords)||e.email.toLowerCase().includes(h.value.keywords);return h.value.admin!=null&&(t=t&&e.is_admin==h.value.admin),h.value.oauth!=null&&(t=t&&e.oauth_provider==h.value.oauth),t})),h=B(()=>{const e={admin:void 0,oauth:void 0,keywords:a.value.toLowerCase()},t=a.value.toLowerCase().split(" "),l=/admin:([01])/,k=/oauth:([a-zA-Z0-9])/;return t.forEach(d=>{d.match(l)&&(e.admin=parseInt(d.replace(l,"$1")),e.keywords=e.keywords.replace(d,"").trim()),d.match(k)&&(e.oauth=d.replace(k,"$1"),e.keywords=e.keywords.replace(d,"").trim())}),e});T(()=>{A()});function f(e){const t=/admin:([01])/,l=/oauth:([a-zA-Z0-9]*)/;a.value.match(t)&&e.match(t)?a.value=a.value.replace(t,e):h.value.oauth!=null&&e.match(l)?a.value=a.value.replace(l,e):a.value=a.value?a.value+" "+e:e}function A(){_.value=!0,I.getAll({returnError:!0}).then(e=>{y.value=e.data}).catch(e=>{z.show(e)}).finally(()=>{_.value=!1})}return M(e=>{e.name.startsWith("admin.")||S.clear()}),(e,t)=>{const l=p("RouterLink"),k=p("Spinner"),d=p("FormWrapper"),N=p("NavigationButton"),V=p("VueFooter"),j=p("StackLayout");return c(),C(j,null,{header:u(()=>[r(i(P),{tabs:i(q),"active-tab":"admin.users",onTabSelected:t[0]||(t[0]=o=>("router"in e?e.router:i($)).push({name:o}))},null,8,["tabs"])]),content:u(()=>[r(d,null,{default:u(()=>[r(i(G),null,{default:u(({mode:o})=>[s("h4",K,m(e.$t("heading.users")),1),s("div",Q,m(e.$t("message.admin_users_legend")),1),s("div",Y,[r(l,{class:"is-link mt-5",to:{name:"admin.createUser"}},{default:u(()=>[r(i(J)),L(" "+m(e.$t("link.create_new_user")),1)]),_:1})]),s("div",ee,[s("div",te,[r(i(W),{keyword:i(a),"onUpdate:keyword":t[1]||(t[1]=n=>D(a)?a.value=n:null),hasNoBackground:!0,placeholder:e.$t("placeholder.search_user_placeholder")},null,8,["keyword","placeholder"])])]),s("div",se,[s("div",ae,[s("div",oe,[s("button",{onClick:t[2]||(t[2]=n=>f("admin:1")),class:g(["button tag",{"has-text-grey":o=="dark","is-white has-text-grey":o!="dark"}])}," admin ",2),s("button",{onClick:t[3]||(t[3]=n=>f("oauth:github")),class:g(["button tag",{"has-text-grey":o=="dark","is-white has-text-grey":o!="dark"}])}," github ",2),s("button",{onClick:t[4]||(t[4]=n=>f("oauth:openid")),class:g(["button tag",{"has-text-grey":o=="dark","is-white has-text-grey":o!="dark"}])}," openId ",2)])])]),i(w).length>0?(c(),v("div",ne,[(c(!0),v(Z,null,H(i(w),n=>(c(),v("div",{key:n.id,class:"list-item is-size-5 is-size-6-mobile is-flex is-justify-content-space-between"},[s("div",ie,[s("span",null,m(n.name),1),s("span",re,m(n.email),1),s("div",le,[n.is_admin?(c(),v("span",{key:0,class:g(["tag is-rounded",o=="dark"?"has-text-warning-40 has-background-black-bis":"has-text-warning-35 has-background-grey-lighter"])},"admin",2)):x("",!0),n.oauth_provider?(c(),v("span",{key:1,class:g(["tag is-rounded has-text-grey",o=="dark"?"has-background-black-bis":"has-background-grey-lighter"])},"oauth: "+m(n.oauth_provider),3)):x("",!0)])]),s("div",de,[r(l,{to:{name:"admin.manageUser",params:{userId:n.id}},class:g(["button is-small has-normal-radius",{"is-dark":o=="dark"}]),title:e.$t("tooltip.manage")},{default:u(()=>[L(m(e.$t("link.manage")),1)]),_:1},8,["to","class","title"])])]))),128))])):i(_)?(c(),C(k,{key:1,isVisible:!0,type:"list-loading"})):(c(),v("div",ue,m(e.$t("message.no_result")),1))]),_:1})]),_:1})]),footer:u(()=>[r(V,null,{default:u(()=>[r(N,{action:"close",onClosed:t[5]||(t[5]=o=>("router"in e?e.router:i($)).push({name:i(U)})),"current-page-title":e.$t("title.admin.users")},null,8,["current-page-title"])]),_:1})]),_:1})}}};export{ke as default};
+1
View File
@@ -0,0 +1 @@
import{C as M,u as P,a as j,P as K,a8 as W,o as R,v as q,a1 as y,af as H,d as I,w as d,M as J,e as F,f as p,g as G,h,i as l,j as t,l as _,t as s,k,m as n,q as Q,p as V,F as X,E as Y,n as Z,ak as ee,B as te,$ as se}from"./app-dvJP63FL.js";import{t as ne}from"./tabs-Btun2NN0.js";import{w as ae}from"./webauthnService-D363et0U.js";import{U as ie}from"./index-BJsmINgd.js";import{C as oe}from"./circle-plus-BM92Iipr.js";import"./createLucideIcon-DsaEAGzP.js";const le={key:0,class:"notification is-warning has-text-centered"},re={key:1,class:"notification is-warning has-text-centered"},ue={class:"title is-4"},ce={class:"is-size-7-mobile"},de={class:"mt-3"},pe={key:2,class:"field"},he=["onClick","title"],_e={class:"mt-2 is-size-7 is-pulled-right"},me={class:"title is-4 pt-6"},fe={class:"field"},ge={class:"help"},ve={class:"help mt-3"},Fe={__name:"WebAuthn",setup(be){const w=M(),{t:r}=P(),$=J("2fauth"),i=j(),C=K(),u=se(),f=G(),x=W($.prefix+"returnTo","accounts"),N=W($.prefix+"activeLoginForm","legacy"),o=F([]),g=F(!1),m=te(()=>C.enableSso&&C.useSsoOnly||i.authenticated_by_proxy);R(()=>{L()}),q(()=>i.preferences.useWebauthnOnly,()=>{y.updatePreference("useWebauthnOnly",i.preferences.useWebauthnOnly).then(e=>{u.success({text:r("notification.setting_saved")})})});function S(){if(m.value==!0)return u.warn({text:r("error.unsupported_with_reverseproxy")}),!1;ae.register().then(e=>{f.push({name:"settings.webauthn.editCredential",params:{credentialId:JSON.parse(e.config.data).id}})}).catch(e=>{"webauthn"in e?e.name=="is-warning"?u.warn({text:r(e.message)}):u.alert({text:r(e.message)}):e.response?.status===422?u.alert({text:e.response.data.message}):w.show(e)})}function O(e){confirm(r("confirmation.revoke_device"))&&y.revokeWebauthnDevice(e).then(a=>{o.value=o.value.filter(v=>v.id!==e),o.value.length==0&&(i.preferences.useWebauthnOnly=!1),u.success({text:r("notification.device_revoked")})})}function B(e){return e.alias?e.alias:r("label.my_device")+" (#"+e.id.substring(0,10)+")"}function L(){g.value=!0,y.getWebauthnDevices({returnError:!0}).then(e=>{o.value=e.data}).catch(e=>{e.response.status===403||w.show(e)}).finally(()=>{g.value=!1})}async function D(){N.value="webauthn"}return H(e=>{e.name.startsWith("settings.")||u.clear()}),(e,a)=>{const v=p("Spinner"),z=p("FormCheckbox"),A=p("FormWrapper"),T=p("NavigationButton"),U=p("VueFooter"),E=p("StackLayout");return h(),I(E,null,{header:d(()=>[l(t(ee),{tabs:t(ne),"active-tab":"settings.webauthn.devices",onTabSelected:a[0]||(a[0]=c=>t(f).push({name:c}))},null,8,["tabs"])]),content:d(()=>[l(A,null,{default:d(()=>[t(m)&&t(i).oauth_provider?(h(),_("div",le,s(e.$t("message.sso_only_x_settings_are_disabled",{auth_method:"WebAuthn"})),1)):k("",!0),t(m)&&t(i).authenticated_by_proxy?(h(),_("div",re,s(e.$t("message.auth_handled_by_proxy")+" "+e.$t("message.manage_auth_at_proxy_level")),1)):k("",!0),n("h4",ue,s(e.$t("heading.security_devices")),1),n("div",ce,s(e.$t("message.security_devices_legend")),1),n("div",de,[n("a",{tabindex:"0",class:"is-link",onClick:S,onKeyup:Q(S,["enter"])},[l(t(oe)),V(" "+s(e.$t("link.register_a_new_device")),1)],32)]),t(o).length>0?(h(),_("div",pe,[l(t(ie),null,{default:d(({mode:c})=>[(h(!0),_(X,null,Y(t(o),b=>(h(),_("div",{key:b.id,class:"group-item is-size-5 is-size-6-mobile"},[V(s(B(b))+" ",1),n("button",{type:"button",class:Z(["button tag is-pulled-right",c==="dark"?"is-dark":"is-white"]),onClick:ye=>O(b.id),title:e.$t("tooltip.revoke")},s(e.$t("label.revoke")),11,he)]))),128))]),_:1}),n("div",_e,s(e.$t("message.revoking_a_device_is_permanent")),1)])):k("",!0),l(v,{isVisible:t(g)&&t(o).length===0,type:"list-loading"},null,8,["isVisible"]),n("h4",me,s(e.$t("heading.options")),1),n("div",fe,s(e.$t("message.need_a_security_device_to_enable_options")),1),n("form",null,[l(z,{modelValue:t(i).preferences.useWebauthnOnly,"onUpdate:modelValue":[a[1]||(a[1]=c=>t(i).preferences.useWebauthnOnly=c),a[2]||(a[2]=c=>D())],fieldName:"useWebauthnOnly",label:"field.use_webauthn_only",help:"field.use_webauthn_only.help",isDisabled:t(m)||t(o).length===0},null,8,["modelValue","isDisabled"]),n("p",ge,s(e.$t("field.use_webauthn_only.help_bis")),1),n("p",ve,s(e.$t("field.use_webauthn_only.help_ter")),1)])]),_:1})]),footer:d(()=>[l(U,null,{default:d(()=>[l(T,{action:"close",onClosed:a[3]||(a[3]=c=>t(f).push({name:t(x)})),"current-page-title":e.$t("title.settings.webauthn.devices")},null,8,["current-page-title"])]),_:1})]),_:1})}}};export{Fe as default};
+1
View File
@@ -0,0 +1 @@
@charset "UTF-8";:root{--bulma-control-radius: var(--bulma-radius);--bulma-control-radius-small: var(--bulma-radius-small);--bulma-control-border-width: 1px;--bulma-control-height: 2.5em;--bulma-control-line-height: 1.5;--bulma-control-padding-vertical: calc(.5em - 1px) ;--bulma-control-padding-horizontal: calc(.75em - 1px) ;--bulma-control-size: var(--bulma-size-normal);--bulma-control-focus-shadow-l: 50%}:root{--bulma-scheme-h: 221;--bulma-scheme-s: 14%;--bulma-light-l: 90%;--bulma-light-invert-l: 20%;--bulma-dark-l: 20%;--bulma-dark-invert-l: 90%;--bulma-soft-l: 90%;--bulma-bold-l: 20%;--bulma-soft-invert-l: 20%;--bulma-bold-invert-l: 90%;--bulma-hover-background-l-delta: -5%;--bulma-active-background-l-delta: -10%;--bulma-hover-border-l-delta: -10%;--bulma-active-border-l-delta: -20%;--bulma-hover-color-l-delta: -5%;--bulma-active-color-l-delta: -10%;--bulma-hover-shadow-a-delta: -.05;--bulma-active-shadow-a-delta: -.1;--bulma-scheme-brightness: light;--bulma-scheme-main-l: 100%;--bulma-scheme-main-bis-l: 98%;--bulma-scheme-main-ter-l: 96%;--bulma-background-l: 96%;--bulma-border-weak-l: 93%;--bulma-border-l: 86%;--bulma-text-weak-l: 48%;--bulma-text-strong-l: 21%;--bulma-text-title-l: 14%;--bulma-scheme-invert-ter-l: 14%;--bulma-scheme-invert-bis-l: 7%;--bulma-scheme-invert-l: 4%;--bulma-family-primary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif;--bulma-family-secondary: Inter, SF Pro, Segoe UI, Roboto, Oxygen, Ubuntu, Helvetica Neue, Helvetica, Arial, sans-serif;--bulma-family-code: Inconsolata, Hack, SF Mono, Roboto Mono, Source Code Pro, Ubuntu Mono, monospace;--bulma-size-small: .75rem;--bulma-size-normal: 1rem;--bulma-size-medium: 1.25rem;--bulma-size-large: 1.5rem;--bulma-weight-light: 300;--bulma-weight-normal: 400;--bulma-weight-medium: 500;--bulma-weight-semibold: 600;--bulma-weight-bold: 700;--bulma-weight-extrabold: 800;--bulma-block-spacing: 1.5rem;--bulma-duration: 50ms;--bulma-easing: ease-out;--bulma-radius-small: .25rem;--bulma-radius: .375rem;--bulma-radius-medium: .5em;--bulma-radius-large: .75rem;--bulma-radius-rounded: 9999px;--bulma-speed: 86ms;--bulma-arrow-color: var(--bulma-link);--bulma-loading-color: var(--bulma-border);--bulma-burger-h: var(--bulma-link-h);--bulma-burger-s: var(--bulma-link-s);--bulma-burger-l: var(--bulma-link-l);--bulma-burger-border-radius: .5em;--bulma-burger-gap: 5px;--bulma-burger-item-height: 2px;--bulma-burger-item-width: 20px;--bulma-white: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1);--bulma-white-base: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-l), 1);--bulma-white-rgb: 255, 255, 255;--bulma-white-h: 0deg;--bulma-white-s: 0%;--bulma-white-l: 100%;--bulma-white-invert-l: 4%;--bulma-white-invert: hsl(0, 0%, 4%);--bulma-white-on-scheme-l: 35%;--bulma-white-on-scheme: hsla(var(--bulma-white-h), var(--bulma-white-s), var(--bulma-white-on-scheme-l), 1);--bulma-black: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1);--bulma-black-base: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-l), 1);--bulma-black-rgb: 10.2, 10.2, 10.2;--bulma-black-h: 0deg;--bulma-black-s: 0%;--bulma-black-l: 4%;--bulma-black-invert-l: 100%;--bulma-black-invert: hsl(0, 0%, 100%);--bulma-black-on-scheme-l: 4%;--bulma-black-on-scheme: hsla(var(--bulma-black-h), var(--bulma-black-s), var(--bulma-black-on-scheme-l), 1);--bulma-light: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1);--bulma-light-base: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-l), 1);--bulma-light-rgb: 244.8, 244.8, 244.8;--bulma-light-h: 0deg;--bulma-light-s: 0%;--bulma-light-l: 96%;--bulma-light-invert-l: 21%;--bulma-light-invert: hsl(0, 0%, 21%);--bulma-light-on-scheme-l: 36%;--bulma-light-on-scheme: hsla(var(--bulma-light-h), var(--bulma-light-s), var(--bulma-light-on-scheme-l), 1);--bulma-dark: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1);--bulma-dark-base: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-l), 1);--bulma-dark-rgb: 53.55, 53.55, 53.55;--bulma-dark-h: 0deg;--bulma-dark-s: 0%;--bulma-dark-l: 21%;--bulma-dark-invert-l: 96%;--bulma-dark-invert: hsl(0, 0%, 96%);--bulma-dark-on-scheme-l: 21%;--bulma-dark-on-scheme: hsla(var(--bulma-dark-h), var(--bulma-dark-s), var(--bulma-dark-on-scheme-l), 1);--bulma-text: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1);--bulma-text-base: hsla(var(--bulma-text-h), var(--bulma-text-s), var(--bulma-text-l), 1);--bulma-text-rgb: 73.95, 73.95, 73.95;--bulma-text-h: 0deg;--bulma-text-s: 0%;--bulma-text-l: 29%;--bulma-text-00-l: 0%;--bulma-text-05-l: 4%;--bulma-text-10-l: 9%;--bulma-text-15-l: 14%;--bulma-text-20-l: 19%;--bulma-text-25-l: 24%;--bulma-text-30-l: 29%;--bulma-text-35-l: 34%;--bulma-text-40-l: 39%;--bulma-text-45-l: 44%;--bulma-text-50-l: 49%;--bulma-text-55-l: 54%;--bulma-text-60-l: 59%;--bulma-text-65-l:Line truncated
+20
View File
@@ -0,0 +1,20 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./Start-Dnu4qWlC.js","./Form-ZbAUhXmz.js","./bus-ChE1sp8V.js","./Capture-BG6QMHLW.js","./QrContentDisplay-DiIjf7a_.js","./external-link-CqpXNovN.js","./createLucideIcon-DsaEAGzP.js","./index-BJsmINgd.js","./Accounts-znshhaJC.js","./shareService-BU7jlLil.js","./useSortable-6hRbxhTj.js","./circle-x-AvUNZzwX.js","./users-CLZI37iw.js","./qr-code-eSL1bq0j.js","./x-DQVIq0xP.js","./CreateUpdate-tvLQ26rU.js","./iconService-rm6LRV4U.js","./Import-C0sC5CLD.js","./check-CPGWPXZa.js","./AccountSharing-kU7yk02h.js","./TwofaccountMedia-DzLyeBxh.js","./helpers-B2oe4lHy.js","./circle-plus-BM92Iipr.js","./Share-DkTnn1jz.js","./TransferOwnership-BsVNwpBY.js","./OtpLogs-CAP6rwu6.js","./tablet-DYUfDfjC.js","./Groups-Ccrpwp-O.js","./CreateUpdate-CbOB1O7q.js","./Options-Bun4hDR8.js","./tabs-Btun2NN0.js","./breakpoints-CyLcIEOu.js","./Account-CvhJGfLO.js","./OAuth-aXCqlLPs.js","./Edit-Ba84j7PP.js","./WebAuthn-C_HU0Xj8.js","./webauthnService-D363et0U.js","./AppSetup-9GPB7B-I.js","./tabs-BVx9tg1F.js","./appSettingsUpdater-D1Bq_3WB.js","./CopyButton-CgxgBp0c.js","./Auth-DslSg1a9.js","./Users-DyNCDMUg.js","./Create-Vv-BwDWf.js","./Manage-B1CTWqgo.js","./AccessLogViewer-D5ke4CwJ.js","./Access-BQVm4alb.js","./Login-XfEMUKl8.js","./Register-DffuLlzx.js","./RequestReset-w8-YSMaH.js","./Reset-RiTuOlH9.js","./Recover-CEob990V.js","./About-DlWJhNxo.js","./Error-DG0pgQA2.js"])))=>i.map(i=>d[i]);
function r0(t,e){typeof console<"u"&&(console.warn("[intlify] "+t),e&&console.warn(e.stack))}const Bo=typeof window<"u",ns=(t,e=!1)=>e?Symbol.for(t):Symbol(t),n0=(t,e,i)=>l0({l:t,k:e,s:i}),l0=t=>JSON.stringify(t).replace(/\u2028/g,"\\u2028").replace(/\u2029/g,"\\u2029").replace(/\u0027/g,"\\u0027"),ce=t=>typeof t=="number"&&isFinite(t),hb=t=>Ol(t)==="[object Date]",$o=t=>Ol(t)==="[object RegExp]",br=t=>zt(t)&&Object.keys(t).length===0,pe=Object.assign,u0=Object.create,Ht=(t=null)=>u0(t);let Tu;const Pl=()=>Tu||(Tu=typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:typeof global<"u"?global:Ht());function Su(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/\//g,"&#x2F;").replace(/=/g,"&#x3D;")}function d0(t){return t.replace(/&(?![a-zA-Z0-9#]{2,6};)/g,"&amp;").replace(/"/g,"&quot;").replace(/'/g,"&apos;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const c0=/^\s*javascript\s*(?::|&#0*58;?|&#x0*3a;?|&colon;?)/i,b0=/^(?:href|src|action|formaction)$/i;function El(t){return c0.test(t)}function _0(t){const e=/url\s*\(/gi;let i="",s=0,a;for(;(a=e.exec(t))!==null;){const o=a.index,r=e.lastIndex-1;let n=r+1,l=1,u=null;for(;n<t.length;n++){const _=t[n];if(u){_===u&&(u=null);continue}if(_==='"'||_==="'")u=_;else if(_==="(")l++;else if(_===")"&&(l--,l===0))break}if(l!==0)break;const d=t.slice(r+1,n).trim(),c=d.startsWith('"')&&d.endsWith('"')||d.startsWith("'")&&d.endsWith("'")?d.slice(1,-1).trim():d;i+=t.slice(s,o),i+=El(c)?"url(about:blank)":t.slice(o,n+1),s=n+1}return i+t.slice(s)}function Fu(t,e){if(b0.test(t)&&El(e))return"about:blank";const i=t.toLowerCase()==="style"?_0(e):e;return d0(i)}function h0(t){return t=t.replace(/([\w:-]+)\s*=\s*"([^"]*)"/g,(i,s,a)=>`${s}="${Fu(s,a)}"`),t=t.replace(/([\w:-]+)\s*=\s*'([^']*)'/g,(i,s,a)=>`${s}='${Fu(s,a)}'`),/\s*on\w+\s*=\s*["']?[^"'>]+["']?/gi.test(t)&&(t=t.replace(/(\s+)(on)(\w+\s*=)/gi,"$1&#111;n$3")),t=t.replace(/(\s+(?:href|src|action|formaction)\s*=\s*)([^\s"'=<>`]+)/gi,(i,s,a)=>El(a)?`${s}about:blank`:i),t}const p0=Object.prototype.hasOwnProperty;function Ze(t,e){return p0.call(t,e)}const le=Array.isArray,re=t=>typeof t=="function",dt=t=>typeof t=="string",se=t=>typeof t=="boolean",Ct=t=>t!==null&&typeof t=="object",m0=t=>Ct(t)&&re(t.then)&&re(t.catch),pb=Object.prototype.toString,Ol=t=>pb.call(t),zt=t=>Ol(t)==="[object Object]",g0=t=>t==null?"":le(t)||zt(t)&&t.toString===pb?JSON.stringify(t,null,2):String(t);function Rl(t,e=""){return t.reduce((i,s,a)=>a===0?i+s:i+e+s,"")}const _o=t=>!Ct(t)||le(t);function Co(t,e){if(_o(t)||_o(e))throw new Error("Invalid value");const i=[{src:t,des:e}];for(;i.length;){const{src:s,des:a}=i.pop();Object.keys(s).forEach(o=>{o!=="__proto__"&&(Ct(s[o])&&!Ct(a[o])&&(a[o]=Array.isArray(s[o])?[]:Ht()),_o(a[o])||_o(s[o])?a[o]=s[o]:i.push({src:s[o],des:a[o]}))})}}function f0(t,e,i){return{line:t,column:e,offset:i}}function Ln(t,e,i){return{start:t,end:e}}const jt={EXPECTED_TOKEN:1,INVALID_TOKEN_IN_PLACEHOLDER:2,UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER:3,UNKNOWN_ESCAPE_SEQUENCE:4,INVALID_UNICODE_ESCAPE_SEQUENCE:5,UNBALANCED_CLOSING_BRACE:6,UNTERMINATED_CLOSING_BRACE:7,EMPTY_PLACEHOLDER:8,NOT_ALLOW_NEST_PLACEHOLDER:9,INVALID_LINKED_FORMAT:10,MUST_HAVE_MESSAGES_IN_PLURAL:11,UNEXPECTED_EMPTY_LINKED_MODIFIER:12,UNEXPECTED_EMPTY_LINKED_KEY:13,UNEXPECTED_LEXICAL_ANALYSIS:14},v0=17;function _r(t,e,i={}){const{domain:s,messages:a,args:o}=i,r=t,n=new SyntaxError(String(r));return n.code=t,e&&(n.location=e),n.domain=s,n}function w0(t){throw t}const di=" ",y0="\r",ye=`
`,k0="\u2028",A0="\u2029";function x0(t){const e=t;let i=0,s=1,a=1,o=0;const r=F=>e[F]===y0&&e[F+1]===ye,n=F=>e[F]===ye,l=F=>e[F]===A0,u=F=>e[F]===k0,d=F=>r(F)||n(F)||l(F)||u(F),c=()=>i,_=()=>s,p=()=>a,v=()=>o,g=F=>r(F)||l(F)||u(F)?ye:e[F],y=()=>g(i),m=()=>g(i+o);function w(){return o=0,d(i)&&(s++,a=0),r(i)&&i++,i++,a++,e[i]}function x(){return r(i+o)&&o++,o++,e[i+o]}function f(){i=0,s=1,a=1,o=0}function T(F=0){o=F}function P(){const F=i+o;for(;F!==i;)w();o=0}return{index:c,line:_,column:p,peekOffset:v,charAt:g,currentChar:y,currentPeek:m,next:w,peek:x,reset:f,resetPeek:T,skipToPeek:P}}const Si=void 0,T0=".",Pu="'",S0="tokenizer";function F0(t,e={}){const i=e.location!==!1,s=x0(t),a=()=>s.index(),o=()=>f0(s.line(),s.column(),s.index()),r=o(),n=a(),l={currentType:13,offset:n,startLoc:r,endLoc:r,lastType:13,lastOffset:n,lastStartLoc:r,lastEndLoc:r,braceNest:0,inLinked:!1,text:""},u=()=>l,{onError:d}=e;function c(b,h,A,...E){const Y=u();if(h.column+=A,h.offset+=A,d){const U=i?Ln(Y.startLoc,h):null,k=_r(b,U,{domain:S0,args:E});d(k)}}function _(b,h,A){b.endLoc=o(),b.currentType=h;const E={type:h};return i&&(E.loc=Ln(b.startLoc,b.endLoc)),A!=null&&(E.value=A),E}const p=b=>_(b,13);function v(b,h){return b.currentChar()===h?(b.next(),h):(c(jt.EXPECTED_TOKEN,o(),0,h),"")}function g(b){let h="";for(;b.currentPeek()===di||b.currentPeek()===ye;)h+=b.currentPeek(),b.peek();return h}function y(b){const h=g(b);return b.skipToPeek(),h}function m(b){if(b===Si)return!1;const h=b.charCodeAt(0);return h>=97&&h<=122||h>=65&&h<=90||h===95}function w(b){if(b===Si)return!1;const h=b.charCodeAt(0);return h>=48&&h<=57}function x(b,h){const{currentType:A}=h;if(A!==2)return!1;g(b);const E=m(b.currentPeek());return b.resetPeek(),E}function f(b,h){const{currentType:A}=h;if(A!==2)return!1;g(b);const E=b.currentPeek()==="-"?b.peek():b.currentPeek(),Y=w(E);return b.resetPeek(),Y}function T(b,h){const{currentType:A}=h;if(A!==2)return!1;g(b);const E=b.currentPeek()===Pu;return b.resetPeek(),E}function P(b,h){const{currentType:A}=h;if(A!==7)return!1;g(b);const E=b.currentPeek()===".";return b.resetPeek(),E}function F(b,h){const{currentType:A}=h;if(A!==8)return!1;g(b);const E=m(b.currentPeek());return b.resetPeek(),E}function B(b,h){const{currentType:A}=h;if(!(A===7||A===11))return!1;g(b);const E=b.currentPeek()===":";return b.resetPeek(),E}function q(b,h){const{currentType:A}=h;if(A!==9)return!1;const E=()=>{const U=b.currentPeek();return U==="{"?m(b.peek()):U==="@"||U==="|"||U===":"||U==="."||U===di||!U?!1:U===ye?(b.peek(),E()):Q(b,!1)},Y=E();return b.resetPeek(),Y}function N(b){g(b);const h=b.currentPeek()==="|";return b.resetPeek(),h}function Q(b,h=!0){const A=(Y=!1,U="")=>{const k=b.currentPeek();return k==="{"||k==="@"||!k?Y:k==="|"?!(U===di||U===ye):k===di?(b.peek(),A(!0,di)):k===ye?(b.peek(),A(!0,ye)):!0},E=A();return h&&b.resetPeek(),E}function z(b,h){const A=b.currentChar();return A===Si?Si:h(A)?(b.next(),A):null}function X(b){const h=b.charCodeAt(0);return h>=97&&h<=122||h>=65&&h<=90||h>=48&&h<=57||h===95||h===36}function L(b){return z(b,X)}function tt(b){const h=b.charCodeAt(0);return h>=97&&h<=122||h>=65&&h<=90||h>=48&&h<=57||h===95||h===36||h===45}function et(b){return z(b,tt)}function ht(b){const h=b.charCodeAt(0);return h>=48&&h<=57}function mt(b){return z(b,ht)}function yt(b){const h=b.charCodeAt(0);return h>=48&&h<=57||h>=65&&h<=70||h>=97&&h<=102}function Pt(b){return z(b,yt)}function _t(b){let h="",A="";for(;h=mt(b);)A+=h;return A}function lt(b){let h="";for(;;){const A=b.currentChar();if(A==="\\"){const E=b.peek();E==="{"||E==="}"||E==="@"||E==="|"||E==="\\"?(h+=A+E,b.next(),b.next()):(b.resetPeek(),h+=A,b.next())}else{if(A==="{"||A==="}"||A==="@"||A==="|"||!A)break;if(A===di||A===ye)if(Q(b))h+=A,b.next();else{if(N(b))break;h+=A,b.next()}else h+=A,b.next()}}return h}function gt(b){y(b);let h="",A="";for(;h=et(b);)A+=h;const E=b.currentChar();if(E&&E!=="}"&&E!==Si&&E!==di&&E!==ye&&E!==" "){const Y=ut(b);return c(jt.INVALID_TOKEN_IN_PLACEHOLDER,o(),0,A+Y),A+Y}return b.currentChar()===Si&&c(jt.UNTERMINATED_CLOSING_BRACE,o(),0),A}function Qt(b){y(b);let h="";return b.currentChar()==="-"?(b.next(),h+=`-${_t(b)}`):h+=_t(b),b.currentChar()===Si&&c(jt.UNTERMINATED_CLOSING_BRACE,o(),0),h}function Xt(b){return b!==Pu&&b!==ye}function te(b){y(b),v(b,"'");let h="",A="";for(;h=z(b,Xt);)h==="\\"?A+=j(b):A+=h;const E=b.currentChar();return E===ye||E===Si?(c(jt.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER,o(),0),E===ye&&(b.next(),v(b,"'")),A):(v(b,"'"),A)}function j(b){const h=b.currentChar();switch(h){case"\\":case"'":return b.next(),`\\${h}`;case"u":return K(b,h,4);case"U":return K(b,h,6);default:return c(jt.UNKNOWN_ESCAPE_SEQUENCE,o(),0,h),""}}function K(b,h,A){v(b,h);let E="";for(let Y=0;Y<A;Y++){const U=Pt(b);if(!U){c(jt.INVALID_UNICODE_ESCAPE_SEQUENCE,o(),0,`\\${h}${E}${b.currentChar()}`);break}E+=U}return`\\${h}${E}`}function Z(b){return b!=="{"&&b!=="}"&&b!==di&&b!==ye}function ut(b){y(b);let h="",A="";for(;h=z(b,Z);)A+=h;return A}f Line truncated
`,o=e.needIndent?e.needIndent:i!=="arrow",r=t.helpers||[],n=N0(t,{filename:s,breakLineCode:a,needIndent:o});n.push(i==="normal"?"function __msg__ (ctx) {":"(ctx) => {"),n.indent(o),r.length>0&&(n.push(`const { ${Rl(r.map(d=>`${d}: _${d}`),", ")} } = ctx`),n.newline()),n.push("return "),Xs(n,t),n.deindent(o),n.push("}"),delete t.helpers;const{code:l,map:u}=n.context();return{ast:t,code:l,map:u?u.toJSON():void 0}};function B0(t,e={}){const i=pe({},e),s=!!i.jit,a=!!i.minify,o=i.optimize==null?!0:i.optimize,n=C0(i).parse(t);return s?(o&&D0(n),a&&js(n),{ast:n,code:""}):(z0(n,i),W0(n,i))}function $0(){typeof __INTLIFY_PROD_DEVTOOLS__!="boolean"&&(Pl().__INTLIFY_PROD_DEVTOOLS__=!1)}function yi(t){return Ct(t)&&Cl(t)===0&&(Ze(t,"b")||Ze(t,"body"))}const mb=["b","body"];function H0(t){return ls(t,mb)}const gb=["c","cases"];function G0(t){return ls(t,gb,[])}const fb=["s","static"];function V0(t){return ls(t,fb)}const vb=["i","items"];function Q0(t){return ls(t,vb,[])}const wb=["t","type"];function Cl(t){return ls(t,wb)}const yb=["v","value"];function ho(t,e){const i=ls(t,yb);if(i!=null)return i;throw Da(e)}const kb=["m","modifier"];function K0(t){return ls(t,kb)}const Ab=["k","key"];function Y0(t){const e=ls(t,Ab);if(e)return e;throw Da(6)}function ls(t,e,i){for(let s=0;s<e.length;s++){const a=e[s];if(Ze(t,a)&&t[a]!=null)return t[a]}return i}const xb=[...mb,...gb,...fb,...vb,...Ab,...kb,...yb,...wb];function Da(t){return new Error(`unhandled node type: ${t}`)}function Jr(t){return i=>J0(i,t)}function J0(t,e){const i=H0(e);if(i==null)throw Da(0);if(Cl(i)===1){const o=G0(i);return t.plural(o.reduce((r,n)=>[...r,Ru(t,n)],[]))}else return Ru(t,i)}function Ru(t,e){const i=V0(e);if(i!=null)return t.type==="text"?i:t.normalize([i]);{const s=Q0(e).reduce((a,o)=>[...a,Un(t,o)],[]);return t.normalize(s)}}function Un(t,e){const i=Cl(e);switch(i){case 3:return ho(e,i);case 9:return ho(e,i);case 4:{const s=e;if(Ze(s,"k")&&s.k)return t.interpolate(t.named(s.k));if(Ze(s,"key")&&s.key)return t.interpolate(t.named(s.key));throw Da(i)}case 5:{const s=e;if(Ze(s,"i")&&ce(s.i))return t.interpolate(t.list(s.i));if(Ze(s,"index")&&ce(s.index))return t.interpolate(t.list(s.index));throw Da(i)}case 6:{const s=e,a=K0(s),o=Y0(s);return t.linked(Un(t,o),a?Un(t,a):void 0,t.type)}case 7:return ho(e,i);case 8:return ho(e,i);default:throw new Error(`unhandled node on format message part: ${i}`)}}const Z0=t=>t;let po=Ht();function X0(t,e={}){let i=!1;const s=e.onError||w0;return e.onError=a=>{i=!0,s(a)},{...B0(t,e),detectError:i}}function t2(t,e){if(dt(t)){se(e.warnHtmlMessage)&&e.warnHtmlMessage;const s=(e.onCacheKey||Z0)(t),a=po[s];if(a)return a;const{ast:o,detectError:r}=X0(t,{...e,location:!1,jit:!0}),n=Jr(o);return r?n:po[s]=n}else{const i=t.cacheKey;if(i){const s=po[i];return s||(po[i]=Jr(t))}else return Jr(t)}}let Na=null;function e2(t){Na=t}function i2(t,e,i){Na&&Na.emit("i18n:init",{timestamp:Date.now(),i18n:t,version:e,meta:i})}const s2=a2("function:translate");function a2(t){return e=>Na&&Na.emit(t,e)}const Ii={INVALID_ARGUMENT:v0,INVALID_DATE_ARGUMENT:18,INVALID_ISO_DATE_ARGUMENT:19,NOT_SUPPORT_LOCALE_PROMISE_VALUE:21,NOT_SUPPORT_LOCALE_ASYNC_FUNCTION:22,NOT_SUPPORT_LOCALE_TYPE:23},o2=24;function zi(t){return _r(t,null,void 0)}function Il(t,e){return e.locale!=null?qu(e.locale):qu(t.locale)}let Zr;function qu(t){if(dt(t))return t;if(re(t)){if(t.resolvedOnce&&Zr!=null)return Zr;if(t.constructor.name==="Function"){const e=t();if(m0(e))throw zi(Ii.NOT_SUPPORT_LOCALE_PROMISE_VALUE);return Zr=e}else throw zi(Ii.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION)}else throw zi(Ii.NOT_SUPPORT_LOCALE_TYPE)}function r2(t,e,i){return[...new Set([i,...le(e)?e:Ct(e)?Object.keys(e):dt(e)?[e]:[i]])]}function jn(t,e,i){const s=dt(i)?i:Ho,a=t;a.__localeChainCache||(a.__localeChainCache=new Map);let o=a.__localeChainCache.get(s);if(!o){o=[];let r=[i];for(;le(r);)r=Cu(o,r,e);const n=le(e)||!zt(e)?e:e.default?e.default:null;r=dt(n)?[n]:n,le(r)&&Cu(o,r,!1),a.__localeChainCache.set(s,o)}return o}function Cu(t,e,i){let s=!0;for(let a=0;a<e.length&&se(s);a++){const o=e[a];dt(o)&&(s=n2(t,e[a],i))}return s}function n2(t,e,i){let s;const a=e.split("-");do{const o=a.join("-");s=l2(t,o,i),a.splice(-1,1)}while(a.length&&s===!0);return s}function l2(t,e,i){let s=!1;if(!t.includes(e)&&(s=!0,e)){s=e[e.length-1]!=="!";const a=e.replace(/!/g,"");t.push(a),(le(i)||zt(i))&&i[a]&&(s=i[a])}return s}const us=[];us[0]={w:[0],i:[3,0],"[":[4],o:[7]};us[1]={w:[1],".":[2],"[":[4],o:[7]};us[2]={w:[2],i:[3,0],0:[3,0]};us[3]={i:[3,0],0:[3,0],w:[1,1],".":[2,1],"[":[4,1],o:[7,1]};us[4]={"'":[5,0],'"':[6,0],"[":[4,2],"]":[1,3],o:8,l:[4,0]};us[5]={"'":[4,0],o:8,l:[5,0]};us[6]={'"':[4,0],o:8,l:[6,0]};const u2=/^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;function d2(t){return u2.test(t)}function c2(t){const e=t.charCodeAt(0),i=t.charCodeAt(t.length-1);return e===i&&(e===34||e===39)?t.slice(1,-1):t}function b2(t){if(t==null)return"o";switch(t.charCodeAt(0)){case 91:case 93:case 46:case 34:case 39:retur Line truncated
`}},"field.icon_source":{t:0,b:{t:2,i:[{t:3}],s:"图标获取来源"}},"field.icon_pack.help":{t:0,b:{t:2,i:[{t:3}],s:"获取图标时所使用的图标包。若要使用本地图标包,需要先将图标包上传至 2FAuth 服务器,请咨询此实例的管理员了解详情。"}},"field.icon_pack":{t:0,b:{t:2,i:[{t:3}],s:"图标包"}},"field.icon_variant_strict_fetch.help":{t:0,b:{t:2,i:[{t:3}],s:"获取图标时仅获取选中的样式。如果不存在此样式,2FAuth 将不会自动获取 “普通” 图标。"}},"field.icon_variant_strict_fetch":{t:0,b:{t:2,i:[{t:3}],s:"严格模式"}},"field.icon_variant.help":{t:0,b:{t:2,i:[{t:3}],s:"某些图标提供不同的样式,用以适配 “亮色” 或 “暗色” 的模式界面。您可以选择一个为优先获取的样式,若选中的样式无法获取到时,将自动获取 “普通” 样式。"}},"field.icon_variant":{t:0,b:{t:2,i:[{t:3}],s:"图标样式"}},"field.icon":{t:0,b:{t:2,i:[{t:3}],s:"图标"}},"field.is_admin.help":{t:0,b:{t:2,i:[{t:3}],s:"授予用户管理员权限。管理员有权管理整个应用,如调整 “设置” 和管理其他用户,但管理员无法获取他人账号内的 2FA 验证码。"}},"field.is_admin":{t:0,b:{t:2,i:[{t:3}],s:"管理员"}},"field.keep_sso_registration_enabled.help":{t:0,b:{t:2,i:[{t:3}],s:"在注册被禁用时,仍然允许新用户通过 SSO 登录"}},"field.keep_sso_registration_enabled":{t:0,b:{t:2,i:[{t:3}],s:"仍然允许通过 SSO 注册新账户"}},"field.language.help":{t:0,b:{t:2,i:[{t:3}],s:"设置 2FAuth 的界面语言。以下仅列出已有的翻译,您可以手动选择一个语言,或跟随浏览器语言自动切换。"}},"field.language":{t:0,b:{t:2,i:[{t:3}],s:"语言"}},"field.name_this_device":{t:0,b:{t:2,i:[{t:3}],s:"命名此设备"}},"field.name":{t:0,b:{t:2,i:[{t:3}],s:"名称"}},"field.new_name":{t:0,b:{t:2,i:[{t:3}],s:"新名称"}},"field.new_owner.help":{t:0,b:{t:2,i:[{t:3}],s:"所有权将被转移给此用户。"}},"field.new_owner":{t:0,b:{t:2,i:[{t:3}],s:"新所有者"}},"field.new_password":{t:0,b:{t:2,i:[{t:3}],s:"新密码"}},"field.notify_on_failed_login.help":{t:0,b:{t:2,i:[{t:3}],s:"每次登录失败时都发送邮件通知"}},"field.notify_on_failed_login":{t:0,b:{t:2,i:[{t:3}],s:"登录失败时"}},"field.notify_on_new_auth_device.help":{t:0,b:{t:2,i:[{t:3}],s:"当新设备首次登录时发送邮件通知"}},"field.notify_on_new_auth_device":{t:0,b:{t:2,i:[{t:3}],s:"来自新设备时"}},"field.options.help":{t:0,b:{t:2,i:[{t:3}],s:"如果您不了解下列选项,请留空来使用默认配置。"}},"field.otp_generation.help":{t:0,b:{t:2,i:[{t:3}],s:"设置验证码的显示方式和时间。"}},"field.otp_generation":{t:0,b:{t:2,i:[{t:3}],s:"显示验证码"}},"field.otp_type.help":{t:0,b:{t:2,i:[{t:3}],s:"TOTP,HOTP 或 Steam OTP"}},"field.otp_type":{t:0,b:{t:2,i:[{t:3}],s:"选择要创建的 OTP 类型"}},"field.password_format.help":{t:0,b:{t:2,i:[{t:3}],s:"分段显示验证码,提高可读性并且便于记忆"}},"field.password_format":{t:0,b:{t:2,i:[{t:3}],s:"密码格式"}},"field.password":{t:0,b:{t:2,i:[{t:3}],s:"密码"}},"field.period.help":{t:0,b:{t:2,i:[{t:3}],s:"验证码的有效期 (秒)"}},"field.period.placeholder":{t:0,b:{t:2,i:[{t:3}],s:"默认为 30"}},"field.period":{t:0,b:{t:2,i:[{t:3}],s:"周期"}},"field.remember_active_group.help":{t:0,b:{t:2,i:[{t:3}],s:"记住选中的分组,并在下次访问时自动切换至此分组"}},"field.remember_active_group":{t:0,b:{t:2,i:[{t:3}],s:"记住选中的分组"}},"field.restrict_list.help":{t:0,b:{t:2,i:[{t:3},{t:9},{t:3}],s:"仅允许此列表中的邮箱进行注册,用管道符 ('|') 来分隔多个地址"}},"field.restrict_list":{t:0,b:{t:2,i:[{t:3}],s:"过滤列表"}},"field.restrict_registration.help":{t:0,b:{t:2,i:[{t:3}],s:"只允许符合规则的邮箱地址进行注册。可以同时使用下方的两条规则来进行限制。SSO 的注册流程不受此限制的影响。"}},"field.restrict_registration":{t:0,b:{t:2,i:[{t:3}],s:"限制注册"}},"field.restrict_rule.help":{t:0,b:{t:2,i:[{t:3}],s:"仅允许匹配正则表达式的邮箱地址进行注册"}},"field.restrict_rule":{t:0,b:{t:2,i:[{t:3}],s:"过滤规则"}},"field.reveal_dotted_otp.help":{t:0,b:{t:2,i:[{t:3}],s:"允许验证码临时以明文显示"}},"field.reveal_dotted_otp":{t:0,b:{t:2,i:[{t:3}],s:"显示被遮挡的验证码"}},"field.secret.help":{t:0,b:{t:2,i:[{t:3}],s:"用于生成安全码的密钥"}},"field.secret":{t:0,b:{t:2,i:[{t:3}],s:"密钥"}},"field.service.placeholder":{t:0,b:{t:2,i:[{t:3}],s:"服务名称"}},"field.service":{t:0,b:{t:2,i:[{t:3}],s:"服务"}},"field.show_accounts_icons.help":{t:0,b:{t:2,i:[{t:3}],s:"在主视图中显示图标"}},"field.show_accounts_icons":{t:0,b:{t:2,i:[{t:3}],s:"显示图标"}},"field.show_email_in_footer.help":{t:0,b:{t:2,i:[{t:3}],s:"在页面底部显示当前登录用户的邮箱地址,而非直接显示导航链接。当 Line truncated
启用此功能可以令 2FAuth 更易于备份:仅需备份数据库,即可保存 2FAuth 的数据以及所有的图标。`}},"field.store_icon_to_database.help_bis":{t:0,b:{t:2,i:[{t:3}],s:`但要注意的是,此功能可能会产生负面效果:如果上传了大量的大体积图标,那么数据库的体积也会显著地增大。
此功能也可能会影响 2FAuth 的性能,因为需要频繁地读写磁盘来保证 ”图标“ 数据与数据库保持同步。`}},"field.store_icon_to_database":{t:0,b:{t:2,i:[{t:3}],s:"保存图标至数据库"}},"field.test_email.help":{t:0,b:{t:2,i:[{t:3}],s:"发送一封测试邮件,验证邮件服务器是否已正确配置。如果配置存在错误,用户将无法收到 “重置密码” 的邮件。"}},"field.test_email":{t:0,b:{t:2,i:[{t:3}],s:"测试送信配置"}},"field.theme.help":{t:0,b:{t:2,i:[{t:3}],s:"手动设置为某个主题,或自动跟随系统 / 浏览器的主题方案"}},"field.theme":{t:0,b:{t:2,i:[{t:3}],s:"主题"}},"field.timezone.help":{t:0,b:{t:2,i:[{t:3}],s:"为所有的 “日期” 与 “时间” 设置时区"}},"field.timezone":{t:0,b:{t:2,i:[{t:3}],s:"时区"}},"field.use_basic_qrcode_reader.help":{t:0,b:{t:2,i:[{t:3}],s:"如果你在扫描二维码时遇到问题,此选项可以切换到更简单但更稳定的二维码扫描器"}},"field.use_basic_qrcode_reader":{t:0,b:{t:2,i:[{t:3}],s:"使用简版二维码扫描器"}},"field.use_chips_to_select_group.help":{t:0,b:{t:2,i:[{t:3}],s:"Show a set of chips above the 2FA account list to allow group toggling direclty from the main view. When disabled, the name of the active group is displayed on a label that must be clicked to invoke the group selector."}},"field.use_chips_to_select_group":{t:0,b:{t:2,i:[{t:3}],s:"Use Chips for toggling"}},"field.use_encryption.help":{t:0,b:{t:2,i:[{t:3}],s:"敏感数据、2FA 秘钥和邮箱地址会以加密形式储存在数据库中。请您务必备份在 .env 中配置的 APP_KEY 的值 (或备份整个 .env 文件)。如果此密钥丢失,那么已加密的数据将无法解密。"}},"field.use_encryption":{t:0,b:{t:2,i:[{t:3}],s:"保护敏感数据"}},"field.use_sso_only.help":{t:0,b:{t:2,i:[{t:3}],s:"仅允许通过 SSO 进行登录。启用此功能后,普通用户将无法使用密码和 WebAuthn 来登录 2FAuth,但管理员不受影响。"}},"field.use_sso_only":{t:0,b:{t:2,i:[{t:3}],s:"仅允许 SSO 登录"}},"field.use_webauthn_only.help":{t:0,b:{t:2,i:[{t:3}],s:"将 WebAuthn 设为 2FAuth 的唯一鉴权方式。若要完全发挥 WebAuth 的安全性,推荐启用此选项。"}},"field.use_webauthn_only.help_bis":{t:0,b:{t:2,i:[{t:3}],s:"当设备丢失时, 您可以重置此选项来恢复您的账户,并使用您的邮箱与密码来登录。"}},"field.use_webauthn_only.help_ter":{t:0,b:{t:2,i:[{t:3}],s:"请注意! 即使启用了此选项,2FAuth 也仍会显示邮箱与密码的登录界面。但如果尝试使用邮箱登录,则会永远提示 “验证失败”。"}},"field.use_webauthn_only":{t:0,b:{t:2,i:[{t:3}],s:"仅允许使用 WebAuthn 鉴权"}},"field.useDirectCapture.help":{t:0,b:{t:2,i:[{t:3}],s:"在数据录入时,默认会提供多种录入的方式供您选择。若您想锁定为某一种方式,您可以打开此选项。"}},"field.useDirectCapture":{t:0,b:{t:2,i:[{t:3}],s:"锁定录入方式"}},"field.view_default_group_on_copy.help":{t:0,b:{t:2,i:[{t:3}],s:"复制 OTP 验证码后,总是返回到默认分组"}},"field.view_default_group_on_copy":{t:0,b:{t:2,i:[{t:3}],s:"复制后返回默认分组"}},"heading.about":{t:0,b:{t:2,i:[{t:3}],s:"关于"}},"heading.access_log":{t:0,b:{t:2,i:[{t:3}],s:"访问日志"}},"heading.access":{t:0,b:{t:2,i:[{t:3}],s:"访问"}},"heading.account_recovery":{t:0,b:{t:2,i:[{t:3}],s:"恢复账户"}},"heading.2fa_accounts":{t:0,b:{t:2,i:[{t:3}],s:"2FA 账号"}},"heading.sharing":{t:0,b:{t:2,i:[{t:3}],s:"分享"}},"heading.sharing_setting":{t:0,b:{t:2,i:[{t:3}],s:"分享设置"}},"heading.authentication":{t:0,b:{t:2,i:[{t:3}],s:"身份认证"}},"heading.browser_restrictions":{t:0,b:{t:2,i:[{t:3}],s:"浏览器限制"}},"heading.change_password":{t:0,b:{t:2,i:[{t:3}],s:"修改密码"}},"heading.danger_zone":{t:0,b:{t:2,i:[{t:3}],s:"危险选项"}},"heading.data_input":{t:0,b:{t:2,i:[{t:3}],s:"数据录入"}},"heading.delete_account":{t:0,b:{t:2,i:[{t:3}],s:"删除账户"}},"heading.edit_account":{t:0,b:{t:2,i:[{t:3}],s:"编辑账号"}},"heading.edit_group":{t:0,b:{t:2,i:[{t:3}],s:"编辑分组"}},"heading.environment":{t:0,b:{t:2,i:[{t:3}],s:"环境变量"}},"heading.general":{t:0,b:{t:2,i:[{t:3}],s:"通用"}},"heading.groups":{t:0,b:{t:2,i:[{t:3}],s:"分组"}},"heading.icons":{t:0,b:{t:2,i:[{t:3}],s:"图标"}},"heading.import":{t:0,b:{t:2,i:[{t:3}],s:"导入"}},"heading.last_accesses":{t:0,b:{t:2,i:[{t:3}],s:"最近访问"}},"heading.login":{t:0,b:{t:2,i:[{t:3}],s:"登录"}},"heading.new_account":{t:0,b:{t:2,i:[{t:3}],s:"新建账号"}},"heading.new_group":{t:0,b:{t:2,i:[{t:3}],s:"新建分组"}},"heading.new_password":{t:0,b:{t:2,i:[{t:3}],s:"新密码"}},"heading.new_sharing":{t:0,b:{t:2,i:[{t:3}],s:"新建分享"}},"heading.new_token":{t:0,b:{t:2,i:[{t:3}],s:"新建令牌"}},"heading.new_user":{t:0,b:{t:2,i:[{t:3}],s:"新用户"}},"heading.notifications":{t:0,b:{t:2,i:[{t:3}],s:" Line truncated
啟用此功能可以令 2FAuth 更易於備份:僅需備份資料庫,即可儲存 2FAuth 的資料以及所有的圖示。`}},"field.store_icon_to_database.help_bis":{t:0,b:{t:2,i:[{t:3}],s:`但要注意的是,此功能可能會產生負面效果:如果上傳了大量的大體積圖示,那麼資料庫的體積也會顯著地增大。
此功能也可能會影響 2FAuth 的性能,因為需要頻繁地讀寫磁碟來保證 」圖示「 資料與資料庫保持同步。`}},"field.store_icon_to_database":{t:0,b:{t:2,i:[{t:3}],s:"儲存圖示至資料庫"}},"field.test_email.help":{t:0,b:{t:2,i:[{t:3}],s:"發送一封測試郵件,以此驗證送信設定是否正確。如果沒有正確地設定郵件伺服器,使用者將無法收到 「重置密碼」 的郵件。"}},"field.test_email":{t:0,b:{t:2,i:[{t:3}],s:"測試送信設定"}},"field.theme.help":{t:0,b:{t:2,i:[{t:3}],s:"手動設定為某個主題,或自動跟隨系統 / 瀏覽器的主題方案"}},"field.theme":{t:0,b:{t:2,i:[{t:3}],s:"主題"}},"field.timezone.help":{t:0,b:{t:2,i:[{t:3}],s:"為所有的 「日期」 與 「時間」 設定時區"}},"field.timezone":{t:0,b:{t:2,i:[{t:3}],s:"時區"}},"field.use_basic_qrcode_reader.help":{t:0,b:{t:2,i:[{t:3}],s:"如果你在掃描QR Code時遇到問題,此選項可以切換到更簡單但更可靠的QR Code掃描器"}},"field.use_basic_qrcode_reader":{t:0,b:{t:2,i:[{t:3}],s:"使用簡版QR Code掃描器"}},"field.use_chips_to_select_group.help":{t:0,b:{t:2,i:[{t:3}],s:"Show a set of chips above the 2FA account list to allow group toggling direclty from the main view. When disabled, the name of the active group is displayed on a label that must be clicked to invoke the group selector."}},"field.use_chips_to_select_group":{t:0,b:{t:2,i:[{t:3}],s:"Use Chips for toggling"}},"field.use_encryption.help":{t:0,b:{t:2,i:[{t:3}],s:"敏感資料、2FA 秘鑰和信箱位址會以加密形式儲存在資料庫中。請您務必備份在 .env 中設定的 APP_KEY 的值 (或備份整個 .env 檔案)。如果此密鑰丟失,那麼已加密的資料將無法解密。"}},"field.use_encryption":{t:0,b:{t:2,i:[{t:3}],s:"保護敏感資料"}},"field.use_sso_only.help":{t:0,b:{t:2,i:[{t:3}],s:"僅允許通過 SSO 進行登入。啟用此功能後,普通使用者將無法使用密碼和 WebAuthn 來登入 2FAuth,但管理員不受此限制的影響。"}},"field.use_sso_only":{t:0,b:{t:2,i:[{t:3}],s:"僅允許 SSO 登入"}},"field.use_webauthn_only.help":{t:0,b:{t:2,i:[{t:3}],s:"將 WebAuthn 設為 2FAuth 的唯一認證方式。若要發揮 WebAuth 的最佳安全性,推薦啟用此選項。"}},"field.use_webauthn_only.help_bis":{t:0,b:{t:2,i:[{t:3}],s:"當設備丟失時, 您可以重置此選項來恢復您的帳號,並使用您的信箱與密碼來登入。"}},"field.use_webauthn_only.help_ter":{t:0,b:{t:2,i:[{t:3}],s:"請注意! 即使啟用此選項,2FAuth 也不會禁用信箱和密碼的登入界面,但如果嘗試使用信箱登入,則永遠會提示 「驗證失敗」。"}},"field.use_webauthn_only":{t:0,b:{t:2,i:[{t:3}],s:"僅允許 WebAuthn"}},"field.useDirectCapture.help":{t:0,b:{t:2,i:[{t:3}],s:"在預設情況下,資料錄入時會提供多種錄入的方式。您可以打開此選項來鎖定到某一種方式"}},"field.useDirectCapture":{t:0,b:{t:2,i:[{t:3}],s:"鎖定錄入方式"}},"field.view_default_group_on_copy.help":{t:0,b:{t:2,i:[{t:3}],s:"複製 OTP 驗證碼後,總是返回到預設分組"}},"field.view_default_group_on_copy":{t:0,b:{t:2,i:[{t:3}],s:"複製後返回預設分組"}},"heading.about":{t:0,b:{t:2,i:[{t:3}],s:"關於"}},"heading.access_log":{t:0,b:{t:2,i:[{t:3}],s:"訪問日誌"}},"heading.access":{t:0,b:{t:2,i:[{t:3}],s:"訪問"}},"heading.account_recovery":{t:0,b:{t:2,i:[{t:3}],s:"恢復帳號"}},"heading.2fa_accounts":{t:0,b:{t:2,i:[{t:3}],s:"2FA accounts"}},"heading.sharing":{t:0,b:{t:2,i:[{t:3}],s:"Sharing"}},"heading.sharing_setting":{t:0,b:{t:2,i:[{t:3}],s:"Sharing setting"}},"heading.authentication":{t:0,b:{t:2,i:[{t:3}],s:"身份認證"}},"heading.browser_restrictions":{t:0,b:{t:2,i:[{t:3}],s:"Browser Restrictions"}},"heading.change_password":{t:0,b:{t:2,i:[{t:3}],s:"修改密碼"}},"heading.danger_zone":{t:0,b:{t:2,i:[{t:3}],s:"危險選項"}},"heading.data_input":{t:0,b:{t:2,i:[{t:3}],s:"資料錄入"}},"heading.delete_account":{t:0,b:{t:2,i:[{t:3}],s:"刪除帳號"}},"heading.edit_account":{t:0,b:{t:2,i:[{t:3}],s:"編輯帳號"}},"heading.edit_group":{t:0,b:{t:2,i:[{t:3}],s:"Edit group"}},"heading.environment":{t:0,b:{t:2,i:[{t:3}],s:"環境變數"}},"heading.general":{t:0,b:{t:2,i:[{t:3}],s:"通用"}},"heading.groups":{t:0,b:{t:2,i:[{t:3}],s:"分組"}},"heading.icons":{t:0,b:{t:2,i:[{t:3}],s:"Icons"}},"heading.import":{t:0,b:{t:2,i:[{t:3}],s:"導入"}},"heading.last_accesses":{t:0,b:{t:2,i:[{t:3}],s:"最近訪問"}},"heading.login":{t:0,b:{t:2,i:[{t:3}],s:"登入"}},"heading.new_account":{t:0,b:{t:2,i:[{t:3}],s:"新建帳號"}},"heading.new_group":{t:0,b:{t:2,i:[{t:3}],s:"新建分組"}},"heading.new_password":{t:0,b:{t:2,i:[{t:3}],s:"新密碼"}},"heading.new_sharing":{t:0,b:{t:2,i:[{t:3}],s:"New sharing"}},"heading.new_token":{t:0,b:{t:2,i:[{t:3}],s:"新建令牌"}},"heading.new_user":{t:0,b:{t:2,i:[{t:3}],s:"新使用者"}},"heading.notifications":{t:0,b:{t:2,i:[{t:3}],s: Line truncated
`,Uk="\u2028",jk="\u2029";function Mk(t){const e=t;let i=0,s=1,a=1,o=0;const r=F=>e[F]===Lk&&e[F+1]===ke,n=F=>e[F]===ke,l=F=>e[F]===jk,u=F=>e[F]===Uk,d=F=>r(F)||n(F)||l(F)||u(F),c=()=>i,_=()=>s,p=()=>a,v=()=>o,g=F=>r(F)||l(F)||u(F)?ke:e[F],y=()=>g(i),m=()=>g(i+o);function w(){return o=0,d(i)&&(s++,a=0),r(i)&&i++,i++,a++,e[i]}function x(){return r(i+o)&&o++,o++,e[i+o]}function f(){i=0,s=1,a=1,o=0}function T(F=0){o=F}function P(){const F=i+o;for(;F!==i;)w();o=0}return{index:c,line:_,column:p,peekOffset:v,charAt:g,currentChar:y,currentPeek:m,next:w,peek:x,reset:f,resetPeek:T,skipToPeek:P}}const Ei=void 0,Wk=".",fc="'",Bk="tokenizer";function $k(t,e={}){const i=e.location!==!1,s=Mk(t),a=()=>s.index(),o=()=>zk(s.line(),s.column(),s.index()),r=o(),n=a(),l={currentType:13,offset:n,startLoc:r,endLoc:r,lastType:13,lastOffset:n,lastStartLoc:r,lastEndLoc:r,braceNest:0,inLinked:!1,text:""},u=()=>l,{onError:d}=e;function c(b,h,A,...E){const Y=u();if(h.column+=A,h.offset+=A,d){const U=i?dl(Y.startLoc,h):null,k=jr(b,U,{domain:Bk,args:E});d(k)}}function _(b,h,A){b.endLoc=o(),b.currentType=h;const E={type:h};return i&&(E.loc=dl(b.startLoc,b.endLoc)),A!=null&&(E.value=A),E}const p=b=>_(b,13);function v(b,h){return b.currentChar()===h?(b.next(),h):(c(Mt.EXPECTED_TOKEN,o(),0,h),"")}function g(b){let h="";for(;b.currentPeek()===_i||b.currentPeek()===ke;)h+=b.currentPeek(),b.peek();return h}function y(b){const h=g(b);return b.skipToPeek(),h}function m(b){if(b===Ei)return!1;const h=b.charCodeAt(0);return h>=97&&h<=122||h>=65&&h<=90||h===95}function w(b){if(b===Ei)return!1;const h=b.charCodeAt(0);return h>=48&&h<=57}function x(b,h){const{currentType:A}=h;if(A!==2)return!1;g(b);const E=m(b.currentPeek());return b.resetPeek(),E}function f(b,h){const{currentType:A}=h;if(A!==2)return!1;g(b);const E=b.currentPeek()==="-"?b.peek():b.currentPeek(),Y=w(E);return b.resetPeek(),Y}function T(b,h){const{currentType:A}=h;if(A!==2)return!1;g(b);const E=b.currentPeek()===fc;return b.resetPeek(),E}function P(b,h){const{currentType:A}=h;if(A!==7)return!1;g(b);const E=b.currentPeek()===".";return b.resetPeek(),E}function F(b,h){const{currentType:A}=h;if(A!==8)return!1;g(b);const E=m(b.currentPeek());return b.resetPeek(),E}function B(b,h){const{currentType:A}=h;if(!(A===7||A===11))return!1;g(b);const E=b.currentPeek()===":";return b.resetPeek(),E}function q(b,h){const{currentType:A}=h;if(A!==9)return!1;const E=()=>{const U=b.currentPeek();return U==="{"?m(b.peek()):U==="@"||U==="|"||U===":"||U==="."||U===_i||!U?!1:U===ke?(b.peek(),E()):Q(b,!1)},Y=E();return b.resetPeek(),Y}function N(b){g(b);const h=b.currentPeek()==="|";return b.resetPeek(),h}function Q(b,h=!0){const A=(Y=!1,U="")=>{const k=b.currentPeek();return k==="{"||k==="@"||!k?Y:k==="|"?!(U===_i||U===ke):k===_i?(b.peek(),A(!0,_i)):k===ke?(b.peek(),A(!0,ke)):!0},E=A();return h&&b.resetPeek(),E}function z(b,h){const A=b.currentChar();return A===Ei?Ei:h(A)?(b.next(),A):null}function X(b){const h=b.charCodeAt(0);return h>=97&&h<=122||h>=65&&h<=90||h>=48&&h<=57||h===95||h===36}function L(b){return z(b,X)}function tt(b){const h=b.charCodeAt(0);return h>=97&&h<=122||h>=65&&h<=90||h>=48&&h<=57||h===95||h===36||h===45}function et(b){return z(b,tt)}function ht(b){const h=b.charCodeAt(0);return h>=48&&h<=57}function mt(b){return z(b,ht)}function yt(b){const h=b.charCodeAt(0);return h>=48&&h<=57||h>=65&&h<=70||h>=97&&h<=102}function Pt(b){return z(b,yt)}function _t(b){let h="",A="";for(;h=mt(b);)A+=h;return A}function lt(b){let h="";for(;;){const A=b.currentChar();if(A==="\\"){const E=b.peek();E==="{"||E==="}"||E==="@"||E==="|"||E==="\\"?(h+=A+E,b.next(),b.next()):(b.resetPeek(),h+=A,b.next())}else{if(A==="{"||A==="}"||A==="@"||A==="|"||!A)break;if(A===_i||A===ke)if(Q(b))h+=A,b.next();else{if(N(b))break;h+=A,b.next()}else h+=A,b.next()}}return h}function gt(b){y(b);let h="",A="";for(;h=et(b);)A+=h;const E=b.currentChar();if(E&&E!=="}"&&E!==Ei&&E!==_i&&E!==ke&&E!==" "){const Y=ut(b);return c(Mt.INVALID_TOKEN_IN_PLACEHOLDER,o(),0,A+Y),A+Y}return b.currentChar()===Ei&&c(Mt.UNTERMINATED_CLOSING_BRACE,o(),0),A}function Qt(b){y(b);let h="";return b.currentChar()==="-"?(b.next(),h+=`-${_t(b)}`):h+=_t(b),b.currentChar()===Ei&&c(Mt.UNTERMINATED_CLOSING_BRACE,o(),0),h}function Xt(b){return b!==fc&&b!==ke}function te(b){y(b),v(b,"'");let h="",A="";for(;h=z(b,Xt);)h==="\\"?A+=j(b):A+=h;const E=b.currentChar();return E===ke||E===Ei?(c(Mt.UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER,o(),0),E===ke&&(b.next(),v(b,"'")),A):(v(b,"'"),A)}function j(b){const h=b.currentChar();switch(h){case"\\":case"'":return b.next(),`\\${h}`;case"u":return K(b,h,4);case"U":return K(b,h,6);default:return c(Mt.UNKNOWN_ESCAPE_SEQUENCE,o(),0,h),""}}function K(b,h,A){v(b,h);let E="";for(let Y=0;Y<A;Y++){const U=Pt(b);if(!U){c(Mt.INVALID_UNICODE_ESCAPE_SEQUENCE,o(),0,`\\${h}${E}${b.currentChar()}`);break}E+=U}return`\\${h}${E}`}function Z(b){return b!=="{"&&b!=="}"&&b!==_i&&b!==ke}function ut(b){y(b);let h="",A="";for(;h=z(b,Z);)A+=h;return A}f Line truncated
`,o=e.needIndent?e.needIndent:i!=="arrow",r=t.helpers||[],n=tA(t,{filename:s,breakLineCode:a,needIndent:o});n.push(i==="normal"?"function __msg__ (ctx) {":"(ctx) => {"),n.indent(o),r.length>0&&(n.push(`const { ${ru(r.map(d=>`${d}: _${d}`),", ")} } = ctx`),n.newline()),n.push("return "),ra(n,t),n.deindent(o),n.push("}"),delete t.helpers;const{code:l,map:u}=n.context();return{ast:t,code:l,map:u?u.toJSON():void 0}};function rA(t,e={}){const i=me({},e),s=!!i.jit,a=!!i.minify,o=i.optimize==null?!0:i.optimize,n=Yk(i).parse(t);return s?(o&&Xk(n),a&&Bs(n),{ast:n,code:""}):(Zk(n,i),oA(n,i))}function nA(){typeof __INTLIFY_PROD_DEVTOOLS__!="boolean"&&(su().__INTLIFY_PROD_DEVTOOLS__=!1)}function xi(t){return It(t)&&lu(t)===0&&(Xe(t,"b")||Xe(t,"body"))}const Yh=["b","body"];function lA(t){return cs(t,Yh)}const Jh=["c","cases"];function uA(t){return cs(t,Jh,[])}const Zh=["s","static"];function dA(t){return cs(t,Zh)}const Xh=["i","items"];function cA(t){return cs(t,Xh,[])}const tp=["t","type"];function lu(t){return cs(t,tp)}const ep=["v","value"];function So(t,e){const i=cs(t,ep);if(i!=null)return i;throw Qa(e)}const ip=["m","modifier"];function bA(t){return cs(t,ip)}const sp=["k","key"];function _A(t){const e=cs(t,sp);if(e)return e;throw Qa(6)}function cs(t,e,i){for(let s=0;s<e.length;s++){const a=e[s];if(Xe(t,a)&&t[a]!=null)return t[a]}return i}const ap=[...Yh,...Jh,...Zh,...Xh,...sp,...ip,...ep,...tp];function Qa(t){return new Error(`unhandled node type: ${t}`)}function xn(t){return i=>hA(i,t)}function hA(t,e){const i=lA(e);if(i==null)throw Qa(0);if(lu(i)===1){const o=uA(i);return t.plural(o.reduce((r,n)=>[...r,yc(t,n)],[]))}else return yc(t,i)}function yc(t,e){const i=dA(e);if(i!=null)return t.type==="text"?i:t.normalize([i]);{const s=cA(e).reduce((a,o)=>[...a,cl(t,o)],[]);return t.normalize(s)}}function cl(t,e){const i=lu(e);switch(i){case 3:return So(e,i);case 9:return So(e,i);case 4:{const s=e;if(Xe(s,"k")&&s.k)return t.interpolate(t.named(s.k));if(Xe(s,"key")&&s.key)return t.interpolate(t.named(s.key));throw Qa(i)}case 5:{const s=e;if(Xe(s,"i")&&be(s.i))return t.interpolate(t.list(s.i));if(Xe(s,"index")&&be(s.index))return t.interpolate(t.list(s.index));throw Qa(i)}case 6:{const s=e,a=bA(s),o=_A(s);return t.linked(cl(t,o),a?cl(t,a):void 0,t.type)}case 7:return So(e,i);case 8:return So(e,i);default:throw new Error(`unhandled node on format message part: ${i}`)}}const pA=t=>t;let Fo=Gt();function mA(t,e={}){let i=!1;const s=e.onError||Nk;return e.onError=a=>{i=!0,s(a)},{...rA(t,e),detectError:i}}function gA(t,e){if(ct(t)){ae(e.warnHtmlMessage)&&e.warnHtmlMessage;const s=(e.onCacheKey||pA)(t),a=Fo[s];if(a)return a;const{ast:o,detectError:r}=mA(t,{...e,location:!1,jit:!0}),n=xn(o);return r?n:Fo[s]=n}else{const i=t.cacheKey;if(i){const s=Fo[i];return s||(Fo[i]=xn(t))}else return xn(t)}}let Ka=null;function fA(t){Ka=t}function vA(t,e,i){Ka&&Ka.emit("i18n:init",{timestamp:Date.now(),i18n:t,version:e,meta:i})}const wA=yA("function:translate");function yA(t){return e=>Ka&&Ka.emit(t,e)}const Di={INVALID_ARGUMENT:Dk,INVALID_DATE_ARGUMENT:18,INVALID_ISO_DATE_ARGUMENT:19,NOT_SUPPORT_LOCALE_PROMISE_VALUE:21,NOT_SUPPORT_LOCALE_ASYNC_FUNCTION:22,NOT_SUPPORT_LOCALE_TYPE:23},kA=24;function Ni(t){return jr(t,null,void 0)}function uu(t,e){return e.locale!=null?kc(e.locale):kc(t.locale)}let Tn;function kc(t){if(ct(t))return t;if(ne(t)){if(t.resolvedOnce&&Tn!=null)return Tn;if(t.constructor.name==="Function"){const e=t();if(Ck(e))throw Ni(Di.NOT_SUPPORT_LOCALE_PROMISE_VALUE);return Tn=e}else throw Ni(Di.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION)}else throw Ni(Di.NOT_SUPPORT_LOCALE_TYPE)}function AA(t,e,i){return[...new Set([i,...ue(e)?e:It(e)?Object.keys(e):ct(e)?[e]:[i]])]}function bl(t,e,i){const s=ct(i)?i:nr,a=t;a.__localeChainCache||(a.__localeChainCache=new Map);let o=a.__localeChainCache.get(s);if(!o){o=[];let r=[i];for(;ue(r);)r=Ac(o,r,e);const n=ue(e)||!Dt(e)?e:e.default?e.default:null;r=ct(n)?[n]:n,ue(r)&&Ac(o,r,!1),a.__localeChainCache.set(s,o)}return o}function Ac(t,e,i){let s=!0;for(let a=0;a<e.length&&ae(s);a++){const o=e[a];ct(o)&&(s=xA(t,e[a],i))}return s}function xA(t,e,i){let s;const a=e.split("-");do{const o=a.join("-");s=TA(t,o,i),a.splice(-1,1)}while(a.length&&s===!0);return s}function TA(t,e,i){let s=!1;if(!t.includes(e)&&(s=!0,e)){s=e[e.length-1]!=="!";const a=e.replace(/!/g,"");t.push(a),(ue(i)||Dt(i))&&i[a]&&(s=i[a])}return s}const bs=[];bs[0]={w:[0],i:[3,0],"[":[4],o:[7]};bs[1]={w:[1],".":[2],"[":[4],o:[7]};bs[2]={w:[2],i:[3,0],0:[3,0]};bs[3]={i:[3,0],0:[3,0],w:[1,1],".":[2,1],"[":[4,1],o:[7,1]};bs[4]={"'":[5,0],'"':[6,0],"[":[4,2],"]":[1,3],o:8,l:[4,0]};bs[5]={"'":[4,0],o:8,l:[5,0]};bs[6]={'"':[4,0],o:8,l:[6,0]};const SA=/^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;function FA(t){return SA.test(t)}function PA(t){const e=t.charCodeAt(0),i=t.charCodeAt(t.length-1);return e===i&&(e===34||e===39)?t.slice(1,-1):t}function EA(t){if(t==null)return"o";switch(t.charCodeAt(0)){case 91:case 93:case 46:case 34:case 39:retur Line truncated
`).forEach(function(r){a=r.indexOf(":"),i=r.substring(0,a).trim().toLowerCase(),s=r.substring(a+1).trim(),!(!i||e[i]&&IF[i])&&(i==="set-cookie"?e[i]?e[i].push(s):e[i]=[s]:e[i]=e[i]?e[i]+", "+s:s)}),e};function DF(t){let e=0,i=t.length;for(;e<i;){const s=t.charCodeAt(e);if(s!==9&&s!==32)break;e+=1}for(;i>e;){const s=t.charCodeAt(i-1);if(s!==9&&s!==32)break;i-=1}return e===0&&i===t.length?t:t.slice(e,i)}const NF=new RegExp("[\\u0000-\\u0008\\u000a-\\u001f\\u007f]+","g"),LF=new RegExp("[^\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+","g");function mu(t,e){return I.isArray(t)?t.map(i=>mu(i,e)):DF(String(t).replace(e,""))}const UF=t=>mu(t,NF),jF=t=>mu(t,LF);function jp(t){const e=Object.create(null);return I.forEach(t.toJSON(),(i,s)=>{e[s]=jF(i)}),e}const tb=Symbol("internals");function ka(t){return t&&String(t).trim().toLowerCase()}function jo(t){return t===!1||t==null?t:I.isArray(t)?t.map(jo):UF(String(t))}function MF(t){const e=Object.create(null),i=/([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g;let s;for(;s=i.exec(t);)e[s[1]]=s[2];return e}const WF=t=>/^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(t.trim());function Rn(t,e,i,s,a){if(I.isFunction(s))return s.call(this,e,i);if(a&&(e=i),!!I.isString(e)){if(I.isString(s))return e.indexOf(s)!==-1;if(I.isRegExp(s))return s.test(e)}}function BF(t){return t.trim().toLowerCase().replace(/([a-z\d])(\w*)/g,(e,i,s)=>i.toUpperCase()+s)}function $F(t,e){const i=I.toCamelCase(" "+e);["get","set","has"].forEach(s=>{Object.defineProperty(t,s+i,{__proto__:null,value:function(a,o,r){return this[s].call(this,e,a,o,r)},configurable:!0})})}let Ce=class{constructor(e){e&&this.set(e)}set(e,i,s){const a=this;function o(n,l,u){const d=ka(l);if(!d)throw new Error("header name must be a non-empty string");const c=I.findKey(a,d);(!c||a[c]===void 0||u===!0||u===void 0&&a[c]!==!1)&&(a[c||l]=jo(n))}const r=(n,l)=>I.forEach(n,(u,d)=>o(u,d,l));if(I.isPlainObject(e)||e instanceof this.constructor)r(e,i);else if(I.isString(e)&&(e=e.trim())&&!WF(e))r(zF(e),i);else if(I.isObject(e)&&I.isIterable(e)){let n={},l,u;for(const d of e){if(!I.isArray(d))throw TypeError("Object iterator must return a key-value pair");n[u=d[0]]=(l=n[u])?I.isArray(l)?[...l,d[1]]:[l,d[1]]:d[1]}r(n,i)}else e!=null&&o(i,e,s);return this}get(e,i){if(e=ka(e),e){const s=I.findKey(this,e);if(s){const a=this[s];if(!i)return a;if(i===!0)return MF(a);if(I.isFunction(i))return i.call(this,a,s);if(I.isRegExp(i))return i.exec(a);throw new TypeError("parser must be boolean|regexp|function")}}}has(e,i){if(e=ka(e),e){const s=I.findKey(this,e);return!!(s&&this[s]!==void 0&&(!i||Rn(this,this[s],s,i)))}return!1}delete(e,i){const s=this;let a=!1;function o(r){if(r=ka(r),r){const n=I.findKey(s,r);n&&(!i||Rn(s,s[n],n,i))&&(delete s[n],a=!0)}}return I.isArray(e)?e.forEach(o):o(e),a}clear(e){const i=Object.keys(this);let s=i.length,a=!1;for(;s--;){const o=i[s];(!e||Rn(this,this[o],o,e,!0))&&(delete this[o],a=!0)}return a}normalize(e){const i=this,s={};return I.forEach(this,(a,o)=>{const r=I.findKey(s,o);if(r){i[r]=jo(a),delete i[o];return}const n=e?BF(o):String(o).trim();n!==o&&delete i[o],i[n]=jo(a),s[n]=!0}),this}concat(...e){return this.constructor.concat(this,...e)}toJSON(e){const i=Object.create(null);return I.forEach(this,(s,a)=>{s!=null&&s!==!1&&(i[a]=e&&I.isArray(s)?s.join(", "):s)}),i}[Symbol.iterator](){return Object.entries(this.toJSON())[Symbol.iterator]()}toString(){return Object.entries(this.toJSON()).map(([e,i])=>e+": "+i).join(`
`)}getSetCookie(){return this.get("set-cookie")||[]}get[Symbol.toStringTag](){return"AxiosHeaders"}static from(e){return e instanceof this?e:new this(e)}static concat(e,...i){const s=new this(e);return i.forEach(a=>s.set(a)),s}static accessor(e){const s=(this[tb]=this[tb]={accessors:{}}).accessors,a=this.prototype;function o(r){const n=ka(r);s[n]||($F(a,r),s[n]=!0)}return I.isArray(e)?e.forEach(o):o(e),this}};Ce.accessor(["Content-Type","Content-Length","Accept","Accept-Encoding","User-Agent","Authorization"]);I.reduceDescriptors(Ce.prototype,({value:t},e)=>{let i=e[0].toUpperCase()+e.slice(1);return{get:()=>t,set(s){this[i]=s}}});I.freezeMethods(Ce);const HF="[REDACTED ****]";function GF(t){if(I.hasOwnProp(t,"toJSON"))return!0;let e=Object.getPrototypeOf(t);for(;e&&e!==Object.prototype;){if(I.hasOwnProp(e,"toJSON"))return!0;e=Object.getPrototypeOf(e)}return!1}function VF(t,e){const i=new Set(e.map(o=>String(o).toLowerCase())),s=[],a=o=>{if(o===null||typeof o!="object"||I.isBuffer(o))return o;if(s.indexOf(o)!==-1)return;o instanceof Ce&&(o=o.toJSON()),s.push(o);let r;if(I.isArray(o))r=[],o.forEach((n,l)=>{const u=a(n);I.isUndefined(u)||(r[l]=u)});else{if(!I.isPlainObject(o)&&GF(o))return s.pop(),o;r=Object.create(null);for(const[n,l]of Object.entries(o)){const u=i.has(n.toLowerCase())?HF:a(l);I.isUndefined(u)||(r[n]=u)}}return s.pop(),r};return a(t)}let bt=class Mp extends Error{static from(e,i,s,a,o,r){const n=new Mp(e.message,i||e.code,s,a,o);return n.cause=e,n.name=e.name,e.status!=null&&n.status==null&&(n.status=e.status),r&&Object.assign(n,r),n}constructor(e,i,s,a,o){super(e),Object.defineProperty(this,"message",{__proto__:null,value:e,enumerable:!0,writable:!0,configurable:!0}),this.name="AxiosError",this.isAxiosError=!0,i&&(this.code=i),s&&(this.config=s),a&&(this.request=a),o&&(this.response=o,this.status=o.status)}toJSON(){const e=this.config,i=e&&I.hasOwnProp(e,"redact")?e.redact:void 0,s=I.isArray(i)&&i.length>0?VF(e,i):I.toJSONObject(e);return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:s,code:this.code,status:this.status}}};bt.ERR_BAD_OPTION_VALUE="ERR_BAD_OPTION_VALUE";bt.ERR_BAD_OPTION="ERR_BAD_OPTION";bt.ECONNABORTED="ECONNABORTED";bt.ETIMEDOUT="ETIMEDOUT";bt.ECONNREFUSED="ECONNREFUSED";bt.ERR_NETWORK="ERR_NETWORK";bt.ERR_FR_TOO_MANY_REDIRECTS="ERR_FR_TOO_MANY_REDIRECTS";bt.ERR_DEPRECATED="ERR_DEPRECATED";bt.ERR_BAD_RESPONSE="ERR_BAD_RESPONSE";bt.ERR_BAD_REQUEST="ERR_BAD_REQUEST";bt.ERR_CANCELED="ERR_CANCELED";bt.ERR_NOT_SUPPORT="ERR_NOT_SUPPORT";bt.ERR_INVALID_URL="ERR_INVALID_URL";bt.ERR_FORM_DATA_DEPTH_EXCEEDED="ERR_FORM_DATA_DEPTH_EXCEEDED";const QF=null;function Tl(t){return I.isPlainObject(t)||I.isArray(t)}function Wp(t){return I.endsWith(t,"[]")?t.slice(0,-2):t}function qn(t,e,i){return t?t.concat(e).map(function(a,o){return a=Wp(a),!i&&o?"["+a+"]":a}).join(i?".":""):e}function KF(t){return I.isArray(t)&&!t.some(Tl)}const YF=I.toFlatObject(I,{},null,function(e){return/^is[A-Z]/.test(e)});function Kr(t,e,i){if(!I.isObject(t))throw new TypeError("target must be an object");e=e||new FormData,i=I.toFlatObject(i,{metaTokens:!0,dots:!1,indexes:!1},!1,function(y,m){return!I.isUndefined(m[y])});const s=i.metaTokens,a=i.visitor||c,o=i.dots,r=i.indexes,n=i.Blob||typeof Blob<"u"&&Blob,l=i.maxDepth===void 0?100:i.maxDepth,u=n&&I.isSpecCompliantForm(e);if(!I.isFunction(a))throw new TypeError("visitor must be a function");function d(g){if(g===null)return"";if(I.isDate(g))return g.toISOString();if(I.isBoolean(g))return g.toString();if(!u&&I.isBlob(g))throw new bt("Blob is not supported. Use a Buffer instead.");return I.isArrayBuffer(g)||I.isTypedArray(g)?u&&typeof Blob=="function"?new Blob([g]):Buffer.from(g):g}function c(g,y,m){let w=g;if(I.isReactNative(e)&&I.isReactNativeBlob(g))return e.append(qn(m,y,o),d(g)),!1;if(g&&!m&&typeof g=="object"){if(I.endsWith(y,"{}"))y=s?y:y.slice(0,-2),g=JSON.stringify(g);else if(I.isArray(g)&&KF(g)||(I.isFileList(g)||I.endsWith(y,"[]"))&&(w=I.toArray(g)))return y=Wp(y),w.forEach(function(f,T){!(I.isUndefined(f)||f===null)&&e.append(r===!0?qn([y],T,o):r===null?y:y+"[]",d(f))}),!1}return Tl(g)?!0:(e.append(qn(m,y,o),d(g)),!1)}const _=[],p=Object.assign(YF,{defaultVisitor:c,convertValue:d,isVisitable:Tl});function v(g,y,m=0){if(!I.isUndefined(g)){if(m>l)throw new bt("Object is too deeply nested ("+m+" levels). Max depth: "+l,bt.ERR_FORM_DATA_DEPTH_EXCEEDED);if(_.indexOf(g)!==-1)throw Error("Circular reference detected in "+y.join("."));_.push(g),I.forEach(g,function(x,f){(!(I.isUndefined(x)||x===null)&&a.call(e,x,I.isString(f)?f.trim():f,y,p))===!0&&v(x,y?y.concat(f):[f],m+1)}),_.pop()}}if(!I.isObject(t))throw new TypeError("data must be an object");return v(t),e}function eb(t){const e={"!":"%21","'":"%27","(":"%28",")":"%29","~":"%7E","%20":"+"};return encodeURIComponent(t).replace(/[!'()~]|%20/g,function(s){return e[s]})} Line truncated
`+r.map(ub).join(`
`):" "+ub(r[0]):"as no adapter specified";throw new bt("There is no suitable adapter to dispatch the request "+n,"ERR_NOT_SUPPORT")}return a}const Jp={getAdapter:OP,adapters:yu};function In(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new co(null,t)}function db(t){return In(t),t.headers=Ce.from(t.headers),t.data=Cn.call(t,t.transformRequest),["post","put","patch"].indexOf(t.method)!==-1&&t.headers.setContentType("application/x-www-form-urlencoded",!1),Jp.getAdapter(t.adapter||uo.adapter,t)(t).then(function(s){In(t),t.response=s;try{s.data=Cn.call(t,t.transformResponse,s)}finally{delete t.response}return s.headers=Ce.from(s.headers),s},function(s){if(!Gp(s)&&(In(t),s&&s.response)){t.response=s.response;try{s.response.data=Cn.call(t,t.transformResponse,s.response)}finally{delete t.response}s.response.headers=Ce.from(s.response.headers)}return Promise.reject(s)})}const Yr={};["object","boolean","number","function","string","symbol"].forEach((t,e)=>{Yr[t]=function(s){return typeof s===t||"a"+(e<1?"n ":" ")+t}});const cb={};Yr.transitional=function(e,i,s){function a(o,r){return"[Axios v"+wu+"] Transitional option '"+o+"'"+r+(s?". "+s:"")}return(o,r,n)=>{if(e===!1)throw new bt(a(r," has been removed"+(i?" in "+i:"")),bt.ERR_DEPRECATED);return i&&!cb[r]&&(cb[r]=!0,console.warn(a(r," has been deprecated since v"+i+" and will be removed in the near future"))),e?e(o,r,n):!0}};Yr.spelling=function(e){return(i,s)=>(console.warn(`${s} is likely a misspelling of ${e}`),!0)};function RP(t,e,i){if(typeof t!="object")throw new bt("options must be an object",bt.ERR_BAD_OPTION_VALUE);const s=Object.keys(t);let a=s.length;for(;a-- >0;){const o=s[a],r=Object.prototype.hasOwnProperty.call(e,o)?e[o]:void 0;if(r){const n=t[o],l=n===void 0||r(n,o,t);if(l!==!0)throw new bt("option "+o+" must be "+l,bt.ERR_BAD_OPTION_VALUE);continue}if(i!==!0)throw new bt("Unknown option "+o,bt.ERR_BAD_OPTION)}}const Mo={assertOptions:RP,validators:Yr},Qe=Mo.validators;let As=class{constructor(e){this.defaults=e||{},this.interceptors={request:new ib,response:new ib}}async request(e,i){try{return await this._request(e,i)}catch(s){if(s instanceof Error){let a={};Error.captureStackTrace?Error.captureStackTrace(a):a=new Error;const o=(()=>{if(!a.stack)return"";const r=a.stack.indexOf(`
`);return r===-1?"":a.stack.slice(r+1)})();try{if(!s.stack)s.stack=o;else if(o){const r=o.indexOf(`
`),n=r===-1?-1:o.indexOf(`
`,r+1),l=n===-1?"":o.slice(n+1);String(s.stack).endsWith(l)||(s.stack+=`
`+o)}}catch{}}throw s}}_request(e,i){typeof e=="string"?(i=i||{},i.url=e):i=e||{},i=Fs(this.defaults,i);const{transitional:s,paramsSerializer:a,headers:o}=i;s!==void 0&&Mo.assertOptions(s,{silentJSONParsing:Qe.transitional(Qe.boolean),forcedJSONParsing:Qe.transitional(Qe.boolean),clarifyTimeoutError:Qe.transitional(Qe.boolean),legacyInterceptorReqResOrdering:Qe.transitional(Qe.boolean)},!1),a!=null&&(I.isFunction(a)?i.paramsSerializer={serialize:a}:Mo.assertOptions(a,{encode:Qe.function,serialize:Qe.function},!0)),i.allowAbsoluteUrls!==void 0||(this.defaults.allowAbsoluteUrls!==void 0?i.allowAbsoluteUrls=this.defaults.allowAbsoluteUrls:i.allowAbsoluteUrls=!0),Mo.assertOptions(i,{baseUrl:Qe.spelling("baseURL"),withXsrfToken:Qe.spelling("withXSRFToken")},!0),i.method=(i.method||this.defaults.method||"get").toLowerCase();let r=o&&I.merge(o.common,o[i.method]);o&&I.forEach(["delete","get","head","post","put","patch","query","common"],v=>{delete o[v]}),i.headers=Ce.concat(r,o);const n=[];let l=!0;this.interceptors.request.forEach(function(g){if(typeof g.runWhen=="function"&&g.runWhen(i)===!1)return;l=l&&g.synchronous;const y=i.transitional||fu;y&&y.legacyInterceptorReqResOrdering?n.unshift(g.fulfilled,g.rejected):n.push(g.fulfilled,g.rejected)});const u=[];this.interceptors.response.forEach(function(g){u.push(g.fulfilled,g.rejected)});let d,c=0,_;if(!l){const v=[db.bind(this),void 0];for(v.unshift(...n),v.push(...u),_=v.length,d=Promise.resolve(i);c<_;)d=d.then(v[c++],v[c++]);return d}_=n.length;let p=i;for(;c<_;){const v=n[c++],g=n[c++];try{p=v(p)}catch(y){g.call(this,y);break}}try{d=db.call(this,p)}catch(v){return Promise.reject(v)}for(c=0,_=u.length;c<_;)d=d.then(u[c++],u[c++]);return d}getUri(e){e=Fs(this.defaults,e);const i=Qp(e.baseURL,e.url,e.allowAbsoluteUrls);return $p(i,e.params,e.paramsSerializer)}};I.forEach(["delete","get","head","options"],function(e){As.prototype[e]=function(i,s){return this.request(Fs(s||{},{method:e,url:i,data:(s||{}).data}))}});I.forEach(["post","put","patch","query"],function(e){function i(s){return function(o,r,n){return this.request(Fs(n||{},{method:e,headers:s?{"Content-Type":"multipart/form-data"}:{},url:o,data:r}))}}As.prototype[e]=i(),e!=="query"&&(As.prototype[e+"Form"]=i(!0))});let qP=class Zp{constructor(e){if(typeof e!="function")throw new TypeError("executor must be a function.");let i;this.promise=new Promise(function(o){i=o});const s=this;this.promise.then(a=>{if(!s._listeners)return;let o=s._listeners.length;for(;o-- >0;)s._listeners[o](a);s._listeners=null}),this.promise.then=a=>{let o;const r=new Promise(n=>{s.subscribe(n),o=n}).then(a);return r.cancel=function(){s.unsubscribe(o)},r},e(function(o,r,n){s.reason||(s.reason=new co(o,r,n),i(s.reason))})}throwIfRequested(){if(this.reason)throw this.reason}subscribe(e){if(this.reason){e(this.reason);return}this._listeners?this._listeners.push(e):this._listeners=[e]}unsubscribe(e){if(!this._listeners)return;const i=this._listeners.indexOf(e);i!==-1&&this._listeners.splice(i,1)}toAbortSignal(){const e=new AbortController,i=s=>{e.abort(s)};return this.subscribe(i),e.signal.unsubscribe=()=>this.unsubscribe(i),e.signal}static source(){let e;return{token:new Zp(function(a){e=a}),cancel:e}}};function CP(t){return function(i){return t.apply(null,i)}}function IP(t){return I.isObject(t)&&t.isAxiosError===!0}const Fl={Continue:100,SwitchingProtocols:101,Processing:102,EarlyHints:103,Ok:200,Created:201,Accepted:202,NonAuthoritativeInformation:203,NoContent:204,ResetContent:205,PartialContent:206,MultiStatus:207,AlreadyReported:208,ImUsed:226,MultipleChoices:300,MovedPermanently:301,Found:302,SeeOther:303,NotModified:304,UseProxy:305,Unused:306,TemporaryRedirect:307,PermanentRedirect:308,BadRequest:400,Unauthorized:401,PaymentRequired:402,Forbidden:403,NotFound:404,MethodNotAllowed:405,NotAcceptable:406,ProxyAuthenticationRequired:407,RequestTimeout:408,Conflict:409,Gone:410,LengthRequired:411,PreconditionFailed:412,PayloadTooLarge:413,UriTooLong:414,UnsupportedMediaType:415,RangeNotSatisfiable:416,ExpectationFailed:417,ImATeapot:418,MisdirectedRequest:421,UnprocessableEntity:422,Locked:423,FailedDependency:424,TooEarly:425,UpgradeRequired:426,PreconditionRequired:428,TooManyRequests:429,RequestHeaderFieldsTooLarge:431,UnavailableForLegalReasons:451,InternalServerError:500,NotImplemented:501,BadGateway:502,ServiceUnavailable:503,GatewayTimeout:504,HttpVersionNotSupported:505,VariantAlsoNegotiates:506,InsufficientStorage:507,LoopDetected:508,NotExtended:510,NetworkAuthenticationRequired:511,WebServerIsDown:521,ConnectionTimedOut:522,OriginIsUnreachable:523,TimeoutOccurred:524,SslHandshakeFailed:525,InvalidSslCertificate:526};Object.entries(Fl).forEach(([t,e])=>{Fl[e]=t});function Xp(t){const e=new As(t),i=qp(As.prototype.request,e);return I.extend(i,As.prototype,e,{allOwnKeys:!0}),I.extend(i,e,null,{allOwnKeys:!0}),i.create=function(a){return Xp(Fs(t,a))},i}const oe=Xp(uo);oe.Axios=As;oe.CanceledError=co;oe.CancelToken=qP;oe.isCa Line truncated
`)],{type:"text/plain;charset=utf-8"});_b.saveAs.saveAs(s,"2fauth_export_otpauth.txt")}):Aa.export(this.selectedIds.join(),!1,{responseType:"blob"}).then(e=>{var i=new Blob([e.data],{type:"application/json;charset=utf-8"});_b.saveAs.saveAs(i,"2fauth_export.json")})},saveOrder(t="free"){Aa.saveOrder(this.orderedIds).then(()=>{Ne().preferences.sortOrder=t,e0.updatePreference("sortOrder",t)})},sortDefault(){Ne().preferences.sortOrder=="asc"&&this.sortAsc(),Ne().preferences.sortOrder=="desc"&&this.sortDesc()},sortAsc(){this.items.sort(function(t,e){const i=t.service??"",s=e.service??"";return Ne().preferences.sortCaseSensitive?i.normalize("NFD").replace(/[\u0300-\u036f]/g,"")>s.normalize("NFD").replace(/[\u0300-\u036f]/g,"")?1:-1:i.localeCompare(s,Ne().preferences.lang)}),this.saveOrder("asc")},sortDesc(){this.items.sort(function(t,e){const i=t.service??"",s=e.service??"";return Ne().preferences.sortCaseSensitive?i.normalize("NFD").replace(/[\u0300-\u036f]/g,"")<s.normalize("NFD").replace(/[\u0300-\u036f]/g,"")?1:-1:s.localeCompare(i,Ne().preferences.lang)}),this.saveOrder("desc")},accountIdsWithPeriod(t){return this.items.filter(e=>e.period==t).map(e=>e.id)}}}),xa=Rs("api"),zn={getAll(){return xa.get("groups")},get(t,e={}){return xa.get("/groups/"+t,{...e})},assign(t,e,i={}){return xa.post("/groups/"+e+"/assign",{ids:t},{...i})},delete(t,e={}){return xa.delete("/groups/"+t,{...e})},saveOrder(t,e={}){return xa.post("/groups/reorder",{orderedIds:t},{...e})}},UP=oo("groups",()=>{const t=Ne(),e=Ss(),i=vt([]),s=vt(null),a=st(()=>{const g=i.value.find(y=>y.id===parseInt(t.preferences.activeGroup));return g&&t.preferences.activeGroup>0?g.name:null}),o=st(()=>i.value.map(g=>g.id)),r=st(()=>i.value.filter(g=>g.id>0)),n=st(()=>i.value.find(g=>g.id==0)),l=st(()=>r.value.length==0),u=st(()=>r.value.length);function d(){i.value=[],s.value=null}function c(g){const y=i.value.findIndex(m=>m.id===parseInt(g.id));y>-1?(i.value[y]=g,e.success({text:this.$i18n.global.t("notification.group_name_saved")})):(i.value.push(g),e.success({text:this.$i18n.global.t("notification.group_successfully_created")}))}async function _(){Math.floor(Date.now()-s.value)>2e3&&(s.value=Date.now(),await zn.getAll().then(m=>{i.value=m.data}))}async function p(g){confirm(this.$i18n.global.t("confirmation.delete_group"))&&await zn.delete(g).then(y=>{i.value=i.value.filter(m=>m.id!==g),e.success({text:this.$i18n.global.t("notification.group_successfully_deleted")}),parseInt(t.preferences.activeGroup)===g&&(t.preferences.activeGroup=0)})}function v(){zn.saveOrder(o.value)}return{items:i,fetchedOn:s,current:a,orderedIds:o,withoutTheAllGroup:r,theAllGroup:n,isEmpty:l,count:u,$reset:d,addOrEdit:c,fetch:_,remove:p,saveOrder:v}}),Dn=Rs("api"),jP={getAll(t={}){return Dn.get("/settings",{...t})},update(t,e,i={}){return Dn.put("/settings/"+t,{value:e},{...i})},delete(t,e={}){return Dn.delete("/settings/"+t,{...e})}},cr=oo("appSettings",{state:()=>({lockedPreferences:window.lockedPreferences,...window.appSettings}),getters:{isSynced:t=>t.useEncryption!=null},actions:{async fetch(){jP.getAll({returnError:!0}).then(t=>{t.data.forEach(e=>{this[e.key]=e.value})}).catch(t=>{Ss().alert({text:this.$i18n.global.t("error.failed_to_retrieve_app_settings")})})}}}),Ne=oo("user",{state:()=>({id:void 0,name:void 0,email:void 0,oauth_provider:void 0,authenticated_by_proxy:void 0,preferences:window.defaultPreferences,isAdmin:!1}),getters:{isAuthenticated(){return this.name!=null}},actions:{async loginAs(t){this.$patch(t),await this.initDataStores(),this.applyUserPrefs()},async initDataStores(){const t=i0(),e=UP();this.isAuthenticated?(await t.fetch(),e.fetch()):(t.$reset(),e.$reset())},logout(t={}){const{kicked:e}=t,i=Ss(),s=Qs();if(this.$2fauth.config.proxyAuth)if(this.$2fauth.config.proxyLogoutUrl)location.assign(this.$2fauth.config.proxyLogoutUrl);else return!1;else t0.logout({returnError:!0}).then(()=>{e&&(i.clear(),i.warn({text:this.$i18n.global.t("notification.autolock_triggered_punchline"),duration:-1})),this.tossOut()}).catch(a=>{a.response.status!==401?s.show(a):this.tossOut()})},tossOut(){this.$reset(),this.initDataStores(),this.applyUserPrefs();const t=cr(),e=t.enableSso,i=t.useSsoOnly,s=t.disableRegistration;t.$reset(),t.enableSso=e,t.useSsoOnly=i,t.disableRegistration=s,bo.push({name:"login"})},applyTheme(){const t=NS({class:"dark"});t.value=this.preferences.theme=="system"?"auto":this.preferences.theme},applyLanguage(){const{isSupported:t,language:e}=Sp();let i=this.$i18n.fallbackLocale;t&&(i=this.preferences.lang=="browser"?e.value.slice(0,2):this.preferences.lang),this.$i18n.global.locale=i},applyUserPrefs(){this.applyTheme(),this.applyLanguage()},refreshPreferences(){const t=cr();e0.getPreferences({returnError:!0}).then(e=>{e.data.forEach(i=>{this.preferences[i.key]=i.value;let s=t.lockedPreferences.indexOf(i.key);i.locked==!0&&s===-1?t.lockedPreferences.push(i.key):i.locked==!1&&s>0&&t.lockedPreferences.splice(s,1)})}).catch(e=>{Ss().alert({text:this.$i18n.global Line truncated
@@ -0,0 +1 @@
import{al as p,C as o}from"./app-dvJP63FL.js";async function l(r,t,n=!1){let s=null,a=null;return await p.update(r,t,{returnError:!0}).then(e=>{s=t}).catch(e=>{n&&e.response.status===422?a=e.response.data.message:o().show(e)}),{data:s,error:a}}export{l as u};
@@ -0,0 +1 @@
import{am as t}from"./app-dvJP63FL.js";function a(){return{isLaptop:t({laptop:1024}).laptop}}export{a as u};
+1
View File
@@ -0,0 +1 @@
import{an as e}from"./app-dvJP63FL.js";const r=e("bus",{state:()=>({migrationUri:null,decodedUri:null,inManagementMode:!1,editedGroupName:null,username:null}),actions:{}});export{r as u};
+1
View File
@@ -0,0 +1 @@
import{c}from"./createLucideIcon-DsaEAGzP.js";const e=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],t=c("check",e);export{t as C};
@@ -0,0 +1 @@
import{c}from"./createLucideIcon-DsaEAGzP.js";const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M8 12h8",key:"1wcyev"}],["path",{d:"M12 8v8",key:"napkw2"}]],r=c("circle-plus",e);export{r as C};
+1
View File
@@ -0,0 +1 @@
import{c}from"./createLucideIcon-DsaEAGzP.js";const e=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["line",{x1:"12",x2:"12",y1:"8",y2:"12",key:"1pkeuh"}],["line",{x1:"12",x2:"12.01",y1:"16",y2:"16",key:"4dfq90"}]],i=c("circle-alert",e);const r=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"m15 9-6 6",key:"1uzhvr"}],["path",{d:"m9 9 6 6",key:"z0biqf"}]],l=c("circle-x",r);export{i as C,l as a};
@@ -0,0 +1 @@
import{M as v,ao as u,B as A}from"./app-dvJP63FL.js";const h=t=>t==="";const S=(...t)=>t.filter((e,r,o)=>!!e&&e.trim()!==""&&o.indexOf(e)===r).join(" ").trim();const w=t=>t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();const L=t=>t.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,r,o)=>o?o.toUpperCase():r.toLowerCase());const W=t=>{const e=L(t);return e.charAt(0).toUpperCase()+e.slice(1)};var s={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor","stroke-width":2,"stroke-linecap":"round","stroke-linejoin":"round"};const $=Symbol("lucide-icons");function j(){return v($,{})}const B=({name:t,iconNode:e,absoluteStrokeWidth:r,"absolute-stroke-width":o,strokeWidth:c,"stroke-width":k,size:i,color:C,...f},{slots:l})=>{const{size:n,color:p,strokeWidth:m=2,absoluteStrokeWidth:g=!1,class:x=""}=j(),b=A(()=>{const a=h(r)||h(o)||r===!0||o===!0||g===!0,d=c||k||m||s["stroke-width"];return a?Number(d)*24/Number(i??n??s.width):d});return u("svg",{...s,...f,width:i??n??s.width,height:i??n??s.height,stroke:C??p??s.stroke,"stroke-width":b.value,class:S("lucide",x,...t?[`lucide-${w(W(t))}-icon`,`lucide-${w(t)}`]:["lucide-icon"])},[...e.map(a=>u(...a)),...l.default?[l.default()]:[]])};const I=(t,e)=>(r,{slots:o,attrs:c})=>u(B,{...c,...r,iconNode:e,name:t},o.default?{default:o.default}:void 0);export{I as c};
@@ -0,0 +1 @@
import{c as a}from"./createLucideIcon-DsaEAGzP.js";const e=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]],n=a("external-link",e);export{n as E};
+1
View File
@@ -0,0 +1 @@
function t(r){return Array.isArray(r)?r:Array.isArray(r?.data)?r.data:[]}export{t as a};
@@ -0,0 +1 @@
import{c as n}from"./createLucideIcon-DsaEAGzP.js";import{ae as r}from"./app-dvJP63FL.js";const i=[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]],d=n("refresh-cw",i),o=r("api"),h={getLogo(e,t,c,a={}){return o.post("/icons/default",{service:e,iconCollection:t,variant:c},{...a})},getLogoFromPack(e,t,c={}){return o.post("/icons/default",{service:e,iconPack:t},{...c})},getIconPacks(e={}){return o.get("/icons/packs",{...e})},deleteIcon(e,t={}){return o.delete("/icons/"+e,{...t})}};export{d as R,h as i};
+1
View File
@@ -0,0 +1 @@
import{s,ap as a,r as n}from"./app-dvJP63FL.js";const l=s((t,{slots:o})=>{const e=a(t),r=n({mode:e,system:e.system,store:e.store});return()=>{if(o.default)return o.default(r)}},{name:"UseColorMode",props:["attribute","deep","disableTransition","emitAuto","eventFilter","flush","initOnMounted","initialValue","listenToStorageChanges","mergeDefaults","modes","onChanged","onError","selector","serializer","shallow","storage","storageKey","storageRef","window","writeDefaults"]});export{l as U};
+1
View File
@@ -0,0 +1 @@
import{c as t}from"./createLucideIcon-DsaEAGzP.js";const e=[["rect",{width:"5",height:"5",x:"3",y:"3",rx:"1",key:"1tu5fj"}],["rect",{width:"5",height:"5",x:"16",y:"3",rx:"1",key:"1v8r4q"}],["rect",{width:"5",height:"5",x:"3",y:"16",rx:"1",key:"1x03jg"}],["path",{d:"M21 16h-3a2 2 0 0 0-2 2v3",key:"177gqh"}],["path",{d:"M21 21v.01",key:"ents32"}],["path",{d:"M12 7v3a2 2 0 0 1-2 2H7",key:"8crl2c"}],["path",{d:"M3 12h.01",key:"nlz23k"}],["path",{d:"M12 3h.01",key:"n36tog"}],["path",{d:"M12 16v.01",key:"133mhm"}],["path",{d:"M16 12h1",key:"1slzba"}],["path",{d:"M21 12v.01",key:"1lwtk9"}],["path",{d:"M12 21v-1",key:"1880an"}]],a=t("qr-code",e);export{a as Q};
@@ -0,0 +1 @@
import{ae as a}from"./app-dvJP63FL.js";const s=a("api"),o={getShares(t,e={}){return s.get("/twofaccounts/"+t+"/shares",{...e})},shareWithUsers(t,e,r={}){return s.post("/twofaccounts/"+t+"/shares",{user_ids:e},{...r})},unshareWithUser(t,e,r={}){return s.delete("/twofaccounts/"+t+"/shares/"+e,{...r})},unshare(t,e={}){return s.delete("/twofaccounts/"+t+"/shares",{...e})},getRecipients(t,e="",r={}){return s.get("/twofaccounts/"+t+"/recipients"+(e?"?filter[nameOrEmail]="+e:""),{...r})},shareWithAll(t,e={}){return s.post("/twofaccounts/"+t+"/shares/all",{...e})}};export{o as s};
+1
View File
@@ -0,0 +1 @@
import{c as e}from"./createLucideIcon-DsaEAGzP.js";const t=[["path",{d:"m14 18 4-4 4 4",key:"ftkppy"}],["path",{d:"M16 2v4",key:"4m81vk"}],["path",{d:"M18 22v-8",key:"su0gjh"}],["path",{d:"M21 11.343V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h9",key:"1exg90"}],["path",{d:"M3 10h18",key:"8toen8"}],["path",{d:"M8 2v4",key:"1cmpym"}]],r=e("calendar-arrow-up",t);const a=[["path",{d:"m14 18 4 4 4-4",key:"1waygx"}],["path",{d:"M16 2v4",key:"4m81vk"}],["path",{d:"M18 14v8",key:"irew45"}],["path",{d:"M21 11.354V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h7.343",key:"bse4f3"}],["path",{d:"M3 10h18",key:"8toen8"}],["path",{d:"M8 2v4",key:"1cmpym"}]],d=e("calendar-arrow-down",a);const o=[["rect",{width:"20",height:"14",x:"2",y:"3",rx:"2",key:"48i651"}],["line",{x1:"8",x2:"16",y1:"21",y2:"21",key:"1svkeh"}],["line",{x1:"12",x2:"12",y1:"17",y2:"21",key:"vw1qmm"}]],c=e("monitor",o);const y=[["rect",{width:"14",height:"20",x:"5",y:"2",rx:"2",ry:"2",key:"1yt0o3"}],["path",{d:"M12 18h.01",key:"mhygvu"}]],p=e("smartphone",y);const h=[["rect",{width:"16",height:"20",x:"4",y:"2",rx:"2",ry:"2",key:"76otgf"}],["line",{x1:"12",x2:"12.01",y1:"18",y2:"18",key:"1dp563"}]],k=e("tablet",h);export{d as C,c as M,p as S,k as T,r as a};
+1
View File
@@ -0,0 +1 @@
const e=[{name:"label.app_setup",view:"admin.appSetup",id:"lnkTabApp",icon:"Settings"},{name:"label.auth",view:"admin.auth",id:"lnkTabAuth",icon:"ShieldUser"},{name:"label.users",view:"admin.users",id:"lnkTabUsers",icon:"UsersRound"}];export{e as t};
+1
View File
@@ -0,0 +1 @@
const e=[{name:"label.options",view:"settings.options",id:"lnkTabOptions",icon:"SlidersHorizontal"},{name:"label.account",view:"settings.account",id:"lnkTabAccount",icon:"CircleUser"},{name:"label.oauth",view:"settings.oauth.tokens",id:"lnkTabOAuth",icon:"KeySquare"},{name:"label.webauthn",view:"settings.webauthn.devices",id:"lnkTabWebauthn",icon:"ScanFace"}];export{e as t};
@@ -0,0 +1 @@
import{c as be}from"./createLucideIcon-DsaEAGzP.js";import{ag as ke,ah as Re,ai as Xe,aj as se,Q as Ye,D as je}from"./app-dvJP63FL.js";const Be=[["path",{d:"M4 5h16",key:"1tepv9"}],["path",{d:"M4 12h16",key:"1lakjw"}],["path",{d:"M4 19h16",key:"1djgab"}]],_n=be("menu",Be);const He=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],Dn=be("trash-2",He);function We(o,t,n){return(t=$e(t))in o?Object.defineProperty(o,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):o[t]=n,o}function V(){return V=Object.assign?Object.assign.bind():function(o){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var e in n)({}).hasOwnProperty.call(n,e)&&(o[e]=n[e])}return o},V.apply(null,arguments)}function ue(o,t){var n=Object.keys(o);if(Object.getOwnPropertySymbols){var e=Object.getOwnPropertySymbols(o);t&&(e=e.filter(function(i){return Object.getOwnPropertyDescriptor(o,i).enumerable})),n.push.apply(n,e)}return n}function L(o){for(var t=1;t<arguments.length;t++){var n=arguments[t]!=null?arguments[t]:{};t%2?ue(Object(n),!0).forEach(function(e){We(o,e,n[e])}):Object.getOwnPropertyDescriptors?Object.defineProperties(o,Object.getOwnPropertyDescriptors(n)):ue(Object(n)).forEach(function(e){Object.defineProperty(o,e,Object.getOwnPropertyDescriptor(n,e))})}return o}function Ge(o,t){if(o==null)return{};var n,e,i=Le(o,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(o);for(e=0;e<r.length;e++)n=r[e],t.indexOf(n)===-1&&{}.propertyIsEnumerable.call(o,n)&&(i[n]=o[n])}return i}function Le(o,t){if(o==null)return{};var n={};for(var e in o)if({}.hasOwnProperty.call(o,e)){if(t.indexOf(e)!==-1)continue;n[e]=o[e]}return n}function ze(o,t){if(typeof o!="object"||!o)return o;var n=o[Symbol.toPrimitive];if(n!==void 0){var e=n.call(o,t);if(typeof e!="object")return e;throw new TypeError("@@toPrimitive must return a primitive value.")}return(t==="string"?String:Number)(o)}function $e(o){var t=ze(o,"string");return typeof t=="symbol"?t:t+""}function Zt(o){"@babel/helpers - typeof";return Zt=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(t){return typeof t}:function(t){return t&&typeof Symbol=="function"&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Zt(o)}var Ue="1.15.7";function U(o){if(typeof window<"u"&&window.navigator)return!!navigator.userAgent.match(o)}var q=U(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i),Ct=U(/Edge/i),ce=U(/firefox/i),Et=U(/safari/i)&&!U(/chrome/i)&&!U(/android/i),oe=U(/iP(ad|od|hone)/i),ye=U(/chrome/i)&&U(/android/i),we={capture:!1,passive:!1};function w(o,t,n){o.addEventListener(t,n,!q&&we)}function y(o,t,n){o.removeEventListener(t,n,!q&&we)}function Xt(o,t){if(t){if(t[0]===">"&&(t=t.substring(1)),o)try{if(o.matches)return o.matches(t);if(o.msMatchesSelector)return o.msMatchesSelector(t);if(o.webkitMatchesSelector)return o.webkitMatchesSelector(t)}catch{return!1}return!1}}function Ee(o){return o.host&&o!==document&&o.host.nodeType&&o.host!==o?o.host:o.parentNode}function H(o,t,n,e){if(o){n=n||document;do{if(t!=null&&(t[0]===">"?o.parentNode===n&&Xt(o,t):Xt(o,t))||e&&o===n)return o;if(o===n)break}while(o=Ee(o))}return null}var fe=/\s+/g;function k(o,t,n){if(o&&t)if(o.classList)o.classList[n?"add":"remove"](t);else{var e=(" "+o.className+" ").replace(fe," ").replace(" "+t+" "," ");o.className=(e+(n?" "+t:"")).replace(fe," ")}}function h(o,t,n){var e=o&&o.style;if(e){if(n===void 0)return document.defaultView&&document.defaultView.getComputedStyle?n=document.defaultView.getComputedStyle(o,""):o.currentStyle&&(n=o.currentStyle),t===void 0?n:n[t];!(t in e)&&t.indexOf("webkit")===-1&&(t="-webkit-"+t),e[t]=n+(typeof n=="string"?"":"px")}}function ft(o,t){var n="";if(typeof o=="string")n=o;else do{var e=h(o,"transform");e&&e!=="none"&&(n=e+" "+n)}while(!t&&(o=o.parentNode));var i=window.DOMMatrix||window.WebKitCSSMatrix||window.CSSMatrix||window.MSCSSMatrix;return i&&new i(n)}function _e(o,t,n){if(o){var e=o.getElementsByTagName(t),i=0,r=e.length;if(n)for(;i<r;i++)n(e[i],i);return e}return[]}function G(){var o=document.scrollingElement;return o||document.documentElement}function C(o,t,n,e,i){if(!(!o.getBoundingClientRect&&o!==window)){var r,a,l,s,u,d,f;if(o!==window&&o.parentNode&&o!==G()?(r=o.getBoundingClientRect(),a=r.top,l=r.left,s=r.bottom,u=r.right,d=r.height,f=r.width):(a=0,l=0,s=window.innerHeight,u=window.innerWidth,d=window.innerHeight,f=window.innerWidth),(t||n)&&o!==window&&(i=i||o.parentNode,!q))do if(i&&i.getBoundingClientRect&&(h(i,"transform")!=="none"||n&&h(i,"position")!=="static")){var v=i.getBoundingClientRect();a-=v.top+parseInt(h(i,"border-top-width")),l-=v.left+parseInt(h(i,"border-left-width")),s=a+r.height,u=l+r.width;break}while(i=i.parentNode);if(e&&o!==window){var m=ft(i||o),b=m&&m.a,E=m&&m.d;m&&(a/=E,l/=b,f/=b,d/=E,s=a+d,u=l+f)}reLine truncated
+1
View File
@@ -0,0 +1 @@
import{c as e}from"./createLucideIcon-DsaEAGzP.js";const c=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],r=e("users",c);export{r as U};
@@ -0,0 +1 @@
import{ae as g}from"./app-dvJP63FL.js";class h{controller;createNewAbortSignal(){if(this.controller){const e=new Error("Cancelling existing WebAuthn API call for new one");e.name="AbortError",this.controller.abort(e)}const r=new AbortController;return this.controller=r,r.signal}}const c=new h;function d(n){return n==="localhost"||/^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/i.test(n)}function w(n,r){const{publicKey:e}=r;if(n.name==="AbortError"){if(r.signal instanceof AbortSignal)return{phrase:"error.aborted_by_user",type:"is-warning"}}else if(n.name==="ConstraintError"){if(e.authenticatorSelection?.requireResidentKey===!0)return{phrase:"error.authenticator_missing_discoverable_credential_support",type:"is-danger"};if(e.authenticatorSelection?.userVerification==="required")return{phrase:"error.authenticator_missing_user_verification_support",type:"is-danger"}}else{if(n.name==="InvalidStateError")return{phrase:"error.security_device_already_registered",type:"is-danger"};if(n.name==="NotAllowedError")return{phrase:"error.not_allowed_operation",type:"is-danger"};if(n.name==="NotSupportedError")return e.pubKeyCredParams.filter(o=>o.type==="public-key").length===0?{phrase:"error.no_entry_was_of_type_public_key",type:"is-danger"}:{phrase:"error.no_authenticator_support_specified_algorithms",type:"is-danger"};if(n.name==="SecurityError"){const t=window.location.hostname;if(d(t)){if(e.rp.id!==t)return{phrase:"error.security_error_check_rpid",type:"is-danger"}}else return{phrase:"error.2fauth_has_not_a_valid_domain",type:"is-danger"}}else if(n.name==="TypeError"){if(e.user.id.byteLength<1||e.user.id.byteLength>64)return{phrase:"error.user_id_not_between_1_64",type:"is-danger"}}else if(n.name==="UnknownError")return{phrase:"error.unknown_error",type:"is-danger"}}return{phrase:"error.unknown_error",type:"is-danger"}}function f(n,r){const{publicKey:e}=r;if(n.name==="AbortError"){if(r.signal instanceof AbortSignal)return{phrase:"error.aborted_by_user",type:"is-warning"}}else{if(n.name==="NotAllowedError")return{phrase:"error.not_allowed_operation",type:"is-danger"};if(n.name==="SecurityError"){const t=window.location.hostname;if(d(t)){if(e.rpId!==t)return{phrase:"error.security_error_check_rpid",type:"is-danger"}}else return{phrase:"error.2fauth_has_not_a_valid_domain",type:"is-danger"}}else if(n.name==="UnknownError")return{phrase:"error.unknown_error",type:"is-danger"}}return{phrase:"error.unknown_error",type:"is-danger"}}const p=g("web");class a{async register(){let r={webauthn:!0,type:"is-danger",message:""};if(!window.isSecureContext)return r.message="error.https_required",Promise.reject(r);if(!a.supportsWebAuthn)return r.message="error.browser_does_not_support_webauthn",Promise.reject(r);const e=await p.post("/webauthn/register/options").then(i=>i.data);let o={publicKey:a.parseIncomingServerOptions(e)};o.signal=c.createNewAbortSignal();let u;try{u=await navigator.credentials.create(o)}catch(i){const s=w(i,o);return Promise.reject({webauthn:!0,type:s.type,message:s.phrase})}const l=a.parseOutgoingCredentials(u);return p.post("/webauthn/register",l,{returnError:!0})}async authenticate(r){if(!window.isSecureContext)return err.message="error.https_required",Promise.reject(err);if(!a.supportsWebAuthn)return err.message="error.browser_does_not_support_webauthn",Promise.reject(err);const e=await p.post("/webauthn/login/options",{email:r}).then(i=>i.data);let o={publicKey:a.parseIncomingServerOptions(e)};o.signal=c.createNewAbortSignal();const u=await navigator.credentials.get(o).catch(i=>{const s=f(i,o);return Promise.reject({webauthn:!0,type:s.type,message:s.phrase})});let l=a.parseOutgoingCredentials(u);return l.email=r,p.post("/webauthn/login",l,{returnError:!0})}static parseIncomingServerOptions(r){return r.challenge=a.uint8Array(r.challenge),"user"in r&&(r.user={...r.user,id:a.uint8Array(r.user.id)}),["excludeCredentials","allowCredentials"].filter(e=>e in r).forEach(e=>{r[e]=r[e].map(t=>({...t,id:a.uint8Array(t.id)}))}),r}static parseOutgoingCredentials(r){let e={id:r.id,type:r.type,rawId:a.arrayToBase64String(r.rawId),response:{}};return["clientDataJSON","attestationObject","authenticatorData","signature","userHandle"].filter(t=>t in r.response).forEach(t=>e.response[t]=a.arrayToBase64String(r.response[t])),e}static uint8Array(r,e=!1){return Uint8Array.from(e?atob(r):a.base64UrlDecode(r),t=>t.charCodeAt(0))}static arrayToBase64String(r){return btoa(String.fromCharCode(...new Uint8Array(r)))}static base64UrlDecode(r){r=r.replace(/-/g,"+").replace(/_/g,"/");const e=r.length%4;if(e){if(e===1)throw new Error("InvalidLengthError: Input base64url string is the wrong length to determine padding");r+=new Array(5-e).join("=")}return atob(r)}static supportsWebAuthn(){return window?.PublicKeyCredential!==void 0&&typeof window.PublicKeyCredential=="function"}}const _=new a;export{_ as w};
+1
View File
@@ -0,0 +1 @@
import{c as o}from"./createLucideIcon-DsaEAGzP.js";const c=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],t=o("x",c);export{t as X};
+620
View File
@@ -0,0 +1,620 @@
{
"_AccessLogViewer-D5ke4CwJ.js": {
"file": "assets/AccessLogViewer-D5ke4CwJ.js",
"name": "AccessLogViewer",
"imports": [
"resources/js/app.js",
"_index-BJsmINgd.js",
"_tablet-DYUfDfjC.js",
"_x-DQVIq0xP.js",
"_check-CPGWPXZa.js"
]
},
"_CopyButton-CgxgBp0c.js": {
"file": "assets/CopyButton-CgxgBp0c.js",
"name": "CopyButton",
"imports": [
"resources/js/app.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"_Form-ZbAUhXmz.js": {
"file": "assets/Form-ZbAUhXmz.js",
"name": "Form",
"imports": [
"resources/js/app.js"
]
},
"_QrContentDisplay-DiIjf7a_.js": {
"file": "assets/QrContentDisplay-DiIjf7a_.js",
"name": "QrContentDisplay",
"imports": [
"resources/js/app.js",
"_external-link-CqpXNovN.js"
]
},
"_TwofaccountMedia-DzLyeBxh.js": {
"file": "assets/TwofaccountMedia-DzLyeBxh.js",
"name": "TwofaccountMedia",
"imports": [
"_index-BJsmINgd.js",
"resources/js/app.js"
]
},
"_appSettingsUpdater-D1Bq_3WB.js": {
"file": "assets/appSettingsUpdater-D1Bq_3WB.js",
"name": "appSettingsUpdater",
"imports": [
"resources/js/app.js"
]
},
"_breakpoints-CyLcIEOu.js": {
"file": "assets/breakpoints-CyLcIEOu.js",
"name": "breakpoints",
"imports": [
"resources/js/app.js"
]
},
"_bus-ChE1sp8V.js": {
"file": "assets/bus-ChE1sp8V.js",
"name": "bus",
"imports": [
"resources/js/app.js"
]
},
"_check-CPGWPXZa.js": {
"file": "assets/check-CPGWPXZa.js",
"name": "check",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_circle-plus-BM92Iipr.js": {
"file": "assets/circle-plus-BM92Iipr.js",
"name": "circle-plus",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_circle-x-AvUNZzwX.js": {
"file": "assets/circle-x-AvUNZzwX.js",
"name": "circle-x",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_createLucideIcon-DsaEAGzP.js": {
"file": "assets/createLucideIcon-DsaEAGzP.js",
"name": "createLucideIcon",
"imports": [
"resources/js/app.js"
]
},
"_external-link-CqpXNovN.js": {
"file": "assets/external-link-CqpXNovN.js",
"name": "external-link",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_helpers-B2oe4lHy.js": {
"file": "assets/helpers-B2oe4lHy.js",
"name": "helpers"
},
"_iconService-rm6LRV4U.js": {
"file": "assets/iconService-rm6LRV4U.js",
"name": "iconService",
"imports": [
"_createLucideIcon-DsaEAGzP.js",
"resources/js/app.js"
]
},
"_index-BJsmINgd.js": {
"file": "assets/index-BJsmINgd.js",
"name": "index",
"imports": [
"resources/js/app.js"
]
},
"_qr-code-eSL1bq0j.js": {
"file": "assets/qr-code-eSL1bq0j.js",
"name": "qr-code",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_shareService-BU7jlLil.js": {
"file": "assets/shareService-BU7jlLil.js",
"name": "shareService",
"imports": [
"resources/js/app.js"
]
},
"_tablet-DYUfDfjC.js": {
"file": "assets/tablet-DYUfDfjC.js",
"name": "tablet",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_tabs-BVx9tg1F.js": {
"file": "assets/tabs-BVx9tg1F.js",
"name": "tabs"
},
"_tabs-Btun2NN0.js": {
"file": "assets/tabs-Btun2NN0.js",
"name": "tabs"
},
"_useSortable-6hRbxhTj.js": {
"file": "assets/useSortable-6hRbxhTj.js",
"name": "useSortable",
"imports": [
"_createLucideIcon-DsaEAGzP.js",
"resources/js/app.js"
]
},
"_users-CLZI37iw.js": {
"file": "assets/users-CLZI37iw.js",
"name": "users",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"_webauthnService-D363et0U.js": {
"file": "assets/webauthnService-D363et0U.js",
"name": "webauthnService",
"imports": [
"resources/js/app.js"
]
},
"_x-DQVIq0xP.js": {
"file": "assets/x-DQVIq0xP.js",
"name": "x",
"imports": [
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/app.js": {
"file": "assets/app-dvJP63FL.js",
"name": "app",
"src": "resources/js/app.js",
"isEntry": true,
"dynamicImports": [
"resources/js/views/Start.vue",
"resources/js/views/twofaccounts/Capture.vue",
"resources/js/views/twofaccounts/Accounts.vue",
"resources/js/views/twofaccounts/CreateUpdate.vue",
"resources/js/views/twofaccounts/Import.vue",
"resources/js/views/twofaccounts/CreateUpdate.vue",
"resources/js/views/twofaccounts/QRcode.vue",
"resources/js/views/sharing/AccountSharing.vue",
"resources/js/views/sharing/Share.vue",
"resources/js/views/sharing/TransferOwnership.vue",
"resources/js/views/twofaccounts/OtpLogs.vue",
"resources/js/views/groups/Groups.vue",
"resources/js/views/groups/CreateUpdate.vue",
"resources/js/views/groups/CreateUpdate.vue",
"resources/js/views/settings/Options.vue",
"resources/js/views/settings/Account.vue",
"resources/js/views/settings/OAuth.vue",
"resources/js/views/settings/Credentials/Edit.vue",
"resources/js/views/settings/WebAuthn.vue",
"resources/js/views/admin/AppSetup.vue",
"resources/js/views/admin/Auth.vue",
"resources/js/views/admin/Users.vue",
"resources/js/views/admin/users/Create.vue",
"resources/js/views/admin/users/Manage.vue",
"resources/js/views/admin/logs/Access.vue",
"resources/js/views/auth/Login.vue",
"resources/js/views/auth/Register.vue",
"resources/js/views/auth/RequestReset.vue",
"resources/js/views/auth/password/Reset.vue",
"resources/js/views/auth/RequestReset.vue",
"resources/js/views/auth/webauthn/Recover.vue",
"resources/js/views/About.vue",
"resources/js/views/Error.vue",
"resources/js/views/Error.vue",
"resources/js/views/Error.vue"
],
"css": [
"assets/app-C6trQ8-_.css"
]
},
"resources/js/views/About.vue": {
"file": "assets/About-DlWJhNxo.js",
"name": "About",
"src": "resources/js/views/About.vue",
"isDynamicEntry": true,
"imports": [
"_index-BJsmINgd.js",
"resources/js/app.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/Error.vue": {
"file": "assets/Error-DG0pgQA2.js",
"name": "Error",
"src": "resources/js/views/Error.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_index-BJsmINgd.js"
]
},
"resources/js/views/Start.vue": {
"file": "assets/Start-Dnu4qWlC.js",
"name": "Start",
"src": "resources/js/views/Start.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_bus-ChE1sp8V.js"
]
},
"resources/js/views/admin/AppSetup.vue": {
"file": "assets/AppSetup-9GPB7B-I.js",
"name": "AppSetup",
"src": "resources/js/views/admin/AppSetup.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-BVx9tg1F.js",
"_appSettingsUpdater-D1Bq_3WB.js",
"_check-CPGWPXZa.js",
"_x-DQVIq0xP.js",
"_CopyButton-CgxgBp0c.js",
"_breakpoints-CyLcIEOu.js",
"_createLucideIcon-DsaEAGzP.js",
"_external-link-CqpXNovN.js"
]
},
"resources/js/views/admin/Auth.vue": {
"file": "assets/Auth-DslSg1a9.js",
"name": "Auth",
"src": "resources/js/views/admin/Auth.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-BVx9tg1F.js",
"_appSettingsUpdater-D1Bq_3WB.js"
]
},
"resources/js/views/admin/Users.vue": {
"file": "assets/Users-DyNCDMUg.js",
"name": "Users",
"src": "resources/js/views/admin/Users.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-BVx9tg1F.js",
"_index-BJsmINgd.js",
"_circle-plus-BM92Iipr.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/admin/logs/Access.vue": {
"file": "assets/Access-BQVm4alb.js",
"name": "Access",
"src": "resources/js/views/admin/logs/Access.vue",
"isDynamicEntry": true,
"imports": [
"_AccessLogViewer-D5ke4CwJ.js",
"resources/js/app.js",
"_bus-ChE1sp8V.js",
"_index-BJsmINgd.js",
"_tablet-DYUfDfjC.js",
"_createLucideIcon-DsaEAGzP.js",
"_x-DQVIq0xP.js",
"_check-CPGWPXZa.js"
]
},
"resources/js/views/admin/users/Create.vue": {
"file": "assets/Create-Vv-BwDWf.js",
"name": "Create",
"src": "resources/js/views/admin/users/Create.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js"
]
},
"resources/js/views/admin/users/Manage.vue": {
"file": "assets/Manage-B1CTWqgo.js",
"name": "Manage",
"src": "resources/js/views/admin/users/Manage.vue",
"isDynamicEntry": true,
"imports": [
"_CopyButton-CgxgBp0c.js",
"_AccessLogViewer-D5ke4CwJ.js",
"resources/js/app.js",
"_index-BJsmINgd.js",
"_bus-ChE1sp8V.js",
"_breakpoints-CyLcIEOu.js",
"_createLucideIcon-DsaEAGzP.js",
"_tablet-DYUfDfjC.js",
"_x-DQVIq0xP.js",
"_check-CPGWPXZa.js"
]
},
"resources/js/views/auth/Login.vue": {
"file": "assets/Login-XfEMUKl8.js",
"name": "Login",
"src": "resources/js/views/auth/Login.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_webauthnService-D363et0U.js"
]
},
"resources/js/views/auth/Register.vue": {
"file": "assets/Register-DffuLlzx.js",
"name": "Register",
"src": "resources/js/views/auth/Register.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_webauthnService-D363et0U.js",
"_check-CPGWPXZa.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/auth/RequestReset.vue": {
"file": "assets/RequestReset-w8-YSMaH.js",
"name": "RequestReset",
"src": "resources/js/views/auth/RequestReset.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js"
]
},
"resources/js/views/auth/password/Reset.vue": {
"file": "assets/Reset-RiTuOlH9.js",
"name": "Reset",
"src": "resources/js/views/auth/password/Reset.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js"
]
},
"resources/js/views/auth/webauthn/Recover.vue": {
"file": "assets/Recover-CEob990V.js",
"name": "Recover",
"src": "resources/js/views/auth/webauthn/Recover.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js"
]
},
"resources/js/views/groups/CreateUpdate.vue": {
"file": "assets/CreateUpdate-CbOB1O7q.js",
"name": "CreateUpdate",
"src": "resources/js/views/groups/CreateUpdate.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_bus-ChE1sp8V.js"
]
},
"resources/js/views/groups/Groups.vue": {
"file": "assets/Groups-Ccrpwp-O.js",
"name": "Groups",
"src": "resources/js/views/groups/Groups.vue",
"isDynamicEntry": true,
"imports": [
"_index-BJsmINgd.js",
"resources/js/app.js",
"_bus-ChE1sp8V.js",
"_useSortable-6hRbxhTj.js",
"_circle-plus-BM92Iipr.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/settings/Account.vue": {
"file": "assets/Account-CvhJGfLO.js",
"name": "Account",
"src": "resources/js/views/settings/Account.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-Btun2NN0.js",
"_Form-ZbAUhXmz.js",
"_breakpoints-CyLcIEOu.js"
]
},
"resources/js/views/settings/Credentials/Edit.vue": {
"file": "assets/Edit-Ba84j7PP.js",
"name": "Edit",
"src": "resources/js/views/settings/Credentials/Edit.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js"
]
},
"resources/js/views/settings/OAuth.vue": {
"file": "assets/OAuth-aXCqlLPs.js",
"name": "OAuth",
"src": "resources/js/views/settings/OAuth.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-Btun2NN0.js",
"_Form-ZbAUhXmz.js",
"_index-BJsmINgd.js",
"_circle-plus-BM92Iipr.js",
"_check-CPGWPXZa.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/settings/Options.vue": {
"file": "assets/Options-Bun4hDR8.js",
"name": "Options",
"src": "resources/js/views/settings/Options.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-Btun2NN0.js",
"_iconService-rm6LRV4U.js",
"_breakpoints-CyLcIEOu.js",
"_external-link-CqpXNovN.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/settings/WebAuthn.vue": {
"file": "assets/WebAuthn-C_HU0Xj8.js",
"name": "WebAuthn",
"src": "resources/js/views/settings/WebAuthn.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_tabs-Btun2NN0.js",
"_webauthnService-D363et0U.js",
"_index-BJsmINgd.js",
"_circle-plus-BM92Iipr.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/sharing/AccountSharing.vue": {
"file": "assets/AccountSharing-kU7yk02h.js",
"name": "AccountSharing",
"src": "resources/js/views/sharing/AccountSharing.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_shareService-BU7jlLil.js",
"_TwofaccountMedia-DzLyeBxh.js",
"_helpers-B2oe4lHy.js",
"_index-BJsmINgd.js",
"_circle-plus-BM92Iipr.js",
"_users-CLZI37iw.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/sharing/Share.vue": {
"file": "assets/Share-DkTnn1jz.js",
"name": "Share",
"src": "resources/js/views/sharing/Share.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_shareService-BU7jlLil.js",
"_TwofaccountMedia-DzLyeBxh.js",
"_bus-ChE1sp8V.js",
"_helpers-B2oe4lHy.js",
"_index-BJsmINgd.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/sharing/TransferOwnership.vue": {
"file": "assets/TransferOwnership-BsVNwpBY.js",
"name": "TransferOwnership",
"src": "resources/js/views/sharing/TransferOwnership.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_shareService-BU7jlLil.js",
"_TwofaccountMedia-DzLyeBxh.js",
"_helpers-B2oe4lHy.js",
"_index-BJsmINgd.js"
]
},
"resources/js/views/twofaccounts/Accounts.vue": {
"file": "assets/Accounts-znshhaJC.js",
"name": "Accounts",
"src": "resources/js/views/twofaccounts/Accounts.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_shareService-BU7jlLil.js",
"_index-BJsmINgd.js",
"_createLucideIcon-DsaEAGzP.js",
"_useSortable-6hRbxhTj.js",
"_bus-ChE1sp8V.js",
"_circle-x-AvUNZzwX.js",
"_users-CLZI37iw.js",
"_qr-code-eSL1bq0j.js",
"_x-DQVIq0xP.js"
]
},
"resources/js/views/twofaccounts/Capture.vue": {
"file": "assets/Capture-BG6QMHLW.js",
"name": "Capture",
"src": "resources/js/views/twofaccounts/Capture.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_QrContentDisplay-DiIjf7a_.js",
"_bus-ChE1sp8V.js",
"_index-BJsmINgd.js",
"_createLucideIcon-DsaEAGzP.js",
"_external-link-CqpXNovN.js"
]
},
"resources/js/views/twofaccounts/CreateUpdate.vue": {
"file": "assets/CreateUpdate-tvLQ26rU.js",
"name": "CreateUpdate",
"src": "resources/js/views/twofaccounts/CreateUpdate.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_QrContentDisplay-DiIjf7a_.js",
"_iconService-rm6LRV4U.js",
"_bus-ChE1sp8V.js",
"_index-BJsmINgd.js",
"_createLucideIcon-DsaEAGzP.js",
"_qr-code-eSL1bq0j.js",
"_external-link-CqpXNovN.js"
]
},
"resources/js/views/twofaccounts/Import.vue": {
"file": "assets/Import-C0sC5CLD.js",
"name": "Import",
"src": "resources/js/views/twofaccounts/Import.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js",
"_Form-ZbAUhXmz.js",
"_bus-ChE1sp8V.js",
"_index-BJsmINgd.js",
"_qr-code-eSL1bq0j.js",
"_createLucideIcon-DsaEAGzP.js",
"_check-CPGWPXZa.js",
"_x-DQVIq0xP.js",
"_circle-x-AvUNZzwX.js"
]
},
"resources/js/views/twofaccounts/OtpLogs.vue": {
"file": "assets/OtpLogs-CAP6rwu6.js",
"name": "OtpLogs",
"src": "resources/js/views/twofaccounts/OtpLogs.vue",
"isDynamicEntry": true,
"imports": [
"_index-BJsmINgd.js",
"_tablet-DYUfDfjC.js",
"_x-DQVIq0xP.js",
"_check-CPGWPXZa.js",
"resources/js/app.js",
"_TwofaccountMedia-DzLyeBxh.js",
"_createLucideIcon-DsaEAGzP.js"
]
},
"resources/js/views/twofaccounts/QRcode.vue": {
"file": "assets/QRcode-Da_iUmWo.js",
"name": "QRcode",
"src": "resources/js/views/twofaccounts/QRcode.vue",
"isDynamicEntry": true,
"imports": [
"resources/js/app.js"
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Loaded 100 of 156 files, more files were not shown because too many files have changed in this diff. Show more