From c559759e613f125c2cc85f7cbd13c4fa5584b7ba Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 28 Nov 2024 19:14:36 +0100 Subject: [PATCH 1/2] Build RPM package (#362) --- .github/workflows/release.yaml | 14 +++++++++- resources-linux/defguard-client.spec | 41 ++++++++++++++++++++++++++++ src-tauri/src/utils.rs | 2 +- src-tauri/tauri.conf.json | 2 +- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 resources-linux/defguard-client.spec diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 60ccb6db..e19966e6 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -101,11 +101,23 @@ jobs: - name: Install Linux dependencies run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev unzip protobuf-compiler libprotobuf-dev + sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev unzip protobuf-compiler libprotobuf-dev rpm - name: Build packages uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Create RPM + run: | + rpmbuild --build-in-place --define "_topdir $(pwd)" --define "version ${{ env.VERSION }}" -bb resources-linux/defguard-client.spec + - name: Upload RPM + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ needs.create-release.outputs.upload_url }} + asset_path: RPMS/${{ matrix.binary_arch }}/defguard-client-${{ env.VERSION }}-1.${{ matrix.binary_arch }}.rpm + asset_name: defguard-client-${{ env.VERSION }}-1.${{ matrix.binary_arch }}.rpm + asset_content_type: application/octet-stream - name: Upload DEB uses: actions/upload-release-asset@v1.0.2 env: diff --git a/resources-linux/defguard-client.spec b/resources-linux/defguard-client.spec new file mode 100644 index 00000000..df6aa89f --- /dev/null +++ b/resources-linux/defguard-client.spec @@ -0,0 +1,41 @@ +Name: defguard-client +Version: %{version} +Release: 1%{?dist} +Summary: Defguard desktop client + +License: Apache-2.0 +URL: https://defguard.net/ +Requires: libappindicator-gtk3 webkit2gtk4.0 + +%description +Desktop client for managing WireGuard VPN connections + +%install +%{__mkdir} -p %{buildroot}/%{_bindir} %{buildroot}/%{_sbindir} %{buildroot}/%{_prefix}/lib/systemd/system +%{__install} -m 755 src-tauri/target/release/defguard-client %{buildroot}/%{_bindir}/ +%{__install} -m 755 src-tauri/target/release/defguard-service %{buildroot}/%{_sbindir}/ +%{__install} -m 644 resources-linux/defguard-service.service %{buildroot}/%{_prefix}/lib/systemd/system/ + +%post +# %{systemd_post} defguard-service.service +if [ $1 -eq 1 ]; then + systemctl daemon-reload + systemctl enable defguard-service.service + systemctl start defguard-service.service +fi + +%preun +# %{systemd_preun} defguard-service.service +if [ $1 -eq 0 ]; then + systemctl stop defguard-service.service + systemctl disable defguard-service.service +fi + +%postun +# %{systemd_postun} defguard-service.service +systemctl daemon-reload + +%files +%{_bindir}/defguard-client +%{_sbindir}/defguard-service +%{_prefix}/lib/systemd/system/defguard-service.service diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 3381027c..cd09739f 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -898,7 +898,7 @@ fn close_service_handle( // so `handle_connection_for_location` and `handle_connection_for_tunnel` are not // partially duplicated here. #[cfg(target_os = "windows")] -pub(crate) async fn sync_connections(app_handle: &AppHandle) -> Result<(), Error> { +pub async fn sync_connections(app_handle: &AppHandle) -> Result<(), Error> { debug!("Synchronizing active connections with the systems' state..."); let appstate = app_handle.state::(); let all_locations = Location::all(&appstate.db).await?; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 438f51d4..ad78fa1f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -72,7 +72,7 @@ }, "resources": ["resources/*"], "shortDescription": "", - "targets": ["deb", "app", "appimage"], + "targets": ["deb", "app"], "windows": { "certificateThumbprint": null, "digestAlgorithm": "sha256", From f1f895a6a1392d8f0c6642853e7e97ec2c37af5a Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 4 Dec 2024 15:30:29 +0100 Subject: [PATCH 2/2] Connection timeout (#364) --- LICENSE.md | 666 ++++++++++++++++++ src-tauri/Cargo.lock | 333 ++++----- src-tauri/Cargo.toml | 2 +- src-tauri/src/app_config.rs | 5 +- src-tauri/src/commands.rs | 14 +- src-tauri/src/events.rs | 17 +- src-tauri/src/periodic/connection.rs | 50 +- src-tauri/src/utils.rs | 180 +---- src/i18n/en/index.ts | 5 - src/i18n/i18n-types.ts | 20 - src/pages/client/clientAPI/types.ts | 1 - src/pages/client/hooks/useClientStore.tsx | 1 - .../GlobalSettingsTab/GlobalSettingsTab.tsx | 21 - .../AppConfigConnectionVerificationPeriod.tsx | 85 --- .../AppConfigPeerAlive/AppConfigPeerAlive.tsx | 84 --- 15 files changed, 865 insertions(+), 619 deletions(-) create mode 100644 LICENSE.md delete mode 100644 src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigConnectionVerificationPeriod/AppConfigConnectionVerificationPeriod.tsx delete mode 100644 src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigPeerAlive/AppConfigPeerAlive.tsx diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..65be7750 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,666 @@ +# Dual license info +The code in this repository is available under a dual licensing model: + +1. Open Source License: The code, except for the contents of the "src/enterprise" directory, is licensed under the AGPL license (this license). This applies to the open core components of the software. +2. Enterprise License: All code in this repository (including within the "src/enterprise" directory) is licensed under a separate Enterprise License (see file src/enterprise/LICENSE.md). + +# GNU AFFERO GENERAL PUBLIC LICENSE + +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +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. + + + Copyright (C) + + 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 . + +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 . diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index cf9a025e..36a498e1 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -66,9 +66,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android-tzdata" @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.93" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "arboard" @@ -338,7 +338,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -378,7 +378,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -395,7 +395,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -453,10 +453,10 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", - "itoa 1.0.13", + "itoa 1.0.14", "matchit", "memchr", "mime", @@ -479,7 +479,7 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "mime", @@ -622,7 +622,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -715,9 +715,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -758,9 +758,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", @@ -838,9 +838,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" dependencies = [ "clap_builder", "clap_derive", @@ -848,9 +848,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.21" +version = "4.5.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" dependencies = [ "anstream", "anstyle", @@ -867,7 +867,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1157,7 +1157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1167,7 +1167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1193,7 +1193,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1233,7 +1233,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1244,7 +1244,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1360,7 +1360,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1381,7 +1381,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1391,7 +1391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1404,7 +1404,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1501,7 +1501,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1510,7 +1510,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.5", + "libloading 0.8.6", ] [[package]] @@ -1623,7 +1623,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1634,12 +1634,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1689,9 +1689,9 @@ dependencies = [ [[package]] name = "event-listener-strategy" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" dependencies = [ "event-listener 5.3.1", "pin-project-lite", @@ -1827,7 +1827,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -1947,7 +1947,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -2320,7 +2320,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.6.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2338,8 +2338,8 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.1.0", - "indexmap 2.6.0", + "http 1.2.0", + "indexmap 2.7.0", "slab", "tokio", "tokio-util", @@ -2468,18 +2468,18 @@ checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", - "itoa 1.0.13", + "itoa 1.0.14", ] [[package]] name = "http" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" dependencies = [ "bytes", "fnv", - "itoa 1.0.13", + "itoa 1.0.14", ] [[package]] @@ -2500,7 +2500,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http 1.2.0", ] [[package]] @@ -2511,7 +2511,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2549,9 +2549,9 @@ dependencies = [ "http-body 0.4.6", "httparse", "httpdate", - "itoa 1.0.13", + "itoa 1.0.14", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -2568,11 +2568,11 @@ dependencies = [ "futures-channel", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "httparse", "httpdate", - "itoa 1.0.13", + "itoa 1.0.14", "pin-project-lite", "smallvec", "tokio", @@ -2586,7 +2586,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http 1.1.0", + "http 1.2.0", "hyper 1.5.1", "hyper-util", "rustls", @@ -2647,11 +2647,11 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "hyper 1.5.1", "pin-project-lite", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -2805,7 +2805,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -2889,9 +2889,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -2956,9 +2956,9 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "itoa" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "javascriptcore-rs" @@ -3036,10 +3036,11 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -3114,9 +3115,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.164" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libgit2-sys" @@ -3142,9 +3143,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -3364,11 +3365,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi 0.3.9", "libc", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", @@ -3841,7 +3841,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -4006,7 +4006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.6.0", + "indexmap 2.7.0", ] [[package]] @@ -4113,7 +4113,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -4160,7 +4160,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -4220,7 +4220,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.6.0", + "indexmap 2.7.0", "quick-xml 0.32.0", "serde", "time", @@ -4298,7 +4298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -4386,7 +4386,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.89", + "syn 2.0.90", "tempfile", ] @@ -4400,7 +4400,7 @@ dependencies = [ "itertools", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -4688,7 +4688,7 @@ dependencies = [ "futures-core", "futures-util", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -4789,9 +4789,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid", "digest", @@ -4888,9 +4888,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.18" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "once_cell", "rustls-pki-types", @@ -5051,7 +5051,7 @@ checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5060,8 +5060,8 @@ version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap 2.6.0", - "itoa 1.0.13", + "indexmap 2.7.0", + "itoa 1.0.14", "memchr", "ryu", "serde", @@ -5075,7 +5075,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5094,7 +5094,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa 1.0.13", + "itoa 1.0.14", "ryu", "serde", ] @@ -5109,7 +5109,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_derive", "serde_json", @@ -5126,7 +5126,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5148,7 +5148,7 @@ checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5265,9 +5265,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5365,7 +5365,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.6.0", + "indexmap 2.7.0", "log", "memchr", "once_cell", @@ -5394,7 +5394,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5417,7 +5417,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.89", + "syn 2.0.90", "tempfile", "tokio", "url", @@ -5447,7 +5447,7 @@ dependencies = [ "hex", "hkdf", "hmac", - "itoa 1.0.13", + "itoa 1.0.14", "log", "md-5", "memchr", @@ -5489,7 +5489,7 @@ dependencies = [ "hkdf", "hmac", "home", - "itoa 1.0.13", + "itoa 1.0.14", "log", "md-5", "memchr", @@ -5613,7 +5613,7 @@ checksum = "4596646090f0d724e6c7f3b65d694f99a0daa1a5893a78ef83887025e041405c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5635,7 +5635,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5657,9 +5657,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.89" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -5689,7 +5689,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5817,7 +5817,7 @@ checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -5961,7 +5961,7 @@ dependencies = [ [[package]] name = "tauri-plugin-log" version = "0.0.0" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#80ecd87bfc826240211d1383536f93bf5a3d15b8" +source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#017975ad5243183c13143289410028e07084e9a9" dependencies = [ "byte-unit", "fern", @@ -5976,7 +5976,7 @@ dependencies = [ [[package]] name = "tauri-plugin-single-instance" version = "0.0.0" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#80ecd87bfc826240211d1383536f93bf5a3d15b8" +source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#017975ad5243183c13143289410028e07084e9a9" dependencies = [ "log", "serde", @@ -5990,7 +5990,7 @@ dependencies = [ [[package]] name = "tauri-plugin-window-state" version = "0.1.1" -source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#80ecd87bfc826240211d1383536f93bf5a3d15b8" +source = "git+https://github.com/tauri-apps/plugins-workspace?branch=v1#017975ad5243183c13143289410028e07084e9a9" dependencies = [ "bincode", "bitflags 2.6.0", @@ -6141,7 +6141,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -6167,12 +6167,12 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", - "itoa 1.0.13", + "itoa 1.0.14", "libc", "num-conv", "num_threads", @@ -6190,9 +6190,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -6234,9 +6234,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.1" +version = "1.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" dependencies = [ "backtrace", "bytes", @@ -6245,7 +6245,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -6258,7 +6258,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -6354,7 +6354,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -6367,7 +6367,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.6.0", + "indexmap 2.7.0", "serde", "serde_spanned", "toml_datetime", @@ -6386,7 +6386,7 @@ dependencies = [ "base64 0.22.1", "bytes", "h2 0.4.7", - "http 1.1.0", + "http 1.2.0", "http-body 1.0.1", "http-body-util", "hyper 1.5.1", @@ -6395,7 +6395,7 @@ dependencies = [ "percent-encoding", "pin-project", "prost", - "socket2 0.5.7", + "socket2 0.5.8", "tokio", "tokio-stream", "tower 0.4.13", @@ -6415,7 +6415,7 @@ dependencies = [ "prost-build", "prost-types", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -6466,9 +6466,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -6490,20 +6490,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -6522,9 +6522,9 @@ dependencies = [ [[package]] name = "tracing-serde" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" dependencies = [ "serde", "tracing-core", @@ -6532,9 +6532,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -6709,9 +6709,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "9.0.1" +version = "9.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349ed9e45296a581f455bc18039878f409992999bc1d5da12a6800eb18c8752f" +checksum = "31f25fc8f8f05df455c7941e87f093ad22522a9ff33d7a027774815acf6f0639" dependencies = [ "anyhow", "derive_builder", @@ -6722,9 +6722,9 @@ dependencies = [ [[package]] name = "vergen-git2" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e771aff771c0d7c2f42e434e2766d304d917e29b40f0424e8faaaa936bbc3f29" +checksum = "5e63e069d8749fead1e3bab7a9d79e8fb90516b2ec66fc2243a798ecdc1a31d7" dependencies = [ "anyhow", "derive_builder", @@ -6737,9 +6737,9 @@ dependencies = [ [[package]] name = "vergen-lib" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229eaddb0050920816cf051e619affaf18caa3dd512de8de5839ccbc8e53abb0" +checksum = "c0c767e6751c09fc85cde58722cf2f1007e80e4c8d5a4321fc90d83dc54ca147" dependencies = [ "anyhow", "derive_builder", @@ -6829,9 +6829,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -6840,36 +6840,37 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6877,22 +6878,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-streams" @@ -6982,9 +6983,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" dependencies = [ "js-sys", "wasm-bindgen", @@ -6992,9 +6993,9 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5f07fb9bc8de2ddfe6b24a71a75430673fd679e568c48b52716cef1cfae923" +checksum = "ea9fe1ebb156110ff855242c1101df158b822487e4957b0556d9ffce9db0f535" dependencies = [ "block2", "core-foundation 0.10.0", @@ -7247,7 +7248,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -7258,7 +7259,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -7823,7 +7824,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", "synstructure", ] @@ -7929,7 +7930,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", "zvariant_utils 2.1.0", ] @@ -7973,7 +7974,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -7993,7 +7994,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", "synstructure", ] @@ -8014,7 +8015,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -8036,7 +8037,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] [[package]] @@ -8088,7 +8089,7 @@ dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", "zvariant_utils 2.1.0", ] @@ -8111,5 +8112,5 @@ checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" dependencies = [ "proc-macro2", "quote", - "syn 2.0.89", + "syn 2.0.90", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 644fb51c..00149736 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -2,7 +2,7 @@ name = "defguard-client" version = "1.1.0" description = "Defguard desktop client" -license = "" +license-file = "../LICENSE.md" homepage = "https://github.com/DefGuard/client" repository = "https://github.com/DefGuard/client" default-run = "defguard-client" diff --git a/src-tauri/src/app_config.rs b/src-tauri/src/app_config.rs index 646c640e..9147effc 100644 --- a/src-tauri/src/app_config.rs +++ b/src-tauri/src/app_config.rs @@ -62,9 +62,7 @@ pub struct AppConfig { pub tray_theme: AppTrayTheme, pub check_for_updates: bool, pub log_level: LevelFilter, - /// In seconds. How much time should client wait after connecting for the first handshake. - pub connection_verification_time: u32, - /// In seconds. How much time can be between handshakes before connection is automatically dropped. + /// In seconds. How much time after last network activity the connection is automatically dropped. pub peer_alive_period: u32, } @@ -76,7 +74,6 @@ impl Default for AppConfig { check_for_updates: true, tray_theme: AppTrayTheme::Color, log_level: LevelFilter::Info, - connection_verification_time: 10, peer_alive_period: 300, } } diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index f511ca1b..6d4f4f0c 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -38,7 +38,7 @@ use crate::{ utils::{ disconnect_interface, execute_command, get_location_interface_details, get_tunnel_interface_details, get_tunnel_or_location_name, handle_connection_for_location, - handle_connection_for_tunnel, verify_connection, ConnectionToVerify, + handle_connection_for_tunnel, }, wg_config::parse_wireguard_config, CommonConnection, CommonConnectionInfo, CommonLocationStats, ConnectionType, @@ -68,12 +68,6 @@ pub async fn connect( handle_connection_for_location(&location, preshared_key, handle.clone()).await?; reload_tray_menu(&handle).await; info!("Connected to location {location}"); - // verify if connection is alive - tauri::async_runtime::spawn(verify_connection( - handle.clone(), - ConnectionToVerify::Location(location), - )); - debug!("Connection verification task spawned."); } else { error!("Location with ID {location_id} not found in the database, aborting connection attempt"); return Err(Error::NotFound); @@ -85,12 +79,6 @@ pub async fn connect( ); handle_connection_for_tunnel(&tunnel, handle.clone()).await?; info!("Successfully connected to tunnel {tunnel}"); - // verify if connection is alive - tauri::async_runtime::spawn(verify_connection( - handle.clone(), - ConnectionToVerify::Tunnel(tunnel), - )); - debug!("Connection verification task spawned."); } else { error!("Tunnel {location_id} not found"); return Err(Error::NotFound); diff --git a/src-tauri/src/events.rs b/src-tauri/src/events.rs index 52a454e7..772f92b5 100644 --- a/src-tauri/src/events.rs +++ b/src-tauri/src/events.rs @@ -1,5 +1,4 @@ use serde::Serialize; -use strum::Display; use tauri::{api::notification::Notification, AppHandle, Manager}; use crate::ConnectionType; @@ -14,33 +13,19 @@ pub static CONFIG_CHANGED: &str = "config-changed"; pub static DEAD_CONNECTION_DROPPED: &str = "dead-connection-dropped"; pub static APPLICATION_CONFIG_CHANGED: &str = "application-config-changed"; -/// Why [`DEAD_CONNECTION_DROPPED`] event was emitted -#[derive(Display, Clone, Debug, Serialize)] -pub enum DeadConDroppedOutReason { - /// Connections verification periodic loop - PeriodicVerification, - /// Verification after connection establishment - ConnectionVerification, -} - /// Used as payload for [`DEAD_CONNECTION_DROPPED`] event #[derive(Serialize, Clone, Debug)] pub struct DeadConnDroppedOut { pub(crate) name: String, pub(crate) con_type: ConnectionType, - pub(crate) reason: DeadConDroppedOutReason, } impl DeadConnDroppedOut { /// Emits [`DEAD_CONNECTION_DROPPED`] event with corresponding side effects. pub(crate) fn emit(self, app_handle: &AppHandle) { - let body = match self.reason { - DeadConDroppedOutReason::ConnectionVerification => "No handshake.", - DeadConDroppedOutReason::PeriodicVerification => "Handshake timeout.", - }; if let Err(err) = Notification::new(&app_handle.config().tauri.bundle.identifier) .title(format!("{} {} disconnected", self.con_type, self.name)) - .body(body) + .body("Connection activity timeout") .show() { warn!("Dead connection dropped notification not shown. Reason: {err}"); diff --git a/src-tauri/src/periodic/connection.rs b/src-tauri/src/periodic/connection.rs index 183de5b7..a14e4d16 100644 --- a/src-tauri/src/periodic/connection.rs +++ b/src-tauri/src/periodic/connection.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use chrono::{DateTime, TimeDelta, Utc}; +use chrono::{NaiveDateTime, TimeDelta, Utc}; use tauri::{AppHandle, Manager}; use tokio::time::sleep; @@ -14,26 +14,19 @@ use crate::{ Id, }, error::Error, - events::{DeadConDroppedOutReason, DeadConnDroppedOut}, + events::DeadConnDroppedOut, ConnectionType, }; -const INTERVAL_IN_SECONDS: Duration = Duration::from_secs(30); +const CHECK_INTERVAL: Duration = Duration::from_secs(30); /// Returns true if connection is valid -//TODO: Take peer alive period from location -fn check_last_active_connection(last_handshake: i64, peer_alive_period: u32) -> bool { - if let Some(last_handshake) = DateTime::from_timestamp(last_handshake, 0) { - let alive_period = TimeDelta::new(peer_alive_period.into(), 0).unwrap(); - let now = Utc::now(); - let elapsed = now - last_handshake; - let res = elapsed <= alive_period; - trace!( - "Stat check: last_handshake: {last_handshake}, elapsed: {elapsed}, check_result: {res}" - ); - return res; - } - true +fn check_last_active_connection(last: NaiveDateTime, peer_alive_period: TimeDelta) -> bool { + let now = Utc::now(); + let elapsed = now - last.and_utc(); + let res = elapsed <= peer_alive_period; + trace!("Stat check: last activity: {last}, elapsed: {elapsed}, result: {res}"); + res } async fn reconnect( @@ -55,7 +48,6 @@ async fn reconnect( let payload = DeadConnDroppedOut { name: con_interface_name.to_string(), con_type, - reason: DeadConDroppedOutReason::PeriodicVerification, }; payload.emit(app_handle); } @@ -83,7 +75,6 @@ async fn disconnect_dead_connection( let event_payload = DeadConnDroppedOut { con_type, name: con_interface_name.to_string(), - reason: DeadConDroppedOutReason::PeriodicVerification, }; event_payload.emit(&app_handle); } @@ -93,25 +84,28 @@ async fn disconnect_dead_connection( } } -/// Verify if the active connection is valid or not, this is needed in case client was offline and gateway already terminated the peer but client still assume it's connected. +/// Verify if the active connection is active. This is needed in case client was offline and +/// gateway already terminated the peer but client still assume it's connected. pub async fn verify_active_connections(app_handle: AppHandle) -> Result<(), Error> { let app_state = app_handle.state::(); let pool = &app_state.db; - let peer_alive_period = app_state.app_config.lock().unwrap().peer_alive_period; debug!("Active connections verification started."); - // Both are by IDs. + // Both vectors contain IDs. let mut locations_to_disconnect = Vec::new(); let mut tunnels_to_disconnect = Vec::new(); loop { - sleep(INTERVAL_IN_SECONDS).await; + sleep(CHECK_INTERVAL).await; let connections = app_state.active_connections.lock().await; let connection_count = connections.len(); if connection_count == 0 { - debug!("Connections verification skipped, no active connections found, task will wait for next {INTERVAL_IN_SECONDS:?}"); + debug!("Connections verification skipped, no active connections found, task will wait for next {CHECK_INTERVAL:?}"); } - // check every current active connection + let peer_alive_period = TimeDelta::seconds(i64::from( + app_state.app_config.lock().unwrap().peer_alive_period, + )); + // Check currently active connections. for con in &*connections { trace!("Connection: {con:?}"); match con.connection_type { @@ -120,15 +114,16 @@ pub async fn verify_active_connections(app_handle: AppHandle) -> Result<(), Erro Ok(Some(latest_stat)) => { trace!("Latest statistics for location: {latest_stat:?}"); if !check_last_active_connection( - latest_stat.last_handshake, + latest_stat.collected_at, peer_alive_period, ) { + debug!("There wasn't any activity for Location {}; considering it being dead.", con.location_id); locations_to_disconnect.push(con.location_id); } } Ok(None) => { error!( - "LocationStats not found in databse for active connection {} {}({})", + "LocationStats not found in database for active connection {} {}({})", con.connection_type, con.interface_name, con.location_id ); } @@ -142,9 +137,10 @@ pub async fn verify_active_connections(app_handle: AppHandle) -> Result<(), Erro Ok(Some(latest_stat)) => { trace!("Latest statistics for tunnel: {latest_stat:?}"); if !check_last_active_connection( - latest_stat.last_handshake, + latest_stat.collected_at, peer_alive_period, ) { + debug!("There wasn't any activity for Tunnel {}; considering it being dead.", con.location_id); tunnels_to_disconnect.push(con.location_id); } } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index cd09739f..ceec6fcb 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -3,33 +3,30 @@ use std::{ path::Path, process::Command, str::FromStr, - time::Duration, }; -use chrono::{DateTime, NaiveDateTime, Utc}; use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration}; use sqlx::query; -use tauri::{AppHandle, Manager, State}; -use tokio::time::sleep; +use tauri::{AppHandle, Manager}; use tonic::{transport::Channel, Code}; use tracing::Level; use crate::{ appstate::AppState, - commands::{disconnect, LocationInterfaceDetails, Payload}, + commands::{LocationInterfaceDetails, Payload}, database::{ models::{ connection::{ActiveConnection, Connection}, location::Location, - location_stats::{peer_to_location_stats, LocationStats}, - tunnel::{peer_to_tunnel_stats, Tunnel, TunnelConnection, TunnelStats}, + location_stats::peer_to_location_stats, + tunnel::{peer_to_tunnel_stats, Tunnel, TunnelConnection}, wireguard_keys::WireguardKeys, Id, }, DbPool, }, error::Error, - events::{DeadConDroppedOutReason, DeadConnDroppedOut, CONNECTION_CHANGED}, + events::CONNECTION_CHANGED, log_watcher::service_log_watcher::spawn_log_watcher_task, service::proto::{ desktop_daemon_service_client::DesktopDaemonServiceClient, CreateInterfaceRequest, @@ -1094,170 +1091,3 @@ pub async fn sync_connections(app_handle: &AppHandle) -> Result<(), Error> { Ok(()) } - -pub(crate) enum ConnectionToVerify { - Location(Location), - Tunnel(Tunnel), -} - -#[must_use] -fn is_connection_alive(connection_start: NaiveDateTime, last_activity: NaiveDateTime) -> bool { - let start = DateTime::::from_naive_utc_and_offset(connection_start, Utc); - let activity = DateTime::::from_naive_utc_and_offset(last_activity, Utc); - let result = activity >= start; - trace!( - "Check for connection, start: {start}, last activity: {activity}, check result: {result}" - ); - result -} - -/// Verify if made connection is actually alive after being optimistically connected. -/// This works by checking if any activity was made after connecting, within specified time window. -// TODO: put the verification time into UI Settings -pub(crate) async fn verify_connection(app_handle: AppHandle, connection: ConnectionToVerify) { - let state: State = app_handle.state(); - let wait_time = Duration::from_secs( - state - .app_config - .lock() - .unwrap() - .connection_verification_time - .into(), - ); - debug!("Connection verification task is sleeping for {wait_time:?}"); - sleep(wait_time).await; - debug!("Connection verification task finished sleeping"); - let db_pool = &state.db; - let active_connections = state.active_connections.lock().await; - - match connection { - ConnectionToVerify::Location(location) => { - match active_connections.iter().find(|&x| { - x.location_id == location.id && x.connection_type == ConnectionType::Location - }) { - Some(active_connection) => { - debug!("Verifying connection to location {location}"); - trace!("Verifying connection {active_connection:?}"); - let payload = DeadConnDroppedOut { - con_type: ConnectionType::Location, - name: location.name.to_string(), - reason: DeadConDroppedOutReason::ConnectionVerification, - }; - let connection_start = active_connection.start; - drop(active_connections); // release Mutex lock - - match LocationStats::latest_by_location_id(db_pool, location.id).await { - Ok(Some(latest_stat)) => { - if is_connection_alive(connection_start, latest_stat.collected_at) { - info!("Active connection for location {location} verified successfully."); - } else { - info!("Location {location} will be disconnected due to lack of activity within {wait_time:?}."); - match disconnect( - location.id, - ConnectionType::Location, - app_handle.clone(), - ) - .await - { - Ok(()) => { - payload.emit(&app_handle); - } - Err(err) => { - error!( - "Failed to disconnect location {location}. Error: {err}" - ); - } - } - } - } - Ok(None) => { - info!("Location {location} will be disconnected due to lack of statistics within {wait_time:?}."); - match disconnect( - location.id, - ConnectionType::Location, - app_handle.clone(), - ) - .await - { - Ok(()) => { - payload.emit(&app_handle); - } - Err(err) => { - error!( - "Failed to disconnect location {location}. Error: {err}" - ); - } - } - } - Err(err) => { - error!("Connection verification for location {location} Failed during retrieval of stats. Error: {err}"); - } - } - } - None => { - error!("Connection verification for location {location} failed. Active connection in appstate not found."); - } - } - } - ConnectionToVerify::Tunnel(tunnel) => { - debug!("Verifying connection to tunnel {tunnel}"); - match active_connections.iter().find(|&x| { - x.location_id == tunnel.id && x.connection_type == ConnectionType::Tunnel - }) { - Some(active_connection) => { - trace!("Verifying connection {active_connection:?}"); - let payload = DeadConnDroppedOut { - con_type: ConnectionType::Tunnel, - name: tunnel.name.to_string(), - reason: DeadConDroppedOutReason::ConnectionVerification, - }; - let connection_start = active_connection.start; - drop(active_connections); // release Mutex lock - - match TunnelStats::latest_by_tunnel_id(db_pool, tunnel.id).await { - Ok(Some(latest_stat)) => { - if is_connection_alive(connection_start, latest_stat.collected_at) { - info!("Tunnel {tunnel} connection verified successfully."); - } else { - info!("Tunnel {tunnel} will be disconnected due to lack of activity within specified time."); - match disconnect( - tunnel.id, - ConnectionType::Tunnel, - app_handle.clone(), - ) - .await - { - Ok(()) => { - payload.emit(&app_handle); - } - Err(err) => { - error!("Connection for tunnel {tunnel} could not be disconnected. Reason: {err}"); - } - } - } - } - Ok(None) => { - info!("Tunnel {tunnel} will be disconnected due to lack of stats in specified time."); - match disconnect(tunnel.id, ConnectionType::Tunnel, app_handle.clone()) - .await - { - Ok(()) => { - payload.emit(&app_handle); - } - Err(err) => { - error!("Connection for tunnel {tunnel} could not be disconnected. Reason: {err}"); - } - } - } - Err(err) => { - error!("Connection verification for tunnel {tunnel} failed during retrieval of stats. Reason: {err}"); - } - } - } - None => { - error!("Connection verification for tunnel {tunnel} failed. Active connection not found."); - } - } - } - } -} diff --git a/src/i18n/en/index.ts b/src/i18n/en/index.ts index 88466169..2fb45f34 100644 --- a/src/i18n/en/index.ts +++ b/src/i18n/en/index.ts @@ -150,11 +150,6 @@ If you are an admin/devops - all your customers (instances) and all their tunnel helper: 'If active connection exceeds given time without making an handshake with the server. The connection will be considered invalid and disconnected automatically.', }, - connection_verification: { - title: 'Connect timeout', - helper: - 'If set time will pass and any handshake with the server was not made. The connection will be disconnected automatically.', - }, tray: { title: 'System tray', label: 'Tray icon theme', diff --git a/src/i18n/i18n-types.ts b/src/i18n/i18n-types.ts index c5c1d027..29210db3 100644 --- a/src/i18n/i18n-types.ts +++ b/src/i18n/i18n-types.ts @@ -349,16 +349,6 @@ type RootTranslation = { */ helper: string } - connection_verification: { - /** - * C​o​n​n​e​c​t​ ​t​i​m​e​o​u​t - */ - title: string - /** - * I​f​ ​s​e​t​ ​t​i​m​e​ ​w​i​l​l​ ​p​a​s​s​ ​a​n​d​ ​a​n​y​ ​h​a​n​d​s​h​a​k​e​ ​w​i​t​h​ ​t​h​e​ ​s​e​r​v​e​r​ ​w​a​s​ ​n​o​t​ ​m​a​d​e​.​ ​T​h​e​ ​c​o​n​n​e​c​t​i​o​n​ ​w​i​l​l​ ​b​e​ ​d​i​s​c​o​n​n​e​c​t​e​d​ ​a​u​t​o​m​a​t​i​c​a​l​l​y​. - */ - helper: string - } tray: { /** * S​y​s​t​e​m​ ​t​r​a​y @@ -1957,16 +1947,6 @@ export type TranslationFunctions = { */ helper: () => LocalizedString } - connection_verification: { - /** - * Connect timeout - */ - title: () => LocalizedString - /** - * If set time will pass and any handshake with the server was not made. The connection will be disconnected automatically. - */ - helper: () => LocalizedString - } tray: { /** * System tray diff --git a/src/pages/client/clientAPI/types.ts b/src/pages/client/clientAPI/types.ts index aef91043..c28a126a 100644 --- a/src/pages/client/clientAPI/types.ts +++ b/src/pages/client/clientAPI/types.ts @@ -79,7 +79,6 @@ export type AppConfig = { log_level: LogLevel; tray_theme: TrayIconTheme; check_for_updates: boolean; - connection_verification_time: number; peer_alive_period: number; }; diff --git a/src/pages/client/hooks/useClientStore.tsx b/src/pages/client/hooks/useClientStore.tsx index 0fa635b0..604573df 100644 --- a/src/pages/client/hooks/useClientStore.tsx +++ b/src/pages/client/hooks/useClientStore.tsx @@ -34,7 +34,6 @@ const defaultValues: StoreValues = { theme: 'light', tray_theme: 'color', check_for_updates: true, - connection_verification_time: 10, peer_alive_period: 300, }, }; diff --git a/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/GlobalSettingsTab.tsx b/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/GlobalSettingsTab.tsx index a9e2f01c..23b5dfe1 100644 --- a/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/GlobalSettingsTab.tsx +++ b/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/GlobalSettingsTab.tsx @@ -75,12 +75,6 @@ export const GlobalSettingsTab = () => { .min(1, LL.form.errors.required()) .refine((v) => availableTrayThemes.includes(v as TrayIconTheme)), check_for_updates: z.boolean(), - connection_verification_time: z - .number({ - invalid_type_error: LL.form.errors.required(), - required_error: LL.form.errors.required(), - }) - .gte(5, LL.form.errors.minValue({ min: 5 })), peer_alive_period: z .number({ invalid_type_error: LL.form.errors.required(), @@ -145,21 +139,6 @@ export const GlobalSettingsTab = () => { -
-
-

- {localLL.connection_verification.title()}{' '} - {localLL.common.value_in_seconds()} -

- -

{localLL.connection_verification.helper()}

-
-
- -
); }; diff --git a/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigConnectionVerificationPeriod/AppConfigConnectionVerificationPeriod.tsx b/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigConnectionVerificationPeriod/AppConfigConnectionVerificationPeriod.tsx deleted file mode 100644 index 5ec5f2d3..00000000 --- a/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigConnectionVerificationPeriod/AppConfigConnectionVerificationPeriod.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { zodResolver } from '@hookform/resolvers/zod'; -import { useMutation } from '@tanstack/react-query'; -import { useEffect, useMemo, useRef } from 'react'; -import { SubmitHandler, useForm } from 'react-hook-form'; -import { debounceTime, Subject } from 'rxjs'; -import { z } from 'zod'; - -import { useI18nContext } from '../../../../../../../../i18n/i18n-react'; -import { FormInput } from '../../../../../../../../shared/defguard-ui/components/Form/FormInput/FormInput'; -import { useClientStore } from '../../../../../../hooks/useClientStore'; - -export const AppConfigConnectionVerificationPeriod = () => { - const submitRef = useRef(null); - const subjectRef = useRef(new Subject()); - const storeValue = useClientStore((s) => s.appConfig.connection_verification_time); - const updateAppConfig = useClientStore((s) => s.updateAppConfig); - const { mutateAsync } = useMutation({ - mutationFn: updateAppConfig, - }); - const { LL } = useI18nContext(); - - const schema = useMemo( - () => - z.object({ - verificationTime: z - .number({ - required_error: LL.form.errors.required(), - invalid_type_error: LL.form.errors.required(), - }) - .gte( - 5, - LL.form.errors.minValue({ - min: 5, - }), - ), - }), - [LL.form.errors], - ); - - type FormFields = z.infer; - - const { - handleSubmit, - control, - watch, - formState: { isValid, isDirty, isValidating }, - } = useForm({ - defaultValues: { - verificationTime: storeValue, - }, - mode: 'all', - resolver: zodResolver(schema), - }); - - const handleValidSubmit: SubmitHandler = async (values) => { - await mutateAsync({ - connection_verification_time: values.verificationTime, - }); - }; - - const watchedData = watch('verificationTime'); - - useEffect(() => { - if (isValid && isDirty && !isValidating) { - subjectRef.current.next(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [watchedData, isDirty, isValidating]); - - useEffect(() => { - const sub = subjectRef.current - .pipe(debounceTime(200)) - .subscribe(() => submitRef.current?.click()); - return () => { - sub.unsubscribe(); - }; - }, []); - - return ( -
- - - - ); -}; diff --git a/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigPeerAlive/AppConfigPeerAlive.tsx b/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigPeerAlive/AppConfigPeerAlive.tsx deleted file mode 100644 index 09c521c8..00000000 --- a/src/pages/client/pages/ClientSettingsPage/components/GlobalSettingsTab/components/AppConfigPeerAlive/AppConfigPeerAlive.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { zodResolver } from '@hookform/resolvers/zod'; -import { useMutation } from '@tanstack/react-query'; -import { useEffect, useMemo, useRef } from 'react'; -import { SubmitHandler, useForm } from 'react-hook-form'; -import { debounceTime, Subject } from 'rxjs'; -import { z } from 'zod'; - -import { useI18nContext } from '../../../../../../../../i18n/i18n-react'; -import { FormInput } from '../../../../../../../../shared/defguard-ui/components/Form/FormInput/FormInput'; -import { useClientStore } from '../../../../../../hooks/useClientStore'; - -export const AppConfigPeerAlive = () => { - const { LL } = useI18nContext(); - const submitRef = useRef(null); - const submitSubject = useRef(new Subject()); - const peerAlive = useClientStore((s) => s.appConfig.peer_alive_period); - const updateAppConfig = useClientStore((s) => s.updateAppConfig); - - const { mutateAsync } = useMutation({ - mutationFn: updateAppConfig, - }); - - const schema = useMemo( - () => - z.object({ - peer_alive: z - .number({ - required_error: LL.form.errors.required(), - invalid_type_error: LL.form.errors.required(), - }) - .min( - 0, - LL.form.errors.minValue({ - min: 0, - }), - ), - }), - [LL.form.errors], - ); - - type FormFields = z.infer; - - const { - handleSubmit, - control, - watch, - formState: { isValid, isValidating, isDirty }, - } = useForm({ - defaultValues: { - peer_alive: peerAlive, - }, - mode: 'all', - resolver: zodResolver(schema), - }); - - const onValidSubmit: SubmitHandler = async (values) => { - await mutateAsync({ peer_alive_period: values.peer_alive }); - }; - - const watchedFormData = watch('peer_alive'); - - useEffect(() => { - if (isValid && !isValidating && isDirty) { - submitSubject.current.next(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [watchedFormData, isValidating, isDirty]); - - useEffect(() => { - const sub = submitSubject.current.pipe(debounceTime(200)).subscribe(() => { - submitRef.current?.click(); - }); - return () => { - sub.unsubscribe(); - }; - }, []); - - return ( -
- - - - ); -};