diff options
| -rw-r--r-- | .env.example | 17 | ||||
| -rw-r--r-- | .gitignore | 42 | ||||
| -rw-r--r-- | Caddyfile | 71 | ||||
| -rw-r--r-- | LICENSE | 661 | ||||
| -rw-r--r-- | README.txt | 22 | ||||
| -rw-r--r-- | contact-cert.pgp | 913 | ||||
| -rw-r--r-- | contact-cert.pgp.license | 2 | ||||
| -rw-r--r-- | contact-service/Cargo.lock | 802 | ||||
| -rw-r--r-- | contact-service/Cargo.toml | 11 | ||||
| -rw-r--r-- | contact-service/src/main.rs | 215 | ||||
| -rw-r--r-- | contact.env.example | 19 | ||||
| -rw-r--r-- | docker-compose.yml | 54 | ||||
| -rw-r--r-- | searxng/settings.yml | 24 | ||||
| -rw-r--r-- | www/.well-known/openpgpkey/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp | bin | 0 -> 427 bytes | |||
| -rw-r--r-- | www/.well-known/openpgpkey/luuduct.ai/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp | bin | 0 -> 427 bytes | |||
| -rw-r--r-- | www/.well-known/openpgpkey/luuduct.ai/policy | 0 | ||||
| -rw-r--r-- | www/.well-known/openpgpkey/policy | 0 | ||||
| -rw-r--r-- | www/form.css | 190 | ||||
| -rw-r--r-- | www/index.html | 153 | ||||
| -rw-r--r-- | www/message.html | 87 | ||||
| -rw-r--r-- | www/styles.css | 123 |
21 files changed, 3406 insertions, 0 deletions
diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1a3dc2c --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +MIROTALK_HOST_USERS='[{"username":"admin","password":"CHANGE_THIS_PASSWORD"}]' +SEARXNG_SECRET=GENERATE_RANDOM_HEX_KEY diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1c4f2e3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,42 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# Environment & secrets +.env +contact.env +*.rev +*.key +*.priv + +# Stored visitor messages +inbox/ + +# Compiled binaries and Rust artifacts +bin/ +target/ +**/target/ + +# Caddy TLS certs and runtime state (prevents permission errors) +caddy/ + +# Empty placeholder directories +git/ +mirotalk/ + +# OS / Editor clutter +.DS_Store +*.swp +*.bak +www/favicon.svg diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..301661d --- /dev/null +++ b/Caddyfile @@ -0,0 +1,71 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +luuduct.ai { + handle /.well-known/openpgpkey/* { + root * /srv + header Content-Type application/octet-stream + file_server + } + + handle { + redir https://doan.luuduct.ai{uri} permanent + } +} + +www.luuduct.ai { + redir https://doan.luuduct.ai{uri} permanent +} + +doan.luuduct.ai { + root * /srv + file_server + + redir /git /git/ + + handle /send-message { + reverse_proxy host.docker.internal:8085 + } + + handle /cgit* { + reverse_proxy host.docker.internal:8082 + } + + handle /git/* { + reverse_proxy host.docker.internal:8082 + } +} + +openpgpkey.luuduct.ai { + handle /.well-known/openpgpkey/* { + root * /srv + header Content-Type application/octet-stream + file_server + } +} + +git.doan.luuduct.ai { + redir /{path}.git /{path} permanent + + reverse_proxy host.docker.internal:8082 +} + +search.doan.luuduct.ai { + reverse_proxy searxng:8080 +} + +meet.doan.luuduct.ai { + reverse_proxy mirotalk:3000 +} @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +<https://www.gnu.org/licenses/>. diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..324814a --- /dev/null +++ b/README.txt @@ -0,0 +1,22 @@ +================================================================================ +SERVER STACK FOR https://doan.luuduct.ai (infra) +================================================================================ + +Personal infrastructure stack. + +LICENSE +-------------------------------------------------------------------------------- +All software, configuration files, and documentation in this repository are +licensed under the GNU Affero General Public License v3.0 or later +(AGPL-3.0-or-later). See the LICENSE file for details. + +Licensing Exceptions & Public Domain Dedications: + +- contact-cert.pgp and www/.well-known/openpgpkey/**: + Public cryptographic key material and Web Key Directory endpoints are + dedicated to the public domain under CC0 1.0 Universal: + https://creativecommons.org/publicdomain/zero/1.0/ + +- contact-service/Cargo.lock: + Machine-generated dependency lockfile. + diff --git a/contact-cert.pgp b/contact-cert.pgp new file mode 100644 index 0000000..0dff628 --- /dev/null +++ b/contact-cert.pgp @@ -0,0 +1,913 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: 2C53 4169 EEEB 0E82 C257 C189 BA35 BF64 6403 1763 95A5 D143 D890 3A62 4156 DB7D +Comment: Website Contact Form Receiver + +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 +AAAAAAAAAAAAAAQKERUfJCgu +-----END PGP PUBLIC KEY BLOCK----- diff --git a/contact-cert.pgp.license b/contact-cert.pgp.license new file mode 100644 index 0000000..638bed1 --- /dev/null +++ b/contact-cert.pgp.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2026 Doan Luu Duc Tai <doan@luuduct.ai> +SPDX-License-Identifier: CC0-1.0 diff --git a/contact-service/Cargo.lock b/contact-service/Cargo.lock new file mode 100644 index 0000000..caf09cc --- /dev/null +++ b/contact-service/Cargo.lock @@ -0,0 +1,802 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "axum" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "contact-service" +version = "0.1.0" +dependencies = [ + "axum", + "chrono", + "serde", + "tokio", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "slab", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "bytes", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "js-sys" +version = "0.3.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce57d20d1ea864ce2ac172ab472d409214f4fd359f0b2a2775abdf522e2af99e" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mio" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.5", +] + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "unicode-ident" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab72a15cf68d77cb0987d3684aa8a45c5ef827e8cb49ee2f30bfd7ba2feb519f" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aecb87a33d3b0c5e3b7aa46336eaf486cffafbd281b195e4c8b80d50df2351bf" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a690d511e3c1a8b3a55e33511e3c2c00c78415cd23650f32b808627f5696b9ed" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411e4887f0071ef2d2164a9d5fdf2d20efbef78fccd3a78b0c10a1dc5295e48a" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.5", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.128" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81941cd78d0c92026c33e5e01312845a4cb1e9af3407f9134b100dd03144103e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/contact-service/Cargo.toml b/contact-service/Cargo.toml new file mode 100644 index 0000000..b06ac33 --- /dev/null +++ b/contact-service/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "contact-service" +version = "0.1.0" +edition = "2021" +license = "AGPL-3.0-or-later" + +[dependencies] +axum = "0.8" +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } +chrono = "0.4" diff --git a/contact-service/src/main.rs b/contact-service/src/main.rs new file mode 100644 index 0000000..b83bbb8 --- /dev/null +++ b/contact-service/src/main.rs @@ -0,0 +1,215 @@ +// Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +use axum::{ + extract::{Form, State}, + response::Html, + routing::post, + Router, +}; +use chrono::Utc; +use serde::Deserialize; +use std::io::Write; +use std::path::PathBuf; +use std::process::{Command, Stdio}; +use std::sync::Arc; + +#[derive(Clone)] +struct AppConfig { + bind_addr: String, + cert_path: PathBuf, + inbox_dir: PathBuf, + sq_bin: PathBuf, +} + +impl AppConfig { + fn from_env() -> Self { + let home = std::env::var("HOME").unwrap_or_else(|_| "/home/ops".into()); + + Self { + bind_addr: std::env::var("BIND_ADDR").unwrap_or_else(|_| "0.0.0.0:8085".into()), + cert_path: PathBuf::from( + std::env::var("CERT_PATH") + .unwrap_or_else(|_| format!("{}/stack/contact-cert.pgp", home)), + ), + inbox_dir: PathBuf::from( + std::env::var("INBOX_DIR") + .unwrap_or_else(|_| format!("{}/stack/inbox", home)), + ), + sq_bin: PathBuf::from( + std::env::var("SQ_BIN") + .unwrap_or_else(|_| format!("{}/.cargo/bin/sq", home)), + ), + } + } +} + +#[derive(Deserialize)] +struct ContactForm { + sender: Option<String>, + message: String, +} + +#[tokio::main] +async fn main() { + let config = Arc::new(AppConfig::from_env()); + + let app = Router::new() + .route("/send-message", post(handle_message)) + .with_state(config.clone()); + + let listener = tokio::net::TcpListener::bind(&config.bind_addr) + .await + .unwrap_or_else(|_| panic!("Failed to bind to {}", config.bind_addr)); + + println!("Contact backend listening on http://{}", config.bind_addr); + println!("Using PQC Cert: {:?}", config.cert_path); + println!("Storing inbox in: {:?}", config.inbox_dir); + + axum::serve(listener, app).await.unwrap(); +} + +async fn handle_message( + State(config): State<Arc<AppConfig>>, + Form(form): Form<ContactForm>, +) -> Html<&'static str> { + let message = form.message.trim(); + if message.is_empty() { + return Html(ERROR_PAGE); + } + + let raw_sender = form.sender.as_deref().unwrap_or("").trim(); + let sender_display = if raw_sender.is_empty() { + "Anonymous" + } else { + raw_sender + }; + + let now = Utc::now(); + let timestamp_str = now.format("%Y-%m-%d_%H-%M-%S").to_string(); + + let sanitized_sender: String = raw_sender + .chars() + .filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_') + .take(30) + .collect(); + + let filename = if sanitized_sender.is_empty() { + format!("{}.pgp", timestamp_str) + } else { + format!("{}_{}.pgp", timestamp_str, sanitized_sender) + }; + + let output_path = config.inbox_dir.join(filename); + + let payload = format!( + "=== RFC 9980 PQC MESSAGE ===\nSender: {}\nTimestamp: {}\n============================\n\n{}", + sender_display, + now.to_rfc3339(), + message + ); + + let mut child = match Command::new(&config.sq_bin) + .args([ + "encrypt", + "--for-file", + config.cert_path.to_str().unwrap_or_default(), + "--without-signature", + ]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + { + Ok(proc) => proc, + Err(e) => { + eprintln!("Failed to spawn sq binary ({:?}): {}", config.sq_bin, e); + return Html(ERROR_PAGE); + } + }; + + if let Some(mut stdin) = child.stdin.take() { + if stdin.write_all(payload.as_bytes()).is_err() { + return Html(ERROR_PAGE); + } + } + + let output = match child.wait_with_output() { + Ok(out) => out, + Err(_) => return Html(ERROR_PAGE), + }; + + if !output.status.success() { + eprintln!( + "sq encryption failed: {}", + String::from_utf8_lossy(&output.stderr) + ); + return Html(ERROR_PAGE); + } + + if std::fs::write(&output_path, &output.stdout).is_err() { + eprintln!("Failed to write to file {:?}", output_path); + return Html(ERROR_PAGE); + } + + Html(SUCCESS_PAGE) +} + +const SUCCESS_PAGE: &str = r#"<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <title>Message Sent - Doan Luu Duc Tai</title> + <link rel="stylesheet" href="/styles.css"> +</head> +<body> + <div id="page"> + <div class="badge">[ JS-free ]</div> + <div id="content"> + <pre> +<a href="/" class="logo"> + ____ ___ _ _ _ +| _ \ / _ \ / \ | \ | | +| | | | | | |/ _ \ | \| | +| |_| | |_| / ___ \| |\ | +|____/ \___/_/ \_\_| \_| LUU DUC TAI +</a> + ++------------------------------------------------------------------------------+ +| [+] Success: Message encrypted and delivered to inbox. | ++------------------------------------------------------------------------------+ + +<a href="/"><-- Return to Home Page</a> + </pre> + </div> + </div> +</body> +</html>"#; + +const ERROR_PAGE: &str = r#"<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>Error</title> + <link rel="stylesheet" href="/styles.css"> +</head> +<body> + <pre> +[!] Error: Unable to process or encrypt message. + +<a href="/message.html"><-- Try Again</a> + </pre> +</body> +</html>"#; diff --git a/contact.env.example b/contact.env.example new file mode 100644 index 0000000..23afec1 --- /dev/null +++ b/contact.env.example @@ -0,0 +1,19 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +BIND_ADDR=0.0.0.0:8085 +CERT_PATH=/path/to/contact-cert.pgp +INBOX_DIR=/path/to/inbox +SQ_BIN=/path/to/sq diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..28e79c6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,54 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +services: + caddy: + image: caddy:2-alpine + restart: unless-stopped + ports: + - "80:80" + - "443:443" + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - ./caddy/data:/data + - ./caddy/config:/config + - ./www:/srv:ro + networks: [gateway] + + searxng: + image: searxng/searxng:latest + restart: unless-stopped + cap_drop: [ALL] + security_opt: [no-new-privileges:true] + env_file: .env + volumes: + - ./searxng:/etc/searxng + networks: [gateway] + + mirotalk: + image: mirotalk/p2p:latest + restart: unless-stopped + cap_drop: [ALL] + security_opt: [no-new-privileges:true] + environment: + HOST_PROTECTED: "true" + HOST_USER_AUTH: "false" + HOST_USERS: ${MIROTALK_HOST_USERS} + networks: [gateway] + +networks: + gateway: diff --git a/searxng/settings.yml b/searxng/settings.yml new file mode 100644 index 0000000..f8f7d6b --- /dev/null +++ b/searxng/settings.yml @@ -0,0 +1,24 @@ +# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +use_default_settings: true + +server: + limiter: true + public_instance: false + +search: + formats: + - html diff --git a/www/.well-known/openpgpkey/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp b/www/.well-known/openpgpkey/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp Binary files differnew file mode 100644 index 0000000..f0fa994 --- /dev/null +++ b/www/.well-known/openpgpkey/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp diff --git a/www/.well-known/openpgpkey/luuduct.ai/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp b/www/.well-known/openpgpkey/luuduct.ai/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp Binary files differnew file mode 100644 index 0000000..f0fa994 --- /dev/null +++ b/www/.well-known/openpgpkey/luuduct.ai/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp diff --git a/www/.well-known/openpgpkey/luuduct.ai/policy b/www/.well-known/openpgpkey/luuduct.ai/policy new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/www/.well-known/openpgpkey/luuduct.ai/policy diff --git a/www/.well-known/openpgpkey/policy b/www/.well-known/openpgpkey/policy new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/www/.well-known/openpgpkey/policy diff --git a/www/form.css b/www/form.css new file mode 100644 index 0000000..e2e42ae --- /dev/null +++ b/www/form.css @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +.ascii-form-container { + width: 80ch; + max-width: 100%; + margin: 16px 0; + display: flex; + flex-direction: column; + gap: 16px; + box-sizing: border-box; +} + +.ascii-box { + display: flex; + flex-direction: column; + width: 100%; +} + +.ascii-bar { + font: inherit; + line-height: 1.2; + white-space: pre; + user-select: none; + color: inherit; +} + +.ascii-body { + display: flex; + align-items: stretch; + min-height: 1.5em; + background-repeat: repeat-y; + background-position: left top, right top; + background-image: + url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1ch' height='1.5em'><text x='0' y='1.15em' font-family='monospace' font-size='16px' fill='%23000000'>|</text></svg>"), + url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1ch' height='1.5em'><text x='0' y='1.15em' font-family='monospace' font-size='16px' fill='%23000000'>|</text></svg>"); +} + +@media (prefers-color-scheme: dark) { + .ascii-body { + background-image: + url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1ch' height='1.5em'><text x='0' y='1.15em' font-family='monospace' font-size='16px' fill='%23ffffff'>|</text></svg>"), + url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='1ch' height='1.5em'><text x='0' y='1.15em' font-family='monospace' font-size='16px' fill='%23ffffff'>|</text></svg>"); + } +} + +.ascii-content-padding { + display: flex; + align-items: center; + width: 100%; + padding: 0 2ch; + box-sizing: border-box; +} + +.ascii-prompt { + color: #090; + font-weight: bold; + user-select: none; + margin-right: 1ch; +} + +.ascii-input, +.ascii-textarea { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background: transparent; + border: none; + outline: none; + font: inherit; + color: inherit; + padding: 0; + margin: 0; + width: 100%; + box-sizing: border-box; + border-radius: 0; + line-height: 1.5; +} + +.ascii-textarea { + display: block; + resize: none; + overflow-y: hidden; + min-height: 6em; + field-sizing: content; +} + +.ascii-input::placeholder, +.ascii-textarea::placeholder { + color: #666; + opacity: 0.7; +} + +@media (prefers-color-scheme: dark) { + .ascii-prompt { + color: #0f0; + } + .ascii-input::placeholder, + .ascii-textarea::placeholder { + color: #555; + } +} + +.ascii-actions { + display: flex; + gap: 2ch; + margin-top: 8px; +} + +.ascii-btn { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background: transparent; + border: none; + outline: none; + font: inherit; + padding: 0; + margin: 0; + cursor: pointer; + white-space: pre; + font-weight: bold; +} + +.ascii-btn-submit { + color: #090; +} + +.ascii-btn-reset { + color: #a00; +} + +.ascii-btn-submit:hover, +.ascii-btn-submit:focus { + background: #090; + color: #fff; +} + +.ascii-btn-reset:hover, +.ascii-btn-reset:focus { + background: #a00; + color: #fff; +} + +@media (prefers-color-scheme: dark) { + .ascii-btn-submit { + color: #0f0; + } + .ascii-btn-submit:hover, + .ascii-btn-submit:focus { + background: #0f0; + color: #000; + } + .ascii-btn-reset { + color: #f33; + } + .ascii-btn-reset:hover, + .ascii-btn-reset:focus { + background: #f33; + color: #000; + } +} + +.ascii-status { + font: inherit; + color: #06c; + white-space: pre-wrap; + padding: 4px 0; + user-select: none; +} + +@media (prefers-color-scheme: dark) { + .ascii-status { + color: #6cf; + } +} diff --git a/www/index.html b/www/index.html new file mode 100644 index 0000000..f02c538 --- /dev/null +++ b/www/index.html @@ -0,0 +1,153 @@ +<!doctype html> +<!-- +Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. +--> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + + <title>Doan Luu Duc Tai</title> + + <link rel="stylesheet" href="styles.css"> + </head> + + <body> + + <div id="page"> + + <div class="badge">[ JS-free ]</div> + + <div id="content"> + + <pre> +<a href="/" class="logo"> + ____ ___ _ _ _ +| _ \ / _ \ / \ | \ | | +| | | | | | |/ _ \ | \| | +| |_| | |_| / ___ \| |\ | +|____/ \___/_/ \_\_| \_| LUU DUC TAI +</a> + +<a href="/">Home</a> <a href="#projects">Projects</a> <a href="#services">Services</a> <a href="#contact">Contact</a> <a href="message.html">Message Me</a> + + ++------------------------------------------------------------------------------+ +| | +| Doan Luu Duc Tai | +| | +| Email: <a href="mailto:doan@luuduct.ai">doan@luuduct.ai</a> | +| <a href="https://smp11.simplex.im/a#ikrTZ8sfleSZEifKV2wI8foAVwkbKfOoKc6TO2P4ZT8">SimpleX Chat</a> | +| <a href="https://signal.me/#eu/Xr5_r_ei8UYUpd7Lus4536PnlKvW28LXBjg3Lb71BtFp4iDVXoRF4ZVPQYw_0Guk">Signal</a> | +| | +| GPG: <a href="https://openpgpkey.luuduct.ai/.well-known/openpgpkey/luuduct.ai/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp?l=doan">8990FFC0F9D95FAA4C04520BADF3DE23F687C623</a> | +| Cv25519 | +| | ++------------------------------------------------------------------------------+ + + + + +<span id="projects">Projects</span> +________________________________________________________________________________ + + +<a href="https://git.doan.luuduct.ai/csprdg/">csprdg</a> + Conjecturally Secure Pseudo-Random Document Generator + + +<a href="https://git.doan.luuduct.ai/csprsg/">csprsg</a> + Conjecturally Secure Pseudo-Random Spreadsheet Generator + + +<a href="https://git.doan.luuduct.ai/fileshare/">fileshare</a> + LAN File Server + + +<a href="https://git.doan.luuduct.ai/vfetch/">vfetch</a> + neofetch but the ascii part is a video + + + + +<span id="services">Services</span> +________________________________________________________________________________ + + +<a href="https://git.doan.luuduct.ai/">git.doan.luuduct.ai</a> +* A <a href="https://git.zx2c4.com/cgit">cgit</a> instance, <span class="good">functional without JS</span>. + + Personal Git repositories + + +<a href="https://search.doan.luuduct.ai/">search.doan.luuduct.ai</a> +* A <a href="https://github.com/searxng/searxng">SearXNG</a> instance, <span class="good">functional without JS</span>. + + Private search engine + + +<a href="https://meet.doan.luuduct.ai/">meet.doan.luuduct.ai</a> +* A <a href="https://github.com/miroslavpejic85/mirotalk">MiroTalk</a> instance, <span class="warn" title="Practice your due diligence: read the source code, audit dependencies, and check what JavaScript is executed.">JS-required, non-<a href="https://www.gnu.org/software/librejs/index.html">LibreJS</a>-compliant</span>, <a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPLv3</a>-licensed. + + Video conferencing + + + + +<span id="contact">Contact</span> +________________________________________________________________________________ + ___ ___ _ _ _ _ _ _ _ _ ___ _ _ ___ _____ _ ___ +| \ / _ \ /_\ | \| | | | | | | | | | | | \| | | |/ __| |_ _/_\ |_ _| +| |) | (_) / _ \| .` | | |_| |_| | |_| | | |) | |_| | (__ | |/ _ \ | | +|___/ \___/_/ \_\_|\_| |____\___/ \___/ |___/ \___/ \___| |_/_/ \_\___| + + + +Message: + + <a href="message.html">[ Send Encrypted Message ]</a> + + +Email: + + <a href="mailto:doan@luuduct.ai">doan@luuduct.ai</a> + + +GPG: + + <a href="https://openpgpkey.luuduct.ai/.well-known/openpgpkey/luuduct.ai/hu/t76q8xqkeassgy1kr38re1ppj6cpc1dp?l=doan">8990FFC0F9D95FAA4C04520BADF3DE23F687C623</a> + Cv25519 + + +<a href="https://simplex.chat">SimpleX Chat</a> + + <a href="https://smp11.simplex.im/a#ikrTZ8sfleSZEifKV2wI8foAVwkbKfOoKc6TO2P4ZT8">SimpleX Contact Link</a> + + +<a href="https://signal.org/">Signal</a> + + <a href="https://signal.me/#eu/Xr5_r_ei8UYUpd7Lus4536PnlKvW28LXBjg3Lb71BtFp4iDVXoRF4ZVPQYw_0Guk">@v3QKypba7PzWPAuv2Eu2wRFgUVDuYDhm.73</a> + + + + + </pre> + + </div> + </div> + + </body> +</html> diff --git a/www/message.html b/www/message.html new file mode 100644 index 0000000..a463a1c --- /dev/null +++ b/www/message.html @@ -0,0 +1,87 @@ +<!doctype html> +<!-- +Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. +--> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + + <title>Message Me - Doan Luu Duc Tai</title> + + <link rel="stylesheet" href="styles.css"> + <link rel="stylesheet" href="form.css"> + </head> + + <body> + + <div id="page"> + + <div class="badge">[ JS-free ]</div> + + <div id="content"> + + <pre> +<a href="/" class="logo"> + ____ ___ _ _ _ +| _ \ / _ \ / \ | \ | | +| | | | | | |/ _ \ | \| | +| |_| | |_| / ___ \| |\ | +|____/ \___/_/ \_\_| \_| LUU DUC TAI +</a> + </pre> + + <form id="message-form" action="/send-message" method="POST" class="ascii-form-container"> + + <div class="ascii-box"> + <div class="ascii-bar">+--[ Reply Contact (Optional) ]------------------------------------------------+</div> + <div class="ascii-body"> + <div class="ascii-content-padding"> + <span class="ascii-prompt">></span> + <input type="text" id="sender-input" name="sender" class="ascii-input" maxlength="120" autocomplete="off" spellcheck="false"> + </div> + </div> + <div class="ascii-bar">+------------------------------------------------------------------------------+</div> + </div> + + <div class="ascii-box"> + <div class="ascii-bar">+--[ Message Body ]------------------------------------------------------------+</div> + <div class="ascii-body"> + <div class="ascii-content-padding"> + <textarea id="message-input" name="message" class="ascii-textarea" rows="4" required></textarea> + </div> + </div> + <div class="ascii-bar">+------------------------------------------------------------------------------+</div> + </div> + + <div class="ascii-actions"> + <button type="submit" id="submit-btn" class="ascii-btn ascii-btn-submit">[ < SEND > ]</button> + <button type="reset" id="reset-btn" class="ascii-btn ascii-btn-reset">[ < CLEAR > ]</button> + </div> + + </form> + + <pre> +________________________________________________________________________________ + +<a href="/">Return to Home Page</a> + </pre> + + </div> + </div> + + </body> +</html> diff --git a/www/styles.css b/www/styles.css new file mode 100644 index 0000000..35b7695 --- /dev/null +++ b/www/styles.css @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +body { + overflow-y: scroll; + font: 16px monospace, monospace; + margin: 0; + padding: 0; +} + +pre { + margin: 0; + overflow-x: auto; +} + +a { + color: #06c; + text-decoration: none; +} + +.good { + color: #090; + font-weight: bold; +} + +.warn { + color: #c90; + font-weight: bold; +} + +.logo { + color: #a00; + text-decoration: none; +} + +.logo:hover { + text-decoration: none; +} + +.badge { + position: absolute; + top: 16px; + left: calc(50% + 280px); + color: #090; + font-weight: bold; + white-space: nowrap; +} + +#page { + display: table; + margin: 16px auto; + position: relative; +} + +#content { + max-width: 80ch; + width: 100%; +} + +.good a, .warn a { + color: inherit; + text-decoration: underline; +} + +.good a { + text-decoration-style: wavy; +} + +.warn a { + text-decoration-style: dotted; +} + +@media (prefers-color-scheme: dark) { + body { + background: #000; + color: #fff; + } + + a { + color: #6cf; + } + + .logo { + color: #f33; + } + + .badge { + color: #0f0; + } + + .good { + color: #0f0; + } + + .warn { + color: #ff0; + } +} + +@media (max-width: 999px) { + body { + font-size: 1.94vw; + } + + .badge { + left: auto; + right: 16px; + } +} |
