diff --git a/.chglog.yml b/.chglog.yml new file mode 100644 index 0000000..75a36d8 --- /dev/null +++ b/.chglog.yml @@ -0,0 +1,7 @@ +conventional-commits: false +deb: + distribution: [] + urgency: "" +debug: false +owner: "" +package-name: "" diff --git a/CHANGELOG.md b/CHANGELOG.md index a1e08db..d101ef5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,47 @@ -8f915f9 (tag: v1.0.2) Add menu `update configs`, refresh combobox without restart soft -27ae224 Add submodule 'github.com/Vai3soh/go-openvpn/' Correct build app with update library libopenvpn3 -284a43b Update readme -8888862 Prepare for v1.0.1 release -272e231 (tag: v1.0.1) Fix bug crash app if use systemd true -89e3746 Update Readme.md -d714ef0 Update Readme.md -b4e1167 Update Readme.md + +1.0.2 +============= +2022-08-10 + +* Add menu `update configs`, refresh combobox without restart soft (8f915f95) +* Add submodule 'github.com/Vai3soh/go-openvpn/' (27ae2241) +* Update readme (284a43b2) +* Prepare for v1.0.1 release (88888625) + +1.0.1 +============= +2022-04-15 + +* Fix bug crash app if use systemd true (272e2316) +* Update Readme.md (89e37469) +* Update Readme.md (d714ef0f) +* Update Readme.md (b4e1167b) + +1.0.0 +============= +2022-03-08 + +* Update Readme.md (ff569857) +* Update Readme.md (9d3bde71) +* Add instruction to run appimage (99a61d51) +* Add make directives, add build packages with nfpm (2f0d6cb1) +* Generate mock test (39799eaf) +* Add files,script to appimage build (920e586e) +* Add dockerfile, license, how to in readme, and more (f6385146) +* Minor changes (7b37d7dc) +* Fix panic negative WaitGroup counter, remove stop sync.WaitGroup (cda909ca) +* Add package openvpn3 from https://github.com/mysteriumnetwork/go-openvpn/tree/master/openvpn3 (188cc871) +* Add package for logging (cf888562) +* Move cmd/goovpn to cmd/app (8d27bb5b) +* Add usecase logics, interfaces, and logics start stop openvpn (4b18ba57) +* Add package, session start disconnect from openvpn server (31305ee3) +* Add logics QT view application (80cc3866) +* Add package for correctly stopping the application (556df8bb) +* Add package - storing profiles in memory. (13657106) +* Add package necessary for config changes(openvpn config). And create test for package. (13889e52) +* Сreating extended versions of modules cmd and file. (5715ca08) +* Create entry point, main() app. (da8bcb1b) +* Add variable icons to application. (0cfdceb8) +* Add entity and create config application. (4ef20cd7) + + diff --git a/LICENSE.md b/LICENSE.md index d570a02..2da5700 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,21 +1,661 @@ -# MIT License - -Copyright (c) 2020 Expenses - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2022 Vai3soh. + 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/Makefile b/Makefile index 9a5bb65..e30d151 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ -CONTAINER_PATH := /home/user/work/src/github.com/Vai3soh/cmd/app/deploy/linux/app project_name = $(notdir $(shell pwd)) main_path = ./cmd/app -submodule_path := third_party/go-openvpn generate: mock-gen @@ -9,20 +7,14 @@ mock-gen: @rm -rf ./test/mocks/packages @go generate ./... -build_docker: - git submodule update --init - cd $(submodule_path) && git checkout goovpn_dev && \ - scripts/xgo_run.sh scripts/build-bridge.sh && cd - - cp $(submodule_path)/openvpn3/bridge/libopenvpn3_linux_amd64.a pkg/openvpn3/bridge/ - @docker pull therecipe/qt:linux_static - @docker build -t goovpn:latest -f Dockerfile . - @docker run --name goovpn goovpn:latest - @docker cp goovpn:$(CONTAINER_PATH) $(main_path)/$(project_name) - @docker stop goovpn - @docker rm goovpn - @docker image rm goovpn:latest - @docker image rm therecipe/qt:linux_static - rm -rf $(submodule_path) +build_bin_linux: + cd $(main_path) && wails build -platform linux/amd64 + +build_bin_windows: + cd $(main_path) && CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++-posix wails build -platform windows/amd64 -skipbindings -ldflags "-linkmode external -extldflags -static" + +build_debug_race: + cd $(main_path) && wails build -debug -race build_package: @nfpm package -t ./build/package -p deb @@ -35,7 +27,9 @@ fmt: gofmt -s -w . clean: - @rm -rf $(main_path)/$(project_name) - + @rm -rf ./build/bin/goovpn ./build/bin/goovpn.exe + changelog_update: - git log v1.0.0...v1.0.2 --oneline --decorate > CHANGELOG.md + rm -rf changelog.yml + chglog init + chglog format --template repo > CHANGELOG.md diff --git a/Readme.md b/Readme.md index 5caa7bd..a3e66f9 100644 --- a/Readme.md +++ b/Readme.md @@ -1,20 +1,24 @@ Goovpn -This gui openvpn client for linux. +This gui openvpn client for linux, windows. Program uses the following libraries: | Package | Changes commits | ----------------------------------------- | ---------------------------------------- -| github.com/mysteriumnetwork/go-openvpn | 7ec797ccb0654e1ecc5459b1199471afcf2e9554 -| github.com/therecipe/qt | +| github.com/Vai3soh/ovpncli (core) | +| github.com/wailsapp/wails | | github.com/fangdingjun/go-log/v5 | + Build: -```git clone --recurse-submodules github.com/Vai3soh/goovpn``` +```git clone github.com/Vai3soh/goovpn``` -Build binary with docker: -```make build_docker``` +Build binary: + linux: + ```make build_bin_linux``` + windows: + ```make build_bin_windows``` And then run build(deb/rpm package): ```make build_package``` @@ -27,23 +31,17 @@ Download deb, rpm, appimage package in realese: ```github.com/Vai3soh/goovpn/releases``` Install package: -```sudo dpkg -i goovpn_1.0.0_amd64.deb or sudo dnf goovpn-1.0.0.x86_64.rpm``` +```sudo dpkg -i goovpn_1.0.3_amd64.deb or sudo dnf goovpn-1.0.3.x86_64.rpm``` After install run: -```sudo edit /etc/goovpn/config.yml``` -and modify path to configs dir (configs_path: '~/ovpnconfigs/') +Run soft ```goovpn``` and modify path to configs dir (option ```Configs dir path```) add path to current user aka: ```/home/user/ovpnconfigs```, create dir ```mkdir /home/user/ovpnconfigs```, -move your openvpn configs files to this dir and run program: - -1. From terminal: ```goovpn -config /etc/goovpn/config.yml``` -2. From menu in DE - -If use Goovpn-x86_64.AppImage, config file is located ```~/.config/goovpn/config.yml``` +move your openvpn configs files to this dir. DNS query: -1. If your distr with systemd, modify config directive ```use_systemd: false``` set ```use_systemd: true``` and install ```systemd-resolve```. +1. If your distr with systemd, enable the option ```Use systemd``` and install ```systemd-resolve```. After restart unit systemd-resolved, your ```/etc/resolv.conf``` ``` @@ -73,11 +71,17 @@ Current DNS Server: 10.211.254.254 DNS Servers: 10.211.254.254 8.8.8.8 DNS Domain: ~. ``` -2. If use ```use_systemd: false``` install ```resolvconf``` - +2. If system not use systemd disable ```Use systemd``` install ```resolvconf``` + +For windows OS (dependencies): + install webview2: https://developer.microsoft.com/en-us/microsoft-edge/webview2/ + install tap or wintun driver: + go to ```https://swupdate.openvpn.org/community/releases/OpenVPN-2.5.8-I604-amd64.msi``` download installer + run and custom install only tap and wintun driver. + Screenshot: -![Data_Label](https://raw.githubusercontent.com/Vai3soh/goovpn/master/goovpn_screen.png) - +![Data_Label](https://raw.githubusercontent.com/Vai3soh/goovpn/master/goovpn_screen1.png) +![Data_Label](https://raw.githubusercontent.com/Vai3soh/goovpn/master/goovpn_screen2.png) diff --git a/build/README.md b/build/README.md new file mode 100644 index 0000000..1ae2f67 --- /dev/null +++ b/build/README.md @@ -0,0 +1,35 @@ +# Build Directory + +The build directory is used to house all the build files and assets for your application. + +The structure is: + +* bin - Output directory +* darwin - macOS specific files +* windows - Windows specific files + +## Mac + +The `darwin` directory holds files specific to Mac builds. +These may be customised and used as part of the build. To return these files to the default state, simply delete them +and +build with `wails build`. + +The directory contains the following files: + +- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`. +- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`. + +## Windows + +The `windows` directory contains the manifest and rc files used when building with `wails build`. +These may be customised for your application. To return these files to the default state, simply delete them and +build with `wails build`. + +- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to + use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file + will be created using the `appicon.png` file in the build directory. +- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`. +- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer, + as well as the application itself (right click the exe -> properties -> details) +- `wails.exe.manifest` - The main application manifest file. \ No newline at end of file diff --git a/build/appicon.png b/build/appicon.png new file mode 100644 index 0000000..63617fe Binary files /dev/null and b/build/appicon.png differ diff --git a/build/darwin/Info.dev.plist b/build/darwin/Info.dev.plist new file mode 100644 index 0000000..02e7358 --- /dev/null +++ b/build/darwin/Info.dev.plist @@ -0,0 +1,32 @@ + + + + CFBundlePackageType + APPL + CFBundleName + {{.Info.ProductName}} + CFBundleExecutable + {{.Name}} + CFBundleIdentifier + com.wails.{{.Name}} + CFBundleVersion + {{.Info.ProductVersion}} + CFBundleGetInfoString + {{.Info.Comments}} + CFBundleShortVersionString + {{.Info.ProductVersion}} + CFBundleIconFile + iconfile + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + {{.Info.Copyright}} + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + + \ No newline at end of file diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist new file mode 100644 index 0000000..e7819a7 --- /dev/null +++ b/build/darwin/Info.plist @@ -0,0 +1,27 @@ + + + + CFBundlePackageType + APPL + CFBundleName + {{.Info.ProductName}} + CFBundleExecutable + {{.Name}} + CFBundleIdentifier + com.wails.{{.Name}} + CFBundleVersion + {{.Info.ProductVersion}} + CFBundleGetInfoString + {{.Info.Comments}} + CFBundleShortVersionString + {{.Info.ProductVersion}} + CFBundleIconFile + iconfile + LSMinimumSystemVersion + 10.13.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + {{.Info.Copyright}} + + \ No newline at end of file diff --git a/build/docker/linux/Dockerfile.linux b/build/docker/linux/Dockerfile.linux deleted file mode 100644 index 5fb4082..0000000 --- a/build/docker/linux/Dockerfile.linux +++ /dev/null @@ -1,23 +0,0 @@ -FROM therecipe/qt:linux_static AS qt - -ARG VERSION=1.19 - -RUN apt-get update && \ -apt-get --no-install-recommends -y install git curl && \ -rm -rf /usr/local/go/ && \ -GO=go$VERSION.linux-amd64.tar.gz && \ -curl -sL --retry 10 --retry-delay 60 -O https://go.dev/dl/$GO && \ -tar -xzf $GO -C /usr/local - -WORKDIR /home/user/work/src/github.com/Vai3soh/goovpn -COPY . /home/user/work/src/github.com/Vai3soh/goovpn - -RUN go get github.com/therecipe/qt/internal/binding/files/docs/5.13.0@v0.0.0-20200904063919-c0c124a5770d - -ENV QT_MXE_ARCH=amd64 -WORKDIR /home/user/work/src/github.com/Vai3soh/goovpn/cmd/app/ - -RUN go mod vendor && \ -cd /home/user/work/src/github.com/Vai3soh/goovpn/vendor/github.com/Vai3soh/ && \ -rm -rf ovpncli && git clone https://github.com/Vai3soh/ovpncli && cd - && \ -qtdeploy build desktop diff --git a/build/docker/windows_64_static/Dockerfile b/build/docker/windows_64_static/Dockerfile deleted file mode 100644 index 98f1d04..0000000 --- a/build/docker/windows_64_static/Dockerfile +++ /dev/null @@ -1,48 +0,0 @@ -#docker build -t therecipe/qt:builder -f Dockerfile . -#docker load --input builder_win_static.tar - -FROM ubuntu:20.04 as base -LABEL maintainer therecipe - -ENV USER user -ENV HOME /home/$USER -ENV GOPATH $HOME/work - -COPY --from=therecipe/qt:linux $GOPATH/bin $GOPATH/bin -COPY --from=therecipe/qt:linux /usr/local/go /usr/local/go -COPY --from=therecipe/qt:linux $GOPATH/src/github.com/therecipe/qt \ -$GOPATH/src/github.com/therecipe/qt - -COPY --from=therecipe/qt:windows_64_static_base_posix /usr/lib/mxe/ \ -/usr/lib/mxe/ - -RUN tar -cvzpf /tmp/all.tar.gz /usr/local/go $GOPATH/bin \ -$GOPATH/src/github.com/therecipe/qt /usr/lib/mxe/ - -FROM ubuntu:20.04 -LABEL maintainer therecipe - -ENV USER=user \ - HOME=/home/user \ - GOPATH=/home/user/work \ - PATH=/usr/lib/mxe/usr/bin:/usr/local/go/bin:$PATH \ - QT_DOCKER=true \ - QT_MXE=true \ - QT_MXE_ARCH=amd64 \ - QT_MXE_STATIC=true \ - QT_PROJ_GIT_PATH=/home/user/work/src/github.com/therecipe/qt - -COPY --from=base /tmp/all.tar.gz /tmp/all.tar.gz - -RUN tar -xvzpf /tmp/all.tar.gz && rm -rf /tmp/all.tar.gz && \ -apt-get -qq update && DEBIAN_FRONTEND=noninteractive apt-get \ ---no-install-recommends -qq -y install \ -ca-certificates git pkg-config - -RUN cd $QT_PROJ_GIT_PATH && \ -$GOPATH/bin/qtsetup prep && \ -$GOPATH/bin/qtsetup check windows && \ -$GOPATH/bin/qtsetup generate windows && \ -$GOPATH/bin/qtsetup install windows && \ -cd $GOPATH/src/github.com/therecipe/qt/internal/examples/widgets/line_edits && \ -$GOPATH/bin/qtdeploy build windows && rm -rf ./deploy diff --git a/build/docker/windows_64_static/Dockerfile.base b/build/docker/windows_64_static/Dockerfile.base deleted file mode 100644 index 8a6b5fb..0000000 --- a/build/docker/windows_64_static/Dockerfile.base +++ /dev/null @@ -1,31 +0,0 @@ -#docker build -t therecipe/qt:windows_64_static_base_posix -f Dockerfile.base . -#docker load --input windows_64_static_base_posix.tar - -FROM ubuntu:20.04 as base - -RUN apt-get -qq update && DEBIAN_FRONTEND=noninteractive \ -apt-get --no-install-recommends -qq -y install ca-certificates git \ -curl autoconf automake autopoint bash bison bzip2 flex g++ g++-multilib \ -gettext git gperf intltool libc6-dev-i386 libgdk-pixbuf2.0-dev \ -libltdl-dev libssl-dev libtool-bin libxml-parser-perl make openssl \ -p7zip-full patch perl pkg-config python python3 python3-pip \ -ruby scons sed unzip wget xz-utils lzip && \ -curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py && \ -python2 get-pip.py && pip install Mako && \ -pip3 install Mako && \ -git clone https://github.com/mxe/mxe.git /usr/lib/mxe && \ -cd /usr/lib/mxe && git pull && \ -find . -type f -print0 | \ -xargs -0 sed -i 's/download\.qt\.io/ftp\.jaist\.ac\.jp\/pub\/qtproject\//g' && \ -cd /usr/lib/mxe && \ -make -j $(grep -c ^processor /proc/cpuinfo) \ -MXE_TARGETS='x86_64-w64-mingw32.static x86_64-w64-mingw32.static.posix' qt5 && \ -rm -rf /usr/lib/mxe/log && \ -rm -rf /usr/lib/mxe/pkg && \ -rm -rf /usr/lib/mxe/.ccache - -FROM ubuntu:20.04 -LABEL maintainer therecipe - -COPY --from=base /usr/lib/mxe /usr/lib/mxe - diff --git a/build/docker/windows_64_static/Dockerfile.qt_ b/build/docker/windows_64_static/Dockerfile.qt_ deleted file mode 100644 index b2696b4..0000000 --- a/build/docker/windows_64_static/Dockerfile.qt_ +++ /dev/null @@ -1,95 +0,0 @@ -#docker build -t therecipe/qt:linux -f Dockerfile.qt_ . -#docker load --input docker.qt_.tar - -FROM ubuntu:20.04 as base - -ENV GO_VER 1.19 -ENV USER user -ENV HOME /home/$USER -ENV GOPATH $HOME/work -ENV go /usr/local/go/bin/go -ENV QT_PROJ_GIT_PATH $GOPATH/src/github.com/therecipe/qt -ENV QT_REPO https://ftp.jaist.ac.jp/pub/qtproject - -RUN apt-get -qq update && \ -DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends \ --qq -y install ca-certificates curl git - -RUN GO=go$GO_VER.linux-amd64.tar.gz && \ -curl -sL --retry 10 --retry-delay 60 -O https://dl.google.com/go/$GO && \ -tar -xzf $GO -C /usr/local - -RUN git clone https://github.com/therecipe/qt/ \ -$HOME/work/src/github.com/therecipe/qt && cd $QT_PROJ_GIT_PATH && \ -find . -type f -print0 | \ -xargs -0 sed -i 's/download\.qt\.io/ftp\.jaist\.ac\.jp\/pub\/qtproject\//g' && \ -$go install -v -tags=no_env github.com/therecipe/qt/cmd/... || : - -RUN cd $QT_PROJ_GIT_PATH && \ -$go get github.com/therecipe/qt/internal/binding/files/docs/5.12.0 && \ -$go get github.com/therecipe/qt/internal/binding/files/docs/5.13.0 && \ -$go get github.com/therecipe/qt/internal/cmd/moc && \ -$go install -v -tags=no_env github.com/therecipe/qt/cmd/... - -RUN apt-get -qq update && \ -DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -qq \ --y install dbus fontconfig libx11-6 libx11-xcb1 - -ENV QT qt-opensource-linux-x64-5.13.0.run - -RUN curl --progress-bar --retry 10 --retry-delay 60 -O \ -$QT_REPO/archive/qt/5.13/5.13.0/$QT && \ -chmod +x $QT - -RUN QT_QPA_PLATFORM=minimal ./$QT --verbose --addTempRepository $QT_REPO/ \ ---no-force-installations --script $GOPATH/src/github.com/\ -therecipe/qt/internal/ci/iscript.qs \ -LINUX=true - -RUN find /opt/Qt5.13.0/5.13.0 -type f -name "*.debug" -delete -RUN find /opt/Qt5.13.0/Docs -type f ! -name "*.index" -delete - -RUN apt-get -qq update && apt-get --no-install-recommends -qq -y \ -install binutils - -RUN find /opt/Qt5.13.0/5.13.0/gcc_64 -type f ! -name "*.a" ! \ --name "*.la" ! -name "*.h" ! -name "*.prl" -name "lib*" -exec strip -s {} \; - -RUN tar -cvzpf /tmp/all.tar.gz /usr/local/go $GOPATH/bin \ -$GOPATH/src/github.com/therecipe/qt /opt/Qt5.13.0/5.13.0 \ -/opt/Qt5.13.0/Docs /opt/Qt5.13.0/Licenses - -FROM ubuntu:20.04 -LABEL maintainer therecipe - -ENV USER user -ENV HOME /home/$USER -ENV GOPATH $HOME/work -ENV PATH /usr/local/go/bin:$PATH -ENV QT_DIR /opt/Qt5.13.0 -ENV QT_DOCKER true -ENV QT_VERSION 5.13.0 -ENV QT_PROJ_GIT_PATH $GOPATH/src/github.com/therecipe/qt - -COPY --from=base /tmp/all.tar.gz /tmp/all.tar.gz - -RUN tar -xvzpf /tmp/all.tar.gz && rm -rf /tmp/all.tar.gz && \ -apt-get -qq update && \ -DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends -qq \ --y install build-essential libglib2.0-dev libglu1-mesa-dev \ -libpulse-dev fontconfig libasound2 libegl1-mesa libnss3 libpci3 \ -libxcomposite1 libxcursor1 libxi6 libxrandr2 libxtst6 \ -fcitx-frontend-qt5 curl unzip ca-certificates git pkg-config && \ -cd $QT_PROJ_GIT_PATH && $GOPATH/bin/qtsetup prep && \ -$GOPATH/bin/qtsetup check && \ -$GOPATH/bin/qtsetup generate && cd $QT_PROJ_GIT_PATH/internal/\ -examples/widgets/line_edits && \ -$GOPATH/bin/qtdeploy build linux && rm -rf ./deploy - -ENV PATH $HOME/flutter/bin:$PATH - -RUN git clone -q --depth 1 -b stable \ -https://github.com/flutter/flutter.git $HOME/flutter - -RUN flutter config --no-analytics && \ -flutter precache --linux --no-android diff --git a/build/docker/windows_64_static/Dockerfile.win b/build/docker/windows_64_static/Dockerfile.win deleted file mode 100644 index 8772fd3..0000000 --- a/build/docker/windows_64_static/Dockerfile.win +++ /dev/null @@ -1,28 +0,0 @@ -FROM vai3soh/qt:win_builder - -ENV LIB_NAME libopenvpn3_windows_amd64.a -ENV WORK_DIR /home/user/work/src/github.com/Vai3soh -ENV WIN_LIB_PATH third_party/go-openvpn/openvpn3/bridge/$LIB_NAME - -ENV GO_VER=1.19 REPO=https://github.com/Vai3soh/goovpn \ - SUB_MODULE_PATH=$WORK_DIR/goovpn/third_party/go-openvpn/ \ - GOPATH=$HOME/work \ - QT_MXE_ARCH=amd64 \ - LIB=$WORK_DIR/goovpn/$WIN_LIB_PATH \ - ABS_BRIDGE_PATH=$WORK_DIR/goovpn/pkg/openvpn3/bridge/ - -RUN apt-get update && \ -apt-get --no-install-recommends -y install git curl && \ -rm -rf /usr/local/go/ && \ -GO=go$GO_VER.linux-amd64.tar.gz && \ -curl -sL --retry 10 --retry-delay 60 -O https://go.dev/dl/$GO && \ -tar -xzf $GO -C /usr/local - -WORKDIR $WORK_DIR - -RUN git clone --recursive $REPO && cd goovpn && git checkout windows_builder && \ -cd $SUB_MODULE_PATH && git checkout goovpn_dev && \ -cp $LIB $ABS_BRIDGE_PATH && \ -cd $WORK_DIR/goovpn/cmd/app/ && qtdeploy build windows - -#QT_DEBUG=true QT_DEBUG_CONSOLE=true qtdeploy build windows diff --git a/build/windows/icon.ico b/build/windows/icon.ico new file mode 100644 index 0000000..bfa0690 Binary files /dev/null and b/build/windows/icon.ico differ diff --git a/build/windows/info.json b/build/windows/info.json new file mode 100644 index 0000000..9727946 --- /dev/null +++ b/build/windows/info.json @@ -0,0 +1,15 @@ +{ + "fixed": { + "file_version": "{{.Info.ProductVersion}}" + }, + "info": { + "0000": { + "ProductVersion": "{{.Info.ProductVersion}}", + "CompanyName": "{{.Info.CompanyName}}", + "FileDescription": "{{.Info.ProductName}}", + "LegalCopyright": "{{.Info.Copyright}}", + "ProductName": "{{.Info.ProductName}}", + "Comments": "{{.Info.Comments}}" + } + } +} \ No newline at end of file diff --git a/build/windows/installer/project.nsi b/build/windows/installer/project.nsi new file mode 100644 index 0000000..3b1588e --- /dev/null +++ b/build/windows/installer/project.nsi @@ -0,0 +1,101 @@ +Unicode true + +#### +## Please note: Template replacements don't work in this file. They are provided with default defines like +## mentioned underneath. +## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo. +## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually +## from outside of Wails for debugging and development of the installer. +## +## For development first make a wails nsis build to populate the "wails_tools.nsh": +## > wails build --target windows/amd64 --nsis +## Then you can call makensis on this file with specifying the path to your binary: +## For a AMD64 only installer: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe +## For a ARM64 only installer: +## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe +## For a installer with both architectures: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe +#### +## The following information is taken from the ProjectInfo file, but they can be overwritten here. +#### +## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}" +## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}" +## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}" +## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}" +## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}" +### +## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" +## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +#### +## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html +#### +## Include the wails tools +#### +!include "wails_tools.nsh" + +# The version information for this two must consist of 4 parts +VIProductVersion "${INFO_PRODUCTVERSION}.0" +VIFileVersion "${INFO_PRODUCTVERSION}.0" + +VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" +VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" +VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" +VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" + +!include "MUI.nsh" + +!define MUI_ICON "..\icon.ico" +!define MUI_UNICON "..\icon.ico" +# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 +!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps +!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. + +!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. +# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer +!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. +!insertmacro MUI_PAGE_INSTFILES # Installing page. +!insertmacro MUI_PAGE_FINISH # Finished installation page. + +!insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page + +!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer + +## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 +#!uninstfinalize 'signtool --file "%1"' +#!finalize 'signtool --file "%1"' + +Name "${INFO_PRODUCTNAME}" +OutFile "..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. +InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). +ShowInstDetails show # This will always show the installation details. + +Function .onInit + !insertmacro wails.checkArchitecture +FunctionEnd + +Section + !insertmacro wails.webview2runtime + + SetOutPath $INSTDIR + + !insertmacro wails.files + + CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + + !insertmacro wails.writeUninstaller +SectionEnd + +Section "uninstall" + RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath + + RMDir /r $INSTDIR + + Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" + Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" + + !insertmacro wails.deleteUninstaller +SectionEnd diff --git a/build/windows/installer/tmp/MicrosoftEdgeWebview2Setup.exe b/build/windows/installer/tmp/MicrosoftEdgeWebview2Setup.exe new file mode 100755 index 0000000..89a56ec Binary files /dev/null and b/build/windows/installer/tmp/MicrosoftEdgeWebview2Setup.exe differ diff --git a/build/windows/installer/wails_tools.nsh b/build/windows/installer/wails_tools.nsh new file mode 100644 index 0000000..46fbd29 --- /dev/null +++ b/build/windows/installer/wails_tools.nsh @@ -0,0 +1,171 @@ +# DO NOT EDIT - Generated automatically by `wails build` + +!include "x64.nsh" +!include "WinVer.nsh" +!include "FileFunc.nsh" + +!ifndef INFO_PROJECTNAME + !define INFO_PROJECTNAME "goovpn" +!endif +!ifndef INFO_COMPANYNAME + !define INFO_COMPANYNAME "goovpn" +!endif +!ifndef INFO_PRODUCTNAME + !define INFO_PRODUCTNAME "goovpn" +!endif +!ifndef INFO_PRODUCTVERSION + !define INFO_PRODUCTVERSION "1.0.0" +!endif +!ifndef INFO_COPYRIGHT + !define INFO_COPYRIGHT "Copyright........." +!endif +!ifndef PRODUCT_EXECUTABLE + !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" +!endif +!ifndef UNINST_KEY_NAME + !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +!endif +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" + +!ifndef REQUEST_EXECUTION_LEVEL + !define REQUEST_EXECUTION_LEVEL "admin" +!endif + +RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" + +!ifdef ARG_WAILS_AMD64_BINARY + !define SUPPORTS_AMD64 +!endif + +!ifdef ARG_WAILS_ARM64_BINARY + !define SUPPORTS_ARM64 +!endif + +!ifdef SUPPORTS_AMD64 + !ifdef SUPPORTS_ARM64 + !define ARCH "amd64_arm64" + !else + !define ARCH "amd64" + !endif +!else + !ifdef SUPPORTS_ARM64 + !define ARCH "arm64" + !else + !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" + !endif +!endif + +!macro wails.checkArchitecture + !ifndef WAILS_WIN10_REQUIRED + !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." + !endif + + !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED + !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" + !endif + + ${If} ${AtLeastWin10} + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + Goto ok + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + Goto ok + ${EndIf} + !endif + + IfSilent silentArch notSilentArch + silentArch: + SetErrorLevel 65 + Abort + notSilentArch: + MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" + Quit + ${else} + IfSilent silentWin notSilentWin + silentWin: + SetErrorLevel 64 + Abort + notSilentWin: + MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" + Quit + ${EndIf} + + ok: +!macroend + +!macro wails.files + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" + ${EndIf} + !endif +!macroend + +!macro wails.writeUninstaller + WriteUninstaller "$INSTDIR\uninstall.exe" + + SetRegView 64 + WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" +!macroend + +!macro wails.deleteUninstaller + Delete "$INSTDIR\uninstall.exe" + + SetRegView 64 + DeleteRegKey HKLM "${UNINST_KEY}" +!macroend + +# Install webview2 by launching the bootstrapper +# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment +!macro wails.webview2runtime + !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT + !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" + !endif + + SetRegView 64 + # If the admin key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + + ${If} ${REQUEST_EXECUTION_LEVEL} == "user" + # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + ${EndIf} + + SetDetailsPrint both + DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" + SetDetailsPrint listonly + + InitPluginsDir + CreateDirectory "$pluginsdir\webview2bootstrapper" + SetOutPath "$pluginsdir\webview2bootstrapper" + File "tmp\MicrosoftEdgeWebview2Setup.exe" + ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' + + SetDetailsPrint both + ok: +!macroend \ No newline at end of file diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest new file mode 100644 index 0000000..17e1a23 --- /dev/null +++ b/build/windows/wails.exe.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + true/pm + permonitorv2,permonitor + + + \ No newline at end of file diff --git a/changelog.yml b/changelog.yml new file mode 100644 index 0000000..486ff70 --- /dev/null +++ b/changelog.yml @@ -0,0 +1,256 @@ +- semver: 1.0.2 + date: 2022-08-10T12:45:29+10:00 + packager: GitHub + changes: + - commit: 8f915f953033761084c498d49a19176a7c641a72 + note: Add menu `update configs`, refresh combobox without restart soft + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: Vai3soh + email: work.rwx.seven@gmail.com + - commit: 27ae2241dcef1d7c211adf32d01fbfaf7b18a159 + note: |- + Add submodule 'github.com/Vai3soh/go-openvpn/' + Correct build app with update library libopenvpn3 + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: Vai3soh + email: work.rwx.seven@gmail.com + - commit: 284a43b25067b878ccd67442cf1f3fa5b37628f1 + note: Update readme + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: Vai3soh + email: work.rwx.seven@gmail.com + - commit: 88888625aa427e45cac1a7f29537fea393f1f8e5 + note: Prepare for v1.0.1 release + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: Vai3soh + email: work.rwx.seven@gmail.com +- semver: 1.0.1 + date: 2022-04-15T16:27:35+10:00 + packager: GitHub + changes: + - commit: 272e23162a060e494a2e0008e57c7239301723e6 + note: Fix bug crash app if use systemd true + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: Vai3soh + email: work.rwx.seven@gmail.com + - commit: 89e374690dee12343301cf036281ee65623fca11 + note: Update Readme.md + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: GitHub + email: noreply@github.com + - commit: d714ef0fc768a19b2d666ce3b249a240b4a6881f + note: Update Readme.md + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: GitHub + email: noreply@github.com + - commit: b4e1167b517f3f9211af20ded8f53e40c6d706a9 + note: Update Readme.md + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: GitHub + email: noreply@github.com +- semver: 1.0.0 + date: 2022-03-08T18:30:44+10:00 + packager: GitHub + changes: + - commit: ff56985782ca2fced5b9a775dea1cdd136c828f3 + note: Update Readme.md + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: GitHub + email: noreply@github.com + - commit: 9d3bde71c41e1e54d9af75617ddbc552149186fd + note: Update Readme.md + author: + name: Vai3soh + email: work.rwx.seven@gmail.com + committer: + name: GitHub + email: noreply@github.com + - commit: 99a61d51027563b3c6dae39aa6ced8e5237444ea + note: Add instruction to run appimage + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 2f0d6cb1965acbc41b7fe67dfb770a4a76cc17bc + note: Add make directives, add build packages with nfpm + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 39799eaf00e82cf82922089257b35cb7f44d692a + note: Generate mock test + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 920e586e593ac1db70eadd3c7ced94cbb22a9fa5 + note: Add files,script to appimage build + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: f63851467990a94aef4091e129adfcf0a0c6e76a + note: Add dockerfile, license, how to in readme, and more + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 7b37d7dc1122cb41baa10856589dd08b492e72cb + note: Minor changes + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: cda909caf0f9c611d6b96f065b047b5449d85c4b + note: Fix panic negative WaitGroup counter, remove stop sync.WaitGroup + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 188cc8714050d4028183a85f7c642b982b432f14 + note: Add package openvpn3 from https://github.com/mysteriumnetwork/go-openvpn/tree/master/openvpn3 + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: cf888562d2ec379883d03b853621e8d21e8d5df7 + note: Add package for logging + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 8d27bb5b40ca44b31aa3befbab9bf13c355bc63c + note: Move cmd/goovpn to cmd/app + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 4b18ba57b9afa763907595959d1b77b73cb02039 + note: Add usecase logics, interfaces, and logics start stop openvpn + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 31305ee3b00cdd02a7776c0a36e252509b1c51ca + note: Add package, session start disconnect from openvpn server + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 80cc38660f7e22616d9f8fc05a8da2cc84b74d58 + note: Add logics QT view application + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 556df8bb02042a3ef6fb3cd2b99181173efe2c39 + note: Add package for correctly stopping the application + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 13657106fa71455a61774c24c89804a32c6c64a6 + note: |- + Add package - storing profiles in memory. + Add package - openvpn dns control over (systemd-resolve/resolvconf). + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 13889e522f95fc691734ef6e806f9ec10167109e + note: Add package necessary for config changes(openvpn config). And create test for package. + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 5715ca08263af0d08fc597078ad564d383fce612 + note: Сreating extended versions of modules cmd and file. + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: da8bcb1b4c74d7bae7d5fedc23c4326ae41e96e7 + note: Create entry point, main() app. + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 0cfdceb8316a22085662afdcd0b3f433eb60c798 + note: Add variable icons to application. + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com + - commit: 4ef20cd7890b618b472a724cb11f6042007ac8c8 + note: Add entity and create config application. + author: + name: Vai3soh + email: he9tei7@protonmail.com + committer: + name: Vai3soh + email: he9tei7@protonmail.com diff --git a/cmd/app/main.go b/cmd/app/main.go index 7032576..e13e367 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -1,32 +1,25 @@ -//go:build linux -// +build linux - package main import ( - "flag" "log" - "github.com/Vai3soh/goovpn/config" + embedfile "github.com/Vai3soh/goovpn" "github.com/Vai3soh/goovpn/internal/app" - "github.com/ilyakaznacheev/cleanenv" -) - -var Config = flag.String( - "config", "./config/config.yml", - "path to configuration file", + "github.com/caarlos0/env/v6" ) -func init() { - flag.Parse() +type config struct { + LogLvl string `env:"LVL_GOOVPN" envDefault:"debug"` + PathDB string `env:"DB_GOOVPN" envDefault:"goovpn.db"` } func main() { - cfg := config.Config{} - err := cleanenv.ReadConfig(*Config, &cfg) - if err != nil { - log.Fatalf("Config error: [%s]\n", err) + embd := embedfile.NewData() + + cfg := config{} + if err := env.Parse(&cfg); err != nil { + log.Fatal(err) } - app.Run(&cfg) + app.Run_wails(*embd.Fs, embd.Icon, cfg.LogLvl, cfg.PathDB) } diff --git a/cmd/app/main_win.go b/cmd/app/main_win.go deleted file mode 100644 index c631023..0000000 --- a/cmd/app/main_win.go +++ /dev/null @@ -1,32 +0,0 @@ -//go:build windows -// +build windows - -package main - -import ( - "flag" - "log" - - "github.com/Vai3soh/goovpn/config" - "github.com/Vai3soh/goovpn/internal/app" - "github.com/ilyakaznacheev/cleanenv" -) - -var Config = flag.String( - "config", "C:\\ProgramData\\goovpn\\config_win.yml", - "path to configuration file", -) - -func init() { - flag.Parse() -} - -func main() { - cfg := config.Config{} - err := cleanenv.ReadConfig(*Config, &cfg) - if err != nil { - log.Fatalf("Config error: [%s]\n", err) - } - - app.Run(&cfg) -} diff --git a/cmd/app/wails.json b/cmd/app/wails.json new file mode 100644 index 0000000..a8fbc27 --- /dev/null +++ b/cmd/app/wails.json @@ -0,0 +1,11 @@ +{ + "name": "goovpn", + "outputfilename": "goovpn", + "assetdir": "../../frontend", + "frontend:dir": "../../frontend", + "build:dir": "../../build/", + "author": { + "name": "Vai3soh", + "email": "work.rwx.seven@gmail.com" + } +} diff --git a/config/config.go b/config/config.go deleted file mode 100644 index 8e4aa23..0000000 --- a/config/config.go +++ /dev/null @@ -1,39 +0,0 @@ -package config - -type ( - Config struct { - App `yaml:"app"` - Log `yaml:"logger"` - } - - App struct { - Name string `env-required:"true" yaml:"name" env:"APP_NAME"` - Version string `env-required:"true" yaml:"version" env:"APP_VERSION"` - IdApp string `env-required:"true" yaml:"id_app" env:"ID_APP"` - AppIcon string `env-required:"true" yaml:"app_icon" env:"APP_ICON"` - AppImagePathConnected string `env-required:"true" yaml:"image_path_connected" env:"IMAGE_PATH_CONNECTED"` - AppImagePathBlink string `env-required:"true" yaml:"image_path_blink" env:"IMAGE_PATH_BLINK"` - AppImagePathOpen string `env-required:"true" yaml:"image_path_open" env:"IMAGE_PATH_OPEN"` - AppImagePathDisconnected string `env-required:"true" yaml:"image_path_disconnected" env:"IMAGE_PATH_DISCONNECTED"` - TempDir string `env-required:"true" yaml:"temp_dir" env:"TEMP_DIR"` - ConfigsPath string `env-required:"true" yaml:"configs_path" env:"CONFIGS_PATH"` - StopTimeout int `env-required:"true" yaml:"stop_time" env:"STOP_TIME"` - Height float32 `env-required:"true" yaml:"height_app" env:"HEIGHT_APP"` - Width float32 `env-required:"true" yaml:"width_app" env:"WIDTH_APP"` - UseSystemd bool `yaml:"use_systemd" env:"USE_SYSTEMD"` - TunPersist bool `yaml:"tun_persist" env:"TUN_PERSIST"` - ClockTicks int `env-required:"true" yaml:"clock_ticks_time_ms" env:"CLOCK_TICKS_TIME_MS"` - CountReconn int `env-required:"true" yaml:"count_reconnection_attempt" env:"COUNT_RECCONECTION_ATTEMPT"` - VerbLogs bool `yaml:"verbose_logs" env:"VERB_LOGS"` - ConnectTimeout int `env-required:"true" yaml:"conn_timeout" env:"CONN_TIMEOUT"` - CompressionMode string `env-required:"true" yaml:"mode" env:"MODE"` - CheckDisableClientCert bool `yaml:"disable_cert" env:"DISABLE_CERT"` - } - - Log struct { - Level string `env-required:"true" yaml:"log_level" env:"LOG_LEVEL"` - Logfile string `yaml:"log_file" env:"LOG_FILE" ` - LogFileCount int `yaml:"log_file_count" env:"LOG_FILE_COUNT"` - Log_File_Size int64 `yaml:"log_file_size" env:"LOG_FILE_SIZE"` - } -) diff --git a/config/config.yml b/config/config.yml deleted file mode 100644 index 5973f77..0000000 --- a/config/config.yml +++ /dev/null @@ -1,30 +0,0 @@ -app: - name: 'Goovpn' - version: '1.0.2' - id_app: 'Goovpn' - stop_time: 400 - image_path_connected: 'assets/connecting.png' - image_path_disconnected: 'assets/disconnect.png' - image_path_blink: 'assets/blink.png' - image_path_open: 'assets/open.png' - app_icon: 'assets/app.png' - temp_dir: '/tmp/goovpn/' - configs_path: '~/ovpnconfigs/' - height_app: 500 - width_app: 600 - use_systemd: false - tun_persist: true - clock_ticks_time_ms: 1000 - verbose_logs: false - disable_cert: false - mode: 'yes' #yes no - conn_timeout: 30 - count_reconnection_attempt: 7 - -logger: - log_level: 'debug' #info - #log_file: - #log_file_count: - #log_file_size: - - diff --git a/config/config_win.yml b/config/config_win.yml deleted file mode 100644 index d5fcb6d..0000000 --- a/config/config_win.yml +++ /dev/null @@ -1,29 +0,0 @@ -app: - name: 'Goovpn' - version: '1.0.2' - id_app: 'Goovpn' - stop_time: 400 - image_path_connected: 'assets/connecting.png' - image_path_disconnected: 'assets/disconnect.png' - image_path_blink: 'assets/blink.png' - image_path_open: 'assets/open.png' - app_icon: 'assets/app.png' - temp_dir: 'C:\Users\Default\AppData\Local\Temp\' - configs_path: 'Desktop\OVPNCONFIGS\' #use os.Getenv(`USERPROFILE`) - height_app: 500 - width_app: 600 - use_systemd: false - tun_persist: true - clock_ticks_time_ms: 1000 - verbose_logs: false - disable_cert: false - mode: 'yes' #yes no - conn_timeout: 30 - count_reconnection_attempt: 7 - -logger: - log_level: 'debug' #info - #log_file: - #log_file_count: - #log_file_size: - \ No newline at end of file diff --git a/embedfile.go b/embedfile.go new file mode 100644 index 0000000..4cf81b7 --- /dev/null +++ b/embedfile.go @@ -0,0 +1,24 @@ +package embedfile + +import ( + "embed" +) + +var ( + //go:embed frontend/src + assets embed.FS + //go:embed build/appicon.png + icon []byte +) + +type Data struct { + Fs *embed.FS + Icon []byte +} + +func NewData() *Data { + return &Data{ + Fs: &assets, + Icon: icon, + } +} diff --git a/entity/profile.go b/entity/profile.go index 348d9a6..ae1f576 100644 --- a/entity/profile.go +++ b/entity/profile.go @@ -4,3 +4,8 @@ type Profile struct { Body string Path string } + +type Message struct { + AtrId string + Value string +} diff --git a/frontend/src/home.html b/frontend/src/home.html new file mode 100644 index 0000000..9db5246 --- /dev/null +++ b/frontend/src/home.html @@ -0,0 +1,43 @@ + + + + + + goovpn + + + + + + + + +
+ +
+
+
+
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + + diff --git a/frontend/src/index.html b/frontend/src/index.html new file mode 100644 index 0000000..5c62e7c --- /dev/null +++ b/frontend/src/index.html @@ -0,0 +1,345 @@ + + + + + + + + + + + +
+ +
+
+ General configure: +
+
+ +

Use systemd

+
+
+
+
+

Configs dir path

+ +

+ +

+
+
+
+
+

Count of reconnection attempts

+ +

+ +

+
+
+
+
+ General openvpn library: +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ Debug and Compression: +
+
+

Ssl Debug Level

+
+
+
+
+
+

Compression Mode

+
+
+
+
+
+ Other options: +
+
+

Connection Timeout

+ +
+
+
+
+

Unused Addr Families

+ +

+ +

+
+
+
+
+

Clock Tick(MS)

+ +

+ +

+
+
+
+
+

External Pki Alias

+ +

+ +

+
+
+
+
+

Gremlin Config

+ +

+ +

+
+
+
+
+

Gui Version

+ +

+ +

+
+
+
+
+

HwAddr Override

+ +

+ +

+
+
+
+
+

Platform Version

+ +

+ +

+
+
+
+
+

Port override

+ +

+ +

+
+
+
+
+

Private Key Password

+ +

+ +

+
+
+
+
+

Proto Override

+ +

+ +

+
+
+
+
+

Proto Version Override

+ +

+ +

+
+
+
+
+

Proxy Host

+ +

+ +

+
+
+
+
+

Proxy Username

+ +

+ +

+
+
+
+
+

Proxy Password

+ +

+ +

+
+
+
+
+

Proxy Port

+ +

+ +

+
+
+
+
+

Server Override

+ +

+ +

+
+
+
+
+

Sso Methods

+ +

+ +

+
+
+
+
+

Tls Cert Profile Override

+ +

+ +

+
+
+
+
+

Tls Cipher List

+ +

+ +

+
+
+
+
+

Tls Ciphersuites List

+ +

+ +

+
+
+
+
+

Tls Version Min Override

+ +

+ +

+
+
+
+
+

Default Key Direction

+ +

+ +

+
+
+
+ + + diff --git a/frontend/src/static/css/fonts/GraublauWeb.otf b/frontend/src/static/css/fonts/GraublauWeb.otf new file mode 100644 index 0000000..189822b Binary files /dev/null and b/frontend/src/static/css/fonts/GraublauWeb.otf differ diff --git a/frontend/src/static/css/home.css b/frontend/src/static/css/home.css new file mode 100644 index 0000000..974c75a --- /dev/null +++ b/frontend/src/static/css/home.css @@ -0,0 +1,111 @@ +body { + background: #5D666D none no-repeat scroll 0% 100%; +} + +.content-wrapper{ + height: 100%; + +} + +textarea { + display: block; + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + resize:none; + height: 80vh; + margin-top: 1em; +} + +::-webkit-scrollbar { + -webkit-appearance: none; + width: 10px; +} + +::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: rgba(0,0,0,.3); +} + +@font-face { + font-family: 'GraublauWeb'; + font-weight: bold; + src: url("fonts/GraublauWeb.otf") format("opentype"); +} + +.itc-select__toggle { + font-family: GraublauWeb +} + +li.itc-select__option { + font-family: GraublauWeb +} + +.myButton { + box-shadow:inset 0px 1px 0px 0px #ffffff; + background:linear-gradient(to bottom, #ededed 5%, #dfdfdf 100%); + background-color:#ededed; + border-radius:6px; + border:1px solid #dcdcdc; + cursor:pointer; + color:#080808; + font-family:'Arial Narrow'; + font-size:15px; + padding:6px 24px; + text-decoration:none; + text-shadow:0px 1px 0px #ffffff; + width:98%; +} + +.myButton:hover { + background:linear-gradient(to bottom, #dfdfdf 5%, #ededed 100%); + background-color:#dfdfdf; +} + +.myButton:active { + position:relative; + top:1px; +} + +.flex-container { + width: 100%; + margin-top: 1em; + display: -webkit-flex; + display: flex; + height: 100%; +} + +.flex-container div { + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +ul { + list-style: none; + padding-left: 0; +} + +a { + text-decoration: none; + color:#080808; + font-family:'Arial Narrow'; + font-size: 20px; +} + + +li.option { + list-style: none; + background: url(/static/icons/settings.svg) no-repeat 0 1px; + padding-left: 24px; +} + +li.option:active { + position:relative; + top:1px; +} + +#btnDisconnect { + cursor: not-allowed; +} \ No newline at end of file diff --git a/frontend/src/static/css/itc-custom-select.css b/frontend/src/static/css/itc-custom-select.css new file mode 100644 index 0000000..9ce8722 --- /dev/null +++ b/frontend/src/static/css/itc-custom-select.css @@ -0,0 +1,92 @@ +.itc-select { + position: relative; + width: 100%; +} + +.itc-select__toggle { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-style: italic; + line-height: 1.4; + background-color: #fff; + border: 1px solid #ccc; + border-radius: 0.3125rem; + cursor: pointer; + user-select: none; +} + +.itc-select__toggle::after { + flex-shrink: 0; + width: 0.75rem; + height: 0.75rem; + margin-left: 1rem; + background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" height="100" width="100"%3E%3Cpath d="M97.625 25.3l-4.813-4.89c-1.668-1.606-3.616-2.41-5.84-2.41-2.27 0-4.194.804-5.777 2.41L50 52.087 18.806 20.412C17.223 18.805 15.298 18 13.03 18c-2.225 0-4.172.804-5.84 2.41l-4.75 4.89C.813 26.95 0 28.927 0 31.23c0 2.346.814 4.301 2.439 5.865l41.784 42.428C45.764 81.174 47.689 82 50 82c2.268 0 4.215-.826 5.84-2.476l41.784-42.428c1.584-1.608 2.376-3.563 2.376-5.865 0-2.26-.792-4.236-2.375-5.932z"/%3E%3C/svg%3E'); + background-size: cover; + content: ""; +} + +.itc-select__toggle:focus { + outline: none; +} + +.itc-select_show .itc-select__toggle::after { + transform: rotate(180deg); +} + +.itc-select__dropdown { + position: absolute; + top: 2.5rem; + right: 0; + left: 0; + z-index: 2; + display: none; + max-height: 10rem; + overflow-y: auto; + background-color: #fff; + border: 1px solid #ccc; + border-radius: 0.3125rem; +} + +.itc-select_show .itc-select__dropdown { + display: block; +} + +.itc-select_show .itc-select__backdrop { + display: block; +} + +.itc-select__options { + margin: 0; + padding: 0; + list-style: none; +} + +.itc-select__option { + padding: 0.375rem 0.75rem; +} + +.itc-select__option_selected { + display: flex; + justify-content: space-between; + align-items: center; + background-color: #e1f5fe; +} + +.itc-select__option_selected::after { + width: 0.75rem; + height: 0.75rem; + color: #0277bd; + background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" height="100" width="100" class="svg-inline--fa fa-check fa-w-16" data-icon="check" data-prefix="fas" aria-hidden="true"%3E%3Cpath d="M33.964 85.547l-32.5-32.251a4.935 4.935 0 010-7.017l7.071-7.017a5.027 5.027 0 017.071 0L37.5 60.987l46.894-46.534a5.028 5.028 0 017.07 0l7.072 7.017a4.935 4.935 0 010 7.017l-57.5 57.06a5.027 5.027 0 01-7.072 0z" fill="%230277bd"/%3E%3C/svg%3E'); + background-size: cover; + content: ""; +} + +.itc-select__option:hover { + background-color: #f5f5f5; + cursor: pointer; + transition: 0.2s background-color ease-in-out; +} diff --git a/frontend/src/static/css/settings.css b/frontend/src/static/css/settings.css new file mode 100644 index 0000000..e0fb9cb --- /dev/null +++ b/frontend/src/static/css/settings.css @@ -0,0 +1,126 @@ +body { + background: #5D666D none no-repeat scroll 0% 100%; +} + +p, +label { + font: 1rem 'Fira Sans', sans-serif; +} + +input { + margin: .2rem; +} + +fieldset { + border-color: black; +} + +body > fieldset > div.options{ + display: inline-block; +} + +.itc-select{ + position: relative; + display: inline-block; + width: auto; + height: 10px; +} + +.itc-select__toggle { + width: 60px; + height: 25px; +} + +div.select_{ + height: 35px; +} + +div.select__{ + height: 35px; +} + +div.ssl_debug{ + margin-top: -20px; +} + +input[type="text"] { + width: 50px; + border: 1px solid black; + border-radius: 5px; +} + + +input#config_dir_path[type="text"] { + width: 100px; + border: 1px solid black; + border-radius: 5px; +} + +div.timeout_conn{ + margin-top: -20px; +} + +::-webkit-scrollbar { + -webkit-appearance: none; + width: 10px; +} + +::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: rgba(0,0,0,.3); +} + +.itc-select__toggle { + width: 90px; +} + +.submit { + background:linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%); + background-color:#f9f9f9; + border-radius:6px; + border:1px solid #dcdcdc; + display:inline-block; + cursor:pointer; + color:#666666; + font-family:Arial; + font-size:11px; + font-weight:bold; + padding:4px 9px; + text-decoration:none; + text-shadow:0px 1px 0px #ffffff; + border: 1px solid black; + width: 100%; +} +.submit:hover { + background:linear-gradient(to bottom, #e9e9e9 5%, #f9f9f9 100%); + background-color:#e9e9e9; +} + +.submit:active { + position:relative; + top:1px; +} + +ul { + list-style: none; + padding-left: 0; +} + +li.option { + list-style: none; + background: url(/static/icons/home.svg) no-repeat 0 -1px; + padding-left: 30px; +} + +li.option:active { + position:relative; + top:1px; +} + +a { + text-decoration: none; + color:#080808; + font-family:'Arial Narrow'; + font-size: 20px; + margin-top: 10px; +} diff --git a/frontend/src/static/icons/download.svg b/frontend/src/static/icons/download.svg new file mode 100644 index 0000000..53b7fa1 --- /dev/null +++ b/frontend/src/static/icons/download.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/static/icons/download_.svg b/frontend/src/static/icons/download_.svg new file mode 100644 index 0000000..92ea81e --- /dev/null +++ b/frontend/src/static/icons/download_.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/static/icons/favicon.png b/frontend/src/static/icons/favicon.png new file mode 100644 index 0000000..9ad2fb5 Binary files /dev/null and b/frontend/src/static/icons/favicon.png differ diff --git a/frontend/src/static/icons/favicon2.png b/frontend/src/static/icons/favicon2.png new file mode 100644 index 0000000..8998ad5 Binary files /dev/null and b/frontend/src/static/icons/favicon2.png differ diff --git a/frontend/src/static/icons/home.svg b/frontend/src/static/icons/home.svg new file mode 100644 index 0000000..1331cd9 --- /dev/null +++ b/frontend/src/static/icons/home.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/static/icons/info.svg b/frontend/src/static/icons/info.svg new file mode 100644 index 0000000..e38914a --- /dev/null +++ b/frontend/src/static/icons/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/static/icons/settings.svg b/frontend/src/static/icons/settings.svg new file mode 100644 index 0000000..4066b9f --- /dev/null +++ b/frontend/src/static/icons/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/static/js/home.js b/frontend/src/static/js/home.js new file mode 100644 index 0000000..e7f43da --- /dev/null +++ b/frontend/src/static/js/home.js @@ -0,0 +1,107 @@ +var cfg = ''; + +function getSelect(){ + return window.go.gui.Gui.GetConfigsAndChangeCWD().then(result => { + var arr = []; + for (var i = 0; i < result.length; i++) { + arr[i] = [result[i],result[i]]; + } + const select_ = new ItcCustomSelect('#inputGroupSelect01', { + name: 'config', + options: arr, + onSelected(select) { + cfg = select.value; + }, + }); + return select_; + }); +} + +let Promise__ = getSelect().then( + function(value){ + return value; +}); + +function ClearLog(){ + document.getElementById('FormControlTextarea1').innerHTML = ""; +} + +function getElementByXpath(path) { + return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; +} + +var connect = document.getElementById('btnConnect'); +var disconnect = document.getElementById('btnDisconnect'); +var box = document.getElementsByClassName('itc-select__toggle'); +var settings = getElementByXpath("/html/body/div[1]/ul/li"); + +var isEvent = false; +runtime.EventsOn("rcv:read_log", (msg,count,countReconn) => { + + document.getElementById('FormControlTextarea1').innerHTML += msg + "\n"; + + if (!isEvent) { + Promise__.then(select => { + select.dispose(); + connect.disabled = true; + connect.style.cursor = "not-allowed"; + settings.style.visibility = "hidden"; + }); + isEvent = true; + } + + if (msg.includes("event name: RECONNECTING")) { + box.config.style.color = "black"; + } + + if (msg.includes("Server poll timeout, trying next remote entry...")) { + box.config.style.color = "black"; + count++; + if (count == countReconn) { + Promise__.then(select => { + select.enable(); + disconnect.disabled = true; + disconnect.style.cursor = "not-allowed"; + }); + } + } + + if (msg.includes("event name: DISCONNECTED") || msg.includes("UNKNOWN/UNSUPPORTED OPTIONS")) { + connect.disabled = false; + connect.style.cursor = "pointer"; + box.config.style.color = "black"; + settings.style.visibility = "visible"; + + Promise__.then(select => { + select.enable(); + disconnect.disabled = true; + disconnect.style.cursor = "not-allowed"; + }); + + } + + if (msg.includes("event name: CONNECTING")) { + disconnect.disabled = false; + disconnect.style.cursor = "pointer"; + } + + if (msg.includes("event name: CONNECTED")) { + box.config.style.color = "green"; + } +}) + +function Runners() { + if (cfg != "") { + ClearLog(); + window.go.openvpn.TransportOvpnClient.Connect(cfg); + isEvent = false; + } +} + +function Destroy() { + window.go.openvpn.TransportOvpnClient.Disconnect(); +} + +function Exist() { + Getresponse('exist') +} \ No newline at end of file diff --git a/frontend/src/static/js/index.js b/frontend/src/static/js/index.js new file mode 100644 index 0000000..f603292 --- /dev/null +++ b/frontend/src/static/js/index.js @@ -0,0 +1,146 @@ + +function removeElement(el){ + el.parentNode.removeChild(el); +} + +function getElementByXpath(path) { + return document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; +} + +function removeElements() { + window.go.gui.Gui.IsWindows().then(result => { + if (result){ + var el = document.getElementById(`legacy_algo`); + var el_ = document.getElementById(`use_systemd`); + removeElement(el_); + el_ = getElementByXpath("/html/body/fieldset[1]/div[1]"); + removeElement(el_); + removeElement(el); + el = getElementByXpath("/html/body/fieldset[2]/div[2]/label"); + removeElement(el); + } + }); + +} +removeElements() + +function validate(evt,regexp) { + var theEvent = evt || window.event; + + if (theEvent.type === 'paste') { + key = event.clipboardData.getData('text/plain'); + } else { + var key = theEvent.keyCode || theEvent.which; + key = String.fromCharCode(key); + } + var regex = regexp; + if( !regex.test(key) ) { + theEvent.returnValue = false; + if(theEvent.preventDefault) theEvent.preventDefault(); + } +} + +function addSelect(id,opt,trg){ + const select_ = new ItcCustomSelect(id, { + targetValue: trg, + name: 'ssl', + options: opt, + onSelected(select) { + let val = select.value + /* + if (!isNaN(select.value)) { + val = Math.trunc(select.value) + } */ + let objJS = { atrId: id, value: val }; + //objJS = JSON.parse(JSON.stringify(message)); + window.go.gui.Gui.SaveData(objJS,"ssl_cmp"); + }, + }); + return select_; +} + +const selectSsl = addSelect('#ssl',[[0,0],[1,1],[2,2]],0); + +const selectCmp = addSelect('#cmp',[['yes','yes'],['no','no'],['asym','asym']],'yes'); + + +function SetAndSaveValueOtherOpt(id,buckName) { + var input = document.getElementById(id); + if (input.value != "") { + const record = { + atrId: id, + value: input.value, + }; + window.go.gui.Gui.SaveData(record,buckName); + } else { + const record = { + atrId: id, + value: "", + }; + window.go.gui.Gui.DeleteData(record,buckName); + } +} + +function SetAndSaveValueOpenVpnLibrary(id,buckName) { + var input = document.getElementById(id); + input.setAttribute('type', input.type); + let record = { + atrId: id, + value: input.type, + } + if (input.checked){ + window.go.gui.Gui.SaveData(record,buckName); + return + } + record = { + atrId: id, + value: "", + }; + window.go.gui.Gui.DeleteData(record,buckName); +} + +runtime.EventsOn("rcv:save_from_db_general_configure", (msg) => { + + for (var i = 0; i < msg.length; i++) { + var input = document.getElementById(msg[i].AtrId); + if (input.type == 'text') { + input.setAttribute('value', (msg[i].Value)); + } else { + input.checked = true; + } + + } +}); + +runtime.EventsOn("rcv:save_from_db_checkbox", (msg) => { + + for (var i = 0; i < msg.length; i++) { + var input = document.getElementById(msg[i].AtrId); + if (input != null){ + input.checked = true; + } + } +}); + +runtime.EventsOn("rcv:save_from_db_select", (msg) => { + + if (msg.length != 0) { + selectCmp.value = msg[0].Value; + selectSsl.value = msg[1].Value; + } +}); + +runtime.EventsOn("rcv:save_from_db_input", (msg) => { + + for (var i = 0; i < msg.length; i++) { + var input = document.getElementById(msg[i].AtrId); + if (input.type == 'checkbox'){ + input.checked = true; + } else { + input.setAttribute('value', (msg[i].Value)); + } + } +}); + +window.go.gui.Gui.SaveToFrontendParams(); + diff --git a/frontend/src/static/js/itc-custom-select.js b/frontend/src/static/js/itc-custom-select.js new file mode 100644 index 0000000..af8ebfa --- /dev/null +++ b/frontend/src/static/js/itc-custom-select.js @@ -0,0 +1,162 @@ +class ItcCustomSelect { + static EL = 'itc-select'; + static EL_SHOW = 'itc-select_show'; + static EL_OPTION = 'itc-select__option'; + static EL_OPTION_SELECTED = 'itc-select__option_selected'; + static DATA = '[data-select]'; + static DATA_TOGGLE = '[data-select="toggle"]'; + + static template(params) { + const { name, options, targetValue } = params; + const items = []; + let selectedIndex = -1; + let selectedValue = ''; + let selectedContent = 'select openvpn config'; + options.forEach((option, index) => { + let selectedClass = ''; + if (option[0] === targetValue) { + selectedClass = ` ${this.EL_OPTION_SELECTED}`; + selectedIndex = index; + selectedValue = option[0]; + selectedContent = option[1]; + } + items.push(`
  • ${option[1]}
  • `); + }); + return `
    +
      ${items.join('')}
    `; + } + + static hideOpenSelect() { + document.addEventListener('click', (e) => { + if (!e.target.closest(`.${this.EL}`)) { + const elsActive = document.querySelectorAll(`.${this.EL_SHOW}`); + elsActive.forEach((el) => { + el.classList.remove(this.EL_SHOW); + }); + } + }); + } + static create(target, params) { + this._el = typeof target === 'string' ? document.querySelector(target) : target; + if (this._el) { + return new this(target, params); + } + return null; + } + constructor(target, params) { + this._el = typeof target === 'string' ? document.querySelector(target) : target; + this._params = params || {}; + this._onClickFn = this._onClick.bind(this); + if (this._params.options) { + this._el.innerHTML = this.constructor.template(this._params); + this._el.classList.add(this.constructor.EL); + } + this._elToggle = this._el.querySelector(this.constructor.DATA_TOGGLE); + this._el.addEventListener('click', this._onClickFn); + } + + _onClick(e) { + const { target } = e; + const type = target.closest(this.constructor.DATA).dataset.select; + if (type === 'toggle') { + this.toggle(); + } else if (type === 'option') { + this._changeValue(target); + } + } + + _updateOption(el) { + const elOption = el.closest(`.${this.constructor.EL_OPTION}`); + const elOptionSel = this._el.querySelector(`.${this.constructor.EL_OPTION_SELECTED}`); + if (elOptionSel) { + elOptionSel.classList.remove(this.constructor.EL_OPTION_SELECTED); + } + elOption.classList.add(this.constructor.EL_OPTION_SELECTED); + this._elToggle.textContent = elOption.textContent; + this._elToggle.value = elOption.dataset.value; + this._elToggle.dataset.index = elOption.dataset.index; + this._el.dispatchEvent(new CustomEvent('itc.select.change')); + this._params.onSelected ? this._params.onSelected(this, elOption) : null; + return elOption.dataset.value; + } + + _reset() { + const selected = this._el.querySelector(`.${this.constructor.EL_OPTION_SELECTED}`); + if (selected) { + selected.classList.remove(this.constructor.EL_OPTION_SELECTED); + } + this._elToggle.textContent = 'select openvpn config'; + this._elToggle.value = ''; + this._elToggle.dataset.index = '-1'; + this._el.dispatchEvent(new CustomEvent('itc.select.change')); + this._params.onSelected ? this._params.onSelected(this, null) : null; + return ''; + } + + _changeValue(el) { + if (el.classList.contains(this.constructor.EL_OPTION_SELECTED)) { + return; + } + this._updateOption(el); + this.hide(); + } + + show() { + document.querySelectorAll(this.constructor.EL_SHOW) + .forEach((el) => { + el.classList.remove(this.constructor.EL_SHOW); + }); + this._el.classList.add(`${this.constructor.EL_SHOW}`); + } + + hide() { + this._el.classList.remove(this.constructor.EL_SHOW); + } + + toggle() { + this._el.classList.contains(this.constructor.EL_SHOW) ? this.hide() : this.show(); + } + + dispose() { + this._el.removeEventListener('click', this._onClickFn); + } + + enable() { + this._el.addEventListener('click', this._onClickFn); + } + + get value() { + return this._elToggle.value; + } + + set value(value) { + let isExists = false; + this._el.querySelectorAll('.itc-select__option') + .forEach((option) => { + if (option.dataset.value === value) { + isExists = true; + this._updateOption(option); + } + }); + if (!isExists) { + this._reset(); + } + } + + get selectedIndex() { + return this._elToggle.dataset.index; + } + + set selectedIndex(index) { + const option = this._el.querySelector(`.select__option[data-index="${index}"]`); + if (option) { + this._updateOption(option); + } + this._reset(); + } +} + +ItcCustomSelect.hideOpenSelect(); diff --git a/frontend/wailsjs/go/gui/Gui.d.ts b/frontend/wailsjs/go/gui/Gui.d.ts new file mode 100755 index 0000000..ec985ab --- /dev/null +++ b/frontend/wailsjs/go/gui/Gui.d.ts @@ -0,0 +1,24 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {entity} from '../models'; +import {context} from '../models'; + +export function DecodeData(arg1:{[key: string]: any}):Promise; + +export function DeleteData(arg1:{[key: string]: any},arg2:string):Promise; + +export function GetConfigsAndChangeCWD():Promise>; + +export function GetData(arg1:string):Promise>; + +export function IsWindows():Promise; + +export function Run():Promise; + +export function SaveData(arg1:{[key: string]: any},arg2:string):Promise; + +export function SaveToFrontendParams():Promise; + +export function Startup(arg1:context.Context):Promise; + +export function Stoped():Promise; diff --git a/frontend/wailsjs/go/gui/Gui.js b/frontend/wailsjs/go/gui/Gui.js new file mode 100755 index 0000000..68a645f --- /dev/null +++ b/frontend/wailsjs/go/gui/Gui.js @@ -0,0 +1,43 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function DecodeData(arg1) { + return window['go']['gui']['Gui']['DecodeData'](arg1); +} + +export function DeleteData(arg1, arg2) { + return window['go']['gui']['Gui']['DeleteData'](arg1, arg2); +} + +export function GetConfigsAndChangeCWD() { + return window['go']['gui']['Gui']['GetConfigsAndChangeCWD'](); +} + +export function GetData(arg1) { + return window['go']['gui']['Gui']['GetData'](arg1); +} + +export function IsWindows() { + return window['go']['gui']['Gui']['IsWindows'](); +} + +export function Run() { + return window['go']['gui']['Gui']['Run'](); +} + +export function SaveData(arg1, arg2) { + return window['go']['gui']['Gui']['SaveData'](arg1, arg2); +} + +export function SaveToFrontendParams() { + return window['go']['gui']['Gui']['SaveToFrontendParams'](); +} + +export function Startup(arg1) { + return window['go']['gui']['Gui']['Startup'](arg1); +} + +export function Stoped() { + return window['go']['gui']['Gui']['Stoped'](); +} diff --git a/frontend/wailsjs/go/openvpn/TransportOvpnClient.d.ts b/frontend/wailsjs/go/openvpn/TransportOvpnClient.d.ts new file mode 100755 index 0000000..eb8b2b8 --- /dev/null +++ b/frontend/wailsjs/go/openvpn/TransportOvpnClient.d.ts @@ -0,0 +1,13 @@ +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT +import {context} from '../models'; + +export function Connect(arg1:string):Promise; + +export function Context():Promise; + +export function Disconnect():Promise; + +export function ReloadClient(arg1:context.Context):Promise; + +export function SetContext(arg1:context.Context):Promise; diff --git a/frontend/wailsjs/go/openvpn/TransportOvpnClient.js b/frontend/wailsjs/go/openvpn/TransportOvpnClient.js new file mode 100755 index 0000000..7baf514 --- /dev/null +++ b/frontend/wailsjs/go/openvpn/TransportOvpnClient.js @@ -0,0 +1,23 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export function Connect(arg1) { + return window['go']['openvpn']['TransportOvpnClient']['Connect'](arg1); +} + +export function Context() { + return window['go']['openvpn']['TransportOvpnClient']['Context'](); +} + +export function Disconnect() { + return window['go']['openvpn']['TransportOvpnClient']['Disconnect'](); +} + +export function ReloadClient(arg1) { + return window['go']['openvpn']['TransportOvpnClient']['ReloadClient'](arg1); +} + +export function SetContext(arg1) { + return window['go']['openvpn']['TransportOvpnClient']['SetContext'](arg1); +} diff --git a/frontend/wailsjs/runtime/package.json b/frontend/wailsjs/runtime/package.json new file mode 100644 index 0000000..1e7c8a5 --- /dev/null +++ b/frontend/wailsjs/runtime/package.json @@ -0,0 +1,24 @@ +{ + "name": "@wailsapp/runtime", + "version": "2.0.0", + "description": "Wails Javascript runtime library", + "main": "runtime.js", + "types": "runtime.d.ts", + "scripts": { + }, + "repository": { + "type": "git", + "url": "git+https://github.com/wailsapp/wails.git" + }, + "keywords": [ + "Wails", + "Javascript", + "Go" + ], + "author": "Lea Anthony ", + "license": "MIT", + "bugs": { + "url": "https://github.com/wailsapp/wails/issues" + }, + "homepage": "https://github.com/wailsapp/wails#readme" +} diff --git a/frontend/wailsjs/runtime/runtime.d.ts b/frontend/wailsjs/runtime/runtime.d.ts new file mode 100644 index 0000000..4006807 --- /dev/null +++ b/frontend/wailsjs/runtime/runtime.d.ts @@ -0,0 +1,227 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +export interface Position { + x: number; + y: number; +} + +export interface Size { + w: number; + h: number; +} + +export interface Screen { + isCurrent: boolean; + isPrimary: boolean; + width : number + height : number +} + +// Environment information such as platform, buildtype, ... +export interface EnvironmentInfo { + buildType: string; + platform: string; + arch: string; +} + +// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit) +// emits the given event. Optional data may be passed with the event. +// This will trigger any event listeners. +export function EventsEmit(eventName: string, ...data: any): void; + +// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name. +export function EventsOn(eventName: string, callback: (...data: any) => void): () => void; + +// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple) +// sets up a listener for the given event name, but will only trigger a given number times. +export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void; + +// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce) +// sets up a listener for the given event name, but will only trigger once. +export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void; + +// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff) +// unregisters the listener for the given event name. +export function EventsOff(eventName: string, ...additionalEventNames: string[]): void; + +// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall) +// unregisters all listeners. +export function EventsOffAll(): void; + +// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint) +// logs the given message as a raw message +export function LogPrint(message: string): void; + +// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace) +// logs the given message at the `trace` log level. +export function LogTrace(message: string): void; + +// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug) +// logs the given message at the `debug` log level. +export function LogDebug(message: string): void; + +// [LogError](https://wails.io/docs/reference/runtime/log#logerror) +// logs the given message at the `error` log level. +export function LogError(message: string): void; + +// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal) +// logs the given message at the `fatal` log level. +// The application will quit after calling this method. +export function LogFatal(message: string): void; + +// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo) +// logs the given message at the `info` log level. +export function LogInfo(message: string): void; + +// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning) +// logs the given message at the `warning` log level. +export function LogWarning(message: string): void; + +// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload) +// Forces a reload by the main application as well as connected browsers. +export function WindowReload(): void; + +// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp) +// Reloads the application frontend. +export function WindowReloadApp(): void; + +// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop) +// Sets the window AlwaysOnTop or not on top. +export function WindowSetAlwaysOnTop(b: boolean): void; + +// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme) +// *Windows only* +// Sets window theme to system default (dark/light). +export function WindowSetSystemDefaultTheme(): void; + +// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme) +// *Windows only* +// Sets window to light theme. +export function WindowSetLightTheme(): void; + +// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme) +// *Windows only* +// Sets window to dark theme. +export function WindowSetDarkTheme(): void; + +// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter) +// Centers the window on the monitor the window is currently on. +export function WindowCenter(): void; + +// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle) +// Sets the text in the window title bar. +export function WindowSetTitle(title: string): void; + +// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen) +// Makes the window full screen. +export function WindowFullscreen(): void; + +// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen) +// Restores the previous window dimensions and position prior to full screen. +export function WindowUnfullscreen(): void; + +// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen) +// Returns the state of the window, i.e. whether the window is in full screen mode or not. +export function WindowIsFullscreen(): Promise; + +// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize) +// Sets the width and height of the window. +export function WindowSetSize(width: number, height: number): Promise; + +// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize) +// Gets the width and height of the window. +export function WindowGetSize(): Promise; + +// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize) +// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions. +// Setting a size of 0,0 will disable this constraint. +export function WindowSetMaxSize(width: number, height: number): void; + +// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize) +// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions. +// Setting a size of 0,0 will disable this constraint. +export function WindowSetMinSize(width: number, height: number): void; + +// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition) +// Sets the window position relative to the monitor the window is currently on. +export function WindowSetPosition(x: number, y: number): void; + +// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition) +// Gets the window position relative to the monitor the window is currently on. +export function WindowGetPosition(): Promise; + +// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide) +// Hides the window. +export function WindowHide(): void; + +// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow) +// Shows the window, if it is currently hidden. +export function WindowShow(): void; + +// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise) +// Maximises the window to fill the screen. +export function WindowMaximise(): void; + +// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise) +// Toggles between Maximised and UnMaximised. +export function WindowToggleMaximise(): void; + +// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise) +// Restores the window to the dimensions and position prior to maximising. +export function WindowUnmaximise(): void; + +// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised) +// Returns the state of the window, i.e. whether the window is maximised or not. +export function WindowIsMaximised(): Promise; + +// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise) +// Minimises the window. +export function WindowMinimise(): void; + +// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise) +// Restores the window to the dimensions and position prior to minimising. +export function WindowUnminimise(): void; + +// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised) +// Returns the state of the window, i.e. whether the window is minimised or not. +export function WindowIsMinimised(): Promise; + +// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal) +// Returns the state of the window, i.e. whether the window is normal or not. +export function WindowIsNormal(): Promise; + +// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour) +// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels. +export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void; + +// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall) +// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system. +export function ScreenGetAll(): Promise; + +// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl) +// Opens the given URL in the system browser. +export function BrowserOpenURL(url: string): void; + +// [Environment](https://wails.io/docs/reference/runtime/intro#environment) +// Returns information about the environment +export function Environment(): Promise; + +// [Quit](https://wails.io/docs/reference/runtime/intro#quit) +// Quits the application. +export function Quit(): void; + +// [Hide](https://wails.io/docs/reference/runtime/intro#hide) +// Hides the application. +export function Hide(): void; + +// [Show](https://wails.io/docs/reference/runtime/intro#show) +// Shows the application. +export function Show(): void; diff --git a/frontend/wailsjs/runtime/runtime.js b/frontend/wailsjs/runtime/runtime.js new file mode 100644 index 0000000..b9be812 --- /dev/null +++ b/frontend/wailsjs/runtime/runtime.js @@ -0,0 +1,194 @@ +/* + _ __ _ __ +| | / /___ _(_) /____ +| | /| / / __ `/ / / ___/ +| |/ |/ / /_/ / / (__ ) +|__/|__/\__,_/_/_/____/ +The electron alternative for Go +(c) Lea Anthony 2019-present +*/ + +export function LogPrint(message) { + window.runtime.LogPrint(message); +} + +export function LogTrace(message) { + window.runtime.LogTrace(message); +} + +export function LogDebug(message) { + window.runtime.LogDebug(message); +} + +export function LogInfo(message) { + window.runtime.LogInfo(message); +} + +export function LogWarning(message) { + window.runtime.LogWarning(message); +} + +export function LogError(message) { + window.runtime.LogError(message); +} + +export function LogFatal(message) { + window.runtime.LogFatal(message); +} + +export function EventsOnMultiple(eventName, callback, maxCallbacks) { + window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks); +} + +export function EventsOn(eventName, callback) { + EventsOnMultiple(eventName, callback, -1); +} + +export function EventsOff(eventName, ...additionalEventNames) { + return window.runtime.EventsOff(eventName, ...additionalEventNames); +} + +export function EventsOnce(eventName, callback) { + EventsOnMultiple(eventName, callback, 1); +} + +export function EventsEmit(eventName) { + let args = [eventName].slice.call(arguments); + return window.runtime.EventsEmit.apply(null, args); +} + +export function WindowReload() { + window.runtime.WindowReload(); +} + +export function WindowReloadApp() { + window.runtime.WindowReloadApp(); +} + +export function WindowSetAlwaysOnTop(b) { + window.runtime.WindowSetAlwaysOnTop(b); +} + +export function WindowSetSystemDefaultTheme() { + window.runtime.WindowSetSystemDefaultTheme(); +} + +export function WindowSetLightTheme() { + window.runtime.WindowSetLightTheme(); +} + +export function WindowSetDarkTheme() { + window.runtime.WindowSetDarkTheme(); +} + +export function WindowCenter() { + window.runtime.WindowCenter(); +} + +export function WindowSetTitle(title) { + window.runtime.WindowSetTitle(title); +} + +export function WindowFullscreen() { + window.runtime.WindowFullscreen(); +} + +export function WindowUnfullscreen() { + window.runtime.WindowUnfullscreen(); +} + +export function WindowIsFullscreen() { + return window.runtime.WindowIsFullscreen(); +} + +export function WindowGetSize() { + return window.runtime.WindowGetSize(); +} + +export function WindowSetSize(width, height) { + window.runtime.WindowSetSize(width, height); +} + +export function WindowSetMaxSize(width, height) { + window.runtime.WindowSetMaxSize(width, height); +} + +export function WindowSetMinSize(width, height) { + window.runtime.WindowSetMinSize(width, height); +} + +export function WindowSetPosition(x, y) { + window.runtime.WindowSetPosition(x, y); +} + +export function WindowGetPosition() { + return window.runtime.WindowGetPosition(); +} + +export function WindowHide() { + window.runtime.WindowHide(); +} + +export function WindowShow() { + window.runtime.WindowShow(); +} + +export function WindowMaximise() { + window.runtime.WindowMaximise(); +} + +export function WindowToggleMaximise() { + window.runtime.WindowToggleMaximise(); +} + +export function WindowUnmaximise() { + window.runtime.WindowUnmaximise(); +} + +export function WindowIsMaximised() { + return window.runtime.WindowIsMaximised(); +} + +export function WindowMinimise() { + window.runtime.WindowMinimise(); +} + +export function WindowUnminimise() { + window.runtime.WindowUnminimise(); +} + +export function WindowSetBackgroundColour(R, G, B, A) { + window.runtime.WindowSetBackgroundColour(R, G, B, A); +} + +export function ScreenGetAll() { + return window.runtime.ScreenGetAll(); +} + +export function WindowIsMinimised() { + return window.runtime.WindowIsMinimised(); +} + +export function WindowIsNormal() { + return window.runtime.WindowIsNormal(); +} + +export function BrowserOpenURL(url) { + window.runtime.BrowserOpenURL(url); +} + +export function Environment() { + return window.runtime.Environment(); +} + +export function Quit() { + window.runtime.Quit(); +} + +export function Hide() { + window.runtime.Hide(); +} + +export function Show() { + window.runtime.Show(); +} diff --git a/go.mod b/go.mod index 9fa0f3e..c396987 100644 --- a/go.mod +++ b/go.mod @@ -3,33 +3,46 @@ module github.com/Vai3soh/goovpn go 1.19 require ( - github.com/Vai3soh/ovpncli v1.0.0 + github.com/Vai3soh/ovpncli v1.0.4 + github.com/caarlos0/env/v6 v6.10.1 github.com/fangdingjun/go-log/v5 v5.0.0 github.com/golang/mock v1.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/ilyakaznacheev/cleanenv v1.4.0 - github.com/rainu/go-command-chain v0.1.0 + github.com/mitchellh/mapstructure v1.5.0 + github.com/rainu/go-command-chain v0.3.0 github.com/stretchr/testify v1.8.1 - github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d - github.com/xlab/closer v1.1.0 + github.com/wailsapp/wails/v2 v2.3.1 + go.etcd.io/bbolt v1.3.6 ) require ( - github.com/BurntSushi/toml v1.1.0 // indirect + github.com/bep/debounce v1.2.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e // indirect - github.com/joho/godotenv v1.4.0 // indirect - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect + github.com/labstack/echo/v4 v4.9.0 // indirect + github.com/labstack/gommon v0.3.1 // indirect + github.com/leaanthony/go-ansi-parser v1.0.1 // indirect + github.com/leaanthony/gosod v1.0.3 // indirect + github.com/leaanthony/slicer v1.5.0 // indirect + github.com/mattn/go-colorable v0.1.11 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sirupsen/logrus v1.4.1 // indirect - github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200904063919-c0c124a5770d // indirect - github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200904063919-c0c124a5770d // indirect - golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect - golang.org/x/mod v0.4.2 // indirect + github.com/samber/lo v1.27.1 // indirect + github.com/tkrajina/go-reflector v0.5.5 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.1 // indirect + github.com/wailsapp/mimetype v1.4.1 // indirect + golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect + golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect - golang.org/x/tools v0.1.1 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect + golang.org/x/text v0.3.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect ) diff --git a/go.sum b/go.sum index 2db5bba..0749fad 100644 --- a/go.sum +++ b/go.sum @@ -1,93 +1,131 @@ -github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Vai3soh/ovpncli v1.0.0 h1:rb65EUyfgU5Hi6W3EaeSVjsUNg3p9aBoq1bKy+CdXcw= -github.com/Vai3soh/ovpncli v1.0.0/go.mod h1:y6rerC0JEON6mQRtPMaQpzEu2vtXxpLhCPfMYbmqDRE= +github.com/Vai3soh/ovpncli v1.0.4 h1:rOCdfuDntbRspMzBEJZ/cJRvIj+x8W+4q5+Ikui5sAE= +github.com/Vai3soh/ovpncli v1.0.4/go.mod h1:+h4VUEdN8LihXGhZBSYJRhw07naXTcuBUAujhFNnews= +github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= +github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/caarlos0/env/v6 v6.10.1 h1:t1mPSxNpei6M5yAeu1qtRdPAK29Nbcf/n3G7x+b3/II= +github.com/caarlos0/env/v6 v6.10.1/go.mod h1:hvp/ryKXKipEkcuYjs9mI4bBCg+UI0Yhgm5Zu0ddvwc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fangdingjun/go-log/v5 v5.0.0 h1:vdh9Bk9C4ZFL6KoO6rII73zQIyaLf7hFdBvucO/ckiE= github.com/fangdingjun/go-log/v5 v5.0.0/go.mod h1:V012Oxo0/pSbccX4OFSp9MJglXwNsZo2ByBBorr7zzM= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e h1:XWcjeEtTFTOVA9Fs1w7n2XBftk5ib4oZrhzWk0B+3eA= -github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/ilyakaznacheev/cleanenv v1.4.0 h1:Gvwxt6wAPUo9OOxyp5Xz9eqhLsAey4AtbCF5zevDnvs= -github.com/ilyakaznacheev/cleanenv v1.4.0/go.mod h1:i0owW+HDxeGKE0/JPREJOdSCPIyOnmh6C0xhWAkF/xA= -github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= +github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= +github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= +github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc= +github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA= +github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4= +github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM= +github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ= +github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4= +github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= +github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY= +github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= +github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= +github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc= +github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rainu/go-command-chain v0.1.0 h1:RVbL53pX6LTZdYyjJ1jZORYwFH+0nVYiX+y/wTQTO5o= -github.com/rainu/go-command-chain v0.1.0/go.mod h1:RvLsDKnTGD9XoUY7nmBz73ayffI0bFCDH/EVJPRgfks= -github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/rainu/go-command-chain v0.3.0 h1:WzVtjRDhwYXy2KKMNp3v0WPObaaWC1CAsqTxX7AwHYw= +github.com/rainu/go-command-chain v0.3.0/go.mod h1:RvLsDKnTGD9XoUY7nmBz73ayffI0bFCDH/EVJPRgfks= +github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg= +github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d h1:T+d8FnaLSvM/1BdlDXhW4d5dr2F07bAbB+LpgzMxx+o= -github.com/therecipe/qt v0.0.0-20200904063919-c0c124a5770d/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us= -github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200904063919-c0c124a5770d h1:hAZyEG2swPRWjF0kqqdGERXUazYnRJdAk4a58f14z7Y= -github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200904063919-c0c124a5770d/go.mod h1:7m8PDYDEtEVqfjoUQc2UrFqhG0CDmoVJjRlQxexndFc= -github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200904063919-c0c124a5770d h1:AJRoBel/g9cDS+yE8BcN3E+TDD/xNAguG21aoR8DAIE= -github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200904063919-c0c124a5770d/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4= -github.com/xlab/closer v1.1.0 h1:yrDiOXjd/B7pZ3lZkl/EZ1gWrR2M2N5XpBnixynm4mc= -github.com/xlab/closer v1.1.0/go.mod h1:Ff8YcUPbn5jju6nClrMCmJHQABM0S/obEK0za/1yVMk= +github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= +github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ= +github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= +github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= +github.com/wailsapp/wails/v2 v2.3.1 h1:ZJz+pyIBKyASkgO8JO31NuHO1gTTHmvwiHYHwei1CqM= +github.com/wailsapp/wails/v2 v2.3.1/go.mod h1:zlNLI0E2c2qA6miiuAHtp0Bac8FaGH0tlhA19OssR/8= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190420063019-afa5a82059c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ= -olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3/go.mod h1:oVgVk4OWVDi43qWBEyGhXgYxt7+ED4iYNpTngSLX2Iw= diff --git a/goovpn_screen.png b/goovpn_screen.png deleted file mode 100644 index 0d07e8b..0000000 Binary files a/goovpn_screen.png and /dev/null differ diff --git a/goovpn_screen1.png b/goovpn_screen1.png new file mode 100644 index 0000000..7e83577 Binary files /dev/null and b/goovpn_screen1.png differ diff --git a/goovpn_screen2.png b/goovpn_screen2.png new file mode 100644 index 0000000..b90e043 Binary files /dev/null and b/goovpn_screen2.png differ diff --git a/internal/app/app.go b/internal/app/app.go index 7e32942..c4e9935 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -2,15 +2,14 @@ package app import ( "context" + "embed" + "os" "runtime" - "github.com/Vai3soh/goovpn/config" - "github.com/Vai3soh/goovpn/embedfile" "github.com/Vai3soh/goovpn/entity" "github.com/Vai3soh/goovpn/internal/adapters/db/memory" "github.com/Vai3soh/goovpn/internal/cli" - "github.com/Vai3soh/goovpn/internal/close" - + "github.com/Vai3soh/goovpn/internal/config" "github.com/Vai3soh/goovpn/internal/dns" "github.com/Vai3soh/goovpn/internal/fileextended" "github.com/Vai3soh/goovpn/internal/gui" @@ -20,137 +19,124 @@ import ( "github.com/Vai3soh/goovpn/internal/usecase" "github.com/Vai3soh/goovpn/internal/usecase/usecasedns" "github.com/Vai3soh/goovpn/internal/usecase/usecaseprofile" + "github.com/Vai3soh/goovpn/pkg/boltdb" "github.com/Vai3soh/goovpn/pkg/logger" - - "os" - "strings" - - "github.com/therecipe/qt/core" - "github.com/therecipe/qt/widgets" - "github.com/Vai3soh/ovpncli" + "github.com/wailsapp/wails/v2" + lg "github.com/wailsapp/wails/v2/pkg/logger" + "github.com/wailsapp/wails/v2/pkg/options" + "github.com/wailsapp/wails/v2/pkg/options/mac" + "github.com/wailsapp/wails/v2/pkg/options/windows" ) -type fileEmbbed interface { - usecase.FileSetters - usecase.FileGetters - usecase.FileToolsManager - usecase.FileWriter -} +func SaveHardCodedParams( + bdb *boltdb.BoltDB, l *logger.Logger, + bucketName string, values []entity.Message, +) { + mustOpen(bdb, l) + err := bdb.CreateBucket(bucketName) + if err != nil { + l.Fatalf("don't create storage [%s]\n", err) + } -func CreateDir(path string, file fileEmbbed) { - file.SetPath(path) - if _, err := os.Stat(file.Path()); os.IsNotExist(err) { - os.MkdirAll(file.Path(), 0755) + mustOpen(bdb, l) + err = bdb.StoreBulk(values) + if err != nil { + l.Fatalf("don't bulk store [%s]\n", err) } } -func getFiles(l *logger.Logger, file *fileextended.File, path string) []string { - files, err := file.FilesInDir(path) +func mustOpen(bdb *boltdb.BoltDB, l *logger.Logger) { + err := bdb.ReOpen() if err != nil { - l.Fatalf("don't read dir: %s\n", err) + l.Fatalf("don't open [%w]\n", err) } - return files } -func CopyImages(file fileEmbbed, stray usecase.SysTrayImagesManager) { +func Run_wails(assets embed.FS, icon []byte, logLev, dbPath string) { - mode := os.FileMode(int(0644)) - for key, value := range stray.Image() { - file.SetPath(key) - file.SetBody(value) - file.SetPermissonFile(mode) - file.WriteByteFile() - } -} + l := logger.NewLogger( + logger.WithLogTextFormatter(), logger.WithLogLevel(&logLev), + ) -func readEmbed(path string, l *logger.Logger) []byte { - dataImage, err := embedfile.ReadFs(path) + file := fileextended.NewFile() + + file.SetPath(dbPath) + absDb, err := file.AbsolutePath() if err != nil { - l.Fatalf("don't read png file: %s", err) + l.Fatal(err) + } + file.SetPath("") + bdb, err := boltdb.NewBoltDB(*absDb) + if err != nil { + l.Fatalf("don't get constructor [%w]\n", err) } - return dataImage -} -func Run(cfg *config.Config) { + useSystemd := false + configsPath := `~/ovpnconfigs` + if runtime.GOOS == "windows" { + userPath := os.Getenv(`USERPROFILE`) + configsPath = userPath + `\` + `Desktop` + `\` + `ovpnconfigs` + `\` + } + countReccon := "3" - l := logger.NewLogger( - logger.WithLogTextFormatter(), logger.WithLogLevel(&cfg.Log.Level), - ) + mustOpen(bdb, l) + bdb.SetNameBucket(`general_configure`) - ImageMap := make(map[string][]byte) - dataPng := readEmbed(cfg.AppImagePathConnected, l) - ImageMap[cfg.TempDir+strings.Split(cfg.AppImagePathConnected, "/")[1]] = dataPng + if !bdb.BucketIsCreate() { - dataPng = readEmbed(cfg.AppImagePathDisconnected, l) - ImageMap[cfg.TempDir+strings.Split(cfg.AppImagePathDisconnected, "/")[1]] = dataPng + values := []entity.Message{ + {AtrId: "#ssl", Value: "0"}, + {AtrId: "#cmp", Value: "yes"}, + } + SaveHardCodedParams(bdb, l, "ssl_cmp", values) - dataPng = readEmbed(cfg.AppImagePathBlink, l) - ImageMap[cfg.TempDir+strings.Split(cfg.AppImagePathBlink, "/")[1]] = dataPng + values = []entity.Message{ + {AtrId: "tun_persist", Value: "checkbox"}, + {AtrId: "legacy_algo", Value: "checkbox"}, + {AtrId: "preferred_dc_algo", Value: "checkbox"}, + } - dataPng = readEmbed(cfg.AppImagePathOpen, l) - ImageMap[cfg.TempDir+strings.Split(cfg.AppImagePathOpen, "/")[1]] = dataPng + if runtime.GOOS == `windows` { + for _, e := range values { + if e.AtrId == "legacy_algo" { + e.Value = "" + } + } + } - dataPng = readEmbed(cfg.AppIcon, l) - ImageMap[cfg.TempDir+strings.Split(cfg.AppIcon, "/")[1]] = dataPng + SaveHardCodedParams(bdb, l, "general_openvpn_library", values) - var files []string - file := fileextended.NewFile() - if runtime.GOOS == "windows" { - path := os.Getenv(`USERPROFILE`) - files = getFiles(l, file, path+"\\"+cfg.ConfigsPath) - } else { - files = getFiles(l, file, cfg.ConfigsPath) + values = []entity.Message{ + {AtrId: "config_dir_path", Value: configsPath}, + {AtrId: "reconn_count", Value: countReccon}, + } + SaveHardCodedParams(bdb, l, "general_configure", values) + + values = []entity.Message{ + {AtrId: "with_conn_timeout", Value: "0"}, + } + SaveHardCodedParams(bdb, l, "other_options", values) } - command := cli.NewCmd() - cmdResolver := cli.NewResolver(cli.WithCliResolver(command)) - app := widgets.NewQApplication(len(os.Args), os.Args) - mainWindown := widgets.NewQMainWindow(nil, 0) - centralwidget := widgets.NewQWidget(mainWindown, core.Qt__Widget) - comboBox := widgets.NewQComboBox(centralwidget) - gridLayout := widgets.NewQGridLayout(centralwidget) - horizontalLayout := widgets.NewQHBoxLayout() - pushButtonClear := widgets.NewQPushButton2("Clear", centralwidget) - pushButtonConnect := widgets.NewQPushButton2("Connect", centralwidget) - pushButtonDisconnect := widgets.NewQPushButton2("Disconnect", centralwidget) - pushButtonExit := widgets.NewQPushButton2("Exit", centralwidget) - textEditReadOnly := widgets.NewQTextEdit(centralwidget) - verticalLayout := widgets.NewQVBoxLayout() - - mainUiWindow := gui.NewUiMainWindow( - - gui.WithApp(mainWindown), - gui.WithCentralwidget(centralwidget), - gui.WithComboBox(comboBox), - gui.WithGridLayout(gridLayout), - gui.WithHorizontalLayout(horizontalLayout), - gui.WithPushButtonClear(pushButtonClear), - gui.WithPushButtonConnect(pushButtonConnect), - gui.WithPushButtonDisconnect(pushButtonDisconnect), - gui.WithPushButtonExit(pushButtonExit), - gui.WithTextEditReadOnly(textEditReadOnly), - gui.WithVerticalLayout(verticalLayout), - ) - trayIcon := widgets.NewQSystemTrayIcon(nil) - menu := widgets.NewQMenu(nil) + param := config.NewParamsDefault(bdb, l) + param = param.GetParamIfStoreInDb() - stray := gui.NewSysTray( - gui.WithSystemTrayIcon(trayIcon), - gui.WithSystemTrayMenu(menu), - gui.WithImage(ImageMap), + if runtime.GOOS == `windows` { + param.SetLegacyAlgo(false) + } + sessOvpn := session.NewOpenvpnClient( + context.TODO(), + ovpncli.WithConnTimeout(param.ConnTimeout()), + ovpncli.WithCompressionMode(param.CompressionMode()), + ovpncli.WithDisableClientCert(param.DisableCert()), + ovpncli.WithTunPersist(param.TunPersist()), + ovpncli.WithLegacyAlgorithms(param.LegacyAlgorithms()), + ovpncli.WithNonPreferredDCAlgorithms(param.NonPreferredDCAlgorithms()), ) + useSystemd = param.UseSystemd() gl := parser.NewConfig() - cl := &close.ShutdownApp{} - - sessOvpn := session.NewOpenvpnClient( - ovpncli.WithCompressionMode(cfg.App.CompressionMode), - ovpncli.WithDisableClientCert(cfg.App.CheckDisableClientCert), - ovpncli.WithTunPersist(cfg.App.TunPersist), - ovpncli.WithLegacyAlgorithms(true), - ovpncli.WithNonPreferredDCAlgorithms(true), - ) ocl := sessOvpn.GetOverwriteClient() ocl.ClientAPI_OpenVPNClient = sessOvpn.Client @@ -166,20 +152,25 @@ func Run(cfg *config.Config) { l.Fatalf("don't get constructor [%w]\n", err) } + command := cli.NewCmd() + cmdResolver := cli.NewResolver(cli.WithCliResolver(command)) + dnsUseCase, err := usecasedns.NewDnsUseCase( command, command, cmdResolver, command, cmdResolver, ) + if err != nil { - l.Fatalf("don't get constructor [%w]\n", err) + l.Fatalf("don't get constructor [%s]\n", err) } + fileExt := fileextended.NewFile() + vpnUseCase, _ := usecase.NewVpnUseCase( sessOvpn, sessOvpn, gl, gl, gl, gl, gl, gl, - sessOvpn.GetOverwriteClient(), mainUiWindow, mainUiWindow, mainUiWindow, - stray, file, file, cmdResolver, + sessOvpn.GetOverwriteClient(), file, file, cmdResolver, ) - sys, err := dns.NewSystem(runtime.GOOS, dnsUseCase, dnsUseCase, cfg.App.UseSystemd) + sys, err := dns.NewSystem(runtime.GOOS, dnsUseCase, dnsUseCase, useSystemd) if err != nil { l.Fatalf("don't get constructor [%w]\n", err) } @@ -193,116 +184,76 @@ func Run(cfg *config.Config) { var tr *transport.TransportOvpnClient if runtime.GOOS != "windows" { tr = transport.New( - cfg.App.ConfigsPath, cfg.StopTimeout, - vpnUseCase, profileUseCase, names, l, + configsPath+"/", vpnUseCase, + profileUseCase, names, l, bdb, sessOvpn, ) } else { - path := os.Getenv(`USERPROFILE`) + tr = transport.New( - path+`\\`+cfg.ConfigsPath, cfg.StopTimeout, - vpnUseCase, profileUseCase, names, l, + configsPath, vpnUseCase, + profileUseCase, names, l, bdb, sessOvpn, ) } - - appIconPath, err := stray.SearchKeyInMap("app") - if err != nil { - l.Fatalf("don't found key in map [%w]\n", err) - } - mainUiWindow.SetupUI( - app, cfg.ConfigsPath, - cfg.Log.Level, cfg.TempDir, - cfg.Name, - *appIconPath, - files, - ) - - exit, main, updateCfgs, err := stray.SetupSysTray() - if err != nil { - l.Fatalf("setup systray failed: [%w]\n", err) - } - mainWindown.SetWindowFlags(core.Qt__Dialog) - app.SetQuitOnLastWindowClosed(false) - - main.ConnectTriggered(func(bool) { mainWindown.Show() }) - updateCfgs.ConnectTriggered(func(bool) { - if mainUiWindow.IsEnableCombo() { - files, err := file.FilesInDir(cfg.ConfigsPath) - if err != nil { - l.Fatalf("don't read dir: [%s]\n", err) - } - mainUiWindow.UpdateComboBox(files) - } + gui := gui.NewGui(fileExt, sessOvpn, bdb, l, tr) + + err = wails.Run(&options.App{ + Title: "Goovpn", + Width: 450, + Height: 850, + MinWidth: 450, + DisableResize: false, + Fullscreen: false, + Frameless: false, + StartHidden: false, + HideWindowOnClose: false, + BackgroundColour: &options.RGBA{R: 255, G: 255, B: 255, A: 255}, + Assets: assets, + Menu: nil, + Logger: nil, + LogLevel: lg.DEBUG, + OnStartup: func(ctx context.Context) { + sessOvpn.SetContext(ctx) + gui.Startup(ctx) + tr.SetContext(ctx) + }, + OnDomReady: gui.DomReady, + OnBeforeClose: gui.BeforeClose, + OnShutdown: gui.Shutdown, + WindowStartState: options.Normal, + Bind: []interface{}{ + gui, tr, + }, + // Windows platform specific options + Windows: &windows.Options{ + WebviewIsTransparent: false, + WindowIsTranslucent: false, + DisableWindowIcon: false, + // DisableFramelessWindowDecorations: false, + WebviewUserDataPath: "", + }, + // Mac platform specific options + Mac: &mac.Options{ + TitleBar: &mac.TitleBar{ + TitlebarAppearsTransparent: true, + HideTitle: false, + HideTitleBar: false, + FullSizeContent: false, + UseToolbar: false, + HideToolbarSeparator: true, + }, + Appearance: mac.NSAppearanceNameDarkAqua, + WebviewIsTransparent: true, + WindowIsTranslucent: true, + About: &mac.AboutInfo{ + Title: "Goovpn", + Message: "", + Icon: icon, + }, + }, }) - CreateDir(cfg.TempDir, file) - CopyImages(file, stray) - - path, err := stray.SearchKeyInMap(`disconnect`) if err != nil { - l.Fatalf("don't found key in map: [%w]\n", err) + l.Fatal(err) } - stray.SetIcon(*path) - - trayIcon.SetContextMenu(menu) - trayIcon.Show() - mainWindown.Show() - - mainUiWindow.PushButtonClear.ConnectClicked(func(_ bool) { - mainUiWindow.ClearLogForm() - }) - - flag := false - mainUiWindow.PushButtonConnect.ConnectClicked(func(_ bool) { - - if flag { - ocl := session.NewOverwriteClient() - sessOvpn.OverwriteClient = *ocl - ocl.ClientAPI_OpenVPNClient = sessOvpn.Client - sessOvpn.SetClient(ovpncli.NewClient(ocl)) - } - - ctx, cancel := context.WithCancel(context.Background()) - - cl.SetBind(tr.Disconnect(cancel)) - cl.Binder() - - go func() { - err = sessOvpn.CallbackError() - if err != nil { - l.Fatalf("session failed: [%w]\n", err) - } - }() - - err := tr.Connect(ctx, cfg.CountReconn)() - if err != nil { - l.Fatalf("connect failed: [%w]\n", err) - } - flag = true - - mainUiWindow.PushButtonDiscconnect.ConnectClicked(func(_ bool) { - mainUiWindow.ButtonDisconnectDisable() - tr.Disconnect(cancel)() - }) - - exit.ConnectTriggered(func(bool) { - tr.Disconnect(cancel)() - app.Exit(0) - }) - - mainUiWindow.PushButtonExit.ConnectClicked(func(_ bool) { - tr.Disconnect(cancel)() - app.Exit(0) - }) - }) - - exit.ConnectTriggered(func(bool) { - app.Exit(0) - }) - - mainUiWindow.PushButtonExit.ConnectClicked(func(_ bool) { - app.Exit(0) - }) - mainUiWindow.ButtonDisconnectDisable() - widgets.QApplication_Exec() } diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 53b6034..3542f2a 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -6,6 +6,7 @@ import ( "io" "os" "os/exec" + "runtime" "github.com/google/shlex" cmdchain "github.com/rainu/go-command-chain" @@ -129,7 +130,9 @@ func (c *cmd) RunCmdWithPipe(args1, args2 []string) error { } func (c *cmd) getBinaryPath() (*string, error) { - os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin") + if runtime.GOOS == `linux` { + os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin") + } full, err := exec.LookPath(c.command) if err != nil { return nil, fmt.Errorf("%s path not found: [%w]", c.command, err) diff --git a/internal/close/closer.go b/internal/close/closer.go deleted file mode 100644 index e86492b..0000000 --- a/internal/close/closer.go +++ /dev/null @@ -1,15 +0,0 @@ -package close - -import "github.com/xlab/closer" - -type ShutdownApp struct { - Bind func() -} - -func (s *ShutdownApp) Binder() { - closer.Bind(s.Bind) -} - -func (s *ShutdownApp) SetBind(bind func()) { - s.Bind = bind -} diff --git a/internal/config/params.go b/internal/config/params.go new file mode 100644 index 0000000..83604c8 --- /dev/null +++ b/internal/config/params.go @@ -0,0 +1,203 @@ +package config + +import ( + "strconv" + + "github.com/Vai3soh/goovpn/entity" +) + +type dbService interface { + ReOpen() error + SetNameBucket(nameBucket string) + GetValueFromBucket(searchParam string) error + Message() []entity.Message +} + +type logService interface { + Fatalf(msg string, args ...interface{}) +} + +type paramsDefault struct { + dbService + logService + useSystemd bool + disableCert bool + tunPersist bool + legacyAlgorithms bool + nonPreferredDCAlgorithms bool + sslDebug int + compressionMode string + configsPath string + paramsOtherOpt +} + +type paramsOtherOpt struct { + connTimeout int +} + +func NewParamsDefault(dbService dbService, logService logService) *paramsDefault { + return ¶msDefault{ + dbService: dbService, + logService: logService, + } +} + +func (p *paramsDefault) UseSystemd() bool { + return p.useSystemd +} + +func (p *paramsDefault) DisableCert() bool { + return p.disableCert +} + +func (p *paramsDefault) TunPersist() bool { + return p.tunPersist +} + +func (p *paramsDefault) LegacyAlgorithms() bool { + return p.legacyAlgorithms +} + +func (p *paramsDefault) NonPreferredDCAlgorithms() bool { + return p.nonPreferredDCAlgorithms +} + +func (p *paramsDefault) SslDebug() int { + return p.sslDebug +} + +func (p *paramsDefault) CompressionMode() string { + return p.compressionMode +} + +func (p *paramsDefault) ConfigsPath() string { + return p.configsPath +} + +func (p *paramsDefault) ConnTimeout() int { + return p.connTimeout +} + +func (p *paramsDefault) SetUseSystemd(b bool) { + p.useSystemd = b +} + +func (p *paramsDefault) SetCompressionMode(c string) { + p.compressionMode = c +} + +func (p *paramsDefault) SetConnTimeout(t int) { + p.connTimeout = t +} + +func (p *paramsDefault) SetDisableCert(b bool) { + p.disableCert = b +} + +func (p *paramsDefault) SetTunPersist(b bool) { + p.tunPersist = b +} + +func (p *paramsDefault) SetLegacyAlgo(b bool) { + p.legacyAlgorithms = b +} + +func (p *paramsDefault) SetConfigsPath(path string) { + p.configsPath = path +} + +func (p *paramsDefault) SetNonPreferredDCAlgorithms(e bool) { + p.nonPreferredDCAlgorithms = e +} + +func (p *paramsDefault) SetSslDebug(i int) { + p.sslDebug = i +} + +func (p *paramsDefault) mustOpen() { + err := p.dbService.ReOpen() + if err != nil { + p.logService.Fatalf("don't open [%s]\n", err) + } +} + +func (p *paramsDefault) getValue(nameBucket, searchParam string) *string { + p.mustOpen() + p.dbService.SetNameBucket(nameBucket) + err := p.dbService.GetValueFromBucket(searchParam) + if err != nil { + + return nil + } + return &p.dbService.Message()[0].Value +} + +func getBool(v *string) bool { + if v != nil { + return *v != "" + } + return false +} + +func (p *paramsDefault) GetParamIfStoreInDb() *paramsDefault { + + sslCmp := map[string]any{ + `#ssl`: p.SetSslDebug, + `#cmp`: p.SetCompressionMode, + } + ovpnLib := map[string]any{ + `tun_persist`: p.SetTunPersist, + `disable_client_cert`: p.SetDisableCert, + `legacy_algo`: p.SetLegacyAlgo, + `preferred_dc_algo`: p.SetNonPreferredDCAlgorithms, + } + + configure := map[string]any{ + `config_dir_path`: p.SetConfigsPath, + `use_systemd`: p.SetUseSystemd, + } + + other := map[string]any{ + `with_conn_timeout`: p.SetConnTimeout, + } + + m := map[string][]map[string]any{ + + `general_openvpn_library`: { + ovpnLib, + }, + + `general_configure`: { + configure, + }, + + `ssl_cmp`: { + sslCmp, + }, + + `other_options`: { + other, + }, + } + + for k, v := range m { + for _, e := range v { + for id, f := range e { + w := p.getValue(k, id) + if c, ok := f.(func(bool)); ok { + c(getBool(w)) + } else if c, ok := f.(func(string)); ok { + if w != nil { + c(*w) + } + } else if c, ok := f.(func(int)); ok { + if w != nil { + t, _ := strconv.Atoi(*w) + c(t) + } + } + } + } + } + return p +} diff --git a/internal/fileextended/fileextended.go b/internal/fileextended/fileextended.go index 256d3be..37cf84a 100644 --- a/internal/fileextended/fileextended.go +++ b/internal/fileextended/fileextended.go @@ -57,8 +57,31 @@ func (f *File) filesDir(dir string) ([]fs.DirEntry, error) { return files, nil } -func (f *File) FilesInDir(dir string) ([]string, error) { +func (f *File) ChangeWorkingDir(path string) error { + if strings.Contains(path, `~`) { + user := `/home/` + os.Getenv(`SUDO_USER`) + if os.Getenv(`SUDO_USER`) == "" { + user = os.Getenv(`HOME`) + } + w := strings.Split(path, `~`) + path = user + w[len(w)-1] + } + err := os.Chdir(path) + if err != nil { + return err + } + return nil +} +func (f *File) FilesInDir(dir string) ([]string, error) { + if strings.Contains(dir, `~`) { + user := `/home/` + os.Getenv(`SUDO_USER`) + if os.Getenv(`SUDO_USER`) == "" { + user = os.Getenv(`HOME`) + } + w := strings.Split(dir, `~`) + dir = user + w[len(w)-1] + } files, err := f.filesDir(dir) if err != nil { return nil, fmt.Errorf("get files failed: [%w]", err) diff --git a/internal/gui/gui.go b/internal/gui/gui.go deleted file mode 100644 index c662d28..0000000 --- a/internal/gui/gui.go +++ /dev/null @@ -1,273 +0,0 @@ -package gui - -import ( - "fmt" - "strings" - - qtgui "github.com/therecipe/qt/gui" - "github.com/therecipe/qt/widgets" -) - -type sysTray struct { - Tray *widgets.QSystemTrayIcon - menu *widgets.QMenu - image map[string][]byte -} - -type uiMainWindow struct { - mainWindow *widgets.QMainWindow - centralwidget *widgets.QWidget - gridLayout *widgets.QGridLayout - horizontalLayout *widgets.QHBoxLayout - PushButtonClear *widgets.QPushButton - PushButtonConnect *widgets.QPushButton - PushButtonDiscconnect *widgets.QPushButton - PushButtonExit *widgets.QPushButton - verticalLayout *widgets.QVBoxLayout - textEditReadOnly *widgets.QTextEdit - comboBox *widgets.QComboBox -} - -type Option func(*uiMainWindow) - -func NewUiMainWindow(opts ...Option) *uiMainWindow { - f := &uiMainWindow{} - for _, opt := range opts { - opt(f) - } - return f -} - -func WithApp(mainWindow *widgets.QMainWindow) Option { - return func(ui *uiMainWindow) { - ui.mainWindow = mainWindow - } -} - -func WithCentralwidget(centralwidget *widgets.QWidget) Option { - return func(ui *uiMainWindow) { - ui.centralwidget = centralwidget - } -} - -func WithGridLayout(gridLayout *widgets.QGridLayout) Option { - return func(ui *uiMainWindow) { - ui.gridLayout = gridLayout - } -} - -func WithHorizontalLayout(horizontalLayout *widgets.QHBoxLayout) Option { - return func(ui *uiMainWindow) { - ui.horizontalLayout = horizontalLayout - } -} - -func WithPushButtonClear(pushButtonClear *widgets.QPushButton) Option { - return func(ui *uiMainWindow) { - ui.PushButtonClear = pushButtonClear - } -} - -func WithPushButtonConnect(pushButtonConnect *widgets.QPushButton) Option { - return func(ui *uiMainWindow) { - ui.PushButtonConnect = pushButtonConnect - } -} - -func WithPushButtonDisconnect(pushButtonDisconnect *widgets.QPushButton) Option { - return func(ui *uiMainWindow) { - ui.PushButtonDiscconnect = pushButtonDisconnect - } -} - -func WithPushButtonExit(pushButtonExit *widgets.QPushButton) Option { - return func(ui *uiMainWindow) { - ui.PushButtonExit = pushButtonExit - } -} - -func WithVerticalLayout(verticalLayout *widgets.QVBoxLayout) Option { - return func(ui *uiMainWindow) { - ui.verticalLayout = verticalLayout - } -} - -func WithTextEditReadOnly(textEditReadOnly *widgets.QTextEdit) Option { - return func(ui *uiMainWindow) { - ui.textEditReadOnly = textEditReadOnly - } -} - -func WithComboBox(comboBox *widgets.QComboBox) Option { - return func(ui *uiMainWindow) { - ui.comboBox = comboBox - } -} - -type OptionTray func(*sysTray) - -func NewSysTray(opts ...OptionTray) *sysTray { - s := &sysTray{} - for _, opt := range opts { - opt(s) - } - return s -} - -func WithImage(image map[string][]byte) OptionTray { - return func(s *sysTray) { - s.image = image - } -} - -func WithSystemTrayIcon(t *widgets.QSystemTrayIcon) OptionTray { - return func(s *sysTray) { - s.Tray = t - } -} - -func WithSystemTrayMenu(m *widgets.QMenu) OptionTray { - return func(s *sysTray) { - s.menu = m - } -} - -func (ui *uiMainWindow) SetupUI( - app *widgets.QApplication, configsPath, - level, tempDir, appName, appPath string, configsName []string, -) { - - ui.mainWindow.SetWindowTitle(appName) - ui.mainWindow.SetGeometry2(100, 100, 600, 400) - ui.mainWindow.SetWindowIcon(qtgui.NewQIcon5(appPath)) - ui.horizontalLayout.AddWidget(ui.PushButtonClear, 1, 0) - ui.horizontalLayout.AddWidget(ui.PushButtonConnect, 1, 0) - ui.horizontalLayout.AddWidget(ui.PushButtonDiscconnect, 1, 0) - ui.horizontalLayout.AddWidget(ui.PushButtonExit, 1, 0) - ui.gridLayout.AddLayout(ui.horizontalLayout, 2, 0, 1) - ui.textEditReadOnly.SetReadOnly(true) - ui.verticalLayout.AddWidget(ui.textEditReadOnly, 0, 0) - ui.gridLayout.AddLayout(ui.verticalLayout, 1, 0, 1) - - ui.gridLayout.AddWidget2(ui.comboBox, 0, 0, 0) - ui.comboBox.AddItems(configsName) - ui.mainWindow.SetCentralWidget(ui.centralwidget) - -} - -func (ui *uiMainWindow) DisableListConfigsBox() { - ui.comboBox.SetDisabled(true) -} - -func (ui *uiMainWindow) EnableListConfigsBox() { - ui.comboBox.SetEnabled(true) -} - -func (ui *uiMainWindow) ButtonConnectDisable() { - ui.PushButtonConnect.SetDisabled(true) -} - -func (ui *uiMainWindow) ButtonConnectEnable() { - ui.PushButtonConnect.SetEnabled(true) -} - -func (ui *uiMainWindow) ButtonDisconnectDisable() { - ui.PushButtonDiscconnect.SetDisabled(true) -} - -func (ui *uiMainWindow) ButtonDisconnectEnable() { - ui.PushButtonDiscconnect.SetEnabled(true) -} - -func (ui *uiMainWindow) SelectedCfgFromListConfigs() *string { - s := ui.comboBox.CurrentText() - return &s -} - -func (ui *uiMainWindow) SetTextInLogForm(text string) { - ui.textEditReadOnly.SetPlainText(text) -} - -func (ui *uiMainWindow) GetTextFromLogForm() string { - return ui.textEditReadOnly.ToPlainText() -} - -func (ui *uiMainWindow) ClearLogForm() { - ui.textEditReadOnly.Clear() -} - -func (ui *uiMainWindow) IsEnableCombo() bool { - return ui.comboBox.IsEnabled() -} - -func (ui *uiMainWindow) UpdateComboBox(configs []string) { - ui.comboBox.Clear() - ui.comboBox.AddItems(configs) -} - -func (s *sysTray) SetupSysTray() (*widgets.QAction, - *widgets.QAction, *widgets.QAction, error) { - path, err := s.SearchKeyInMap("disconnect") - if err != nil { - return nil, nil, nil, err - } - s.SetIcon(*path) - main := s.menu.AddAction("Open main window") - updateComboBox := s.menu.AddAction("Update configs") - exit := s.menu.AddAction("Exit") - return exit, main, updateComboBox, nil -} - -func (s *sysTray) Image() map[string][]byte { - return s.image -} - -func (s *sysTray) SearchKeyInMap(st string) (*string, error) { - for key := range s.Image() { - if strings.Contains(key, st) { - return &key, nil - } - } - return nil, fmt.Errorf("key in map not found") -} - -func (s *sysTray) SetIcon(path string) { - s.Tray.SetIcon(qtgui.NewQIcon5(path)) -} - -func (s *sysTray) SetConnectIcon() error { - path, err := s.SearchKeyInMap("connecting") - if err != nil { - return fmt.Errorf("search key in map error: [%w]", err) - } - s.SetIcon(*path) - return nil -} - -func (s *sysTray) SetDisconnectIcon() error { - path, err := s.SearchKeyInMap("disconnect") - if err != nil { - return fmt.Errorf("search key in map error: [%w]", err) - } - s.SetIcon(*path) - return nil -} - -func (s *sysTray) SetOpenIcon() error { - path, err := s.SearchKeyInMap("open") - if err != nil { - return fmt.Errorf("search key in map error: [%w]", err) - } - - s.SetIcon(*path) - return nil -} - -func (s *sysTray) SetBlinkIcon() error { - path, err := s.SearchKeyInMap("blink") - if err != nil { - return fmt.Errorf("search key in map error: [%w]", err) - } - s.SetIcon(*path) - return nil -} diff --git a/internal/gui/gui_wails.go b/internal/gui/gui_wails.go new file mode 100644 index 0000000..9a6fb06 --- /dev/null +++ b/internal/gui/gui_wails.go @@ -0,0 +1,251 @@ +package gui + +import ( + "context" + "fmt" + rt "runtime" + + "github.com/Vai3soh/goovpn/entity" + "github.com/mitchellh/mapstructure" + "github.com/wailsapp/wails/v2/pkg/runtime" +) + +type Gui struct { + ctx context.Context + fileManager FilesManager + sessionService SessionService + dbService DbService + logService LogService + transportService TransportService +} + +type TransportService interface { + Disconnect() +} + +type FilesManager interface { + FilesInDir(path string) ([]string, error) + ChangeWorkingDir(path string) error +} + +type SessionService interface { + SetConnTimeout(t int) + SetProxyAllowCleartextAuth(b bool) + SetAllowUnusedAddrFamilies(s string) + SetClockTickMS(uint) + SetProxyHost(s string) + SetExternalPkiAlias(s string) + SetGremlinConfig(string) + SetGuiVersion(string) + SetHwAddrOverride(string) + SetPlatformVersion(string) + SetPortOverride(string) + SetPrivateKeyPassword(string) + SetProtoOverride(string) + SetProtoVersionOverride(int) + SetProxyUsername(string) + SetProxyPassword(string) + SetProxyPort(string) + SetServerOverride(string) + SetSsoMethods(string) + SetTlsCertProfileOverride(string) + SetTlsCipherList(string) + SetTlsCiphersuitesList(string) + SetTlsVersionMinOverride(string) + SetDefaultKeyDirection(int) + SetTunPersist(bool) + SetEnableLegacyAlgorithms(bool) + SetEnableNonPreferredDCAlgorithms(bool) + SetDisableClientCert(bool) + SetRetryOnAuthFailed(bool) + SetAllowLocalDnsResolvers(bool) + SetAllowLocalLanAccess(bool) + SetAltProxy(bool) + SetAutologinSessions(bool) + SetDco(bool) + SetEcho(bool) + SetGenerate_tun_builder_capture_event(bool) + SetGoogleDnsFallback(bool) + SetInfo(bool) + SetSynchronousDnsLookup(bool) + SetWintun(bool) + + SetSslDebugLevel(int) + SetCompressionMode(string) +} + +type LogService interface { + Fatal(...interface{}) + Debugf(string, ...interface{}) + Fatalf(string, ...interface{}) + Info(...interface{}) +} + +type DbService interface { + ReOpen() error + CreateBucket(name string) error + Store(key, value string) error + DeleteKey(key string) error + StoreBulk(result []entity.Message) error + GetValueFromBucket(key string) error + GetAllValue() + Message() []entity.Message + SetNameBucket(nameBucket string) + BucketIsCreate() bool +} + +func NewGui( + f FilesManager, s SessionService, + d DbService, l LogService, t TransportService) *Gui { + return &Gui{ + sessionService: s, + fileManager: f, + dbService: d, + logService: l, + transportService: t, + } +} + +func (g *Gui) Startup(ctx context.Context) { + g.ctx = ctx +} + +func (g *Gui) DomReady(ctx context.Context) { + +} + +func (g *Gui) BeforeClose(ctx context.Context) (prevent bool) { + return false +} + +func (g *Gui) Shutdown(ctx context.Context) { + g.transportService.Disconnect() +} + +func (g *Gui) Run() { + +} + +func (g *Gui) Stoped() { + +} + +func (g *Gui) IsWindows() bool { + return rt.GOOS == `windows` +} + +func (g *Gui) GetData(name string) []entity.Message { + g.dbMustOpen() + g.dbService.SetNameBucket(name) + g.dbService.GetAllValue() + return g.dbService.Message() +} + +func (g *Gui) SaveToFrontendParams() { + + data := g.GetData(`general_configure`) + runtime.EventsEmit(g.ctx, "rcv:save_from_db_general_configure", data) + + data = g.GetData(`general_openvpn_library`) + err := g.setSessionParamsGeneralOvpnLib(data) + if err != nil { + g.logService.Fatal(err) + } + runtime.EventsEmit(g.ctx, "rcv:save_from_db_checkbox", data) + + data = g.GetData(`ssl_cmp`) + g.setSessionParamsDebugSslAndCompression(data) + + runtime.EventsEmit(g.ctx, "rcv:save_from_db_select", data) + + data = g.GetData(`other_options`) + err = g.setSessionParamsOtherOpt(data) + if err != nil { + g.logService.Fatal(err) + } + runtime.EventsEmit(g.ctx, "rcv:save_from_db_input", data) + +} + +func (g *Gui) GetConfigsAndChangeCWD() ([]string, error) { + g.dbMustOpen() + g.dbService.SetNameBucket(`general_configure`) + err := g.dbService.GetValueFromBucket(`config_dir_path`) + if err != nil { + return nil, err + } + path := g.dbService.Message() + files, err := g.fileManager.FilesInDir(path[0].Value) + if err != nil { + return nil, err + } + err = g.fileManager.ChangeWorkingDir(path[0].Value) + if err != nil { + return nil, err + } + return files, err +} + +func (g *Gui) dbMustOpen() { + err := g.dbService.ReOpen() + if err != nil { + g.logService.Fatalf("don't reopen db [%s]\n", err) + } +} + +func (g *Gui) DeleteData(data map[string]interface{}, bucketName string) { + result, err := g.DecodeData(data) + if err != nil { + g.logService.Fatalf("don't decode data [%s]\n", err) + } + g.dbMustOpen() + err = g.dbService.CreateBucket(bucketName) + if err != nil { + g.logService.Fatalf("don't create storage [%s]\n", err) + } + g.dbMustOpen() + err = g.dbService.DeleteKey(result.AtrId) + if err != nil { + g.logService.Fatalf("don't create storage [%s]\n", err) + } + g.setSessionFromAnyBucket(result, bucketName) +} + +func (g *Gui) setSessionFromAnyBucket(result *entity.Message, bucketName string) { + inObj := []entity.Message{*result} + if bucketName == `general_openvpn_library` { + g.setSessionParamsGeneralOvpnLib(inObj) + } else if bucketName == `ssl_cmp` { + g.setSessionParamsDebugSslAndCompression(inObj) + } else if bucketName == `other_options` { + g.setSessionParamsOtherOpt(inObj) + } +} + +func (g *Gui) SaveData(data map[string]interface{}, bucketName string) { + + result, err := g.DecodeData(data) + if err != nil { + g.logService.Fatalf("don't decode data [%s]\n", err) + } + g.dbMustOpen() + err = g.dbService.CreateBucket(bucketName) + if err != nil { + g.logService.Fatalf("don't create storage [%s]\n", err) + } + g.dbMustOpen() + err = g.dbService.Store(result.AtrId, result.Value) + if err != nil { + g.logService.Fatalf("don't save value [%s] [%s]\n", result.Value, err) + } + g.setSessionFromAnyBucket(result, bucketName) +} + +func (g *Gui) DecodeData(data map[string]interface{}) (*entity.Message, error) { + var result entity.Message + err := mapstructure.Decode(data, &result) + if err != nil { + return nil, fmt.Errorf("decode failed %s", err) + } + return &result, nil +} diff --git a/internal/gui/helper.go b/internal/gui/helper.go new file mode 100644 index 0000000..84ccdda --- /dev/null +++ b/internal/gui/helper.go @@ -0,0 +1,148 @@ +package gui + +import ( + "fmt" + "runtime" + "strconv" + + "github.com/Vai3soh/goovpn/entity" +) + +func getBool(v *string) bool { + if v != nil { + return *v != "" + } + return false +} + +func getUint(v string) (*uint, error) { + u64, err := strconv.ParseUint(v, 10, 32) + if err != nil { + return nil, fmt.Errorf("convert string to uint failed: [%s]", err) + + } + r := uint(u64) + return &r, nil +} + +func (g *Gui) setSessionParamsOtherOpt(data []entity.Message) error { + for _, e := range data { + switch e.AtrId { + case `with_conn_timeout`: + t, _ := strconv.Atoi(e.Value) + g.sessionService.SetConnTimeout(t) + case `with_allow_unused_addr_families`: + g.sessionService.SetAllowUnusedAddrFamilies(e.Value) + case `with_clock_tick_ms`: + v, err := getUint(e.Value) + if err != nil { + return err + } + g.sessionService.SetClockTickMS(*v) + case `with_external_pki_alias`: + g.sessionService.SetExternalPkiAlias(e.Value) + case `with_gremlin_config`: + g.sessionService.SetGremlinConfig(e.Value) + case `with_gui_version`: + g.sessionService.SetGuiVersion(e.Value) + case `with_hwaddr_override`: + g.sessionService.SetHwAddrOverride(e.Value) + case `with_platform_version`: + g.sessionService.SetPlatformVersion(e.Value) + case `with_port_override`: + g.sessionService.SetPortOverride(e.Value) + case `with_private_key_password`: + g.sessionService.SetPrivateKeyPassword(e.Value) + case `with_proto_override`: + g.sessionService.SetProtoOverride(e.Value) + case `with_proto_version_override`: + t, _ := strconv.Atoi(e.Value) + g.sessionService.SetProtoVersionOverride(t) + case `with_proxy_allow_clear_text_auth`: + g.sessionService.SetProxyAllowCleartextAuth(getBool(&e.Value)) + case `with_proxy_host`: + g.sessionService.SetProxyHost(e.Value) + case `with_proxy_username`: + g.sessionService.SetProxyUsername(e.Value) + case `with_proxy_password`: + g.sessionService.SetProxyPassword(e.Value) + case `with_proxy_port`: + g.sessionService.SetProxyPort(e.Value) + case `with_server_override`: + g.sessionService.SetServerOverride(e.Value) + case `with_sso_methods`: + g.sessionService.SetSsoMethods(e.Value) + case `with_tls_cert_profile_override`: + g.sessionService.SetTlsCertProfileOverride(e.Value) + case `with_tls_cipher_list`: + g.sessionService.SetTlsCipherList(e.Value) + case `with_tls_cipher_suites_list`: + g.sessionService.SetTlsCiphersuitesList(e.Value) + case `with_tls_version_min_override`: + g.sessionService.SetTlsVersionMinOverride(e.Value) + case `with_default_key_direction`: + t, _ := strconv.Atoi(e.Value) + g.sessionService.SetDefaultKeyDirection(t) + } + + } + return nil +} + +func (g *Gui) setSessionParamsGeneralOvpnLib(data []entity.Message) error { + for _, e := range data { + switch e.AtrId { + case `tun_persist`: + g.sessionService.SetTunPersist(getBool(&e.Value)) + case `legacy_algo`: + g.sessionService.SetEnableLegacyAlgorithms(getBool(&e.Value)) + if runtime.GOOS == "windows" { + g.sessionService.SetEnableLegacyAlgorithms(false) + } + case `preferred_dc_algo`: + g.sessionService.SetEnableNonPreferredDCAlgorithms(getBool(&e.Value)) + case `disable_client_cert`: + g.sessionService.SetDisableClientCert(getBool(&e.Value)) + case `retry_on_failed`: + g.sessionService.SetRetryOnAuthFailed(getBool(&e.Value)) + case `allow_local_dns_resolvers`: + g.sessionService.SetAllowLocalDnsResolvers(getBool(&e.Value)) + case `allow_local_lan_access`: + g.sessionService.SetAllowLocalLanAccess(getBool(&e.Value)) + case `alt_proxy`: + g.sessionService.SetAltProxy(getBool(&e.Value)) + case `auto_login_sessions`: + g.sessionService.SetAutologinSessions(getBool(&e.Value)) + case `use_dco`: + g.sessionService.SetDco(getBool(&e.Value)) + case `with_echo`: + g.sessionService.SetEcho(getBool(&e.Value)) + case `tun_builder_cupture_event`: + g.sessionService.SetGenerate_tun_builder_capture_event(getBool(&e.Value)) + case `google_dns_fallback`: + g.sessionService.SetGoogleDnsFallback(getBool(&e.Value)) + case `info`: + g.sessionService.SetInfo(getBool(&e.Value)) + case `proxy_allow_clear_text_auth`: + g.sessionService.SetProxyAllowCleartextAuth(getBool(&e.Value)) + case `synch_dns_lookup`: + g.sessionService.SetSynchronousDnsLookup(getBool(&e.Value)) + case `enable_win_tun`: + g.sessionService.SetWintun(getBool(&e.Value)) + + } + } + return nil +} + +func (g *Gui) setSessionParamsDebugSslAndCompression(data []entity.Message) { + for _, e := range data { + switch e.AtrId { + case `#ssl`: + v, _ := strconv.Atoi(e.Value) + g.sessionService.SetSslDebugLevel(v) + case `#cmp`: + g.sessionService.SetCompressionMode(e.Value) + } + } +} diff --git a/internal/session/session.go b/internal/session/session.go index c2780ca..40d0d87 100644 --- a/internal/session/session.go +++ b/internal/session/session.go @@ -30,7 +30,6 @@ func NewOverwriteClient() *OverwriteClient { func (ocl *OverwriteClient) Log(li ovpncli.ClientAPI_LogInfo) { ocl.vpnLog <- li.GetText() - } func (ocl *OverwriteClient) ChanVpnLog() chan string { @@ -63,16 +62,20 @@ func NewOpenvpnClientCred(optsCred ...ovpncli.OptionCred) *OpenvpnClientCred { return op } -func NewOpenvpnClient(opts ...ovpncli.Option) *OpenvpnClient { +func NewOpenvpnClient(ctx context.Context, opts ...ovpncli.Option) *OpenvpnClient { ocl := &OverwriteClient{vpnLog: make(chan string)} op := &OpenvpnClient{ - Client: ovpncli.NewClient(ocl), + Client: ovpncli.NewClient(ocl, ctx), ClientAPI_Config: ovpncli.NewClientConfig(opts...), OverwriteClient: *ocl, } return op } +func (op *OpenvpnClient) GetClient() ovpncli.Client { + return op.Client +} + func (op *OpenvpnClient) SetClient(c ovpncli.Client) { op.Client = c } @@ -85,12 +88,15 @@ func (op *OpenvpnClient) GetOverwriteClient() *OverwriteClient { return &op.OverwriteClient } -func (op *OpenvpnClient) StartSession(ctx context.Context) error { +func (op *OpenvpnClient) StartSession() error { ev := op.Eval_config(op.ClientAPI_Config) if ev.GetError() { return fmt.Errorf("config eval failed [%s]", ev.GetMessage()) } - op.StartConnection(ctx) + err := op.StartConnection() + if err != nil { + return err + } return nil } @@ -110,3 +116,9 @@ func (op *OpenvpnClient) SetCread(u, p string) error { } return nil } + +func (op *OpenvpnClient) ReloadClient(ctx context.Context) { + ocl_ := NewOverwriteClient() + op.OverwriteClient = *ocl_ + op.SetClient(ovpncli.NewClient(ocl_, ctx)) +} diff --git a/internal/transport/openvpn/openvpn.go b/internal/transport/openvpn/openvpn.go index 5a495cb..f65f9df 100644 --- a/internal/transport/openvpn/openvpn.go +++ b/internal/transport/openvpn/openvpn.go @@ -4,9 +4,12 @@ import ( "context" "os" "regexp" + "strconv" "strings" + "time" "github.com/Vai3soh/goovpn/entity" + "github.com/wailsapp/wails/v2/pkg/runtime" ) type Logger interface { @@ -16,6 +19,10 @@ type Logger interface { Info(...interface{}) } +type sessionService interface { + ReloadClient(context.Context) +} + type core interface { SetSessionCread(u, p string) error GetOvpnAuthPathFileName() string @@ -25,22 +32,18 @@ type core interface { GetVpnCread() (string, string) CheckOvpnUseAuthUserPass() bool SetProfileBody(profileBody string) - RunSession(ctx context.Context) error + RunSession() error DestroyVpnClient() ExitSession() - OffComboBoxAndClear() - DisableConnectionButton() - GetTextFromComboBox() string - EnableDisconnectButton() GetChanVpnLog() chan string - CaseSetLogsInTextWidget(text string) - EnableConnectButton() - TurnOnConfigsBox() - DisableDisconnectButton() - TraySetImageDisconnect() error - TraySetImageConnect() error SetPhyseInterface(iface string) - CaseFlickeringIcon() error +} + +type DBService interface { + SetNameBucket(name string) + GetValueFromBucket(key string) error + ReOpen() error + Message() []entity.Message } type DnsManager interface { @@ -58,26 +61,31 @@ type ProfileCore interface { } type TransportOvpnClient struct { + ctx context.Context configsPath string - stopTimeout int core core dnsManager DnsManager pcore ProfileCore l Logger + + dbService DBService + sessionService } func New( - configsPath string, stopTimeout int, - core core, pcore ProfileCore, dnsManager DnsManager, l Logger, + configsPath string, core core, + pcore ProfileCore, dnsManager DnsManager, + l Logger, db DBService, s sessionService, ) *TransportOvpnClient { return &TransportOvpnClient{ - configsPath: configsPath, - stopTimeout: stopTimeout, - core: core, - dnsManager: dnsManager, - pcore: pcore, - l: l, + configsPath: configsPath, + core: core, + dnsManager: dnsManager, + pcore: pcore, + l: l, + dbService: db, + sessionService: s, } } @@ -118,57 +126,77 @@ func (t *TransportOvpnClient) initSession() { } } -func (t *TransportOvpnClient) caseRunSessionOpenvpn(ctx context.Context, profile string) { +func (t *TransportOvpnClient) caseRunSessionOpenvpn(profile string) { t.core.SetProfileBody(profile) t.initSession() - err := t.core.RunSession(ctx) + err := t.core.RunSession() if err != nil { - t.l.Fatal(err) + _, err := runtime.MessageDialog(t.ctx, runtime.MessageDialogOptions{ + Type: runtime.ErrorDialog, + Title: "Error", + Message: err.Error(), + }) + if err != nil { + t.l.Fatal(err) + } } } -func (t *TransportOvpnClient) Connect(ctx context.Context, countReccon int) func() error { +func (t *TransportOvpnClient) Context() context.Context { + return t.ctx +} + +func (t *TransportOvpnClient) SetContext(ctx context.Context) { + t.ctx = ctx +} + +func (t *TransportOvpnClient) Connect(cfgName string) { - f := func() error { - go t.readLogsFromChan(countReccon) - t.core.OffComboBoxAndClear() - t.core.DisableConnectionButton() - cfg := t.configsPath + t.core.GetTextFromComboBox() - profile := t.pcore.GetProfileFromCache(cfg) - if profile.Body == "" { - err := t.pcore.SaveProfileWithoutCfgFile(cfg) + t.sessionService.ReloadClient(t.Context()) + err := t.dbService.ReOpen() + if err != nil { + t.l.Fatal(err) + } + t.dbService.SetNameBucket(`general_configure`) + err = t.dbService.GetValueFromBucket(`reconn_count`) + if err != nil { + t.l.Fatal(err) + } + message := t.dbService.Message() + v, _ := strconv.Atoi(message[0].Value) + go t.readLogsFromChan(v) + cfg := t.configsPath + cfgName + profile := t.pcore.GetProfileFromCache(cfg) + if profile.Body == "" { + err := t.pcore.SaveProfileWithoutCfgFile(cfg) + if err != nil { + t.l.Fatalf("pcore failed: [%w]\n", err) + } + if !t.pcore.CheckUseCfgFile() { + profile := t.pcore.GetProfileFromCache(cfg) + os.Chdir(t.configsPath) + t.caseRunSessionOpenvpn(profile.Body) + + } else { + os.Chdir(t.configsPath) + err := t.pcore.SaveProfileWithCfgFile(cfg) if err != nil { - return err - } - if !t.pcore.CheckUseCfgFile() { - profile := t.pcore.GetProfileFromCache(cfg) - os.Chdir(t.configsPath) - t.caseRunSessionOpenvpn(ctx, profile.Body) - } else { - os.Chdir(t.configsPath) - err := t.pcore.SaveProfileWithCfgFile(cfg) - if err != nil { - return err - } - profile := t.pcore.GetProfileFromCache(cfg) - t.caseRunSessionOpenvpn(ctx, profile.Body) + t.l.Fatalf("pcore failed: [%w]\n", err) } - } else { - t.caseRunSessionOpenvpn(ctx, profile.Body) + profile := t.pcore.GetProfileFromCache(cfg) + t.caseRunSessionOpenvpn(profile.Body) } - return nil + } else { + t.caseRunSessionOpenvpn(profile.Body) } - return f } -func (t *TransportOvpnClient) Disconnect(stop context.CancelFunc) func() { - return func() { - stop() - t.dnsManager.ConfigureDns(`revert`) - err := t.dnsManager.SetupDns(`revert`) - if err != nil { - t.l.Fatalf("don't manager dns: [%w]\n", err) - } +func (t *TransportOvpnClient) Disconnect() { + t.core.ExitSession() + t.dnsManager.ConfigureDns(`revert`) + err := t.dnsManager.SetupDns(`revert`) + if err != nil { + t.l.Fatalf("don't manager dns: [%w]\n", err) } } @@ -179,32 +207,31 @@ func (t *TransportOvpnClient) readLogsFromChan(countReccon int) { toBreak := false count := 0 for text := range logChan { - t.core.CaseSetLogsInTextWidget(text) + runtime.EventsEmit(t.ctx, "rcv:read_log", text, count, countReccon) + if toBreak { + time.Sleep(time.Duration(10) * time.Millisecond) t.core.DestroyVpnClient() break } - if strings.Contains(text, `Server poll timeout, trying next remote entry...`) { + if strings.Contains(text, "Server poll timeout, trying next remote entry...") { count++ if count == countReccon { - t.core.TurnOnConfigsBox() - t.core.EnableConnectButton() - toBreak = true + t.core.ExitSession() } } - if strings.Contains(text, `event name: CONNECTING`) { - t.core.EnableDisconnectButton() - } - if strings.Contains(text, `DNS Servers:`) { t.dnsManager.AddDnsAddrs(text) } + if strings.Contains(text, "UNKNOWN/UNSUPPORTED OPTIONS") { + toBreak = true + } + if strings.Contains(text, `event name: DISCONNECTED`) { - t.core.EnableConnectButton() - t.core.TurnOnConfigsBox() + if !iterSkip { t.dnsManager.ConfigureDns(`revert`) err := t.dnsManager.SetupDns(`revert`) @@ -212,27 +239,15 @@ func (t *TransportOvpnClient) readLogsFromChan(countReccon int) { t.l.Fatalf("don't manager dns: [%w]\n", err) } } - t.core.DisableDisconnectButton() - err := t.core.TraySetImageDisconnect() - if err != nil { - t.l.Info("don't set image: [%w]\n", err) - } toBreak = true } if strings.Contains(text, `event name: CONNECTED`) { - err := t.core.TraySetImageConnect() - if err != nil { - t.l.Info("don't set image: [%w]\n", err) - } continue } if strings.Contains(text, `event name: RECONNECTING`) { - err := t.core.CaseFlickeringIcon() - if err != nil { - t.l.Fatalf("case flick icon fatal err: [%w]", err) - } + } if iterSkip { @@ -251,18 +266,12 @@ func (t *TransportOvpnClient) readLogsFromChan(countReccon int) { if err != nil { t.l.Fatalf("setup dns err [%w]\n", err) } - err = t.core.TraySetImageConnect() - if err != nil { - t.l.Info("don't set image: [%w]\n", err) - } + iterSkip = true continue } else { - err := t.core.CaseFlickeringIcon() - if err != nil { - t.l.Fatalf("case flick icon fatal err: [%w]", err) - } + } } } diff --git a/internal/usecase/interfaces.go b/internal/usecase/interfaces.go index 53fc642..d5c95d5 100644 --- a/internal/usecase/interfaces.go +++ b/internal/usecase/interfaces.go @@ -1,7 +1,6 @@ package usecase import ( - "context" "io/fs" "os" @@ -19,7 +18,7 @@ type ( } SessionManager interface { - StartSession(ctx context.Context) error + StartSession() error StopSession() DestroyClient() } @@ -57,37 +56,37 @@ type ( GetUserAndPass() (string, string) } - UiLogFormManager interface { - GetTextFromLogForm() string - SetTextInLogForm(text string) - ClearLogForm() - } - - UiButtonsManager interface { - ButtonConnectEnable() - ButtonConnectDisable() - ButtonDisconnectEnable() - ButtonDisconnectDisable() - } - - UiListConfigsManager interface { - DisableListConfigsBox() - EnableListConfigsBox() - SelectedCfgFromListConfigs() *string - } - - SysTrayIconsManager interface { - SetIcon(path string) - SetDisconnectIcon() error - SetConnectIcon() error - SetOpenIcon() error - SetBlinkIcon() error - } - - SysTrayImagesManager interface { - SearchKeyInMap(s string) (*string, error) - Image() map[string][]byte - } + /* UiLogFormManager interface { + GetTextFromLogForm() string + SetTextInLogForm(text string) + ClearLogForm() + } + + UiButtonsManager interface { + ButtonConnectEnable() + ButtonConnectDisable() + ButtonDisconnectEnable() + ButtonDisconnectDisable() + } + + UiListConfigsManager interface { + DisableListConfigsBox() + EnableListConfigsBox() + SelectedCfgFromListConfigs() *string + } + + SysTrayIconsManager interface { + SetIcon(path string) + SetDisconnectIcon() error + SetConnectIcon() error + SetOpenIcon() error + SetBlinkIcon() error + } + + SysTrayImagesManager interface { + SearchKeyInMap(s string) (*string, error) + Image() map[string][]byte + } */ FileSetters interface { SetBody([]byte) diff --git a/internal/usecase/usecase.go b/internal/usecase/usecase.go index e5adefc..db7ce1c 100644 --- a/internal/usecase/usecase.go +++ b/internal/usecase/usecase.go @@ -1,29 +1,26 @@ package usecase import ( - "context" "fmt" - "runtime" - "time" ) type VpnUseCase struct { - sessionSetters SessionSetters - sessionManager SessionManager - cfgSetters ConfigSetters - cfgBody ConfigBody - cfgRemover ConfigRemover - cfgCheck ConfigChecker - cfgMerg ConfigMerger - cfgTools ConfigTools - sessionLoger SessionLoger - uiLogFormManager UiLogFormManager - uiButtonsManager UiButtonsManager - uiListConfigsManager UiListConfigsManager - sysTrayIconsManager SysTrayIconsManager - fileSetters FileSetters - fileReader FileReader - dnsSetters DnsSetters + sessionSetters SessionSetters + sessionManager SessionManager + cfgSetters ConfigSetters + cfgBody ConfigBody + cfgRemover ConfigRemover + cfgCheck ConfigChecker + cfgMerg ConfigMerger + cfgTools ConfigTools + sessionLoger SessionLoger + /* uiLogFormManager UiLogFormManager + uiButtonsManager UiButtonsManager + uiListConfigsManager UiListConfigsManager + sysTrayIconsManager SysTrayIconsManager */ + fileSetters FileSetters + fileReader FileReader + dnsSetters DnsSetters } func NewVpnUseCase( @@ -37,31 +34,31 @@ func NewVpnUseCase( cfgMerg ConfigMerger, cfgTools ConfigTools, sessionLoger SessionLoger, - uiLogFormManager UiLogFormManager, - uiButtonsManager UiButtonsManager, - uiListConfigsManager UiListConfigsManager, - sysTrayIconsManager SysTrayIconsManager, + /* uiLogFormManager UiLogFormManager, + uiButtonsManager UiButtonsManager, + uiListConfigsManager UiListConfigsManager, + sysTrayIconsManager SysTrayIconsManager, */ fileSetters FileSetters, fileReader FileReader, dnsSetters DnsSetters, ) (obj *VpnUseCase, err error) { obj = &VpnUseCase{ - sessionSetters: sessionSetters, - sessionManager: sessionManager, - cfgSetters: cfgSetters, - cfgBody: cfgBody, - cfgRemover: cfgRemover, - cfgCheck: cfgCheck, - cfgMerg: cfgMerg, - cfgTools: cfgTools, - sessionLoger: sessionLoger, - uiLogFormManager: uiLogFormManager, + sessionSetters: sessionSetters, + sessionManager: sessionManager, + cfgSetters: cfgSetters, + cfgBody: cfgBody, + cfgRemover: cfgRemover, + cfgCheck: cfgCheck, + cfgMerg: cfgMerg, + cfgTools: cfgTools, + sessionLoger: sessionLoger, + /* uiLogFormManager: uiLogFormManager, uiButtonsManager: uiButtonsManager, uiListConfigsManager: uiListConfigsManager, - sysTrayIconsManager: sysTrayIconsManager, - fileSetters: fileSetters, - fileReader: fileReader, - dnsSetters: dnsSetters, + sysTrayIconsManager: sysTrayIconsManager, */ + fileSetters: fileSetters, + fileReader: fileReader, + dnsSetters: dnsSetters, } return } @@ -71,7 +68,7 @@ func (v *VpnUseCase) GetChanVpnLog() chan string { return logChan } -func (vp *VpnUseCase) CaseSetLogsInTextWidget(text string) { +/* func (vp *VpnUseCase) CaseSetLogsInTextWidget(text string) { if runtime.GOOS != "windows" { time.Sleep(time.Duration(50) * time.Millisecond) } @@ -120,11 +117,13 @@ func (v *VpnUseCase) TraySetImageConnect() error { return nil } +*/ + func (v *VpnUseCase) SetPhyseInterface(i string) { v.dnsSetters.SetInterface(i) } -func (vp *VpnUseCase) CaseFlickeringIcon() error { +/* func (vp *VpnUseCase) CaseFlickeringIcon() error { if runtime.GOOS != "windows" { time.Sleep(time.Duration(250) * time.Millisecond) @@ -152,7 +151,7 @@ func (vp *VpnUseCase) CaseFlickeringIcon() error { func (vp *VpnUseCase) GetTextFromComboBox() string { return *vp.uiListConfigsManager.SelectedCfgFromListConfigs() -} +} */ func (vp *VpnUseCase) ReadFile() ([]byte, error) { body, err := vp.fileReader.ReadFileAsByte() @@ -175,8 +174,8 @@ func (vp *VpnUseCase) CheckOvpnUseAuthUserPass() bool { return vp.cfgCheck.CheckStringAuthUserPass() } -func (vp *VpnUseCase) RunSession(ctx context.Context) error { - return vp.sessionManager.StartSession(ctx) +func (vp *VpnUseCase) RunSession() error { + return vp.sessionManager.StartSession() } func (vp *VpnUseCase) DestroyVpnClient() { diff --git a/internal/usecase/usecaseprofile/profile.go b/internal/usecase/usecaseprofile/profile.go index e4a4bde..9f513f4 100644 --- a/internal/usecase/usecaseprofile/profile.go +++ b/internal/usecase/usecaseprofile/profile.go @@ -2,6 +2,7 @@ package usecaseprofile import ( "fmt" + "os" "strings" "github.com/Vai3soh/goovpn/entity" @@ -131,11 +132,6 @@ func (p *ProfileUseCase) GetProfileFromCache(cfg string) entity.Profile { return p.profileRepo.Find(cfg) } -func (p *ProfileUseCase) CheckFileExists(f string) bool { - p.fileSetters.SetPath(f) - return p.fileToolsManager.CheckFileExists() -} - func (p *ProfileUseCase) CheckUseCfgFile() bool { return p.cfgCheck.CheckConfigUseFiles() } @@ -153,7 +149,16 @@ func (p *ProfileUseCase) SaveProfile(cfg string) error { if profile.Body == "" { for _, f := range [2]string{cfg + ".ovpn", cfg + ".conf"} { - if p.CheckFileExists(f) { + if strings.Contains(f, `~`) { + user := `/home/` + os.Getenv(`SUDO_USER`) + if os.Getenv(`SUDO_USER`) == "" { + user = os.Getenv(`HOME`) + } + w := strings.Split(f, `~`) + f = user + w[len(w)-1] + } + p.fileSetters.SetPath(f) + if p.fileToolsManager.CheckFileExists() { break } } diff --git a/nfpm.yaml b/nfpm.yaml index 3ed77cc..dba8905 100644 --- a/nfpm.yaml +++ b/nfpm.yaml @@ -1,19 +1,19 @@ name: "goovpn" arch: "amd64" platform: "linux" -version: "v1.0.2" +version: "v1.0.3" section: "default" priority: "extra" -maintainer: "Vai3soh " +maintainer: "Vai3soh " description: | - Goovpn openvpn client gui(use qt) for linux. + Goovpn openvpn client gui(use wails) for linux. -license: "MIT" -changelog: "changelog.yaml" +license: "GNU AGPL" +changelog: "changelog.yml" contents: -- src: ./cmd/app/goovpn +- src: ./build/bin/goovpn dst: /usr/sbin/goovpn file_info: mode: 0755 @@ -25,43 +25,139 @@ contents: - src: ./scripts/goovpn.desktop dst: /usr/share/applications/goovpn.desktop + +- dst: /etc/goovpn/ + type: dir + file_info: + mode: 0700 -- src: ./config/config.yml - dst: /etc/goovpn/config.yml - type: config +- dst: /etc/goovpn/goovpn.db + type: ghost - src: ./embedfile/assets/app.png dst: /usr/share/icons/hicolor/128x128/apps/goovpn.png overrides: deb: - depends: - - iproute2 - - libfontconfig1 - - libfreetype6 - - libxcb-glx0 - - libx11-xcb1 - - libxcb1 - - libxrender1 - - libx11-6 - - libc6 - - libxkbcommon0 - - libglib2.0-0 - - libgl1 - - libstdc++6 - - libgcc-s1 - - libexpat1 - - libuuid1 - - libpng16-16 - - zlib1g - - libbrotli1 - - libxau6 - - libxdmcp6 - - libpcre3 - - libglvnd0 - - libglx0 - - libbsd0 - - libmd0 + depends: + - iproute2 + - libc6 + - libwebkit2gtk-4.0-37 + - libgtk-3-0 + - libgdk-pixbuf-2.0-0 + - libglib2.0-0 + - libjavascriptcoregtk-4.0-18 + - libstdc++6 + - libgcc-s1 + - libwpe-1.0-1 + - libwpebackend-fdo-1.0-1 + - libegl1 + - libatomic1 + - libnotify4 + - libicu67 + - libelogind0 + - libpangocairo-1.0-0 + - libpango-1.0-0 + - libharfbuzz0b + - libcairo-gobject2 + - libcairo2 + - libxml2 + - libsqlite3-0 + - libxslt1.1 + - libopengl0 + - libglx0 + - liblcms2-2 + - libwoff1 + - libfontconfig1 + - libfreetype6 + - libharfbuzz-icu0 + - libgcrypt20 + - libgpg-error0 + - libgstreamer-plugins-base1.0-0 + - libgstreamer1.0-0 + - libgstreamer-gl1.0-0 + - libjpeg62-turbo + - libpng16-16 + - zlib1g + - libopenjp2-7 + - libwebpdemux2 + - libwebp6 + - libsoup2.4-1 + - libatk1.0-0 + - libenchant-2-2 + - libsecret-1-0 + - libtasn1-6 + - libhyphen0 + - libx11-6 + - libxcomposite1 + - libxdamage1 + - libxrender1 + - libxt6 + - libwayland-server0 + - libwayland-egl1 + - libwayland-client0 + - libmanette-0.2-0 + - libseccomp2 + - libxi6 + - libxfixes3 + - libatk-bridge2.0-0 + - libepoxy0 + - libfribidi0 + - libpangoft2-1.0-0 + - libxinerama1 + - libxrandr2 + - libxcursor1 + - libxkbcommon0 + - libwayland-cursor0 + - libxext6 + - libmount1 + - libselinux1 + - libffi7 + - libpcre3 + - libglvnd0 + - libcap2 + - libthai0 + - libgraphite2-3 + - libpixman-1-0 + - libxcb-shm0 + - libxcb1 + - libxcb-render0 + - liblzma5 + - libbrotli1 + - libexpat1 + - libuuid1 + - libunwind8 + - libdw1 + - liborc-0.4-0 + - libgl1 + - libx11-xcb1 + - libgudev-1.0-0 + - libdrm2 + - libgbm1 + - libgssapi-krb5-2 + - libpsl5 + - libsm6 + - libice6 + - libevdev2 + - libdbus-1-3 + - libatspi2.0-0 + - libblkid1 + - libpcre2-8-0 + - libdatrie1 + - libxau6 + - libxdmcp6 + - libelf1 + - libbz2-1.0 + - libeudev1 + - libkrb5-3 + - libk5crypto3 + - libcom-err2 + - libkrb5support0 + - libunistring2 + - libidn2-0 + - libbsd0 + - libkeyutils1 + - libmd0 rpm: depends: diff --git a/pkg/boltdb/bolt_db.go b/pkg/boltdb/bolt_db.go new file mode 100644 index 0000000..8c8a95a --- /dev/null +++ b/pkg/boltdb/bolt_db.go @@ -0,0 +1,206 @@ +package boltdb + +import ( + "fmt" + "sync" + + "github.com/Vai3soh/goovpn/entity" + bolt "go.etcd.io/bbolt" //https://github.com/etcd-io/bbolt +) + +type BoltDB struct { + db *bolt.DB + path string + nameBucket string + m []entity.Message + mu sync.Mutex +} + +func openBolt(filePath string) (*bolt.DB, error) { + db, err := bolt.Open(filePath, 0600, nil) + if err != nil { + return nil, err + } + return db, nil +} + +func NewBoltDB(filePath string) (*BoltDB, error) { + db, err := openBolt(filePath) + if err != nil { + return nil, err + } + return &BoltDB{db: db, path: filePath}, nil +} + +func (b *BoltDB) SetDB(db *bolt.DB) { + b.mu.Lock() + defer b.mu.Unlock() + b.db = db +} + +func (b *BoltDB) ReOpen() error { + b.Close() + db, err := openBolt(b.path) + if err != nil { + return err + } + b.SetDB(db) + return nil +} + +func (b *BoltDB) SetMessage(m []entity.Message) { + b.m = m +} + +func (b *BoltDB) Message() []entity.Message { + return b.m +} + +func (b *BoltDB) SetNameBucket(name string) { + b.nameBucket = name +} + +func (b *BoltDB) NameBucket() string { + return b.nameBucket +} + +func (b *BoltDB) Path() string { + return b.db.Path() +} + +func (b *BoltDB) Close() { + b.mu.Lock() + defer b.mu.Unlock() + b.db.Close() +} + +func (b *BoltDB) CreateBucket(name string) error { + defer b.Close() + err := b.db.Update(func(tx *bolt.Tx) error { + _, err := tx.CreateBucketIfNotExists([]byte(name)) + if err != nil { + return fmt.Errorf(`create bucket: [%s]`, err) + } + b.SetNameBucket(name) + return nil + }) + if err != nil { + return err + } + return nil +} + +func (b *BoltDB) DeleteBucket(name string) error { + defer b.Close() + err := b.db.Update(func(tx *bolt.Tx) error { + err := tx.DeleteBucket([]byte(name)) + if err != nil { + return fmt.Errorf(`delete bucket: [%s]`, err) + } + b.SetNameBucket("") + return nil + }) + if err != nil { + return err + } + return nil +} + +func (b *BoltDB) Store(key, value string) error { + defer b.Close() + err := b.db.Update(func(tx *bolt.Tx) error { + buck := tx.Bucket([]byte(b.NameBucket())) + err := buck.Put([]byte(key), []byte(value)) + if err != nil { + return fmt.Errorf(`put value,key: [%s]`, err) + } + return nil + }) + + if err != nil { + return err + } + return nil +} + +func (b *BoltDB) StoreBulk(result []entity.Message) error { + defer b.Close() + err := b.db.Update(func(tx *bolt.Tx) error { + buck := tx.Bucket([]byte(b.NameBucket())) + for i := 0; i < len(result); i++ { + err := buck.Put([]byte(result[i].AtrId), []byte(result[i].Value)) + if err != nil { + return fmt.Errorf(`put value,key: [%s]`, err) + } + } + return nil + }) + if err != nil { + return err + } + return nil +} + +func (b *BoltDB) DeleteKey(key string) error { + defer b.Close() + err := b.db.Update(func(tx *bolt.Tx) error { + buck := tx.Bucket([]byte(b.NameBucket())) + err := buck.Delete([]byte(key)) + if err != nil { + return fmt.Errorf(`delete key: [%s]`, err) + } + return nil + }) + if err != nil { + return err + } + return nil +} + +func (b *BoltDB) BucketIsCreate() bool { + defer b.Close() + b.db.View(func(tx *bolt.Tx) error { + buck := tx.Bucket([]byte(b.NameBucket())) + if buck == nil { + b.SetNameBucket("") + } + return nil + }) + return b.nameBucket != "" +} + +func (b *BoltDB) GetAllValue() { + defer b.Close() + b.db.View(func(tx *bolt.Tx) error { + buck := tx.Bucket([]byte(b.NameBucket())) + res := make([]entity.Message, 0) + buck.ForEach(func(k, v []byte) error { + m := entity.Message{AtrId: string(k), Value: string(v)} + res = append(res, m) + return nil + }) + b.SetMessage(res) + return nil + }) +} + +func (b *BoltDB) GetValueFromBucket(key string) error { + defer b.Close() + err := b.db.View(func(tx *bolt.Tx) error { + buck := tx.Bucket([]byte(b.NameBucket())) + value := buck.Get([]byte(key)) + if value == nil { + return fmt.Errorf("key [%s] not found in bucket [%s]", key, b.NameBucket()) + } + m := entity.Message{ + AtrId: string(key), + Value: string(value), + } + b.SetMessage([]entity.Message{m}) + return nil + }) + if err != nil { + return err + } + return nil +} diff --git a/pkg/boltdb/bolt_db_test.go b/pkg/boltdb/bolt_db_test.go new file mode 100644 index 0000000..3846ce5 --- /dev/null +++ b/pkg/boltdb/bolt_db_test.go @@ -0,0 +1,77 @@ +package boltdb + +import ( + "log" + "testing" + + "github.com/stretchr/testify/require" +) + +var bdb, _ = NewBoltDB(`/tmp/bolt_test.db`) + +var key = `config_dir_path` +var value = `~/ovpnconfigs` + +func TestBucketIsCreateFalse(t *testing.T) { + bdb.SetNameBucket(`general_configure`) + bdb.ReOpen() + create := bdb.BucketIsCreate() + require.False(t, create, "") +} + +func TestCreateBucket(t *testing.T) { + bdb.ReOpen() + err := bdb.CreateBucket(`general_configure`) + if err != nil { + log.Fatal(err) + } +} + +func TestBucketIsCreateTrue(t *testing.T) { + bdb.SetNameBucket(`general_configure`) + bdb.ReOpen() + create := bdb.BucketIsCreate() + require.True(t, create, "") +} + +func TestStore(t *testing.T) { + bdb.SetNameBucket(`general_configure`) + bdb.ReOpen() + err := bdb.Store(key, value) + if err != nil { + log.Fatal(err) + } +} + +func TestGetAllValue(t *testing.T) { + defer bdb.Close() + bdb.SetNameBucket(`general_configure`) + bdb.ReOpen() + bdb.GetAllValue() + m := bdb.Message() + for _, e := range m { + require.Contains(t, e.AtrId, key) + require.Contains(t, e.Value, value) + } +} + +func TestGetValueFromBucket(t *testing.T) { + bdb.SetNameBucket(`general_configure`) + bdb.ReOpen() + err := bdb.GetValueFromBucket(`config_dir_path`) + if err != nil { + log.Fatal(err) + } + m := bdb.Message() + require.Contains(t, m[0].AtrId, key) + require.Contains(t, m[0].Value, value) +} + +func TestDeleteKey(t *testing.T) { + bdb.SetNameBucket(`general_configure`) + bdb.ReOpen() + err := bdb.DeleteKey(key) + if err != nil { + log.Fatal(err) + } +} diff --git a/scripts/build_appimage.sh b/scripts/build_appimage.sh index 2665f9e..91c6fc6 100755 --- a/scripts/build_appimage.sh +++ b/scripts/build_appimage.sh @@ -1,8 +1,10 @@ -#!/bin/bash +#!/usr/bin/env bash + set -eux +version=`grep -r 'version' nfpm.yaml | awk '{ print $NF }' | tr -d \"v` dir_build='/tmp/AppDir' -[ -f ./cmd/app/goovpn ] || exit 0 +[ -f ./build/bin/goovpn ] || exit 0 mkdir -p ${dir_build}/goovpn/ mkdir -p ${dir_build}/goovpn/usr/bin/ @@ -11,7 +13,7 @@ mkdir -p ${dir_build}/goovpn/usr/lib/ mkdir -p ${dir_build}/goovpn/usr/share/icons/hicolor/128x128/apps/ mkdir -p ${dir_build}/goovpn/etc/goovpn/ -cp ./cmd/app/goovpn ${dir_build}/goovpn/usr/sbin/goovpn +cp ./build/bin/goovpn ${dir_build}/goovpn/usr/sbin/goovpn chmod +x ${dir_build}/goovpn/usr/sbin/goovpn cat < ${dir_build}/goovpn/usr/bin/goovpn @@ -20,21 +22,17 @@ cat < ${dir_build}/goovpn/usr/bin/goovpn dir=\$(dirname \$PWD) cmd=\${dir}/usr/sbin/goovpn -mkdir -p /tmp/appimage_root/ \$HOME/.config/goovpn/ -if [ ! -f \$HOME/.config/goovpn/config.yml ]; then - cp \${dir}/etc/goovpn/config.yml \$HOME/.config/goovpn/ -fi +mkdir -p /tmp/appimage_root/ \$HOME/.config/goovpn/ cp \$cmd /tmp/appimage_root/ - pkexec --disable-internal-agent \ -env DISPLAY=\$DISPLAY XAUTHORITY=\$XAUTHORITY \ -/tmp/appimage_root/goovpn -config \$HOME/.config/goovpn/config.yml - +env DISPLAY=\$DISPLAY SUDO_USER=\$USER \ +DB_GOOVPN=\$HOME/.config/goovpn/goovpn.db \ +XAUTHORITY=\$XAUTHORITY /tmp/appimage_root/goovpn EOF + chmod +x ${dir_build}/goovpn/usr/bin/goovpn -cp ./config/config.yml ${dir_build}/goovpn/etc/goovpn/config.yml cat < ${dir_build}/goovpn/goovpn.desktop [Desktop Entry] @@ -50,7 +48,8 @@ sed -i 's/HOME/\\$HOME/'g ${dir_build}/goovpn/goovpn.desktop cp ./embedfile/assets/app.png ${dir_build}/goovpn/goovpn.png cp ./embedfile/assets/app.png ${dir_build}/goovpn/usr/share/icons/hicolor/128x128/apps/goovpn.png -ldd ./cmd/app/goovpn | grep "=> /" | awk '{print $3}' | xargs -I '{}' cp -v '{}' ${dir_build}/goovpn/usr/lib/ +ldd ./build/bin/goovpn | grep "=> /" | awk '{print $3}' | \ +xargs -I '{}' cp -v '{}' ${dir_build}/goovpn/usr/lib/ url='https://github.com/AppImage/AppImageKit/releases/download/continuous/AppRun-x86_64' wget -O ${dir_build}/goovpn/AppRun ${url} @@ -62,6 +61,7 @@ chmod +x ${dir_build}/appimagetool-x86_64.AppImage cd ${dir_build}/ && ARCH=x86_64 ./appimagetool-x86_64.AppImage -v -n --comp xz goovpn cd - || exit -mv ${dir_build}/Goovpn-x86_64.AppImage ./build/package/ +mv ${dir_build}/Goovpn-x86_64.AppImage \ +./build/package/Goovpn-${version}_x86_64.AppImage rm -rf ${dir_build}/ diff --git a/scripts/goovpn b/scripts/goovpn index fb96397..d7c4121 100755 --- a/scripts/goovpn +++ b/scripts/goovpn @@ -1,5 +1,5 @@ #!/usr/bin/env bash pkexec --disable-internal-agent \ -env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY \ -'/usr/sbin/goovpn' "$@" +env DISPLAY=$DISPLAY SUDO_USER=$USER DB_GOOVPN=/etc/goovpn/goovpn.db \ +XAUTHORITY=$XAUTHORITY '/usr/sbin/goovpn' "$@" diff --git a/scripts/goovpn.desktop b/scripts/goovpn.desktop index ff1eac6..c2271b0 100644 --- a/scripts/goovpn.desktop +++ b/scripts/goovpn.desktop @@ -1,7 +1,7 @@ [Desktop Entry] Name=Goovpn -Exec=goovpn -config /etc/goovpn/config.yml %f +Exec=goovpn %f Icon=/usr/share/icons/hicolor/128x128/apps/goovpn.png Terminal=false Type=Application -Categories=Network;Qt; +Categories=Network;Wails; diff --git a/test/mocks/packages/usecaserepomocks/usecase_repo_mocks.go b/test/mocks/packages/usecaserepomocks/usecase_repo_mocks.go index 6a1e843..5861393 100644 --- a/test/mocks/packages/usecaserepomocks/usecase_repo_mocks.go +++ b/test/mocks/packages/usecaserepomocks/usecase_repo_mocks.go @@ -50,27 +50,54 @@ func (mr *MockSessionSettersMockRecorder) SetConfig(config interface{}) *gomock. } // SetCread mocks base method. -func (m *MockSessionSetters) SetCread(user, pwd string) { +func (m *MockSessionSetters) SetCread(u, p string) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetCread", user, pwd) + ret := m.ctrl.Call(m, "SetCread", u, p) + ret0, _ := ret[0].(error) + return ret0 } // SetCread indicates an expected call of SetCread. -func (mr *MockSessionSettersMockRecorder) SetCread(user, pwd interface{}) *gomock.Call { +func (mr *MockSessionSettersMockRecorder) SetCread(u, p interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCread", reflect.TypeOf((*MockSessionSetters)(nil).SetCread), user, pwd) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCread", reflect.TypeOf((*MockSessionSetters)(nil).SetCread), u, p) +} + +// MockSessionLoger is a mock of SessionLoger interface. +type MockSessionLoger struct { + ctrl *gomock.Controller + recorder *MockSessionLogerMockRecorder +} + +// MockSessionLogerMockRecorder is the mock recorder for MockSessionLoger. +type MockSessionLogerMockRecorder struct { + mock *MockSessionLoger } -// SetSession mocks base method. -func (m *MockSessionSetters) SetSession() { +// NewMockSessionLoger creates a new mock instance. +func NewMockSessionLoger(ctrl *gomock.Controller) *MockSessionLoger { + mock := &MockSessionLoger{ctrl: ctrl} + mock.recorder = &MockSessionLogerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockSessionLoger) EXPECT() *MockSessionLogerMockRecorder { + return m.recorder +} + +// ChanVpnLog mocks base method. +func (m *MockSessionLoger) ChanVpnLog() chan string { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetSession") + ret := m.ctrl.Call(m, "ChanVpnLog") + ret0, _ := ret[0].(chan string) + return ret0 } -// SetSession indicates an expected call of SetSession. -func (mr *MockSessionSettersMockRecorder) SetSession() *gomock.Call { +// ChanVpnLog indicates an expected call of ChanVpnLog. +func (mr *MockSessionLogerMockRecorder) ChanVpnLog() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSession", reflect.TypeOf((*MockSessionSetters)(nil).SetSession)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChanVpnLog", reflect.TypeOf((*MockSessionLoger)(nil).ChanVpnLog)) } // MockSessionManager is a mock of SessionManager interface. @@ -96,10 +123,24 @@ func (m *MockSessionManager) EXPECT() *MockSessionManagerMockRecorder { return m.recorder } +// DestroyClient mocks base method. +func (m *MockSessionManager) DestroyClient() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "DestroyClient") +} + +// DestroyClient indicates an expected call of DestroyClient. +func (mr *MockSessionManagerMockRecorder) DestroyClient() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DestroyClient", reflect.TypeOf((*MockSessionManager)(nil).DestroyClient)) +} + // StartSession mocks base method. -func (m *MockSessionManager) StartSession(ctx context.Context) { +func (m *MockSessionManager) StartSession(ctx context.Context) error { m.ctrl.T.Helper() - m.ctrl.Call(m, "StartSession", ctx) + ret := m.ctrl.Call(m, "StartSession", ctx) + ret0, _ := ret[0].(error) + return ret0 } // StartSession indicates an expected call of StartSession. @@ -455,379 +496,6 @@ func (mr *MockConfigToolsMockRecorder) SearchFilesPaths() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchFilesPaths", reflect.TypeOf((*MockConfigTools)(nil).SearchFilesPaths)) } -// MockUiLoger is a mock of UiLoger interface. -type MockUiLoger struct { - ctrl *gomock.Controller - recorder *MockUiLogerMockRecorder -} - -// MockUiLogerMockRecorder is the mock recorder for MockUiLoger. -type MockUiLogerMockRecorder struct { - mock *MockUiLoger -} - -// NewMockUiLoger creates a new mock instance. -func NewMockUiLoger(ctrl *gomock.Controller) *MockUiLoger { - mock := &MockUiLoger{ctrl: ctrl} - mock.recorder = &MockUiLogerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockUiLoger) EXPECT() *MockUiLogerMockRecorder { - return m.recorder -} - -// ChanVpnLog mocks base method. -func (m *MockUiLoger) ChanVpnLog() chan string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChanVpnLog") - ret0, _ := ret[0].(chan string) - return ret0 -} - -// ChanVpnLog indicates an expected call of ChanVpnLog. -func (mr *MockUiLogerMockRecorder) ChanVpnLog() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChanVpnLog", reflect.TypeOf((*MockUiLoger)(nil).ChanVpnLog)) -} - -// MockUiLogFormManager is a mock of UiLogFormManager interface. -type MockUiLogFormManager struct { - ctrl *gomock.Controller - recorder *MockUiLogFormManagerMockRecorder -} - -// MockUiLogFormManagerMockRecorder is the mock recorder for MockUiLogFormManager. -type MockUiLogFormManagerMockRecorder struct { - mock *MockUiLogFormManager -} - -// NewMockUiLogFormManager creates a new mock instance. -func NewMockUiLogFormManager(ctrl *gomock.Controller) *MockUiLogFormManager { - mock := &MockUiLogFormManager{ctrl: ctrl} - mock.recorder = &MockUiLogFormManagerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockUiLogFormManager) EXPECT() *MockUiLogFormManagerMockRecorder { - return m.recorder -} - -// ClearLogForm mocks base method. -func (m *MockUiLogFormManager) ClearLogForm() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ClearLogForm") -} - -// ClearLogForm indicates an expected call of ClearLogForm. -func (mr *MockUiLogFormManagerMockRecorder) ClearLogForm() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClearLogForm", reflect.TypeOf((*MockUiLogFormManager)(nil).ClearLogForm)) -} - -// GetTextFromLogForm mocks base method. -func (m *MockUiLogFormManager) GetTextFromLogForm() string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTextFromLogForm") - ret0, _ := ret[0].(string) - return ret0 -} - -// GetTextFromLogForm indicates an expected call of GetTextFromLogForm. -func (mr *MockUiLogFormManagerMockRecorder) GetTextFromLogForm() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTextFromLogForm", reflect.TypeOf((*MockUiLogFormManager)(nil).GetTextFromLogForm)) -} - -// SetTextInLogForm mocks base method. -func (m *MockUiLogFormManager) SetTextInLogForm(text string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetTextInLogForm", text) -} - -// SetTextInLogForm indicates an expected call of SetTextInLogForm. -func (mr *MockUiLogFormManagerMockRecorder) SetTextInLogForm(text interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTextInLogForm", reflect.TypeOf((*MockUiLogFormManager)(nil).SetTextInLogForm), text) -} - -// MockUiButtonsManager is a mock of UiButtonsManager interface. -type MockUiButtonsManager struct { - ctrl *gomock.Controller - recorder *MockUiButtonsManagerMockRecorder -} - -// MockUiButtonsManagerMockRecorder is the mock recorder for MockUiButtonsManager. -type MockUiButtonsManagerMockRecorder struct { - mock *MockUiButtonsManager -} - -// NewMockUiButtonsManager creates a new mock instance. -func NewMockUiButtonsManager(ctrl *gomock.Controller) *MockUiButtonsManager { - mock := &MockUiButtonsManager{ctrl: ctrl} - mock.recorder = &MockUiButtonsManagerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockUiButtonsManager) EXPECT() *MockUiButtonsManagerMockRecorder { - return m.recorder -} - -// ButtonConnectDisable mocks base method. -func (m *MockUiButtonsManager) ButtonConnectDisable() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ButtonConnectDisable") -} - -// ButtonConnectDisable indicates an expected call of ButtonConnectDisable. -func (mr *MockUiButtonsManagerMockRecorder) ButtonConnectDisable() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ButtonConnectDisable", reflect.TypeOf((*MockUiButtonsManager)(nil).ButtonConnectDisable)) -} - -// ButtonConnectEnable mocks base method. -func (m *MockUiButtonsManager) ButtonConnectEnable() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ButtonConnectEnable") -} - -// ButtonConnectEnable indicates an expected call of ButtonConnectEnable. -func (mr *MockUiButtonsManagerMockRecorder) ButtonConnectEnable() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ButtonConnectEnable", reflect.TypeOf((*MockUiButtonsManager)(nil).ButtonConnectEnable)) -} - -// ButtonDisconnectDisable mocks base method. -func (m *MockUiButtonsManager) ButtonDisconnectDisable() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ButtonDisconnectDisable") -} - -// ButtonDisconnectDisable indicates an expected call of ButtonDisconnectDisable. -func (mr *MockUiButtonsManagerMockRecorder) ButtonDisconnectDisable() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ButtonDisconnectDisable", reflect.TypeOf((*MockUiButtonsManager)(nil).ButtonDisconnectDisable)) -} - -// ButtonDisconnectEnable mocks base method. -func (m *MockUiButtonsManager) ButtonDisconnectEnable() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "ButtonDisconnectEnable") -} - -// ButtonDisconnectEnable indicates an expected call of ButtonDisconnectEnable. -func (mr *MockUiButtonsManagerMockRecorder) ButtonDisconnectEnable() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ButtonDisconnectEnable", reflect.TypeOf((*MockUiButtonsManager)(nil).ButtonDisconnectEnable)) -} - -// MockUiListConfigsManager is a mock of UiListConfigsManager interface. -type MockUiListConfigsManager struct { - ctrl *gomock.Controller - recorder *MockUiListConfigsManagerMockRecorder -} - -// MockUiListConfigsManagerMockRecorder is the mock recorder for MockUiListConfigsManager. -type MockUiListConfigsManagerMockRecorder struct { - mock *MockUiListConfigsManager -} - -// NewMockUiListConfigsManager creates a new mock instance. -func NewMockUiListConfigsManager(ctrl *gomock.Controller) *MockUiListConfigsManager { - mock := &MockUiListConfigsManager{ctrl: ctrl} - mock.recorder = &MockUiListConfigsManagerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockUiListConfigsManager) EXPECT() *MockUiListConfigsManagerMockRecorder { - return m.recorder -} - -// DisableListConfigsBox mocks base method. -func (m *MockUiListConfigsManager) DisableListConfigsBox() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "DisableListConfigsBox") -} - -// DisableListConfigsBox indicates an expected call of DisableListConfigsBox. -func (mr *MockUiListConfigsManagerMockRecorder) DisableListConfigsBox() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableListConfigsBox", reflect.TypeOf((*MockUiListConfigsManager)(nil).DisableListConfigsBox)) -} - -// EnableListConfigsBox mocks base method. -func (m *MockUiListConfigsManager) EnableListConfigsBox() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "EnableListConfigsBox") -} - -// EnableListConfigsBox indicates an expected call of EnableListConfigsBox. -func (mr *MockUiListConfigsManagerMockRecorder) EnableListConfigsBox() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableListConfigsBox", reflect.TypeOf((*MockUiListConfigsManager)(nil).EnableListConfigsBox)) -} - -// SelectedCfgFromListConfigs mocks base method. -func (m *MockUiListConfigsManager) SelectedCfgFromListConfigs() *string { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SelectedCfgFromListConfigs") - ret0, _ := ret[0].(*string) - return ret0 -} - -// SelectedCfgFromListConfigs indicates an expected call of SelectedCfgFromListConfigs. -func (mr *MockUiListConfigsManagerMockRecorder) SelectedCfgFromListConfigs() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectedCfgFromListConfigs", reflect.TypeOf((*MockUiListConfigsManager)(nil).SelectedCfgFromListConfigs)) -} - -// MockSysTrayIconsManager is a mock of SysTrayIconsManager interface. -type MockSysTrayIconsManager struct { - ctrl *gomock.Controller - recorder *MockSysTrayIconsManagerMockRecorder -} - -// MockSysTrayIconsManagerMockRecorder is the mock recorder for MockSysTrayIconsManager. -type MockSysTrayIconsManagerMockRecorder struct { - mock *MockSysTrayIconsManager -} - -// NewMockSysTrayIconsManager creates a new mock instance. -func NewMockSysTrayIconsManager(ctrl *gomock.Controller) *MockSysTrayIconsManager { - mock := &MockSysTrayIconsManager{ctrl: ctrl} - mock.recorder = &MockSysTrayIconsManagerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSysTrayIconsManager) EXPECT() *MockSysTrayIconsManagerMockRecorder { - return m.recorder -} - -// SetBlinkIcon mocks base method. -func (m *MockSysTrayIconsManager) SetBlinkIcon() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetBlinkIcon") - ret0, _ := ret[0].(error) - return ret0 -} - -// SetBlinkIcon indicates an expected call of SetBlinkIcon. -func (mr *MockSysTrayIconsManagerMockRecorder) SetBlinkIcon() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlinkIcon", reflect.TypeOf((*MockSysTrayIconsManager)(nil).SetBlinkIcon)) -} - -// SetConnectIcon mocks base method. -func (m *MockSysTrayIconsManager) SetConnectIcon() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetConnectIcon") - ret0, _ := ret[0].(error) - return ret0 -} - -// SetConnectIcon indicates an expected call of SetConnectIcon. -func (mr *MockSysTrayIconsManagerMockRecorder) SetConnectIcon() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetConnectIcon", reflect.TypeOf((*MockSysTrayIconsManager)(nil).SetConnectIcon)) -} - -// SetDisconnectIcon mocks base method. -func (m *MockSysTrayIconsManager) SetDisconnectIcon() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetDisconnectIcon") - ret0, _ := ret[0].(error) - return ret0 -} - -// SetDisconnectIcon indicates an expected call of SetDisconnectIcon. -func (mr *MockSysTrayIconsManagerMockRecorder) SetDisconnectIcon() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDisconnectIcon", reflect.TypeOf((*MockSysTrayIconsManager)(nil).SetDisconnectIcon)) -} - -// SetIcon mocks base method. -func (m *MockSysTrayIconsManager) SetIcon(path string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetIcon", path) -} - -// SetIcon indicates an expected call of SetIcon. -func (mr *MockSysTrayIconsManagerMockRecorder) SetIcon(path interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetIcon", reflect.TypeOf((*MockSysTrayIconsManager)(nil).SetIcon), path) -} - -// SetOpenIcon mocks base method. -func (m *MockSysTrayIconsManager) SetOpenIcon() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SetOpenIcon") - ret0, _ := ret[0].(error) - return ret0 -} - -// SetOpenIcon indicates an expected call of SetOpenIcon. -func (mr *MockSysTrayIconsManagerMockRecorder) SetOpenIcon() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetOpenIcon", reflect.TypeOf((*MockSysTrayIconsManager)(nil).SetOpenIcon)) -} - -// MockSysTrayImagesManager is a mock of SysTrayImagesManager interface. -type MockSysTrayImagesManager struct { - ctrl *gomock.Controller - recorder *MockSysTrayImagesManagerMockRecorder -} - -// MockSysTrayImagesManagerMockRecorder is the mock recorder for MockSysTrayImagesManager. -type MockSysTrayImagesManagerMockRecorder struct { - mock *MockSysTrayImagesManager -} - -// NewMockSysTrayImagesManager creates a new mock instance. -func NewMockSysTrayImagesManager(ctrl *gomock.Controller) *MockSysTrayImagesManager { - mock := &MockSysTrayImagesManager{ctrl: ctrl} - mock.recorder = &MockSysTrayImagesManagerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockSysTrayImagesManager) EXPECT() *MockSysTrayImagesManagerMockRecorder { - return m.recorder -} - -// Image mocks base method. -func (m *MockSysTrayImagesManager) Image() map[string][]byte { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Image") - ret0, _ := ret[0].(map[string][]byte) - return ret0 -} - -// Image indicates an expected call of Image. -func (mr *MockSysTrayImagesManagerMockRecorder) Image() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Image", reflect.TypeOf((*MockSysTrayImagesManager)(nil).Image)) -} - -// SearchKeyInMap mocks base method. -func (m *MockSysTrayImagesManager) SearchKeyInMap(s string) (*string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SearchKeyInMap", s) - ret0, _ := ret[0].(*string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SearchKeyInMap indicates an expected call of SearchKeyInMap. -func (mr *MockSysTrayImagesManagerMockRecorder) SearchKeyInMap(s interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchKeyInMap", reflect.TypeOf((*MockSysTrayImagesManager)(nil).SearchKeyInMap), s) -} - // MockFileSetters is a mock of FileSetters interface. type MockFileSetters struct { ctrl *gomock.Controller