commit 414692240a2c4f92de5dcb9e610b4b7340f6472b Author: aitzol Date: Sat Apr 9 17:38:00 2022 +0200 first release diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..805bb57 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +/settings.ini +/settings.ini.example.original +session \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..805bb57 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/settings.ini +/settings.ini.example.original +session \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..375f1e2 --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# LDAP kudeaketarako Web Interfazea +[base]: https://github.com/jirutka/ldap-passwd-webui +[proiektu-izena]: ldap-python-webui +[git-izena]: aitzol/[proiektu-izena] +[pypi-bottle]: https://pypi.python.org/pypi/bottle/ +[pypi-ldap3]: https://pypi.python.org/pypi/ldap3 +[settings]: https://git.lainoa.eus/aitzol/ldap-python-webui/src/branch/master/settings.ini.example +[LICENSE]: https://www.gnu.org/licenses/gpl-3.0.txt +[GPL3]: https://www.gnu.org/licenses/licenses.html +[wsgiref]: https://docs.python.org/3/library/wsgiref.html#module-wsgiref.simple_server +[WSGI]: https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface +[LDAP]: https://eu.wikipedia.org/wiki/LDAP +[fork]: https://github.com/jirutka/ldap-passwd-webui + +Proiektu honen helburua erabiltzaileei [LDAP][LDAP] protokoloa erabiltzen duten zerbitzuetan norberaren kontuaren kudeaketarako tresna bat eskaintzea da, kontua sortu, pasahitza aldatu eta oinarrizko beste eragiketa batzuk burutzeko aukera emanez. [Bottle](http://bottlepy.org), Python-en WSGI web-framework-a erabiliz dago eraikia, [@jirutka][fork]-ren _ldap-passwd-webui_ proiektuan oinarritua. + +## Instalakuntza + +#### Baldintzak + +* Python 3.x +* [bottle][pypi-bottle] +* [ldap3][pypi-ldap3] 2.x + +### Urratsak + +Biltegi honetako edukiak klonatu eta menpekotasunak instalatu: + + git clone https://git.lainoa.eus/aitzol/ldap-python-webui + cd ldap-python-webui + pip install -r requirements.txt + +## Abian jarri + +#### Konfiguraketa + +Konfiguraketa [settings.ini][settings] fitxategian ezartzen da. Fitxategi honen kokapena `CONF_FILE` ingurumen-aldagaia erabiliz zehaztu daiteke. + +#### Ingurunea + +`LDAP_ADMIN_PASSWORD` eta `LDAP_READONLY_PASSWORD` _environment_ edo ingurumen-aldagaiak sisteman ezarri. + +#### Abiarazteko aukerak + +* [WSGI][WSGI] zerbitzariaren bidez, [wsgiref][wsgiref]-en oinarritua: + +``` + uwsgi --http :8080 --enable-threads --wsgi-file app.py +``` + +* Berezko Bottle zerbitzariaren bidez zuzenean `app.py` exekutatuz: + +``` + cd ldap-python-webui + python3 app.py +``` + +* Ondoren nabigatzailean http://localhost:8080 helbidea ireki + +## Ezaugarriak +* Saioa hasi + > Erabiltzaile izena eta pasahitzaz LDAP zerbitzarian saioa hasi. +* Izen-abizenak(aukerakoa) editatu +* Email helbidea editatu +* Pasahitza aldatu +* kontua ezabatu +* Kontua sortu + > Gonbidapen kodea erabiliz +* Lokalizazioa/Hizkuntza egokitzeko aukera + +## Egiteke + +* Erabiltzaileari ePosta bidez kontua aktibatzeko eskatzea. +* Pasahitza berrezartzen denean erabiltzaileari ePosta bidez jakinaraztea. + +## Screenshot + +![alt text](data/screenshot.png "Screenshot") + + +## Lizentzia + +Lan hau [GPL License][GPL3] lizentziapean aurkitzen da. +Lizentziaren textu osoa eskuratzeko ikusi ondorengo [esteka][LICENSE]. \ No newline at end of file diff --git a/app.py b/app.py new file mode 100644 index 0000000..605ea97 --- /dev/null +++ b/app.py @@ -0,0 +1,981 @@ +#!/usr/bin/env python3 + +''' +ldap-python-webui :: LDAP kudeaketarako Web Interfazea - Web UI for LDAP management. +Copyright (C) 2022 Aitzol Berasategi - Wproject + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +''' + +import bottle +from bottle import get, post, static_file, request, route, template +from bottle import SimpleTemplate +from bottle.ext import beaker +from configparser import ConfigParser +from ldap3 import Server, Connection, ALL +from ldap3 import SIMPLE, SUBTREE, MODIFY_REPLACE, ALL_ATTRIBUTES +from ldap3.core.exceptions import LDAPBindError, LDAPConstraintViolationResult, \ + LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError, \ + LDAPSocketOpenError, LDAPExceptionError +import logging +from os import getenv, environ, path +import re +import sqlite3 +from data import flist, slist +import random +import gettext + +BASE_DIR = path.dirname(__file__) +LOG = logging.getLogger(__name__) +LOG_FORMAT = '%(asctime)s %(levelname)s: %(message)s' +VERSION = '0.0.1' + +@get('/') +def get_index(): + try: + return user_tpl(data=newSession().get(), str=i18n.str) + except Exception as e: + return index_tpl(str=i18n.str) + +@get('/user') +def get_index(): + try: + return user_tpl(data=newSession().get(), str=i18n.str) + except Exception as e: + return index_tpl(str=i18n.str) + +@get('/signup') +def get_index(): + newSession() + return signup_tpl(str=i18n.str) + +@get('/change_pwd') +def get_index(): + try: + return change_pwd_tpl(data=newSession().get(), str=i18n.str) + except Exception as e: + return index_tpl(str=i18n.str) + +@get('/edit_fullname') +def get_index(): + try: + return edit_fullname_tpl(data=newSession().get(), str=i18n.str) + except Exception as e: + return index_tpl(str=i18n.str) + +@get('/edit_email') +def get_index(): + try: + return edit_email_tpl(data=newSession().get(), str=i18n.str) + except Exception as e: + return index_tpl(str=i18n.str) + +@get('/delete') +def get_index(): + try: + return delete_tpl(data=newSession().get(), str=i18n.str) + except Exception as e: + return index_tpl(str=i18n.str) + +@get('/logout') +def get_index(): + + def error(msg): + return index_tpl(alerts=[('error', msg, 'fadeOut')], str=i18n.str) + + try: + username = newSession().get()['username'] + if(username is not None): + logout(username) + except Error as e: + LOG.warning("Unsuccessful attempt to log out: %s" % e) + return error(str(e)) + + return index_tpl(alerts=[('success', i18n.msg[0], 'fadeOut')], str=i18n.str) + +@post('/user') +def post_user(): + form = request.forms.getunicode + + def error(msg): + return index_tpl(alerts=[('error', msg, 'fadeOut')], str=i18n.str) + + if len(form('username')) < 3: + return error(i18n.msg[1]) + + if len(form('password')) < 1: + return error(i18n.msg[2]) + + try: + login(form('username'), form('password')) + except Error as e: + LOG.warning("Unsuccessful attempt to login %s: %s" % (form('username'), e)) + return error(str(e)) + + return user_tpl(alerts=[('success', '%s %s' % (i18n.msg[3], form('username').capitalize()), 'fadeOut' )], data=newSession().get(), str=i18n.str) + +@post('/signup') +def post_signup(): + #ensure that i18n exists + if 'i18n' not in globals(): + newSession() + + form = request.forms.getunicode + isFake = False + + def username_validation(e): + regex = r'^\w+$' + return(bool(re.fullmatch(regex, e))) + + def email_validation(e): + regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' + return(bool(re.fullmatch(regex, e))) + + def code_is_valid(code): + con = sqlite3.connect('data/invite-codes.db') + cur = con.cursor() + + codes=[] + for row in cur.execute('SELECT * FROM codes WHERE valid = 1'): + codes.append(row[0]) + + return(bool(code in codes)) + + def mark_code_as_used(code): + con = sqlite3.connect('data/invite-codes.db') + cur = con.cursor() + + cur.execute('''UPDATE codes SET valid=? WHERE code==?''',(0, code)) + con.commit() + + def auto_complete(arg): + if arg == 'firstname': + result = random.choice(flist.firstname) + elif arg == 'surname': + result = random.choice(slist.surname) + return(result.lower()) + + def error(msg): + return signup_tpl(alerts=[('error', msg, 'fadeOut')], str=i18n.str) + + if not code_is_valid(form('invite_code')): + return(error(i18n.msg[4])) + + if len(form('username')) < 3: + return error(i18n.msg[5]) + + username = form('username').lower() + if not username_validation(username): + return error(i18n.msg[6]) + + if len(form('firstname')) == 0: + firstname = auto_complete('firstname') + isFake = True + else: + firstname = form('firstname').lower() + + if len(form('surname')) == 0: + surname = auto_complete('surname') + isFake = True + else: + surname = form('surname').lower() + + email = form('email').lower() + + if form('password') != form('confirm-password'): + return error(i18n.msg[7]) + + if len(form('password')) < 8: + return error(i18n.msg[8]) + + try: + account_request(username, firstname, surname, form('password'), email, isFake) + except Error as e: + LOG.warning("Unsuccessful attempt to create an account for %s: %s" % (form('username'), e)) + return error(str(e)) + + try: + mark_code_as_used(form('invite_code')) + except Error as e: + LOG.warning("There was a problem verifying the invitation code, please try again later.", e) + return error(str(e)) + + LOG.info("New account successfully created for %s" % form('username')) + + return index_tpl(alerts=[('success', i18n.msg[9], 'fadeOut')], str=i18n.str) + +@post('/edit_fullname') +def post_edit_fullname(): + form = request.forms.getunicode + + try: + username = newSession().get()['username'] + old_firstname = newSession().get()['firstname'] + old_surname = newSession().get()['surname'] + except Error as e: + return index_tpl(alerts=[('error', str(e), 'fadeOut')], str=i18n.str) + + def error(msg): + return edit_fullname_tpl(alerts=[('error', msg, 'fadeOut')], data=newSession().get(), str=i18n.str) + + if len(form('firstname')) < 3: + return error(i18n.msg[10]) + + if len(form('surname')) < 3: + return error(i18n.msg[11]) + + try: + edit_fullname(username, old_firstname, old_surname, form('firstname').lower(), form('surname').lower()) + except Error as e: + LOG.warning("Unsuccessful attempt to edit fullname for %s: %s" % (username, e)) + return error(str(e)) + + return user_tpl(alerts=[('success', i18n.msg[12], 'fadeOut' )], data=newSession().get(), str=i18n.str) + +@post('/edit_email') +def post_edit_email(): + form = request.forms.getunicode + + try: + username = newSession().get()['username'] + old_email = newSession().get()['mail'] + except Error as e: + return index_tpl(alerts=[('error', str(e), 'fadeOut')], str=i18n.str) + + def email_is_valid(e): + regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' + return(bool(re.fullmatch(regex, e))) + + def error(msg): + return edit_email_tpl(alerts=[('error', msg, 'fadeOut')], data=newSession().get(), str=i18n.str) + + if not email_is_valid(form('email')): + return(error(i18n.msg[13])) + + try: + edit_email(username, old_email, form('email').lower()) + except Error as e: + LOG.warning("Unsuccessful attempt to change email addres for %s: %s" % (username, e)) + return error(str(e)) + + return user_tpl(alerts=[('success', i18n.msg[14], 'fadeOut' )], data=newSession().get(), str=i18n.str) + +@post('/change_pwd') +def post_change_pwd(): + form = request.forms.getunicode + try: + username=newSession().get()['username'] + except Error as e: + return index_tpl(alerts=[('error', str(e), 'fadeOut')], str=i18n.str) + + def error(msg): + return change_pwd_tpl(username=username, alerts=[('error', msg, 'fadeOut')], str=i18n.str) + + if form('new-password') != form('confirm-password'): + return error(i18n.msg[7]) + + if len(form('new-password')) < 8: + return error(i18n.msg[8]) + + if form('old-password') == form('confirm-password'): + return error(i18n.msg[15]) + + try: + change_passwords(username, form('old-password'), form('new-password')) + logout(username) + except Error as e: + LOG.warning("Unsuccessful attempt to change password for %s: %s" % (username, e)) + return error(str(e)) + + LOG.info("Password successfully changed for: %s" % username) + + return index_tpl(alerts=[('success', i18n.msg[16], 'fadeOut')], username=username, str=i18n.str) + +@post('/delete') +def post_delete(): + form = request.forms.getunicode + + def error(msg): + return delete_tpl(alerts=[('error', msg, 'fadeOut')], str=i18n.str) + + try: + username = newSession().get()['username'] + if(form('username').lower() == username): + del_user(username) + else: + return(error(i18n.msg[17])) + except Error as e: + LOG.warning("Unsuccessful attempt to delete the account: %s" % e) + return error(str(e)) + + LOG.info("Account successfully deleted") + + return index_tpl(alerts=[('success', i18n.msg[18], 'fadeOut')], str=i18n.str) + +@route('/static/', name='static') +def serve_static(filename): + return static_file(filename, root=path.join(BASE_DIR, 'static')) + +def index_tpl(**kwargs): + return template('index', **kwargs) + +def user_tpl(**kwargs): + return template('user', **kwargs) + +def signup_tpl(**kwargs): + return template('signup', **kwargs) + +def change_pwd_tpl(**kwargs): + return template('change_pwd', **kwargs) + +def edit_email_tpl(**kwargs): + return template('edit_email', **kwargs) + +def edit_fullname_tpl(**kwargs): + return template('edit_fullname', **kwargs) + +def delete_tpl(**kwargs): + return template('delete', **kwargs) + +def connect_ldap(conf, **kwargs): + server = Server(host=conf['host'], + port=conf.getint('port', None), + use_ssl=conf.getboolean('use_ssl', False), + connect_timeout=5) + + return Connection(server, raise_exceptions=True, **kwargs) + +#LOGIN +def login(username, password): + n = N + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("%s is trying to logging in %s" % (username, key)) + n -= 1 + try: + login_user(CONF[key], username, password) + except Error as e: + if n >=1: + e = [] + continue + else: + raise e + + break + +def login_user(conf, *args): + try: + login_user_ldap(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[19]) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + +def login_user_ldap(conf, username, password): + #set current LDAP + superUser = SuperUsers(conf) + + #with connect_ldap(conf) as c: + with connect_ldap(conf, user=superUser.readonly_dn, password=superUser.readonly_pwd) as c: + user_dn = find_user_dn(conf, c, username) + + # Note: raises LDAPUserNameIsMandatoryError when user_dn is None. + with connect_ldap(conf, authentication=SIMPLE, user=user_dn, password=password) as c: + c.bind() + newSession().set(get_user_data(user_dn, c)) + LOG.debug("%s logged in to %s" % (username, conf['base'])) + +#LOGOUT +def logout(username): + n = N + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("Logging out %s from %s" % (username, key)) + n -= 1 + try: + logout_user(CONF[key], username) + except Error as e: + if n >=1: + e = [] + continue + else: + raise e + + break + +def logout_user(conf, *args): + try: + logout_user_ldap(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[19]) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + +def logout_user_ldap(conf, username): + #set current LDAP + superUser = SuperUsers(conf) + + #with connect_ldap(conf) as c: + with connect_ldap(conf, user=superUser.readonly_dn, password=superUser.readonly_pwd) as c: + user_dn = find_user_dn(conf, c, username) + c.unbind() + #newSession().close() + newSession().delete() + LOG.info("%s LOGED OUT" % (username)) + +#SIGN UP +def account_request(username, firstname, surname, password, email, isFake): + created = [] + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("Creating account for %s on %s server" % (username, key)) + try: + new_user_account(CONF[key], username, firstname, surname, password, email, isFake) + created.append(key) + except Error as e: + for key in reversed(created): + LOG.info("Reverting account creation in %s for %s" % (key, username)) + try: + #Akatsen bat gertatzen bada LDAP instantzia guztietan kontua ezabatu + del_account(CONF[key], username) + except Error as e2: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e2)) + raise e + +def new_user_account(conf, *args): + try: + register(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[19]) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + +def register(conf, username, firstname, surname, password, email, isFake): + + def to_ascii(str): + ascii_str="" + for c in str: + if 0 <= ord(c) <= 127: + ascii_str=ascii_str+c + else: + ascii_str=ascii_str+"X" + return(ascii_str) + + #set current LDAP + superUser = SuperUsers(conf) + + with connect_ldap(conf, user=superUser.admin_dn, password=superUser.admin_pwd) as c: + + try: + if (find_user_dn(conf,c,username) is not None): + raise Error(i18n.msg[22]) + + if (find_email(conf,c,email)): + raise Error(i18n.msg[23]) + + except Error as e: + raise e + + else: + #create new account + uidNumber = find_uid_number(conf,c)+1 + directory = 'home/user/'+to_ascii(username) + OBJECT_CLASS = ['top', 'inetOrgPerson', 'posixAccount', 'accountsManagement'] + attributes = {'gidNumber': '501', 'uidNumber': uidNumber, 'homeDirectory': directory, 'givenName': firstname, 'sn': surname, 'uid' : username, 'mail': email, 'active': False, 'fakeCn': isFake} + new_user_dn = "cn="+firstname+" "+ surname+",cn=users,"+conf['base'] + c.add(dn=new_user_dn,object_class=OBJECT_CLASS, attributes=attributes) + #create/change user password + c.extend.standard.modify_password(new_user_dn, '', password) + LOG.info("%s has registered on %s" % (username, conf)) + +#EDIT FULLNAME +def edit_fullname(username, old_firstname, old_surname, firstname, surname,): + changed = [] + + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("Changing fullname in %s for %s" % (key, username)) + try: + new_fullname(CONF[key], username, firstname, surname) + changed.append(key) + LOG.debug("%s changed fullname on %s" % (username, key)) + except Error as e: + for key in reversed(changed): + LOG.info("Reverting fullname change in %s for %s" % (key, username)) + try: + new_fullname(CONF[key], username, old_firstname, old_surname) + except Error as e2: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e2)) + raise e + +def new_fullname(conf, *args): + try: + update_fullname(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[24]) + + except LDAPConstraintViolationResult as e: + # Extract useful part of the error message (for Samba 4 / AD). + msg = e.message.split('check_password_restrictions: ')[-1].capitalize() + raise Error(msg) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + +def update_fullname(conf, username, firstname, surname): + #set current LDAP + superUser = SuperUsers(conf) + + with connect_ldap(conf, user=superUser.admin_dn, password=superUser.admin_pwd) as c: + #with connect_ldap(conf) as c: + user_dn = find_user_dn(conf, c, username) + c.modify(user_dn, {'givenName': [( MODIFY_REPLACE, firstname )], 'sn': [( MODIFY_REPLACE, surname )]}) + + new_cn = "cn="+firstname+" "+ surname + c.modify_dn(user_dn, new_cn) + new_user_dn = new_cn+",cn=users,"+conf['base'] + + base = ",cn=users," + conf['base'] + fakeFullName = user_dn[3:-len(base)].split(" ") + + if(user_dn == new_user_dn): + raise Error('Izen-abizenak ez dira aldatu.') + + c.modify(new_user_dn, {'fakeCn': [(MODIFY_REPLACE, 'false' )]}) + newSession().set(get_user_data(new_user_dn, c)) + +#EDIT EMAIL +def edit_email(username, old_email, new_email): + changed = [] + + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("Changing email in %s for %s" % (key, username)) + try: + new_email_address(CONF[key], username, old_email, new_email) + changed.append(key) + LOG.debug("%s changed email address on %s" % (username, key)) + except Error as e: + for key in reversed(changed): + LOG.info("Reverting email change in %s for %s" % (key, username)) + try: + new_email_address(CONF[key], username, new_email, old_email) + except Error as e2: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e2)) + raise e + +def new_email_address(conf, *args): + try: + update_email_address(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[24]) + + except LDAPConstraintViolationResult as e: + # Extract useful part of the error message (for Samba 4 / AD). + msg = e.message.split('check_password_restrictions: ')[-1].capitalize() + raise Error(msg) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + + +def update_email_address(conf, username, old_email, new_email): + if(old_email == new_email): + raise Error('Email helbidea ez da aldatu.') + + #set current LDAP + superUser = SuperUsers(conf) + + with connect_ldap(conf, user=superUser.admin_dn, password=superUser.admin_pwd) as c: + user_dn = find_user_dn(conf, c, username) + new_email_addresses = get_user_email_array(user_dn, c, old_email, new_email) + c.modify(user_dn, {'mail': [( MODIFY_REPLACE, new_email_addresses )]}) + newSession().set(get_user_data(user_dn, c)) + +#CHANGE PASSWORD +def change_passwords(username, old_pass, new_pass): + changed = [] + + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + + LOG.debug("Changing password in %s for %s" % (key, username)) + try: + change_password(CONF[key], username, old_pass, new_pass) + changed.append(key) + LOG.debug("%s changed pwd on %s" % (username, key)) + except Error as e: + for key in reversed(changed): + LOG.info("Reverting password change in %s for %s" % (key, username)) + try: + change_password(CONF[key], username, new_pass, old_pass) + except Error as e2: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e2)) + raise e + +def change_password(conf, *args): + try: + if conf.get('type') == 'ad': + change_password_ad(conf, *args) + else: + change_password_ldap(conf, *args) + + except (LDAPBindError, LDAPInvalidCredentialsResult, LDAPUserNameIsMandatoryError): + raise Error(i18n.msg[24]) + + except LDAPConstraintViolationResult as e: + # Extract useful part of the error message (for Samba 4 / AD). + msg = e.message.split('check_password_restrictions: ')[-1].capitalize() + raise Error(msg) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + + +def change_password_ldap(conf, username, old_pass, new_pass): + #set current LDAP + superUser = SuperUsers(conf) + + with connect_ldap(conf, user=superUser.readonly_dn, password=superUser.readonly_pwd) as c: + #with connect_ldap(conf) as c: + user_dn = find_user_dn(conf, c, username) + + # Note: raises LDAPUserNameIsMandatoryError when user_dn is None. + with connect_ldap(conf, authentication=SIMPLE, user=user_dn, password=old_pass) as c: + c.bind() + c.extend.standard.modify_password(user_dn, old_pass, new_pass) + +def change_password_ad(conf, username, old_pass, new_pass): + user = username + '@' + conf['ad_domain'] + + with connect_ldap(conf, authentication=SIMPLE, user=user, password=old_pass) as c: + c.bind() + user_dn = find_user_dn(conf, c, username) + c.extend.microsoft.modify_password(user_dn, new_pass, old_pass) + +#DELETE ACCOUNT +def del_user(username): + n = N + for key in (key for key in CONF.sections() + if key == 'ldap' or key.startswith('ldap:')): + LOG.debug("Deleting account for %s from %s" % (username, key)) + n -= 1 + try: + del_account(CONF[key], username) + LOG.debug("Account for %s deleted on -> %s" % (username, CONF[key])) + if(n == 0 and newSession().get()['username'] is not None): + newSession().delete() + + except Error as e: + raise e + +def del_account(conf, *args): + try: + delete(conf, *args) + + except LDAPSocketOpenError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[20]) + + except LDAPExceptionError as e: + LOG.error('{}: {!s}'.format(e.__class__.__name__, e)) + raise Error(i18n.msg[21]) + +def delete(conf, username): + #set current LDAP + superUser = SuperUsers(conf) + + with connect_ldap(conf, user=superUser.admin_dn, password=superUser.admin_pwd) as c: + try: + user_dn = find_user_dn(conf, c, username) + c.delete(user_dn) + + except Error as e: + raise e + +#AUXILIARY FUNCTIONS +#find user +def find_user_dn(conf, conn, uid): + search_filter = conf['search_filter'].replace('{uid}', uid) + conn.search(conf['base'], "(%s)" % search_filter, SUBTREE) + + return conn.response[0]['dn'] if conn.response else None + +#find email +def find_email(conf, conn, email): + search_filter = '(uid=*)' + if conn.search(conf['base'], search_filter, attributes=['mail']): + for i in conn.response: + for j in i['attributes']['mail']: + if(j == email): + return True + + return False + +#find highest uidNumber +def find_uid_number(conf, conn): + search_filter = '(uid=*)' + if conn.search(conf['base'], search_filter, attributes=['uidNumber']): + + uidNumbersList=[] + for i in conn.response: + uidNumbersList.append(i['attributes']['uidNumber']) + + return max(uidNumbersList) + + else: + return(999) + +def get_user_email_array(user_dn, conn, old_email, new_email): + search_filter = '(objectClass=*)' + conn.search(user_dn, search_filter, attributes=['mail']) + emails = conn.entries[0].mail.values + for i in range(len(emails)): + if(emails[i] == old_email): + emails[i] = new_email + return(emails) + +def get_user_data(user_dn, conn): + search_filter = '(objectClass=*)' + conn.search(user_dn, search_filter, attributes=['active','fakeCn','givenName','sn','uid','mail']) + data = [] + data.append(conn.entries[0].active.values[0]) + data.append(conn.entries[0].fakeCn.values[0]) + data.append(conn.entries[0].givenName.values[0]) + data.append(conn.entries[0].sn.values[0]) + data.append(conn.entries[0].uid.values[0]) + data.append(conn.entries[0].mail.values[0]) + return(data) + +def read_config(): + config = ConfigParser() + config.read([path.join(BASE_DIR, 'settings.ini'), getenv('CONF_FILE', '')]) + return config + +CONF = read_config() + +def ldaps_count(): + keys = [] + for i, key in enumerate(CONF.sections()): + if key == 'ldap' or key.startswith('ldap:'): + keys.append(key) + #n=len(keys) + return(len(keys)) + +N = ldaps_count() + +class Error(Exception): + pass + +#SESSIONS MANAGEMENT +def newSession(): + + class Session(object): + """docstring for Session""" + def __init__(self): + super(Session, self).__init__() + self.data = bottle.request.environ.get('beaker.session') + self.lang = self.get_lang() + #localization + global i18n + i18n = LocalizeTo(self.lang) + + def get_lang(self): + if 'HTTP_ACCEPT_LANGUAGE' in bottle.request.environ: + lang = bottle.request.get('HTTP_ACCEPT_LANGUAGE') + return str(lang[:2]) + else: + return CONF['locale']['lang'] + + def get(self): + if 'username' in self.data: + return(self.data) + else: + raise Error(i18n.msg[25]) + + def set(self, data): + self.active = data[0] + self.fakeCn = data[1] + self.firstname = data[2] + self.surname = data[3] + self.username = data[4] + self.mail = data[5] + + self.data['active'] = self.active + self.data['fakeCn'] = self.fakeCn + self.data['firstname'] = self.firstname + self.data['surname'] = self.surname + self.data['username'] = self.username + self.data['mail'] = self.mail + + def close(self): + self.data.pop('username') + + def delete(self): + self.data.delete() + + s=Session() + return s + +class LocalizeTo(object): + """docstring for Session""" + def __init__(self, lang): + super(LocalizeTo, self).__init__() + translate = gettext.translation('base', localedir=CONF['locale']['dir'], languages=[lang]) + translate.install() + _ = translate.gettext + + #generic strings + str_00 = _("User") + str_01 = _("Username") + str_02 = _("Firstname") + str_03 = _("Surname") + str_04 = _("Password") + str_05 = _("Old password") + str_06 = _("New password") + str_07 = _("Confirm password") + str_08 = _("Email") + str_09 = _("edit") + str_10 = _("Login") + str_11 = _("Logout") + str_12 = _("Delete") + str_13 = _("Sign Up") + str_14 = _("Back") + str_15 = _("Update") + str_16 = _("Or Sign In") + str_17 = _("Or Sign Up") + str_18 = _("Invite code") + str_19 = _("Edit your fullname") + str_20 = _("Edit your email") + str_21 = _("Change your password") + str_22 = _("Delete your account") + str_23 = _("Welcome") + + #messages + msg_00 = _("The session was closed.") + msg_01 = _("Username must be at least 3 characters long!") + msg_02 = _("Please enter your password!") + msg_03 = _("Welcome") + msg_04 = _("The code is invalid or has expired.") + msg_05 = _("A bit short, don't you think?!") + msg_06 = _("Not allowed characters for the username field.") + msg_07 = _("Passwords do not match!") + msg_08 = _("Password must be at least 8 characters long!") + msg_09 = _("Congratulations, your account has been created!") + msg_10 = _("Your firstname is a bit short, don't you think?") + msg_11 = _("Your surname is a bit short, don't you think?") + msg_12 = _("Your first and last name have been successfully updated.") + msg_13 = _("Invalid email address. Please try again.") + msg_14 = _("Your email has been successfully updated.") + msg_15 = _("The password entered is the same as the current password.") + msg_16 = _("Password has been changed!") + msg_17 = _("Please, type your username for account deletion.") + msg_18 = _("Account successfully deleted!") + msg_19 = _("Username or password is incorrect!") + msg_20 = _("Unable to connect to the remote server.") + msg_21 = _("Encountered an unexpected error while communicating with the remote server.") + msg_22 = _("User already exists.") + msg_23 = _("Email already exists.") + msg_24 = _("Forgot your password? Please try again.") + msg_25 = _("The session has expired.") + + self.str = {'usr':str_00, 'usrn':str_01, 'fn':str_02, 'sn':str_03, 'pwd':str_04, 'old-pwd':str_05, 'new-pwd':str_06, 'conf-pwd':str_07, 'email':str_08, 'edit':str_09, 'login':str_10, 'log-out':str_11, 'del':str_12, 'sign-up':str_13, 'back':str_14, 'update':str_15, 'or-sign-in':str_16, 'or-sign-up':str_17, 'inv-code':str_18, 'edit-fn':str_19, 'edit-email':str_20, 'ch-pwd':str_21, 'del-account':str_22, 'welcome':str_23} + self.msg = (msg_00, msg_01, msg_02, msg_03, msg_04, msg_05, msg_06, msg_07, msg_08, msg_09, msg_10, msg_11, msg_12, msg_13, msg_14, msg_15, msg_16, msg_17, msg_18, msg_19, msg_20, msg_21, msg_22, msg_23, msg_24, msg_25) + +if environ.get('DEBUG'): + bottle.debug(True) + +# Set up logging. +logging.basicConfig(format=LOG_FORMAT) +LOG.setLevel(logging.INFO) +LOG.info("Starting ldap-python-webui %s" % VERSION) + +session_opts = { + 'session.type': CONF['session']['type'], + 'session.cookie_expires': CONF['session']['expire'], + 'session.data_dir': CONF['session']['data_dir'], + 'session.auto': CONF['session']['auto'] +} + +class SuperUsers(object): + """docstring for Session""" + def __init__(self, conf): + super(SuperUsers, self).__init__() + self.domain=conf['base'][conf['base'].find(","):] + self.admin_dn="cn=admin"+self.domain + self.admin_pwd=environ['LDAP_ADMIN_PASSWORD'] + self.readonly_dn="cn=readonly"+self.domain + self.readonly_pwd=environ['LDAP_READONLY_PASSWORD'] + +superUser = SuperUsers(CONF['ldap:0']) + +app = beaker.middleware.SessionMiddleware(bottle.app(), session_opts) + +bottle.TEMPLATE_PATH = [BASE_DIR] + +# Set default attributes to pass into templates. +#SimpleTemplate.defaults = dict(CONF['html']) +SimpleTemplate.defaults['url'] = bottle.url + + +# Run bottle internal server when invoked directly (mainly for development). +if __name__ == '__main__': + bottle.run(app, **CONF['server']) +# Run bottle in application mode (in production under uWSGI server). +else: + #application = bottle.default_app() + application = app diff --git a/change_pwd.tpl b/change_pwd.tpl new file mode 100644 index 0000000..5da670b --- /dev/null +++ b/change_pwd.tpl @@ -0,0 +1,46 @@ + + + + + + + + + {{ str['ch-pwd'] }} + + + + + +
+

{{ str['ch-pwd'] }}

+ +
+ + + + + + + + + + +
+ + +
+ +
+ + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + diff --git a/data/__pycache__/flist.cpython-39.pyc b/data/__pycache__/flist.cpython-39.pyc new file mode 100644 index 0000000..0ff74a1 Binary files /dev/null and b/data/__pycache__/flist.cpython-39.pyc differ diff --git a/data/__pycache__/fnlist.cpython-39.pyc b/data/__pycache__/fnlist.cpython-39.pyc new file mode 100644 index 0000000..d4bb04f Binary files /dev/null and b/data/__pycache__/fnlist.cpython-39.pyc differ diff --git a/data/__pycache__/slist.cpython-39.pyc b/data/__pycache__/slist.cpython-39.pyc new file mode 100644 index 0000000..28a698f Binary files /dev/null and b/data/__pycache__/slist.cpython-39.pyc differ diff --git a/data/flist.py b/data/flist.py new file mode 100644 index 0000000..9cc112a --- /dev/null +++ b/data/flist.py @@ -0,0 +1,2739 @@ +firstname = [ + "Aaran", + "Aaren", + "Aarez", + "Aarman", + "Aaron", + "Aaron-James", + "Aarron", + "Aaryan", + "Aaryn", + "Aayan", + "Aazaan", + "Abaan", + "Abbas", + "Abdallah", + "Abdalroof", + "Abdihakim", + "Abdirahman", + "Abdisalam", + "Abdul", + "Abdul-Aziz", + "Abdulbasir", + "Abdulkadir", + "Abdulkarem", + "Abdulkhader", + "Abdullah", + "Abdul-Majeed", + "Abdulmalik", + "Abdul-Rehman", + "Abdur", + "Abdurraheem", + "Abdur-Rahman", + "Abdur-Rehmaan", + "Abel", + "Abhinav", + "Abhisumant", + "Abid", + "Abir", + "Abraham", + "Abu", + "Abubakar", + "Ace", + "Adain", + "Adam", + "Adam-James", + "Addison", + "Addisson", + "Adegbola", + "Adegbolahan", + "Aden", + "Adenn", + "Adie", + "Adil", + "Aditya", + "Adnan", + "Adrian", + "Adrien", + "Aedan", + "Aedin", + "Aedyn", + "Aeron", + "Afonso", + "Ahmad", + "Ahmed", + "Ahmed-Aziz", + "Ahoua", + "Ahtasham", + "Aiadan", + "Aidan", + "Aiden", + "Aiden-Jack", + "Aiden-Vee", + "Aidian", + "Aidy", + "Ailin", + "Aiman", + "Ainsley", + "Ainslie", + "Airen", + "Airidas", + "Airlie", + "AJ", + "Ajay", + "A-Jay", + "Ajayraj", + "Akan", + "Akram", + "Al", + "Ala", + "Alan", + "Alanas", + "Alasdair", + "Alastair", + "Alber", + "Albert", + "Albie", + "Aldred", + "Alec", + "Aled", + "Aleem", + "Aleksandar", + "Aleksander", + "Aleksandr", + "Aleksandrs", + "Alekzander", + "Alessandro", + "Alessio", + "Alex", + "Alexander", + "Alexei", + "Alexx", + "Alexzander", + "Alf", + "Alfee", + "Alfie", + "Alfred", + "Alfy", + "Alhaji", + "Al-Hassan", + "Ali", + "Aliekber", + "Alieu", + "Alihaider", + "Alisdair", + "Alishan", + "Alistair", + "Alistar", + "Alister", + "Aliyaan", + "Allan", + "Allan-Laiton", + "Allen", + "Allesandro", + "Allister", + "Ally", + "Alphonse", + "Altyiab", + "Alum", + "Alvern", + "Alvin", + "Alyas", + "Amaan", + "Aman", + "Amani", + "Ambanimoh", + "Ameer", + "Amgad", + "Ami", + "Amin", + "Amir", + "Ammaar", + "Ammar", + "Ammer", + "Amolpreet", + "Amos", + "Amrinder", + "Amrit", + "Amro", + "Anay", + "Andrea", + "Andreas", + "Andrei", + "Andrejs", + "Andrew", + "Andy", + "Anees", + "Anesu", + "Angel", + "Angelo", + "Angus", + "Anir", + "Anis", + "Anish", + "Anmolpreet", + "Annan", + "Anndra", + "Anselm", + "Anthony", + "Anthony-John", + "Antoine", + "Anton", + "Antoni", + "Antonio", + "Antony", + "Antonyo", + "Anubhav", + "Aodhan", + "Aon", + "Aonghus", + "Apisai", + "Arafat", + "Aran", + "Arandeep", + "Arann", + "Aray", + "Arayan", + "Archibald", + "Archie", + "Arda", + "Ardal", + "Ardeshir", + "Areeb", + "Areez", + "Aref", + "Arfin", + "Argyle", + "Argyll", + "Ari", + "Aria", + "Arian", + "Arihant", + "Aristomenis", + "Aristotelis", + "Arjuna", + "Arlo", + "Armaan", + "Arman", + "Armen", + "Arnab", + "Arnav", + "Arnold", + "Aron", + "Aronas", + "Arran", + "Arrham", + "Arron", + "Arryn", + "Arsalan", + "Artem", + "Arthur", + "Artur", + "Arturo", + "Arun", + "Arunas", + "Arved", + "Arya", + "Aryan", + "Aryankhan", + "Aryian", + "Aryn", + "Asa", + "Asfhan", + "Ash", + "Ashlee-jay", + "Ashley", + "Ashton", + "Ashton-Lloyd", + "Ashtyn", + "Ashwin", + "Asif", + "Asim", + "Aslam", + "Asrar", + "Ata", + "Atal", + "Atapattu", + "Ateeq", + "Athol", + "Athon", + "Athos-Carlos", + "Atli", + "Atom", + "Attila", + "Aulay", + "Aun", + "Austen", + "Austin", + "Avani", + "Averon", + "Avi", + "Avinash", + "Avraham", + "Awais", + "Awwal", + "Axel", + "Ayaan", + "Ayan", + "Aydan", + "Ayden", + "Aydin", + "Aydon", + "Ayman", + "Ayomide", + "Ayren", + "Ayrton", + "Aytug", + "Ayub", + "Ayyub", + "Azaan", + "Azedine", + "Azeem", + "Azim", + "Aziz", + "Azlan", + "Azzam", + "Azzedine", + "Babatunmise", + "Babur", + "Bader", + "Badr", + "Badsha", + "Bailee", + "Bailey", + "Bailie", + "Bailley", + "Baillie", + "Baley", + "Balian", + "Banan", + "Barath", + "Barkley", + "Barney", + "Baron", + "Barrie", + "Barry", + "Bartlomiej", + "Bartosz", + "Basher", + "Basile", + "Baxter", + "Baye", + "Bayley", + "Beau", + "Beinn", + "Bekim", + "Believe", + "Ben", + "Bendeguz", + "Benedict", + "Benjamin", + "Benjamyn", + "Benji", + "Benn", + "Bennett", + "Benny", + "Benoit", + "Bentley", + "Berkay", + "Bernard", + "Bertie", + "Bevin", + "Bezalel", + "Bhaaldeen", + "Bharath", + "Bilal", + "Bill", + "Billy", + "Binod", + "Bjorn", + "Blaike", + "Blaine", + "Blair", + "Blaire", + "Blake", + "Blazej", + "Blazey", + "Blessing", + "Blue", + "Blyth", + "Bo", + "Boab", + "Bob", + "Bobby", + "Bobby-Lee", + "Bodhan", + "Boedyn", + "Bogdan", + "Bohbi", + "Bony", + "Bowen", + "Bowie", + "Boyd", + "Bracken", + "Brad", + "Bradan", + "Braden", + "Bradley", + "Bradlie", + "Bradly", + "Brady", + "Bradyn", + "Braeden", + "Braiden", + "Brajan", + "Brandan", + "Branden", + "Brandon", + "Brandonlee", + "Brandon-Lee", + "Brandyn", + "Brannan", + "Brayden", + "Braydon", + "Braydyn", + "Breandan", + "Brehme", + "Brendan", + "Brendon", + "Brendyn", + "Breogan", + "Bret", + "Brett", + "Briaddon", + "Brian", + "Brodi", + "Brodie", + "Brody", + "Brogan", + "Broghan", + "Brooke", + "Brooklin", + "Brooklyn", + "Bruce", + "Bruin", + "Bruno", + "Brunon", + "Bryan", + "Bryce", + "Bryden", + "Brydon", + "Brydon-Craig", + "Bryn", + "Brynmor", + "Bryson", + "Buddy", + "Bully", + "Burak", + "Burhan", + "Butali", + "Butchi", + "Byron", + "Cabhan", + "Cadan", + "Cade", + "Caden", + "Cadon", + "Cadyn", + "Caedan", + "Caedyn", + "Cael", + "Caelan", + "Caelen", + "Caethan", + "Cahl", + "Cahlum", + "Cai", + "Caidan", + "Caiden", + "Caiden-Paul", + "Caidyn", + "Caie", + "Cailaen", + "Cailean", + "Caileb-John", + "Cailin", + "Cain", + "Caine", + "Cairn", + "Cal", + "Calan", + "Calder", + "Cale", + "Calean", + "Caleb", + "Calen", + "Caley", + "Calib", + "Calin", + "Callahan", + "Callan", + "Callan-Adam", + "Calley", + "Callie", + "Callin", + "Callum", + "Callun", + "Callyn", + "Calum", + "Calum-James", + "Calvin", + "Cambell", + "Camerin", + "Cameron", + "Campbel", + "Campbell", + "Camron", + "Caolain", + "Caolan", + "Carl", + "Carlo", + "Carlos", + "Carrich", + "Carrick", + "Carson", + "Carter", + "Carwyn", + "Casey", + "Casper", + "Cassy", + "Cathal", + "Cator", + "Cavan", + "Cayden", + "Cayden-Robert", + "Cayden-Tiamo", + "Ceejay", + "Ceilan", + "Ceiran", + "Ceirin", + "Ceiron", + "Cejay", + "Celik", + "Cephas", + "Cesar", + "Cesare", + "Chad", + "Chaitanya", + "Chang-Ha", + "Charles", + "Charley", + "Charlie", + "Charly", + "Chase", + "Che", + "Chester", + "Chevy", + "Chi", + "Chibudom", + "Chidera", + "Chimsom", + "Chin", + "Chintu", + "Chiqal", + "Chiron", + "Chris", + "Chris-Daniel", + "Chrismedi", + "Christian", + "Christie", + "Christoph", + "Christopher", + "Christopher-Lee", + "Christy", + "Chu", + "Chukwuemeka", + "Cian", + "Ciann", + "Ciar", + "Ciaran", + "Ciarian", + "Cieran", + "Cillian", + "Cillin", + "Cinar", + "CJ", + "C-Jay", + "Clark", + "Clarke", + "Clayton", + "Clement", + "Clifford", + "Clyde", + "Cobain", + "Coban", + "Coben", + "Cobi", + "Cobie", + "Coby", + "Codey", + "Codi", + "Codie", + "Cody", + "Cody-Lee", + "Coel", + "Cohan", + "Cohen", + "Colby", + "Cole", + "Colin", + "Coll", + "Colm", + "Colt", + "Colton", + "Colum", + "Colvin", + "Comghan", + "Conal", + "Conall", + "Conan", + "Conar", + "Conghaile", + "Conlan", + "Conley", + "Conli", + "Conlin", + "Conlly", + "Conlon", + "Conlyn", + "Connal", + "Connall", + "Connan", + "Connar", + "Connel", + "Connell", + "Conner", + "Connolly", + "Connor", + "Connor-David", + "Conor", + "Conrad", + "Cooper", + "Copeland", + "Coray", + "Corben", + "Corbin", + "Corey", + "Corey-James", + "Corey-Jay", + "Cori", + "Corie", + "Corin", + "Cormac", + "Cormack", + "Cormak", + "Corran", + "Corrie", + "Cory", + "Cosmo", + "Coupar", + "Craig", + "Craig-James", + "Crawford", + "Creag", + "Crispin", + "Cristian", + "Crombie", + "Cruiz", + "Cruz", + "Cuillin", + "Cullen", + "Cullin", + "Curtis", + "Cyrus", + "Daanyaal", + "Daegan", + "Daegyu", + "Dafydd", + "Dagon", + "Dailey", + "Daimhin", + "Daithi", + "Dakota", + "Daksh", + "Dale", + "Dalong", + "Dalton", + "Damian", + "Damien", + "Damon", + "Dan", + "Danar", + "Dane", + "Danial", + "Daniel", + "Daniele", + "Daniel-James", + "Daniels", + "Daniil", + "Danish", + "Daniyal", + "Danniel", + "Danny", + "Dante", + "Danyal", + "Danyil", + "Danys", + "Daood", + "Dara", + "Darach", + "Daragh", + "Darcy", + "D'arcy", + "Dareh", + "Daren", + "Darien", + "Darius", + "Darl", + "Darn", + "Darrach", + "Darragh", + "Darrel", + "Darrell", + "Darren", + "Darrie", + "Darrius", + "Darroch", + "Darryl", + "Darryn", + "Darwyn", + "Daryl", + "Daryn", + "Daud", + "Daumantas", + "Davi", + "David", + "David-Jay", + "David-Lee", + "Davie", + "Davis", + "Davy", + "Dawid", + "Dawson", + "Dawud", + "Dayem", + "Daymian", + "Deacon", + "Deagan", + "Dean", + "Deano", + "Decklan", + "Declain", + "Declan", + "Declyan", + "Declyn", + "Dedeniseoluwa", + "Deecan", + "Deegan", + "Deelan", + "Deklain-Jaimes", + "Del", + "Demetrius", + "Denis", + "Deniss", + "Dennan", + "Dennin", + "Dennis", + "Denny", + "Dennys", + "Denon", + "Denton", + "Denver", + "Denzel", + "Deon", + "Derek", + "Derick", + "Derin", + "Dermot", + "Derren", + "Derrie", + "Derrin", + "Derron", + "Derry", + "Derryn", + "Deryn", + "Deshawn", + "Desmond", + "Dev", + "Devan", + "Devin", + "Devlin", + "Devlyn", + "Devon", + "Devrin", + "Devyn", + "Dex", + "Dexter", + "Dhani", + "Dharam", + "Dhavid", + "Dhyia", + "Diarmaid", + "Diarmid", + "Diarmuid", + "Didier", + "Diego", + "Diesel", + "Diesil", + "Digby", + "Dilan", + "Dilano", + "Dillan", + "Dillon", + "Dilraj", + "Dimitri", + "Dinaras", + "Dion", + "Dissanayake", + "Dmitri", + "Doire", + "Dolan", + "Domanic", + "Domenico", + "Domhnall", + "Dominic", + "Dominick", + "Dominik", + "Donald", + "Donnacha", + "Donnie", + "Dorian", + "Dougal", + "Douglas", + "Dougray", + "Drakeo", + "Dre", + "Dregan", + "Drew", + "Dugald", + "Duncan", + "Duriel", + "Dustin", + "Dylan", + "Dylan-Jack", + "Dylan-James", + "Dylan-John", + "Dylan-Patrick", + "Dylin", + "Dyllan", + "Dyllan-James", + "Dyllon", + "Eadie", + "Eagann", + "Eamon", + "Eamonn", + "Eason", + "Eassan", + "Easton", + "Ebow", + "Ed", + "Eddie", + "Eden", + "Ediomi", + "Edison", + "Eduardo", + "Eduards", + "Edward", + "Edwin", + "Edwyn", + "Eesa", + "Efan", + "Efe", + "Ege", + "Ehsan", + "Ehsen", + "Eiddon", + "Eidhan", + "Eihli", + "Eimantas", + "Eisa", + "Eli", + "Elias", + "Elijah", + "Eliot", + "Elisau", + "Eljay", + "Eljon", + "Elliot", + "Elliott", + "Ellis", + "Ellisandro", + "Elshan", + "Elvin", + "Elyan", + "Emanuel", + "Emerson", + "Emil", + "Emile", + "Emir", + "Emlyn", + "Emmanuel", + "Emmet", + "Eng", + "Eniola", + "Enis", + "Ennis", + "Enrico", + "Enrique", + "Enzo", + "Eoghain", + "Eoghan", + "Eoin", + "Eonan", + "Erdehan", + "Eren", + "Erencem", + "Eric", + "Ericlee", + "Erik", + "Eriz", + "Ernie-Jacks", + "Eroni", + "Eryk", + "Eshan", + "Essa", + "Esteban", + "Ethan", + "Etienne", + "Etinosa", + "Euan", + "Eugene", + "Evan", + "Evann", + "Ewan", + "Ewen", + "Ewing", + "Exodi", + "Ezekiel", + "Ezra", + "Fabian", + "Fahad", + "Faheem", + "Faisal", + "Faizaan", + "Famara", + "Fares", + "Farhaan", + "Farhan", + "Farren", + "Farzad", + "Fauzaan", + "Favour", + "Fawaz", + "Fawkes", + "Faysal", + "Fearghus", + "Feden", + "Felix", + "Fergal", + "Fergie", + "Fergus", + "Ferre", + "Fezaan", + "Fiachra", + "Fikret", + "Filip", + "Filippo", + "Finan", + "Findlay", + "Findlay-James", + "Findlie", + "Finlay", + "Finley", + "Finn", + "Finnan", + "Finnean", + "Finnen", + "Finnlay", + "Finnley", + "Fintan", + "Fionn", + "Firaaz", + "Fletcher", + "Flint", + "Florin", + "Flyn", + "Flynn", + "Fodeba", + "Folarinwa", + "Forbes", + "Forgan", + "Forrest", + "Fox", + "Francesco", + "Francis", + "Francisco", + "Franciszek", + "Franco", + "Frank", + "Frankie", + "Franklin", + "Franko", + "Fraser", + "Frazer", + "Fred", + "Freddie", + "Frederick", + "Fruin", + "Fyfe", + "Fyn", + "Fynlay", + "Fynn", + "Gabriel", + "Gallagher", + "Gareth", + "Garren", + "Garrett", + "Garry", + "Gary", + "Gavin", + "Gavin-Lee", + "Gene", + "Geoff", + "Geoffrey", + "Geomer", + "Geordan", + "Geordie", + "George", + "Georgia", + "Georgy", + "Gerard", + "Ghyll", + "Giacomo", + "Gian", + "Giancarlo", + "Gianluca", + "Gianmarco", + "Gideon", + "Gil", + "Gio", + "Girijan", + "Girius", + "Gjan", + "Glascott", + "Glen", + "Glenn", + "Gordon", + "Grady", + "Graeme", + "Graham", + "Grahame", + "Grant", + "Grayson", + "Greg", + "Gregor", + "Gregory", + "Greig", + "Griffin", + "Griffyn", + "Grzegorz", + "Guang", + "Guerin", + "Guillaume", + "Gurardass", + "Gurdeep", + "Gursees", + "Gurthar", + "Gurveer", + "Gurwinder", + "Gus", + "Gustav", + "Guthrie", + "Guy", + "Gytis", + "Habeeb", + "Hadji", + "Hadyn", + "Hagun", + "Haiden", + "Haider", + "Hamad", + "Hamid", + "Hamish", + "Hamza", + "Hamzah", + "Han", + "Hansen", + "Hao", + "Hareem", + "Hari", + "Harikrishna", + "Haris", + "Harish", + "Harjeevan", + "Harjyot", + "Harlee", + "Harleigh", + "Harley", + "Harman", + "Harnek", + "Harold", + "Haroon", + "Harper", + "Harri", + "Harrington", + "Harris", + "Harrison", + "Harry", + "Harvey", + "Harvie", + "Harvinder", + "Hasan", + "Haseeb", + "Hashem", + "Hashim", + "Hassan", + "Hassanali", + "Hately", + "Havila", + "Hayden", + "Haydn", + "Haydon", + "Haydyn", + "Hcen", + "Hector", + "Heddle", + "Heidar", + "Heini", + "Hendri", + "Henri", + "Henry", + "Herbert", + "Heyden", + "Hiro", + "Hirvaansh", + "Hishaam", + "Hogan", + "Honey", + "Hong", + "Hope", + "Hopkin", + "Hosea", + "Howard", + "Howie", + "Hristomir", + "Hubert", + "Hugh", + "Hugo", + "Humza", + "Hunter", + "Husnain", + "Hussain", + "Hussan", + "Hussnain", + "Hussnan", + "Hyden", + "I", + "Iagan", + "Iain", + "Ian", + "Ibraheem", + "Ibrahim", + "Idahosa", + "Idrees", + "Idris", + "Iestyn", + "Ieuan", + "Igor", + "Ihtisham", + "Ijay", + "Ikechukwu", + "Ikemsinachukwu", + "Ilyaas", + "Ilyas", + "Iman", + "Immanuel", + "Inan", + "Indy", + "Ines", + "Innes", + "Ioannis", + "Ireayomide", + "Ireoluwa", + "Irvin", + "Irvine", + "Isa", + "Isaa", + "Isaac", + "Isaiah", + "Isak", + "Isher", + "Ishwar", + "Isimeli", + "Isira", + "Ismaeel", + "Ismail", + "Israel", + "Issiaka", + "Ivan", + "Ivar", + "Izaak", + "J", + "Jaay", + "Jac", + "Jace", + "Jack", + "Jacki", + "Jackie", + "Jack-James", + "Jackson", + "Jacky", + "Jacob", + "Jacques", + "Jad", + "Jaden", + "Jadon", + "Jadyn", + "Jae", + "Jagat", + "Jago", + "Jaheim", + "Jahid", + "Jahy", + "Jai", + "Jaida", + "Jaiden", + "Jaidyn", + "Jaii", + "Jaime", + "Jai-Rajaram", + "Jaise", + "Jak", + "Jake", + "Jakey", + "Jakob", + "Jaksyn", + "Jakub", + "Jamaal", + "Jamal", + "Jameel", + "Jameil", + "James", + "James-Paul", + "Jamey", + "Jamie", + "Jan", + "Jaosha", + "Jardine", + "Jared", + "Jarell", + "Jarl", + "Jarno", + "Jarred", + "Jarvi", + "Jasey-Jay", + "Jasim", + "Jaskaran", + "Jason", + "Jasper", + "Jaxon", + "Jaxson", + "Jay", + "Jaydan", + "Jayden", + "Jayden-James", + "Jayden-Lee", + "Jayden-Paul", + "Jayden-Thomas", + "Jaydn", + "Jaydon", + "Jaydyn", + "Jayhan", + "Jay-Jay", + "Jayke", + "Jaymie", + "Jayse", + "Jayson", + "Jaz", + "Jazeb", + "Jazib", + "Jazz", + "Jean", + "Jean-Lewis", + "Jean-Pierre", + "Jebadiah", + "Jed", + "Jedd", + "Jedidiah", + "Jeemie", + "Jeevan", + "Jeffrey", + "Jensen", + "Jenson", + "Jensyn", + "Jeremy", + "Jerome", + "Jeronimo", + "Jerrick", + "Jerry", + "Jesse", + "Jesuseun", + "Jeswin", + "Jevan", + "Jeyun", + "Jez", + "Jia", + "Jian", + "Jiao", + "Jimmy", + "Jincheng", + "JJ", + "Joaquin", + "Joash", + "Jock", + "Jody", + "Joe", + "Joeddy", + "Joel", + "Joey", + "Joey-Jack", + "Johann", + "Johannes", + "Johansson", + "John", + "Johnathan", + "Johndean", + "Johnjay", + "John-Michael", + "Johnnie", + "Johnny", + "Johnpaul", + "John-Paul", + "John-Scott", + "Johnson", + "Jole", + "Jomuel", + "Jon", + "Jonah", + "Jonatan", + "Jonathan", + "Jonathon", + "Jonny", + "Jonothan", + "Jon-Paul", + "Jonson", + "Joojo", + "Jordan", + "Jordi", + "Jordon", + "Jordy", + "Jordyn", + "Jorge", + "Joris", + "Jorryn", + "Josan", + "Josef", + "Joseph", + "Josese", + "Josh", + "Joshiah", + "Joshua", + "Josiah", + "Joss", + "Jostelle", + "Joynul", + "Juan", + "Jubin", + "Judah", + "Jude", + "Jules", + "Julian", + "Julien", + "Jun", + "Junior", + "Jura", + "Justan", + "Justin", + "Justinas", + "Kaan", + "Kabeer", + "Kabir", + "Kacey", + "Kacper", + "Kade", + "Kaden", + "Kadin", + "Kadyn", + "Kaeden", + "Kael", + "Kaelan", + "Kaelin", + "Kaelum", + "Kai", + "Kaid", + "Kaidan", + "Kaiden", + "Kaidinn", + "Kaidyn", + "Kaileb", + "Kailin", + "Kain", + "Kaine", + "Kainin", + "Kainui", + "Kairn", + "Kaison", + "Kaiwen", + "Kajally", + "Kajetan", + "Kalani", + "Kale", + "Kaleb", + "Kaleem", + "Kal-el", + "Kalen", + "Kalin", + "Kallan", + "Kallin", + "Kalum", + "Kalvin", + "Kalvyn", + "Kameron", + "Kames", + "Kamil", + "Kamran", + "Kamron", + "Kane", + "Karam", + "Karamvir", + "Karandeep", + "Kareem", + "Karim", + "Karimas", + "Karl", + "Karol", + "Karson", + "Karsyn", + "Karthikeya", + "Kasey", + "Kash", + "Kashif", + "Kasim", + "Kasper", + "Kasra", + "Kavin", + "Kayam", + "Kaydan", + "Kayden", + "Kaydin", + "Kaydn", + "Kaydyn", + "Kaydyne", + "Kayleb", + "Kaylem", + "Kaylum", + "Kayne", + "Kaywan", + "Kealan", + "Kealon", + "Kean", + "Keane", + "Kearney", + "Keatin", + "Keaton", + "Keavan", + "Keayn", + "Kedrick", + "Keegan", + "Keelan", + "Keelin", + "Keeman", + "Keenan", + "Keenan-Lee", + "Keeton", + "Kehinde", + "Keigan", + "Keilan", + "Keir", + "Keiran", + "Keiren", + "Keiron", + "Keiryn", + "Keison", + "Keith", + "Keivlin", + "Kelam", + "Kelan", + "Kellan", + "Kellen", + "Kelso", + "Kelum", + "Kelvan", + "Kelvin", + "Ken", + "Kenan", + "Kendall", + "Kendyn", + "Kenlin", + "Kenneth", + "Kensey", + "Kenton", + "Kenyon", + "Kenzeigh", + "Kenzi", + "Kenzie", + "Kenzo", + "Kenzy", + "Keo", + "Ker", + "Kern", + "Kerr", + "Kevan", + "Kevin", + "Kevyn", + "Kez", + "Khai", + "Khalan", + "Khaleel", + "Khaya", + "Khevien", + "Khizar", + "Khizer", + "Kia", + "Kian", + "Kian-James", + "Kiaran", + "Kiarash", + "Kie", + "Kiefer", + "Kiegan", + "Kienan", + "Kier", + "Kieran", + "Kieran-Scott", + "Kieren", + "Kierin", + "Kiern", + "Kieron", + "Kieryn", + "Kile", + "Killian", + "Kimi", + "Kingston", + "Kinneil", + "Kinnon", + "Kinsey", + "Kiran", + "Kirk", + "Kirwin", + "Kit", + "Kiya", + "Kiyonari", + "Kjae", + "Klein", + "Klevis", + "Kobe", + "Kobi", + "Koby", + "Koddi", + "Koden", + "Kodi", + "Kodie", + "Kody", + "Kofi", + "Kogan", + "Kohen", + "Kole", + "Konan", + "Konar", + "Konnor", + "Konrad", + "Koray", + "Korben", + "Korbyn", + "Korey", + "Kori", + "Korrin", + "Kory", + "Koushik", + "Kris", + "Krish", + "Krishan", + "Kriss", + "Kristian", + "Kristin", + "Kristofer", + "Kristoffer", + "Kristopher", + "Kruz", + "Krzysiek", + "Krzysztof", + "Ksawery", + "Ksawier", + "Kuba", + "Kurt", + "Kurtis", + "Kurtis-Jae", + "Kyaan", + "Kyan", + "Kyde", + "Kyden", + "Kye", + "Kyel", + "Kyhran", + "Kyie", + "Kylan", + "Kylar", + "Kyle", + "Kyle-Derek", + "Kylian", + "Kym", + "Kynan", + "Kyral", + "Kyran", + "Kyren", + "Kyrillos", + "Kyro", + "Kyron", + "Kyrran", + "Lachlainn", + "Lachlan", + "Lachlann", + "Lael", + "Lagan", + "Laird", + "Laison", + "Lakshya", + "Lance", + "Lancelot", + "Landon", + "Lang", + "Lasse", + "Latif", + "Lauchlan", + "Lauchlin", + "Laughlan", + "Lauren", + "Laurence", + "Laurie", + "Lawlyn", + "Lawrence", + "Lawrie", + "Lawson", + "Layne", + "Layton", + "Lee", + "Leigh", + "Leigham", + "Leighton", + "Leilan", + "Leiten", + "Leithen", + "Leland", + "Lenin", + "Lennan", + "Lennen", + "Lennex", + "Lennon", + "Lennox", + "Lenny", + "Leno", + "Lenon", + "Lenyn", + "Leo", + "Leon", + "Leonard", + "Leonardas", + "Leonardo", + "Lepeng", + "Leroy", + "Leven", + "Levi", + "Levon", + "Levy", + "Lewie", + "Lewin", + "Lewis", + "Lex", + "Leydon", + "Leyland", + "Leylann", + "Leyton", + "Liall", + "Liam", + "Liam-Stephen", + "Limo", + "Lincoln", + "Lincoln-John", + "Lincon", + "Linden", + "Linton", + "Lionel", + "Lisandro", + "Litrell", + "Liyonela-Elam", + "LLeyton", + "Lliam", + "Lloyd", + "Lloyde", + "Loche", + "Lochlan", + "Lochlann", + "Lochlan-Oliver", + "Lock", + "Lockey", + "Logan", + "Logann", + "Logan-Rhys", + "Loghan", + "Lokesh", + "Loki", + "Lomond", + "Lorcan", + "Lorenz", + "Lorenzo", + "Lorne", + "Loudon", + "Loui", + "Louie", + "Louis", + "Loukas", + "Lovell", + "Luc", + "Luca", + "Lucais", + "Lucas", + "Lucca", + "Lucian", + "Luciano", + "Lucien", + "Lucus", + "Luic", + "Luis", + "Luk", + "Luka", + "Lukas", + "Lukasz", + "Luke", + "Lukmaan", + "Luqman", + "Lyall", + "Lyle", + "Lyndsay", + "Lysander", + "Maanav", + "Maaz", + "Mac", + "Macallum", + "Macaulay", + "Macauley", + "Macaully", + "Machlan", + "Maciej", + "Mack", + "Mackenzie", + "Mackenzy", + "Mackie", + "Macsen", + "Macy", + "Madaki", + "Maddison", + "Maddox", + "Madison", + "Madison-Jake", + "Madox", + "Mael", + "Magnus", + "Mahan", + "Mahdi", + "Mahmoud", + "Maias", + "Maison", + "Maisum", + "Maitlind", + "Majid", + "Makensie", + "Makenzie", + "Makin", + "Maksim", + "Maksymilian", + "Malachai", + "Malachi", + "Malachy", + "Malakai", + "Malakhy", + "Malcolm", + "Malik", + "Malikye", + "Malo", + "Ma'moon", + "Manas", + "Maneet", + "Manmohan", + "Manolo", + "Manson", + "Mantej", + "Manuel", + "Manus", + "Marc", + "Marc-Anthony", + "Marcel", + "Marcello", + "Marcin", + "Marco", + "Marcos", + "Marcous", + "Marcquis", + "Marcus", + "Mario", + "Marios", + "Marius", + "Mark", + "Marko", + "Markus", + "Marley", + "Marlin", + "Marlon", + "Maros", + "Marshall", + "Martin", + "Marty", + "Martyn", + "Marvellous", + "Marvin", + "Marwan", + "Maryk", + "Marzuq", + "Mashhood", + "Mason", + "Mason-Jay", + "Masood", + "Masson", + "Matas", + "Matej", + "Mateusz", + "Mathew", + "Mathias", + "Mathu", + "Mathuyan", + "Mati", + "Matt", + "Matteo", + "Matthew", + "Matthew-William", + "Matthias", + "Max", + "Maxim", + "Maximilian", + "Maximillian", + "Maximus", + "Maxwell", + "Maxx", + "Mayeul", + "Mayson", + "Mazin", + "Mcbride", + "McCaulley", + "McKade", + "McKauley", + "McKay", + "McKenzie", + "McLay", + "Meftah", + "Mehmet", + "Mehraz", + "Meko", + "Melville", + "Meshach", + "Meyzhward", + "Micah", + "Michael", + "Michael-Alexander", + "Michael-James", + "Michal", + "Michat", + "Micheal", + "Michee", + "Mickey", + "Miguel", + "Mika", + "Mikael", + "Mikee", + "Mikey", + "Mikhail", + "Mikolaj", + "Miles", + "Millar", + "Miller", + "Milo", + "Milos", + "Milosz", + "Mir", + "Mirza", + "Mitch", + "Mitchel", + "Mitchell", + "Moad", + "Moayd", + "Mobeen", + "Modoulamin", + "Modu", + "Mohamad", + "Mohamed", + "Mohammad", + "Mohammad-Bilal", + "Mohammed", + "Mohanad", + "Mohd", + "Momin", + "Momooreoluwa", + "Montague", + "Montgomery", + "Monty", + "Moore", + "Moosa", + "Moray", + "Morgan", + "Morgyn", + "Morris", + "Morton", + "Moshy", + "Motade", + "Moyes", + "Msughter", + "Mueez", + "Muhamadjavad", + "Muhammad", + "Muhammed", + "Muhsin", + "Muir", + "Munachi", + "Muneeb", + "Mungo", + "Munir", + "Munmair", + "Munro", + "Murdo", + "Murray", + "Murrough", + "Murry", + "Musa", + "Musse", + "Mustafa", + "Mustapha", + "Muzammil", + "Muzzammil", + "Mykie", + "Myles", + "Mylo", + "Nabeel", + "Nadeem", + "Nader", + "Nagib", + "Naif", + "Nairn", + "Narvic", + "Nash", + "Nasser", + "Nassir", + "Natan", + "Nate", + "Nathan", + "Nathanael", + "Nathanial", + "Nathaniel", + "Nathan-Rae", + "Nawfal", + "Nayan", + "Neco", + "Neil", + "Nelson", + "Neo", + "Neshawn", + "Nevan", + "Nevin", + "Ngonidzashe", + "Nial", + "Niall", + "Nicholas", + "Nick", + "Nickhill", + "Nicki", + "Nickson", + "Nicky", + "Nico", + "Nicodemus", + "Nicol", + "Nicolae", + "Nicolas", + "Nidhish", + "Nihaal", + "Nihal", + "Nikash", + "Nikhil", + "Niki", + "Nikita", + "Nikodem", + "Nikolai", + "Nikos", + "Nilav", + "Niraj", + "Niro", + "Niven", + "Noah", + "Noel", + "Nolan", + "Noor", + "Norman", + "Norrie", + "Nuada", + "Nyah", + "Oakley", + "Oban", + "Obieluem", + "Obosa", + "Odhran", + "Odin", + "Odynn", + "Ogheneochuko", + "Ogheneruno", + "Ohran", + "Oilibhear", + "Oisin", + "Ojima-Ojo", + "Okeoghene", + "Olaf", + "Ola-Oluwa", + "Olaoluwapolorimi", + "Ole", + "Olie", + "Oliver", + "Olivier", + "Oliwier", + "Ollie", + "Olurotimi", + "Oluwadamilare", + "Oluwadamiloju", + "Oluwafemi", + "Oluwafikunayomi", + "Oluwalayomi", + "Oluwatobiloba", + "Oluwatoni", + "Omar", + "Omri", + "Oran", + "Orin", + "Orlando", + "Orley", + "Orran", + "Orrick", + "Orrin", + "Orson", + "Oryn", + "Oscar", + "Osesenagha", + "Oskar", + "Ossian", + "Oswald", + "Otto", + "Owain", + "Owais", + "Owen", + "Owyn", + "Oz", + "Ozzy", + "Pablo", + "Pacey", + "Padraig", + "Paolo", + "Pardeepraj", + "Parkash", + "Parker", + "Pascoe", + "Pasquale", + "Patrick", + "Patrick-John", + "Patrikas", + "Patryk", + "Paul", + "Pavit", + "Pawel", + "Pawlo", + "Pearce", + "Pearse", + "Pearsen", + "Pedram", + "Pedro", + "Peirce", + "Peiyan", + "Pele", + "Peni", + "Peregrine", + "Peter", + "Phani", + "Philip", + "Philippos", + "Phinehas", + "Phoenix", + "Phoevos", + "Pierce", + "Pierre-Antoine", + "Pieter", + "Pietro", + "Piotr", + "Porter", + "Prabhjoit", + "Prabodhan", + "Praise", + "Pranav", + "Pravin", + "Precious", + "Prentice", + "Presley", + "Preston", + "Preston-Jay", + "Prinay", + "Prince", + "Prithvi", + "Promise", + "Puneetpaul", + "Pushkar", + "Qasim", + "Qirui", + "Quinlan", + "Quinn", + "Radmiras", + "Raees", + "Raegan", + "Rafael", + "Rafal", + "Rafferty", + "Rafi", + "Raheem", + "Rahil", + "Rahim", + "Rahman", + "Raith", + "Raithin", + "Raja", + "Rajab-Ali", + "Rajan", + "Ralfs", + "Ralph", + "Ramanas", + "Ramit", + "Ramone", + "Ramsay", + "Ramsey", + "Rana", + "Ranolph", + "Raphael", + "Rasmus", + "Rasul", + "Raul", + "Raunaq", + "Ravin", + "Ray", + "Rayaan", + "Rayan", + "Rayane", + "Rayden", + "Rayhan", + "Raymond", + "Rayne", + "Rayyan", + "Raza", + "Reace", + "Reagan", + "Reean", + "Reece", + "Reed", + "Reegan", + "Rees", + "Reese", + "Reeve", + "Regan", + "Regean", + "Reggie", + "Rehaan", + "Rehan", + "Reice", + "Reid", + "Reigan", + "Reilly", + "Reily", + "Reis", + "Reiss", + "Remigiusz", + "Remo", + "Remy", + "Ren", + "Renars", + "Reng", + "Rennie", + "Reno", + "Reo", + "Reuben", + "Rexford", + "Reynold", + "Rhein", + "Rheo", + "Rhett", + "Rheyden", + "Rhian", + "Rhoan", + "Rholmark", + "Rhoridh", + "Rhuairidh", + "Rhuan", + "Rhuaridh", + "Rhudi", + "Rhy", + "Rhyan", + "Rhyley", + "Rhyon", + "Rhys", + "Rhys-Bernard", + "Rhyse", + "Riach", + "Rian", + "Ricards", + "Riccardo", + "Ricco", + "Rice", + "Richard", + "Richey", + "Richie", + "Ricky", + "Rico", + "Ridley", + "Ridwan", + "Rihab", + "Rihan", + "Rihards", + "Rihonn", + "Rikki", + "Riley", + "Rio", + "Rioden", + "Rishi", + "Ritchie", + "Rivan", + "Riyadh", + "Riyaj", + "Roan", + "Roark", + "Roary", + "Rob", + "Robbi", + "Robbie", + "Robbie-lee", + "Robby", + "Robert", + "Robert-Gordon", + "Robertjohn", + "Robi", + "Robin", + "Rocco", + "Roddy", + "Roderick", + "Rodrigo", + "Roen", + "Rogan", + "Roger", + "Rohaan", + "Rohan", + "Rohin", + "Rohit", + "Rokas", + "Roman", + "Ronald", + "Ronan", + "Ronan-Benedict", + "Ronin", + "Ronnie", + "Rooke", + "Roray", + "Rori", + "Rorie", + "Rory", + "Roshan", + "Ross", + "Ross-Andrew", + "Rossi", + "Rowan", + "Rowen", + "Roy", + "Ruadhan", + "Ruaidhri", + "Ruairi", + "Ruairidh", + "Ruan", + "Ruaraidh", + "Ruari", + "Ruaridh", + "Ruben", + "Rubhan", + "Rubin", + "Rubyn", + "Rudi", + "Rudy", + "Rufus", + "Rui", + "Ruo", + "Rupert", + "Ruslan", + "Russel", + "Russell", + "Ryaan", + "Ryan", + "Ryan-Lee", + "Ryden", + "Ryder", + "Ryese", + "Ryhs", + "Rylan", + "Rylay", + "Rylee", + "Ryleigh", + "Ryley", + "Rylie", + "Ryo", + "Ryszard", + "Saad", + "Sabeen", + "Sachkirat", + "Saffi", + "Saghun", + "Sahaib", + "Sahbian", + "Sahil", + "Saif", + "Saifaddine", + "Saim", + "Sajid", + "Sajjad", + "Salahudin", + "Salman", + "Salter", + "Salvador", + "Sam", + "Saman", + "Samar", + "Samarjit", + "Samatar", + "Sambrid", + "Sameer", + "Sami", + "Samir", + "Sami-Ullah", + "Samual", + "Samuel", + "Samuela", + "Samy", + "Sanaullah", + "Sandro", + "Sandy", + "Sanfur", + "Sanjay", + "Santiago", + "Santino", + "Satveer", + "Saul", + "Saunders", + "Savin", + "Sayad", + "Sayeed", + "Sayf", + "Scot", + "Scott", + "Scott-Alexander", + "Seaan", + "Seamas", + "Seamus", + "Sean", + "Seane", + "Sean-James", + "Sean-Paul", + "Sean-Ray", + "Seb", + "Sebastian", + "Sebastien", + "Selasi", + "Seonaidh", + "Sephiroth", + "Sergei", + "Sergio", + "Seth", + "Sethu", + "Seumas", + "Shaarvin", + "Shadow", + "Shae", + "Shahmir", + "Shai", + "Shane", + "Shannon", + "Sharland", + "Sharoz", + "Shaughn", + "Shaun", + "Shaunpaul", + "Shaun-Paul", + "Shaun-Thomas", + "Shaurya", + "Shaw", + "Shawn", + "Shawnpaul", + "Shay", + "Shayaan", + "Shayan", + "Shaye", + "Shayne", + "Shazil", + "Shea", + "Sheafan", + "Sheigh", + "Shenuk", + "Sher", + "Shergo", + "Sheriff", + "Sherwyn", + "Shiloh", + "Shiraz", + "Shreeram", + "Shreyas", + "Shyam", + "Siddhant", + "Siddharth", + "Sidharth", + "Sidney", + "Siergiej", + "Silas", + "Simon", + "Sinai", + "Skye", + "Sofian", + "Sohaib", + "Sohail", + "Soham", + "Sohan", + "Sol", + "Solomon", + "Sonneey", + "Sonni", + "Sonny", + "Sorley", + "Soul", + "Spencer", + "Spondon", + "Stanislaw", + "Stanley", + "Stefan", + "Stefano", + "Stefin", + "Stephen", + "Stephenjunior", + "Steve", + "Steven", + "Steven-lee", + "Stevie", + "Stewart", + "Stewarty", + "Strachan", + "Struan", + "Stuart", + "Su", + "Subhaan", + "Sudais", + "Suheyb", + "Suilven", + "Sukhi", + "Sukhpal", + "Sukhvir", + "Sulayman", + "Sullivan", + "Sultan", + "Sung", + "Sunny", + "Suraj", + "Surien", + "Sweyn", + "Syed", + "Sylvain", + "Symon", + "Szymon", + "Tadd", + "Taddy", + "Tadhg", + "Taegan", + "Taegen", + "Tai", + "Tait", + "Taiwo", + "Talha", + "Taliesin", + "Talon", + "Talorcan", + "Tamar", + "Tamiem", + "Tammam", + "Tanay", + "Tane", + "Tanner", + "Tanvir", + "Tanzeel", + "Taonga", + "Tarik", + "Tariq-Jay", + "Tate", + "Taylan", + "Taylar", + "Tayler", + "Taylor", + "Taylor-Jay", + "Taylor-Lee", + "Tayo", + "Tayyab", + "Tayye", + "Tayyib", + "Teagan", + "Tee", + "Teejay", + "Tee-jay", + "Tegan", + "Teighen", + "Teiyib", + "Te-Jay", + "Temba", + "Teo", + "Teodor", + "Teos", + "Terry", + "Teydren", + "Theo", + "Theodore", + "Thiago", + "Thierry", + "Thom", + "Thomas", + "Thomas-Jay", + "Thomson", + "Thorben", + "Thorfinn", + "Thrinei", + "Thumbiko", + "Tiago", + "Tian", + "Tiarnan", + "Tibet", + "Tieran", + "Tiernan", + "Timothy", + "Timucin", + "Tiree", + "Tisloh", + "Titi", + "Titus", + "Tiylar", + "TJ", + "Tjay", + "T-Jay", + "Tobey", + "Tobi", + "Tobias", + "Tobie", + "Toby", + "Todd", + "Tokinaga", + "Toluwalase", + "Tom", + "Tomas", + "Tomasz", + "Tommi-Lee", + "Tommy", + "Tomson", + "Tony", + "Torin", + "Torquil", + "Torran", + "Torrin", + "Torsten", + "Trafford", + "Trai", + "Travis", + "Tre", + "Trent", + "Trey", + "Tristain", + "Tristan", + "Troy", + "Tubagus", + "Turki", + "Turner", + "Ty", + "Ty-Alexander", + "Tye", + "Tyelor", + "Tylar", + "Tyler", + "Tyler-James", + "Tyler-Jay", + "Tyllor", + "Tylor", + "Tymom", + "Tymon", + "Tymoteusz", + "Tyra", + "Tyree", + "Tyrnan", + "Tyrone", + "Tyson", + "Ubaid", + "Ubayd", + "Uchenna", + "Uilleam", + "Umair", + "Umar", + "Umer", + "Umut", + "Urban", + "Uri", + "Usman", + "Uzair", + "Uzayr", + "Valen", + "Valentin", + "Valentino", + "Valery", + "Valo", + "Vasyl", + "Vedantsinh", + "Veeran", + "Victor", + "Victory", + "Vinay", + "Vince", + "Vincent", + "Vincenzo", + "Vinh", + "Vinnie", + "Vithujan", + "Vladimir", + "Vladislav", + "Vrishin", + "Vuyolwethu", + "Wabuya", + "Wai", + "Walid", + "Wallace", + "Walter", + "Waqaas", + "Warkhas", + "Warren", + "Warrick", + "Wasif", + "Wayde", + "Wayne", + "Wei", + "Wen", + "Wesley", + "Wesley-Scott", + "Wiktor", + "Wilkie", + "Will", + "William", + "William-John", + "Willum", + "Wilson", + "Windsor", + "Wojciech", + "Woyenbrakemi", + "Wyatt", + "Wylie", + "Wynn", + "Xabier", + "Xander", + "Xavier", + "Xiao", + "Xida", + "Xin", + "Xue", + "Yadgor", + "Yago", + "Yahya", + "Yakup", + "Yang", + "Yanick", + "Yann", + "Yannick", + "Yaseen", + "Yasin", + "Yasir", + "Yassin", + "Yoji", + "Yong", + "Yoolgeun", + "Yorgos", + "Youcef", + "Yousif", + "Youssef", + "Yu", + "Yuanyu", + "Yuri", + "Yusef", + "Yusuf", + "Yves", + "Zaaine", + "Zaak", + "Zac", + "Zach", + "Zachariah", + "Zacharias", + "Zacharie", + "Zacharius", + "Zachariya", + "Zachary", + "Zachary-Marc", + "Zachery", + "Zack", + "Zackary", + "Zaid", + "Zain", + "Zaine", + "Zaineddine", + "Zainedin", + "Zak", + "Zakaria", + "Zakariya", + "Zakary", + "Zaki", + "Zakir", + "Zakk", + "Zamaar", + "Zander", + "Zane", + "Zarran", + "Zayd", + "Zayn", + "Zayne", + "Ze", + "Zechariah", + "Zeek", + "Zeeshan", + "Zeid", + "Zein", + "Zen", + "Zendel", + "Zenith", + "Zennon", + "Zeph", + "Zerah", + "Zhen", + "Zhi", + "Zhong", + "Zhuo", + "Zi", + "Zidane", + "Zijie", + "Zinedine", + "Zion", + "Zishan", + "Ziya", + "Ziyaan", + "Zohaib", + "Zohair", + "Zoubaeir", + "Zubair", + "Zubayr", + "Zuriel"] \ No newline at end of file diff --git a/data/invite-codes.db b/data/invite-codes.db new file mode 100644 index 0000000..80a141b Binary files /dev/null and b/data/invite-codes.db differ diff --git a/data/screenshot.png b/data/screenshot.png new file mode 100644 index 0000000..1c85e21 Binary files /dev/null and b/data/screenshot.png differ diff --git a/data/slist.py b/data/slist.py new file mode 100644 index 0000000..1491a8a --- /dev/null +++ b/data/slist.py @@ -0,0 +1,1001 @@ +surname = [ + "Abbott", + "Acevedo", + "Acosta", + "Adams", + "Adkins", + "Agirre", + "Aguilar", + "Albert", + "Alexander", + "Alford", + "Allen", + "Allison", + "Alston", + "Alvarado", + "Alvarez", + "Anderson", + "Andrews", + "Anthony", + "Armstrong", + "Arnold", + "Ashley", + "Atkins", + "Atkinson", + "Austin", + "Avery", + "Avila", + "Ayala", + "Ayers", + "Bailey", + "Baird", + "Baker", + "Baldwin", + "Ball", + "Ballard", + "Banks", + "Barber", + "Barker", + "Barlow", + "Barnes", + "Barnett", + "Barr", + "Barrera", + "Barrett", + "Barron", + "Barry", + "Bartlett", + "Barton", + "Bass", + "Bates", + "Battle", + "Bauer", + "Baxter", + "Beach", + "Bean", + "Beard", + "Beasley", + "Beck", + "Becker", + "Bell", + "Bender", + "Benjamin", + "Bennett", + "Benson", + "Bentley", + "Benton", + "Berg", + "Berger", + "Bernard", + "Berry", + "Best", + "Bird", + "Bishop", + "Black", + "Blackburn", + "Blackwell", + "Blair", + "Blake", + "Blanchard", + "Blankenship", + "Blevins", + "Bolton", + "Bond", + "Bonner", + "Booker", + "Boone", + "Booth", + "Bowen", + "Bowers", + "Bowman", + "Boyd", + "Boyer", + "Boyle", + "Bradford", + "Bradley", + "Bradshaw", + "Brady", + "Branch", + "Bray", + "Brennan", + "Brewer", + "Bridges", + "Briggs", + "Bright", + "Britt", + "Brock", + "Brooks", + "Brown", + "Browning", + "Bruce", + "Bryan", + "Bryant", + "Buchanan", + "Buck", + "Buckley", + "Buckner", + "Bullock", + "Burch", + "Burgess", + "Burke", + "Burks", + "Burnett", + "Burns", + "Burris", + "Burt", + "Burton", + "Bush", + "Butler", + "Byers", + "Byrd", + "Cabrera", + "Cain", + "Calderon", + "Caldwell", + "Calhoun", + "Callahan", + "Camacho", + "Cameron", + "Campbell", + "Campos", + "Cannon", + "Cantrell", + "Cantu", + "Cardenas", + "Carey", + "Carlson", + "Carney", + "Carpenter", + "Carr", + "Carrillo", + "Carroll", + "Carson", + "Carter", + "Carver", + "Case", + "Casey", + "Cash", + "Castaneda", + "Castillo", + "Castro", + "Cervantes", + "Chambers", + "Chan", + "Chandler", + "Chaney", + "Chang", + "Chapman", + "Charles", + "Chase", + "Chavez", + "Chen", + "Cherry", + "Christensen", + "Christian", + "Church", + "Clark", + "Clarke", + "Clay", + "Clayton", + "Clements", + "Clemons", + "Cleveland", + "Cline", + "Cobb", + "Cochran", + "Coffey", + "Cohen", + "Cole", + "Coleman", + "Collier", + "Collins", + "Colon", + "Combs", + "Compton", + "Conley", + "Conner", + "Conrad", + "Contreras", + "Conway", + "Cook", + "Cooke", + "Cooley", + "Cooper", + "Copeland", + "Cortez", + "Cote", + "Cotton", + "Cox", + "Craft", + "Craig", + "Crane", + "Crawford", + "Crosby", + "Cross", + "Cruz", + "Cummings", + "Cunningham", + "Curry", + "Curtis", + "Dale", + "Dalton", + "Daniel", + "Daniels", + "Daugherty", + "Davenport", + "David", + "Davidson", + "Davis", + "Dawson", + "Day", + "Dean", + "Decker", + "Dejesus", + "Delacruz", + "Delaney", + "Deleon", + "Delgado", + "Dennis", + "Diaz", + "Dickerson", + "Dickson", + "Dillard", + "Dillon", + "Dixon", + "Dodson", + "Dominguez", + "Donaldson", + "Donovan", + "Dorsey", + "Dotson", + "Douglas", + "Downs", + "Doyle", + "Drake", + "Dudley", + "Duffy", + "Duke", + "Duncan", + "Dunlap", + "Dunn", + "Duran", + "Durham", + "Dyer", + "Eaton", + "Edwards", + "Elliott", + "Ellis", + "Ellison", + "Emerson", + "England", + "English", + "Erickson", + "Espinoza", + "Estes", + "Estrada", + "Evans", + "Everett", + "Ewing", + "Farley", + "Farmer", + "Farrell", + "Faulkner", + "Ferguson", + "Fernandez", + "Ferrell", + "Fields", + "Figueroa", + "Finch", + "Finley", + "Fischer", + "Fisher", + "Fitzgerald", + "Fitzpatrick", + "Fleming", + "Fletcher", + "Flores", + "Flowers", + "Floyd", + "Flynn", + "Foley", + "Forbes", + "Ford", + "Foreman", + "Foster", + "Fowler", + "Fox", + "Francis", + "Franco", + "Frank", + "Franklin", + "Franks", + "Frazier", + "Frederick", + "Freeman", + "French", + "Frost", + "Fry", + "Frye", + "Fuentes", + "Fuller", + "Fulton", + "Gaines", + "Gallagher", + "Gallegos", + "Galloway", + "Gamble", + "Garcia", + "Gardner", + "Garner", + "Garrett", + "Garrison", + "Garza", + "Gates", + "Gay", + "Gentry", + "George", + "Gibbs", + "Gibson", + "Gilbert", + "Giles", + "Gill", + "Gillespie", + "Gilliam", + "Gilmore", + "Glass", + "Glenn", + "Glover", + "Goff", + "Golden", + "Gomez", + "Gonzales", + "Gonzalez", + "Good", + "Goodman", + "Goodwin", + "Gordon", + "Gould", + "Graham", + "Grant", + "Graves", + "Gray", + "Green", + "Greene", + "Greer", + "Gregory", + "Griffin", + "Griffith", + "Grimes", + "Gross", + "Guerra", + "Guerrero", + "Guthrie", + "Gutierrez", + "Guy", + "Guzman", + "Hahn", + "Hale", + "Haley", + "Hall", + "Hamilton", + "Hammond", + "Hampton", + "Hancock", + "Haney", + "Hansen", + "Hanson", + "Hardin", + "Harding", + "Hardy", + "Harmon", + "Harper", + "Harrell", + "Harrington", + "Harris", + "Harrison", + "Hart", + "Hartman", + "Harvey", + "Hatfield", + "Hawkins", + "Hayden", + "Hayes", + "Haynes", + "Hays", + "Head", + "Heath", + "Hebert", + "Henderson", + "Hendricks", + "Hendrix", + "Henry", + "Hensley", + "Henson", + "Herman", + "Hernandez", + "Herrera", + "Herring", + "Hess", + "Hester", + "Hewitt", + "Hickman", + "Hicks", + "Higgins", + "Hill", + "Hines", + "Hinton", + "Hobbs", + "Hodge", + "Hodges", + "Hoffman", + "Hogan", + "Holcomb", + "Holden", + "Holder", + "Holland", + "Holloway", + "Holman", + "Holmes", + "Holt", + "Hood", + "Hooper", + "Hoover", + "Hopkins", + "Hopper", + "Horn", + "Horne", + "Horton", + "House", + "Houston", + "Howard", + "Howe", + "Howell", + "Hubbard", + "Huber", + "Hudson", + "Huff", + "Huffman", + "Hughes", + "Hull", + "Humphrey", + "Hunt", + "Hunter", + "Hurley", + "Hurst", + "Hutchinson", + "Hyde", + "Ingram", + "Irwin", + "Jackson", + "Jacobs", + "Jacobson", + "James", + "Jarvis", + "Jefferson", + "Jenkins", + "Jennings", + "Jensen", + "Jimenez", + "Johns", + "Johnson", + "Johnston", + "Jones", + "Jordan", + "Joseph", + "Joyce", + "Joyner", + "Juarez", + "Justice", + "Kane", + "Kaufman", + "Keith", + "Keller", + "Kelley", + "Kelly", + "Kemp", + "Kennedy", + "Kent", + "Kerr", + "Key", + "Kidd", + "Kim", + "King", + "Kinney", + "Kirby", + "Kirk", + "Kirkland", + "Klein", + "Kline", + "Knapp", + "Knight", + "Knowles", + "Knox", + "Koch", + "Kramer", + "Lamb", + "Lambert", + "Lancaster", + "Landry", + "Lane", + "Lang", + "Langley", + "Lara", + "Larsen", + "Larson", + "Lawrence", + "Lawson", + "Le", + "Leach", + "Leblanc", + "Lee", + "Leon", + "Leonard", + "Lester", + "Levine", + "Levy", + "Lewis", + "Lindsay", + "Lindsey", + "Little", + "Livingston", + "Lloyd", + "Logan", + "Long", + "Lopez", + "Lott", + "Love", + "Lowe", + "Lowery", + "Lucas", + "Luna", + "Lynch", + "Lynn", + "Lyons", + "Macdonald", + "Macias", + "Mack", + "Madden", + "Maddox", + "Maldonado", + "Malone", + "Mann", + "Manning", + "Marks", + "Marquez", + "Marsh", + "Marshall", + "Martin", + "Martinez", + "Mason", + "Massey", + "Mathews", + "Mathis", + "Matthews", + "Maxwell", + "May", + "Mayer", + "Maynard", + "Mayo", + "Mays", + "Mcbride", + "Mccall", + "Mccarthy", + "Mccarty", + "Mcclain", + "Mcclure", + "Mcconnell", + "Mccormick", + "Mccoy", + "Mccray", + "Mccullough", + "Mcdaniel", + "Mcdonald", + "Mcdowell", + "Mcfadden", + "Mcfarland", + "Mcgee", + "Mcgowan", + "Mcguire", + "Mcintosh", + "Mcintyre", + "Mckay", + "Mckee", + "Mckenzie", + "Mckinney", + "Mcknight", + "Mclaughlin", + "Mclean", + "Mcleod", + "Mcmahon", + "Mcmillan", + "Mcneil", + "Mcpherson", + "Meadows", + "Medina", + "Mejia", + "Melendez", + "Melton", + "Mendez", + "Mendoza", + "Mercado", + "Mercer", + "Merrill", + "Merritt", + "Meyer", + "Meyers", + "Michael", + "Middleton", + "Miles", + "Miller", + "Mills", + "Miranda", + "Mitchell", + "Molina", + "Monroe", + "Montgomery", + "Montoya", + "Moody", + "Moon", + "Mooney", + "Moore", + "Morales", + "Moran", + "Moreno", + "Morgan", + "Morin", + "Morris", + "Morrison", + "Morrow", + "Morse", + "Morton", + "Moses", + "Mosley", + "Moss", + "Mueller", + "Mullen", + "Mullins", + "Munoz", + "Murphy", + "Murray", + "Myers", + "Nash", + "Navarro", + "Neal", + "Nelson", + "Newman", + "Newton", + "Nguyen", + "Nichols", + "Nicholson", + "Nielsen", + "Nieves", + "Nixon", + "Noble", + "Noel", + "Nolan", + "Norman", + "Norris", + "Norton", + "Nunez", + "Obrien", + "Ochoa", + "Oconnor", + "Odom", + "Odonnell", + "Oliver", + "Olsen", + "Olson", + "Oneal", + "Oneil", + "Oneill", + "Orr", + "Ortega", + "Ortiz", + "Osborn", + "Osborne", + "Owen", + "Owens", + "Pace", + "Pacheco", + "Padilla", + "Page", + "Palmer", + "Park", + "Parker", + "Parks", + "Parrish", + "Parsons", + "Pate", + "Patel", + "Patrick", + "Patterson", + "Patton", + "Paul", + "Payne", + "Pearson", + "Peck", + "Pena", + "Pennington", + "Perez", + "Perkins", + "Perry", + "Peters", + "Petersen", + "Peterson", + "Petty", + "Phelps", + "Phillips", + "Pickett", + "Pierce", + "Pittman", + "Pitts", + "Pollard", + "Poole", + "Pope", + "Porter", + "Potter", + "Potts", + "Powell", + "Powers", + "Pratt", + "Preston", + "Price", + "Prince", + "Pruitt", + "Puckett", + "Pugh", + "Quinn", + "Ramirez", + "Ramos", + "Ramsey", + "Randall", + "Randolph", + "Rasmussen", + "Ratliff", + "Ray", + "Raymond", + "Reed", + "Reese", + "Reeves", + "Reid", + "Reilly", + "Reyes", + "Reynolds", + "Rhodes", + "Rice", + "Rich", + "Richard", + "Richards", + "Richardson", + "Richmond", + "Riddle", + "Riggs", + "Riley", + "Rios", + "Rivas", + "Rivera", + "Rivers", + "Roach", + "Robbins", + "Roberson", + "Roberts", + "Robertson", + "Robinson", + "Robles", + "Rocha", + "Rodgers", + "Rodriguez", + "Rodriquez", + "Rogers", + "Rojas", + "Rollins", + "Roman", + "Romero", + "Rosa", + "Rosales", + "Rosario", + "Rose", + "Ross", + "Roth", + "Rowe", + "Rowland", + "Roy", + "Ruiz", + "Rush", + "Russell", + "Russo", + "Rutledge", + "Ryan", + "Salas", + "Salazar", + "Salinas", + "Sampson", + "Sanchez", + "Sanders", + "Sandoval", + "Sanford", + "Santana", + "Santiago", + "Santos", + "Sargent", + "Saunders", + "Savage", + "Sawyer", + "Schmidt", + "Schneider", + "Schroeder", + "Schultz", + "Schwartz", + "Scott", + "Sears", + "Sellers", + "Serrano", + "Sexton", + "Shaffer", + "Shannon", + "Sharp", + "Sharpe", + "Shaw", + "Shelton", + "Shepard", + "Shepherd", + "Sheppard", + "Sherman", + "Shields", + "Short", + "Silva", + "Simmons", + "Simon", + "Simpson", + "Sims", + "Singleton", + "Skinner", + "Slater", + "Sloan", + "Small", + "Smith", + "Snider", + "Snow", + "Snyder", + "Solis", + "Solomon", + "Sosa", + "Soto", + "Sparks", + "Spears", + "Spence", + "Spencer", + "Stafford", + "Stanley", + "Stanton", + "Stark", + "Steele", + "Stein", + "Stephens", + "Stephenson", + "Stevens", + "Stevenson", + "Stewart", + "Stokes", + "Stone", + "Stout", + "Strickland", + "Strong", + "Stuart", + "Suarez", + "Sullivan", + "Summers", + "Sutton", + "Swanson", + "Sweeney", + "Sweet", + "Sykes", + "Talley", + "Tanner", + "Tate", + "Taylor", + "Terrell", + "Terry", + "Thomas", + "Thompson", + "Thornton", + "Tillman", + "Todd", + "Torres", + "Townsend", + "Tran", + "Travis", + "Trevino", + "Trujillo", + "Tucker", + "Turner", + "Tyler", + "Tyson", + "Underwood", + "Valdez", + "Valencia", + "Valentine", + "Valenzuela", + "Vance", + "Vang", + "Vargas", + "Vasquez", + "Vaughan", + "Vaughn", + "Vazquez", + "Vega", + "Velasquez", + "Velazquez", + "Velez", + "Villarreal", + "Vincent", + "Vinson", + "Wade", + "Wagner", + "Walker", + "Wall", + "Wallace", + "Waller", + "Walls", + "Walsh", + "Walter", + "Walters", + "Walton", + "Ward", + "Ware", + "Warner", + "Warren", + "Washington", + "Waters", + "Watkins", + "Watson", + "Watts", + "Weaver", + "Webb", + "Weber", + "Webster", + "Weeks", + "Weiss", + "Welch", + "Wells", + "West", + "Wheeler", + "Whitaker", + "White", + "Whitehead", + "Whitfield", + "Whitley", + "Whitney", + "Wiggins", + "Wilcox", + "Wilder", + "Wiley", + "Wilkerson", + "Wilkins", + "Wilkinson", + "William", + "Williams", + "Williamson", + "Willis", + "Wilson", + "Winters", + "Wise", + "Witt", + "Wolf", + "Wolfe", + "Wong", + "Wood", + "Woodard", + "Woods", + "Woodward", + "Wooten", + "Workman", + "Wright", + "Wyatt", + "Wynn", + "Yang", + "Yates", + "York", + "Young", + "Zamora", + "Zimmerman"] \ No newline at end of file diff --git a/delete.tpl b/delete.tpl new file mode 100644 index 0000000..685958f --- /dev/null +++ b/delete.tpl @@ -0,0 +1,38 @@ + + + + + + + + + {{ str['del-account'] }} + + + + + +
+

{{ str['del-account'] }}

+ +
+ + + + +
+ + +
+ +
+ + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + diff --git a/edit_email.tpl b/edit_email.tpl new file mode 100644 index 0000000..458a604 --- /dev/null +++ b/edit_email.tpl @@ -0,0 +1,38 @@ + + + + + + + + + {{ str['edit-email'] }} + + + + + +
+

{{ str['edit-email'] }}

+ +
+ + + + +
+ + +
+ +
+ + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + diff --git a/edit_fullname.tpl b/edit_fullname.tpl new file mode 100644 index 0000000..c544666 --- /dev/null +++ b/edit_fullname.tpl @@ -0,0 +1,41 @@ + + + + + + + + + {{ str['edit-fn'] }} + + + + + +
+

{{ str['edit-fn'] }}

+ +
+ + + + + + + +
+ + +
+ +
+ + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + diff --git a/index.tpl b/index.tpl new file mode 100644 index 0000000..c47460b --- /dev/null +++ b/index.tpl @@ -0,0 +1,37 @@ + + + + + + + + + {{ str['login'] }} + + + + + +
+

{{ str['login'] }}

+ +
+ + + + + + + + {{ str['or-sign-up'] }} +
+ + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + diff --git a/locales/base.pot b/locales/base.pot new file mode 100644 index 0000000..642cbd6 --- /dev/null +++ b/locales/base.pot @@ -0,0 +1,215 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: 0.0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-07 17:23+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Aitzol Berasategi \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: app.py:880 +msgid "User" +msgstr "" + +#: app.py:881 +msgid "Username" +msgstr "" + +#: app.py:882 +msgid "Firstname" +msgstr "" + +#: app.py:883 +msgid "Surname" +msgstr "" + +#: app.py:884 +msgid "Password" +msgstr "" + +#: app.py:885 +msgid "Old password" +msgstr "" + +#: app.py:886 +msgid "New password" +msgstr "" + +#: app.py:887 +msgid "Confirm password" +msgstr "" + +#: app.py:888 +msgid "Email" +msgstr "" + +#: app.py:889 +msgid "edit" +msgstr "" + +#: app.py:890 +msgid "Login" +msgstr "" + +#: app.py:891 +msgid "Logout" +msgstr "" + +#: app.py:892 +msgid "Delete" +msgstr "" + +#: app.py:893 +msgid "Sign Up" +msgstr "" + +#: app.py:894 +msgid "Back" +msgstr "" + +#: app.py:895 +msgid "Update" +msgstr "" + +#: app.py:896 +msgid "Or Sign In" +msgstr "" + +#: app.py:897 +msgid "Or Sign Up" +msgstr "" + +#: app.py:898 +msgid "Invite code" +msgstr "" + +#: app.py:899 +msgid "Edit your fullname" +msgstr "" + +#: app.py:900 +msgid "Edit your email" +msgstr "" + +#: app.py:901 +msgid "Change your password" +msgstr "" + +#: app.py:902 +msgid "Delete your account" +msgstr "" + +#: app.py:903 app.py:909 +msgid "Welcome" +msgstr "" + +#: app.py:906 +msgid "The session was closed." +msgstr "" + +#: app.py:907 +msgid "Username must be at least 3 characters long!" +msgstr "" + +#: app.py:908 +msgid "Please enter your password!" +msgstr "" + +#: app.py:910 +msgid "The code is invalid or has expired." +msgstr "" + +#: app.py:911 +msgid "A bit short, don't you think?!" +msgstr "" + +#: app.py:912 +msgid "Not allowed characters for the username field." +msgstr "" + +#: app.py:913 +msgid "Passwords do not match!" +msgstr "" + +#: app.py:914 +msgid "Password must be at least 8 characters long!" +msgstr "" + +#: app.py:915 +msgid "Congratulations, your account has been created!" +msgstr "" + +#: app.py:916 +msgid "Your firstname is a bit short, don't you think?" +msgstr "" + +#: app.py:917 +msgid "Your surname is a bit short, don't you think?" +msgstr "" + +#: app.py:918 +msgid "Your first and last name have been successfully updated." +msgstr "" + +#: app.py:919 +msgid "Invalid email address. Please try again." +msgstr "" + +#: app.py:920 +msgid "Your email has been successfully updated." +msgstr "" + +#: app.py:921 +msgid "The password entered is the same as the current password." +msgstr "" + +#: app.py:922 +msgid "Password has been changed!" +msgstr "" + +#: app.py:923 +msgid "Please, type your username for account deletion." +msgstr "" + +#: app.py:924 +msgid "Account successfully deleted!" +msgstr "" + +#: app.py:925 +msgid "Username or password is incorrect!" +msgstr "" + +#: app.py:926 +msgid "Unable to connect to the remote server." +msgstr "" + +#: app.py:927 +msgid "" +"Encountered an unexpected error while communicating with the remote server." +msgstr "" + +#: app.py:928 +msgid "User already exists." +msgstr "" + +#: app.py:929 +msgid "Email already exists." +msgstr "" + +#: app.py:930 +msgid "Forgot your password? Please try again." +msgstr "" + +#: app.py:931 +msgid "The session has expired." +msgstr "" \ No newline at end of file diff --git a/locales/en/LC_MESSAGES/base.mo b/locales/en/LC_MESSAGES/base.mo new file mode 100644 index 0000000..ddd17cc Binary files /dev/null and b/locales/en/LC_MESSAGES/base.mo differ diff --git a/locales/en/LC_MESSAGES/base.po b/locales/en/LC_MESSAGES/base.po new file mode 100644 index 0000000..0dc32d1 --- /dev/null +++ b/locales/en/LC_MESSAGES/base.po @@ -0,0 +1,215 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: 0.0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-07 17:23+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Aitzol Berasategi \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: app.py:880 +msgid "User" +msgstr "User" + +#: app.py:881 +msgid "Username" +msgstr "Username" + +#: app.py:882 +msgid "Firstname" +msgstr "Firstname" + +#: app.py:883 +msgid "Surname" +msgstr "Surname" + +#: app.py:884 +msgid "Password" +msgstr "Password" + +#: app.py:885 +msgid "Old password" +msgstr "Old password" + +#: app.py:886 +msgid "New password" +msgstr "New password" + +#: app.py:887 +msgid "Confirm password" +msgstr "Confirm password" + +#: app.py:888 +msgid "Email" +msgstr "Email" + +#: app.py:889 +msgid "edit" +msgstr "edit" + +#: app.py:890 +msgid "Login" +msgstr "Login" + +#: app.py:891 +msgid "Logout" +msgstr "Logout" + +#: app.py:892 +msgid "Delete" +msgstr "Delete" + +#: app.py:893 +msgid "Sign Up" +msgstr "Sign Up" + +#: app.py:894 +msgid "Back" +msgstr "Back" + +#: app.py:895 +msgid "Update" +msgstr "Update" + +#: app.py:896 +msgid "Or Sign In" +msgstr "Or Sign In" + +#: app.py:897 +msgid "Or Sign Up" +msgstr "Or Sign Up" + +#: app.py:898 +msgid "Invite code" +msgstr "Invite code" + +#: app.py:899 +msgid "Edit your fullname" +msgstr "Edit your fullname" + +#: app.py:900 +msgid "Edit your email" +msgstr "Edit your email" + +#: app.py:901 +msgid "Change your password" +msgstr "Change your password" + +#: app.py:902 +msgid "Delete your account" +msgstr "Delete your account" + +#: app.py:903 app.py:909 +msgid "Welcome" +msgstr "Welcome" + +#: app.py:906 +msgid "The session was closed." +msgstr "The session was closed." + +#: app.py:907 +msgid "Username must be at least 3 characters long!" +msgstr "Username must be at least 3 characters long!" + +#: app.py:908 +msgid "Please enter your password!" +msgstr "Please enter your password!" + +#: app.py:910 +msgid "The code is invalid or has expired." +msgstr "The code is invalid or has expired." + +#: app.py:911 +msgid "A bit short, don't you think?!" +msgstr "A bit short, don't you think?!" + +#: app.py:912 +msgid "Not allowed characters for the username field." +msgstr "Not allowed characters for the username field." + +#: app.py:913 +msgid "Passwords do not match!" +msgstr "Passwords do not match!" + +#: app.py:914 +msgid "Password must be at least 8 characters long!" +msgstr "Password must be at least 8 characters long!" + +#: app.py:915 +msgid "Congratulations, your account has been created!" +msgstr "Congratulations, your account has been created!" + +#: app.py:916 +msgid "Your firstname is a bit short, don't you think?" +msgstr "Your firstname is a bit short, don't you think?" + +#: app.py:917 +msgid "Your surname is a bit short, don't you think?" +msgstr "Your surname is a bit short, don't you think?" + +#: app.py:918 +msgid "Your first and last name have been successfully updated." +msgstr "Your first and last name have been successfully updated." + +#: app.py:919 +msgid "Invalid email address. Please try again." +msgstr "Invalid email address. Please try again." + +#: app.py:920 +msgid "Your email has been successfully updated." +msgstr "Your email has been successfully updated." + +#: app.py:921 +msgid "The password entered is the same as the current password." +msgstr "The password entered is the same as the current password." + +#: app.py:922 +msgid "Password has been changed!" +msgstr "Password has been changed!" + +#: app.py:923 +msgid "Please, type your username for account deletion." +msgstr "Please, type your username for account deletion." + +#: app.py:924 +msgid "Account successfully deleted!" +msgstr "Account successfully deleted!" + +#: app.py:925 +msgid "Username or password is incorrect!" +msgstr "Username or password is incorrect!" + +#: app.py:926 +msgid "Unable to connect to the remote server." +msgstr "Unable to connect to the remote server." + +#: app.py:927 +msgid "" +"Encountered an unexpected error while communicating with the remote server." +msgstr "Encountered an unexpected error while communicating with the remote server." + +#: app.py:928 +msgid "User already exists." +msgstr "User already exists." + +#: app.py:929 +msgid "Email already exists." +msgstr "Email already exists." + +#: app.py:930 +msgid "Forgot your password? Please try again." +msgstr "Forgot your password? Please try again." + +#: app.py:931 +msgid "The session has expired." +msgstr "The session has expired." diff --git a/locales/eu/LC_MESSAGES/base.mo b/locales/eu/LC_MESSAGES/base.mo new file mode 100644 index 0000000..0f92fda Binary files /dev/null and b/locales/eu/LC_MESSAGES/base.mo differ diff --git a/locales/eu/LC_MESSAGES/base.po b/locales/eu/LC_MESSAGES/base.po new file mode 100644 index 0000000..9ee7630 --- /dev/null +++ b/locales/eu/LC_MESSAGES/base.po @@ -0,0 +1,215 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , 2022. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: 0.0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-04-07 17:23+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Aitzol Berasategi \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: app.py:880 +msgid "User" +msgstr "Erabiltzailea" + +#: app.py:881 +msgid "Username" +msgstr "Erabiltzaile izena" + +#: app.py:882 +msgid "Firstname" +msgstr "Izena" + +#: app.py:883 +msgid "Surname" +msgstr "Abizena" + +#: app.py:884 +msgid "Password" +msgstr "Pasahitza" + +#: app.py:885 +msgid "Old password" +msgstr "Pasahitz zaharra" + +#: app.py:886 +msgid "New password" +msgstr "Pasahitz berria" + +#: app.py:887 +msgid "Confirm password" +msgstr "Pasahitza berretsi" + +#: app.py:888 +msgid "Email" +msgstr "Emaila" + +#: app.py:889 +msgid "edit" +msgstr "editatu" + +#: app.py:890 +msgid "Login" +msgstr "Saioa hasi" + +#: app.py:891 +msgid "Logout" +msgstr "Saioa itxi" + +#: app.py:892 +msgid "Delete" +msgstr "Ezabatu" + +#: app.py:893 +msgid "Sign Up" +msgstr "Kontua sortu" + +#: app.py:894 +msgid "Back" +msgstr "Itzuli" + +#: app.py:895 +msgid "Update" +msgstr "Eguneratu" + +#: app.py:896 +msgid "Or Sign In" +msgstr "Edo Saioa hasi" + +#: app.py:897 +msgid "Or Sign Up" +msgstr "Edo Kontua sortu" + +#: app.py:898 +msgid "Invite code" +msgstr "Gonbidapen kodea" + +#: app.py:899 +msgid "Edit your fullname" +msgstr "Izen-abizenak editatu" + +#: app.py:900 +msgid "Edit your email" +msgstr "Email helbidea editatu" + +#: app.py:901 +msgid "Change your password" +msgstr "Pasahitza eguneratu" + +#: app.py:902 +msgid "Delete your account" +msgstr "Kontua ezabatu" + +#: app.py:903 app.py:909 +msgid "Welcome" +msgstr "Ongi etorri" + +#: app.py:906 +msgid "The session was closed." +msgstr "Saioa itxi da." + +#: app.py:907 +msgid "Username must be at least 3 characters long!" +msgstr "Erabiltzaile izenak gutxienez 3 karaktere izan behar ditu!" + +#: app.py:908 +msgid "Please enter your password!" +msgstr "Sartu zure pasahitza, mesedez!" + +#: app.py:910 +msgid "The code is invalid or has expired." +msgstr "Kodea baliogabea da edo iraungi egin da." + +#: app.py:911 +msgid "A bit short, don't you think?!" +msgstr "Labur-xamarra, ez duzu uste?" + +#: app.py:912 +msgid "Not allowed characters for the username field." +msgstr "Erabiltzaile izenerako onartzen ez diren karaktereak." + +#: app.py:913 +msgid "Passwords do not match!" +msgstr "Pasahitzak ez datoz bat!" + +#: app.py:914 +msgid "Password must be at least 8 characters long!" +msgstr "Pasahitzak gutxienez 8 karaktereko luzera izan behar du!" + +#: app.py:915 +msgid "Congratulations, your account has been created!" +msgstr "Zorionak, zure kontua sortu da!" + +#: app.py:916 +msgid "Your firstname is a bit short, don't you think?" +msgstr "Zure izena labur-xamarra da, ez duzu uste?" + +#: app.py:917 +msgid "Your surname is a bit short, don't you think?" +msgstr "Zure abizena labur-xamarra da, ez duzu uste?" + +#: app.py:918 +msgid "Your first and last name have been successfully updated." +msgstr "Zure izen-abizenak ongi eguneratu dira." + +#: app.py:919 +msgid "Invalid email address. Please try again." +msgstr "Baliogabeko email helbidea. Saia zaitez berriz, mesedez. " + +#: app.py:920 +msgid "Your email has been successfully updated." +msgstr "Zure emaila ongi eguneratu da." + +#: app.py:921 +msgid "The password entered is the same as the current password." +msgstr "Sartutako pasahitza egungo pasahitzaren berdina da." + +#: app.py:922 +msgid "Password has been changed!" +msgstr "Pasahitza eguneratua izan da!" + +#: app.py:923 +msgid "Please, type your username for account deletion." +msgstr "Kontua ezabatzeko idatzi zure erabiltzaile izena, mesedez." + +#: app.py:924 +msgid "Account successfully deleted!" +msgstr "Kontua ongi ezabatu da!" + +#: app.py:925 +msgid "Username or password is incorrect!" +msgstr "Erabiltzaile izena edo pasahitza okerrak dira!" + +#: app.py:926 +msgid "Unable to connect to the remote server." +msgstr "Ezinezkoa urruneko zerbitzara konektatzea." + +#: app.py:927 +msgid "" +"Encountered an unexpected error while communicating with the remote server." +msgstr "Ezusteko errore bat gertatu da urruneko zerbitzariarekin komunikatzean." + +#: app.py:928 +msgid "User already exists." +msgstr "Erabiltzaile hori existitzen da." + +#: app.py:929 +msgid "Email already exists" +msgstr "Email hori existitzen da." + +#: app.py:930 +msgid "Forgot your password? Please try again." +msgstr "Zure pasahitza ahaztu duzu? Saia zeitez berriz, mesedez." + +#: app.py:931 +msgid "The session has expired." +msgstr "Saioa iraungi egin da." diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..207ea11 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +bottle>=0.12.19 +ldap3>=2.9.1 \ No newline at end of file diff --git a/settings.ini.example b/settings.ini.example new file mode 100644 index 0000000..2a54054 --- /dev/null +++ b/settings.ini.example @@ -0,0 +1,42 @@ +#[html] +#page_title = Login + +[ldap:0] +host = localhost +port = 636 +use_ssl = True +base = ou=groups,dc=example,dc=org +search_filter = uid={uid} + +# LDAP zerbitzariak gehitu nahi badira... +#[ldap:1] +#host = localhost +#base = ou=People,dc=example,dc=org +#search_filter = uid={uid} + +[uwsgi] +plugins = python3 +socket = /run/uwsgi/main.sock +chdir = /var/www/scripts +logger = file:/var/log/uwsgi/main.log +processes = 1 +threads = 2 +# map URI paths to applications +mount = /admin/ldap-python-webui=ldap-python-webui/app.py +manage-script-name = true + +[server] +server = auto +host = localhost +port = 8080 + +[session] +type = file +expire = 300 +data_dir = ./session +auto = true + +[locale] +dir = ./locales +#default lang +lang = en \ No newline at end of file diff --git a/signup.tpl b/signup.tpl new file mode 100644 index 0000000..a110e8b --- /dev/null +++ b/signup.tpl @@ -0,0 +1,55 @@ + + + + + + + + + {{ str['sign-up'] }} + + + + + +
+

{{ str['sign-up'] }}

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + {{ str['or-sign-in'] }} + +
+ + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..02b49ca --- /dev/null +++ b/static/style.css @@ -0,0 +1,203 @@ +body { + font-family: sans-serif; + color: #333; +} + +main { + margin: 0 auto; +} + +h1 { + font-size: 2em; + margin-bottom: 2.5em; + margin-top: 2em; + text-align: center; +} + +h1 span{ + text-transform: capitalize; +} + +a:link{ + text-decoration: none; +} + +a:active { + color: #1F1F1F; +} + +.user p{ + text-transform: capitalize; +} +.edit { + display: none; +} + +form[name="fullNameForm"] input{ + text-transform: capitalize; +} + + +form { +/* border-radius: 0.2rem; + border: 1px solid #CCC;*/ + margin: 0 auto; + max-width: 16rem; + padding: 2rem 2.5rem 1.5rem 2.5rem; +} + +input { + background-color: #FAFAFA; + border-radius: 0.2rem; + border: 1px solid #CCC; + box-shadow: inset 0 1px 3px #DDD; + box-sizing: border-box; + display: block; + font-size: 1em; + padding: 0.4em 0.6em; + vertical-align: middle; + width: 100%; +} + +.form-buttons{ + display:flex; + flex-direction:row; +} + +.form-buttons > a, .form-buttons > button{ + flex-grow:1; +} + +input:focus { + background-color: #FFF; + border-color: #51A7E8; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075) inset, 0 0 5px rgba(81, 167, 232, 0.5); + outline: 0; +} + +input.not-required { + background-color: #E0E0E0; +} + +label { + color: #666; + display: block; + font-size: 0.9em; + font-weight: bold; + margin: 1em 0 0.25em 0; +} + +button { + border-radius: 0.2rem; + border: 1px solid; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: block; + font-size: 0.9em; + font-weight: bold; + margin: 2em 0 0.5em 0; + padding: 0.5em 0.7em; + text-align: center; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.3); + user-select: none; + vertical-align: middle; + white-space: nowrap; +} + +button.green { + background-color: #60B044; + background-image: linear-gradient(#8ADD6D, #60B044); + border-color: #5CA941; +} +button.green:focus, +button.green:hover { + background-color: #569E3D; + background-image: linear-gradient(#79D858, #569E3D); + border-color: #4A993E; +} + +button.red { + background-color: #E74C3C; + background-image: linear-gradient(#CF0B04, #E74C3C); + border-color: #C0392B; +} +button.red:focus, +button.red:hover{ + background-color: #D13E2E; + background-image: linear-gradient(#CF0000, #D13E2E); + border-color: #C92F1E; +} + + +/*alerts*/ +.alerts { + margin: 2rem auto 0 auto; + max-width: 30rem; + animation-duration: 5s; + animation-fill-mode: both; + -webkit-animation-duration: 5s; + -webkit-animation-fill-mode: both; +} + +.alert { + border-radius: 0.2rem; + border: 1px solid; + color: #fff; + padding: 0.7em 1.5em; +} + +.alert.error { + background-color: #E74C3C; + border-color: #C0392B; +} + +.alert.success { + background-color: #60B044; + border-color: #5CA941; +} + +@-webkit-keyframes fadeOut { + 0% {opacity: 1;} + 70% {opacity: 1;} + 100% {opacity: 0;} +} + +@keyframes fadeOut { + 0% {opacity: 1;} + 60% {opacity: 1;} + 100% {opacity: 0;} +} + +.fadeOut { + -webkit-animation-name: fadeOut; + animation-name: fadeOut; +} + +/**/ +.grid-container { + display: grid; + grid-template-columns: 90% 10%; + margin: 0 auto; + max-width: 16rem; + padding: 0 2.5rem 0 2.5rem; + align-items: first baseline; +} +.grid-item a { + color: #222; +} +.grid-item a:visited { + color: #888; +} +.grid-item h5 { + text-transform: capitalize; +} + +/**/ +@media only screen and (max-width: 480px) { + + form { + border: 0; + } +} diff --git a/user.tpl b/user.tpl new file mode 100644 index 0000000..d46c1d3 --- /dev/null +++ b/user.tpl @@ -0,0 +1,74 @@ + + + + + + + + + {{ str['welcome'] }} + + + + + +
+

{{ str['welcome'] }} {{ data['username'] }}

+ +
+
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + + +
+ + + %for type, text, animation in get('alerts', []): +
+
{{ text }}
+
+ %end + +
+ + + +