From 8b70d51c8735a5820de9869c1326b1936d65e40d Mon Sep 17 00:00:00 2001 From: orohi Date: Sun, 26 Jul 2026 00:02:18 +0300 Subject: [PATCH] Add Amnezia Web Panel source with PostgreSQL 17 storage. Co-authored-by: Cursor --- .env.example | 13 + .github/workflows/build.yml | 102 + .gitignore | 40 + Dockerfile | 16 + Dockerfile.warp | 38 + LICENSE | 674 +++++ app.py | 3968 ++++++++++++++++++++++++++++ db/__init__.py | 29 + db/connection.py | 82 + db/migrate_json.py | 58 + db/schema.sql | 75 + db/store.py | 413 +++ docker-compose.warp.yml | 28 + docker-compose.yml | 50 + docker-entrypoint-warp.sh | 22 + managers/__init__.py | 7 + managers/adguard_manager.py | 264 ++ managers/awg_manager.py | 1378 ++++++++++ managers/backup_manager.py | 170 ++ managers/dns_manager.py | 83 + managers/nginx_manager.py | 383 +++ managers/socks5_manager.py | 240 ++ managers/ssh_manager.py | 227 ++ managers/telemt_manager.py | 571 ++++ managers/wireguard_manager.py | 823 ++++++ managers/xray_manager.py | 800 ++++++ protocol_telemt/Dockerfile | 108 + protocol_telemt/config.toml | 62 + protocol_telemt/docker-compose.yml | 31 + requirements.txt | 41 + screen/panel1-2.png | Bin 0 -> 141967 bytes screen/panel1-3.png | Bin 0 -> 134360 bytes screen/panel1.png | Bin 0 -> 466574 bytes static/css/style.css | 1868 +++++++++++++ static/favicon.svg | 11 + static/js/qrcode.min.js | 1 + telegram_bot.py | 1137 ++++++++ templates/base.html | 269 ++ templates/index.html | 453 ++++ templates/login.html | 285 ++ templates/my_connections.html | 162 ++ templates/server.html | 2347 ++++++++++++++++ templates/settings.html | 1035 ++++++++ templates/user_share.html | 249 ++ templates/users.html | 1084 ++++++++ translations/en.json | 423 +++ translations/fa.json | 390 +++ translations/fr.json | 390 +++ translations/ru.json | 423 +++ translations/zh.json | 390 +++ 50 files changed, 21713 insertions(+) create mode 100644 .env.example create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Dockerfile.warp create mode 100644 LICENSE create mode 100644 app.py create mode 100644 db/__init__.py create mode 100644 db/connection.py create mode 100644 db/migrate_json.py create mode 100644 db/schema.sql create mode 100644 db/store.py create mode 100644 docker-compose.warp.yml create mode 100644 docker-compose.yml create mode 100644 docker-entrypoint-warp.sh create mode 100644 managers/__init__.py create mode 100644 managers/adguard_manager.py create mode 100644 managers/awg_manager.py create mode 100644 managers/backup_manager.py create mode 100644 managers/dns_manager.py create mode 100644 managers/nginx_manager.py create mode 100644 managers/socks5_manager.py create mode 100644 managers/ssh_manager.py create mode 100644 managers/telemt_manager.py create mode 100644 managers/wireguard_manager.py create mode 100644 managers/xray_manager.py create mode 100644 protocol_telemt/Dockerfile create mode 100644 protocol_telemt/config.toml create mode 100644 protocol_telemt/docker-compose.yml create mode 100644 requirements.txt create mode 100644 screen/panel1-2.png create mode 100644 screen/panel1-3.png create mode 100644 screen/panel1.png create mode 100644 static/css/style.css create mode 100644 static/favicon.svg create mode 100644 static/js/qrcode.min.js create mode 100644 telegram_bot.py create mode 100644 templates/base.html create mode 100644 templates/index.html create mode 100644 templates/login.html create mode 100644 templates/my_connections.html create mode 100644 templates/server.html create mode 100644 templates/settings.html create mode 100644 templates/user_share.html create mode 100644 templates/users.html create mode 100644 translations/en.json create mode 100644 translations/fa.json create mode 100644 translations/fr.json create mode 100644 translations/ru.json create mode 100644 translations/zh.json diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..2200963 --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +# Panel +APP_PORT=5000 +SECRET_KEY=change-me-to-a-long-random-string + +# PostgreSQL 17 +POSTGRES_USER=amnezia +POSTGRES_PASSWORD=amnezia +POSTGRES_DB=amnezia_panel +POSTGRES_PORT=5432 + +# Used by the panel process (local run or Docker) +# Docker Compose sets this automatically to point at the db service. +DATABASE_URL=postgresql://amnezia:amnezia@localhost:5432/amnezia_panel diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..40fd03e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,102 @@ +name: Build Binaries + +on: + push: + branches: [ "main" ] + tags: + - 'v*' + workflow_dispatch: + +permissions: + contents: write + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pyinstaller + pip install -r requirements.txt + + - name: Build Linux + if: runner.os == 'Linux' + run: | + pyinstaller --name Amnezia-Web-Panel-Linux \ + --add-data "static:static" \ + --add-data "templates:templates" \ + --add-data "translations:translations" \ + --hidden-import uvicorn \ + --hidden-import fastapi \ + --clean \ + -y \ + -F app.py + + - name: Build Windows + if: runner.os == 'Windows' + run: | + pyinstaller --name Amnezia-Web-Panel-Windows ` + --add-data "static;static" ` + --add-data "templates;templates" ` + --add-data "translations;translations" ` + --hidden-import uvicorn ` + --hidden-import fastapi ` + --clean ` + -y ` + -F app.py + + - name: Build macOS + if: runner.os == 'macOS' + run: | + pyinstaller --name Amnezia-Web-Panel-macOS \ + --add-data "static:static" \ + --add-data "templates:templates" \ + --add-data "translations:translations" \ + --hidden-import uvicorn \ + --hidden-import fastapi \ + --clean \ + -y \ + -F app.py + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: binaries-${{ runner.os }} + path: dist/* + + release: + needs: build + + if: startsWith(github.ref, 'refs/tags/') + + runs-on: ubuntu-latest + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Display structure + run: ls -R artifacts + + - name: Publish Release + uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + files: | + artifacts/**/* + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4564e0f --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# Virtual Environment +venv/ +env/ +.venv/ + +# PyInstaller folders +build/ +dist/ +*.spec + +# Python +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +env/ +pip-log.txt +pip-delete-this-directory.txt +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.log +.pytest_cache/ +.mypy_cache/ + +# User data +data.json +data.json.migrated.*.bak +tunnels_state.json +.env +.DS_Store + +# IDEs +.vscode/ +.idea/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c6990fd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +# syntax=docker/dockerfile:1 + +FROM python:3.14-slim + +WORKDIR /app + +# Копируем requirements.txt и устанавливаем зависимости +COPY requirements.txt requirements.txt +RUN pip3 install --no-cache-dir -r requirements.txt + +# Копируем остальные файлы проекта +COPY . . + + +# Команда запуска приложения +CMD ["python3", "app.py"] \ No newline at end of file diff --git a/Dockerfile.warp b/Dockerfile.warp new file mode 100644 index 0000000..ab0e2ae --- /dev/null +++ b/Dockerfile.warp @@ -0,0 +1,38 @@ +# syntax=docker/dockerfile:1 + +# Optional image variant with Cloudflare WARP installed inside the container. +# Use with: +# docker compose -f docker-compose.yml -f docker-compose.warp.yml up -d --build + +FROM python:3.14-slim-bookworm + +WORKDIR /app + +ARG CLOUDFLARE_WARP_REPO_CODENAME=bookworm + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + gnupg \ + iproute2 \ + iputils-ping \ + procps \ + && mkdir -p /usr/share/keyrings \ + && curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg \ + | gpg --dearmor -o /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg \ + && echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ ${CLOUDFLARE_WARP_REPO_CODENAME} main" \ + > /etc/apt/sources.list.d/cloudflare-client.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends cloudflare-warp \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt requirements.txt +RUN pip3 install --no-cache-dir -r requirements.txt + +COPY . . +COPY docker-entrypoint-warp.sh /usr/local/bin/docker-entrypoint-warp.sh +RUN chmod +x /usr/local/bin/docker-entrypoint-warp.sh + +ENTRYPOINT ["docker-entrypoint-warp.sh"] +CMD ["python3", "app.py"] 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/app.py b/app.py new file mode 100644 index 0000000..e3fdce9 --- /dev/null +++ b/app.py @@ -0,0 +1,3968 @@ +import os +import sys +import json +import logging + +from dotenv import load_dotenv +load_dotenv() +import base64 +import hashlib +import secrets +import uuid +import asyncio +import platform +import re +import shutil +import shlex +import tempfile +import subprocess +import tarfile +import threading +import time +import urllib.request +import zipfile +import signal +from datetime import datetime +import io +from fastapi.responses import JSONResponse, RedirectResponse, HTMLResponse, StreamingResponse, FileResponse +from starlette.background import BackgroundTask +from fastapi.staticfiles import StaticFiles +from fastapi.templating import Jinja2Templates +from fastapi import FastAPI, Request, Query, UploadFile, File +from starlette.middleware.sessions import SessionMiddleware +from pydantic import BaseModel +from typing import Optional, List, Dict +import uvicorn +import httpx + +try: + from multicolorcaptcha import CaptchaGenerator +except ImportError: + CaptchaGenerator = None + +from managers.ssh_manager import SSHManager +from managers.awg_manager import AWGManager +from managers.xray_manager import XrayManager +from managers.wireguard_manager import WireGuardManager +from managers.backup_manager import BackupManager +import telegram_bot as tg_bot + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Ordered list of OpenAPI tag groups — the order here drives the section order in /docs and /redoc. +OPENAPI_TAGS = [ + {"name": "System Templates", "description": "HTML pages served to browsers. These return Jinja-rendered templates rather than a JSON contract — they are not part of the public API and are listed here only for completeness."}, + {"name": "Authentication", "description": "Login, captcha, and session lifecycle."}, + {"name": "Servers", "description": "Server inventory, lifecycle and host-level operations (add, edit, delete, ping, reorder, reboot, clear, stats, status check)."}, + {"name": "Protocols", "description": "Install, uninstall, container start/stop and raw config editing for the protocols/services on a server (AWG, Xray, WireGuard, Telemt, AmneziaDNS, AdGuard Home, SOCKS5)."}, + {"name": "Connections", "description": "Per-protocol VPN client connections on a server (CRUD plus enable/disable and config retrieval)."}, + {"name": "Users", "description": "Panel user accounts and the connections assigned to them."}, + {"name": "Self-service", "description": "Endpoints called by a regular user for their own data (the /my surface)."}, + {"name": "Sharing", "description": "Public, token-protected configuration sharing for end users — no panel session required."}, + {"name": "Settings", "description": "Panel-wide settings, Telegram bot, Remnawave sync, JSON backup/restore."}, + {"name": "API Tokens", "description": "Bearer tokens for external integrations. Send the token in `Authorization: Bearer `; tokens have admin-equivalent rights and are tied to the admin user that created them."}, +] + +app = FastAPI( + title="Amnezia Web Panel", + openapi_tags=OPENAPI_TAGS, + # FastAPI's stock /redoc loads the JS bundle from `redoc@next` on jsdelivr — + # an unstable rolling tag that breaks unpredictably. Disable the default and + # serve our own /redoc just below, pinned to the stable v2 bundle. + redoc_url=None, +) + + +@app.get("/redoc", include_in_schema=False) +async def custom_redoc(): + """Self-curated ReDoc page. Differs from FastAPI's default in two ways: + pinned bundle (`redoc@2` instead of `@next`) and Google Fonts disabled + (the Montserrat/Roboto stylesheet is blocked on a lot of networks and made + the page hang for some users).""" + from fastapi.openapi.docs import get_redoc_html + return get_redoc_html( + openapi_url=app.openapi_url or "/openapi.json", + title=f"{app.title} — ReDoc", + redoc_js_url="https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js", + with_google_fonts=False, + ) +app.add_middleware(SessionMiddleware, secret_key=os.environ.get('SECRET_KEY', secrets.token_hex(32))) + +# Mount static files & templates +app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "static")), name="static") +templates = Jinja2Templates(directory=os.path.join(os.path.dirname(__file__), "templates")) + +if getattr(sys, 'frozen', False): + application_path = os.path.dirname(sys.executable) +else: + application_path = os.path.dirname(__file__) + +DATA_FILE = os.path.join(application_path, 'data.json') # legacy JSON; used only for one-shot import / export +CURRENT_VERSION = "v1.5.0" +BIN_DIR = os.environ.get('TUNNEL_BIN_DIR', os.path.join(application_path, 'bin')) +TUNNEL_STATE_FILE = os.environ.get('TUNNEL_STATE_FILE', os.path.join(application_path, 'tunnels_state.json')) + +# Panel state lives in PostgreSQL 17 (see db/). load_data/save_data keep the old dict API. +from db import ( # noqa: E402 + clear_tunnel_state, + ensure_db_ready, + export_data_dict, + load_data, + load_tunnel_state, + save_data, + save_tunnel_state, + update_tunnel_state, +) + + +class TunnelRuntime: + def __init__(self): + self.process = None + self.pid = None + self.public_url = '' + self.last_error = '' + self.started_at = None + self.output = [] + + +TUNNEL_RUNTIMES = { + 'cloudflare': TunnelRuntime(), + 'ngrok': TunnelRuntime(), +} +TUNNEL_LOCK = threading.Lock() +TUNNEL_URL_RE = re.compile(r'https://[^\s"\']+') +WARP_CLI_COMMAND = 'warp-cli.exe' if os.name == 'nt' else 'warp-cli' + + + +# ======================== Translations ======================== +TRANSLATIONS = {} + +def load_translations(): + global TRANSLATIONS + trans_dir = os.path.join(os.path.dirname(__file__), 'translations') + if os.path.exists(trans_dir): + for f in os.listdir(trans_dir): + if f.endswith('.json'): + lang = f.split('.')[0] + try: + with open(os.path.join(trans_dir, f), 'r', encoding='utf-8') as tf: + TRANSLATIONS[lang] = json.load(tf) + except Exception as e: + logger.error(f"Error loading translation {f}: {e}") + logger.info(f"Loaded translations: {list(TRANSLATIONS.keys())}") + +def _t(text_id, lang='en'): + lang_batch = TRANSLATIONS.get(lang, TRANSLATIONS.get('en', {})) + return lang_batch.get(text_id, text_id) + +load_translations() + + +# ======================== Helpers ======================== + +# Global lock for panel DB writes to prevent race conditions during async operations +DATA_LOCK = asyncio.Lock() + + +async def save_data_async(data): + """Saves panel state to PostgreSQL in a thread-safe way.""" + async with DATA_LOCK: + await asyncio.to_thread(save_data, data) + + +def get_ssh(server): + return SSHManager( + host=server['host'], + port=server.get('ssh_port', 22), + username=server['username'], + password=server.get('password'), + private_key=server.get('private_key'), + ) + + +def get_panel_local_url(request: Optional[Request] = None): + data = load_data() + ssl_conf = data.get('settings', {}).get('ssl', {}) + scheme = 'https' if ssl_conf.get('enabled') else 'http' + host = '127.0.0.1' + port = ssl_conf.get('panel_port', 5000) or 5000 + if request: + scheme = request.url.scheme or scheme + host = request.url.hostname or host + port = request.url.port or port + return f"{scheme}://{host}:{port}" + + +def get_panel_tunnel_target_url(): + data = load_data() + ssl_conf = data.get('settings', {}).get('ssl', {}) + scheme = 'https' if ssl_conf.get('enabled') else 'http' + port = ssl_conf.get('panel_port', 5000) or 5000 + return f"{scheme}://127.0.0.1:{port}" + + +def get_warp_cli_binary(): + found = shutil.which(WARP_CLI_COMMAND) + if found: + return found + if os.name == 'nt': + for base in (os.environ.get('ProgramFiles'), os.environ.get('ProgramFiles(x86)')): + if not base: + continue + candidate = os.path.join(base, 'Cloudflare', 'Cloudflare WARP', 'warp-cli.exe') + if os.path.exists(candidate): + return candidate + return None + + +def is_warp_cli_installed(): + return bool(get_warp_cli_binary()) + + +def _warp_install_hint(): + system = platform.system().lower() + if system == 'windows': + return 'Install Cloudflare WARP from https://1.1.1.1/ or winget install Cloudflare.Warp, then restart this panel.' + if system == 'darwin': + return 'Install Cloudflare WARP from https://1.1.1.1/ or brew install --cask cloudflare-warp, then restart this panel.' + return 'Install the official cloudflare-warp package for your Linux distribution, start warp-svc, then restart this panel.' + + +def run_warp_cli(*args, timeout: int = 12): + binary = get_warp_cli_binary() + if not binary: + raise RuntimeError(_warp_install_hint()) + creationflags = subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0 + command = [binary] + if '--accept-tos' not in args: + command.append('--accept-tos') + command.extend(args) + result = subprocess.run( + command, + capture_output=True, + text=True, + encoding='utf-8', + errors='replace', + timeout=timeout, + creationflags=creationflags, + ) + output = '\n'.join(part.strip() for part in (result.stdout, result.stderr) if part and part.strip()) + if result.returncode != 0: + raise RuntimeError(output or f'warp-cli exited with code {result.returncode}') + return output + + +def _parse_warp_status(output: str): + lowered = (output or '').lower() + if 'registration missing' in lowered or 'not registered' in lowered or 'not enrolled' in lowered: + return 'not_registered' + if 'disconnect' in lowered or 'disabled' in lowered: + return 'disconnected' + if 'connecting' in lowered: + return 'connecting' + if 'connected' in lowered: + return 'connected' + return 'unknown' + + +def get_warp_status(): + installed = is_warp_cli_installed() + status = { + 'installed': installed, + 'running': False, + 'connected': False, + 'status': 'not_installed' if not installed else 'unknown', + 'raw': '', + 'last_error': '' if installed else _warp_install_hint(), + 'install_hint': _warp_install_hint(), + } + if not installed: + return status + try: + output = run_warp_cli('status') + parsed = _parse_warp_status(output) + status.update({ + 'running': parsed in ('connected', 'connecting'), + 'connected': parsed == 'connected', + 'status': parsed, + 'raw': output, + 'last_error': '', + }) + except Exception as e: + status['last_error'] = str(e) + lowered = str(e).lower() + if 'registration missing' in lowered or 'not registered' in lowered or 'not enrolled' in lowered: + status['status'] = 'not_registered' + elif 'service' in lowered or 'daemon' in lowered or 'warp-svc' in lowered: + status['status'] = 'service_unavailable' + else: + status['status'] = 'error' + return status + + +def enable_warp(): + current = get_warp_status() + if not current.get('installed'): + raise RuntimeError(current.get('install_hint') or _warp_install_hint()) + try: + if current.get('status') == 'not_registered': + run_warp_cli('registration', 'new', timeout=30) + run_warp_cli('mode', 'warp', timeout=15) + run_warp_cli('connect', timeout=30) + except Exception as e: + message = str(e) + if 'registration' in message.lower() or 'not registered' in message.lower() or 'not enrolled' in message.lower(): + run_warp_cli('registration', 'new', timeout=30) + run_warp_cli('mode', 'warp', timeout=15) + run_warp_cli('connect', timeout=30) + else: + raise + time.sleep(1) + return get_warp_status() + + +def disable_warp(): + current = get_warp_status() + if not current.get('installed'): + raise RuntimeError(current.get('install_hint') or _warp_install_hint()) + run_warp_cli('disconnect', timeout=20) + time.sleep(0.5) + return get_warp_status() + + +def get_tunnel_command_name(provider: str): + if provider == 'cloudflare': + return 'cloudflared.exe' if os.name == 'nt' else 'cloudflared' + if provider == 'ngrok': + return 'ngrok.exe' if os.name == 'nt' else 'ngrok' + raise ValueError('Unsupported tunnel provider') + + +def get_tunnel_binary_path(provider: str): + return os.path.join(BIN_DIR, get_tunnel_command_name(provider)) + + +def find_tunnel_binary(provider: str): + bundled = get_tunnel_binary_path(provider) + if os.path.exists(bundled): + return bundled + return shutil.which(get_tunnel_command_name(provider)) + + +def is_tunnel_installed(provider: str): + return bool(find_tunnel_binary(provider)) + + +def pid_is_running(pid): + if not pid: + return False + try: + os.kill(int(pid), 0) + return True + except OSError: + return False + except Exception: + return False + + +def kill_pid(pid): + if not pid: + return + if os.name == 'nt': + subprocess.run(['taskkill', '/PID', str(pid), '/T', '/F'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=10) + deadline = time.monotonic() + 10 + while time.monotonic() < deadline: + if not pid_is_running(pid): + return + time.sleep(0.2) + else: + try: + os.kill(int(pid), signal.SIGTERM) + deadline = time.monotonic() + 10 + while time.monotonic() < deadline: + if not pid_is_running(pid): + return + time.sleep(0.2) + if pid_is_running(pid): + os.kill(int(pid), signal.SIGKILL) + except ProcessLookupError: + return + + +def wait_for_path_release(path, seconds: int = 5): + if os.name != 'nt': + return + deadline = time.monotonic() + seconds + while time.monotonic() < deadline: + try: + if not os.path.exists(path): + return + with open(path, 'ab'): + return + except PermissionError: + time.sleep(0.25) + + +def find_running_tunnel_pids_in_proc(provider: str, binary_path: str = ''): + proc_dir = '/proc' + if os.name == 'nt' or not os.path.isdir(proc_dir): + return [] + command_name = get_tunnel_command_name(provider).lower() + command_base = command_name.replace('.exe', '') + markers = ['tunnel', '--url'] if provider == 'cloudflare' else ['http'] + expected_binary = os.path.abspath(binary_path).lower() if binary_path else '' + pids = [] + try: + for entry in os.listdir(proc_dir): + if not entry.isdigit(): + continue + pid = int(entry) + if pid == os.getpid(): + continue + cmdline_path = os.path.join(proc_dir, entry, 'cmdline') + try: + with open(cmdline_path, 'rb') as f: + cmdline = f.read().replace(b'\x00', b' ').decode('utf-8', errors='replace').strip() + except Exception: + continue + lowered = cmdline.lower() + exe_path = '' + try: + exe_path = os.path.abspath(os.readlink(os.path.join(proc_dir, entry, 'exe'))).lower() + except Exception: + pass + path_matches = bool(expected_binary and exe_path == expected_binary) + command_matches = (command_name in lowered or command_base in lowered) and all(marker in lowered for marker in markers) + if path_matches or command_matches: + if pid_is_running(pid): + pids.append(pid) + except Exception as e: + logger.debug(f"Failed to scan /proc for running {provider} tunnel process: {e}") + return pids + + +def find_running_tunnel_pids(provider: str, binary_path: str = ''): + command_name = get_tunnel_command_name(provider).lower() + process_name = command_name[:-4] if command_name.endswith('.exe') else command_name + markers = ['tunnel', '--url'] if provider == 'cloudflare' else ['http'] + expected_binary = os.path.normcase(os.path.abspath(binary_path or get_tunnel_binary_path(provider))) + pids = [] + try: + if os.name == 'nt': + ps_script = f"Get-CimInstance Win32_Process -Filter \"name='{command_name}'\" | Select-Object ProcessId,CommandLine,ExecutablePath | ConvertTo-Json -Compress" + result = subprocess.run(['powershell', '-NoProfile', '-Command', ps_script], capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5) + rows = [] + if result.returncode == 0 and result.stdout.strip(): + payload = json.loads(result.stdout) + if payload: + rows = payload if isinstance(payload, list) else [payload] + if not rows: + ps_script = f"Get-Process -Name '{process_name}' -ErrorAction SilentlyContinue | Select-Object Id,Path | ConvertTo-Json -Compress" + result = subprocess.run(['powershell', '-NoProfile', '-Command', ps_script], capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5) + if result.returncode == 0 and result.stdout.strip(): + payload = json.loads(result.stdout) + proc_rows = payload if isinstance(payload, list) else ([payload] if payload else []) + rows = [{'ProcessId': r.get('Id'), 'ExecutablePath': r.get('Path'), 'CommandLine': ''} for r in proc_rows] + for row in rows: + if not row: + continue + pid = int(row.get('ProcessId') or 0) + command_line = str(row.get('CommandLine') or '').lower() + executable = os.path.normcase(os.path.abspath(str(row.get('ExecutablePath') or ''))) if row.get('ExecutablePath') else '' + path_matches = bool(expected_binary and executable == expected_binary) + command_matches = command_name in command_line and all(marker in command_line for marker in markers) + if pid and pid != os.getpid() and (path_matches or command_matches) and pid_is_running(pid): + pids.append(pid) + if not pids and os.path.exists(expected_binary): + result = subprocess.run(['tasklist', '/FI', f'IMAGENAME eq {command_name}', '/FO', 'CSV', '/NH'], capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5) + for line in result.stdout.splitlines(): + match = re.match(r'"[^"]+","(\d+)"', line.strip()) + if match: + pid = int(match.group(1)) + if pid != os.getpid() and pid_is_running(pid): + pids.append(pid) + return list(dict.fromkeys(pids)) + else: + result = subprocess.run( + ['ps', '-eo', 'pid=,args='], + capture_output=True, + text=True, + encoding='utf-8', + errors='replace', + timeout=5, + ) + lines = result.stdout.splitlines() + + for line in lines: + text = line.strip() + lowered = text.lower() + if command_name not in lowered or not all(marker in lowered for marker in markers): + continue + pid_match = re.match(r'\s*(\d+)\s+', text) + if pid_match: + pid = int(pid_match.group(1)) + if pid != os.getpid() and pid_is_running(pid): + pids.append(pid) + except Exception as e: + logger.debug(f"Failed to scan running {provider} tunnel process: {e}") + pids.extend(find_running_tunnel_pids_in_proc(provider, expected_binary)) + return list(dict.fromkeys(pids)) + + +def find_running_tunnel_pid(provider: str): + pids = find_running_tunnel_pids(provider) + return pids[0] if pids else None + + +def kill_tunnel_processes(provider: str, binary_path: str = '', include_all_by_name: bool = False): + pids = find_running_tunnel_pids(provider, binary_path) + for pid in pids: + kill_pid(pid) + if os.name == 'nt' and include_all_by_name: + subprocess.run(['taskkill', '/IM', get_tunnel_command_name(provider), '/T', '/F'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=10) + return pids + + +def get_tunnel_download(provider: str): + system = platform.system().lower() + machine = platform.machine().lower() + + if provider == 'cloudflare': + if system == 'windows': + arch = 'amd64' if machine in ('amd64', 'x86_64') else '386' + return f'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-windows-{arch}.exe', 'exe' + if system == 'darwin': + arch = 'arm64' if 'arm' in machine else 'amd64' + return f'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-darwin-{arch}.tgz', 'tgz' + arch = 'arm64' if 'aarch64' in machine or 'arm64' in machine else 'amd64' + return f'https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-{arch}', 'bin' + + if provider == 'ngrok': + if system == 'windows': + os_part = 'windows' + ext = 'zip' + elif system == 'darwin': + os_part = 'darwin' + ext = 'zip' + else: + os_part = 'linux' + ext = 'tgz' + arch = 'arm64' if 'aarch64' in machine or 'arm64' in machine else 'amd64' + return f'https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-{os_part}-{arch}.{ext}', ext + + raise ValueError('Unsupported tunnel provider') + + +def install_tunnel_binary(provider: str): + if is_tunnel_installed(provider): + return find_tunnel_binary(provider) + + os.makedirs(BIN_DIR, exist_ok=True) + url, archive_type = get_tunnel_download(provider) + target = get_tunnel_binary_path(provider) + tmp_path = os.path.join(BIN_DIR, f'{provider}.download') + logger.info(f"Downloading {provider} tunnel binary from {url}") + urllib.request.urlretrieve(url, tmp_path) + + if archive_type in ('bin', 'exe'): + shutil.move(tmp_path, target) + elif archive_type == 'zip': + with zipfile.ZipFile(tmp_path) as zf: + member = next((m for m in zf.namelist() if os.path.basename(m).lower() == get_tunnel_command_name(provider).lower()), None) + if not member: + raise RuntimeError(f'{provider} binary not found in downloaded archive') + with zf.open(member) as src, open(target, 'wb') as dst: + shutil.copyfileobj(src, dst) + os.remove(tmp_path) + elif archive_type == 'tgz': + with tarfile.open(tmp_path, 'r:gz') as tf: + member = next((m for m in tf.getmembers() if os.path.basename(m.name).lower() == get_tunnel_command_name(provider).lower()), None) + if not member: + raise RuntimeError(f'{provider} binary not found in downloaded archive') + extracted = tf.extractfile(member) + if not extracted: + raise RuntimeError(f'Cannot extract {provider} binary') + with extracted as src, open(target, 'wb') as dst: + shutil.copyfileobj(src, dst) + os.remove(tmp_path) + else: + raise RuntimeError(f'Unsupported download format: {archive_type}') + + if os.name != 'nt': + os.chmod(target, 0o755) + return target + + +def get_tunnel_public_urls(provider: str, runtime: TunnelRuntime): + urls = [] + if runtime.public_url: + urls.append(runtime.public_url) + state_url = load_tunnel_state().get(provider, {}).get('public_url') + if state_url: + urls.append(state_url) + if provider == 'ngrok' and runtime.process and runtime.process.poll() is None: + try: + with urllib.request.urlopen('http://127.0.0.1:4040/api/tunnels', timeout=1) as resp: + payload = json.loads(resp.read().decode('utf-8')) + for item in payload.get('tunnels', []): + public_url = item.get('public_url') + if public_url and public_url.startswith('https://'): + urls.append(public_url) + except Exception: + pass + return list(dict.fromkeys(urls)) + + +def watch_tunnel_output(provider: str): + runtime = TUNNEL_RUNTIMES[provider] + process = runtime.process + if not process or not process.stdout: + return + try: + for line in iter(process.stdout.readline, ''): + if not line: + break + text = line.strip() + with TUNNEL_LOCK: + runtime.output.append(text) + runtime.output = runtime.output[-60:] + match = TUNNEL_URL_RE.search(text) + if match: + runtime.public_url = match.group(0).rstrip('.,') + update_tunnel_state(provider, public_url=runtime.public_url) + except Exception as e: + with TUNNEL_LOCK: + runtime.last_error = str(e) + + +def build_tunnel_command(provider: str, binary: str, local_url: str, authtoken: str = ''): + if provider == 'cloudflare': + return [binary, 'tunnel', '--url', local_url, '--no-autoupdate'] + if provider == 'ngrok': + cmd = [binary, 'http', local_url, '--log=stdout'] + return cmd + raise ValueError('Unsupported tunnel provider') + + +def start_tunnel(provider: str, local_url: str, authtoken: str = ''): + binary = find_tunnel_binary(provider) + if not binary: + raise RuntimeError(f'{provider} is not installed') + + runtime = TUNNEL_RUNTIMES[provider] + with TUNNEL_LOCK: + if runtime.process and runtime.process.poll() is None: + return runtime + runtime.public_url = '' + runtime.last_error = '' + runtime.output = [] + runtime.started_at = datetime.now().isoformat() + + creationflags = subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0 + env = os.environ.copy() + if provider == 'ngrok' and authtoken: + env['NGROK_AUTHTOKEN'] = authtoken + + runtime.process = subprocess.Popen( + build_tunnel_command(provider, binary, local_url, authtoken), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + encoding='utf-8', + errors='replace', + cwd=application_path, + env=env, + creationflags=creationflags, + ) + runtime.pid = runtime.process.pid + update_tunnel_state( + provider, + pid=runtime.pid, + public_url='', + started_at=runtime.started_at, + binary=os.path.abspath(binary), + ) + + threading.Thread(target=watch_tunnel_output, args=(provider,), daemon=True).start() + return runtime + + +def stop_tunnel(provider: str): + runtime = TUNNEL_RUNTIMES[provider] + process = runtime.process + state = load_tunnel_state().get(provider, {}) + pids_to_stop = [] + if process and process.poll() is None: + pids_to_stop.append(process.pid) + try: + process.terminate() + try: + process.wait(timeout=10) + except subprocess.TimeoutExpired: + process.kill() + process.wait(timeout=5) + except Exception as e: + with TUNNEL_LOCK: + runtime.last_error = str(e) + raise + if state.get('pid') and pid_is_running(state.get('pid')): + pids_to_stop.append(state.get('pid')) + pids_to_stop.extend(find_running_tunnel_pids(provider, state.get('binary') or get_tunnel_binary_path(provider))) + for pid in dict.fromkeys(pids_to_stop): + if pid_is_running(pid): + kill_pid(pid) + + with TUNNEL_LOCK: + runtime.process = None + runtime.pid = None + runtime.public_url = '' + runtime.started_at = None + runtime.last_error = '' + clear_tunnel_state(provider) + return runtime + + +def delete_tunnel_binary(provider: str): + stop_tunnel(provider) + bundled = get_tunnel_binary_path(provider) + if os.path.exists(bundled): + wait_for_path_release(bundled, seconds=8) + try: + os.remove(bundled) + except PermissionError: + killed = kill_tunnel_processes(provider, bundled, include_all_by_name=True) + if killed: + wait_for_path_release(bundled, seconds=8) + try: + os.remove(bundled) + except PermissionError: + raise RuntimeError('Cannot delete tunnel binary because Windows still keeps it locked. All detected cloudflared/ngrok processes were stopped; close any antivirus scan, terminal, or external process using the file and try again.') + elif shutil.which(get_tunnel_command_name(provider)): + raise RuntimeError('This tunnel binary is installed system-wide. Remove it from PATH manually or use the panel-managed installation.') + + tmp_path = os.path.join(BIN_DIR, f'{provider}.download') + if os.path.exists(tmp_path): + os.remove(tmp_path) + + runtime = TUNNEL_RUNTIMES[provider] + with TUNNEL_LOCK: + runtime.output = [] + clear_tunnel_state(provider) + return runtime + + +def get_tunnel_status(provider: str): + runtime = TUNNEL_RUNTIMES[provider] + state = load_tunnel_state().get(provider, {}) + running = bool(runtime.process and runtime.process.poll() is None) + if not running and state.get('pid'): + running = pid_is_running(state.get('pid')) + if running: + runtime.pid = state.get('pid') + runtime.started_at = runtime.started_at or state.get('started_at') + runtime.public_url = runtime.public_url or state.get('public_url', '') + else: + clear_tunnel_state(provider) + state = {} + if not running and is_tunnel_installed(provider): + found_pid = find_running_tunnel_pid(provider) + if found_pid: + running = True + runtime.pid = found_pid + runtime.started_at = runtime.started_at or datetime.now().isoformat() + update_tunnel_state( + provider, + pid=found_pid, + public_url=runtime.public_url, + started_at=runtime.started_at, + binary=os.path.abspath(find_tunnel_binary(provider) or ''), + ) + state = load_tunnel_state().get(provider, {}) + if runtime.process and not running and not runtime.last_error and runtime.output: + runtime.last_error = runtime.output[-1] + urls = get_tunnel_public_urls(provider, runtime) + return { + 'installed': is_tunnel_installed(provider), + 'running': running, + 'public_url': urls[0] if urls else '', + 'public_urls': urls, + 'last_error': runtime.last_error, + 'started_at': runtime.started_at or state.get('started_at'), + } + + +async def wait_for_tunnel_url(provider: str, seconds: int = 20): + deadline = time.monotonic() + seconds + while time.monotonic() < deadline: + status = get_tunnel_status(provider) + if status.get('public_url') or not status.get('running'): + return status + await asyncio.sleep(0.5) + return get_tunnel_status(provider) + + +BASE_PROTOCOLS = ['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'dns', 'wireguard', 'socks5', 'adguard', 'nginx'] +MULTI_INSTANCE_PROTOCOLS = {'awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'socks5'} + + +def protocol_base(protocol: str) -> str: + return str(protocol or 'awg').split('__', 1)[0] + + +def protocol_instance(protocol: str) -> int: + parts = str(protocol or '').split('__', 1) + if len(parts) == 2: + try: + return max(1, int(parts[1])) + except ValueError: + return 1 + return 1 + + +def protocol_key(base: str, instance: int = 1) -> str: + base = protocol_base(base) + return base if int(instance or 1) <= 1 else f'{base}__{int(instance)}' + + +def next_protocol_key(protocols: dict, base: str) -> str: + base = protocol_base(base) + used = {protocol_instance(k) for k in (protocols or {}).keys() if protocol_base(k) == base} + idx = 1 + while idx in used: + idx += 1 + return protocol_key(base, idx) + + +def protocol_display_name(protocol: str) -> str: + base = protocol_base(protocol) + idx = protocol_instance(protocol) + names = { + 'awg': 'AmneziaWG', + 'awg2': 'AmneziaWG 2.0', + 'awg_legacy': 'AmneziaWG Legacy', + 'xray': 'Xray', + 'telemt': 'Telemt', + 'dns': 'AmneziaDNS', + 'wireguard': 'WireGuard', + 'socks5': 'SOCKS5', + 'adguard': 'AdGuard Home', + 'nginx': 'NGINX', + } + name = names.get(base, base) + return name if idx <= 1 else f'{name} #{idx}' + + +def protocol_container_name(protocol: str) -> Optional[str]: + base = protocol_base(protocol) + idx = protocol_instance(protocol) + base_names = { + 'awg': 'amnezia-awg', + 'awg2': 'amnezia-awg2', + 'awg_legacy': 'amnezia-awg-legacy', + 'xray': 'amnezia-xray', + 'telemt': 'telemt', + 'dns': 'amnezia-dns', + 'wireguard': 'amnezia-wireguard', + 'socks5': 'amnezia-socks5proxy', + 'adguard': 'amnezia-adguard', + 'nginx': 'amnezia-nginx', + } + name = base_names.get(base) + if not name: + return None + return name if idx <= 1 else f'{name}-{idx}' + + +def is_valid_protocol(protocol: str) -> bool: + return protocol_base(protocol) in BASE_PROTOCOLS + + +def get_protocol_manager(ssh, protocol: str): + base = protocol_base(protocol) + if base == 'xray': + from managers.xray_manager import XrayManager + return XrayManager(ssh, protocol) + elif base == 'telemt': + from managers.telemt_manager import TelemtManager + return TelemtManager(ssh, protocol) + elif base == 'dns': + from managers.dns_manager import DNSManager + return DNSManager(ssh) + elif base == 'wireguard': + from managers.wireguard_manager import WireGuardManager + return WireGuardManager(ssh) + elif base == 'socks5': + from managers.socks5_manager import Socks5Manager + return Socks5Manager(ssh, protocol) + elif base == 'adguard': + from managers.adguard_manager import AdguardManager + return AdguardManager(ssh) + elif base == 'nginx': + from managers.nginx_manager import NginxManager + return NginxManager(ssh, protocol) + from managers.awg_manager import AWGManager + return AWGManager(ssh) + + + +def ensure_docker_installed(ssh): + """Ensure Docker is installed and running before installing any protocol/service.""" + out, _, code = ssh.run_command("docker --version 2>/dev/null") + if code == 0 and out.strip(): + status, _, _ = ssh.run_command("systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null") + if 'active' in status or 'running' in status.lower(): + return 'Docker already installed' + ssh.run_sudo_command("systemctl enable --now docker 2>/dev/null || service docker start 2>/dev/null || true", timeout=60) + status, _, _ = ssh.run_command("systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null") + if 'active' in status or 'running' in status.lower(): + return 'Docker service started' + + script = r""" +set -e +if command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -y + apt-get install -y docker.io +elif command -v dnf >/dev/null 2>&1; then + dnf install -y docker +elif command -v yum >/dev/null 2>&1; then + yum install -y docker +elif command -v zypper >/dev/null 2>&1; then + zypper --non-interactive refresh + zypper --non-interactive install docker +elif command -v pacman >/dev/null 2>&1; then + pacman -Sy --noconfirm --noprogressbar docker +else + echo "Packet manager not found" >&2 + exit 1 +fi +(systemctl enable --now docker || service docker start || true) +sleep 3 +docker --version +""" + out, err, code = ssh.run_sudo_script(script, timeout=300) + if code != 0: + raise RuntimeError(f"Failed to install Docker: {err or out}") + status, _, _ = ssh.run_command("systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null") + if 'active' not in status and 'running' not in status.lower(): + raise RuntimeError("Docker installed but service is not running") + return 'Docker installed successfully' + + +def _manager_call(manager, method, protocol, *args, **kwargs): + """Unified call: WireGuard manager methods don't take protocol_type argument.""" + fn = getattr(manager, method) + if isinstance(manager, WireGuardManager): + return fn(*args, **kwargs) + return fn(protocol, *args, **kwargs) + + +def generate_vpn_link(config_text): + b64 = base64.b64encode(config_text.strip().encode('utf-8')).decode('utf-8') + return f"vpn://{b64}" + + +# ===================== API tokens ===================== + +API_TOKEN_PREFIX = 'awp_' # "Amnezia Web Panel" — makes tokens visually distinct in logs / configs +API_TOKEN_TOUCH_INTERVAL = 300 # don't re-write data.json more than once per 5 min per token + + +def _hash_api_token(raw: str) -> str: + """One-way hash of a raw token. We never store the original token — only the + SHA-256 digest, plus a short prefix for the UI to identify rotations.""" + return hashlib.sha256(raw.encode('utf-8')).hexdigest() + + +def _generate_api_token() -> str: + """Generate a fresh bearer token. ~256 bits of entropy with a recognizable + 'awp_' prefix so leaked tokens are obvious in source control / pastes.""" + return f"{API_TOKEN_PREFIX}{secrets.token_urlsafe(32)}" + + +def _resolve_api_token(data: dict, raw_token: str): + """Match a raw bearer token against stored hashes. Returns the user record + that owns the token, or None if the token is unknown / its owner is gone / + its owner is no longer admin-or-support.""" + if not raw_token: + return None + token_hash = _hash_api_token(raw_token) + entry = next( + (t for t in data.get('api_tokens', []) if t.get('token_hash') == token_hash), + None, + ) + if not entry: + return None + user = next((u for u in data.get('users', []) if u['id'] == entry.get('user_id')), None) + if not user: + return None + # Disabled or downgraded admins should not have a working token any more. + if not user.get('enabled', True): + return None + if user.get('role') not in ('admin', 'support'): + return None + return (entry, user) + + +def _touch_api_token(token_entry: dict) -> bool: + """Update last_used_at on a token entry, but only if enough time has passed + since the previous touch — avoids hot-write loops under load. Returns True + if the entry was updated and the caller should persist data.""" + now = datetime.now() + last = token_entry.get('last_used_at') + if last: + try: + prev = datetime.fromisoformat(last) + if (now - prev).total_seconds() < API_TOKEN_TOUCH_INTERVAL: + return False + except Exception: + pass + token_entry['last_used_at'] = now.isoformat() + return True + + +def hash_password(password: str) -> str: + salt = secrets.token_hex(16) + h = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000) + return f"{salt}${h.hex()}" + + +def verify_password(password: str, password_hash: str) -> bool: + try: + salt, h = password_hash.split('$', 1) + new_h = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000) + return new_h.hex() == h + except Exception: + return False + + +async def perform_delete_user(data: dict, user_id: str): + user = next((u for u in data['users'] if u['id'] == user_id), None) + if not user: + return False + # Remove user's connections from servers + user_conns = [c for c in data.get('user_connections', []) if c['user_id'] == user_id] + for uc in user_conns: + try: + sid = uc['server_id'] + if sid < len(data['servers']): + server = data['servers'][sid] + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, uc['protocol']) + _manager_call(manager, 'remove_client', uc['protocol'], uc['client_id']) + ssh.disconnect() + except Exception as e: + logger.warning(f"Failed to remove connection {uc['client_id']} during user delete: {e}") + data['user_connections'] = [c for c in data.get('user_connections', []) if c['user_id'] != user_id] + data['users'] = [u for u in data['users'] if u['id'] != user_id] + return True + + +async def perform_toggle_user(data: dict, user_id: str, enable: bool) -> bool: + """Enable or disable a user and propagate the change to all their VPN connections.""" + user = next((u for u in data['users'] if u['id'] == user_id), None) + if not user: + return False + + user['enabled'] = enable + + user_conns = [c for c in data.get('user_connections', []) if c['user_id'] == user_id] + for uc in user_conns: + try: + sid = uc['server_id'] + if sid >= len(data['servers']): + continue + server = data['servers'][sid] + ssh = get_ssh(server) + await asyncio.to_thread(ssh.connect) + manager = get_protocol_manager(ssh, uc['protocol']) + await asyncio.to_thread( + _manager_call, manager, 'toggle_client', uc['protocol'], uc['client_id'], enable + ) + await asyncio.to_thread(ssh.disconnect) + except Exception as e: + logger.warning(f"Failed to toggle connection {uc['client_id']} during user toggle: {e}") + + return True + + +async def perform_mass_operations(delete_uids: List[str] = None, toggle_uids: List[tuple] = None, create_conns: List[dict] = None): + """ + Executes multiple SSH operations efficiently. + Reloads data inside to ensure we don't overwrite other changes. + """ + data = load_data() + server_ops = {} + + def get_ops(sid): + if sid not in server_ops: + server_ops[sid] = {'delete': [], 'toggle': [], 'create': []} + return server_ops[sid] + + if delete_uids: + for uid in delete_uids: + conns = [c for c in data.get('user_connections', []) if c['user_id'] == uid] + for c in conns: get_ops(c['server_id'])['delete'].append(c) + + if toggle_uids: + for uid, enabled in toggle_uids: + conns = [c for c in data.get('user_connections', []) if c['user_id'] == uid] + for c in conns: get_ops(c['server_id'])['toggle'].append((c, enabled)) + + if create_conns: + for req in create_conns: get_ops(req['server_id'])['create'].append(req) + + async def run_server_ops(srv_id, ops): + # We re-load data inside to be absolutely sure about current state + # but for performance we'll use the passed srv_id + current_data = load_data() + if srv_id >= len(current_data['servers']): return + srv = current_data['servers'][srv_id] + + try: + ssh = get_ssh(srv) + await asyncio.to_thread(ssh.connect) + + # 1. Deletes + for c in ops['delete']: + manager = get_protocol_manager(ssh, c['protocol']) + await asyncio.to_thread(_manager_call, manager, 'remove_client', c['protocol'], c['client_id']) + # Incremental delete from data + async with DATA_LOCK: + current_data = load_data() + current_data['user_connections'] = [conn for conn in current_data['user_connections'] if conn['id'] != c['id']] + save_data(current_data) + + # 2. Toggles + for c, enabled in ops['toggle']: + manager = get_protocol_manager(ssh, c['protocol']) + await asyncio.to_thread(_manager_call, manager, 'toggle_client', c['protocol'], c['client_id'], enabled) + # Incremental toggle in data + async with DATA_LOCK: + current_data = load_data() + # We also need to update user status if it was a user toggle + # Wait, mass ops caller usually handles user enabled status. + # Here we just toggle the actual wireguard peer. + save_data(current_data) + + # 3. Creates + for c_req in ops['create']: + proto_info = srv.get('protocols', {}).get(c_req['protocol'], {}) + port = proto_info.get('port', '55424') + manager = get_protocol_manager(ssh, c_req['protocol']) + + if c_req['protocol'] == 'wireguard': + res = await asyncio.to_thread(manager.add_client, c_req['name'], srv['host']) + else: + res = await asyncio.to_thread(_manager_call, manager, 'add_client', c_req['protocol'], c_req['name'], srv['host'], port) + + if res.get('client_id'): + new_conn = { + 'id': str(uuid.uuid4()), + 'user_id': c_req['user_id'], + 'server_id': srv_id, + 'protocol': c_req['protocol'], + 'client_id': res['client_id'], + 'name': c_req['name'], + 'created_at': datetime.now().isoformat(), + } + async with DATA_LOCK: + current_data = load_data() + current_data['user_connections'].append(new_conn) + save_data(current_data) + + await asyncio.to_thread(ssh.disconnect) + except Exception as e: + logger.error(f"Mass ops failed for server {srv_id}: {e}") + + # Run all servers in parallel + tasks = [run_server_ops(sid, ops) for sid, ops in server_ops.items()] + if tasks: + await asyncio.gather(*tasks) + + # 4. Final user-level cleanup (delete/toggle users metadata) + async with DATA_LOCK: + current_data = load_data() + if delete_uids: + current_data['users'] = [u for u in current_data['users'] if u['id'] not in delete_uids] + current_data['user_connections'] = [c for c in current_data.get('user_connections', []) if c['user_id'] not in delete_uids] + if toggle_uids: + for uid, enabled in toggle_uids: + user = next((u for u in current_data['users'] if u['id'] == uid), None) + if user: user['enabled'] = enabled + save_data(current_data) + + return True + + +async def sync_users_with_remnawave(data: dict): + settings = data.get('settings', {}).get('sync', {}) + if not settings.get('remnawave_sync_users'): + return 0, "Synchronization is disabled in settings" + + url = settings.get('remnawave_url') + api_key = settings.get('remnawave_api_key') + if not url or not api_key: + return 0, "Remnawave URL or API Key not configured" + + api_url = url.rstrip('/') + '/api/users' + headers = {"Authorization": f"Bearer {api_key}"} + + try: + rw_users = [] + async with httpx.AsyncClient(timeout=30.0) as client: + page_size = 50 # Use a smaller page size that is more likely to be accepted + current_start = 0 + while True: + resp = await client.get(f"{api_url}?size={page_size}&start={current_start}", headers=headers) + if resp.status_code != 200: + return 0, f"Remnawave API error: {resp.status_code} {resp.text}" + + page_data = resp.json() + response_obj = page_data.get('response', {}) + page_users = response_obj.get('users', []) + total_count = response_obj.get('total', 0) + + if not page_users: + break + + rw_users.extend(page_users) + logger.info(f"Fetched {len(rw_users)} / {total_count} users from Remnawave...") + + if len(rw_users) >= total_count or len(page_users) == 0: + break + + current_start += len(page_users) + + rw_uuids = {u['uuid'] for u in rw_users} + + # 1. Handle deletion (users that have remnawave_uuid but are no longer in Remnawave) + to_delete_ids = [] + for u in data['users']: + if u.get('remnawave_uuid') and u['remnawave_uuid'] not in rw_uuids: + to_delete_ids.append(u['id']) + + if to_delete_ids: + logger.info(f"Removing {len(to_delete_ids)} users deleted in Remnawave") + await perform_mass_operations(delete_uids=to_delete_ids) + + # 2. Sync / Create users + synced_count = 0 + to_toggle = [] # list of (user_id, enabled) + to_create_conns = [] # list of dicts + + for rw_u in rw_users: + # We reload data in each loop step to handle concurrency + data = load_data() + local_u = next((u for u in data['users'] if u.get('remnawave_uuid') == rw_u['uuid']), None) + if not local_u: + local_u = next((u for u in data['users'] if u['username'] == rw_u['username']), None) + + is_active = (rw_u.get('status') == 'ACTIVE') + + if local_u: + local_u['username'] = rw_u['username'] + local_u['telegramId'] = rw_u.get('telegramId') + local_u['email'] = rw_u.get('email') + local_u['description'] = rw_u.get('description') + local_u['remnawave_uuid'] = rw_u['uuid'] + + if local_u.get('enabled', True) != is_active: + to_toggle.append((local_u['id'], is_active)) + + # Save metadata immediately + async with DATA_LOCK: + current = load_data() + # Update index + idx = next((i for i, u in enumerate(current['users']) if u['id'] == local_u['id']), -1) + if idx != -1: + current['users'][idx] = local_u + save_data(current) + + synced_count += 1 + else: + new_id = str(uuid.uuid4()) + new_user = { + 'id': new_id, + 'username': rw_u['username'], + 'password_hash': '', + 'role': 'user', + 'telegramId': rw_u.get('telegramId'), + 'email': rw_u.get('email'), + 'description': rw_u.get('description'), + 'enabled': is_active, + 'created_at': datetime.now().isoformat(), + 'remnawave_uuid': rw_u['uuid'], + 'share_enabled': False, + 'share_token': secrets.token_urlsafe(16), + 'share_password_hash': None, + } + async with DATA_LOCK: + current = load_data() + current['users'].append(new_user) + save_data(current) + + if settings.get('remnawave_create_conns'): + sid = settings.get('remnawave_server_id') + if sid is not None: + to_create_conns.append({ + 'user_id': new_id, + 'server_id': sid, + 'protocol': settings.get('remnawave_protocol', 'awg'), + 'name': f"{rw_u['username']}_vpn" + }) + synced_count += 1 + + # Execute all collected mass operations + if to_toggle or to_create_conns: + logger.info(f"Executing mass ops for Remnawave sync: toggle={len(to_toggle)}, create={len(to_create_conns)}") + await perform_mass_operations(toggle_uids=to_toggle, create_conns=to_create_conns) + + return synced_count, "Successfully synchronized with Remnawave" + + except Exception as e: + logger.exception("Synchronization error") + return 0, f"Error: {str(e)}" + + +def get_current_user(request: Request): + user_id = request.session.get('user_id') + if not user_id: + return None + data = load_data() + for u in data.get('users', []): + if u['id'] == user_id: + return u + return None + + +def tpl(request, template, **kwargs): + data = load_data() + lang = request.cookies.get('lang', 'en') + ctx = { + 'request': request, + 'current_user': get_current_user(request), + 'site_settings': data.get('settings', {}).get('appearance', {}), + 'captcha_settings': data.get('settings', {}).get('captcha', {}), + 'telegram_settings': data.get('settings', {}).get('telegram', {}), + 'bot_running': tg_bot.is_running(), + 'lang': lang, + '_': lambda text_id: _t(text_id, lang), + 'translations_json': json.dumps(TRANSLATIONS.get(lang, TRANSLATIONS.get('en', {}))), + 'all_translations_json': json.dumps(TRANSLATIONS) + } + ctx.update(kwargs) + return templates.TemplateResponse(template, ctx) + + +# ======================== Pydantic Models ======================== + +class LoginRequest(BaseModel): + username: str + password: str + captcha: Optional[str] = None + + +class AddServerRequest(BaseModel): + host: str = '' + ssh_port: int = 22 + username: str = '' + password: str = '' + private_key: str = '' + name: str = '' + + +class EditServerRequest(BaseModel): + name: str = '' + host: str = '' + ssh_port: int = 22 + username: str = '' + # Optional[str] = None lets the client distinguish "leave field as is" + # (omit / null) from "explicitly clear" (empty string). Both credential + # fields can be omitted to keep current auth unchanged. + password: Optional[str] = None + private_key: Optional[str] = None + + +class ReorderServersRequest(BaseModel): + # `order[i]` is the *old* server index now at position `i` in the new layout. + order: List[int] + + +class InstallProtocolRequest(BaseModel): + protocol: str = 'awg' + port: str = '55424' + install_another: Optional[bool] = False + tls_emulation: Optional[bool] = None + tls_domain: Optional[str] = None + max_connections: Optional[int] = None + # SOCKS5 + socks5_username: Optional[str] = None + socks5_password: Optional[str] = None + # AdGuard Home + adguard_mode: Optional[str] = None # 'replace' or 'sidebyside' + adguard_web_port: Optional[int] = None + adguard_expose_web: Optional[bool] = None + adguard_dot_port: Optional[int] = None + adguard_doh_port: Optional[int] = None + adguard_expose_dns: Optional[bool] = None + adguard_expose_dot: Optional[bool] = None + adguard_expose_doh: Optional[bool] = None + # NGINX + nginx_domain: Optional[str] = None + nginx_email: Optional[str] = None + + +class Socks5SettingsRequest(BaseModel): + protocol: str = 'socks5' + port: Optional[int] = None + username: Optional[str] = None + password: Optional[str] = None + + +class ProtocolRequest(BaseModel): + protocol: str = 'awg' + + +class AddConnectionRequest(BaseModel): + protocol: str = 'awg' + name: str = 'Connection' + user_id: Optional[str] = None + telemt_quota: Optional[str] = None + telemt_max_ips: Optional[int] = None + telemt_expiry: Optional[str] = None + telemt_secret: Optional[str] = None + telemt_ad_tag: Optional[str] = None + telemt_max_conns: Optional[int] = None + + +class EditConnectionRequest(BaseModel): + protocol: str = 'telemt' + client_id: str = '' + telemt_quota: Optional[str] = None + telemt_max_ips: Optional[int] = None + telemt_expiry: Optional[str] = None + telemt_secret: Optional[str] = None + telemt_ad_tag: Optional[str] = None + telemt_max_conns: Optional[int] = None + + +class ConnectionActionRequest(BaseModel): + protocol: str = 'awg' + client_id: str = '' + + +class ToggleConnectionRequest(BaseModel): + protocol: str = 'awg' + client_id: str = '' + enable: bool = True + + +class AddUserRequest(BaseModel): + username: str + password: str + role: str = 'user' + telegramId: Optional[str] = None + email: Optional[str] = None + description: Optional[str] = None + traffic_limit: Optional[float] = 0 + traffic_reset_strategy: Optional[str] = 'never' + server_id: Optional[int] = None + protocol: Optional[str] = None + connection_name: Optional[str] = None + expiration_date: Optional[str] = None + telemt_quota: Optional[str] = None + telemt_max_ips: Optional[int] = None + telemt_expiry: Optional[str] = None + telemt_secret: Optional[str] = None + telemt_ad_tag: Optional[str] = None + telemt_max_conns: Optional[int] = None + + + +class ServerConfigSaveRequest(BaseModel): + protocol: str + config: str + + +class NginxSiteSaveRequest(BaseModel): + protocol: str = 'nginx' + html: str = '' + + +class BackupDownloadRequest(BaseModel): + protocol: str + filename: str + + +class AppearanceSettings(BaseModel): + title: str = 'Amnezia' + logo: str = '🛡' + subtitle: str = 'Web Panel' + + +class SyncSettings(BaseModel): + remnawave_url: str = '' + remnawave_api_key: str = '' + remnawave_sync: bool = False + remnawave_sync_users: bool = False + remnawave_create_conns: bool = False + remnawave_server_id: int = 0 + remnawave_protocol: str = 'awg' + +class CaptchaSettings(BaseModel): + enabled: bool = False + + +class SSLSettings(BaseModel): + enabled: bool = False + domain: str = '' + cert_path: str = '' + key_path: str = '' + cert_text: str = '' + key_text: str = '' + panel_port: int = 5000 + +class TelegramSettings(BaseModel): + token: str = '' + enabled: bool = False + + + + +class UpdateUserRequest(BaseModel): + telegramId: Optional[str] = None + email: Optional[str] = None + description: Optional[str] = None + traffic_limit: Optional[float] = 0 + traffic_reset_strategy: Optional[str] = None + expiration_date: Optional[str] = None + password: Optional[str] = None + + + +class SaveSettingsRequest(BaseModel): + appearance: AppearanceSettings + sync: SyncSettings + captcha: CaptchaSettings + telegram: TelegramSettings + ssl: SSLSettings + + +class ToggleUserRequest(BaseModel): + enabled: bool + + +class AddUserConnectionRequest(BaseModel): + server_id: int + protocol: str = 'awg' + name: str = 'VPN Connection' + client_id: Optional[str] = None + telemt_quota: Optional[str] = None + telemt_max_ips: Optional[int] = None + telemt_expiry: Optional[str] = None + telemt_secret: Optional[str] = None + telemt_ad_tag: Optional[str] = None + telemt_max_conns: Optional[int] = None + + +class CreateApiTokenRequest(BaseModel): + name: str + + +class ShareSetupRequest(BaseModel): + enabled: bool + password: Optional[str] = None + + +class ShareAuthRequest(BaseModel): + password: str + + +class TunnelStartRequest(BaseModel): + authtoken: Optional[str] = None + + +# ======================== Startup ======================== + +@app.on_event("startup") +async def startup(): + # Init Postgres schema; import legacy data.json once if DB is empty + await asyncio.to_thread(ensure_db_ready, DATA_FILE) + # Optional: import tunnels_state.json into DB if present and empty + if os.path.exists(TUNNEL_STATE_FILE): + try: + existing = await asyncio.to_thread(load_tunnel_state) + if not existing: + with open(TUNNEL_STATE_FILE, 'r', encoding='utf-8') as f: + legacy_tunnels = json.load(f) + if isinstance(legacy_tunnels, dict) and legacy_tunnels: + await asyncio.to_thread(save_tunnel_state, legacy_tunnels) + logger.info("Imported legacy tunnels_state.json into PostgreSQL") + except Exception as e: + logger.warning(f"Could not import tunnels_state.json: {e}") + + data = load_data() + changed = False + if not data.get('users'): + data['users'] = [{ + 'id': str(uuid.uuid4()), + 'username': 'admin', + 'password_hash': hash_password('admin'), + 'role': 'admin', + 'enabled': True, + 'created_at': datetime.now().isoformat(), + }] + changed = True + logger.info("Default admin created (admin / admin)") + + # Migration for sharing fields and traffic reset strategy + for u in data['users']: + migrated = False + if 'share_enabled' not in u: + u['share_enabled'] = False + migrated = True + if not u.get('share_token'): + u['share_token'] = secrets.token_urlsafe(16) + migrated = True + if 'share_password_hash' not in u: + u['share_password_hash'] = None + migrated = True + + # Traffic reset strategy and total traffic + if 'traffic_reset_strategy' not in u: + u['traffic_reset_strategy'] = 'never' + migrated = True + if 'traffic_total' not in u: + u['traffic_total'] = u.get('traffic_used', 0) + migrated = True + if 'last_reset_at' not in u: + u['last_reset_at'] = datetime.now().isoformat() + migrated = True + if 'expiration_date' not in u: + u['expiration_date'] = None + migrated = True + + if migrated: + changed = True + logger.info(f"Migrated user {u['username']} to new traffic/sharing fields") + + # API tokens collection — initialise lazily on first run. + if 'api_tokens' not in data: + data['api_tokens'] = [] + changed = True + logger.info("Initialised empty api_tokens collection") + + # SSL settings migration + if 'ssl' not in data.get('settings', {}): + if 'settings' not in data: data['settings'] = {} + data['settings']['ssl'] = { + 'enabled': False, + 'domain': '', + 'cert_path': '', + 'key_path': '', + 'cert_text': '', + 'key_text': '', + 'panel_port': 5000 + } + changed = True + logger.info("Migrated SSL settings") + + if changed: + save_data(data) + + # Start periodic background tasks + asyncio.create_task(periodic_background_tasks()) + + # Start Telegram bot if enabled + tg_cfg = data.get('settings', {}).get('telegram', {}) + if tg_cfg.get('enabled') and tg_cfg.get('token'): + logger.info("Starting Telegram bot from saved settings...") + tg_bot.launch_bot(tg_cfg['token'], load_data, generate_vpn_link, save_data) + + +def _scrape_server_traffic(server, sid, my_conns): + server_updates = [] + try: + ssh = get_ssh(server) + ssh.connect() + for proto in ['awg', 'awg2', 'awg_legacy', 'xray', 'telemt', 'wireguard']: + if proto in server.get('protocols', {}): + manager = get_protocol_manager(ssh, proto) + clients = _manager_call(manager, 'get_clients', proto) + client_bytes = {} + for c in clients: + rx = c.get('userData', {}).get('dataReceivedBytes', 0) + tx = c.get('userData', {}).get('dataSentBytes', 0) + client_bytes[c.get('clientId')] = rx + tx + + for uc in my_conns: + if uc['protocol'] == proto and uc['client_id'] in client_bytes: + curr_bytes = client_bytes[uc['client_id']] + last_bytes = uc.get('last_bytes', 0) + delta = curr_bytes - last_bytes if curr_bytes >= last_bytes else curr_bytes + server_updates.append((uc['id'], delta, curr_bytes)) + ssh.disconnect() + except Exception as e: + logger.error(f"Traffic sync err server {sid}: {e}") + return server_updates + + +async def periodic_background_tasks(): + """Background task to sync traffic limits and Remnawave every 10 minutes""" + while True: + try: + # We wait before the first sync to let the app settle + await asyncio.sleep(60) + + # --- 1. TRAFFIC SYNC & LIMITS --- + logger.info("Starting background traffic sync...") + data = load_data() + + conns_by_server = {} + for uc in data.get('user_connections', []): + sid = uc['server_id'] + conns_by_server.setdefault(sid, []).append(uc) + + updates = [] + + for sid, server in enumerate(data.get('servers', [])): + if sid not in conns_by_server: continue + + # Run the blocking SSH traffic scraping in a background thread! + server_updates = await asyncio.to_thread(_scrape_server_traffic, server, sid, conns_by_server[sid]) + if server_updates: + updates.extend(server_updates) + + to_disable_uids = [] + if updates: + async with DATA_LOCK: + curr_data = load_data() + users_map = {u['id']: u for u in curr_data.get('users', [])} + uc_list = curr_data.get('user_connections', []) + uc_map = {uc['id']: uc for uc in uc_list} + + # Current date/time for reset checking + now = datetime.now() + + for uc_id, delta, curr_bytes in updates: + if uc_id in uc_map: + uc_map[uc_id]['last_bytes'] = curr_bytes + uid = uc_map[uc_id]['user_id'] + if uid in users_map: + u = users_map[uid] + # Check if reset is needed BEFORE adding new consumption + strategy = u.get('traffic_reset_strategy', 'never') + last_reset_iso = u.get('last_reset_at') + + reset_needed = False + if strategy != 'never' and last_reset_iso: + try: + last = datetime.fromisoformat(last_reset_iso) + if strategy == 'daily': + reset_needed = now.date() > last.date() + elif strategy == 'weekly': + reset_needed = now.isocalendar()[1] != last.isocalendar()[1] or now.year != last.year + elif strategy == 'monthly': + reset_needed = now.month != last.month or now.year != last.year + except: + pass + + if reset_needed: + logger.info(f"Resetting traffic for user {u['username']} (strategy: {strategy})") + u['traffic_used'] = 0 + u['last_reset_at'] = now.isoformat() + + # Update both resettable and total traffic + u['traffic_used'] = u.get('traffic_used', 0) + delta + u['traffic_total'] = u.get('traffic_total', 0) + delta + + limit = u.get('traffic_limit', 0) + if limit > 0 and u['traffic_used'] >= limit and u.get('enabled', True): + if uid not in to_disable_uids: + to_disable_uids.append(uid) + + # Check expiration date + exp_str = u.get('expiration_date') + if exp_str and u.get('enabled', True): + try: + exp_date = datetime.fromisoformat(exp_str) + if now > exp_date: + logger.info(f"Subscription expired for user {u['username']} (expired at {exp_str})") + if uid not in to_disable_uids: + to_disable_uids.append(uid) + except: + pass + save_data(curr_data) + + if to_disable_uids: + logger.info(f"Traffic limit reached, disabling users: {to_disable_uids}") + await perform_mass_operations(toggle_uids=[(uid, False) for uid in to_disable_uids]) + + # --- 2. REMNAWAVE SYNC --- + logger.info("Starting background Remnawave sync...") + data = load_data() + if data.get('settings', {}).get('sync', {}).get('remnawave_sync_users'): + count, msg = await sync_users_with_remnawave(data) + logger.info(f"Background Remnawave sync finished: {count} users updated. {msg}") + else: + logger.info("Background Remnawave sync skipped (disabled in settings)") + + except Exception as e: + logger.error(f"Error in periodic_background_tasks: {e}") + + # Wait 10 minutes before next sync + await asyncio.sleep(600) + + +# ======================== PAGE ROUTES ======================== + +@app.get('/login', response_class=HTMLResponse, tags=["System Templates"]) +async def login_page(request: Request): + if get_current_user(request): + return RedirectResponse(url='/', status_code=302) + return tpl(request, 'login.html') + + +@app.get("/set_lang/{lang}", tags=["System Templates"]) +async def set_lang(lang: str, request: Request): + ref = request.headers.get("referer", "/") + response = RedirectResponse(url=ref) + response.set_cookie(key="lang", value=lang, max_age=31536000) + return response + + +@app.get('/logout', tags=["System Templates"]) +async def logout(request: Request): + request.session.clear() + return RedirectResponse(url='/login', status_code=302) + + +@app.get('/', response_class=HTMLResponse, tags=["System Templates"]) +async def index(request: Request): + user = get_current_user(request) + if not user: + return RedirectResponse(url='/login', status_code=302) + if user['role'] == 'user': + return RedirectResponse(url='/my', status_code=302) + data = load_data() + return tpl(request, 'index.html', servers=data['servers']) + + +@app.get('/server/{server_id}', response_class=HTMLResponse, tags=["System Templates"]) +async def server_detail(request: Request, server_id: int): + user = get_current_user(request) + if not user: + return RedirectResponse(url='/login', status_code=302) + if user['role'] not in ('admin', 'support'): + return RedirectResponse(url='/my', status_code=302) + data = load_data() + if server_id >= len(data['servers']): + return RedirectResponse(url='/') + server = data['servers'][server_id] + users_list = data.get('users', []) + return tpl(request, 'server.html', server=server, server_id=server_id, users=users_list) + + +@app.get('/users', response_class=HTMLResponse, tags=["System Templates"]) +async def users_page(request: Request): + user = get_current_user(request) + if not user: + return RedirectResponse(url='/login', status_code=302) + if user['role'] not in ('admin', 'support'): + return RedirectResponse(url='/my', status_code=302) + data = load_data() + users_list = data.get('users', []) + # Count connections per user + conns = data.get('user_connections', []) + for u in users_list: + u['connections_count'] = sum(1 for c in conns if c['user_id'] == u['id']) + servers = data['servers'] + return tpl(request, 'users.html', users=users_list, servers=servers) + + +@app.get('/my', response_class=HTMLResponse, tags=["System Templates"]) +async def my_connections_page(request: Request): + user = get_current_user(request) + if not user: + return RedirectResponse(url='/login', status_code=302) + data = load_data() + conns = [c for c in data.get('user_connections', []) if c['user_id'] == user['id']] + # Enrich with server names + for c in conns: + sid = c.get('server_id', 0) + if sid < len(data['servers']): + c['server_name'] = data['servers'][sid].get('name', data['servers'][sid].get('host', '')) + else: + c['server_name'] = 'Unknown' + return tpl(request, 'my_connections.html', connections=conns) + + +# ======================== AUTH API ======================== + +@app.get('/api/auth/captcha', tags=["Authentication"]) +async def api_captcha(request: Request): + if not CaptchaGenerator: + return JSONResponse({"error": "multicolorcaptcha is not installed"}, status_code=500) + + # 2 is a multiplier for the image resolution size + generator = CaptchaGenerator(2) + captcha = generator.gen_captcha_image(difficult_level=2) + request.session['captcha_answer'] = captcha.characters + + img_bytes = io.BytesIO() + captcha.image.save(img_bytes, format='PNG') + img_bytes.seek(0) + + return StreamingResponse(img_bytes, media_type="image/png") + + +@app.post('/api/auth/login', tags=["Authentication"]) +async def api_login(request: Request, req: LoginRequest): + data = load_data() + captcha_settings = data.get('settings', {}).get('captcha', {}) + if captcha_settings.get('enabled') is True: + answer = request.session.get('captcha_answer') + lang = request.cookies.get('lang', 'ru') + if not answer or not req.captcha or answer.lower() != req.captcha.lower(): + request.session.pop('captcha_answer', None) + return JSONResponse({'error': _t('invalid_captcha', lang)}, status_code=400) + request.session.pop('captcha_answer', None) + + for u in data.get('users', []): + if u['username'] == req.username and verify_password(req.password, u['password_hash']): + lang = request.cookies.get('lang', 'ru') + if not u.get('enabled', True): + return JSONResponse({'error': _t('account_disabled', lang)}, status_code=403) + request.session['user_id'] = u['id'] + return {'status': 'success', 'role': u['role']} + lang = request.cookies.get('lang', 'ru') + return JSONResponse({'error': _t('invalid_login', lang)}, status_code=401) + + +# ======================== SERVER API (admin/support) ======================== + +def _check_admin(request): + """Authorize an admin/support action via session cookie OR Bearer token. + + Tokens are admin-equivalent and inherit the role of the user who created + them — if that user is later disabled or demoted, the token stops working. + """ + user = get_current_user(request) + if user and user['role'] in ('admin', 'support'): + return user + + auth_header = request.headers.get('Authorization', '') + if auth_header.lower().startswith('bearer '): + raw_token = auth_header[7:].strip() + data = load_data() + resolved = _resolve_api_token(data, raw_token) + if resolved: + entry, token_user = resolved + # Best-effort last-used tracking; swallow write errors so a flaky + # disk never blocks an API call from succeeding. + try: + if _touch_api_token(entry): + save_data(data) + except Exception as e: + logger.warning(f"Failed to touch API token last_used_at: {e}") + return token_user + + return None + + +@app.post('/api/servers/add', tags=["Servers"]) +async def api_add_server(request: Request, req: AddServerRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + host = req.host.strip() + username = req.username.strip() + name = req.name.strip() or host + if not host or not username: + return JSONResponse({'error': 'Host and username are required'}, status_code=400) + if not req.password and not req.private_key: + return JSONResponse({'error': 'Password or SSH key is required'}, status_code=400) + + ssh = SSHManager(host, req.ssh_port, username, req.password, req.private_key) + try: + ssh.connect() + server_info = ssh.test_connection() + ssh.disconnect() + except Exception as e: + return JSONResponse({'error': f'Connection failed: {str(e)}'}, status_code=400) + + server = { + 'name': name, 'host': host, 'ssh_port': req.ssh_port, + 'username': username, 'password': req.password, + 'private_key': req.private_key, 'server_info': server_info, + 'protocols': {}, + } + data = load_data() + data['servers'].append(server) + save_data(data) + return {'status': 'success', 'server_id': len(data['servers']) - 1, 'server_info': server_info} + except Exception as e: + logger.exception("Error adding server") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/edit', tags=["Servers"]) +async def api_edit_server(request: Request, server_id: int, req: EditServerRequest): + """Update connection details for an existing server entry. Verifies the new + credentials by SSH-connecting before persisting, so a typo can't lock us out. + """ + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + + new_host = (req.host or '').strip() or server['host'] + new_user = (req.username or '').strip() or server['username'] + new_port = int(req.ssh_port or server.get('ssh_port', 22)) + new_name = (req.name or '').strip() or server.get('name') or new_host + + # Credential resolution: a non-empty value in either field switches to + # that auth method (and clears the other). Both omitted => keep current. + if req.private_key: + new_pass, new_key = '', req.private_key + elif req.password: + new_pass, new_key = req.password, '' + else: + new_pass = server.get('password', '') + new_key = server.get('private_key', '') + + if not new_pass and not new_key: + return JSONResponse({'error': 'Password or SSH key is required'}, status_code=400) + + # Verify the new connection details before committing the change. + ssh = SSHManager(new_host, new_port, new_user, new_pass, new_key) + try: + ssh.connect() + server_info = ssh.test_connection() + ssh.disconnect() + except Exception as e: + return JSONResponse({'error': f'Connection failed: {e}'}, status_code=400) + + server['name'] = new_name + server['host'] = new_host + server['ssh_port'] = new_port + server['username'] = new_user + server['password'] = new_pass + server['private_key'] = new_key + server['server_info'] = server_info + save_data(data) + return {'status': 'success', 'server_info': server_info} + except Exception as e: + logger.exception("Error editing server") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.get('/api/servers/{server_id}/ping', tags=["Servers"]) +async def api_server_ping(request: Request, server_id: int): + """Cheap reachability check: opens a TCP connection to the SSH port, + measures RTT, immediately closes. Runs on the asyncio loop so the page + can issue many pings in parallel without blocking each other. + """ + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + host = server['host'] + port = int(server.get('ssh_port', 22)) + + import time as _time + t0 = _time.perf_counter() + try: + reader, writer = await asyncio.wait_for( + asyncio.open_connection(host, port), timeout=2.0 + ) + ms = round((_time.perf_counter() - t0) * 1000) + writer.close() + try: + await writer.wait_closed() + except Exception: + pass + return {'alive': True, 'ms': ms} + except asyncio.TimeoutError: + return {'alive': False, 'error': 'timeout', 'ms': None} + except Exception as e: + return {'alive': False, 'error': str(e), 'ms': None} + + +@app.post('/api/servers/reorder', tags=["Servers"]) +async def api_reorder_servers(request: Request, req: ReorderServersRequest): + """Persist a user-defined ordering of servers. Also remaps `server_id` + references in user_connections so existing assignments survive the move. + """ + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + async with DATA_LOCK: + data = load_data() + n = len(data['servers']) + order = req.order or [] + if len(order) != n or sorted(order) != list(range(n)): + return JSONResponse( + {'error': f'Order must be a permutation of indices 0..{n - 1}'}, + status_code=400, + ) + new_servers = [data['servers'][i] for i in order] + # Map old index -> new index for user_connections remap + remap = {old: new for new, old in enumerate(order)} + for c in data.get('user_connections', []): + old_id = c.get('server_id') + if isinstance(old_id, int) and old_id in remap: + c['server_id'] = remap[old_id] + # Sync settings.sync.remnawave_server_id if it points at a moved server + sync_cfg = data.get('settings', {}).get('sync', {}) + rsid = sync_cfg.get('remnawave_server_id') + if isinstance(rsid, int) and rsid in remap: + sync_cfg['remnawave_server_id'] = remap[rsid] + data['servers'] = new_servers + save_data(data) + return {'status': 'success'} + + +@app.post('/api/servers/{server_id}/delete', tags=["Servers"]) +async def api_delete_server(request: Request, server_id: int): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + data['servers'].pop(server_id) + # Clean up connections for this server + data['user_connections'] = [c for c in data.get('user_connections', []) if c.get('server_id') != server_id] + # Adjust server_ids for connections pointing to higher indices + for c in data.get('user_connections', []): + if c.get('server_id', 0) > server_id: + c['server_id'] -= 1 + save_data(data) + return {'status': 'success'} + except Exception as e: + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/reboot', tags=["Servers"]) +async def api_reboot_server(request: Request, server_id: int): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + try: + ssh.run_sudo_command("nohup reboot > /dev/null 2>&1 &") + except Exception: + pass + try: + ssh.disconnect() + except: + pass + return {'status': 'success'} + except Exception as e: + logger.exception("Error rebooting server") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/clear', tags=["Servers"]) +async def api_clear_server(request: Request, server_id: int): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + # Match every Amnezia container by name prefix (catches awg/awg2/awg-legacy, + # wireguard, xray/ssxray, openvpn, dns, and any future amnezia-* protocol) + # plus the telemt container which doesn't share that prefix. + # Using a single script avoids one SSH round-trip per command. + cleanup_script = r""" +for c in $(docker ps -a --format '{{.Names}}' 2>/dev/null | grep -E '^(amnezia-|telemt$)'); do + docker stop "$c" >/dev/null 2>&1 || true + docker rm -fv "$c" >/dev/null 2>&1 || true +done + +# Drop locally-built and pulled Amnezia images so reinstall starts from a clean slate +for img in $(docker images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | grep -E '^(amnezia-|amneziavpn/|telemt:)'); do + docker rmi -f "$img" >/dev/null 2>&1 || true +done + +docker network rm amnezia-dns-net >/dev/null 2>&1 || true +rm -rf /opt/amnezia +""" + ssh.run_sudo_script(cleanup_script, timeout=120) + + server['protocols'] = {} + save_data(data) + ssh.disconnect() + return {'status': 'success'} + except Exception as e: + logger.exception("Error clearing server") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/stats', tags=["Servers"]) +async def api_server_stats(request: Request, server_id: int): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + stats = {} + out, _, _ = ssh.run_command( + "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | cut -d'%' -f1 2>/dev/null || " + "awk '{u=$2+$4; t=$2+$4+$5; if(NR==1){pu=u;pt=t} else printf \"%.1f\", (u-pu)/(t-pt)*100}' " + "<(grep 'cpu ' /proc/stat) <(sleep 0.5 && grep 'cpu ' /proc/stat) 2>/dev/null" + ) + try: + stats['cpu'] = round(float(out.strip().split('\n')[0]), 1) + except (ValueError, IndexError): + stats['cpu'] = 0 + out, _, _ = ssh.run_command("free -b | awk 'NR==2{printf \"%d %d\", $3, $2}'") + try: + parts = out.strip().split() + used, total = int(parts[0]), int(parts[1]) + stats.update(ram_used=used, ram_total=total, ram_percent=round(used / total * 100, 1) if total > 0 else 0) + except (ValueError, IndexError): + stats.update(ram_used=0, ram_total=0, ram_percent=0) + out, _, _ = ssh.run_command("df -B1 / | awk 'NR==2{printf \"%d %d\", $3, $2}'") + try: + parts = out.strip().split() + used, total = int(parts[0]), int(parts[1]) + stats.update(disk_used=used, disk_total=total, disk_percent=round(used / total * 100, 1) if total > 0 else 0) + except (ValueError, IndexError): + stats.update(disk_used=0, disk_total=0, disk_percent=0) + out, _, _ = ssh.run_command( + "DEV=$(ip route | awk '/default/ {print $5}' | head -1); " + "cat /proc/net/dev | awk -v dev=\"$DEV:\" '$1==dev{printf \"%d %d\", $2, $10}'" + ) + try: + parts = out.strip().split() + stats['net_rx'], stats['net_tx'] = int(parts[0]), int(parts[1]) + except (ValueError, IndexError): + stats['net_rx'] = stats['net_tx'] = 0 + out, _, _ = ssh.run_command("uptime -p 2>/dev/null || uptime") + stats['uptime'] = out.strip() + ssh.disconnect() + return stats + except Exception as e: + logger.exception("Error getting server stats") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/check', tags=["Servers"]) +async def api_check_server(request: Request, server_id: int): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + # Just use awg's docker checker since it uses the same command + manager = get_protocol_manager(ssh, 'awg') + status = {'connection': 'ok', 'docker_installed': manager.check_docker_installed(), 'protocols': {}} + + changed = False + if 'protocols' not in server: + server['protocols'] = {} + + def merge_saved_protocol_status(proto, result=None, error=None): + """Merge live status with saved protocol metadata. + + Multi-instance protocols are source-of-truth in data.json because + they cannot be discovered from BASE_PROTOCOLS alone. A transient + check failure must not delete awg2__2/awg2__3 from the panel. + """ + db_proto = server.get('protocols', {}).get(proto, {}) or {} + merged = dict(result or {}) + merged.setdefault('protocol', proto) + if error: + merged['error'] = error + if not merged.get('port') and db_proto.get('port'): + merged['port'] = db_proto['port'] + if db_proto.get('awg_params') and not merged.get('awg_params'): + merged['awg_params'] = db_proto.get('awg_params') + merged['base_protocol'] = db_proto.get('base_protocol') or protocol_base(proto) + merged['instance'] = db_proto.get('instance') or protocol_instance(proto) + merged['display_name'] = db_proto.get('display_name') or protocol_display_name(proto) + merged['container_name'] = db_proto.get('container_name') or protocol_container_name(proto) + if protocol_base(proto) == 'adguard': + for key in ('web_port', 'mode', 'internal_ip', 'expose_web'): + if db_proto.get(key) not in (None, ''): + if key == 'web_port' and merged.get('web_exposed'): + continue + merged[key] = db_proto[key] + if 'expose_web' in db_proto and 'web_exposed' not in merged: + merged['web_exposed'] = bool(db_proto.get('expose_web')) + if protocol_base(proto) == 'nginx': + for key in ('domain', 'email', 'site_url'): + if db_proto.get(key) not in (None, ''): + merged[key] = db_proto[key] + return merged + + def should_preserve_saved_protocol(proto, result=None, err=None): + """Return True when check must not remove a saved protocol record.""" + db_proto = server.get('protocols', {}).get(proto) + if not db_proto: + return False + # Additional AWG-family instances are only known by their saved + # dynamic keys (awg__2/awg2__2/awg_legacy__2). Keep them unless + # the user explicitly uninstalls them. + if protocol_base(proto) in MULTI_INSTANCE_PROTOCOLS and protocol_instance(proto) > 1: + return True + # Do not delete any saved protocol on command/check errors; only a + # clean live result with container_exists=False may prune base apps. + if err or (result and result.get('error')): + return True + return False + + def check_proto(proto): + try: + p_manager = get_protocol_manager(ssh, proto) + result = _manager_call(p_manager, 'get_server_status', proto) + return proto, merge_saved_protocol_status(proto, result), None + except Exception as e: + return proto, merge_saved_protocol_status(proto, {}, str(e)), str(e) + + protocols_to_check = list(dict.fromkeys(BASE_PROTOCOLS + list(server.get('protocols', {}).keys()))) + # Run checks sequentially. Several managers use the same SSH connection; + # checking them in parallel through one SSH object can produce false + # negatives and previously caused dynamic AWG instances to be removed. + for proto in protocols_to_check: + proto, result, err = check_proto(proto) + status['protocols'][proto] = result + if err: + continue + if result.get('container_exists'): + if proto not in server['protocols']: + server['protocols'][proto] = { + 'installed': True, + 'port': result.get('port', '55424'), + 'awg_params': result.get('awg_params', {}), + 'base_protocol': protocol_base(proto), + 'instance': protocol_instance(proto), + 'display_name': protocol_display_name(proto), + 'container_name': protocol_container_name(proto), + } + if protocol_base(proto) == 'adguard': + server['protocols'][proto].update({ + 'mode': result.get('mode'), + 'internal_ip': result.get('internal_ip'), + 'web_port': result.get('web_port'), + 'expose_web': result.get('web_exposed'), + }) + if protocol_base(proto) == 'nginx': + server['protocols'][proto].update({ + 'domain': result.get('domain'), + 'email': result.get('email'), + 'site_url': result.get('site_url'), + }) + changed = True + else: + if proto in server['protocols']: + if should_preserve_saved_protocol(proto, result, err): + # Keep saved dynamic instances visible as installed but stopped/unchecked. + status['protocols'][proto]['container_exists'] = True + status['protocols'][proto].setdefault('container_running', False) + status['protocols'][proto]['status_preserved'] = True + else: + del server['protocols'][proto] + changed = True + + if changed: + save_data(data) + + ssh.disconnect() + return status + except Exception as e: + logger.exception("Error checking server") + return JSONResponse({'error': str(e), 'connection': 'failed'}, status_code=500) + + +@app.post('/api/servers/{server_id}/install', tags=["Protocols"]) +async def api_install_protocol(request: Request, server_id: int, req: InstallProtocolRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + if not is_valid_protocol(req.protocol): + return JSONResponse({'error': 'Invalid protocol type'}, status_code=400) + + server = data['servers'][server_id] + if 'protocols' not in server: + server['protocols'] = {} + base_protocol = protocol_base(req.protocol) + if req.install_another: + if base_protocol not in MULTI_INSTANCE_PROTOCOLS: + return JSONResponse({'error': 'Multiple instances are not supported for this protocol yet'}, status_code=400) + install_protocol = next_protocol_key(server.get('protocols', {}), base_protocol) + else: + install_protocol = req.protocol + install_base = protocol_base(install_protocol) + + ssh = get_ssh(server) + ssh.connect() + docker_install_log = ensure_docker_installed(ssh) + manager = get_protocol_manager(ssh, install_protocol) + + # Pass parameters to installer + if install_base == 'telemt': + result = manager.install_protocol( + protocol_type=install_protocol, + port=req.port, + tls_emulation=req.tls_emulation if req.tls_emulation is not None else True, + tls_domain=req.tls_domain, + max_connections=req.max_connections if req.max_connections is not None else 0 + ) + elif install_base == 'xray': + result = manager.install_protocol(port=req.port) + elif install_base == 'wireguard': + result = manager.install_protocol(port=req.port) + elif install_base == 'socks5': + result = manager.install_protocol( + protocol_type=install_protocol, + port=req.port, + username=req.socks5_username, + password=req.socks5_password, + ) + elif install_base == 'adguard': + result = manager.install_protocol( + protocol_type='adguard', + mode=req.adguard_mode or 'sidebyside', + web_port=req.adguard_web_port, + expose_web=bool(req.adguard_expose_web), + dns_port=req.port, + dot_port=req.adguard_dot_port, + doh_port=req.adguard_doh_port, + expose_dns=bool(req.adguard_expose_dns), + expose_dot=bool(req.adguard_expose_dot), + expose_doh=bool(req.adguard_expose_doh), + ) + elif install_base == 'nginx': + result = manager.install_protocol( + protocol_type='nginx', + port=req.port, + domain=req.nginx_domain, + email=req.nginx_email, + ) + else: + result = manager.install_protocol(install_protocol, port=req.port) + + if not isinstance(result, dict): + result = {'status': 'success', 'message': str(result)} + if docker_install_log: + result.setdefault('log', []) + result['log'].insert(0, docker_install_log) + if result.get('status') == 'error' or result.get('error'): + ssh.disconnect() + return JSONResponse({'error': result.get('message') or result.get('error') or 'Installation failed'}, status_code=400) + + proto_record = { + 'installed': True, + 'port': req.port, + 'awg_params': result.get('awg_params', {}), + } + if install_base == 'adguard': + proto_record['mode'] = result.get('mode') + proto_record['internal_ip'] = result.get('internal_ip') + proto_record['web_port'] = result.get('web_port') + proto_record['expose_web'] = result.get('expose_web') + if install_base == 'nginx': + proto_record['domain'] = result.get('domain') + proto_record['email'] = result.get('email') + proto_record['site_url'] = result.get('site_url') + proto_record['base_protocol'] = install_base + proto_record['instance'] = protocol_instance(install_protocol) + proto_record['display_name'] = protocol_display_name(install_protocol) + proto_record['container_name'] = protocol_container_name(install_protocol) + server['protocols'][install_protocol] = proto_record + result['protocol'] = install_protocol + result['base_protocol'] = install_base + result['display_name'] = proto_record['display_name'] + result['container_name'] = proto_record['container_name'] + save_data(data) + ssh.disconnect() + return result + except Exception as e: + logger.exception("Error installing protocol") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.get('/api/servers/{server_id}/socks5/credentials', tags=["Protocols"]) +async def api_socks5_get_credentials(request: Request, server_id: int, protocol: str = 'socks5'): + """Return the current SOCKS5 port/username/password for the panel UI.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + protocol = protocol if is_valid_protocol(protocol) and protocol_base(protocol) == 'socks5' else 'socks5' + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, protocol) + creds = manager.get_credentials() + ssh.disconnect() + return {'status': 'success', **creds} + except Exception as e: + logger.exception("Error reading SOCKS5 credentials") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/socks5/credentials', tags=["Protocols"]) +async def api_socks5_update_credentials(request: Request, server_id: int, req: Socks5SettingsRequest): + """Apply new SOCKS5 connection settings — regenerates the 3proxy config and + reconciles the container (recreating it if the listening port changed).""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + protocol = req.protocol if is_valid_protocol(req.protocol) and protocol_base(req.protocol) == 'socks5' else 'socks5' + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, protocol) + result = manager.update_credentials( + port=req.port, username=req.username, password=req.password + ) + ssh.disconnect() + # Persist the new port in the saved server record so the dashboard + # shows the right value on next check without an SSH round-trip. + if result.get('status') == 'success' and result.get('port'): + srv_proto = server.setdefault('protocols', {}).setdefault(protocol, {}) + srv_proto['port'] = str(result['port']) + srv_proto['installed'] = True + srv_proto['base_protocol'] = protocol_base(protocol) + srv_proto['instance'] = protocol_instance(protocol) + srv_proto['display_name'] = protocol_display_name(protocol) + srv_proto['container_name'] = protocol_container_name(protocol) + save_data(data) + return result + except Exception as e: + logger.exception("Error updating SOCKS5 credentials") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/uninstall', tags=["Protocols"]) +async def api_uninstall_protocol(request: Request, server_id: int, req: ProtocolRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + base = protocol_base(req.protocol) + if base in ('xray', 'wireguard'): + manager.remove_container() + else: + manager.remove_container(req.protocol) + if req.protocol in server.get('protocols', {}): + del server['protocols'][req.protocol] + save_data(data) + ssh.disconnect() + return {'status': 'success'} + except Exception as e: + logger.exception("Error uninstalling protocol") + return JSONResponse({'error': str(e)}, status_code=500) + + +CONTAINER_NAMES = { + 'awg': 'amnezia-awg', + 'awg2': 'amnezia-awg2', + 'awg_legacy': 'amnezia-awg-legacy', + 'xray': 'amnezia-xray', + 'telemt': 'telemt', + 'dns': 'amnezia-dns', + 'wireguard': 'amnezia-wireguard', + 'socks5': 'amnezia-socks5proxy', + 'adguard': 'amnezia-adguard', + 'nginx': 'amnezia-nginx', +} + + + +@app.post('/api/servers/{server_id}/backups', tags=["Protocols"]) +async def api_protocol_backups_list(request: Request, server_id: int, req: ProtocolRequest): + """List backups created on the remote server for one protocol.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if not is_valid_protocol(req.protocol): + return JSONResponse({'error': 'Unknown protocol'}, status_code=400) + ssh = None + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + result = BackupManager(ssh).list_backups(req.protocol) + if result.get('status') == 'error': + return JSONResponse({'error': result.get('message', 'Failed to list backups')}, status_code=500) + return result + except Exception as e: + logger.exception("Error listing protocol backups") + return JSONResponse({'error': str(e)}, status_code=500) + finally: + if ssh: + ssh.disconnect() + + +@app.post('/api/servers/{server_id}/backups/create', tags=["Protocols"]) +async def api_protocol_backup_create(request: Request, server_id: int, req: ProtocolRequest): + """Create a protocol backup archive on the remote server.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if not is_valid_protocol(req.protocol): + return JSONResponse({'error': 'Unknown protocol'}, status_code=400) + ssh = None + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + container = protocol_container_name(req.protocol) + if not container: + return JSONResponse({'error': 'Unknown protocol'}, status_code=400) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + result = BackupManager(ssh).create_backup(req.protocol, container) + if result.get('status') == 'error': + return JSONResponse({'error': result.get('message', 'Failed to create backup')}, status_code=500) + return result + except Exception as e: + logger.exception("Error creating protocol backup") + return JSONResponse({'error': str(e)}, status_code=500) + finally: + if ssh: + ssh.disconnect() + + +@app.post('/api/servers/{server_id}/backups/download', tags=["Protocols"]) +async def api_protocol_backup_download(request: Request, server_id: int, req: BackupDownloadRequest): + """Download one remote protocol backup archive through the panel.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if not is_valid_protocol(req.protocol): + return JSONResponse({'error': 'Unknown protocol'}, status_code=400) + manager = BackupManager(None) + safe_proto = manager.safe_protocol(req.protocol) + filename = manager.safe_filename(req.filename) + if not filename: + return JSONResponse({'error': 'Invalid backup filename'}, status_code=400) + ssh = None + tmp_path = None + tmp_remote = f'/tmp/{filename}' + remote_path = f'{manager.BACKUP_ROOT}/{safe_proto}/{filename}' + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + quoted_remote = shlex.quote(remote_path) + quoted_tmp = shlex.quote(tmp_remote) + _, err, code = ssh.run_sudo_command( + f"test -f {quoted_remote} && cp {quoted_remote} {quoted_tmp} && chmod 0644 {quoted_tmp}" + ) + if code != 0: + return JSONResponse({'error': err or 'Backup not found'}, status_code=404) + fd, tmp_path = tempfile.mkstemp(prefix='amnezia-backup-', suffix='.tar.gz') + os.close(fd) + sftp = ssh.client.open_sftp() + try: + sftp.get(tmp_remote, tmp_path) + finally: + sftp.close() + ssh.run_sudo_command(f"rm -f {quoted_tmp}") + ssh.disconnect() + ssh = None + return FileResponse( + tmp_path, + media_type='application/gzip', + filename=filename, + background=BackgroundTask(lambda p=tmp_path: os.path.exists(p) and os.remove(p)), + ) + except Exception as e: + logger.exception("Error downloading protocol backup") + if tmp_path and os.path.exists(tmp_path): + try: + os.remove(tmp_path) + except Exception: + pass + return JSONResponse({'error': str(e)}, status_code=500) + finally: + if ssh: + ssh.disconnect() + + +@app.post('/api/servers/{server_id}/container/toggle', tags=["Protocols"]) +async def api_container_toggle(request: Request, server_id: int, req: ProtocolRequest): + """Start or stop a protocol Docker container.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + container = protocol_container_name(req.protocol) + if not container: + return JSONResponse({'error': 'Unknown protocol'}, status_code=400) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + # Check current state + out, _, _ = ssh.run_sudo_command( + f"docker inspect -f '{{{{.State.Running}}}}' {container} 2>/dev/null" + ) + is_running = out.strip().lower() == 'true' + if is_running: + ssh.run_sudo_command(f"docker stop {container}") + action = 'stopped' + else: + ssh.run_sudo_command(f"docker start {container}") + action = 'started' + ssh.disconnect() + return {'status': 'success', 'action': action, 'container': container} + except Exception as e: + logger.exception("Error toggling container") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/server_config', tags=["Protocols"]) +async def api_server_config(request: Request, server_id: int, req: ProtocolRequest): + """Get the raw server-side WireGuard/Xray configuration.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + if protocol_base(req.protocol) == 'xray': + from managers.xray_manager import XrayManager + mgr = XrayManager(ssh, req.protocol) + data_json = mgr._get_server_json() + import json as _json + config = _json.dumps(data_json, indent=2, ensure_ascii=False) if data_json else '' + elif protocol_base(req.protocol) == 'telemt': + from managers.telemt_manager import TelemtManager + mgr = TelemtManager(ssh, req.protocol) + config = mgr._get_server_config() + elif protocol_base(req.protocol) == 'wireguard': + from managers.wireguard_manager import WireGuardManager + mgr = WireGuardManager(ssh) + config = mgr._get_server_config() + elif protocol_base(req.protocol) == 'nginx': + from managers.nginx_manager import NginxManager + mgr = NginxManager(ssh, req.protocol) + config = mgr._get_server_config(req.protocol) + else: + mgr = AWGManager(ssh) + config = mgr._get_server_config(req.protocol) + ssh.disconnect() + return {'config': config} + except Exception as e: + logger.exception("Error getting server config") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/server_config/save', tags=["Protocols"]) +async def api_server_config_save(request: Request, server_id: int, req: ServerConfigSaveRequest): + """Save the raw server-side WireGuard/Xray configuration and apply changes.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + if protocol_base(req.protocol) == 'xray': + from managers.xray_manager import XrayManager + mgr = XrayManager(ssh, req.protocol) + import json as _json + try: + data_json = _json.loads(req.config) + except Exception as e: + ssh.disconnect() + return JSONResponse({'error': f'Invalid JSON format: {str(e)}'}, status_code=400) + mgr._save_server_json(data_json) + elif protocol_base(req.protocol) == 'telemt': + from managers.telemt_manager import TelemtManager + mgr = TelemtManager(ssh, req.protocol) + mgr.save_server_config(req.protocol, req.config) + elif protocol_base(req.protocol) == 'wireguard': + from managers.wireguard_manager import WireGuardManager + mgr = WireGuardManager(ssh) + mgr.save_server_config(req.config) + elif protocol_base(req.protocol) == 'nginx': + from managers.nginx_manager import NginxManager + mgr = NginxManager(ssh, req.protocol) + mgr.save_server_config(req.protocol, req.config) + else: + mgr = AWGManager(ssh) + mgr.save_server_config(req.protocol, req.config) + ssh.disconnect() + return {'status': 'success'} + except Exception as e: + logger.exception("Error saving server config") + return JSONResponse({'error': str(e)}, status_code=500) + + + + + +@app.post('/api/servers/{server_id}/nginx/site', tags=["Protocols"]) +async def api_nginx_site_get(request: Request, server_id: int, req: ProtocolRequest): + """Return editable NGINX site index.html.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + if protocol_base(req.protocol) != 'nginx': + return JSONResponse({'error': 'Invalid protocol type'}, status_code=400) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + from managers.nginx_manager import NginxManager + mgr = NginxManager(ssh, req.protocol) + html = mgr.get_site_index(req.protocol) + ssh.disconnect() + return {'status': 'success', 'html': html} + except Exception as e: + logger.exception("Error getting NGINX site") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/nginx/site/save', tags=["Protocols"]) +async def api_nginx_site_save(request: Request, server_id: int, req: NginxSiteSaveRequest): + """Save editable NGINX site index.html.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + if protocol_base(req.protocol) != 'nginx': + return JSONResponse({'error': 'Invalid protocol type'}, status_code=400) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + from managers.nginx_manager import NginxManager + mgr = NginxManager(ssh, req.protocol) + mgr.save_site_index(req.protocol, req.html) + ssh.disconnect() + return {'status': 'success'} + except Exception as e: + logger.exception("Error saving NGINX site") + return JSONResponse({'error': str(e)}, status_code=500) + +@app.get('/api/servers/{server_id}/connections', tags=["Connections"]) +async def api_get_connections(request: Request, server_id: int, protocol: str = Query(default='awg')): + if not protocol: + protocol = 'awg' + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, protocol) + clients = _manager_call(manager, 'get_clients', protocol) + ssh.disconnect() + + # Enrich with user info from user_connections + user_conns = data.get('user_connections', []) + users = data.get('users', []) + users_map = {u['id']: u for u in users} + for client in clients: + cid = client.get('clientId', '') + for uc in user_conns: + if uc.get('client_id') == cid and uc.get('server_id') == server_id and uc.get('protocol') == protocol: + uid = uc.get('user_id') + u = users_map.get(uid) + if u: + client['assigned_user'] = u['username'] + client['assigned_user_id'] = uid + break + return {'clients': clients} + except Exception as e: + logger.exception("Error getting connections") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/connections/add', tags=["Connections"]) +async def api_add_connection(request: Request, server_id: int, req: AddConnectionRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + proto_info = server.get('protocols', {}).get(req.protocol, {}) + port = proto_info.get('port', '55424') + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + + if protocol_base(req.protocol) == 'telemt': + result = manager.add_client( + req.protocol, req.name, server['host'], port, + telemt_quota=req.telemt_quota, + telemt_max_ips=req.telemt_max_ips, + telemt_expiry=req.telemt_expiry, + secret=req.telemt_secret, + user_ad_tag=req.telemt_ad_tag, + max_tcp_conns=req.telemt_max_conns + ) + elif protocol_base(req.protocol) == 'wireguard': + result = manager.add_client(req.name, server['host']) + else: + result = manager.add_client(req.protocol, req.name, server['host'], port) + ssh.disconnect() + + if result.get('config'): + result['vpn_link'] = generate_vpn_link(result['config']) + + # Link connection to user if specified + if req.user_id and result.get('client_id'): + conn = { + 'id': str(uuid.uuid4()), + 'user_id': req.user_id, + 'server_id': server_id, + 'protocol': req.protocol, + 'client_id': result['client_id'], + 'name': req.name, + 'created_at': datetime.now().isoformat(), + } + data['user_connections'].append(conn) + save_data(data) + + return result + except Exception as e: + logger.exception("Error adding connection") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/connections/remove', tags=["Connections"]) +async def api_remove_connection(request: Request, server_id: int, req: ConnectionActionRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + if not req.client_id: + return JSONResponse({'error': 'Client ID is required'}, status_code=400) + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + _manager_call(manager, 'remove_client', req.protocol, req.client_id) + ssh.disconnect() + # Remove from user_connections + data['user_connections'] = [ + c for c in data.get('user_connections', []) + if not (c.get('client_id') == req.client_id and c.get('server_id') == server_id) + ] + save_data(data) + return {'status': 'success'} + except Exception as e: + logger.exception("Error removing connection") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/connections/edit', tags=["Connections"]) +async def api_edit_connection(request: Request, server_id: int, req: EditConnectionRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + + edit_params = {} + if protocol_base(req.protocol) == 'telemt': + edit_params['telemt_quota'] = req.telemt_quota + edit_params['telemt_max_ips'] = req.telemt_max_ips + edit_params['telemt_expiry'] = req.telemt_expiry + edit_params['secret'] = req.telemt_secret + edit_params['user_ad_tag'] = req.telemt_ad_tag + edit_params['max_tcp_conns'] = req.telemt_max_conns + + result = manager.edit_client(req.protocol, req.client_id, edit_params) + ssh.disconnect() + return result + except Exception as e: + logger.exception("Error editing connection") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/connections/config', tags=["Connections"]) +async def api_get_connection_config(request: Request, server_id: int, req: ConnectionActionRequest): + user = get_current_user(request) + if not user: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + # Users can only view their own connections + if user['role'] == 'user': + owned = any( + c for c in data.get('user_connections', []) + if c.get('client_id') == req.client_id and c.get('server_id') == server_id and c.get('user_id') == user['id'] + ) + if not owned: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + server = data['servers'][server_id] + if not req.client_id: + return JSONResponse({'error': 'Client ID is required'}, status_code=400) + proto_info = server.get('protocols', {}).get(req.protocol, {}) + port = proto_info.get('port', '55424') + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + config = _manager_call(manager, 'get_client_config', req.protocol, req.client_id, server['host'], port) + ssh.disconnect() + vpn_link = generate_vpn_link(config) if config else '' + return {'config': config, 'vpn_link': vpn_link} + except Exception as e: + logger.exception("Error getting connection config") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/servers/{server_id}/connections/toggle', tags=["Connections"]) +async def api_toggle_connection(request: Request, server_id: int, req: ToggleConnectionRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + if not req.client_id: + return JSONResponse({'error': 'Client ID is required'}, status_code=400) + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + _manager_call(manager, 'toggle_client', req.protocol, req.client_id, req.enable) + ssh.disconnect() + status = 'enabled' if req.enable else 'disabled' + return {'status': 'success', 'enabled': req.enable, 'message': f'Connection {status}'} + except Exception as e: + logger.exception("Error toggling connection") + return JSONResponse({'error': str(e)}, status_code=500) + + +# ======================== USER API (admin only) ======================== + +@app.get('/api/users', tags=["Users"]) +async def api_list_users(request: Request, search: str = '', page: int = 1, size: int = 10): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + all_users = data.get('users', []) + conns = data.get('user_connections', []) + + # Filter + filtered = [] + search = search.lower() + for u in all_users: + if search: + match = (search in u['username'].lower() or + (u.get('email') and search in u['email'].lower()) or + (u.get('telegramId') and search in str(u['telegramId']).lower())) + if not match: + continue + filtered.append(u) + + total = len(filtered) + start = (page - 1) * size + end = start + size + page_items = filtered[start:end] + + users = [] + for u in page_items: + users.append({ + 'id': u['id'], 'username': u['username'], 'role': u['role'], + 'enabled': u.get('enabled', True), + 'created_at': u.get('created_at', ''), + 'telegramId': u.get('telegramId'), + 'email': u.get('email'), + 'description': u.get('description'), + 'connections_count': sum(1 for c in conns if c['user_id'] == u['id']), + 'traffic_used': u.get('traffic_used', 0), + 'traffic_total': u.get('traffic_total', 0), + 'traffic_limit': u.get('traffic_limit', 0), + 'traffic_reset_strategy': u.get('traffic_reset_strategy', 'never'), + 'last_reset_at': u.get('last_reset_at'), + "expiration_date": u.get("expiration_date"), + 'share_enabled': u.get('share_enabled', False), + 'share_token': u.get('share_token'), + 'has_share_password': bool(u.get('share_password_hash')), + 'source': 'Remnawave' if u.get('remnawave_uuid') else 'Local' + }) + return { + 'users': users, + 'total': total, + 'page': page, + 'size': size, + 'pages': (total + size - 1) // size + } + + +@app.post('/api/users/add', tags=["Users"]) +async def api_add_user(request: Request, req: AddUserRequest): + cur = get_current_user(request) + if not cur or cur['role'] != 'admin': + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + lang = request.cookies.get('lang', 'ru') + # Check duplicate + if any(u['username'] == req.username for u in data.get('users', [])): + return JSONResponse({'error': _t('user_exists', lang)}, status_code=400) + if req.role not in ('admin', 'support', 'user'): + return JSONResponse({'error': 'Invalid role'}, status_code=400) + new_user = { + 'id': str(uuid.uuid4()), + 'username': req.username, + 'password_hash': hash_password(req.password), + 'role': req.role, + 'telegramId': req.telegramId, + 'email': req.email, + 'description': req.description, + 'traffic_limit': int(req.traffic_limit * 1024**3) if req.traffic_limit else 0, + 'traffic_reset_strategy': req.traffic_reset_strategy or 'never', + 'traffic_used': 0, + 'traffic_total': 0, + 'last_reset_at': datetime.now().isoformat(), + 'expiration_date': req.expiration_date, + 'enabled': True, + 'created_at': datetime.now().isoformat(), + 'remnawave_uuid': None, + 'share_enabled': False, + 'share_token': secrets.token_urlsafe(16), + 'share_password_hash': None, + } + data['users'].append(new_user) + save_data(data) + + result = {'status': 'success', 'user_id': new_user['id']} + + # Auto-create connection if server & protocol specified + if req.server_id is not None and req.protocol: + if req.server_id < len(data['servers']): + server = data['servers'][req.server_id] + proto_info = server.get('protocols', {}).get(req.protocol, {}) + port = proto_info.get('port', '55424') + conn_name = req.connection_name or f"{req.username}_vpn" + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, req.protocol) + if protocol_base(req.protocol) == 'telemt': + conn_result = manager.add_client( + req.protocol, conn_name, server['host'], port, + telemt_quota=req.telemt_quota, + telemt_max_ips=req.telemt_max_ips, + telemt_expiry=req.telemt_expiry, + secret=req.telemt_secret, + user_ad_tag=req.telemt_ad_tag, + max_tcp_conns=req.telemt_max_conns + ) + else: + conn_result = manager.add_client(req.protocol, conn_name, server['host'], port) + ssh.disconnect() + + if conn_result.get('client_id'): + conn = { + 'id': str(uuid.uuid4()), + 'user_id': new_user['id'], + 'server_id': req.server_id, + 'protocol': req.protocol, + 'client_id': conn_result['client_id'], + 'name': conn_name, + 'created_at': datetime.now().isoformat(), + } + data = load_data() # reload + data['user_connections'].append(conn) + save_data(data) + result['connection_created'] = True + if conn_result.get('config'): + result['config'] = conn_result['config'] + result['vpn_link'] = generate_vpn_link(conn_result['config']) + return result + except Exception as e: + logger.exception("Error adding user") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/users/{user_id}/update', tags=["Users"]) +async def api_update_user(request: Request, user_id: str, req: UpdateUserRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + user = next((u for u in data['users'] if u['id'] == user_id), None) + if not user: + return JSONResponse({'error': 'User not found'}, status_code=404) + + if req.telegramId is not None: user['telegramId'] = req.telegramId + if req.email is not None: user['email'] = req.email + if req.description is not None: user['description'] = req.description + if req.traffic_limit is not None: + new_limit = int(req.traffic_limit * 1024**3) + user['traffic_limit'] = new_limit + + if req.traffic_reset_strategy is not None: + user['traffic_reset_strategy'] = req.traffic_reset_strategy + user['last_reset_at'] = datetime.now().isoformat() + + req_fields = getattr(req, 'model_fields_set', getattr(req, '__fields_set__', set())) + if 'expiration_date' in req_fields: + user['expiration_date'] = req.expiration_date or None + + if req.password: + user['password_hash'] = hash_password(req.password) + + save_data(data) + + # Auto re-enable if traffic limit increased beyond usage + if req.traffic_limit is not None: + if new_limit > 0 and user.get('traffic_used', 0) < new_limit and not user.get('enabled', True): + await perform_toggle_user(data, user_id, True) + save_data(data) + + return {'status': 'success'} + except Exception as e: + logger.exception("Error updating user") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/users/{user_id}/delete', tags=["Users"]) +async def api_delete_user(request: Request, user_id: str): + cur = get_current_user(request) + if not cur or cur['role'] != 'admin': + return JSONResponse({'error': 'Forbidden'}, status_code=403) + lang = request.cookies.get('lang', 'ru') + if cur['id'] == user_id: + return JSONResponse({'error': _t('cannot_delete_self', lang)}, status_code=400) + try: + data = load_data() + success = await perform_delete_user(data, user_id) + if not success: + return JSONResponse({'error': 'User not found'}, status_code=404) + save_data(data) + return {'status': 'success'} + except Exception as e: + logger.exception("Error deleting user") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/users/{user_id}/toggle', tags=["Users"]) +async def api_toggle_user(request: Request, user_id: str, req: ToggleUserRequest): + cur = get_current_user(request) + if not cur or cur['role'] != 'admin': + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + success = await perform_toggle_user(data, user_id, req.enabled) + if not success: + return JSONResponse({'error': 'User not found'}, status_code=404) + save_data(data) + return {'status': 'success', 'enabled': req.enabled} + except Exception as e: + logger.exception("Error toggling user") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/users/{user_id}/connections/add', tags=["Users"]) +async def api_add_user_connection(request: Request, user_id: str, req: AddUserConnectionRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + user = next((u for u in data['users'] if u['id'] == user_id), None) + if not user: + return JSONResponse({'error': 'User not found'}, status_code=404) + if req.server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][req.server_id] + proto_info = server.get('protocols', {}).get(req.protocol, {}) + port = proto_info.get('port', '55424') + ssh = get_ssh(server) + await asyncio.to_thread(ssh.connect) + manager = get_protocol_manager(ssh, req.protocol) + + if req.client_id: + # Use existing client + target_client_id = req.client_id + # Retrieve config for existing client + config = await asyncio.to_thread(manager.get_client_config, req.protocol, req.client_id, server['host'], port) + result = {'client_id': target_client_id, 'config': config} + else: + # Create new client + if protocol_base(req.protocol) == 'telemt': + result = await asyncio.to_thread( + manager.add_client, req.protocol, req.name, server['host'], port, + telemt_quota=req.telemt_quota, + telemt_max_ips=req.telemt_max_ips, + telemt_expiry=req.telemt_expiry, + secret=req.telemt_secret, + user_ad_tag=req.telemt_ad_tag, + max_tcp_conns=req.telemt_max_conns + ) + else: + result = await asyncio.to_thread(manager.add_client, req.protocol, req.name, server['host'], port) + + await asyncio.to_thread(ssh.disconnect) + + if result.get('client_id'): + conn = { + 'id': str(uuid.uuid4()), + 'user_id': user_id, + 'server_id': req.server_id, + 'protocol': req.protocol, + 'client_id': result['client_id'], + 'name': req.name, + 'created_at': datetime.now().isoformat(), + } + data = load_data() + data['user_connections'].append(conn) + save_data(data) + + resp = {'status': 'success'} + if result.get('config'): + resp['config'] = result['config'] + resp['vpn_link'] = generate_vpn_link(result['config']) + return resp + except Exception as e: + logger.exception("Error adding user connection") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.get('/api/users/{user_id}/connections', tags=["Users"]) +async def api_get_user_connections(request: Request, user_id: str): + user = get_current_user(request) + if not user: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + # Users can only see their own, admin/support can see all + if user['role'] == 'user' and user['id'] != user_id: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + conns = [c for c in data.get('user_connections', []) if c['user_id'] == user_id] + for c in conns: + sid = c.get('server_id', 0) + if sid < len(data['servers']): + c['server_name'] = data['servers'][sid].get('name', '') + return {'connections': conns} + + +# ======================== MY CONNECTIONS API (for user role) ======================== + +@app.get('/api/my/connections', tags=["Self-service"]) +async def api_my_connections(request: Request): + user = get_current_user(request) + if not user: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + conns = [c for c in data.get('user_connections', []) if c['user_id'] == user['id']] + for c in conns: + sid = c.get('server_id', 0) + if sid < len(data['servers']): + c['server_name'] = data['servers'][sid].get('name', '') + else: + c['server_name'] = 'Unknown' + return {'connections': conns} + + +@app.post('/api/users/{user_id}/share/setup', tags=["Users"]) +async def api_user_share_setup(user_id: str, req: ShareSetupRequest, request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + user = next((u for u in data['users'] if u['id'] == user_id), None) + if not user: + return JSONResponse({'error': 'User not found'}, status_code=404) + + user['share_enabled'] = req.enabled + if not user.get('share_token'): + user['share_token'] = secrets.token_urlsafe(16) + if req.password: + user['share_password_hash'] = hash_password(req.password) + elif req.password == "": # Clear + user['share_password_hash'] = None + + save_data(data) + return {'status': 'success', 'share_token': user.get('share_token')} + + +@app.get('/share/{token}', response_class=HTMLResponse, tags=["System Templates"]) +async def share_page(token: str, request: Request): + data = load_data() + user = next((u for u in data['users'] if u.get('share_token') == token), None) + if not user or not user.get('share_enabled'): + lang = request.cookies.get('lang', 'ru') + return HTMLResponse(f"

{_t('share_not_found', lang)}

{_t('share_not_found_desc', lang)}

", status_code=404) + + auth_session_key = f'share_auth_{token}' + need_password = bool(user.get('share_password_hash')) and not request.session.get(auth_session_key) + + return tpl(request, 'user_share.html', + share_user=user, + need_password=need_password, + token=token) + + +@app.post('/api/share/{token}/auth', tags=["Sharing"]) +async def api_share_auth(token: str, req: ShareAuthRequest, request: Request): + data = load_data() + user = next((u for u in data['users'] if u.get('share_token') == token), None) + if not user or not user.get('share_enabled'): + return JSONResponse({'error': 'Link expired or disabled'}, status_code=404) + + if verify_password(req.password, user.get('share_password_hash', '')): + request.session[f'share_auth_{token}'] = True + return {'status': 'success'} + else: + lang = request.cookies.get('lang', 'ru') + return JSONResponse({'error': _t('wrong_share_password', lang)}, status_code=401) + + +@app.get('/api/share/{token}/connections', tags=["Sharing"]) +async def api_share_connections(token: str, request: Request): + data = load_data() + user = next((u for u in data['users'] if u.get('share_token') == token), None) + if not user or not user.get('share_enabled'): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + + if user.get('share_password_hash'): + if not request.session.get(f'share_auth_{token}'): + return JSONResponse({'error': 'Unauthorized'}, status_code=401) + + conns = [dict(c) for c in data.get('user_connections', []) if c['user_id'] == user['id']] + for c in conns: + sid = c['server_id'] + if sid < len(data['servers']): + c['server_name'] = data['servers'][sid].get('name') or data['servers'][sid]['host'] + else: + c['server_name'] = 'Unknown' + + return {'connections': conns, 'username': user['username']} + + +@app.post('/api/share/{token}/config/{connection_id}', tags=["Sharing"]) +async def api_share_config(token: str, connection_id: str, request: Request): + data = load_data() + user = next((u for u in data['users'] if u.get('share_token') == token), None) + if not user or not user.get('share_enabled'): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + + if user.get('share_password_hash'): + if not request.session.get(f'share_auth_{token}'): + return JSONResponse({'error': 'Unauthorized'}, status_code=401) + + conn = next((c for c in data.get('user_connections', []) if c['id'] == connection_id and c['user_id'] == user['id']), None) + if not conn: + return JSONResponse({'error': 'Not found'}, status_code=404) + + try: + sid = conn['server_id'] + server = data['servers'][sid] + proto_info = server.get('protocols', {}).get(conn['protocol'], {}) + port = proto_info.get('port', '55424') + ssh = get_ssh(server) + ssh.connect() + # Use appropriate manager for the protocol + manager = get_protocol_manager(ssh, conn['protocol']) + config = _manager_call(manager, 'get_client_config', conn['protocol'], conn['client_id'], server['host'], port) + ssh.disconnect() + vpn_link = generate_vpn_link(config) if config else '' + return {'config': config, 'vpn_link': vpn_link} + except Exception as e: + logger.exception("Error getting shared config") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/my/connections/{connection_id}/config', tags=["Self-service"]) +async def api_my_connection_config(request: Request, connection_id: str): + user = get_current_user(request) + if not user: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + conn = next( + (c for c in data.get('user_connections', []) if c['id'] == connection_id and c['user_id'] == user['id']), + None + ) + if not conn: + return JSONResponse({'error': 'Connection not found'}, status_code=404) + sid = conn['server_id'] + if sid >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][sid] + proto_info = server.get('protocols', {}).get(conn['protocol'], {}) + port = proto_info.get('port', '55424') + ssh = get_ssh(server) + ssh.connect() + # Use appropriate manager for the protocol (fixes Telemt/Xray not working for users) + manager = get_protocol_manager(ssh, conn['protocol']) + config = _manager_call(manager, 'get_client_config', conn['protocol'], conn['client_id'], server['host'], port) + ssh.disconnect() + vpn_link = generate_vpn_link(config) if config else '' + return {'config': config, 'vpn_link': vpn_link} + except Exception as e: + logger.exception("Error getting my connection config") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.get('/settings', tags=["System Templates"]) +async def settings_page(request: Request): + user = _check_admin(request) + if not user: + return RedirectResponse('/login') + data = load_data() + return tpl(request, 'settings.html', settings=data.get('settings', {}), servers=data.get('servers', []), current_version=CURRENT_VERSION) + + +@app.get('/api/settings', tags=["Settings"]) +async def api_get_settings(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + return data.get('settings', {}) + + +@app.get('/api/settings/tunnels/status', tags=["Settings"]) +async def api_tunnels_status(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + return { + 'local_server': get_panel_local_url(request), + 'cloudflare': get_tunnel_status('cloudflare'), + 'ngrok': get_tunnel_status('ngrok'), + 'warp': get_warp_status(), + } + + +@app.post('/api/settings/tunnels/{provider}/install', tags=["Settings"]) +async def api_tunnel_install(request: Request, provider: str): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if provider not in TUNNEL_RUNTIMES: + return JSONResponse({'error': 'Unsupported tunnel provider'}, status_code=400) + try: + await asyncio.to_thread(install_tunnel_binary, provider) + return get_tunnel_status(provider) + except Exception as e: + logger.exception(f"Error installing {provider} tunnel") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/settings/tunnels/{provider}/start', tags=["Settings"]) +async def api_tunnel_start(request: Request, provider: str, payload: TunnelStartRequest = TunnelStartRequest()): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if provider not in TUNNEL_RUNTIMES: + return JSONResponse({'error': 'Unsupported tunnel provider'}, status_code=400) + try: + local_url = get_panel_tunnel_target_url() + await asyncio.to_thread(start_tunnel, provider, local_url, payload.authtoken or '') + status = await wait_for_tunnel_url(provider) + if not status.get('running'): + return JSONResponse({'error': status.get('last_error') or 'Tunnel process stopped'}, status_code=500) + return status + except Exception as e: + logger.exception(f"Error starting {provider} tunnel") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/settings/tunnels/{provider}/stop', tags=["Settings"]) +async def api_tunnel_stop(request: Request, provider: str): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if provider not in TUNNEL_RUNTIMES: + return JSONResponse({'error': 'Unsupported tunnel provider'}, status_code=400) + try: + await asyncio.to_thread(stop_tunnel, provider) + return get_tunnel_status(provider) + except Exception as e: + logger.exception(f"Error stopping {provider} tunnel") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.delete('/api/settings/tunnels/{provider}', tags=["Settings"]) +async def api_tunnel_delete(request: Request, provider: str): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + if provider not in TUNNEL_RUNTIMES: + return JSONResponse({'error': 'Unsupported tunnel provider'}, status_code=400) + try: + await asyncio.to_thread(delete_tunnel_binary, provider) + return get_tunnel_status(provider) + except Exception as e: + logger.exception(f"Error deleting {provider} tunnel") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/settings/warp/connect', tags=["Settings"]) +async def api_warp_connect(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + return await asyncio.to_thread(enable_warp) + except Exception as e: + logger.exception("Error connecting Cloudflare WARP") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.post('/api/settings/warp/disconnect', tags=["Settings"]) +async def api_warp_disconnect(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + return await asyncio.to_thread(disable_warp) + except Exception as e: + logger.exception("Error disconnecting Cloudflare WARP") + return JSONResponse({'error': str(e)}, status_code=500) + + +# @app.post('/api/settings/save') +# async def api_save_settings(request: Request, body: SaveSettingsRequest): +# _check_admin(request) +# data = load_data() +# data['settings'] = body.dict() +# save_data(data) + +# # Trigger sync if enabled +# if body.sync.remnawave_sync_users: +# await sync_users_with_remnawave(data) +# save_data(data) + +# return {'status': 'success'} + +@app.post('/api/settings/save', tags=["Settings"]) +async def save_settings(request: Request, payload: SaveSettingsRequest): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + data['settings']['appearance'] = payload.appearance.dict() + data['settings']['sync'] = payload.sync.dict() + data['settings']['captcha'] = payload.captcha.dict() + data['settings']['telegram'] = payload.telegram.dict() + data['settings']['ssl'] = payload.ssl.dict() + save_data(data) + logger.info("Settings saved (including captcha and telegram)") + + # Handle bot start/stop based on new telegram settings + tg_cfg = payload.telegram + if tg_cfg.enabled and tg_cfg.token: + if not tg_bot.is_running(): + logger.info("Starting Telegram bot (settings save)...") + tg_bot.launch_bot(tg_cfg.token, load_data, generate_vpn_link, save_data) + else: + if tg_bot.is_running(): + logger.info("Stopping Telegram bot (settings save)...") + asyncio.create_task(tg_bot.stop_bot()) + + return {"status": "success", "bot_running": tg_bot.is_running()} + + +@app.post('/api/settings/telegram/toggle', tags=["Settings"]) +async def api_telegram_toggle(request: Request): + """Quick enable/disable of the bot without a full settings save.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + tg_cfg = data.get('settings', {}).get('telegram', {}) + token = tg_cfg.get('token', '') + if not token: + return JSONResponse({'error': 'Telegram token not set in settings'}, status_code=400) + + if tg_bot.is_running(): + await tg_bot.stop_bot() + tg_cfg['enabled'] = False + data['settings']['telegram'] = tg_cfg + save_data(data) + return {'status': 'stopped', 'bot_running': False} + else: + tg_bot.launch_bot(token, load_data, generate_vpn_link, save_data) + tg_cfg['enabled'] = True + data['settings']['telegram'] = tg_cfg + save_data(data) + return {'status': 'started', 'bot_running': True} + +@app.post('/api/settings/sync_now', tags=["Settings"]) +async def api_sync_now(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + count, msg = await sync_users_with_remnawave(data) + return {'status': 'success', 'count': count, 'message': msg} + + +@app.post('/api/settings/sync_delete', tags=["Settings"]) +async def api_sync_delete(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + to_delete_ids = [u['id'] for u in data['users'] if u.get('remnawave_uuid')] + if to_delete_ids: + await perform_mass_operations(delete_uids=to_delete_ids) + return {'status': 'success', 'count': len(to_delete_ids)} + + +@app.get('/api/servers/{server_id}/{protocol}/clients', tags=["Connections"]) +async def api_get_server_clients(request: Request, server_id: int, protocol: str): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + data = load_data() + if server_id >= len(data['servers']): + return JSONResponse({'error': 'Server not found'}, status_code=404) + server = data['servers'][server_id] + ssh = get_ssh(server) + ssh.connect() + manager = get_protocol_manager(ssh, protocol) + clients = manager.get_clients(protocol) + ssh.disconnect() + + # Filter: only show clients that are not assigned to anyone in the panel + assigned_ids = {c['client_id'] for c in data.get('user_connections', []) if c['server_id'] == server_id and c['protocol'] == protocol} + + filtered = [] + for c in clients: + if c['clientId'] not in assigned_ids: + filtered.append({ + 'id': c['clientId'], + 'name': c.get('userData', {}).get('clientName', 'Unnamed') + }) + + return {'clients': filtered} + except Exception as e: + logger.exception("Error getting server clients") + return JSONResponse({'error': str(e)}, status_code=500) + + +@app.get('/api/settings/tokens', tags=["API Tokens"]) +async def api_list_tokens(request: Request): + """List metadata for every API token. The raw token value is never + returned by this endpoint — only its prefix and timestamps are visible + after creation, by design.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + data = load_data() + users_by_id = {u['id']: u for u in data.get('users', [])} + tokens = [] + for t in data.get('api_tokens', []): + owner = users_by_id.get(t.get('user_id')) + tokens.append({ + 'id': t.get('id'), + 'name': t.get('name', ''), + 'token_prefix': t.get('token_prefix', ''), + 'created_at': t.get('created_at'), + 'last_used_at': t.get('last_used_at'), + 'owner': owner['username'] if owner else None, + 'owner_id': t.get('user_id'), + }) + return {'tokens': tokens} + + +@app.post('/api/settings/tokens', tags=["API Tokens"]) +async def api_create_token(request: Request, req: CreateApiTokenRequest): + """Issue a new bearer token. The full token value is returned **once** in + the response and never persisted in plaintext — only its SHA-256 hash is + stored, so a leaked data.json file alone cannot be used to authenticate. + Save the value at creation time; if it's lost the token must be recreated. + """ + cur = _check_admin(request) + if not cur: + return JSONResponse({'error': 'Forbidden'}, status_code=403) + name = (req.name or '').strip() + if not name: + return JSONResponse({'error': 'Token name is required'}, status_code=400) + + raw = _generate_api_token() + token_id = str(uuid.uuid4()) + # Show enough of the token in the UI to identify it later, but not enough + # to reconstruct it: the prefix + first 4 chars of the secret part. + token_prefix = raw[:len(API_TOKEN_PREFIX) + 4] + + entry = { + 'id': token_id, + 'name': name, + 'token_hash': _hash_api_token(raw), + 'token_prefix': token_prefix, + 'user_id': cur['id'], + 'created_at': datetime.now().isoformat(), + 'last_used_at': None, + } + async with DATA_LOCK: + data = load_data() + data.setdefault('api_tokens', []).append(entry) + save_data(data) + + # `token` is returned only here — subsequent reads will not see it. + return { + 'status': 'success', + 'id': token_id, + 'name': name, + 'token': raw, + 'token_prefix': token_prefix, + 'created_at': entry['created_at'], + } + + +@app.delete('/api/settings/tokens/{token_id}', tags=["API Tokens"]) +async def api_revoke_token(request: Request, token_id: str): + """Permanently revoke a token. The associated bearer value can never be + used again, even if the same name is reissued — every token has its own hash.""" + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + async with DATA_LOCK: + data = load_data() + before = len(data.get('api_tokens', [])) + data['api_tokens'] = [t for t in data.get('api_tokens', []) if t.get('id') != token_id] + if len(data['api_tokens']) == before: + return JSONResponse({'error': 'Token not found'}, status_code=404) + save_data(data) + return {'status': 'success'} + + +@app.get('/api/settings/backup/download', tags=["Settings"]) +async def api_backup_download(request: Request): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + payload = await asyncio.to_thread(export_data_dict) + content = json.dumps(payload, indent=2, ensure_ascii=False).encode('utf-8') + return StreamingResponse( + io.BytesIO(content), + media_type='application/json', + headers={'Content-Disposition': 'attachment; filename="data.json"'}, + ) + + +@app.post('/api/settings/backup/restore', tags=["Settings"]) +async def api_backup_restore(request: Request, file: UploadFile = File(...)): + if not _check_admin(request): + return JSONResponse({'error': 'Forbidden'}, status_code=403) + try: + content = await file.read() + if not content: + return JSONResponse({'error': 'Empty file'}, status_code=400) + + try: + backup_data = json.loads(content) + except json.JSONDecodeError: + return JSONResponse({'error': 'Invalid JSON format'}, status_code=400) + + # Basic structure validation + required_keys = ['servers', 'users'] + missing = [k for k in required_keys if k not in backup_data] + if missing: + return JSONResponse({'error': f'Invalid structure. Missing keys: {", ".join(missing)}'}, status_code=400) + + # Ensure types are correct + if not isinstance(backup_data['servers'], list) or not isinstance(backup_data['users'], list): + return JSONResponse({'error': 'Invalid structure: servers and users must be lists'}, status_code=400) + + # Save the new data + async with DATA_LOCK: + save_data(backup_data) + + # In a real app we might want to restart or re-init background tasks + return {'status': 'success'} + except Exception as e: + logger.exception("Error during restore") + return JSONResponse({'error': str(e)}, status_code=500) + + +if __name__ == '__main__': + data = load_data() + ssl_conf = data.get('settings', {}).get('ssl', {}) + + cert_file = ssl_conf.get('cert_path') + key_file = ssl_conf.get('key_path') + + # If text is provided, create temporary files + temp_dir = os.path.join(os.getcwd(), 'ssl_temp') + if ssl_conf.get('enabled'): + if ssl_conf.get('cert_text') or ssl_conf.get('key_text'): + if not os.path.exists(temp_dir): + os.makedirs(temp_dir) + + if ssl_conf.get('cert_text'): + cert_file = os.path.join(temp_dir, 'cert.pem') + with open(cert_file, 'w') as f: + f.write(ssl_conf['cert_text'].strip() + '\n') + + if ssl_conf.get('key_text'): + key_file = os.path.join(temp_dir, 'key.pem') + with open(key_file, 'w') as f: + f.write(ssl_conf['key_text'].strip() + '\n') + + uvicorn_kwargs = { + "app": app, + "host": "0.0.0.0", + "port": ssl_conf.get('panel_port', 5000) + } + + if ssl_conf.get('enabled') and cert_file and key_file: + if os.path.exists(cert_file) and os.path.exists(key_file): + logger.info(f"Starting panel with HTTPS enabled on domain: {ssl_conf.get('domain')} at port {uvicorn_kwargs['port']}") + uvicorn_kwargs["ssl_certfile"] = cert_file + uvicorn_kwargs["ssl_keyfile"] = key_file + else: + logger.error("SSL certificates not found at specified paths. Starting with HTTP.") + + uvicorn.run(**uvicorn_kwargs) diff --git a/db/__init__.py b/db/__init__.py new file mode 100644 index 0000000..d237706 --- /dev/null +++ b/db/__init__.py @@ -0,0 +1,29 @@ +"""Database package for Amnezia Web Panel (PostgreSQL 17).""" + +from .connection import close_pool, get_database_url, init_schema +from .store import ( + clear_tunnel_state, + ensure_db_ready, + export_data_dict, + import_from_json_file, + load_data, + load_tunnel_state, + save_data, + save_tunnel_state, + update_tunnel_state, +) + +__all__ = [ + 'clear_tunnel_state', + 'close_pool', + 'ensure_db_ready', + 'export_data_dict', + 'get_database_url', + 'import_from_json_file', + 'init_schema', + 'load_data', + 'load_tunnel_state', + 'save_data', + 'save_tunnel_state', + 'update_tunnel_state', +] diff --git a/db/connection.py b/db/connection.py new file mode 100644 index 0000000..a53ddc5 --- /dev/null +++ b/db/connection.py @@ -0,0 +1,82 @@ +"""PostgreSQL connection pool for Amnezia Web Panel.""" + +from __future__ import annotations + +import logging +import os +import threading +from pathlib import Path + +from dotenv import load_dotenv + +load_dotenv() + +logger = logging.getLogger(__name__) + +DEFAULT_DATABASE_URL = 'postgresql://amnezia:amnezia@localhost:5432/amnezia_panel' + +_pool = None +_pool_lock = threading.Lock() +_schema_ready = False + + +def get_database_url() -> str: + return os.environ.get('DATABASE_URL', DEFAULT_DATABASE_URL).strip() + + +def get_pool(): + global _pool + if _pool is not None: + return _pool + with _pool_lock: + if _pool is not None: + return _pool + from psycopg.rows import dict_row + from psycopg_pool import ConnectionPool + + url = get_database_url() + logger.info('Connecting to PostgreSQL…') + _pool = ConnectionPool( + conninfo=url, + min_size=1, + max_size=10, + kwargs={ + 'autocommit': False, + 'row_factory': dict_row, + }, + open=True, + ) + return _pool + + +def close_pool(): + global _pool, _schema_ready + with _pool_lock: + if _pool is not None: + _pool.close() + _pool = None + _schema_ready = False + + +def init_schema(): + """Create tables if they do not exist.""" + global _schema_ready + if _schema_ready: + return + schema_path = Path(__file__).with_name('schema.sql') + sql = schema_path.read_text(encoding='utf-8') + pool = get_pool() + with pool.connection() as conn: + with conn.cursor() as cur: + # psycopg3 executes one statement per execute() + for raw in sql.split(';'): + lines = [ + ln for ln in raw.splitlines() + if ln.strip() and not ln.strip().startswith('--') + ] + stmt = '\n'.join(lines).strip() + if stmt: + cur.execute(stmt) + conn.commit() + _schema_ready = True + logger.info('PostgreSQL schema ready') diff --git a/db/migrate_json.py b/db/migrate_json.py new file mode 100644 index 0000000..237e066 --- /dev/null +++ b/db/migrate_json.py @@ -0,0 +1,58 @@ +"""One-shot CLI: import legacy data.json into PostgreSQL. + +Usage: + python -m db.migrate_json [path/to/data.json] +""" + +from __future__ import annotations + +import logging +import os +import sys + +from dotenv import load_dotenv + +load_dotenv() + +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') +logger = logging.getLogger('migrate_json') + + +def main(argv: list[str] | None = None) -> int: + argv = list(argv if argv is not None else sys.argv[1:]) + force = '--force' in argv + paths = [a for a in argv if not a.startswith('-')] + + if getattr(sys, 'frozen', False): + app_path = os.path.dirname(sys.executable) + else: + app_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + data_file = paths[0] if paths else os.path.join(app_path, 'data.json') + + from db.store import import_from_json_file, is_database_empty, load_data + + if not os.path.exists(data_file): + logger.error('File not found: %s', data_file) + return 1 + + if not is_database_empty(): + logger.warning('Database is not empty — import will overwrite panel tables.') + if not force: + logger.error('Re-run with --force to overwrite existing data.') + return 2 + + import_from_json_file(data_file, backup=True) + data = load_data() + logger.info( + 'Done. servers=%s users=%s connections=%s tokens=%s', + len(data['servers']), + len(data['users']), + len(data['user_connections']), + len(data['api_tokens']), + ) + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/db/schema.sql b/db/schema.sql new file mode 100644 index 0000000..d48a1a1 --- /dev/null +++ b/db/schema.sql @@ -0,0 +1,75 @@ +-- Amnezia Web Panel — PostgreSQL 17 schema + +CREATE TABLE IF NOT EXISTS servers ( + position INTEGER PRIMARY KEY, + name TEXT NOT NULL DEFAULT '', + host TEXT NOT NULL DEFAULT '', + ssh_port INTEGER NOT NULL DEFAULT 22, + username TEXT NOT NULL DEFAULT '', + password TEXT, + private_key TEXT, + server_info JSONB NOT NULL DEFAULT '{}'::jsonb, + protocols JSONB NOT NULL DEFAULT '{}'::jsonb +); + +CREATE TABLE IF NOT EXISTS users ( + id UUID PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + password_hash TEXT NOT NULL DEFAULT '', + role TEXT NOT NULL DEFAULT 'user', + enabled BOOLEAN NOT NULL DEFAULT TRUE, + created_at TIMESTAMPTZ, + telegram_id TEXT, + email TEXT, + description TEXT, + traffic_limit BIGINT NOT NULL DEFAULT 0, + traffic_used BIGINT NOT NULL DEFAULT 0, + traffic_total BIGINT NOT NULL DEFAULT 0, + traffic_reset_strategy TEXT NOT NULL DEFAULT 'never', + last_reset_at TIMESTAMPTZ, + expiration_date TIMESTAMPTZ, + remnawave_uuid TEXT, + share_enabled BOOLEAN NOT NULL DEFAULT FALSE, + share_token TEXT, + share_password_hash TEXT +); + +CREATE TABLE IF NOT EXISTS user_connections ( + id UUID PRIMARY KEY, + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + server_id INTEGER NOT NULL DEFAULT 0, + protocol TEXT NOT NULL DEFAULT '', + client_id TEXT NOT NULL DEFAULT '', + name TEXT NOT NULL DEFAULT '', + created_at TIMESTAMPTZ, + last_bytes BIGINT NOT NULL DEFAULT 0 +); + +CREATE INDEX IF NOT EXISTS idx_user_connections_user_id ON user_connections(user_id); +CREATE INDEX IF NOT EXISTS idx_user_connections_server_id ON user_connections(server_id); + +CREATE TABLE IF NOT EXISTS api_tokens ( + id UUID PRIMARY KEY, + name TEXT NOT NULL DEFAULT '', + token_hash TEXT NOT NULL UNIQUE, + token_prefix TEXT NOT NULL DEFAULT '', + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + created_at TIMESTAMPTZ, + last_used_at TIMESTAMPTZ +); + +CREATE INDEX IF NOT EXISTS idx_api_tokens_user_id ON api_tokens(user_id); +CREATE INDEX IF NOT EXISTS idx_api_tokens_hash ON api_tokens(token_hash); + +CREATE TABLE IF NOT EXISTS settings ( + id SMALLINT PRIMARY KEY DEFAULT 1 CHECK (id = 1), + data JSONB NOT NULL DEFAULT '{}'::jsonb +); + +CREATE TABLE IF NOT EXISTS tunnel_state ( + provider TEXT PRIMARY KEY, + data JSONB NOT NULL DEFAULT '{}'::jsonb +); + +INSERT INTO settings (id, data) VALUES (1, '{}'::jsonb) +ON CONFLICT (id) DO NOTHING; diff --git a/db/store.py b/db/store.py new file mode 100644 index 0000000..29a8304 --- /dev/null +++ b/db/store.py @@ -0,0 +1,413 @@ +"""Panel data store backed by PostgreSQL 17. + +Preserves the same dict shape that used to live in data.json so existing +FastAPI handlers keep working without a full rewrite. +""" + +from __future__ import annotations + +import json +import logging +import os +import shutil +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Optional +from uuid import UUID + +from psycopg.types.json import Jsonb + +from .connection import get_pool, init_schema + +logger = logging.getLogger(__name__) + +DEFAULT_SETTINGS = { + 'appearance': { + 'title': 'Amnezia', + 'logo': '❤️', + 'subtitle': 'Web Panel', + }, + 'sync': { + 'remnawave_url': '', + 'remnawave_api_key': '', + 'remnawave_sync': False, + 'remnawave_sync_users': False, + 'remnawave_create_conns': False, + 'remnawave_server_id': 0, + 'remnawave_protocol': 'awg', + }, +} + + +def _parse_ts(value: Any) -> Optional[datetime]: + if value is None or value == '': + return None + if isinstance(value, datetime): + return value + text = str(value).strip() + if not text: + return None + if text.endswith('Z'): + text = text[:-1] + '+00:00' + try: + return datetime.fromisoformat(text) + except ValueError: + return None + + +def _ts_iso(value: Any) -> Optional[str]: + if value is None: + return None + if isinstance(value, datetime): + return value.isoformat() + return str(value) + + +def _as_uuid(value: Any) -> UUID: + return UUID(str(value)) + + +def _merge_settings(raw: Optional[dict]) -> dict: + settings = json.loads(json.dumps(DEFAULT_SETTINGS)) + if not isinstance(raw, dict): + return settings + for section, defaults in DEFAULT_SETTINGS.items(): + incoming = raw.get(section) + if isinstance(incoming, dict) and isinstance(defaults, dict): + merged = dict(defaults) + merged.update(incoming) + settings[section] = merged + elif section in raw: + settings[section] = raw[section] + for key, value in raw.items(): + if key not in settings: + settings[key] = value + return settings + + +def _row_to_server(row) -> dict: + return { + 'name': row['name'] or '', + 'host': row['host'] or '', + 'ssh_port': int(row['ssh_port'] or 22), + 'username': row['username'] or '', + 'password': row['password'], + 'private_key': row['private_key'], + 'server_info': dict(row['server_info'] or {}), + 'protocols': dict(row['protocols'] or {}), + } + + +def _row_to_user(row) -> dict: + return { + 'id': str(row['id']), + 'username': row['username'], + 'password_hash': row['password_hash'] or '', + 'role': row['role'] or 'user', + 'enabled': bool(row['enabled']), + 'created_at': _ts_iso(row['created_at']), + 'telegramId': row['telegram_id'], + 'email': row['email'], + 'description': row['description'], + 'traffic_limit': int(row['traffic_limit'] or 0), + 'traffic_used': int(row['traffic_used'] or 0), + 'traffic_total': int(row['traffic_total'] or 0), + 'traffic_reset_strategy': row['traffic_reset_strategy'] or 'never', + 'last_reset_at': _ts_iso(row['last_reset_at']), + 'expiration_date': _ts_iso(row['expiration_date']), + 'remnawave_uuid': row['remnawave_uuid'], + 'share_enabled': bool(row['share_enabled']), + 'share_token': row['share_token'], + 'share_password_hash': row['share_password_hash'], + } + + +def _row_to_connection(row) -> dict: + return { + 'id': str(row['id']), + 'user_id': str(row['user_id']), + 'server_id': int(row['server_id'] or 0), + 'protocol': row['protocol'] or '', + 'client_id': row['client_id'] or '', + 'name': row['name'] or '', + 'created_at': _ts_iso(row['created_at']), + 'last_bytes': int(row['last_bytes'] or 0), + } + + +def _row_to_token(row) -> dict: + return { + 'id': str(row['id']), + 'name': row['name'] or '', + 'token_hash': row['token_hash'] or '', + 'token_prefix': row['token_prefix'] or '', + 'user_id': str(row['user_id']), + 'created_at': _ts_iso(row['created_at']), + 'last_used_at': _ts_iso(row['last_used_at']), + } + + +def load_data() -> dict: + init_schema() + pool = get_pool() + with pool.connection() as conn: + with conn.cursor() as cur: + cur.execute( + 'SELECT position, name, host, ssh_port, username, password, ' + 'private_key, server_info, protocols ' + 'FROM servers ORDER BY position ASC' + ) + servers = [_row_to_server(r) for r in cur.fetchall()] + + cur.execute( + 'SELECT id, username, password_hash, role, enabled, created_at, ' + 'telegram_id, email, description, traffic_limit, traffic_used, ' + 'traffic_total, traffic_reset_strategy, last_reset_at, ' + 'expiration_date, remnawave_uuid, share_enabled, share_token, ' + 'share_password_hash FROM users ORDER BY created_at NULLS LAST, username' + ) + users = [_row_to_user(r) for r in cur.fetchall()] + + cur.execute( + 'SELECT id, user_id, server_id, protocol, client_id, name, ' + 'created_at, last_bytes FROM user_connections ' + 'ORDER BY created_at NULLS LAST, id' + ) + user_connections = [_row_to_connection(r) for r in cur.fetchall()] + + cur.execute( + 'SELECT id, name, token_hash, token_prefix, user_id, ' + 'created_at, last_used_at FROM api_tokens ' + 'ORDER BY created_at NULLS LAST, id' + ) + api_tokens = [_row_to_token(r) for r in cur.fetchall()] + + cur.execute('SELECT data FROM settings WHERE id = 1') + settings_row = cur.fetchone() + settings = _merge_settings(settings_row['data'] if settings_row else None) + + return { + 'servers': servers, + 'users': users, + 'user_connections': user_connections, + 'api_tokens': api_tokens, + 'settings': settings, + } + + +def save_data(data: dict) -> None: + """Replace panel state in a single transaction (same semantics as rewriting data.json).""" + init_schema() + servers = data.get('servers') or [] + users = data.get('users') or [] + connections = data.get('user_connections') or [] + tokens = data.get('api_tokens') or [] + settings = _merge_settings(data.get('settings')) + + # Keep only connections whose user still exists + user_ids = {str(u.get('id')) for u in users if u.get('id')} + connections = [c for c in connections if str(c.get('user_id')) in user_ids] + tokens = [t for t in tokens if str(t.get('user_id')) in user_ids] + + pool = get_pool() + with pool.connection() as conn: + with conn.cursor() as cur: + # Order matters for FKs: children first on delete, parents first on insert + cur.execute('DELETE FROM api_tokens') + cur.execute('DELETE FROM user_connections') + cur.execute('DELETE FROM users') + cur.execute('DELETE FROM servers') + + for pos, server in enumerate(servers): + cur.execute( + 'INSERT INTO servers (position, name, host, ssh_port, username, ' + 'password, private_key, server_info, protocols) ' + 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)', + ( + pos, + server.get('name') or '', + server.get('host') or '', + int(server.get('ssh_port') or 22), + server.get('username') or '', + server.get('password'), + server.get('private_key'), + Jsonb(server.get('server_info') or {}), + Jsonb(server.get('protocols') or {}), + ), + ) + + for user in users: + cur.execute( + 'INSERT INTO users (' + 'id, username, password_hash, role, enabled, created_at, ' + 'telegram_id, email, description, traffic_limit, traffic_used, ' + 'traffic_total, traffic_reset_strategy, last_reset_at, ' + 'expiration_date, remnawave_uuid, share_enabled, share_token, ' + 'share_password_hash' + ') VALUES (' + '%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s' + ')', + ( + _as_uuid(user['id']), + user.get('username') or '', + user.get('password_hash') or '', + user.get('role') or 'user', + bool(user.get('enabled', True)), + _parse_ts(user.get('created_at')), + str(user['telegramId']) if user.get('telegramId') is not None else None, + user.get('email'), + user.get('description'), + int(user.get('traffic_limit') or 0), + int(user.get('traffic_used') or 0), + int(user.get('traffic_total') or 0), + user.get('traffic_reset_strategy') or 'never', + _parse_ts(user.get('last_reset_at')), + _parse_ts(user.get('expiration_date')), + user.get('remnawave_uuid'), + bool(user.get('share_enabled', False)), + user.get('share_token'), + user.get('share_password_hash'), + ), + ) + + for conn_row in connections: + cur.execute( + 'INSERT INTO user_connections (' + 'id, user_id, server_id, protocol, client_id, name, created_at, last_bytes' + ') VALUES (%s, %s, %s, %s, %s, %s, %s, %s)', + ( + _as_uuid(conn_row['id']), + _as_uuid(conn_row['user_id']), + int(conn_row.get('server_id') or 0), + conn_row.get('protocol') or '', + conn_row.get('client_id') or '', + conn_row.get('name') or '', + _parse_ts(conn_row.get('created_at')), + int(conn_row.get('last_bytes') or 0), + ), + ) + + for token in tokens: + cur.execute( + 'INSERT INTO api_tokens (' + 'id, name, token_hash, token_prefix, user_id, created_at, last_used_at' + ') VALUES (%s, %s, %s, %s, %s, %s, %s)', + ( + _as_uuid(token['id']), + token.get('name') or '', + token.get('token_hash') or '', + token.get('token_prefix') or '', + _as_uuid(token['user_id']), + _parse_ts(token.get('created_at')), + _parse_ts(token.get('last_used_at')), + ), + ) + + cur.execute( + 'INSERT INTO settings (id, data) VALUES (1, %s) ' + 'ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data', + (Jsonb(settings),), + ) + conn.commit() + + +def export_data_dict() -> dict: + """Export current DB state as the legacy data.json document.""" + return load_data() + + +def is_database_empty() -> bool: + init_schema() + pool = get_pool() + with pool.connection() as conn: + with conn.cursor() as cur: + cur.execute('SELECT COUNT(*) AS n FROM users') + users = cur.fetchone()['n'] + cur.execute('SELECT COUNT(*) AS n FROM servers') + servers = cur.fetchone()['n'] + return users == 0 and servers == 0 + + +def import_from_json_file(path: str | os.PathLike, *, backup: bool = True) -> bool: + """Import legacy data.json into Postgres. Returns True if import ran.""" + path = Path(path) + if not path.exists(): + return False + + with path.open('r', encoding='utf-8') as f: + data = json.load(f) + + if not isinstance(data, dict): + raise ValueError(f'Invalid data.json: expected object, got {type(data).__name__}') + + data.setdefault('servers', []) + data.setdefault('users', []) + data.setdefault('user_connections', []) + data.setdefault('api_tokens', []) + data.setdefault('settings', {}) + + save_data(data) + + if backup: + stamp = datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ') + backup_path = path.with_name(f'data.json.migrated.{stamp}.bak') + try: + shutil.copy2(path, backup_path) + logger.info('Backed up legacy data.json to %s', backup_path) + except OSError as e: + logger.warning('Could not backup data.json: %s', e) + + logger.info( + 'Imported data.json → PostgreSQL (%s servers, %s users, %s connections)', + len(data.get('servers', [])), + len(data.get('users', [])), + len(data.get('user_connections', [])), + ) + return True + + +def load_tunnel_state() -> dict: + init_schema() + pool = get_pool() + with pool.connection() as conn: + with conn.cursor() as cur: + cur.execute('SELECT provider, data FROM tunnel_state') + rows = cur.fetchall() + return {row['provider']: dict(row['data'] or {}) for row in rows} + + +def save_tunnel_state(state: dict) -> None: + init_schema() + pool = get_pool() + with pool.connection() as conn: + with conn.cursor() as cur: + cur.execute('DELETE FROM tunnel_state') + for provider, payload in (state or {}).items(): + cur.execute( + 'INSERT INTO tunnel_state (provider, data) VALUES (%s, %s)', + (str(provider), Jsonb(payload or {})), + ) + conn.commit() + + +def update_tunnel_state(provider: str, **updates) -> None: + state = load_tunnel_state() + provider_state = state.get(provider, {}) + provider_state.update(updates) + state[provider] = provider_state + save_tunnel_state(state) + + +def clear_tunnel_state(provider: str) -> None: + state = load_tunnel_state() + if provider in state: + state.pop(provider) + save_tunnel_state(state) + + +def ensure_db_ready(legacy_data_file: Optional[str] = None) -> None: + """Init schema and one-shot import from data.json when DB is empty.""" + init_schema() + if legacy_data_file and is_database_empty() and os.path.exists(legacy_data_file): + logger.info('Empty database — importing legacy %s', legacy_data_file) + import_from_json_file(legacy_data_file) diff --git a/docker-compose.warp.yml b/docker-compose.warp.yml new file mode 100644 index 0000000..62246a8 --- /dev/null +++ b/docker-compose.warp.yml @@ -0,0 +1,28 @@ +# Optional Docker Compose override for running Cloudflare WARP inside the panel container. +# Usage: +# docker compose -f docker-compose.yml -f docker-compose.warp.yml up -d --build +# +# Why the extra privileges: +# WARP needs a TUN device and NET_ADMIN to create/manage its tunnel interface. + +services: + amnezia_panel: + build: + context: . + dockerfile: Dockerfile.warp + image: amnezia-panel:warp-local + + cap_add: + - NET_ADMIN + - SYS_MODULE + devices: + - /dev/net/tun:/dev/net/tun + sysctls: + net.ipv4.conf.all.src_valid_mark: "1" + + volumes: + - amnezia_data:/app/data + - cloudflare_warp:/var/lib/cloudflare-warp + +volumes: + cloudflare_warp: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9eab514 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,50 @@ +version: '3.8' + +services: + db: + image: postgres:17 + container_name: amnezia_panel_db + environment: + POSTGRES_USER: ${POSTGRES_USER:-amnezia} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-amnezia} + POSTGRES_DB: ${POSTGRES_DB:-amnezia_panel} + volumes: + - amnezia_pgdata:/var/lib/postgresql/data + ports: + - "${POSTGRES_PORT:-5432}:5432" + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-amnezia} -d ${POSTGRES_DB:-amnezia_panel}"] + interval: 10s + timeout: 5s + retries: 10 + start_period: 20s + + amnezia_panel: + build: + context: . + dockerfile: Dockerfile + image: amnezia-panel:local + container_name: amnezia_panel + depends_on: + db: + condition: service_healthy + ports: + - "${APP_PORT:-5000}:5000" + environment: + DATABASE_URL: postgresql://${POSTGRES_USER:-amnezia}:${POSTGRES_PASSWORD:-amnezia}@db:5432/${POSTGRES_DB:-amnezia_panel} + SECRET_KEY: ${SECRET_KEY:-} + APP_PORT: ${APP_PORT:-5000} + volumes: + - amnezia_data:/app/data + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "python3 -c \"import socket; s=socket.socket(); s.connect(('localhost', 5000)); s.close()\""] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + +volumes: + amnezia_data: + amnezia_pgdata: diff --git a/docker-entrypoint-warp.sh b/docker-entrypoint-warp.sh new file mode 100644 index 0000000..352d9a1 --- /dev/null +++ b/docker-entrypoint-warp.sh @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu + +# Start Cloudflare WARP daemon inside the container when present. +# The panel controls it through warp-cli from the Settings page. +if command -v warp-svc >/dev/null 2>&1; then + mkdir -p /var/lib/cloudflare-warp + warp-svc >/tmp/warp-svc.log 2>&1 & + echo "$!" >/tmp/warp-svc.pid + + # Best-effort short wait: app can still start even if WARP service needs more time. + i=0 + while [ "$i" -lt 10 ]; do + if warp-cli --accept-tos status >/tmp/warp-cli-status.log 2>&1; then + break + fi + i=$((i + 1)) + sleep 1 + done +fi + +exec "$@" diff --git a/managers/__init__.py b/managers/__init__.py new file mode 100644 index 0000000..73891c1 --- /dev/null +++ b/managers/__init__.py @@ -0,0 +1,7 @@ +"""Protocol/service/SSH managers used by the web panel. + +Modules in this package are imported either directly (`from managers.ssh_manager import SSHManager`) +or lazily by name through `app.get_protocol_manager`. Keeping them in a dedicated package +makes the project root easier to scan and prevents accidental name collisions with the +generic stdlib (e.g. `socks5_manager`, `dns_manager`). +""" diff --git a/managers/adguard_manager.py b/managers/adguard_manager.py new file mode 100644 index 0000000..e5152ef --- /dev/null +++ b/managers/adguard_manager.py @@ -0,0 +1,264 @@ +""" +AdGuard Home Manager — runs adguard/adguardhome in a Docker container, +joined to the same internal `amnezia-dns-net` network the rest of the panel +uses. Two install modes: + + * 'replace' — removes the AmneziaDNS container (if present) and takes + its static IP (172.29.172.254) so VPN clients keep using + the same upstream. + * 'sidebyside' — runs alongside AmneziaDNS on a different static IP + (172.29.172.253). VPN users can hit it on demand + (e.g. via the web admin UI from inside the tunnel). + +Initial setup of AdGuard itself runs through its built-in wizard on the web +UI port — we do not try to script it (the JSON setup API is unstable across +versions and trying to drive it programmatically tends to break on upgrade). +""" + +import logging + +logger = logging.getLogger(__name__) + + +class AdguardManager: + PROTOCOL = 'adguard' + CONTAINER_NAME = 'amnezia-adguard' + IMAGE_NAME = 'adguard/adguardhome:latest' + + NETWORK_NAME = 'amnezia-dns-net' + NETWORK_SUBNET = '172.29.172.0/24' + REPLACE_IP = '172.29.172.254' # AmneziaDNS's slot + SIDEBYSIDE_IP = '172.29.172.253' # parallel to AmneziaDNS + + HOST_DIR = '/opt/amnezia/adguard' + DEFAULT_DNS_PORT = 53 + DEFAULT_WEB_PORT = 3000 + DEFAULT_DOT_PORT = 853 + DEFAULT_DOH_PORT = 443 + + def __init__(self, ssh): + self.ssh = ssh + + # ===================== STATUS ===================== + + def check_docker_installed(self): + out, _, code = self.ssh.run_command("docker --version 2>/dev/null") + if code != 0: + return False + out2, _, _ = self.ssh.run_command( + "systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null" + ) + return 'active' in out2 or 'running' in out2.lower() + + def check_protocol_installed(self, protocol_type='adguard'): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps -a --filter name=^{self.CONTAINER_NAME}$ --format '{{{{.Names}}}}'" + ) + return self.CONTAINER_NAME in out.strip().split('\n') + + def check_container_running(self): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps --filter name=^{self.CONTAINER_NAME}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def _container_ip(self): + out, _, _ = self.ssh.run_sudo_command( + f"docker inspect -f '{{{{range .NetworkSettings.Networks}}}}{{{{.IPAddress}}}} {{{{end}}}}' {self.CONTAINER_NAME} 2>/dev/null" + ) + ip = out.strip().split()[0] if out.strip() else '' + return ip + + def _detect_mode(self): + """Return 'replace' or 'sidebyside' based on the running container's IP. + Returns None if not detectable (container not running).""" + ip = self._container_ip() + if ip == self.REPLACE_IP: + return 'replace' + if ip == self.SIDEBYSIDE_IP: + return 'sidebyside' + return None + + def _container_web_port(self): + """Read the AdGuard HTTP address configured inside the container. + During the first-run wizard AdGuard writes web.listen_addresses to + AdGuardHome.yaml. If the wizard has not been completed yet, the + container is started with --web-addr 0.0.0.0: and this method can + read that port from docker inspect.""" + grep_cmd = "grep -E '^[[:space:]]*-?[[:space:]]*[0-9.]+:[0-9]+$' /opt/adguardhome/conf/AdGuardHome.yaml 2>/dev/null | head -n1" + out, _, _ = self.ssh.run_sudo_command( + f'docker exec {self.CONTAINER_NAME} sh -c "{grep_cmd}"' + ) + line = out.strip().split('\n')[0].strip().lstrip('-').strip() if out.strip() else '' + if ':' in line: + try: + return int(line.rsplit(':', 1)[1]) + except ValueError: + pass + + out, _, _ = self.ssh.run_sudo_command( + f"docker inspect -f '{{{{json .Config.Cmd}}}}' {self.CONTAINER_NAME} 2>/dev/null" + ) + marker = '--web-addr' + if marker in out: + parts = out.replace('[', ' ').replace(']', ' ').replace(',', ' ').replace('\"', ' ').split() + for i, part in enumerate(parts): + if part == marker and i + 1 < len(parts) and ':' in parts[i + 1]: + try: + return int(parts[i + 1].rsplit(':', 1)[1]) + except ValueError: + pass + return None + + def _exposed_web_port(self, container_port=None): + """Reads back the host->container port mapping for the web UI port, + so the panel can show the correct admin URL after install.""" + container_port = int(container_port or self.DEFAULT_WEB_PORT) + for port in (container_port, self.DEFAULT_WEB_PORT): + out, _, _ = self.ssh.run_sudo_command( + f"docker port {self.CONTAINER_NAME} {port}/tcp 2>/dev/null" + ) + if not out.strip(): + continue + # output like "0.0.0.0:3000" — take the last colon-separated chunk + last = out.strip().split('\n')[0].split(':')[-1].strip() + try: + return int(last) + except ValueError: + continue + return None + + def get_server_status(self, protocol_type='adguard'): + exists = self.check_protocol_installed() + running = self.check_container_running() + mode = self._detect_mode() if running else None + ip = self._container_ip() if running else '' + container_web_port = self._container_web_port() if running else None + exposed_port = self._exposed_web_port(container_web_port) if running else None + # When the web UI is not bound to the host the user still needs an + # admin URL (reachable via VPN) — use the actual container web port + # when known, otherwise fall back to AdGuard's default :3000. + return { + 'container_exists': exists, + 'container_running': running, + 'mode': mode, + 'internal_ip': ip, + 'web_port': exposed_port or container_web_port or self.DEFAULT_WEB_PORT, + 'web_exposed': exposed_port is not None, + 'port': self.DEFAULT_DNS_PORT, + 'protocol': protocol_type, + } + + # ===================== INSTALL / REMOVE ===================== + + def _ensure_network(self): + self.ssh.run_sudo_command( + f"docker network ls | grep -q {self.NETWORK_NAME} || " + f"docker network create --subnet {self.NETWORK_SUBNET} {self.NETWORK_NAME}" + ) + + def install_protocol( + self, + protocol_type='adguard', + mode='sidebyside', + web_port=None, + expose_web=False, + dns_port=None, + dot_port=None, + doh_port=None, + expose_dns=False, + expose_dot=False, + expose_doh=False, + ): + if not self.check_docker_installed(): + return {'status': 'error', 'message': 'Docker not installed'} + if mode not in ('replace', 'sidebyside'): + return {'status': 'error', 'message': f"Invalid mode '{mode}'"} + + web_port = int(web_port or self.DEFAULT_WEB_PORT) + dns_port = int(dns_port or self.DEFAULT_DNS_PORT) + dot_port = int(dot_port or self.DEFAULT_DOT_PORT) + doh_port = int(doh_port or self.DEFAULT_DOH_PORT) + + # Persistent volumes — without these the AdGuard setup wizard would have + # to re-run on every container recreate. + self.ssh.run_sudo_command(f"mkdir -p {self.HOST_DIR}/work {self.HOST_DIR}/conf") + + self._ensure_network() + + # Replace mode: detach + remove AmneziaDNS so we can claim its IP. + if mode == 'replace': + self.ssh.run_sudo_command( + f"docker network disconnect {self.NETWORK_NAME} amnezia-dns 2>/dev/null || true" + ) + self.ssh.run_sudo_command("docker stop amnezia-dns 2>/dev/null || true") + self.ssh.run_sudo_command("docker rm -fv amnezia-dns 2>/dev/null || true") + target_ip = self.REPLACE_IP + else: + target_ip = self.SIDEBYSIDE_IP + + if self.check_protocol_installed(): + self.ssh.run_sudo_command(f"docker stop {self.CONTAINER_NAME} 2>/dev/null || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CONTAINER_NAME} 2>/dev/null || true") + + self.ssh.run_sudo_command(f"docker pull {self.IMAGE_NAME}") + + # Build port mapping. By default ports are reachable only inside + # `amnezia-dns-net` (so VPN clients hit them via the static IP). + # Optional `expose_*` flags add host port mappings for direct access. + ports = [] + if expose_web: + ports.append(f"-p {web_port}:{web_port}/tcp") + if expose_dns: + ports.append(f"-p {dns_port}:53/tcp") + ports.append(f"-p {dns_port}:53/udp") + if expose_dot: + ports.append(f"-p {dot_port}:853/tcp") + if expose_doh: + ports.append(f"-p {doh_port}:443/tcp") + ports_str = ' '.join(ports) + + run_cmd = ( + f"docker run -d --name {self.CONTAINER_NAME} --restart always " + f"--network {self.NETWORK_NAME} --ip {target_ip} " + f"-v {self.HOST_DIR}/work:/opt/adguardhome/work " + f"-v {self.HOST_DIR}/conf:/opt/adguardhome/conf " + f"{ports_str} " + f"{self.IMAGE_NAME} --web-addr 0.0.0.0:{web_port}" + ) + _, err, code = self.ssh.run_sudo_command(run_cmd) + if code != 0: + return {'status': 'error', 'message': f'Failed to start container: {err}'} + + # Re-attach known VPN containers to the DNS network so they can reach + # AdGuard at target_ip (mirrors what dns_manager.py does on install). + for c in ('amnezia-awg', 'amnezia-awg2', 'amnezia-awg-legacy', 'amnezia-xray', 'amnezia-wireguard', 'telemt'): + self.ssh.run_sudo_command( + f"docker ps --format '{{{{.Names}}}}' | grep -q '^{c}$' && " + f"docker network connect {self.NETWORK_NAME} {c} 2>/dev/null || true" + ) + + url_host = self.ssh.host if expose_web else target_ip + admin_url = f"http://{url_host}:{web_port}" + return { + 'status': 'success', + 'protocol': 'adguard', + 'mode': mode, + 'internal_ip': target_ip, + 'web_port': web_port, + 'expose_web': bool(expose_web), + 'admin_url': admin_url, + 'message': 'AdGuard Home installed. Complete the setup wizard via the web UI.', + 'log': [ + f"AdGuard Home installed in '{mode}' mode", + f"Internal IP: {target_ip}", + f"Admin UI: {admin_url}" + ("" if expose_web else " (VPN-only — connect via VPN to reach it)"), + 'Open the URL above to run the AdGuard setup wizard.', + ], + } + + def remove_container(self, protocol_type='adguard'): + self.ssh.run_sudo_command(f"docker stop {self.CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"rm -rf {self.HOST_DIR}") + return True diff --git a/managers/awg_manager.py b/managers/awg_manager.py new file mode 100644 index 0000000..f0125f1 --- /dev/null +++ b/managers/awg_manager.py @@ -0,0 +1,1378 @@ +""" +AWG Protocol Manager - handles AmneziaWG and AmneziaWG-Legacy protocol +installation, configuration, and client management on remote servers. + +Replicates the logic from: +- client/server_scripts/awg/ and awg_legacy/ +- client/configurators/wireguard_configurator.cpp +- client/ui/models/clientManagementModel.cpp +""" + +import json +import os +import secrets +import struct +import hashlib +import logging +import re +from base64 import b64encode, b64decode +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cryptography.hazmat.primitives import serialization + +logger = logging.getLogger(__name__) + +# Default AWG parameters (from protocols_defs.h) +AWG_DEFAULTS = { + 'port': '55424', + 'mtu': '1280', + 'subnet_address': '10.8.1.0', + 'subnet_cidr': '24', + 'subnet_ip': '10.8.1.1', + 'dns1': '1.1.1.1', + 'dns2': '1.0.0.1', + # AWG obfuscation parameters + 'junk_packet_count': '3', + 'junk_packet_min_size': '10', + 'junk_packet_max_size': '30', + 'init_packet_junk_size': '15', + 'response_packet_junk_size': '18', + 'cookie_reply_packet_junk_size': '20', + 'transport_packet_junk_size': '23', + 'init_packet_magic_header': '1020325451', + 'response_packet_magic_header': '3288052141', + 'transport_packet_magic_header': '2528465083', + 'underload_packet_magic_header': '1766607858', +} + + +def generate_wg_keypair(): + """Generate a WireGuard X25519 keypair (private, public) as base64 strings.""" + private_key = X25519PrivateKey.generate() + private_bytes = private_key.private_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PrivateFormat.Raw, + encryption_algorithm=serialization.NoEncryption() + ) + public_bytes = private_key.public_key().public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) + return b64encode(private_bytes).decode(), b64encode(public_bytes).decode() + + +def generate_psk(): + """Generate a WireGuard preshared key.""" + return b64encode(secrets.token_bytes(32)).decode() + + +def generate_awg_params(use_ranges=False): + """Generate random AWG obfuscation parameters. + + For AWG 2.0 (use_ranges=True): generates H1-H4 as non-overlapping + ranges (min-max) for dynamic packet signature. Each packet gets a + random value from its range, defeating static DPI signatures. + For legacy AWG (use_ranges=False): generates fixed single H values. + """ + import random + + jc = random.randint(1, 10) + jmin = random.randint(5, 20) + jmax = random.randint(jmin + 10, jmin + 50) + s1 = random.randint(10, 50) + s2 = random.randint(10, 50) + s3 = random.randint(10, 50) + s4 = random.randint(10, 50) + + if use_ranges: + # AWG 2.0: H1-H4 as non-overlapping ranges (min-max) + # Split [1B, 4.29B] into 4 equal zones, pick random sub-range in each + # Guarantees no intersections between H1-H4 per AWG 2.0 spec + def make_ranges(total_min=1000000000, total_max=4294967295): + zone_size = (total_max - total_min) // 4 + result = [] + for i in range(4): + z_start = total_min + i * zone_size + z_end = z_start + zone_size - 1 + padding = min(100000, zone_size // 4) + a = random.randint(z_start + padding, z_end - padding) + b = random.randint(a + 1, z_end) + result.append(f"{a}-{b}") + return result + + h1, h2, h3, h4 = make_ranges() + else: + h1 = str(random.randint(100000000, 4294967295)) + h2 = str(random.randint(100000000, 4294967295)) + h3 = str(random.randint(100000000, 4294967295)) + h4 = str(random.randint(100000000, 4294967295)) + + return { + 'junk_packet_count': str(jc), + 'junk_packet_min_size': str(jmin), + 'junk_packet_max_size': str(jmax), + 'init_packet_junk_size': str(s1), + 'response_packet_junk_size': str(s2), + 'cookie_reply_packet_junk_size': str(s3), + 'transport_packet_junk_size': str(s4), + 'init_packet_magic_header': h1, + 'response_packet_magic_header': h2, + 'underload_packet_magic_header': h3, + 'transport_packet_magic_header': h4, + } + + +class AWGManager: + """Manages AmneziaWG protocol installation and client management.""" + + # Protocol types + AWG = 'awg' # New AWG (awg-go based, uses awg/awg-quick) + AWG_LEGACY = 'awg_legacy' # Legacy AWG (uses wg/wg-quick) + AWG2 = 'awg2' # AmneziaWG 2.0 (separate container amnezia-awg2) + + def __init__(self, ssh_manager): + self.ssh = ssh_manager + + def _base_protocol(self, protocol_type): + """Return base protocol for instance keys like awg__2.""" + return str(protocol_type or self.AWG).split('__', 1)[0] + + def _instance_index(self, protocol_type): + parts = str(protocol_type or '').split('__', 1) + if len(parts) == 2: + try: + return max(1, int(parts[1])) + except ValueError: + return 1 + return 1 + + def _container_name(self, protocol_type): + """Get Docker container name for protocol type/instance. + First instances keep legacy names; additional instances get -N suffix. + """ + base = self._base_protocol(protocol_type) + idx = self._instance_index(protocol_type) + if base == self.AWG_LEGACY: + name = 'amnezia-awg-legacy' + elif base == self.AWG2: + name = 'amnezia-awg2' + else: + name = 'amnezia-awg' + return name if idx <= 1 else f'{name}-{idx}' + + def _config_path(self, protocol_type): + """Get server config path inside container.""" + if self._base_protocol(protocol_type) == self.AWG_LEGACY: + return '/opt/amnezia/awg/wg0.conf' + # Both AWG and AWG2 use awg0.conf + return '/opt/amnezia/awg/awg0.conf' + + def _config_path_candidates(self, protocol_type): + """Return possible config paths, ordered by the expected path first.""" + expected = self._config_path(protocol_type) + fallback = '/opt/amnezia/awg/awg0.conf' if self._base_protocol(protocol_type) == self.AWG_LEGACY else '/opt/amnezia/awg/wg0.conf' + return [expected, fallback] + + def _resolve_config_path(self, protocol_type): + """Resolve the real config path in existing containers. + + AWG Legacy should use wg0.conf, but some older or manually modified + installations may have a different file name. Resolve the existing file + instead of requiring users to create symlinks inside the container. + """ + container_name = self._container_name(protocol_type) + candidates = self._config_path_candidates(protocol_type) + paths = ' '.join(candidates) + script = f'for p in {paths}; do if [ -f "$p" ]; then echo "$p"; exit 0; fi; done; exit 1' + out, _, code = self.ssh.run_sudo_command( + f"docker exec -i {container_name} sh -c '{script}'" + ) + if code == 0 and out.strip(): + return out.strip().splitlines()[0] + return self._config_path(protocol_type) + + def _wg_binary(self, protocol_type): + """Get the wireguard binary name.""" + if self._base_protocol(protocol_type) == self.AWG_LEGACY: + return 'wg' + # AWG and AWG2 both use 'awg' binary + return 'awg' + + + def _quick_binary(self, protocol_type): + """Get the wireguard-quick binary name.""" + if self._base_protocol(protocol_type) == self.AWG_LEGACY: + return 'wg-quick' + # AWG and AWG2 both use 'awg-quick' + return 'awg-quick' + + + def _interface_name(self, protocol_type, config_path=None): + """Get the interface name.""" + if config_path: + return os.path.splitext(os.path.basename(config_path))[0] + if self._base_protocol(protocol_type) == self.AWG_LEGACY: + return 'wg0' + # AWG and AWG2 both use 'awg0' interface + return 'awg0' + + def _docker_image(self, protocol_type): + """Get Docker image for protocol type.""" + if self._base_protocol(protocol_type) in (self.AWG, self.AWG2): + return 'amneziavpn/amneziawg-go:latest' + return 'amneziavpn/amnezia-wg:latest' + + def _clients_table_path(self): + """Path to the clients table file inside container.""" + return '/opt/amnezia/awg/clientsTable' + + def _get_subnet_ip(self, protocol_type): + """Get the subnet IP (gateway) from server config, or fallback to default.""" + try: + config = self._get_server_config(protocol_type) + for line in config.split('\n'): + if line.startswith('Address'): + addr = line.split('=')[1].strip() + ip = addr.split('/')[0] + return ip + except Exception: + pass + return AWG_DEFAULTS['subnet_ip'] + + def _get_subnet_cidr(self, protocol_type): + """Get the subnet CIDR from server config, or fallback to default.""" + try: + config = self._get_server_config(protocol_type) + for line in config.split('\n'): + if line.startswith('Address'): + addr = line.split('=')[1].strip() + if '/' in addr: + return addr.split('/')[1] + except Exception: + pass + return AWG_DEFAULTS['subnet_cidr'] + + def _get_subnet_base(self, protocol_type): + """Get the subnet network address (e.g. 172.16.21.0) from server config.""" + subnet_ip = self._get_subnet_ip(protocol_type) + cidr = int(self._get_subnet_cidr(protocol_type)) + parts = list(map(int, subnet_ip.split('.'))) + mask = (0xFFFFFFFF << (32 - cidr)) & 0xFFFFFFFF + network = struct.pack('!I', (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]) + net_int = struct.unpack('!I', network)[0] & mask + net_parts = [(net_int >> 24) & 0xFF, (net_int >> 16) & 0xFF, (net_int >> 8) & 0xFF, net_int & 0xFF] + return '.'.join(map(str, net_parts)) + + # ===================== INSTALLATION ===================== + + def check_docker_installed(self): + """Check if Docker is installed and running.""" + out, err, code = self.ssh.run_command("docker --version 2>/dev/null") + if code != 0: + return False + out2, _, code2 = self.ssh.run_command("systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null") + return 'active' in out2 or 'running' in out2.lower() + + def install_docker(self): + """Install Docker on the server (mirrors install_docker.sh).""" + script = r""" +if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian"; +elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora"; +elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos"; +elif which zypper > /dev/null 2>&1; then pm=$(which zypper); silent_inst="-nq install"; check_pkgs="-nq refresh"; docker_pkg="docker"; dist="opensuse"; +elif which pacman > /dev/null 2>&1; then pm=$(which pacman); silent_inst="-S --noconfirm --noprogressbar --quiet"; check_pkgs="-Sup"; docker_pkg="docker"; dist="archlinux"; +else echo "Packet manager not found"; exit 1; fi; +echo "Dist: $dist, Packet manager: $pm"; +if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi; +if ! command -v docker > /dev/null 2>&1; then + $pm $check_pkgs; $pm $silent_inst $docker_pkg; + sleep 5; systemctl enable --now docker; sleep 5; +fi; +if [ "$(systemctl is-active docker)" != "active" ]; then + $pm $check_pkgs; $pm $silent_inst $docker_pkg; + sleep 5; systemctl start docker; sleep 5; +fi; +docker --version +""" + out, err, code = self.ssh.run_sudo_script(script, timeout=180) + if code != 0: + raise RuntimeError(f"Failed to install Docker: {err}") + return out + + def check_container_running(self, protocol_type): + """Check if AWG container is running.""" + container_name = self._container_name(protocol_type) + # Use ^name$ for exact match (Docker name filter does substring match) + out, _, code = self.ssh.run_sudo_command( + f"docker ps --filter name=^{container_name}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def check_protocol_installed(self, protocol_type): + """Check if protocol is installed (container exists).""" + container_name = self._container_name(protocol_type) + out, _, code = self.ssh.run_sudo_command( + f"docker ps -a --filter name=^{container_name}$ --format '{{{{.Names}}}}'" + ) + # Exact match check + return container_name in out.strip().split('\n') + + def prepare_host(self, protocol_type): + """Prepare host for container (mirrors prepare_host.sh).""" + container_name = self._container_name(protocol_type) + dockerfile_folder = f"/opt/amnezia/{container_name}" + script = f""" +mkdir -p {dockerfile_folder} +if ! docker network ls | grep -q amnezia-dns-net; then + docker network create --driver bridge --subnet=172.29.172.0/24 --opt com.docker.network.bridge.name=amn0 amnezia-dns-net +fi +""" + out, err, code = self.ssh.run_sudo_script(script) + if code != 0: + logger.warning(f"prepare_host warning: {err}") + return True + + def setup_firewall(self): + """Setup host firewall (mirrors setup_host_firewall.sh).""" + script = """ +sysctl -w net.ipv4.ip_forward=1 +iptables -C INPUT -p icmp --icmp-type echo-request -j DROP 2>/dev/null || iptables -A INPUT -p icmp --icmp-type echo-request -j DROP +iptables -C FORWARD -j DOCKER-USER 2>/dev/null || iptables -A FORWARD -j DOCKER-USER 2>/dev/null +""" + self.ssh.run_sudo_script(script) + return True + + def install_protocol(self, protocol_type, port=None, awg_params=None): + """ + Full installation of AWG or AWG-Legacy protocol. + Steps: install docker -> prepare host -> build container -> + configure container -> run container -> setup firewall + """ + if port is None: + port = AWG_DEFAULTS['port'] + + if awg_params is None: + awg_params = generate_awg_params(use_ranges=(self._base_protocol(protocol_type) in (self.AWG, self.AWG2))) + + container_name = self._container_name(protocol_type) + docker_image = self._docker_image(protocol_type) + config_path = self._config_path(protocol_type) + wg_bin = self._wg_binary(protocol_type) + quick_bin = self._quick_binary(protocol_type) + iface = self._interface_name(protocol_type) + + results = [] + + # Step 1: Install Docker + if not self.check_docker_installed(): + results.append("Installing Docker...") + self.install_docker() + results.append("Docker installed successfully") + else: + results.append("Docker already installed") + + # Step 2: Prepare host + results.append("Preparing host...") + self.prepare_host(protocol_type) + results.append("Host prepared") + + # Step 3: Remove old container if exists + if self.check_protocol_installed(protocol_type): + results.append("Removing old container...") + self.remove_container(protocol_type) + results.append("Old container removed") + + # Step 4: Build/Pull container + results.append("Pulling Docker image...") + dockerfile_folder = f"/opt/amnezia/{container_name}" + + # Create Dockerfile - matches original from client/server_scripts/awg/ + dockerfile_content = ( + f"FROM {docker_image}\n" + f"\n" + f'LABEL maintainer="AmneziaVPN"\n' + f"\n" + f"RUN apk add --no-cache bash curl dumb-init iptables\n" + f"RUN apk --update upgrade --no-cache\n" + f"\n" + f"RUN mkdir -p /opt/amnezia\n" + f'RUN echo "#!/bin/bash" > /opt/amnezia/start.sh && ' + f'echo "tail -f /dev/null" >> /opt/amnezia/start.sh\n' + f"RUN chmod a+x /opt/amnezia/start.sh\n" + f"\n" + f'ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]\n' + ) + self.ssh.run_sudo_command(f"mkdir -p {dockerfile_folder}") + self.ssh.upload_file_sudo(dockerfile_content, f"{dockerfile_folder}/Dockerfile") + + out, err, code = self.ssh.run_sudo_command( + f"docker build --no-cache --pull -t {container_name} {dockerfile_folder}", + timeout=300 + ) + if code != 0: + raise RuntimeError(f"Failed to build container: {err}") + results.append("Docker image built successfully") + + # Step 5: Run container + results.append("Starting container...") + run_cmd = f"""docker run -d \ +--restart always \ +--privileged \ +--cap-add=NET_ADMIN \ +--cap-add=SYS_MODULE \ +-p {port}:{port}/udp \ +-v /lib/modules:/lib/modules \ +--sysctl="net.ipv4.conf.all.src_valid_mark=1" \ +--name {container_name} \ +{container_name}""" + + out, err, code = self.ssh.run_sudo_command(run_cmd) + if code != 0: + raise RuntimeError(f"Failed to run container: {err}") + + # Connect to DNS network + self.ssh.run_sudo_command(f"docker network connect amnezia-dns-net {container_name}") + + # Wait for container to be fully running + results.append("Waiting for container to start...") + self._wait_container_running(container_name) + results.append("Container started") + + # Step 6: Configure container (generate server keys and config) + results.append("Configuring AWG...") + self._configure_container(protocol_type, port, awg_params) + results.append("AWG configured") + + # Step 7: Upload and run start script + results.append("Starting AWG service...") + self._upload_start_script(protocol_type, port, awg_params) + results.append("AWG service started") + + # Step 8: Setup firewall + results.append("Setting up firewall...") + self.setup_firewall() + results.append("Firewall configured") + + return { + 'status': 'success', + 'protocol': protocol_type, + 'port': port, + 'awg_params': awg_params, + 'log': results, + } + + def _wait_container_running(self, container_name, timeout=30): + """Wait for a container to be in 'running' state.""" + import time + last_status = 'unknown' + for i in range(timeout // 2): + out, _, _ = self.ssh.run_sudo_command( + f"docker inspect --format='{{{{.State.Status}}}}' {container_name}" + ) + last_status = out.strip().strip("'\"") + if last_status == 'running': + logger.info(f"Container {container_name} is running") + time.sleep(1) + return True + logger.info(f"Container {container_name} status: {last_status}, waiting...") + time.sleep(2) + + # Container failed to start — fetch logs for diagnostics + logs_out, _, _ = self.ssh.run_sudo_command( + f"docker logs --tail 50 {container_name} 2>&1" + ) + raise RuntimeError( + f"Container {container_name} did not start within {timeout}s " + f"(status: {last_status}). Logs:\n{logs_out}" + ) + + def _configure_container(self, protocol_type, port, awg_params): + """Configure the AWG container (generate keys and server config).""" + container_name = self._container_name(protocol_type) + wg_bin = self._wg_binary(protocol_type) + config_path = self._config_path(protocol_type) + + subnet_ip = self._get_subnet_ip(protocol_type) + subnet_cidr = self._get_subnet_cidr(protocol_type) + + # Build the server config generation script + if self._base_protocol(protocol_type) in (self.AWG, self.AWG2): + config_script = f""" +mkdir -p /opt/amnezia/awg +cd /opt/amnezia/awg +WIREGUARD_SERVER_PRIVATE_KEY=$({wg_bin} genkey) +echo $WIREGUARD_SERVER_PRIVATE_KEY > /opt/amnezia/awg/wireguard_server_private_key.key + +WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | {wg_bin} pubkey) +echo $WIREGUARD_SERVER_PUBLIC_KEY > /opt/amnezia/awg/wireguard_server_public_key.key + +WIREGUARD_PSK=$({wg_bin} genpsk) +echo $WIREGUARD_PSK > /opt/amnezia/awg/wireguard_psk.key + +cat > {config_path} < /opt/amnezia/awg/wireguard_server_private_key.key + +WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | {wg_bin} pubkey) +echo $WIREGUARD_SERVER_PUBLIC_KEY > /opt/amnezia/awg/wireguard_server_public_key.key + +WIREGUARD_PSK=$({wg_bin} genpsk) +echo $WIREGUARD_PSK > /opt/amnezia/awg/wireguard_psk.key + +cat > {config_path} </dev/null + +# start daemons if configured +if [ -f {config_path} ]; then {quick_bin} up {config_path}; fi + +# Allow traffic on the TUN interface +IFACE=$(basename {config_path} .conf) +iptables -A INPUT -i $IFACE -j ACCEPT +iptables -A FORWARD -i $IFACE -j ACCEPT +iptables -A OUTPUT -o $IFACE -j ACCEPT + +# Allow forwarding traffic only from the VPN +iptables -A FORWARD -i $IFACE -o eth0 -s $SUBNET -j ACCEPT +iptables -A FORWARD -i $IFACE -o eth1 -s $SUBNET -j ACCEPT + +iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT + +iptables -t nat -A POSTROUTING -s $SUBNET -o eth0 -j MASQUERADE +iptables -t nat -A POSTROUTING -s $SUBNET -o eth1 -j MASQUERADE + +tail -f /dev/null +""" + + # Upload start script to container via SFTP + docker cp + self.ssh.upload_file(start_script, "/tmp/_amnz_start.sh") + self.ssh.run_sudo_command(f"docker cp /tmp/_amnz_start.sh {container_name}:/opt/amnezia/start.sh") + self.ssh.run_sudo_command(f"docker exec {container_name} chmod +x /opt/amnezia/start.sh") + self.ssh.run_command("rm -f /tmp/_amnz_start.sh") + + # Restart to apply the start script + self.ssh.run_sudo_command(f"docker restart {container_name}") + import time + time.sleep(5) + + def remove_container(self, protocol_type): + """Remove AWG container (mirrors remove_container.sh).""" + container_name = self._container_name(protocol_type) + self.ssh.run_sudo_command(f"docker stop {container_name}") + self.ssh.run_sudo_command(f"docker rm -fv {container_name}") + self.ssh.run_sudo_command(f"docker rmi {container_name}") + return True + + # ===================== CLIENT MANAGEMENT ===================== + + def _get_clients_table(self, protocol_type): + """Get the clients table from the server.""" + container_name = self._container_name(protocol_type) + clients_table_path = self._clients_table_path() + + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {container_name} cat {clients_table_path} 2>/dev/null" + ) + if code != 0 or not out.strip(): + return [] + + try: + data = json.loads(out) + if isinstance(data, list): + return data + elif isinstance(data, dict): + # Migration from old format + result = [] + for client_id, info in data.items(): + result.append({ + 'clientId': client_id, + 'userData': { + 'clientName': info.get('clientName', 'Unknown'), + } + }) + return result + except json.JSONDecodeError: + return [] + + def _save_clients_table(self, protocol_type, clients_table): + """Save the clients table to the server.""" + container_name = self._container_name(protocol_type) + clients_table_path = self._clients_table_path() + content = json.dumps(clients_table, indent=2) + + # Write to /tmp via SFTP, then docker cp into container + self.ssh.upload_file(content, "/tmp/_amnz_clients.json") + self.ssh.run_sudo_command( + f"docker cp /tmp/_amnz_clients.json {container_name}:{clients_table_path}" + ) + self.ssh.run_command("rm -f /tmp/_amnz_clients.json") + + def _get_server_config(self, protocol_type): + """Get the server WireGuard config.""" + container_name = self._container_name(protocol_type) + config_path = self._resolve_config_path(protocol_type) + + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {container_name} cat {config_path}" + ) + if code != 0: + raise RuntimeError(f"Failed to get server config: {err}") + return out + + def save_server_config(self, protocol_type, config_content): + """Save the server WireGuard config and restart container.""" + container_name = self._container_name(protocol_type) + config_path = self._resolve_config_path(protocol_type) + + # Upload new config into container via SFTP + docker cp + self.ssh.upload_file(config_content.replace('\r\n', '\n'), "/tmp/_amnz_edit_config.conf") + self.ssh.run_sudo_command(f"docker cp /tmp/_amnz_edit_config.conf {container_name}:{config_path}") + self.ssh.run_command("rm -f /tmp/_amnz_edit_config.conf") + + # Regenerate start script so iptables rules pick up the (possibly changed) subnet + quick_bin = self._quick_binary(protocol_type) + start_script = f"""#!/bin/bash +echo "Container startup" + +# Read subnet from server config dynamically +SUBNET=$(grep '^Address' {config_path} | head -1 | cut -d'=' -f2 | tr -d ' ') +if [ -z "$SUBNET" ]; then + SUBNET={AWG_DEFAULTS['subnet_ip']}/{AWG_DEFAULTS['subnet_cidr']} +fi + +# kill daemons in case of restart +{quick_bin} down {config_path} 2>/dev/null + +# start daemons if configured +if [ -f {config_path} ]; then {quick_bin} up {config_path}; fi + +# Allow traffic on the TUN interface +IFACE=$(basename {config_path} .conf) +iptables -A INPUT -i $IFACE -j ACCEPT +iptables -A FORWARD -i $IFACE -j ACCEPT +iptables -A OUTPUT -o $IFACE -j ACCEPT + +# Allow forwarding traffic only from the VPN +iptables -A FORWARD -i $IFACE -o eth0 -s $SUBNET -j ACCEPT +iptables -A FORWARD -i $IFACE -o eth1 -s $SUBNET -j ACCEPT + +iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT + +iptables -t nat -A POSTROUTING -s $SUBNET -o eth0 -j MASQUERADE +iptables -t nat -A POSTROUTING -s $SUBNET -o eth1 -j MASQUERADE + +tail -f /dev/null +""" + self.ssh.upload_file(start_script, "/tmp/_amnz_start.sh") + self.ssh.run_sudo_command(f"docker cp /tmp/_amnz_start.sh {container_name}:/opt/amnezia/start.sh") + self.ssh.run_sudo_command(f"docker exec {container_name} chmod +x /opt/amnezia/start.sh") + self.ssh.run_command("rm -f /tmp/_amnz_start.sh") + + # Restart container to apply all changes (including port and interface changes) + self.ssh.run_sudo_command(f"docker restart {container_name}") + + def _get_server_public_key(self, protocol_type): + """Get server public key.""" + container_name = self._container_name(protocol_type) + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {container_name} cat /opt/amnezia/awg/wireguard_server_public_key.key" + ) + if code != 0: + raise RuntimeError(f"Failed to get server public key: {err}") + return out.strip() + + def _get_server_psk(self, protocol_type): + """Get server preshared key.""" + container_name = self._container_name(protocol_type) + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {container_name} cat /opt/amnezia/awg/wireguard_psk.key" + ) + if code != 0: + raise RuntimeError(f"Failed to get PSK: {err}") + return out.strip() + + def _get_awg_params_from_config(self, protocol_type): + """Extract AWG obfuscation params from server config.""" + config = self._get_server_config(protocol_type) + params = {} + # Mapping from server config keys to our param dictionary keys + param_map = { + 'ListenPort': 'port', + 'Jc': 'junk_packet_count', + 'Jmin': 'junk_packet_min_size', + 'Jmax': 'junk_packet_max_size', + 'S1': 'init_packet_junk_size', + 'S2': 'response_packet_junk_size', + 'S3': 'cookie_reply_packet_junk_size', + 'S4': 'transport_packet_junk_size', + 'H1': 'init_packet_magic_header', + 'H2': 'response_packet_magic_header', + 'H3': 'underload_packet_magic_header', + 'H4': 'transport_packet_magic_header', + 'I1': 'i1', + 'I2': 'i2', + 'I3': 'i3', + 'I4': 'i4', + 'I5': 'i5', + 'CPS': 'cps', + } + + for line in config.split('\n'): + line = line.strip() + # Support both 'key=value' and 'key = value' + if '=' in line and not line.startswith('#') and not line.startswith('['): + parts = line.split('=', 1) + key = parts[0].strip() + val = parts[1].strip() + if key in param_map: + params[param_map[key]] = val + + return params + + def _get_used_ips(self, protocol_type): + """Get list of IPs already assigned in the config.""" + config = self._get_server_config(protocol_type) + ips = [] + for line in config.split('\n'): + line = line.strip() + if line.startswith('AllowedIPs'): + match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line) + if match: + ips.append(match.group(1)) + elif line.startswith('Address'): + match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line) + if match: + ips.append(match.group(1)) + return ips + + def _get_next_ip(self, protocol_type): + """Calculate the next available IP for a new client.""" + used_ips = self._get_used_ips(protocol_type) + if not used_ips: + base = self._get_subnet_base(protocol_type) + parts = base.split('.') + parts[3] = '2' + return '.'.join(parts) + + # Get the last used IP and increment + last_ip = used_ips[-1] + parts = last_ip.split('.') + last_octet = int(parts[3]) + + if last_octet == 254: + next_octet = last_octet + 3 + elif last_octet == 255: + next_octet = last_octet + 2 + else: + next_octet = last_octet + 1 + + parts[3] = str(next_octet) + return '.'.join(parts) + + def _extract_ipv4(self, value): + """Extract the first IPv4 address from AllowedIPs/clientIp-like values.""" + if not value: + return '' + match = re.search(r'(\d+\.\d+\.\d+\.\d+)', str(value)) + return match.group(1) if match else '' + + def _client_ip_from_userdata(self, user_data): + """Return a valid client IP from stored userData, tolerating native Amnezia records.""" + return ( + self._extract_ipv4(user_data.get('clientIp')) + or self._extract_ipv4(user_data.get('allowedIps')) + or self._extract_ipv4(user_data.get('allowed_ip')) + ) + + def _parse_peers_from_config(self, protocol_type): + """Parse [Peer] sections from WireGuard server config and return dict of pubkey -> {allowedIps}.""" + try: + config = self._get_server_config(protocol_type) + except Exception: + return {} + + peers = {} + current_key = None + for line in config.split('\n'): + line = line.strip() + if line == '[Peer]': + current_key = None + elif current_key is None and line.startswith('PublicKey'): + current_key = line.split('=', 1)[1].strip() + peers[current_key] = {'allowedIps': ''} + elif current_key and line.startswith('AllowedIPs'): + peers[current_key]['allowedIps'] = line.split('=', 1)[1].strip() + return peers + + def get_clients(self, protocol_type): + """Get list of all clients.""" + clients_table = self._get_clients_table(protocol_type) + + # Also try to get live data from wg show + try: + wg_show_data = self._wg_show(protocol_type) + except Exception: + wg_show_data = {} + + # Enrich clients table with wg show data + known_ids = set() + for client in clients_table: + client_id = client.get('clientId', '') + known_ids.add(client_id) + if client_id in wg_show_data: + show_data = wg_show_data[client_id] + user_data = client.get('userData', {}) + user_data['latestHandshake'] = show_data.get('latestHandshake', '') + user_data['dataReceived'] = show_data.get('dataReceived', '') + user_data['dataSent'] = show_data.get('dataSent', '') + user_data['dataReceivedBytes'] = show_data.get('dataReceivedBytes', 0) + user_data['dataSentBytes'] = show_data.get('dataSentBytes', 0) + user_data['allowedIps'] = show_data.get('allowedIps', '') + client['userData'] = user_data + + # Pick up peers from conf that are NOT in clientsTable (created via native Amnezia app) + try: + conf_peers = self._parse_peers_from_config(protocol_type) + for pub_key, peer_info in conf_peers.items(): + if pub_key in known_ids: + continue # already in table + show_data = wg_show_data.get(pub_key, {}) + # Derive display name from AllowedIPs (e.g. 10.8.1.5/32 -> peer-10.8.1.5) + allowed_ip = peer_info.get('allowedIps', '') or show_data.get('allowedIps', '') + ip_part = '' + if allowed_ip: + import re as _re + m = _re.search(r'(\d+\.\d+\.\d+\.\d+)', allowed_ip) + if m: + ip_part = m.group(1) + display_name = f'External ({ip_part})' if ip_part else 'External (native app)' + clients_table.append({ + 'clientId': pub_key, + 'userData': { + 'clientName': display_name, + 'clientPrivateKey': '', # not available + 'externalClient': True, + 'clientIp': ip_part, + 'latestHandshake': show_data.get('latestHandshake', ''), + 'dataReceived': show_data.get('dataReceived', ''), + 'dataSent': show_data.get('dataSent', ''), + 'dataReceivedBytes': show_data.get('dataReceivedBytes', 0), + 'dataSentBytes': show_data.get('dataSentBytes', 0), + 'allowedIps': allowed_ip, + } + }) + except Exception as e: + logger.warning(f'get_clients: failed to parse conf peers: {e}') + + return clients_table + + def _parse_bytes(self, size_str): + """Parse human readable size string like '1.50 MiB' into bytes.""" + try: + parts = size_str.strip().split() + if len(parts) != 2: return 0 + val, unit = float(parts[0]), parts[1] + units = {'B': 1, 'KiB': 1024, 'MiB': 1024**2, 'GiB': 1024**3, 'TiB': 1024**4} + return int(val * units.get(unit, 1)) + except Exception: + return 0 + + def _wg_show(self, protocol_type): + """Run 'wg show all' and parse output.""" + container_name = self._container_name(protocol_type) + wg_bin = self._wg_binary(protocol_type) + + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {container_name} bash -c '{wg_bin} show all'" + ) + if code != 0 or not out.strip(): + return {} + + result = {} + current_peer = None + + for line in out.split('\n'): + line = line.strip() + if line.startswith('peer:'): + current_peer = line.split(':', 1)[1].strip() + result[current_peer] = {} + elif current_peer and ':' in line: + key, value = line.split(':', 1) + key = key.strip() + value = value.strip() + if key == 'latest handshake': + result[current_peer]['latestHandshake'] = value + elif key == 'transfer': + parts = value.split(',') + if len(parts) == 2: + received = parts[0].strip().replace(' received', '') + sent = parts[1].strip().replace(' sent', '') + result[current_peer]['dataReceived'] = received + result[current_peer]['dataSent'] = sent + result[current_peer]['dataReceivedBytes'] = self._parse_bytes(received) + result[current_peer]['dataSentBytes'] = self._parse_bytes(sent) + elif key == 'allowed ips': + result[current_peer]['allowedIps'] = value + + return result + + def add_client(self, protocol_type, client_name, server_host, port): + """ + Add a new client/peer to the AWG config. + Returns the client config as a string for the .conf file. + """ + container_name = self._container_name(protocol_type) + wg_bin = self._wg_binary(protocol_type) + config_path = self._resolve_config_path(protocol_type) + iface = self._interface_name(protocol_type, config_path) + + # Generate client keys + client_priv_key, client_pub_key = generate_wg_keypair() + + # Get server info + server_pub_key = self._get_server_public_key(protocol_type) + psk = self._get_server_psk(protocol_type) + + # Get next available IP + client_ip = self._get_next_ip(protocol_type) + + # Get AWG params from server config + awg_params = self._get_awg_params_from_config(protocol_type) + + # Add peer to server config + peer_section = f""" +[Peer] +PublicKey = {client_pub_key} +PresharedKey = {psk} +AllowedIPs = {client_ip}/32 + +""" + # Append peer to server config + escaped_peer = peer_section.replace("'", "'\\''") + self.ssh.run_sudo_command( + f"docker exec -i {container_name} bash -c 'echo \"{escaped_peer}\" >> {config_path}'" + ) + + # Sync config without restart + self.ssh.run_sudo_command( + f"docker exec -i {container_name} bash -c '{wg_bin} syncconf {iface} <({wg_bin}-quick strip {config_path})'" + ) + + # Update clients table — store keys for config reconstruction + clients_table = self._get_clients_table(protocol_type) + new_client = { + 'clientId': client_pub_key, + 'userData': { + 'clientName': client_name, + 'creationDate': __import__('datetime').datetime.now().isoformat(), + 'clientPrivateKey': client_priv_key, + 'clientIp': client_ip, + 'psk': psk, + 'enabled': True, + } + } + clients_table.append(new_client) + self._save_clients_table(protocol_type, clients_table) + + # Build client config + awg_params = self._get_awg_params_from_config(protocol_type) + if awg_params.get('port'): + port = awg_params['port'] + + dns1 = AWG_DEFAULTS['dns1'] + dns2 = AWG_DEFAULTS['dns2'] + + # Check if AmneziaDNS is installed + out, _, _ = self.ssh.run_sudo_command("docker ps -a --filter name=^amnezia-dns$ --format '{{.Names}}'") + if 'amnezia-dns' in out: + dns1 = '172.29.172.254' + + mtu = AWG_DEFAULTS['mtu'] + + # Standard fields + config_lines = [ + f"Address = {client_ip}/32", + f"DNS = {dns1}, {dns2}", + f"PrivateKey = {client_priv_key}", + f"MTU = {mtu}" + ] + + # Conditional obfuscation fields + mapping = [ + ('junk_packet_count', 'Jc'), + ('junk_packet_min_size', 'Jmin'), + ('junk_packet_max_size', 'Jmax'), + ('init_packet_junk_size', 'S1'), + ('response_packet_junk_size', 'S2'), + ('cookie_reply_packet_junk_size', 'S3'), + ('transport_packet_junk_size', 'S4'), + ('init_packet_magic_header', 'H1'), + ('response_packet_magic_header', 'H2'), + ('underload_packet_magic_header', 'H3'), + ('transport_packet_magic_header', 'H4'), + ('i1', 'I1'), + ('i2', 'I2'), + ('i3', 'I3'), + ('i4', 'I4'), + ('i5', 'I5'), + ('cps', 'CPS') + ] + + for param_key, config_key in mapping: + val = awg_params.get(param_key) + if val: + # Basic compatibility filtering + if self._base_protocol(protocol_type) == self.AWG_LEGACY and config_key in ('S3', 'S4', 'I1', 'I2', 'I3', 'I4', 'I5', 'CPS'): + continue + config_lines.append(f"{config_key} = {val}") + + client_config = "[Interface]\n" + "\n".join(config_lines) + f""" + +[Peer] +PublicKey = {server_pub_key} +PresharedKey = {psk} +AllowedIPs = 0.0.0.0/0, ::/0 +Endpoint = {server_host}:{port} +PersistentKeepalive = 25 +""" + + return { + 'client_name': client_name, + 'client_id': client_pub_key, + 'client_ip': client_ip, + 'config': client_config, + } + + def get_client_config(self, protocol_type, client_id, server_host, port): + """Reconstruct client config from stored data.""" + clients_table = self._get_clients_table(protocol_type) + client = None + for c in clients_table: + if c.get('clientId') == client_id: + client = c + break + + if not client: + raise RuntimeError(f"Client {client_id} not found") + + ud = client.get('userData', {}) + client_priv_key = ud.get('clientPrivateKey', '') + client_ip = ud.get('clientIp', '') + psk = ud.get('psk', '') + + if not client_priv_key: + raise RuntimeError("Client private key not stored. Config cannot be reconstructed.") + + server_pub_key = self._get_server_public_key(protocol_type) + if not psk: + psk = self._get_server_psk(protocol_type) + + awg_params = self._get_awg_params_from_config(protocol_type) + if awg_params.get('port'): + port = awg_params['port'] + + dns1 = AWG_DEFAULTS['dns1'] + dns2 = AWG_DEFAULTS['dns2'] + + # Check if AmneziaDNS is installed + out, _, _ = self.ssh.run_sudo_command("docker ps -a --filter name=^amnezia-dns$ --format '{{.Names}}'") + if 'amnezia-dns' in out: + dns1 = '172.29.172.254' + + mtu = AWG_DEFAULTS['mtu'] + + # Standard fields + config_lines = [ + f"Address = {client_ip}/32", + f"DNS = {dns1}, {dns2}", + f"PrivateKey = {client_priv_key}", + f"MTU = {mtu}" + ] + + # Conditional obfuscation fields + mapping = [ + ('junk_packet_count', 'Jc'), + ('junk_packet_min_size', 'Jmin'), + ('junk_packet_max_size', 'Jmax'), + ('init_packet_junk_size', 'S1'), + ('response_packet_junk_size', 'S2'), + ('cookie_reply_packet_junk_size', 'S3'), + ('transport_packet_junk_size', 'S4'), + ('init_packet_magic_header', 'H1'), + ('response_packet_magic_header', 'H2'), + ('underload_packet_magic_header', 'H3'), + ('transport_packet_magic_header', 'H4'), + ('i1', 'I1'), + ('i2', 'I2'), + ('i3', 'I3'), + ('i4', 'I4'), + ('i5', 'I5'), + ('cps', 'CPS') + ] + + for param_key, config_key in mapping: + val = awg_params.get(param_key) + if val: + # Basic compatibility filtering + if self._base_protocol(protocol_type) == self.AWG_LEGACY and config_key in ('S3', 'S4', 'I1', 'I2', 'I3', 'I4', 'I5', 'CPS'): + continue + config_lines.append(f"{config_key} = {val}") + + config = "[Interface]\n" + "\n".join(config_lines) + f""" + +[Peer] +PublicKey = {server_pub_key} +PresharedKey = {psk} +AllowedIPs = 0.0.0.0/0, ::/0 +Endpoint = {server_host}:{port} +PersistentKeepalive = 25 +""" + return config + + def toggle_client(self, protocol_type, client_id, enable): + """Enable or disable a client by adding/removing their [Peer] from server config.""" + container_name = self._container_name(protocol_type) + wg_bin = self._wg_binary(protocol_type) + config_path = self._resolve_config_path(protocol_type) + iface = self._interface_name(protocol_type, config_path) + clients_table = self._get_clients_table(protocol_type) + table_changed = False + + if enable: + # Re-add peer to server config. Native Amnezia clients may not have + # userData.clientIp in clientsTable, so recover it from allowedIps + # before falling back to a new free address. + client = None + for c in clients_table: + if c.get('clientId') == client_id: + client = c + break + if not client: + raise RuntimeError(f"Client {client_id} not found") + + ud = client.setdefault('userData', {}) + psk = ud.get('psk', '') + client_ip = self._client_ip_from_userdata(ud) + if not client_ip: + client_ip = self._get_next_ip(protocol_type) + logger.warning( + "Client %s had no saved AWG IP/AllowedIPs; assigning next free IP %s", + client_id, + client_ip, + ) + + ud['clientIp'] = client_ip + ud['allowedIps'] = f'{client_ip}/32' + table_changed = True + + if not psk: + psk = self._get_server_psk(protocol_type) + ud['psk'] = psk + table_changed = True + + peer_section = f""" +[Peer] +PublicKey = {client_id} +PresharedKey = {psk} +AllowedIPs = {client_ip}/32 + +""" + escaped_peer = peer_section.replace("'", "'\\''") + self.ssh.run_sudo_command( + f"docker exec -i {container_name} bash -c 'echo \"{escaped_peer}\" >> {config_path}'" + ) + else: + # Remove peer from server config, but first persist its current + # AllowedIPs so native/external clients can be enabled later. + config = self._get_server_config(protocol_type) + conf_peers = self._parse_peers_from_config(protocol_type) + allowed_ips = conf_peers.get(client_id, {}).get('allowedIps', '') + client_ip = self._extract_ipv4(allowed_ips) + client = None + for c in clients_table: + if c.get('clientId') == client_id: + client = c + break + if client is None: + client = { + 'clientId': client_id, + 'userData': { + 'clientName': f'External ({client_ip})' if client_ip else 'External (native app)', + 'externalClient': True, + } + } + clients_table.append(client) + table_changed = True + + ud = client.setdefault('userData', {}) + if client_ip: + ud['clientIp'] = client_ip + ud['allowedIps'] = allowed_ips or f'{client_ip}/32' + table_changed = True + if not ud.get('psk'): + ud['psk'] = self._get_server_psk(protocol_type) + table_changed = True + + sections = config.split('[') + new_sections = [] + for section in sections: + if not section.strip(): + continue + if client_id in section: + continue + new_sections.append(section) + + new_config = '[' + '['.join(new_sections) + self.ssh.upload_file(new_config, "/tmp/_amnz_config.conf") + self.ssh.run_sudo_command( + f"docker cp /tmp/_amnz_config.conf {container_name}:{config_path}" + ) + self.ssh.run_command("rm -f /tmp/_amnz_config.conf") + + # Sync config + self.ssh.run_sudo_command( + f"docker exec -i {container_name} bash -c '{wg_bin} syncconf {iface} <({wg_bin}-quick strip {config_path})'" + ) + + # Update enabled status in clients table + for c in clients_table: + if c.get('clientId') == client_id: + c.setdefault('userData', {})['enabled'] = enable + table_changed = True + break + if table_changed: + self._save_clients_table(protocol_type, clients_table) + + def remove_client(self, protocol_type, client_id): + """Remove a client from AWG config (mirrors revokeWireGuard).""" + container_name = self._container_name(protocol_type) + wg_bin = self._wg_binary(protocol_type) + config_path = self._resolve_config_path(protocol_type) + iface = self._interface_name(protocol_type, config_path) + + # Get current config + config = self._get_server_config(protocol_type) + + # Split by [Peer] sections and remove the matching one + sections = config.split('[') + new_sections = [] + for section in sections: + if not section.strip(): + continue + if client_id in section: + continue + new_sections.append(section) + + new_config = '[' + '['.join(new_sections) + + # Upload new config into container via SFTP + docker cp + self.ssh.upload_file(new_config, "/tmp/_amnz_config.conf") + self.ssh.run_sudo_command( + f"docker cp /tmp/_amnz_config.conf {container_name}:{config_path}" + ) + self.ssh.run_command("rm -f /tmp/_amnz_config.conf") + + # Sync config + self.ssh.run_sudo_command( + f"docker exec -i {container_name} bash -c '{wg_bin} syncconf {iface} <({wg_bin}-quick strip {config_path})'" + ) + + # Update clients table + clients_table = self._get_clients_table(protocol_type) + clients_table = [c for c in clients_table if c.get('clientId') != client_id] + self._save_clients_table(protocol_type, clients_table) + + return True + + def get_server_status(self, protocol_type): + """Get detailed status of the AWG server.""" + container_name = self._container_name(protocol_type) + + info = { + 'container_exists': self.check_protocol_installed(protocol_type), + 'container_running': False, + 'protocol': protocol_type, + } + + if info['container_exists']: + info['container_running'] = self.check_container_running(protocol_type) + + if info['container_running']: + try: + config = self._get_server_config(protocol_type) + # Extract port + for line in config.split('\n'): + if 'ListenPort' in line: + info['port'] = line.split('=')[1].strip() + break + info['awg_params'] = self._get_awg_params_from_config(protocol_type) + info['clients_count'] = len(self._get_clients_table(protocol_type)) + except Exception as e: + info['error'] = str(e) + + return info \ No newline at end of file diff --git a/managers/backup_manager.py b/managers/backup_manager.py new file mode 100644 index 0000000..35305ed --- /dev/null +++ b/managers/backup_manager.py @@ -0,0 +1,170 @@ +import json +import re +import shlex + + +class BackupManager: + """Create/list downloadable protocol backups on the remote server. + + Backups are intentionally allowlisted per protocol and include only files + needed to recreate protocol state: host config directories, matching + container config directories when present, and docker inspect metadata. + """ + + BACKUP_ROOT = '/opt/amnezia/backups' + + def __init__(self, ssh_manager): + self.ssh = ssh_manager + + @staticmethod + def proto_base(protocol): + return str(protocol or '').split('__', 1)[0] + + @staticmethod + def proto_instance(protocol): + match = re.search(r'__(\d+)$', str(protocol or '')) + return int(match.group(1)) if match else 1 + + @staticmethod + def safe_protocol(protocol): + safe = re.sub(r'[^a-zA-Z0-9_.-]+', '_', str(protocol or '').replace('__', '-')) + return safe.strip('._-') or 'protocol' + + @staticmethod + def safe_filename(filename): + name = str(filename or '') + if not re.fullmatch(r'[A-Za-z0-9_.-]+\.tar\.gz', name): + return None + return name + + def _paths_for(self, protocol, container_name): + base = self.proto_base(protocol) + idx = self.proto_instance(protocol) + paths = { + 'host': [], + 'container': [], + } + + def inst_path(path, suffix_fmt='-{idx}'): + return path if idx <= 1 else f"{path}{suffix_fmt.format(idx=idx)}" + + if base in ('awg', 'awg2', 'awg_legacy'): + paths['host'] = ['/opt/amnezia/awg', f'/opt/amnezia/{container_name}'] + paths['container'] = ['/opt/amnezia/awg', '/opt/amnezia/start.sh'] + elif base == 'wireguard': + paths['host'] = ['/opt/amnezia/wireguard', f'/opt/amnezia/{container_name}'] + paths['container'] = ['/opt/amnezia/wireguard', '/opt/amnezia/start.sh'] + elif base == 'xray': + config_dir = inst_path('/opt/amnezia/xray') + paths['host'] = [config_dir, f'/opt/amnezia/{container_name}'] + paths['container'] = [config_dir] + elif base == 'telemt': + remote_dir = inst_path('/opt/amnezia/telemt') + paths['host'] = [remote_dir] + paths['container'] = [remote_dir] + elif base == 'dns': + paths['host'] = ['/opt/amnezia/dns'] + paths['container'] = ['/opt/amnezia/dns'] + elif base == 'adguard': + paths['host'] = ['/opt/amnezia/adguard'] + paths['container'] = ['/opt/adguardhome/conf', '/opt/adguardhome/work'] + elif base == 'socks5': + config_dir = inst_path('/opt/amnezia/socks5proxy') + paths['host'] = [config_dir] + paths['container'] = ['/etc/3proxy'] + elif base == 'nginx': + paths['host'] = ['/opt/amnezia/nginx'] + paths['container'] = ['/etc/nginx/conf.d', '/usr/share/nginx/html'] + else: + paths['host'] = [f'/opt/amnezia/{base}'] + paths['container'] = [f'/opt/amnezia/{base}'] + + return paths + + def list_backups(self, protocol): + safe_proto = self.safe_protocol(protocol) + backup_dir = f'{self.BACKUP_ROOT}/{safe_proto}' + cmd = ( + f"mkdir -p {shlex.quote(backup_dir)} && " + f"find {shlex.quote(backup_dir)} -maxdepth 1 -type f -name '*.tar.gz' " + "-printf '%f|%s|%T@\\n' 2>/dev/null | sort -t '|' -k3,3nr" + ) + out, err, code = self.ssh.run_sudo_command(cmd) + if code != 0: + return {'status': 'error', 'message': err or out or 'Failed to list backups'} + backups = [] + for line in (out or '').splitlines(): + parts = line.split('|') + if len(parts) != 3: + continue + name, size, mtime = parts + backups.append({ + 'name': name, + 'size': int(float(size or 0)), + 'mtime': float(mtime or 0), + }) + return {'status': 'success', 'protocol': protocol, 'backups': backups} + + def create_backup(self, protocol, container_name): + safe_proto = self.safe_protocol(protocol) + backup_dir = f'{self.BACKUP_ROOT}/{safe_proto}' + paths = self._paths_for(protocol, container_name) + host_paths = ' '.join(shlex.quote(p) for p in paths['host']) + container_paths = ' '.join(shlex.quote(p) for p in paths['container']) + protocol_q = shlex.quote(str(protocol)) + safe_proto_q = shlex.quote(safe_proto) + container_q = shlex.quote(str(container_name or '')) + backup_dir_q = shlex.quote(backup_dir) + + script = f""" +set -eu +umask 077 +protocol={protocol_q} +safe_proto={safe_proto_q} +container={container_q} +backup_dir={backup_dir_q} +timestamp=$(date -u +%Y%m%dT%H%M%SZ) +work_dir=$(mktemp -d /tmp/amnezia-backup-${{safe_proto}}.XXXXXX) +cleanup() {{ rm -rf "$work_dir"; }} +trap cleanup EXIT +mkdir -p "$backup_dir" "$work_dir/host" "$work_dir/container" "$work_dir/docker" +cat > "$work_dir/backup-info.json" </dev/null 2>&1; then + mkdir -p "$work_dir/container$(dirname "$src")" + docker cp "$container:$src" "$work_dir/container$src" >/dev/null 2>&1 || true + fi +}} +for p in {host_paths}; do copy_host_path "$p"; done +for p in {container_paths}; do copy_container_path "$p"; done +if [ -n "$container" ] && docker inspect "$container" >/dev/null 2>&1; then + docker inspect "$container" > "$work_dir/docker/inspect.json" 2>/dev/null || true + docker logs --tail 300 "$container" > "$work_dir/docker/logs-tail.txt" 2>&1 || true +fi +archive="$backup_dir/${{safe_proto}}-${{timestamp}}.tar.gz" +tar -C "$work_dir" -czf "$archive" . +chmod 0644 "$archive" +printf '%s\n' "$archive" +""".strip() + + out, err, code = self.ssh.run_sudo_command(script) + if code != 0: + return {'status': 'error', 'message': err or out or 'Failed to create backup'} + path = (out or '').strip().splitlines()[-1] if (out or '').strip() else '' + name = path.rsplit('/', 1)[-1] if path else '' + return {'status': 'success', 'protocol': protocol, 'backup': {'name': name, 'path': path}} diff --git a/managers/dns_manager.py b/managers/dns_manager.py new file mode 100644 index 0000000..9ac1575 --- /dev/null +++ b/managers/dns_manager.py @@ -0,0 +1,83 @@ + +import os +import logging + +logger = logging.getLogger(__name__) + +class DNSManager: + def __init__(self, ssh): + self.ssh = ssh + + def install_protocol(self, protocol_type='dns', port='53'): + """Install AmneziaDNS service.""" + try: + # 1. Check if docker is installed + out, _, _ = self.ssh.run_command("docker --version") + if "docker version" not in out.lower(): + return {"status": "error", "message": "Docker not installed"} + + # 2. Prepare directory + self.ssh.run_sudo_command("mkdir -p /opt/amnezia/dns") + + # 3. Create Dockerfile matching official Amnezia implementation + # We use Unbound (mvance/unbound) with DNS-over-TLS to Cloudflare + forward_config = """forward-zone: + name: "." + forward-tls-upstream: yes + forward-addr: 1.1.1.1@853 + forward-addr: 1.0.0.1@853 +""" + self.ssh.write_file("/opt/amnezia/dns/forward-records.conf", forward_config) + + dockerfile = """ +FROM mvance/unbound:latest +LABEL maintainer="AmneziaVPN" +COPY forward-records.conf /opt/unbound/etc/unbound/forward-records.conf +""" + self.ssh.write_file("/opt/amnezia/dns/Dockerfile", dockerfile) + + # 4. Build and run + self.ssh.run_sudo_command("docker build -t amnezia-dns /opt/amnezia/dns") + self.ssh.run_sudo_command("docker stop amnezia-dns || true") + self.ssh.run_sudo_command("docker rm amnezia-dns || true") + + # Create internal network for DNS (like original Amnezia client) + self.ssh.run_sudo_command("docker network ls | grep -q amnezia-dns-net || docker network create --subnet 172.29.172.0/24 amnezia-dns-net") + + # Use internal network with static IP. Do not expose 53 on host to avoid systemd-resolved conflict. + cmd = "docker run -d --name amnezia-dns --restart always --network amnezia-dns-net --ip=172.29.172.254 amnezia-dns" + self.ssh.run_sudo_command(cmd) + + # Connect existing VPN containers to the DNS network + vpn_containers = ['amnezia-awg', 'amnezia-awg2', 'amnezia-awg-legacy', 'amnezia-xray', 'telemt'] + for c in vpn_containers: + self.ssh.run_sudo_command(f"docker ps | grep -q {c} && docker network connect amnezia-dns-net {c} || true") + + return {"status": "success", "message": "AmneziaDNS installed successfully"} + except Exception as e: + logger.exception("Error installing DNS") + return {"status": "error", "message": str(e)} + + def get_server_status(self, protocol_type='dns'): + """Check if AmneziaDNS container is running.""" + try: + out, _, _ = self.ssh.run_sudo_command("docker ps --filter name=^amnezia-dns$ --format '{{.Status}}'") + is_running = 'Up' in out + + out_exists, _, _ = self.ssh.run_sudo_command("docker ps -a --filter name=^amnezia-dns$ --format '{{.Names}}'") + container_exists = 'amnezia-dns' in out_exists.strip().split('\n') + + return { + "container_exists": container_exists, + "container_running": is_running, + "port": "53", + "protocol": protocol_type + } + except Exception as e: + return {"error": str(e)} + + def remove_container(self, protocol_type='dns'): + """Remove AmneziaDNS container.""" + self.ssh.run_sudo_command("docker stop amnezia-dns || true") + self.ssh.run_sudo_command("docker rm amnezia-dns || true") + self.ssh.run_sudo_command("rm -rf /opt/amnezia/dns") diff --git a/managers/nginx_manager.py b/managers/nginx_manager.py new file mode 100644 index 0000000..0a98414 --- /dev/null +++ b/managers/nginx_manager.py @@ -0,0 +1,383 @@ +""" +NGINX Web Server Manager. + +Runs an NGINX container with a single editable site (index.html) and a +Let's Encrypt certificate issued through the webroot HTTP-01 challenge. +The panel owns: + - nginx.conf: editable through the Config button + - index.html: editable through the Site button +""" + +import json +import logging +import re +import shlex + +logger = logging.getLogger(__name__) + + +def _q(value): + return shlex.quote(str(value)) + + +class NginxManager: + PROTOCOL = 'nginx' + CONTAINER_NAME = 'amnezia-nginx' + IMAGE_NAME = 'nginx:alpine' + CERTBOT_IMAGE = 'certbot/certbot:latest' + CERTBOT_CONTAINER_NAME = 'amnezia-nginx-certbot' + BASE_DIR = '/opt/amnezia/nginx' + CONF_DIR = f'{BASE_DIR}/conf' + HTML_DIR = f'{BASE_DIR}/html' + CERTBOT_WWW_DIR = f'{BASE_DIR}/certbot/www' + LETSENCRYPT_DIR = f'{BASE_DIR}/letsencrypt' + META_PATH = f'{BASE_DIR}/metadata.json' + NGINX_CONF_PATH = f'{CONF_DIR}/default.conf' + INDEX_PATH = f'{HTML_DIR}/index.html' + DEFAULT_PORT = 443 + + def __init__(self, ssh, protocol='nginx'): + self.ssh = ssh + self.protocol = protocol or self.PROTOCOL + + # ===================== STATUS ===================== + + def check_docker_installed(self): + out, _, code = self.ssh.run_command("docker --version 2>/dev/null") + if code != 0: + return False + out2, _, _ = self.ssh.run_command( + "systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null" + ) + return 'active' in out2 or 'running' in out2.lower() + + def check_protocol_installed(self, protocol_type='nginx'): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps -a --filter name=^{self.CONTAINER_NAME}$ --format '{{{{.Names}}}}'" + ) + return self.CONTAINER_NAME in out.strip().split('\n') + + def check_container_running(self, protocol_type='nginx'): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps --filter name=^{self.CONTAINER_NAME}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def check_certbot_running(self): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps --filter name=^{self.CERTBOT_CONTAINER_NAME}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def get_server_status(self, protocol_type='nginx'): + exists = self.check_protocol_installed(protocol_type) + running = self.check_container_running(protocol_type) + meta = self._read_metadata() if exists else {} + config = self._get_server_config(protocol_type) if exists else '' + domain = meta.get('domain') or self._parse_domain(config) + port = int(meta.get('port') or self.DEFAULT_PORT) + return { + 'container_exists': exists, + 'container_running': running, + 'port': port, + 'domain': domain, + 'email': meta.get('email'), + 'site_url': self._site_url(domain, port) if domain else None, + 'protocol': protocol_type, + 'base_protocol': self.PROTOCOL, + 'instance': 1, + 'container_name': self.CONTAINER_NAME, + 'certbot_container_name': self.CERTBOT_CONTAINER_NAME, + 'certbot_running': self.check_certbot_running() if exists else False, + } + + # ===================== CONFIG BUILDERS ===================== + + def _validate_domain(self, domain): + domain = (domain or '').strip().lower() + if not domain or len(domain) > 253: + raise ValueError('Domain is required') + if not re.match(r'^(?!-)[a-z0-9.-]+(? + + + + + {domain} + + + +
+

NGINX is running

+

{domain}

+
+ + +""" + + def _parse_domain(self, config_text): + m = re.search(r'^\s*server_name\s+([^;\s]+)', config_text or '', re.MULTILINE) + return m.group(1) if m else None + + # ===================== FILE I/O ===================== + + def _read_file(self, path): + out, _, code = self.ssh.run_sudo_command(f"cat {_q(path)} 2>/dev/null") + return out if code == 0 else '' + + def _write_file(self, path, content): + parent = path.rsplit('/', 1)[0] + self.ssh.run_sudo_command(f"mkdir -p {_q(parent)}") + self.ssh.upload_file_sudo(content, path) + + def _read_metadata(self): + raw = self._read_file(self.META_PATH) + if not raw.strip(): + return {} + try: + return json.loads(raw) + except Exception: + return {} + + def _write_metadata(self, meta): + self._write_file(self.META_PATH, json.dumps(meta, indent=2, ensure_ascii=False)) + + def _get_server_config(self, protocol_type='nginx'): + config = self._read_file(self.NGINX_CONF_PATH) + if config: + return config + out, _, code = self.ssh.run_sudo_command( + f"docker exec {self.CONTAINER_NAME} cat /etc/nginx/conf.d/default.conf 2>/dev/null" + ) + return out if code == 0 else '' + + def save_server_config(self, protocol_type='nginx', config_text=''): + old_config = self._get_server_config(protocol_type) + self._write_file(self.NGINX_CONF_PATH, config_text or '') + if self.check_container_running(protocol_type): + _, err, code = self.ssh.run_sudo_command(f"docker exec {self.CONTAINER_NAME} nginx -t", timeout=30) + if code != 0: + self._write_file(self.NGINX_CONF_PATH, old_config) + self.ssh.run_sudo_command(f"docker exec {self.CONTAINER_NAME} nginx -s reload 2>/dev/null || true") + raise RuntimeError(f'Invalid NGINX config: {err}') + self.ssh.run_sudo_command(f"docker exec {self.CONTAINER_NAME} nginx -s reload") + return True + + def get_site_index(self, protocol_type='nginx'): + return self._read_file(self.INDEX_PATH) + + def save_site_index(self, protocol_type='nginx', html=''): + self._write_file(self.INDEX_PATH, html or '') + return True + + # ===================== INSTALL / REMOVE ===================== + + def _run_nginx_container(self, port): + run_cmd = ( + f"docker run -d --restart always " + f"--name {self.CONTAINER_NAME} " + f"-p 80:80/tcp " + f"-p {int(port)}:443/tcp " + f"-v {self.CONF_DIR}:/etc/nginx/conf.d:ro " + f"-v {self.HTML_DIR}:/usr/share/nginx/html:ro " + f"-v {self.CERTBOT_WWW_DIR}:/var/www/certbot:ro " + f"-v {self.LETSENCRYPT_DIR}:/etc/letsencrypt:ro " + f"{self.IMAGE_NAME}" + ) + return self.ssh.run_sudo_command(run_cmd, timeout=60) + + def _run_certbot_renewer(self, domain, email): + loop_script = f""" +set -eu +if [ ! -f /etc/letsencrypt/live/{domain}/fullchain.pem ]; then + certbot certonly --webroot --webroot-path /var/www/certbot --email {_q(email)} --agree-tos --no-eff-email -d {_q(domain)} +fi +kill -HUP 1 2>/dev/null || true +while :; do + certbot renew --webroot --webroot-path /var/www/certbot --quiet --deploy-hook 'kill -HUP 1 2>/dev/null || true' + sleep 12h & wait $! +done +""" + self.ssh.run_sudo_command(f"docker rm -fv {self.CERTBOT_CONTAINER_NAME} || true") + run_cmd = ( + f"docker run -d --restart always " + f"--name {self.CERTBOT_CONTAINER_NAME} " + f"--pid=container:{self.CONTAINER_NAME} " + f"-v {self.CERTBOT_WWW_DIR}:/var/www/certbot " + f"-v {self.LETSENCRYPT_DIR}:/etc/letsencrypt " + f"--entrypoint /bin/sh " + f"{self.CERTBOT_IMAGE} -c {_q(loop_script)}" + ) + return self.ssh.run_sudo_command(run_cmd, timeout=60) + + def _wait_for_certificate(self, domain): + wait_script = f""" +for i in $(seq 1 60); do + if [ -s {self.LETSENCRYPT_DIR}/live/{domain}/fullchain.pem ] && [ -s {self.LETSENCRYPT_DIR}/live/{domain}/privkey.pem ]; then + exit 0 + fi + if ! docker ps --filter name=^{self.CERTBOT_CONTAINER_NAME}$ --format '{{{{.Names}}}}' | grep -qx {self.CERTBOT_CONTAINER_NAME}; then + docker logs --tail 120 {self.CERTBOT_CONTAINER_NAME} 2>&1 || true + exit 1 + fi + sleep 5 +done +docker logs --tail 120 {self.CERTBOT_CONTAINER_NAME} 2>&1 || true +exit 1 +""" + return self.ssh.run_sudo_command(f"sh -c {_q(wait_script)}", timeout=330) + + def install_protocol(self, protocol_type='nginx', port=None, email=None, domain=None): + if not self.check_docker_installed(): + return {'status': 'error', 'message': 'Docker not installed'} + + port = int(port or self.DEFAULT_PORT) + if port == 80: + return {'status': 'error', 'message': 'Port 80 is reserved for Let\'s Encrypt validation'} + domain = self._validate_domain(domain) + email = self._validate_email(email) + + self.ssh.run_sudo_command(f"docker pull {self.IMAGE_NAME}", timeout=180) + self.ssh.run_sudo_command(f"docker pull {self.CERTBOT_IMAGE}", timeout=180) + + if self.check_protocol_installed(protocol_type): + self.remove_container(protocol_type) + + self.ssh.run_sudo_command( + f"mkdir -p {self.CONF_DIR} {self.HTML_DIR} {self.CERTBOT_WWW_DIR} {self.LETSENCRYPT_DIR}" + ) + self._write_file(self.NGINX_CONF_PATH, self._build_initial_config(domain)) + self._write_file(self.INDEX_PATH, self._default_index(domain)) + self._write_metadata({'domain': domain, 'email': email, 'port': port}) + + _, err, code = self._run_nginx_container(port) + if code != 0: + return {'status': 'error', 'message': f'Failed to start NGINX container: {err}'} + + _, err, code = self._run_certbot_renewer(domain, email) + if code != 0: + self.ssh.run_sudo_command(f"docker logs --tail 100 {self.CONTAINER_NAME} 2>/dev/null || true") + self.ssh.run_sudo_command(f"docker stop {self.CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CONTAINER_NAME} || true") + return {'status': 'error', 'message': f'Failed to start certbot renewer container: {err}'} + + out, err, code = self._wait_for_certificate(domain) + if code != 0: + self.ssh.run_sudo_command(f"docker logs --tail 120 {self.CERTBOT_CONTAINER_NAME} 2>/dev/null || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CERTBOT_CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker stop {self.CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CONTAINER_NAME} || true") + return { + 'status': 'error', + 'message': f"Let's Encrypt certificate issue failed. Make sure {domain} points to this server and port 80 is reachable. {err or out}", + } + + self._write_file(self.NGINX_CONF_PATH, self._build_ssl_config(domain, port)) + _, err, code = self.ssh.run_sudo_command(f"docker exec {self.CONTAINER_NAME} nginx -t", timeout=30) + if code != 0: + return {'status': 'error', 'message': f'Generated NGINX config is invalid: {err}'} + self.ssh.run_sudo_command(f"docker exec {self.CONTAINER_NAME} nginx -s reload") + + url = self._site_url(domain, port) + return { + 'status': 'success', + 'protocol': protocol_type, + 'base_protocol': self.PROTOCOL, + 'instance': 1, + 'container_name': self.CONTAINER_NAME, + 'certbot_container_name': self.CERTBOT_CONTAINER_NAME, + 'certbot_running': self.check_certbot_running(), + 'port': port, + 'domain': domain, + 'email': email, + 'site_url': url, + 'message': 'NGINX web server installed', + 'log': [ + f'NGINX HTTPS port: {port}/TCP', + 'Port 80/TCP is used for Let\'s Encrypt HTTP-01 validation', + f'Certificate issued for {domain}', + f'Auto-renewal container: {self.CERTBOT_CONTAINER_NAME}', + f'Site URL: {url}', + ], + } + + def remove_container(self, protocol_type='nginx'): + self.ssh.run_sudo_command(f"docker stop {self.CERTBOT_CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CERTBOT_CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker stop {self.CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"docker rm -fv {self.CONTAINER_NAME} || true") + self.ssh.run_sudo_command(f"rm -rf {self.BASE_DIR}") + return True diff --git a/managers/socks5_manager.py b/managers/socks5_manager.py new file mode 100644 index 0000000..7226cb7 --- /dev/null +++ b/managers/socks5_manager.py @@ -0,0 +1,240 @@ +""" +SOCKS5 Proxy Manager — runs 3proxy in a Docker container, modelled after the +official Amnezia client install (client/server_scripts/socks5_proxy/). Holds a +single user (port + username + password); credentials can be edited later from +the panel via update_credentials(). +""" + +import logging +import secrets +import string +import re + +logger = logging.getLogger(__name__) + + +def _generate_password(length=16): + alphabet = string.ascii_letters + string.digits + return ''.join(secrets.choice(alphabet) for _ in range(length)) + + +class Socks5Manager: + PROTOCOL = 'socks5' + CONTAINER_NAME = 'amnezia-socks5proxy' + IMAGE_NAME = '3proxy/3proxy:0.9.5' + CONFIG_DIR = '/opt/amnezia/socks5proxy' + CONFIG_PATH = '/etc/3proxy/3proxy.cfg' + + DEFAULT_PORT = 38080 + DEFAULT_USERNAME = 'proxy_user' + + def __init__(self, ssh, protocol='socks5'): + self.ssh = ssh + self.protocol = protocol or self.PROTOCOL + self.instance = self._instance_index(self.protocol) + self.container_name = self._container_name(self.protocol) + self.config_dir = self._config_dir(self.protocol) + + def _instance_index(self, protocol=None): + parts = str(protocol or self.protocol or '').split('__', 1) + if len(parts) == 2: + try: + return max(1, int(parts[1])) + except ValueError: + return 1 + return 1 + + def _container_name(self, protocol=None): + idx = self._instance_index(protocol or self.protocol) + return self.CONTAINER_NAME if idx <= 1 else f'{self.CONTAINER_NAME}-{idx}' + + def _config_dir(self, protocol=None): + idx = self._instance_index(protocol or self.protocol) + return self.CONFIG_DIR if idx <= 1 else f'{self.CONFIG_DIR}-{idx}' + + # ===================== STATUS ===================== + + def check_docker_installed(self): + out, _, code = self.ssh.run_command("docker --version 2>/dev/null") + if code != 0: + return False + out2, _, _ = self.ssh.run_command( + "systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null" + ) + return 'active' in out2 or 'running' in out2.lower() + + def check_protocol_installed(self, protocol_type='socks5'): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps -a --filter name=^{self._container_name(protocol_type)}$ --format '{{{{.Names}}}}'" + ) + return self._container_name(protocol_type) in out.strip().split('\n') + + def check_container_running(self, protocol_type='socks5'): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps --filter name=^{self._container_name(protocol_type)}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def get_server_status(self, protocol_type='socks5'): + exists = self.check_protocol_installed(protocol_type) + running = self.check_container_running(protocol_type) + creds = self.get_credentials() if exists else {} + return { + 'container_exists': exists, + 'container_running': running, + 'port': creds.get('port'), + 'username': creds.get('username'), + 'protocol': protocol_type, + 'base_protocol': self.PROTOCOL, + 'instance': self._instance_index(protocol_type), + 'container_name': self._container_name(protocol_type), + } + + # ===================== CONFIG I/O ===================== + + def _build_config(self, username, password, port): + # Mirrors client/server_scripts/socks5_proxy/configure_container.sh. + # 'auth strong' enforces username/password on every connection; + # 'allow {user}' restricts the ACL to our single user only. + return ( + "#!/bin/3proxy\n" + f"config {self.CONFIG_PATH}\n" + "timeouts 1 5 30 60 180 1800 15 60\n" + f"users {username}:CL:{password}\n" + "log\n" + "auth strong\n" + f"allow {username}\n" + f"socks -p{int(port)}\n" + ) + + def _read_config(self): + out, _, code = self.ssh.run_sudo_command( + f"docker exec {self.container_name} cat {self.CONFIG_PATH} 2>/dev/null" + ) + if code != 0 or not out.strip(): + out, _, code = self.ssh.run_sudo_command( + f"cat {self.config_dir}/3proxy.cfg 2>/dev/null" + ) + if code != 0 or not out.strip(): + return '' + return out + + def _write_config(self, config_text): + # Write to host first (so we have a stable copy outside the container), + # then docker cp into the running container at the path 3proxy expects. + self.ssh.run_sudo_command(f"mkdir -p {self.config_dir}") + self.ssh.upload_file_sudo(config_text, f"{self.config_dir}/3proxy.cfg") + self.ssh.run_sudo_command( + f"docker cp {self.config_dir}/3proxy.cfg {self.container_name}:{self.CONFIG_PATH} 2>/dev/null || true" + ) + + def _parse_credentials(self, config_text): + creds = {'port': None, 'username': None, 'password': None} + if not config_text: + return creds + m_user = re.search(r'^\s*users\s+([^:\s]+):CL:(\S+)', config_text, re.MULTILINE) + if m_user: + creds['username'] = m_user.group(1) + creds['password'] = m_user.group(2) + m_port = re.search(r'^\s*socks\s+-p(\d+)', config_text, re.MULTILINE) + if m_port: + creds['port'] = int(m_port.group(1)) + return creds + + def get_credentials(self): + return self._parse_credentials(self._read_config()) + + # ===================== INSTALL / UPDATE / REMOVE ===================== + + def install_protocol(self, protocol_type='socks5', port=None, username=None, password=None): + if not self.check_docker_installed(): + return {'status': 'error', 'message': 'Docker not installed'} + + port = int(port or self.DEFAULT_PORT) + username = (username or self.DEFAULT_USERNAME).strip() or self.DEFAULT_USERNAME + password = (password or _generate_password()).strip() or _generate_password() + + # Pull image (idempotent — fast no-op if cached) + self.ssh.run_sudo_command(f"docker pull {self.IMAGE_NAME}") + + # Wipe any prior install, including the bind-mounted config dir, before + # writing a fresh config — leftover state would leak old credentials. + install_protocol = protocol_type or self.protocol + container_name = self._container_name(install_protocol) + config_dir = self._config_dir(install_protocol) + + if self.check_protocol_installed(install_protocol): + self.remove_container(install_protocol) + + config_text = self._build_config(username, password, port) + self.ssh.run_sudo_command(f"mkdir -p {config_dir}") + self.ssh.upload_file_sudo(config_text, f"{config_dir}/3proxy.cfg") + + # The 3proxy image reads /etc/3proxy/3proxy.cfg by default. + # Do not pass the config path as the container command: Docker would try + # to execute the config file and fail with "permission denied". + run_cmd = ( + f"docker run -d --restart always " + f"--name {container_name} " + f"-p {port}:{port}/tcp " + f"-v {config_dir}:/etc/3proxy:ro " + f"{self.IMAGE_NAME}" + ) + _, err, code = self.ssh.run_sudo_command(run_cmd) + if code != 0: + return {'status': 'error', 'message': f'Failed to start container: {err}'} + + return { + 'status': 'success', + 'protocol': install_protocol, + 'base_protocol': self.PROTOCOL, + 'instance': self._instance_index(install_protocol), + 'container_name': container_name, + 'port': port, + 'username': username, + 'password': password, + 'message': 'SOCKS5 proxy installed', + 'log': [ + f'SOCKS5 proxy listening on port {port}/TCP', + f'Username: {username}', + f'Password: {password}', + 'Save these credentials — the password can also be viewed later via "Change settings".', + ], + } + + def update_credentials(self, port=None, username=None, password=None): + """Apply new connection settings: regenerates the config file and + restarts the container so the new port mapping takes effect.""" + if not self.check_protocol_installed(self.protocol): + return {'status': 'error', 'message': 'SOCKS5 not installed'} + + current = self.get_credentials() + new_port = int(port if port is not None else (current.get('port') or self.DEFAULT_PORT)) + new_user = (username or current.get('username') or self.DEFAULT_USERNAME).strip() + new_pass = (password or current.get('password') or _generate_password()).strip() + + old_port = current.get('port') + + # If the port changed we must recreate the container — `docker run -p` + # mappings are immutable on existing containers. + if old_port and new_port != old_port: + return self.install_protocol( + protocol_type=self.protocol, port=new_port, username=new_user, password=new_pass + ) + + config_text = self._build_config(new_user, new_pass, new_port) + self._write_config(config_text) + self.ssh.run_sudo_command(f"docker restart {self.container_name}") + + return { + 'status': 'success', + 'port': new_port, + 'username': new_user, + 'password': new_pass, + } + + def remove_container(self, protocol_type='socks5'): + self.ssh.run_sudo_command(f"docker stop {self._container_name(protocol_type)} || true") + self.ssh.run_sudo_command(f"docker rm -fv {self._container_name(protocol_type)} || true") + self.ssh.run_sudo_command(f"rm -rf {self._config_dir(protocol_type)}") + return True diff --git a/managers/ssh_manager.py b/managers/ssh_manager.py new file mode 100644 index 0000000..437e52e --- /dev/null +++ b/managers/ssh_manager.py @@ -0,0 +1,227 @@ +""" +SSH Manager - manages SSH connections to VPN servers. +Replicates the ServerController logic from the AmneziaVPN client. +""" + +import paramiko +import io +import time +import logging + +logger = logging.getLogger(__name__) + + +class SSHManager: + """Manages SSH connections and command execution on remote servers.""" + + def __init__(self, host, port, username, password=None, private_key=None): + self.host = host + self.port = int(port) + self.username = username + self.password = password + self.private_key = private_key + self.client = None + self._is_root = (username == 'root') + + def connect(self): + """Establish SSH connection to the server.""" + self.client = paramiko.SSHClient() + self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + kwargs = { + 'hostname': self.host, + 'port': self.port, + 'username': self.username, + 'timeout': 15, + 'allow_agent': False, + 'look_for_keys': False, + } + + if self.private_key: + key_file = io.StringIO(self.private_key) + try: + pkey = paramiko.RSAKey.from_private_key(key_file) + except paramiko.ssh_exception.SSHException: + key_file.seek(0) + try: + pkey = paramiko.Ed25519Key.from_private_key(key_file) + except paramiko.ssh_exception.SSHException: + key_file.seek(0) + pkey = paramiko.ECDSAKey.from_private_key(key_file) + kwargs['pkey'] = pkey + elif self.password: + kwargs['password'] = self.password + + self.client.connect(**kwargs) + return True + + def disconnect(self): + """Close SSH connection.""" + if self.client: + self.client.close() + self.client = None + + def run_command(self, command, timeout=60): + """Execute command on remote server.""" + if not self.client: + raise ConnectionError("Not connected to server") + + logger.info(f"Running command: {command[:100]}...") + stdin, stdout, stderr = self.client.exec_command(command, timeout=timeout) + + # Crucial: set timeout on the channel to prevent hanging indefinitely + stdout.channel.settimeout(timeout) + stderr.channel.settimeout(timeout) + + try: + exit_code = stdout.channel.recv_exit_status() + out = stdout.read().decode('utf-8', errors='replace').strip() + err = stderr.read().decode('utf-8', errors='replace').strip() + except Exception as e: + logger.error(f"Command timed out or failed to read: {e}") + out, err, exit_code = "", str(e), -1 + + if exit_code != 0: + logger.warning(f"Command exited with code {exit_code}: {err}") + + return out, err, exit_code + + def _sudo_prefix(self): + """Get the sudo command prefix with password handling.""" + if self._is_root: + return '' + if self.password: + # Use sudo -S to read password from stdin + escaped_pass = self.password.replace("'", "'\\''") + return f"echo '{escaped_pass}' | sudo -S " + return 'sudo ' + + def run_sudo_command(self, command, timeout=60): + """ + Execute command with sudo, automatically handling password. + Strips 'sudo ' from the beginning of command if present, + and re-adds it with password piping. + """ + # Remove existing sudo prefix if present + clean_cmd = command + if clean_cmd.strip().startswith('sudo '): + clean_cmd = clean_cmd.strip()[5:] + + if self._is_root: + return self.run_command(clean_cmd, timeout=timeout) + + if self.password: + escaped_pass = self.password.replace("'", "'\\''") + # Pipe password directly to sudo -S, preserving original command quoting + # 2>/dev/null on echo suppresses '[sudo] password for...' prompt noise + full_cmd = f"echo '{escaped_pass}' | sudo -S -p '' {clean_cmd}" + else: + full_cmd = f"sudo {clean_cmd}" + + return self.run_command(full_cmd, timeout=timeout) + + def run_sudo_script(self, script, timeout=120): + """ + Execute a multi-line script with sudo/root privileges. + Writes script to /tmp via SFTP, then runs with sudo bash. + """ + if self._is_root: + return self.run_script(script, timeout=timeout) + + # Write script to temp file via SFTP (avoids heredoc/pipe conflicts) + import hashlib + script_hash = hashlib.md5(script.encode()).hexdigest()[:8] + tmp_script = f"/tmp/_amnz_script_{script_hash}.sh" + self.upload_file(script, tmp_script) + + # Run with sudo + if self.password: + escaped_pass = self.password.replace("'", "'\\''") + full_cmd = f"echo '{escaped_pass}' | sudo -S -p '' bash {tmp_script}; rm -f {tmp_script}" + else: + full_cmd = f"sudo bash {tmp_script}; rm -f {tmp_script}" + + return self.run_command(full_cmd, timeout=timeout) + + def run_script(self, script, timeout=120): + """Execute a multi-line script on remote server.""" + return self.run_command(script, timeout=timeout) + + def upload_file(self, content, remote_path): + """Upload text content to a remote file via SFTP.""" + if not self.client: + raise ConnectionError("Not connected to server") + + # Normalize line endings (Windows CRLF -> Unix LF) + content = content.replace('\r\n', '\n') + + sftp = self.client.open_sftp() + try: + with sftp.file(remote_path, 'w') as f: + f.write(content) + finally: + sftp.close() + + def upload_file_sudo(self, content, remote_path): + """ + Upload text content to a remote file that requires root access. + Uses SFTP to write to /tmp, then sudo mv to the target path. + Also normalizes line endings to Unix-style (LF). + """ + if not self.client: + raise ConnectionError("Not connected to server") + + # Normalize line endings (Windows CRLF -> Unix LF) + content = content.replace('\r\n', '\n') + + # Write to temp file via SFTP (no sudo needed for /tmp) + import hashlib + tmp_name = f"/tmp/_amnz_{hashlib.md5(remote_path.encode()).hexdigest()[:8]}" + self.upload_file(content, tmp_name) + + # Move to target with sudo + self.run_sudo_command(f"mv {tmp_name} {remote_path}") + self.run_sudo_command(f"chmod 644 {remote_path}") + return True + + def download_file(self, remote_path): + """Download text content from a remote file.""" + if not self.client: + raise ConnectionError("Not connected to server") + + sftp = self.client.open_sftp() + try: + with sftp.file(remote_path, 'r') as f: + return f.read().decode('utf-8', errors='replace') + finally: + sftp.close() + + def file_exists(self, remote_path): + """Check if a remote file exists.""" + if not self.client: + raise ConnectionError("Not connected to server") + + sftp = self.client.open_sftp() + try: + sftp.stat(remote_path) + return True + except FileNotFoundError: + return False + finally: + sftp.close() + + def test_connection(self): + """Test SSH connection and return server info.""" + out, err, code = self.run_command("uname -sr && cat /etc/os-release 2>/dev/null | head -2") + return out + + def write_file(self, remote_path, content): + """Write content to a remote file with sudo.""" + return self.upload_file_sudo(content, remote_path) + + def __enter__(self): + self.connect() + return self + + def __exit__(self, *args): + self.disconnect() diff --git a/managers/telemt_manager.py b/managers/telemt_manager.py new file mode 100644 index 0000000..70d8c89 --- /dev/null +++ b/managers/telemt_manager.py @@ -0,0 +1,571 @@ +import json +import logging +import uuid +import re +import os +import secrets +from datetime import datetime +from .ssh_manager import SSHManager + +logger = logging.getLogger(__name__) + +class TelemtManager: + CONTAINER_NAME = "telemt" + API_URL = "http://127.0.0.1:9091" + + def __init__(self, ssh_manager: SSHManager, protocol='telemt'): + self.ssh = ssh_manager + self.protocol = protocol or 'telemt' + self.instance = self._instance_index(self.protocol) + self.container_name = self._container_name(self.protocol) + self.remote_dir = self._remote_dir(self.protocol) + + def _instance_index(self, protocol): + parts = str(protocol or '').split('__', 1) + if len(parts) == 2: + try: + return max(1, int(parts[1])) + except ValueError: + return 1 + return 1 + + def _container_name(self, protocol=None): + idx = self._instance_index(protocol or self.protocol) + base_name = self.CONTAINER_NAME + return base_name if idx <= 1 else f'{base_name}-{idx}' + + def _remote_dir(self, protocol=None): + idx = self._instance_index(protocol or self.protocol) + return '/opt/amnezia/telemt' if idx <= 1 else f'/opt/amnezia/telemt-{idx}' + + def _config_path(self): + return f'{self.remote_dir}/config.toml' + + def _api_host_ports(self): + # Host API mappings are only for diagnostics; panel talks via docker exec. + # Keep first instance backward-compatible, avoid 9090/9091 collisions later. + if self.instance <= 1: + return 9090, 9091 + base = 9090 + (self.instance * 10) + return base, base + 1 + + def _api_request(self, method, path, data=None): + """Execute a curl request inside the docker container.""" + cmd = f"docker exec {self.container_name} curl -s -X {method} {self.API_URL}{path}" + if data: + js_data = json.dumps(data).replace('"', '\\"') + cmd += f" -H 'Content-Type: application/json' -d \"{js_data}\"" + + out, err, code = self.ssh.run_sudo_command(cmd) + if code != 0: + return None + + try: + return json.loads(out) + except json.JSONDecodeError: + return None + + def check_docker_installed(self): + out, _, _ = self.ssh.run_command("docker --version 2>/dev/null") + return bool(out.strip()) + + def check_protocol_installed(self): + out, _, _ = self.ssh.run_command(f"docker ps -a --filter name=^{self.container_name}$ --format '{{{{.Names}}}}'") + return out.strip() == self.container_name + + def get_server_status(self, protocol_type): + exists = self.check_protocol_installed() + out, _, _ = self.ssh.run_command(f"docker inspect -f '{{{{.State.Running}}}}' {self.container_name} 2>/dev/null") + is_running = out.strip().lower() == 'true' + + status = { + 'container_exists': exists, + 'container_running': is_running, + } + + if is_running: + # get external docker port mapping for 443 + out, _, _ = self.ssh.run_command(f"docker port {self.container_name} 443 2>/dev/null") + if out: + port = out.split(':')[-1].strip() + status['port'] = port + else: + status['port'] = None + + config = self._get_server_config() + status['awg_params'] = self._parse_telemt_params(config) + + # Count connections from API + clients = self.get_clients(protocol_type) + status['clients_count'] = len(clients) + + return status + + def _ensure_docker_compose(self): + """Make sure `docker compose` is available, installing the plugin if needed. + + Why: `docker-buildx-plugin` and `docker-compose-plugin` only ship in Docker's + official apt/yum repo. When Docker was installed from distro packages + (e.g. `docker.io` on Ubuntu), that repo is not configured and a plain + `apt-get install docker-compose-plugin` fails. So we add the repo, + refresh package lists, then install. + """ + out, _, code = self.ssh.run_command("docker compose version 2>/dev/null") + if code == 0 and out.strip(): + return + + script = r""" +if command -v apt-get >/dev/null 2>&1; then + export DEBIAN_FRONTEND=noninteractive + apt-get update -y || true + apt-get install -y ca-certificates curl gnupg || exit 1 + install -m 0755 -d /etc/apt/keyrings + . /etc/os-release + DOCKER_DISTRO="$ID" + case "$ID" in + linuxmint|pop|elementary|zorin) DOCKER_DISTRO="ubuntu" ;; + kali|parrot) DOCKER_DISTRO="debian" ;; + esac + if [ ! -s /etc/apt/keyrings/docker.asc ]; then + curl -fsSL "https://download.docker.com/linux/${DOCKER_DISTRO}/gpg" -o /etc/apt/keyrings/docker.asc || exit 1 + chmod a+r /etc/apt/keyrings/docker.asc + fi + CODENAME="${UBUNTU_CODENAME:-$VERSION_CODENAME}" + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${DOCKER_DISTRO} ${CODENAME} stable" > /etc/apt/sources.list.d/docker.list + apt-get update -y || exit 1 + apt-get install -y docker-buildx-plugin docker-compose-plugin || exit 1 +elif command -v dnf >/dev/null 2>&1; then + dnf install -y dnf-plugins-core || exit 1 + . /etc/os-release + dnf config-manager --add-repo "https://download.docker.com/linux/${ID}/docker-ce.repo" \ + || dnf config-manager --add-repo "https://download.docker.com/linux/centos/docker-ce.repo" \ + || exit 1 + dnf makecache || true + dnf install -y docker-buildx-plugin docker-compose-plugin || exit 1 +elif command -v yum >/dev/null 2>&1; then + yum install -y yum-utils || exit 1 + . /etc/os-release + yum-config-manager --add-repo "https://download.docker.com/linux/${ID}/docker-ce.repo" \ + || yum-config-manager --add-repo "https://download.docker.com/linux/centos/docker-ce.repo" \ + || exit 1 + yum makecache || true + yum install -y docker-buildx-plugin docker-compose-plugin || exit 1 +else + echo "Unsupported package manager" >&2 + exit 1 +fi +docker compose version +""" + out, err, code = self.ssh.run_sudo_script(script, timeout=300) + if code != 0: + raise RuntimeError(f"Failed to install docker compose plugin: {err or out}") + + def install_protocol(self, protocol_type='telemt', port='443', tls_emulation=True, tls_domain="", max_connections=0): + results = [] + if not self.check_docker_installed(): + results.append("Installing Docker...") + self.ssh.run_sudo_command("curl -fsSL https://get.docker.com | sh", timeout=300) + + if self.check_protocol_installed(): + self.ssh.run_sudo_command(f"docker rm -f {self.container_name}") + + results.append("Ensuring docker compose plugin...") + self._ensure_docker_compose() + + results.append("Uploading Telemt files...") + local_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'protocol_telemt') + remote_dir = self.remote_dir + self.ssh.run_sudo_command(f"mkdir -p {remote_dir}") + self.ssh.run_sudo_command(f"chmod 755 {remote_dir}") + + # Read and patch config.toml + with open(os.path.join(local_dir, 'config.toml'), 'r', encoding='utf-8') as f: + config_content = f.read() + + tls_emul_str = "true" if tls_emulation else "false" + config_content = re.sub(r'tls_emulation\s*=\s*(true|false|True|False)', f'tls_emulation = {tls_emul_str}', config_content) + + if tls_emulation and tls_domain: + config_content = re.sub(r'tls_domain\s*=\s*".*?"', f'tls_domain = "{tls_domain}"', config_content) + + if max_connections is not None and max_connections > 0: + config_content = re.sub(r'max_connections\s*=\s*\d+', f'max_connections = {max_connections}', config_content) + + # Patch public_host and public_port for links + if "public_host =" in config_content or "# public_host =" in config_content: + config_content = re.sub(r'#?\s*public_host\s*=\s*".*?"', f'public_host = "{self.ssh.host}"', config_content) + else: + config_content = config_content.replace('[general.links]', f'[general.links]\npublic_host = "{self.ssh.host}"') + + config_content = re.sub(r'public_port\s*=\s*\d+', f'public_port = {port}', config_content) + + # Remove default hello user + config_content = re.sub(r'^hello\s*=\s*".*?"', '', config_content, flags=re.MULTILINE) + + self.ssh.upload_file_sudo(config_content, f"{remote_dir}/config.toml") + + # Patch docker-compose.yml with proper port + with open(os.path.join(local_dir, 'docker-compose.yml'), 'r', encoding='utf-8') as f: + compose_content = f.read() + + compose_content = re.sub(r'"443:443"', f'"{port}:443"', compose_content) + compose_content = re.sub(r'container_name:\s*telemt', f'container_name: {self.container_name}', compose_content) + if self.instance > 1: + api_port_9090, api_port_9091 = self._api_host_ports() + compose_content = re.sub(r'"127\.0\.0\.1:9090:9090"', f'"127.0.0.1:{api_port_9090}:9090"', compose_content) + compose_content = re.sub(r'"127\.0\.0\.1:9091:9091"', f'"127.0.0.1:{api_port_9091}:9091"', compose_content) + self.ssh.upload_file_sudo(compose_content, f"{remote_dir}/docker-compose.yml") + + # Upload Dockerfile + with open(os.path.join(local_dir, 'Dockerfile'), 'r', encoding='utf-8') as f: + dockerfile = f.read() + self.ssh.upload_file_sudo(dockerfile, f"{remote_dir}/Dockerfile") + + results.append("Starting Telemt container...") + out, err, code = self.ssh.run_sudo_command(f"sh -c 'cd {remote_dir} && docker compose up -d --build'", timeout=600) + if code != 0: + self.ssh.run_sudo_command(f"sh -c 'cd {remote_dir} && docker-compose up -d --build'", timeout=600) + + return { + "status": "success", + "protocol": self.protocol, + "host": "", + "port": port, + "log": results + } + + def _get_server_config(self): + out, _, code = self.ssh.run_sudo_command(f"cat {self._config_path()}") + if code != 0: return "" + return out + + def save_server_config(self, protocol_type, config_content): + self.ssh.upload_file_sudo(config_content.replace('\r\n', '\n'), f"{self._config_path()}") + # Use SIGHUP (HUP) to reload MTProxy config without restarting the process/container. + # This keeps the traffic statistics (octets) in memory. + self.ssh.run_sudo_command(f"docker kill -s HUP {self.container_name} || docker restart {self.container_name}") + + def _parse_telemt_params(self, config_text): + params = {} + m = re.search(r'tls_emulation\s*=\s*(true|false)', config_text, re.IGNORECASE) + if m: params['tls_emulation'] = m.group(1).lower() == 'true' + + m = re.search(r'tls_domain\s*=\s*"([^"]+)"', config_text) + if m: params['tls_domain'] = m.group(1) + + m = re.search(r'max_connections\s*=\s*(\d+)', config_text) + if m: params['max_connections'] = int(m.group(1)) + + return params + + def remove_container(self, protocol_type=None): + self.ssh.run_sudo_command(f"docker rm -f {self.container_name}") + self.ssh.run_sudo_command(f"rm -rf {self.remote_dir}") + + def get_clients(self, protocol_type): + api_data = {} + resp = self._api_request("GET", "/v1/users") + if resp and resp.get('ok'): + for u in resp.get('data', []): + api_data[u.get('username')] = u + + config_text = self._get_server_config() + users = self._parse_users_from_config(config_text) + + clients = [] + needs_update = False + for username, secret in users.items(): + user_stats = api_data.get(username.lstrip('#').strip(), {}) + links = user_stats.get('links', {}) + tg_link = "" + if links.get('tls'): tg_link = links['tls'][0] + elif links.get('secure'): tg_link = links['secure'][0] + elif links.get('classic'): tg_link = links['classic'][0] + + enabled = not username.startswith('#') + clean_name = username.lstrip('#').strip() + + total_octets = user_stats.get('total_octets', 0) + quota = user_stats.get('data_quota_bytes') + + # AUTO-DISABLE IF QUOTA REACHED + if enabled and quota and total_octets >= quota: + logger.info(f"Auto-disabling client {clean_name} - quota reached: {total_octets} >= {quota}") + # We will trigger a toggle after we finish this loop to avoid re-reading config inside loop + enabled = False + needs_update = True + + clients.append({ + "clientId": clean_name, + "clientName": clean_name, + "enabled": enabled, + "creationDate": "", + "userData": { + "clientName": clean_name, + "token": secret, + "tg_link": tg_link, + "total_octets": total_octets, + "current_connections": user_stats.get('current_connections', 0), + "active_ips": user_stats.get('active_unique_ips', 0), + "quota": quota, + "expiry": user_stats.get('expiration_rfc3339') + } + }) + + if needs_update: + # Re-read and update config strictly at the end + for c in clients: + if not c['enabled']: + self.toggle_client(protocol_type, c['clientId'], False, restart=False) + self.ssh.run_sudo_command(f"docker restart {self.container_name}") + + return clients + + def _parse_users_from_config(self, config_text): + users = {} + lines = config_text.split('\n') + in_section = False + for line in lines: + stripped = line.strip() + if stripped == '[access.users]': + in_section = True + continue + if in_section and stripped.startswith('['): + break + if in_section and stripped: + commented = stripped.startswith('#') + content = stripped.lstrip('#').strip() + if '=' in content: + if content.lower().startswith('format:'): continue + name, secret = content.split('=', 1) + name = name.strip().strip('"').strip() + secret = secret.strip().strip('"').strip() + full_name = ("# " + name) if commented else name + users[full_name] = secret + return users + + def add_client(self, protocol_type, name, host='', port='', **kwargs): + username = re.sub(r'[^a-zA-Z0-9_.-]', '', name.replace(' ', '_')) + if not username: username = "user_" + uuid.uuid4().hex[:8] + + config_text = self._get_server_config() + current_users = self._parse_users_from_config(config_text) + idx = 1 + base_username = username + while any(u.lstrip('#').strip() == username for u in current_users): + username = f"{base_username}_{idx}" + idx += 1 + + secret = kwargs.get('secret') or secrets.token_hex(16) + + # 1. Update config file for persistence (but don't restart yet) + config_text = self._insert_into_section(config_text, "access.users", f'{username} = "{secret}"') + + api_payload = { + "username": username, + "secret": secret + } + + if kwargs.get('telemt_quota'): + val = int(kwargs['telemt_quota']) + config_text = self._insert_into_section(config_text, "access.user_data_quota", f'{username} = {val}') + api_payload['data_quota_bytes'] = val + + if kwargs.get('telemt_max_ips'): + val = int(kwargs['telemt_max_ips']) + config_text = self._insert_into_section(config_text, "access.user_max_unique_ips", f'{username} = {val}') + api_payload['max_unique_ips'] = val + + if kwargs.get('telemt_expiry'): + val = kwargs['telemt_expiry'] + config_text = self._insert_into_section(config_text, "access.user_expirations", f'{username} = "{val}"') + api_payload['expiration_rfc3339'] = val + + if kwargs.get('user_ad_tag'): + val = kwargs['user_ad_tag'] + config_text = self._insert_into_section(config_text, "access.user_ad_tags", f'{username} = "{val}"') + api_payload['user_ad_tag'] = val + + if kwargs.get('max_tcp_conns'): + val = int(kwargs['max_tcp_conns']) + config_text = self._insert_into_section(config_text, "access.user_max_tcp_conns", f'{username} = {val}') + api_payload['max_tcp_conns'] = val + + # Save config to host + self.ssh.upload_file_sudo(config_text.replace('\r\n', '\n'), f"{self._config_path()}") + + # 2. Call API for immediate effect + self._api_request("POST", "/v1/users", data=api_payload) + + # Fetch the official link from API (it includes TLS emulation padding like 'ee...' if enabled) + link = self.get_client_config(protocol_type, username, host, port) + + # Extreme fallback if API is slow or 404 + if link == "Not found": + link = f"tg://proxy?server={host}&port={port}&secret={secret}" + + return { + "client_id": username, + "config": link, + "vpn_link": link + } + + def edit_client(self, protocol_type, client_id, new_params): + """Update existing client parameters via API and in config.""" + config_text = self._get_server_config() + api_payload = {} + + if 'telemt_quota' in new_params: + val = int(new_params['telemt_quota']) if new_params['telemt_quota'] else None + config_text = self._update_line_in_section(config_text, "access.user_data_quota", client_id, val) + api_payload['data_quota_bytes'] = val + + if 'telemt_max_ips' in new_params: + val = int(new_params['telemt_max_ips']) if new_params['telemt_max_ips'] else None + config_text = self._update_line_in_section(config_text, "access.user_max_unique_ips", client_id, val) + api_payload['max_unique_ips'] = val + + if 'telemt_expiry' in new_params: + val = new_params['telemt_expiry'] + quoted_val = f'"{val}"' if val else None + config_text = self._update_line_in_section(config_text, "access.user_expirations", client_id, quoted_val) + api_payload['expiration_rfc3339'] = val + + if 'secret' in new_params: + val = new_params['secret'] + quoted_val = f'"{val}"' if val else None + config_text = self._update_line_in_section(config_text, "access.users", client_id, quoted_val) + api_payload['secret'] = val + + if 'user_ad_tag' in new_params: + val = new_params['user_ad_tag'] + quoted_val = f'"{val}"' if val else None + config_text = self._update_line_in_section(config_text, "access.user_ad_tags", client_id, quoted_val) + api_payload['user_ad_tag'] = val + + if 'max_tcp_conns' in new_params: + val = int(new_params['max_tcp_conns']) if new_params['max_tcp_conns'] else None + config_text = self._update_line_in_section(config_text, "access.user_max_tcp_conns", client_id, val) + api_payload['max_tcp_conns'] = val + + # Save config to host + self.ssh.upload_file_sudo(config_text.replace('\r\n', '\n'), f"{self._config_path()}") + + # API call + self._api_request("PATCH", f"/v1/users/{client_id}", data=api_payload) + return {"status": "success"} + + def _update_line_in_section(self, config_text, section_name, client_id, value): + lines = config_text.split('\n') + section_start = -1 + section_end = -1 + for i, line in enumerate(lines): + if line.strip() == f"[{section_name}]": + section_start = i + elif section_start != -1 and line.strip().startswith('['): + section_end = i + break + + if section_end == -1: section_end = len(lines) + if section_start == -1: + if value is not None: + lines.append(f"[{section_name}]") + lines.append(f'{client_id} = {value}') + lines.append("") + return '\n'.join(lines) + + found = False + for i in range(section_start + 1, section_end): + line = lines[i].strip().lstrip('#').strip() + if line.startswith(f"{client_id} ") or line.startswith(f"{client_id}="): + if value is None: lines.pop(i) + else: lines[i] = f'{client_id} = {value}' + found = True + break + + if not found and value is not None: + lines.insert(section_start + 1, f'{client_id} = {value}') + + return '\n'.join(lines) + + def _insert_into_section(self, config_text, section_name, line_to_insert): + lines = config_text.split('\n') + section_start = -1 + for i, line in enumerate(lines): + if line.strip() == f"[{section_name}]": + section_start = i + break + if section_start == -1: + lines.append(f"[{section_name}]") + lines.append(line_to_insert) + lines.append("") + else: + lines.insert(section_start + 1, line_to_insert) + return '\n'.join(lines) + + def remove_client(self, protocol_type, client_id): + # 1. API + self._api_request("DELETE", f"/v1/users/{client_id}") + + # 2. Config + config_text = self._get_server_config() + lines = config_text.split('\n') + new_lines = [] + for line in lines: + stripped = line.strip().lstrip('#').strip() + if stripped.startswith(f"{client_id} ") or stripped.startswith(f"{client_id}="): + continue + new_lines.append(line) + self.ssh.upload_file_sudo('\n'.join(new_lines).replace('\r\n', '\n'), f"{self._config_path()}") + + def toggle_client(self, protocol_type, client_id, enable, restart=True): + # API doesn't have a direct "toggle", so we either set a huge quota or remove/re-add + # But for Telemt, commenting out in config is the persistent way. + # We'll use HUP after toggling in config. + + config_text = self._get_server_config() + lines = config_text.split('\n') + new_lines = [] + in_access_section = False + for line in lines: + stripped = line.strip() + if stripped.startswith('[access.'): in_access_section = True + elif stripped.startswith('['): in_access_section = False + + if in_access_section: + base_line = line.lstrip('#').strip() + if base_line.startswith(f"{client_id} ") or base_line.startswith(f"{client_id}="): + line = base_line if enable else f"# {base_line}" + new_lines.append(line) + + self.ssh.upload_file_sudo('\n'.join(new_lines).replace('\r\n', '\n'), f"{self._config_path()}") + + if enable: + # If enabling, we re-add via API since it might have been deleted from memory + secret = "" + users = self._parse_users_from_config('\n'.join(new_lines)) + secret = users.get(client_id, "") + if secret: + self._api_request("POST", "/v1/users", data={"username": client_id, "secret": secret}) + else: + # If disabling, we just delete from memory + self._api_request("DELETE", f"/v1/users/{client_id}") + + if restart: + self.ssh.run_sudo_command(f"docker kill -s HUP {self.container_name} || docker restart {self.container_name}") + + def get_client_config(self, protocol_type, client_id, host='', port=''): + resp = self._api_request("GET", f"/v1/users/{client_id}") + if resp and resp.get('ok'): + user = resp.get('data', {}) + links = user.get('links', {}) + if links.get('tls'): return links['tls'][0] + if links.get('secure'): return links['secure'][0] + if links.get('classic'): return links['classic'][0] + + clients = self.get_clients(protocol_type) + c = next((c for c in clients if c['clientId'] == client_id), None) + if c: + secret = c.get('userData', {}).get('token', '') + if secret: return f"tg://proxy?server={host}&port={port}&secret={secret}" + return "Not found" \ No newline at end of file diff --git a/managers/wireguard_manager.py b/managers/wireguard_manager.py new file mode 100644 index 0000000..b646cd3 --- /dev/null +++ b/managers/wireguard_manager.py @@ -0,0 +1,823 @@ +""" +WireGuard Protocol Manager - handles standard WireGuard protocol +installation, configuration, and client management on remote servers. + +Follows the same architecture as awg_manager.py, using: +- client/server_scripts/wireguard/ scripts as reference +- Docker container: amneziavpn/amnezia-wg (same as AWG Legacy) +- Standard wg/wg-quick tools +""" + +import json +import re +import secrets +import logging +from base64 import b64encode +from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey +from cryptography.hazmat.primitives import serialization + +logger = logging.getLogger(__name__) + +WG_DEFAULTS = { + 'port': '51820', + 'mtu': '1420', + 'subnet_address': '10.8.2.0', + 'subnet_cidr': '24', + 'subnet_ip': '10.8.2.1', + 'dns1': '1.1.1.1', + 'dns2': '1.0.0.1', +} + + +def generate_wg_keypair(): + """Generate a WireGuard X25519 keypair (private, public) as base64 strings.""" + private_key = X25519PrivateKey.generate() + private_bytes = private_key.private_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PrivateFormat.Raw, + encryption_algorithm=serialization.NoEncryption() + ) + public_bytes = private_key.public_key().public_bytes( + encoding=serialization.Encoding.Raw, + format=serialization.PublicFormat.Raw + ) + return b64encode(private_bytes).decode(), b64encode(public_bytes).decode() + + +def generate_psk(): + """Generate a WireGuard preshared key.""" + return b64encode(secrets.token_bytes(32)).decode() + + +class WireGuardManager: + """Manages standard WireGuard protocol installation and client management.""" + + PROTOCOL = 'wireguard' + CONTAINER_NAME = 'amnezia-wireguard' + DOCKER_IMAGE = 'amneziavpn/amnezia-wg:latest' + CONFIG_PATH = '/opt/amnezia/wireguard/wg0.conf' + KEY_DIR = '/opt/amnezia/wireguard' + CLIENTS_TABLE_PATH = '/opt/amnezia/wireguard/clientsTable' + INTERFACE = 'wg0' + + def __init__(self, ssh_manager): + self.ssh = ssh_manager + + # ===================== INSTALLATION ===================== + + def check_docker_installed(self): + """Check if Docker is installed and running.""" + out, err, code = self.ssh.run_command("docker --version 2>/dev/null") + if code != 0: + return False + out2, _, code2 = self.ssh.run_command( + "systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null" + ) + return 'active' in out2 or 'running' in out2.lower() + + def install_docker(self): + """Install Docker on the server.""" + script = r""" +if which apt-get > /dev/null 2>&1; then pm=$(which apt-get); silent_inst="-yq install"; check_pkgs="-yq update"; docker_pkg="docker.io"; dist="debian"; +elif which dnf > /dev/null 2>&1; then pm=$(which dnf); silent_inst="-yq install"; check_pkgs="-yq check-update"; docker_pkg="docker"; dist="fedora"; +elif which yum > /dev/null 2>&1; then pm=$(which yum); silent_inst="-y -q install"; check_pkgs="-y -q check-update"; docker_pkg="docker"; dist="centos"; +else echo "Packet manager not found"; exit 1; fi; +if [ "$dist" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive; fi; +if ! command -v docker > /dev/null 2>&1; then + $pm $check_pkgs; $pm $silent_inst $docker_pkg; + sleep 5; systemctl enable --now docker; sleep 5; +fi; +if [ "$(systemctl is-active docker)" != "active" ]; then + $pm $check_pkgs; $pm $silent_inst $docker_pkg; + sleep 5; systemctl start docker; sleep 5; +fi; +docker --version +""" + out, err, code = self.ssh.run_sudo_script(script, timeout=180) + if code != 0: + raise RuntimeError(f"Failed to install Docker: {err}") + return out + + def check_container_running(self): + """Check if WireGuard container is running.""" + out, _, code = self.ssh.run_sudo_command( + f"docker ps --filter name=^{self.CONTAINER_NAME}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def check_protocol_installed(self): + """Check if protocol is installed (container exists).""" + out, _, code = self.ssh.run_sudo_command( + f"docker ps -a --filter name=^{self.CONTAINER_NAME}$ --format '{{{{.Names}}}}'" + ) + return self.CONTAINER_NAME in out.strip().split('\n') + + def prepare_host(self): + """Prepare host for container.""" + dockerfile_folder = f"/opt/amnezia/{self.CONTAINER_NAME}" + script = f""" +mkdir -p {dockerfile_folder} +mkdir -p {self.KEY_DIR} +if ! docker network ls | grep -q amnezia-dns-net; then + docker network create --driver bridge --subnet=172.29.172.0/24 --opt com.docker.network.bridge.name=amn0 amnezia-dns-net +fi +""" + out, err, code = self.ssh.run_sudo_script(script) + if code != 0: + logger.warning(f"prepare_host warning: {err}") + return True + + def setup_firewall(self): + """Setup host firewall.""" + script = """ +sysctl -w net.ipv4.ip_forward=1 +iptables -C INPUT -p icmp --icmp-type echo-request -j DROP 2>/dev/null || iptables -A INPUT -p icmp --icmp-type echo-request -j DROP +iptables -C FORWARD -j DOCKER-USER 2>/dev/null || iptables -A FORWARD -j DOCKER-USER 2>/dev/null +""" + self.ssh.run_sudo_script(script) + return True + + def install_protocol(self, port=None): + """ + Full installation of WireGuard protocol. + Steps: install docker -> prepare host -> build container -> + configure container -> run container -> setup firewall + """ + if port is None: + port = WG_DEFAULTS['port'] + + results = [] + + # Step 1: Install Docker + if not self.check_docker_installed(): + results.append("Installing Docker...") + self.install_docker() + results.append("Docker installed successfully") + else: + results.append("Docker already installed") + + # Step 2: Prepare host + results.append("Preparing host...") + self.prepare_host() + results.append("Host prepared") + + # Step 3: Remove old container if exists + if self.check_protocol_installed(): + results.append("Removing old container...") + self.remove_container() + results.append("Old container removed") + + # Step 4: Build container + results.append("Building Docker image...") + dockerfile_folder = f"/opt/amnezia/{self.CONTAINER_NAME}" + + dockerfile_content = ( + f"FROM {self.DOCKER_IMAGE}\n" + f"\n" + f'LABEL maintainer="AmneziaVPN"\n' + f"\n" + f"RUN apk add --no-cache curl wireguard-tools dumb-init iptables bash\n" + f"RUN apk --update upgrade --no-cache\n" + f"\n" + f"RUN mkdir -p /opt/amnezia\n" + f'RUN echo "#!/bin/bash" > /opt/amnezia/start.sh && ' + f'echo "tail -f /dev/null" >> /opt/amnezia/start.sh\n' + f"RUN chmod a+x /opt/amnezia/start.sh\n" + f"\n" + f'ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ]\n' + ) + self.ssh.run_sudo_command(f"mkdir -p {dockerfile_folder}") + self.ssh.upload_file_sudo(dockerfile_content, f"{dockerfile_folder}/Dockerfile") + + out, err, code = self.ssh.run_sudo_command( + f"docker build --no-cache --pull -t {self.CONTAINER_NAME} {dockerfile_folder}", + timeout=300 + ) + if code != 0: + raise RuntimeError(f"Failed to build container: {err}") + results.append("Docker image built successfully") + + # Step 5: Run container + results.append("Starting container...") + run_cmd = f"""docker run -d \ +--restart always \ +--privileged \ +--cap-add=NET_ADMIN \ +--cap-add=SYS_MODULE \ +-p {port}:{port}/udp \ +-v /lib/modules:/lib/modules \ +--sysctl="net.ipv4.conf.all.src_valid_mark=1" \ +--name {self.CONTAINER_NAME} \ +{self.CONTAINER_NAME}""" + + out, err, code = self.ssh.run_sudo_command(run_cmd) + if code != 0: + raise RuntimeError(f"Failed to run container: {err}") + + # Connect to DNS network + self.ssh.run_sudo_command(f"docker network connect amnezia-dns-net {self.CONTAINER_NAME}") + + # Wait for container + results.append("Waiting for container to start...") + self._wait_container_running() + results.append("Container started") + + # Step 6: Configure container + results.append("Configuring WireGuard...") + self._configure_container(port) + results.append("WireGuard configured") + + # Step 7: Upload start script + results.append("Starting WireGuard service...") + self._upload_start_script(port) + results.append("WireGuard service started") + + # Step 8: Setup firewall + results.append("Setting up firewall...") + self.setup_firewall() + results.append("Firewall configured") + + return { + 'status': 'success', + 'protocol': self.PROTOCOL, + 'port': port, + 'log': results, + } + + def _wait_container_running(self, timeout=30): + """Wait for a container to be in 'running' state.""" + import time + last_status = 'unknown' + for i in range(timeout // 2): + out, _, _ = self.ssh.run_sudo_command( + f"docker inspect --format='{{{{.State.Status}}}}' {self.CONTAINER_NAME}" + ) + last_status = out.strip().strip("'\"") + if last_status == 'running': + time.sleep(1) + return True + time.sleep(2) + + logs_out, _, _ = self.ssh.run_sudo_command( + f"docker logs --tail 50 {self.CONTAINER_NAME} 2>&1" + ) + raise RuntimeError( + f"Container {self.CONTAINER_NAME} did not start within {timeout}s " + f"(status: {last_status}). Logs:\n{logs_out}" + ) + + def _configure_container(self, port): + """Configure the WireGuard container (generate keys and server config).""" + subnet_ip = WG_DEFAULTS['subnet_ip'] + subnet_cidr = WG_DEFAULTS['subnet_cidr'] + + config_script = f""" +mkdir -p {self.KEY_DIR} +cd {self.KEY_DIR} +WIREGUARD_SERVER_PRIVATE_KEY=$(wg genkey) +echo $WIREGUARD_SERVER_PRIVATE_KEY > {self.KEY_DIR}/wireguard_server_private_key.key + +WIREGUARD_SERVER_PUBLIC_KEY=$(echo $WIREGUARD_SERVER_PRIVATE_KEY | wg pubkey) +echo $WIREGUARD_SERVER_PUBLIC_KEY > {self.KEY_DIR}/wireguard_server_public_key.key + +WIREGUARD_PSK=$(wg genpsk) +echo $WIREGUARD_PSK > {self.KEY_DIR}/wireguard_psk.key + +cat > {self.CONFIG_PATH} </dev/null + +# Start WireGuard +if [ -f {self.CONFIG_PATH} ]; then wg-quick up {self.CONFIG_PATH}; fi + +# Allow traffic on the TUN interface +iptables -A INPUT -i {self.INTERFACE} -j ACCEPT +iptables -A FORWARD -i {self.INTERFACE} -j ACCEPT +iptables -A OUTPUT -o {self.INTERFACE} -j ACCEPT + +iptables -A FORWARD -i {self.INTERFACE} -o eth0 -s {subnet_ip}/{subnet_cidr} -j ACCEPT +iptables -A FORWARD -i {self.INTERFACE} -o eth1 -s {subnet_ip}/{subnet_cidr} -j ACCEPT + +iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT + +iptables -t nat -A POSTROUTING -s {subnet_ip}/{subnet_cidr} -o eth0 -j MASQUERADE +iptables -t nat -A POSTROUTING -s {subnet_ip}/{subnet_cidr} -o eth1 -j MASQUERADE + +tail -f /dev/null +""" + self.ssh.upload_file(start_script, "/tmp/_wg_start.sh") + self.ssh.run_sudo_command(f"docker cp /tmp/_wg_start.sh {self.CONTAINER_NAME}:/opt/amnezia/start.sh") + self.ssh.run_sudo_command(f"docker exec {self.CONTAINER_NAME} chmod +x /opt/amnezia/start.sh") + self.ssh.run_command("rm -f /tmp/_wg_start.sh") + + self.ssh.run_sudo_command(f"docker restart {self.CONTAINER_NAME}") + import time + time.sleep(5) + + def remove_container(self): + """Remove WireGuard container.""" + self.ssh.run_sudo_command(f"docker stop {self.CONTAINER_NAME}") + self.ssh.run_sudo_command(f"docker rm -fv {self.CONTAINER_NAME}") + self.ssh.run_sudo_command(f"docker rmi {self.CONTAINER_NAME}") + return True + + # ===================== CLIENT MANAGEMENT ===================== + + def _get_clients_table(self): + """Get the clients table from the server.""" + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} cat {self.CLIENTS_TABLE_PATH} 2>/dev/null" + ) + if code != 0 or not out.strip(): + return [] + try: + data = json.loads(out) + if isinstance(data, list): + return data + return [] + except json.JSONDecodeError: + return [] + + def _save_clients_table(self, clients_table): + """Save the clients table to the server.""" + content = json.dumps(clients_table, indent=2) + self.ssh.upload_file(content, "/tmp/_wg_clients.json") + self.ssh.run_sudo_command( + f"docker cp /tmp/_wg_clients.json {self.CONTAINER_NAME}:{self.CLIENTS_TABLE_PATH}" + ) + self.ssh.run_command("rm -f /tmp/_wg_clients.json") + + def _get_server_config(self): + """Get the server WireGuard config.""" + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} cat {self.CONFIG_PATH}" + ) + if code != 0: + raise RuntimeError(f"Failed to get server config: {err}") + return out + + def save_server_config(self, config_content): + """Save the server WireGuard config and restart container.""" + self.ssh.upload_file(config_content.replace('\r\n', '\n'), "/tmp/_wg_edit_config.conf") + self.ssh.run_sudo_command(f"docker cp /tmp/_wg_edit_config.conf {self.CONTAINER_NAME}:{self.CONFIG_PATH}") + self.ssh.run_command("rm -f /tmp/_wg_edit_config.conf") + self.ssh.run_sudo_command(f"docker restart {self.CONTAINER_NAME}") + + def _get_server_public_key(self): + """Get server public key.""" + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} cat {self.KEY_DIR}/wireguard_server_public_key.key" + ) + if code != 0: + raise RuntimeError(f"Failed to get server public key: {err}") + return out.strip() + + def _get_server_psk(self): + """Get server preshared key.""" + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} cat {self.KEY_DIR}/wireguard_psk.key" + ) + if code != 0: + raise RuntimeError(f"Failed to get PSK: {err}") + return out.strip() + + def _get_listen_port(self): + """Extract ListenPort from server config.""" + config = self._get_server_config() + for line in config.split('\n'): + if line.strip().startswith('ListenPort'): + return line.split('=', 1)[1].strip() + return WG_DEFAULTS['port'] + + def _get_used_ips(self): + """Get list of IPs already assigned in the config.""" + config = self._get_server_config() + ips = [] + for line in config.split('\n'): + line = line.strip() + if line.startswith('AllowedIPs'): + match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line) + if match: + ips.append(match.group(1)) + elif line.startswith('Address'): + match = re.search(r'(\d+\.\d+\.\d+\.\d+)', line) + if match: + ips.append(match.group(1)) + return ips + + def _get_next_ip(self): + """Calculate the next available IP for a new client.""" + used_ips = self._get_used_ips() + if not used_ips: + base = WG_DEFAULTS['subnet_address'] + parts = base.split('.') + parts[3] = '2' + return '.'.join(parts) + + last_ip = used_ips[-1] + parts = last_ip.split('.') + last_octet = int(parts[3]) + next_octet = last_octet + 1 + if next_octet > 254: + next_octet = 2 + parts[3] = str(next_octet) + return '.'.join(parts) + + def _parse_peers_from_config(self): + """Parse [Peer] sections from WireGuard server config.""" + try: + config = self._get_server_config() + except Exception: + return {} + peers = {} + current_key = None + for line in config.split('\n'): + line = line.strip() + if line == '[Peer]': + current_key = None + elif current_key is None and line.startswith('PublicKey'): + current_key = line.split('=', 1)[1].strip() + peers[current_key] = {'allowedIps': ''} + elif current_key and line.startswith('AllowedIPs'): + peers[current_key]['allowedIps'] = line.split('=', 1)[1].strip() + return peers + + def _parse_bytes(self, size_str): + """Parse human readable size string into bytes.""" + try: + parts = size_str.strip().split() + if len(parts) != 2: + return 0 + val, unit = float(parts[0]), parts[1] + units = {'B': 1, 'KiB': 1024, 'MiB': 1024**2, 'GiB': 1024**3, 'TiB': 1024**4} + return int(val * units.get(unit, 1)) + except Exception: + return 0 + + def _wg_show(self): + """Run 'wg show all' and parse output.""" + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} bash -c 'wg show all'" + ) + if code != 0 or not out.strip(): + return {} + + result = {} + current_peer = None + + for line in out.split('\n'): + line = line.strip() + if line.startswith('peer:'): + current_peer = line.split(':', 1)[1].strip() + result[current_peer] = {} + elif current_peer and ':' in line: + key, value = line.split(':', 1) + key = key.strip() + value = value.strip() + if key == 'latest handshake': + result[current_peer]['latestHandshake'] = value + elif key == 'transfer': + parts = value.split(',') + if len(parts) == 2: + received = parts[0].strip().replace(' received', '') + sent = parts[1].strip().replace(' sent', '') + result[current_peer]['dataReceived'] = received + result[current_peer]['dataSent'] = sent + result[current_peer]['dataReceivedBytes'] = self._parse_bytes(received) + result[current_peer]['dataSentBytes'] = self._parse_bytes(sent) + elif key == 'allowed ips': + result[current_peer]['allowedIps'] = value + return result + + def get_clients(self): + """Get list of all clients with live traffic data.""" + clients_table = self._get_clients_table() + + try: + wg_show_data = self._wg_show() + except Exception: + wg_show_data = {} + + known_ids = set() + for client in clients_table: + client_id = client.get('clientId', '') + known_ids.add(client_id) + if client_id in wg_show_data: + show_data = wg_show_data[client_id] + user_data = client.get('userData', {}) + user_data['latestHandshake'] = show_data.get('latestHandshake', '') + user_data['dataReceived'] = show_data.get('dataReceived', '') + user_data['dataSent'] = show_data.get('dataSent', '') + user_data['dataReceivedBytes'] = show_data.get('dataReceivedBytes', 0) + user_data['dataSentBytes'] = show_data.get('dataSentBytes', 0) + user_data['allowedIps'] = show_data.get('allowedIps', '') + client['userData'] = user_data + + # Pick up peers from conf not in clientsTable (native app clients) + try: + conf_peers = self._parse_peers_from_config() + for pub_key, peer_info in conf_peers.items(): + if pub_key in known_ids: + continue + show_data = wg_show_data.get(pub_key, {}) + allowed_ip = peer_info.get('allowedIps', '') or show_data.get('allowedIps', '') + ip_part = '' + if allowed_ip: + m = re.search(r'(\d+\.\d+\.\d+\.\d+)', allowed_ip) + if m: + ip_part = m.group(1) + display_name = f'External ({ip_part})' if ip_part else 'External (native app)' + clients_table.append({ + 'clientId': pub_key, + 'userData': { + 'clientName': display_name, + 'clientPrivateKey': '', + 'externalClient': True, + 'clientIp': ip_part, + 'latestHandshake': show_data.get('latestHandshake', ''), + 'dataReceived': show_data.get('dataReceived', ''), + 'dataSent': show_data.get('dataSent', ''), + 'dataReceivedBytes': show_data.get('dataReceivedBytes', 0), + 'dataSentBytes': show_data.get('dataSentBytes', 0), + 'allowedIps': allowed_ip, + } + }) + except Exception as e: + logger.warning(f'get_clients: failed to parse conf peers: {e}') + + return clients_table + + def add_client(self, client_name, server_host): + """ + Add a new client/peer to the WireGuard config. + Returns the client config string. + """ + # Generate client keys + client_priv_key, client_pub_key = generate_wg_keypair() + + # Get server info + server_pub_key = self._get_server_public_key() + psk = self._get_server_psk() + port = self._get_listen_port() + + # Get next available IP + client_ip = self._get_next_ip() + + dns1 = WG_DEFAULTS['dns1'] + dns2 = WG_DEFAULTS['dns2'] + + # Check if AmneziaDNS is installed + out, _, _ = self.ssh.run_sudo_command("docker ps -a --filter name=^amnezia-dns$ --format '{{.Names}}'") + if 'amnezia-dns' in out: + dns1 = '172.29.172.254' + + mtu = WG_DEFAULTS['mtu'] + + # Append peer to server config + peer_section = f""" +[Peer] +PublicKey = {client_pub_key} +PresharedKey = {psk} +AllowedIPs = {client_ip}/32 + +""" + escaped_peer = peer_section.replace("'", "'\\''") + self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} bash -c 'echo \"{escaped_peer}\" >> {self.CONFIG_PATH}'" + ) + + # Sync config without restart + self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} bash -c 'wg syncconf {self.INTERFACE} <(wg-quick strip {self.CONFIG_PATH})'" + ) + + # Update clients table + clients_table = self._get_clients_table() + new_client = { + 'clientId': client_pub_key, + 'userData': { + 'clientName': client_name, + 'creationDate': __import__('datetime').datetime.now().isoformat(), + 'clientPrivateKey': client_priv_key, + 'clientIp': client_ip, + 'psk': psk, + 'enabled': True, + } + } + clients_table.append(new_client) + self._save_clients_table(clients_table) + + # Build client config + client_config = f"""[Interface] +Address = {client_ip}/32 +DNS = {dns1}, {dns2} +PrivateKey = {client_priv_key} +MTU = {mtu} + +[Peer] +PublicKey = {server_pub_key} +PresharedKey = {psk} +AllowedIPs = 0.0.0.0/0, ::/0 +Endpoint = {server_host}:{port} +PersistentKeepalive = 25 +""" + return { + 'client_name': client_name, + 'client_id': client_pub_key, + 'client_ip': client_ip, + 'config': client_config, + } + + def get_client_config(self, client_id, server_host): + """Reconstruct client config from stored data.""" + clients_table = self._get_clients_table() + client = next((c for c in clients_table if c.get('clientId') == client_id), None) + if not client: + raise RuntimeError(f"Client {client_id} not found") + + ud = client.get('userData', {}) + client_priv_key = ud.get('clientPrivateKey', '') + client_ip = ud.get('clientIp', '') + psk = ud.get('psk', '') + + if not client_priv_key: + raise RuntimeError("Client private key not stored. Config cannot be reconstructed.") + + server_pub_key = self._get_server_public_key() + if not psk: + psk = self._get_server_psk() + + port = self._get_listen_port() + + dns1 = WG_DEFAULTS['dns1'] + dns2 = WG_DEFAULTS['dns2'] + + # Check if AmneziaDNS is installed + out, _, _ = self.ssh.run_sudo_command("docker ps -a --filter name=^amnezia-dns$ --format '{{.Names}}'") + if 'amnezia-dns' in out: + dns1 = '172.29.172.254' + + mtu = WG_DEFAULTS['mtu'] + + config = f"""[Interface] +Address = {client_ip}/32 +DNS = {dns1}, {dns2} +PrivateKey = {client_priv_key} +MTU = {mtu} + +[Peer] +PublicKey = {server_pub_key} +PresharedKey = {psk} +AllowedIPs = 0.0.0.0/0, ::/0 +Endpoint = {server_host}:{port} +PersistentKeepalive = 25 +""" + return config + + def toggle_client(self, client_id, enable): + """Enable or disable a client by adding/removing their [Peer] from server config.""" + if enable: + clients_table = self._get_clients_table() + client = next((c for c in clients_table if c.get('clientId') == client_id), None) + if not client: + raise RuntimeError(f"Client {client_id} not found") + + ud = client.get('userData', {}) + psk = ud.get('psk', '') or self._get_server_psk() + client_ip = ud.get('clientIp', '') + + peer_section = f""" +[Peer] +PublicKey = {client_id} +PresharedKey = {psk} +AllowedIPs = {client_ip}/32 + +""" + escaped_peer = peer_section.replace("'", "'\\''") + self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} bash -c 'echo \"{escaped_peer}\" >> {self.CONFIG_PATH}'" + ) + else: + # Remove peer from server config + config = self._get_server_config() + sections = config.split('[') + new_sections = [s for s in sections if s.strip() and client_id not in s] + new_config = '[' + '['.join(new_sections) + + self.ssh.upload_file(new_config, "/tmp/_wg_config.conf") + self.ssh.run_sudo_command( + f"docker cp /tmp/_wg_config.conf {self.CONTAINER_NAME}:{self.CONFIG_PATH}" + ) + self.ssh.run_command("rm -f /tmp/_wg_config.conf") + + # Sync config + self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} bash -c 'wg syncconf {self.INTERFACE} <(wg-quick strip {self.CONFIG_PATH})'" + ) + + # Update enabled status in clients table + clients_table = self._get_clients_table() + for c in clients_table: + if c.get('clientId') == client_id: + c.setdefault('userData', {})['enabled'] = enable + break + self._save_clients_table(clients_table) + + def remove_client(self, client_id): + """Remove a client from WireGuard config.""" + config = self._get_server_config() + sections = config.split('[') + new_sections = [s for s in sections if s.strip() and client_id not in s] + new_config = '[' + '['.join(new_sections) + + self.ssh.upload_file(new_config, "/tmp/_wg_config.conf") + self.ssh.run_sudo_command( + f"docker cp /tmp/_wg_config.conf {self.CONTAINER_NAME}:{self.CONFIG_PATH}" + ) + self.ssh.run_command("rm -f /tmp/_wg_config.conf") + + # Sync config + self.ssh.run_sudo_command( + f"docker exec -i {self.CONTAINER_NAME} bash -c 'wg syncconf {self.INTERFACE} <(wg-quick strip {self.CONFIG_PATH})'" + ) + + # Update clients table + clients_table = self._get_clients_table() + clients_table = [c for c in clients_table if c.get('clientId') != client_id] + self._save_clients_table(clients_table) + return True + + def get_server_status(self): + """Get detailed status of the WireGuard server.""" + info = { + 'container_exists': self.check_protocol_installed(), + 'container_running': False, + 'protocol': self.PROTOCOL, + } + + if info['container_exists']: + info['container_running'] = self.check_container_running() + if info['container_running']: + try: + config = self._get_server_config() + for line in config.split('\n'): + if 'ListenPort' in line: + info['port'] = line.split('=')[1].strip() + break + info['clients_count'] = len(self._get_clients_table()) + except Exception as e: + info['error'] = str(e) + + return info + + def get_traffic_stats(self): + """Get aggregate traffic stats for all clients.""" + try: + wg_data = self._wg_show() + except Exception: + return {} + + total_rx = 0 + total_tx = 0 + active_peers = 0 + active_ips = [] + + for peer_key, data in wg_data.items(): + rx = data.get('dataReceivedBytes', 0) + tx = data.get('dataSentBytes', 0) + total_rx += rx + total_tx += tx + if rx > 0 or tx > 0: + active_peers += 1 + allowed = data.get('allowedIps', '') + if allowed: + m = re.search(r'(\d+\.\d+\.\d+\.\d+)', allowed) + if m: + active_ips.append(m.group(1)) + + return { + 'total_rx_bytes': total_rx, + 'total_tx_bytes': total_tx, + 'active_connections': active_peers, + 'active_ips': active_ips, + } diff --git a/managers/xray_manager.py b/managers/xray_manager.py new file mode 100644 index 0000000..3483fa5 --- /dev/null +++ b/managers/xray_manager.py @@ -0,0 +1,800 @@ +import json +import os +import uuid +import logging +import base64 +import shlex +from datetime import datetime +import urllib.parse + +logger = logging.getLogger(__name__) + +class XrayManager: + """Manages Xray (VLESS-Reality) protocol installation and client management.""" + + PROTOCOL = 'xray' + CONTAINER_NAME = 'amnezia-xray' + IMAGE_NAME = 'amneziavpn/amnezia-xray' # or we can build it + + def __init__(self, ssh_manager, protocol='xray'): + self.ssh = ssh_manager + self.protocol = protocol or self.PROTOCOL + self.base_protocol = str(self.protocol).split('__', 1)[0] + self.instance = self._instance_index(self.protocol) + self.container_name = self._container_name(self.protocol) + self.image_name = self._image_name(self.protocol) + + def _instance_index(self, protocol): + parts = str(protocol or '').split('__', 1) + if len(parts) == 2: + try: + return max(1, int(parts[1])) + except ValueError: + return 1 + return 1 + + def _container_name(self, protocol=None): + idx = self._instance_index(protocol or self.protocol) + base_name = self.CONTAINER_NAME + return base_name if idx <= 1 else f'{base_name}-{idx}' + + def _image_name(self, protocol=None): + idx = self._instance_index(protocol or self.protocol) + base_name = self.IMAGE_NAME + return base_name if idx <= 1 else f'{base_name}-{idx}' + + def _config_dir(self): + return '/opt/amnezia/xray' if self.instance <= 1 else f'/opt/amnezia/xray-{self.instance}' + + def _config_path(self): + return f'{self._config_dir()}/server.json' + + def _list_xray_files(self): + """List filenames in the on-disk Xray config directory.""" + out, _, code = self.ssh.run_sudo_command(f"ls -1 {self._config_dir()} 2>/dev/null") + if code != 0: + return [] + return [f for f in out.strip().split('\n') if f] + + def _detect_layout(self): + """Pick which on-disk layout this installation uses. + + 'native' — official Amnezia client layout: xray_private.key, + xray_public.key, xray_short_id.key, xray_uuid.key plus a clientsTable + file without an extension. + 'panel' — legacy web-panel layout: meta.json + clientsTable.json. + + On a fresh node with no Xray files yet, defaults to 'native' so new + installs produce the same artifacts as the official client. + """ + if hasattr(self, '_cached_layout'): + return self._cached_layout + files = set(self._list_xray_files()) + if {'xray_private.key', 'xray_public.key'} & files: + layout = 'native' + elif 'meta.json' in files: + layout = 'panel' + else: + layout = 'native' + self._cached_layout = layout + return layout + + def _clients_table_filename(self): + return 'clientsTable' if self._detect_layout() == 'native' else 'clientsTable.json' + + def _clients_table_path(self): + return f'{self._config_dir()}/{self._clients_table_filename()}' + + def _read_remote_file(self, path): + """Read a remote text file, preferring the running container's view.""" + out, _, code = self.ssh.run_sudo_command( + f"docker exec {self.container_name} cat {path} 2>/dev/null" + ) + if code != 0 or not out: + out, _, code = self.ssh.run_sudo_command(f"cat {path} 2>/dev/null") + if code != 0 or not out.strip(): + return None + return out + + def _derive_pubkey_from_priv(self, priv_key): + """Derive the Reality public key from a private key via the xray binary. + Used as a fallback when xray_public.key is missing or unreadable. + """ + if not priv_key: + return '' + out, _, code = self.ssh.run_sudo_command( + f"docker exec {self.container_name} /usr/bin/xray x25519 -i {priv_key}" + ) + if code != 0 or not out.strip(): + out, _, code = self.ssh.run_sudo_command( + f"docker run --rm --entrypoint=\"\" {self.image_name} /usr/bin/xray x25519 -i {priv_key}" + ) + if code != 0 or not out: + return '' + for line in out.split('\n'): + if 'Public' in line and ':' in line: + return line.split(':', 1)[1].strip() + return '' + + def _get_default_xray_uuid(self): + """UUID of the install-time default client (xray_uuid.key) — meaningful only + for native-layout installs. Imports skip this UUID, mirroring the official + Amnezia client behaviour (see usersController.cpp::getXrayClients). + """ + if self._detect_layout() != 'native': + return '' + out = self._read_remote_file(f"{self._config_dir()}/xray_uuid.key") + return (out or '').strip() + + # ===================== INSTALLATION ===================== + + def check_docker_installed(self): + out, err, code = self.ssh.run_command("docker --version 2>/dev/null") + if code != 0: return False + out2, _, code2 = self.ssh.run_command("systemctl is-active docker 2>/dev/null || service docker status 2>/dev/null") + return 'active' in out2 or 'running' in out2.lower() + + def check_container_running(self): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps --filter name=^{self.container_name}$ --format '{{{{.Status}}}}'" + ) + return 'Up' in out + + def check_protocol_installed(self): + out, _, _ = self.ssh.run_sudo_command( + f"docker ps -a --filter name=^{self.container_name}$ --format '{{{{.Names}}}}'" + ) + return self.container_name in out.strip().split('\n') + + def get_server_status(self, protocol): + exists = self.check_protocol_installed() + running = self.check_container_running() + clients = self.get_clients() if exists else [] + meta = self._get_meta_json() if exists else {} + return { + 'container_exists': exists, + 'container_running': running, + 'clients_count': len(clients), + 'port': meta.get('port') + } + + def install_protocol(self, port=443, site_name='yahoo.com'): + """Full installation of Xray.""" + results = [] + + if not self.check_docker_installed(): + results.append("Installing Docker...") + # Using same install method as AWGManager or assume it's installed + pass + + results.append("Removing old container if exists...") + if self.check_protocol_installed(): + self.remove_container() + + results.append("Building Docker image...") + config_dir = self._config_dir() + dockerfile_folder = f"/opt/amnezia/{self.container_name}" + dockerfile_content = f"""FROM alpine:3.15 +RUN apk add --no-cache curl unzip bash openssl netcat-openbsd dumb-init rng-tools xz iptables ip6tables +RUN apk --update upgrade --no-cache +RUN mkdir -p {config_dir} +RUN curl -L -H "Cache-Control: no-cache" -o /root/xray.zip "https://github.com/XTLS/Xray-core/releases/download/v26.3.27/Xray-linux-64.zip" && \\ + unzip /root/xray.zip -d /usr/bin/ && \\ + chmod a+x /usr/bin/xray && \\ + rm /root/xray.zip + +# Tune network +RUN echo "fs.file-max = 51200" >> /etc/sysctl.conf && \\ + echo "net.core.rmem_max = 67108864" >> /etc/sysctl.conf && \\ + echo "net.core.wmem_max = 67108864" >> /etc/sysctl.conf && \\ + echo "net.core.netdev_max_backlog = 250000" >> /etc/sysctl.conf && \\ + echo "net.core.somaxconn = 4096" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_syncookies = 1" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_tw_reuse = 1" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_tw_recycle = 0" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_fin_timeout = 30" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_keepalive_time = 1200" >> /etc/sysctl.conf && \\ + echo "net.ipv4.ip_local_port_range = 10000 65000" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_max_syn_backlog = 8192" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_max_tw_buckets = 5000" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_fastopen = 3" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_mem = 25600 51200 102400" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_rmem = 4096 87380 67108864" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_wmem = 4096 65536 67108864" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_mtu_probing = 1" >> /etc/sysctl.conf && \\ + echo "net.ipv4.tcp_congestion_control = hybla" >> /etc/sysctl.conf + +RUN mkdir -p /etc/security && \\ + echo "* soft nofile 51200" >> /etc/security/limits.conf && \\ + echo "* hard nofile 51200" >> /etc/security/limits.conf + +RUN echo '#!/bin/bash' > /opt/amnezia/start.sh && \\ + echo 'sysctl -p /etc/sysctl.conf 2>/dev/null' >> /opt/amnezia/start.sh && \\ + echo '/usr/bin/xray -config {config_dir}/server.json' >> /opt/amnezia/start.sh && \\ + chmod a+x /opt/amnezia/start.sh + +ENTRYPOINT [ "dumb-init", "/opt/amnezia/start.sh" ] +""" + self.ssh.run_sudo_command(f"mkdir -p {dockerfile_folder}") + self.ssh.upload_file_sudo(dockerfile_content, f"{dockerfile_folder}/Dockerfile") + + _, err, code = self.ssh.run_sudo_command( + f"docker build --no-cache -t {self.image_name} {dockerfile_folder}", timeout=300 + ) + if code != 0: raise RuntimeError(f"Failed to build container: {err}") + + results.append("Generating keys and config...") + # We generate a base config using a temp container or directly if host has openssl + + # Xray keypair generation using a temporary run overriding the entrypoint + keypair_cmd = f"docker run --rm --entrypoint=\"\" {self.image_name} /usr/bin/xray x25519" + out_kp, err_kp, code_kp = self.ssh.run_sudo_command(keypair_cmd) + if code_kp != 0: raise RuntimeError(f"Failed to generate x25519 keys: {err_kp}") + + priv_key = "" + pub_key = "" + for line in out_kp.split('\n'): + if "Private" in line: priv_key = line.split(":", 1)[1].strip() + if "Public" in line: pub_key = line.split(":", 1)[1].strip() + + short_id_cmd = f"docker run --rm --entrypoint=\"\" {self.image_name} openssl rand -hex 8" + out_sid, _, _ = self.ssh.run_sudo_command(short_id_cmd) + short_id = out_sid.strip() + + # Generate initial server.json with Stats and API enabled + server_json = { + "log": {"loglevel": "error"}, + "stats": {}, + "api": { + "services": ["StatsService", "LoggerService", "HandlerService"], + "tag": "api" + }, + "policy": { + "levels": { + "0": {"statsUserUplink": True, "statsUserDownlink": True} + }, + "system": { + "statsInboundUplink": True, "statsInboundDownlink": True, + "statsOutboundUplink": True, "statsOutboundDownlink": True + } + }, + "inbounds": [ + { + "port": int(port), + "protocol": "vless", + "tag": "proxy", + "settings": { + "clients": [], + "decryption": "none" + }, + "streamSettings": { + "network": "tcp", + "security": "reality", + "realitySettings": { + "dest": f"{site_name}:443", + "serverNames": [site_name], + "privateKey": priv_key, + "shortIds": [short_id] + } + } + }, + { + "listen": "127.0.0.1", + "port": 10085, + "protocol": "dokodemo-door", + "settings": {"address": "127.0.0.1"}, + "tag": "api" + } + ], + "outbounds": [{"protocol": "freedom"}], + "routing": { + "rules": [ + { + "inboundTag": ["api"], + "outboundTag": "api", + "type": "field" + } + ] + } + } + + self.ssh.run_sudo_command(f"mkdir -p {config_dir}") + self.ssh.upload_file_sudo(json.dumps(server_json, indent=2), f"{config_dir}/server.json") + # Native layout — separate key files matching the official Amnezia client install. + # See client/server_scripts/xray/configure_container.sh for the canonical layout. + self.ssh.upload_file_sudo(priv_key + '\n', "/opt/amnezia/xray/xray_private.key") + self.ssh.upload_file_sudo(pub_key + '\n', "/opt/amnezia/xray/xray_public.key") + self.ssh.upload_file_sudo(short_id + '\n', "/opt/amnezia/xray/xray_short_id.key") + # xray_uuid.key marks the install-time "default" client whose ID gets skipped on + # auto-import. Panel installs do not reserve such a client, so we leave it empty. + self.ssh.upload_file_sudo('\n', "/opt/amnezia/xray/xray_uuid.key") + self.ssh.upload_file_sudo("[]", "/opt/amnezia/xray/clientsTable") + + results.append("Starting container...") + run_cmd = f"""docker run -d \\ +--restart always \\ +--privileged \\ +--cap-add=NET_ADMIN \\ +-p {port}:{port}/tcp \\ +-p {port}:{port}/udp \\ +-v {config_dir}:{config_dir} \\ +--name {self.container_name} \\ +{self.image_name}""" + + _, err, code = self.ssh.run_sudo_command(run_cmd) + if code != 0: raise RuntimeError(f"Failed to run container: {err}") + + # Try to connect to network if needed + self.ssh.run_sudo_command(f"docker network connect amnezia-dns-net {self.container_name} || true") + + results.append("Xray configured and running") + return {'status': 'success', 'protocol': self.protocol, 'port': port, 'log': results} + + def remove_container(self): + self.ssh.run_sudo_command(f"docker stop {self.container_name}") + self.ssh.run_sudo_command(f"docker rm -fv {self.container_name}") + if self.instance <= 1: + self.ssh.run_sudo_command(f"docker rmi {self.image_name}") + return True + + # ===================== CLIENT MANAGEMENT ===================== + + def _get_server_json(self): + """Read server.json — tries inside container first, falls back to host path.""" + out, _, code = self.ssh.run_sudo_command( + f"docker exec {self.container_name} cat {self._config_path()}" + ) + if code != 0: + out, _, code = self.ssh.run_sudo_command(f"cat {self._config_path()}") + if code != 0 or not out.strip(): + return None + return json.loads(out) + + def _save_server_json(self, data): + return self._write_server_json(data, restart=True) + + def _write_server_json(self, data, restart=True): + """Write server.json into container via docker cp AND sync to host path.""" + tmp_file = "/tmp/_xray_server.json" + self.ssh.upload_file_sudo(json.dumps(data, indent=2), tmp_file) + self.ssh.run_sudo_command( + f"docker cp {tmp_file} {self.container_name}:{self._config_path()}" + ) + # Also keep host copy in sync (handles both volume-mount and no-mount installs) + self.ssh.run_sudo_command( + f"cp {tmp_file} {self._config_path()} 2>/dev/null || true" + ) + if restart: + self.ssh.run_sudo_command(f"docker restart {self.container_name}") + + def _get_vless_inbound(self, config): + for inbound in config.get('inbounds', []): + if inbound.get('protocol') == 'vless': + return inbound + return None + + def _get_vless_inbound_tag(self, config): + inbound = self._get_vless_inbound(config) + return inbound.get('tag') if inbound else None + + def _run_xray_api_json(self, subcommand, payload): + tmp_name = f"/tmp/_xray_api_{uuid.uuid4().hex}.json" + container_tmp = tmp_name + try: + self.ssh.upload_file_sudo(json.dumps(payload, indent=2), tmp_name) + _, err, code = self.ssh.run_sudo_command( + f"docker cp {tmp_name} {self.container_name}:{container_tmp}" + ) + if code != 0: + return False, err + out, err, code = self.ssh.run_sudo_command( + f"docker exec -i {self.container_name} /usr/bin/xray api {subcommand} " + f"-server=127.0.0.1:10085 {container_tmp}" + ) + return code == 0, err or out + finally: + self.ssh.run_sudo_command(f"rm -f {tmp_name}") + self.ssh.run_sudo_command(f"docker exec -i {self.container_name} rm -f {container_tmp} 2>/dev/null || true") + + def _xray_api_add_user(self, config, client): + tag = self._get_vless_inbound_tag(config) + if not tag: + return False + payload = { + "inbounds": [{ + "tag": tag, + "protocol": "vless", + "settings": { + "clients": [client], + "decryption": "none", + } + }] + } + ok, message = self._run_xray_api_json('adu', payload) + if not ok: + logger.warning(f"Xray API add user failed: {message}") + return False + return True + + def _xray_api_remove_user(self, config, client_id): + tag = self._get_vless_inbound_tag(config) + if not tag: + return False + cmd = ( + f"docker exec -i {self.container_name} /usr/bin/xray api rmu " + f"-server=127.0.0.1:10085 " + f"-tag={shlex.quote(tag)} {shlex.quote(client_id)}" + ) + out, err, code = self.ssh.run_sudo_command(cmd) + if code != 0: + logger.warning(f"Xray API remove user failed: {err or out}") + return False + return True + + def _get_meta_json(self): + """Read protocol metadata. Supports both layouts. + + Native layout pulls keys from xray_*.key files. Panel layout reads + meta.json. Either way, port and site_name come from server.json since + that is the authoritative runtime config — meta.json may go stale if + the user edits server.json directly via the panel. + """ + config = self._get_server_json() or {} + + port = None + site_name = None + rs = {} + try: + ib = next(b for b in config.get('inbounds', []) if b.get('protocol') == 'vless') + port = ib.get('port') + rs = ib.get('streamSettings', {}).get('realitySettings', {}) or {} + names = rs.get('serverNames') or [] + if names: + site_name = names[0] + except StopIteration: + pass + + if self._detect_layout() == 'native': + priv = (self._read_remote_file(f"{self._config_dir()}/xray_private.key") or '').strip() + pub = (self._read_remote_file(f"{self._config_dir()}/xray_public.key") or '').strip() + sid = (self._read_remote_file(f"{self._config_dir()}/xray_short_id.key") or '').strip() + if not priv: + priv = rs.get('privateKey', '') + if not sid: + sids = rs.get('shortIds') or [] + sid = sids[0] if sids else '' + if not pub: + pub = self._derive_pubkey_from_priv(priv) + return { + 'private_key': priv, + 'public_key': pub, + 'short_id': sid, + 'port': port, + 'site_name': site_name or 'yahoo.com', + } + + # Panel (legacy) layout + out = self._read_remote_file(f"{self._config_dir()}/meta.json") + meta = {} + if out: + try: + meta = json.loads(out) + except Exception: + meta = {} + if port is not None: + meta['port'] = port + if site_name: + meta['site_name'] = site_name + if not meta.get('private_key'): + meta['private_key'] = rs.get('privateKey', '') + if not meta.get('short_id'): + sids = rs.get('shortIds') or [] + if sids: + meta['short_id'] = sids[0] + if not meta.get('public_key') and meta.get('private_key'): + meta['public_key'] = self._derive_pubkey_from_priv(meta['private_key']) + return meta + + def _get_clients_table(self): + """Read clientsTable, trying both layout filenames.""" + layout = self._detect_layout() + primary = 'clientsTable' if layout == 'native' else 'clientsTable.json' + fallback = 'clientsTable.json' if layout == 'native' else 'clientsTable' + for fname in (primary, fallback): + out = self._read_remote_file(f"{self._config_dir()}/{fname}") + if not out or not out.strip(): + continue + try: + return json.loads(out) + except Exception: + continue + return [] + + def _save_clients_table(self, data): + """Write clientsTable to the file matching the current layout, in both + the container and the host bind-mount. + """ + path = self._clients_table_path() + tmp_file = "/tmp/_xray_clients.json" + self.ssh.upload_file_sudo(json.dumps(data, indent=2), tmp_file) + self.ssh.run_sudo_command( + f"docker cp {tmp_file} {self.container_name}:{path}" + ) + self.ssh.run_sudo_command( + f"cp {tmp_file} {path} 2>/dev/null || true" + ) + + def _upgrade_config_for_stats(self, config, restart=True): + """Injects API and Stats blocks into older Xray configs transparently.""" + dirty = False + if 'stats' not in config: + config['stats'] = {} + dirty = True + if 'api' not in config: + config['api'] = {"services": ["StatsService", "LoggerService", "HandlerService"], "tag": "api"} + dirty = True + else: + services = config['api'].setdefault('services', []) + if 'HandlerService' not in services: + services.append('HandlerService') + dirty = True + if 'policy' not in config: + config['policy'] = { + "levels": {"0": {"statsUserUplink": True, "statsUserDownlink": True}}, + "system": {"statsInboundUplink": True, "statsInboundDownlink": True, "statsOutboundUplink": True, "statsOutboundDownlink": True} + } + dirty = True + if 'routing' not in config: + config['routing'] = {"rules": [{"inboundTag": ["api"], "outboundTag": "api", "type": "field"}]} + dirty = True + + has_api_inbound = any(ib.get('tag') == 'api' for ib in config.get('inbounds', [])) + if not has_api_inbound: + config.setdefault('inbounds', []).append({ + "listen": "127.0.0.1", + "port": 10085, + "protocol": "dokodemo-door", + "settings": {"address": "127.0.0.1"}, + "tag": "api" + }) + dirty = True + + for ib in config.get('inbounds', []): + if ib.get('protocol') == 'vless': + if not ib.get('tag'): + ib['tag'] = 'proxy' + dirty = True + for c in ib.get('settings', {}).get('clients', []): + if 'email' not in c: + c['email'] = c['id'] + dirty = True + + if dirty: + self._write_server_json(config, restart=restart) + return dirty + + def _query_xray_stats(self): + """Query Xray API for traffic stats using xray api command.""" + out, _, code = self.ssh.run_sudo_command( + f"docker exec -i {self.container_name} /usr/bin/xray api statsquery -server=127.0.0.1:10085" + ) + if code != 0 or not out.strip(): + return {} + + try: + stats_raw = json.loads(out) + except Exception: + return {} + + results = {} + # Output format: {"stat": [{"name": "user>>>uid>>>traffic>>>downlink", "value": "123"}, ...]} + for item in stats_raw.get('stat', []): + name_parts = item.get('name', '').split('>>>') + if len(name_parts) == 4 and name_parts[0] == 'user': + uid = name_parts[1] + t_type = name_parts[3] # uplink or downlink + val = int(item.get('value', 0)) + + if uid not in results: + results[uid] = {'rx': 0, 'tx': 0} + + if t_type == 'downlink': + results[uid]['rx'] = val + elif t_type == 'uplink': + results[uid]['tx'] = val + + return results + + def _format_bytes(self, size): + # Format bytes to string like AWG (e.g., 1.50 MiB) + power = 2**10 + n = 0 + powers = {0: 'B', 1: 'KiB', 2: 'MiB', 3: 'GiB', 4: 'TiB'} + while size > power: + size /= power + n += 1 + v = round(size, 2) + if v == int(v): + v = int(v) + return f"{v} {powers.get(n, 'B')}" + + def get_clients(self, protocol=None): + config = self._get_server_json() + if not config: + return [] + + self._upgrade_config_for_stats(config, restart=False) + + # Collect all client IDs currently registered in the Xray server config + xray_clients = [] + for ib in config.get('inbounds', []): + if ib.get('protocol') == 'vless': + xray_clients.extend(ib.get('settings', {}).get('clients', [])) + + clients_table = self._get_clients_table() + table_ids = {c['clientId'] for c in clients_table} + + # Auto-import clients present in server.json but missing from clientsTable + # (e.g. added via the native Amnezia phone/desktop app). Skip the install-time + # default UUID for native-layout installs — the official client treats it as + # the device of the user who installed the server, not a manageable client. + default_uuid = self._get_default_xray_uuid() + updated = False + for xc in xray_clients: + uid = xc.get('id') + if not uid or uid in table_ids or uid == default_uuid: + continue + clients_table.append({ + 'clientId': uid, + 'userData': { + 'clientName': f'Imported_{uid[:8]}', + 'creationDate': datetime.now().isoformat(), + 'enabled': True + } + }) + table_ids.add(uid) + updated = True + logger.info(f"Auto-imported Xray client {uid[:8]} from server.json") + + if updated: + self._save_clients_table(clients_table) + + stats = self._query_xray_stats() + + for c in clients_table: + uid = c.get('clientId', '') + if uid in stats: + user_data = c.setdefault('userData', {}) + rx = stats[uid]['rx'] + tx = stats[uid]['tx'] + if rx > 0 or tx > 0: + user_data['dataReceived'] = self._format_bytes(rx) + user_data['dataSent'] = self._format_bytes(tx) + user_data['dataReceivedBytes'] = rx + user_data['dataSentBytes'] = tx + + return clients_table + + def get_client_config(self, protocol, client_id, server_host, port): + clients = self._get_clients_table() + client = next((c for c in clients if c['clientId'] == client_id), None) + if not client: return None + + meta = self._get_meta_json() + if not meta: return None + + config = self._get_server_json() + sni = meta.get('site_name', 'yahoo.com') + if config: + try: + sni = config['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0] + except Exception: + pass + + # Format URL + # vless://{id}@{host}:{port}?type=tcp&security=reality&pbk={public_key}&sni={sni}&fp=chrome&sid={short_id}&spx=%2F&flow=xtls-rprx-vision#{name} + + name = client.get('userData', {}).get('clientName', 'vpn') + encoded_name = urllib.parse.quote(name) + + url = ( + f"vless://{client_id}@{server_host}:{meta.get('port', port)}" + f"?type=tcp&security=reality&pbk={meta['public_key']}" + f"&sni={sni}&fp=chrome&sid={meta['short_id']}" + f"&spx=%2F&flow=xtls-rprx-vision#{encoded_name}" + ) + return url + + def add_client(self, protocol, client_name, server_host, port): + client_id = str(uuid.uuid4()) + + config = self._get_server_json() + if not config: raise RuntimeError("Xray server config not found.") + + self._upgrade_config_for_stats(config, restart=False) + + inbound = self._get_vless_inbound(config) + if not inbound: + raise RuntimeError("Xray VLESS inbound not found.") + + # Ensure clients structure exists + clients_node = inbound.setdefault('settings', {}).setdefault('clients', []) + client = { + "id": client_id, + "flow": "xtls-rprx-vision", + "email": client_id + } + if not self._xray_api_add_user(config, client): + raise RuntimeError( + "Xray runtime API is not available for hot user updates. " + "The server config was upgraded, but the container must be restarted once to enable HandlerService. " + "Restart the Xray container manually and try again." + ) + clients_node.append(client) + self._write_server_json(config, restart=False) + + # Update table + clients_table = self._get_clients_table() + clients_table.append({ + 'clientId': client_id, + 'userData': { + 'clientName': client_name, + 'creationDate': datetime.now().isoformat(), + 'enabled': True + } + }) + self._save_clients_table(clients_table) + + return { + 'client_id': client_id, + 'config': self.get_client_config(protocol, client_id, server_host, port) + } + + def toggle_client(self, protocol, client_id, enable): + config = self._get_server_json() + self._upgrade_config_for_stats(config, restart=False) + inbound = self._get_vless_inbound(config) + if not inbound: + raise RuntimeError("Xray VLESS inbound not found.") + clients_node = inbound.setdefault('settings', {}).setdefault('clients', []) + + # If toggling on and not present, we can re-add it from clientsTable + if enable: + if not any(c['id'] == client_id for c in clients_node): + client = { + "id": client_id, + "flow": "xtls-rprx-vision", + "email": client_id + } + if not self._xray_api_add_user(config, client): + raise RuntimeError("Xray runtime API failed to enable the client without restarting the container.") + clients_node.append(client) + else: + if not self._xray_api_remove_user(config, client_id): + raise RuntimeError("Xray runtime API failed to disable the client without restarting the container.") + inbound['settings']['clients'] = [c for c in clients_node if c['id'] != client_id] + + self._write_server_json(config, restart=False) + + clients_table = self._get_clients_table() + for c in clients_table: + if c['clientId'] == client_id: + c.setdefault('userData', {})['enabled'] = enable + self._save_clients_table(clients_table) + + def remove_client(self, protocol, client_id): + config = self._get_server_json() + self._upgrade_config_for_stats(config, restart=False) + inbound = self._get_vless_inbound(config) + if not inbound: + raise RuntimeError("Xray VLESS inbound not found.") + clients_node = inbound.setdefault('settings', {}).setdefault('clients', []) + if not self._xray_api_remove_user(config, client_id): + raise RuntimeError("Xray runtime API failed to remove the client without restarting the container.") + inbound['settings']['clients'] = [c for c in clients_node if c['id'] != client_id] + self._write_server_json(config, restart=False) + + clients_table = self._get_clients_table() + clients_table = [c for c in clients_table if c['clientId'] != client_id] + self._save_clients_table(clients_table) + return True diff --git a/protocol_telemt/Dockerfile b/protocol_telemt/Dockerfile new file mode 100644 index 0000000..11dd9d6 --- /dev/null +++ b/protocol_telemt/Dockerfile @@ -0,0 +1,108 @@ +# syntax=docker/dockerfile:1 + +ARG TELEMT_REPOSITORY=telemt/telemt +ARG TELEMT_VERSION=latest + +# ========================== +# Minimal Image +# ========================== +FROM debian:12-slim AS minimal + +ARG TARGETARCH +ARG TELEMT_REPOSITORY +ARG TELEMT_VERSION + +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + binutils \ + ca-certificates \ + curl \ + tar; \ + rm -rf /var/lib/apt/lists/* + +RUN set -eux; \ + case "${TARGETARCH}" in \ + amd64) ASSET="telemt-x86_64-linux-musl.tar.gz" ;; \ + arm64) ASSET="telemt-aarch64-linux-musl.tar.gz" ;; \ + *) echo "Unsupported TARGETARCH: ${TARGETARCH}" >&2; exit 1 ;; \ + esac; \ + VERSION="${TELEMT_VERSION#refs/tags/}"; \ + if [ -z "${VERSION}" ] || [ "${VERSION}" = "latest" ]; then \ + BASE_URL="https://github.com/${TELEMT_REPOSITORY}/releases/latest/download"; \ + else \ + BASE_URL="https://github.com/${TELEMT_REPOSITORY}/releases/download/${VERSION}"; \ + fi; \ + curl -fL \ + --retry 5 \ + --retry-delay 3 \ + --connect-timeout 10 \ + --max-time 120 \ + -o "/tmp/${ASSET}" \ + "${BASE_URL}/${ASSET}"; \ + curl -fL \ + --retry 5 \ + --retry-delay 3 \ + --connect-timeout 10 \ + --max-time 120 \ + -o "/tmp/${ASSET}.sha256" \ + "${BASE_URL}/${ASSET}.sha256"; \ + cd /tmp; \ + sha256sum -c "${ASSET}.sha256"; \ + tar -xzf "${ASSET}" -C /tmp; \ + test -f /tmp/telemt; \ + install -m 0755 /tmp/telemt /telemt; \ + strip --strip-unneeded /telemt || true; \ + rm -f "/tmp/${ASSET}" "/tmp/${ASSET}.sha256" /tmp/telemt + +# ========================== +# Debug Image +# ========================== +FROM debian:12-slim AS debug + +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + tzdata \ + curl \ + iproute2 \ + busybox; \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY --from=minimal /telemt /app/telemt +COPY config.toml /app/config.toml + +EXPOSE 443 9090 9091 + +ENTRYPOINT ["/app/telemt"] +CMD ["config.toml"] + +# ========================== +# Production Distroless on MUSL +# ========================== +#FROM gcr.io/distroless/static-debian12 AS prod +FROM debian:12-slim AS prod + +RUN set -eux; \ + apt-get update; \ + apt-get install -y --no-install-recommends \ + ca-certificates \ + tzdata \ + bash \ + curl; \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +COPY --from=minimal /telemt /app/telemt +COPY config.toml /app/config.toml + +#USER nonroot:nonroot + +EXPOSE 443 9090 9091 + +ENTRYPOINT ["/app/telemt"] +CMD ["config.toml"] diff --git a/protocol_telemt/config.toml b/protocol_telemt/config.toml new file mode 100644 index 0000000..b0b91f4 --- /dev/null +++ b/protocol_telemt/config.toml @@ -0,0 +1,62 @@ +### Telemt Based Config.toml +# We believe that these settings are sufficient for most scenarios +# where cutting-egde methods and parameters or special solutions are not needed + +# === General Settings === +[general] +use_middle_proxy = true +# Global ad_tag fallback when user has no per-user tag in [access.user_ad_tags] +# ad_tag = "00000000000000000000000000000000" +# Per-user ad_tag in [access.user_ad_tags] (32 hex from @MTProxybot) + +# === Log Level === +# Log level: debug | verbose | normal | silent +# Can be overridden with --silent or --log-level CLI flags +# RUST_LOG env var takes absolute priority over all of these +log_level = "normal" + +[general.modes] +classic = false +secure = false +tls = true + +[general.links] +show = "*" +# show = ["alice", "bob"] # Only show links for alice and bob +# show = "*" # Show links for all users +# public_host = "proxy.example.com" # Host (IP or domain) for tg:// links +public_port = 443 # Port for tg:// links (default: server.port) + +# === Server Binding === +[server] +port = 443 +# proxy_protocol = false # Enable if behind HAProxy/nginx with PROXY protocol +metrics_port = 9090 +metrics_listen = "0.0.0.0:9090" # Listen address for metrics (overrides metrics_port) +metrics_whitelist = ["127.0.0.1", "::1", "0.0.0.0/0"] +max_connections = 0 # 0 - unlimited, 10000 - default + +[server.api] +enabled = true +listen = "0.0.0.0:9091" +whitelist = ["127.0.0.0/8"] +minimal_runtime_enabled = false +minimal_runtime_cache_ttl_ms = 1000 + +# Listen on multiple interfaces/IPs - IPv4 +[[server.listeners]] +ip = "0.0.0.0" + +# === Anti-Censorship & Masking === +[censorship] +tls_domain = "petrovich.ru" +mask = false +tls_emulation = true # Fetch real cert lengths and emulate TLS records +tls_front_dir = "tlsfront" # Cache directory for TLS emulation +# mask_host = "172.17.0.1" # Docker host bridge IP +# mask_port = 8443 # Caddy порт +# mask_shape_hardening = true # anti-fingerprint + +[access.users] +# format: "username" = "32_hex_chars_secret" +hello = "00000000000000000000000000000000" diff --git a/protocol_telemt/docker-compose.yml b/protocol_telemt/docker-compose.yml new file mode 100644 index 0000000..d2bf5d5 --- /dev/null +++ b/protocol_telemt/docker-compose.yml @@ -0,0 +1,31 @@ +services: + telemt: + image: ghcr.io/telemt/telemt:latest + build: . + container_name: telemt + restart: unless-stopped + ports: + - "443:443" + - "127.0.0.1:9090:9090" + - "127.0.0.1:9091:9091" + # Allow caching 'proxy-secret' in read-only container + working_dir: /app/conf + volumes: + - .:/app/conf:rw + tmpfs: + - /run/telemt:rw,mode=1777,size=1m + environment: + - RUST_LOG=info + # Uncomment this line if you want to use host network for IPv6, but bridge is default and usually better + # network_mode: host + cap_drop: + - ALL + cap_add: + - NET_BIND_SERVICE # allow binding to port 443 + read_only: false + security_opt: + - no-new-privileges:true + ulimits: + nofile: + soft: 65536 + hard: 65536 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ac29a22 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,41 @@ +annotated-types==0.7.0 +anyio==4.12.1 +bcrypt==5.0.0 +blinker==1.9.0 +certifi==2026.2.25 +cffi==2.0.0 +click==8.3.1 +colorama==0.4.6 +cryptography==44.0.0 +fastapi==0.115.12 +Flask==3.1.0 +h11==0.16.0 +httpcore==1.0.9 +httptools==0.7.1 +httpx==0.25.2 +idna==3.11 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +multicolorcaptcha==1.2.0 +paramiko==3.5.1 +pillow==12.1.1 +pycparser==3.0 +pydantic==2.12.5 +pydantic_core==2.41.5 +PyNaCl==1.6.2 +psycopg[binary]==3.2.9 +psycopg_pool==3.2.6 +python-dotenv==1.2.2 +python-multipart==0.0.20 +python-telegram-bot==20.7 +PyYAML==6.0.3 +sniffio==1.3.1 +starlette==0.46.2 +typing-inspection==0.4.2 +typing_extensions==4.15.0 +uvicorn==0.34.0 +watchfiles==1.1.1 +websockets==16.0 +Werkzeug==3.1.6 + diff --git a/screen/panel1-2.png b/screen/panel1-2.png new file mode 100644 index 0000000000000000000000000000000000000000..486d58a6e991545d36c53393ca98e70f60722022 GIT binary patch literal 141967 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 Y0b?#@uIEj!KnH%VYZ@S{)omjG51J6@(f|Me literal 0 HcmV?d00001 diff --git a/screen/panel1-3.png b/screen/panel1-3.png new file mode 100644 index 0000000000000000000000000000000000000000..1df0f64fc7753d1f0c78f143f335f38e6c1be3a4 GIT binary patch literal 134360 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 literal 0 HcmV?d00001 diff --git a/screen/panel1.png b/screen/panel1.png new file mode 100644 index 0000000000000000000000000000000000000000..910b5beea8f062769ee57f7c21da67bb040527bc GIT binary patch literal 466574 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

y?l+mcMQ>AN?k=2jiF5-6f06xfQ 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

uYCk>yLO0%?AnjdeDcU^CPJ=R+>n>s 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

0?LJYS_N}hm@srTAl8+#zLgT9 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 + + + + + + + + + + diff --git a/static/js/qrcode.min.js b/static/js/qrcode.min.js new file mode 100644 index 0000000..993e88f --- /dev/null +++ b/static/js/qrcode.min.js @@ -0,0 +1 @@ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file diff --git a/telegram_bot.py b/telegram_bot.py new file mode 100644 index 0000000..48fe59b --- /dev/null +++ b/telegram_bot.py @@ -0,0 +1,1137 @@ +""" +Telegram bot for Amnezia Web Panel. +Uses raw Telegram Bot API via httpx — no library version conflicts. +Runs as a background asyncio task alongside the FastAPI app. +""" +import asyncio +import html +import logging +import os +import shlex +import sys +import time +import uuid +from typing import Optional, Callable + +import httpx + +logger = logging.getLogger(__name__) + +# ----------------------------------------------------------------------- # +# Global state +# ----------------------------------------------------------------------- # +_bot_task: Optional[asyncio.Task] = None +_callback_refs = {} +_pending_inputs = {} + +CLIENT_PROTOCOLS = {"awg", "awg2", "awg_legacy", "xray", "telemt", "wireguard"} +SERVICE_PROTOCOLS = {"dns", "adguard", "socks5", "nginx"} + + +# ----------------------------------------------------------------------- # +# Public lifecycle +# ----------------------------------------------------------------------- # +def is_running() -> bool: + return _bot_task is not None and not _bot_task.done() + + +def launch_bot(token: str, load_data_fn: Callable, generate_vpn_link_fn: Callable, save_data_fn: Optional[Callable] = None): + global _bot_task + _bot_task = asyncio.create_task( + _run_bot(token, load_data_fn, generate_vpn_link_fn, save_data_fn), + name="telegram_bot", + ) + return _bot_task + + +async def stop_bot(): + global _bot_task + if _bot_task and not _bot_task.done(): + _bot_task.cancel() + try: + await _bot_task + except asyncio.CancelledError: + pass + _bot_task = None + logger.info("Telegram bot stopped.") + + +# ----------------------------------------------------------------------- # +# Low-level Telegram API helpers +# ----------------------------------------------------------------------- # +class TelegramAPI: + def __init__(self, token: str, client: httpx.AsyncClient): + self.base = f"https://api.telegram.org/bot{token}" + self.client = client + + async def call(self, method: str, **params) -> dict: + r = await self.client.post(f"{self.base}/{method}", json=params, timeout=30) + return r.json() + + async def get_updates(self, offset: int = 0, timeout: int = 25) -> list: + r = await self.client.post( + f"{self.base}/getUpdates", + json={"offset": offset, "timeout": timeout, "allowed_updates": ["message", "callback_query"]}, + timeout=timeout + 10, + ) + data = r.json() + if data.get("ok"): + return data["result"] + return [] + + async def send_message(self, chat_id, text: str, reply_markup=None, parse_mode="HTML") -> dict: + import json + params = {"chat_id": chat_id, "text": text, "parse_mode": parse_mode} + if reply_markup: + params["reply_markup"] = json.dumps(reply_markup) + return await self.call("sendMessage", **params) + + async def edit_message(self, chat_id, message_id, text: str, reply_markup=None, parse_mode="HTML"): + import json + params = {"chat_id": chat_id, "message_id": message_id, "text": text, "parse_mode": parse_mode} + if reply_markup: + params["reply_markup"] = json.dumps(reply_markup) + await self.call("editMessageText", **params) + + async def answer_callback(self, callback_query_id: str, text: str = ""): + await self.call("answerCallbackQuery", callback_query_id=callback_query_id, text=text) + + async def send_document(self, chat_id, filename: str, content: bytes, caption: str = ""): + files = {"document": (filename, content, "text/plain")} + data = {"chat_id": str(chat_id), "caption": caption} + r = await self.client.post(f"{self.base}/sendDocument", data=data, files=files, timeout=30) + return r.json() + + +# ----------------------------------------------------------------------- # +# Generic helpers +# ----------------------------------------------------------------------- # +def _e(value) -> str: + return html.escape(str(value if value is not None else "")) + + +def _format_bytes(value) -> str: + try: + value = float(value or 0) + except Exception: + value = 0 + units = ["B", "KB", "MB", "GB", "TB"] + idx = 0 + while value >= 1024 and idx < len(units) - 1: + value /= 1024 + idx += 1 + if idx == 0: + return f"{int(value)} {units[idx]}" + return f"{value:.2f} {units[idx]}" + + +def _proto_base(protocol: str) -> str: + return str(protocol or "awg").split("__", 1)[0] + + +def _protocol_display_name(protocol: str) -> str: + base = _proto_base(protocol) + names = { + "awg": "AmneziaWG", + "awg2": "AmneziaWG 2.0", + "awg_legacy": "AmneziaWG Legacy", + "xray": "Xray", + "telemt": "Telemt", + "dns": "AmneziaDNS", + "wireguard": "WireGuard", + "socks5": "SOCKS5", + "adguard": "AdGuard Home", + "nginx": "NGINX", + } + name = names.get(base, base) + if "__" in str(protocol): + try: + return f"{name} #{int(str(protocol).split('__', 1)[1])}" + except Exception: + return name + return name + + +def _find_user(load_data_fn: Callable, tg_id: str): + data = load_data_fn() + tg_id_clean = str(tg_id).lstrip("@") + for u in data.get("users", []): + stored = str(u.get("telegramId", "") or "").lstrip("@") + if stored and stored == tg_id_clean: + return u + return None + + +def _is_admin(panel_user: dict) -> bool: + return str((panel_user or {}).get("role", "")).lower() == "admin" + + +def _ref(action: str, payload: dict) -> str: + """Short callback_data indirection; Telegram callback_data is limited to 64 bytes.""" + key = uuid.uuid4().hex[:12] + _callback_refs[key] = {"action": action, "payload": payload, "ts": time.time()} + # Opportunistic cleanup. + if len(_callback_refs) > 500: + cutoff = time.time() - 6 * 3600 + for k in [k for k, v in _callback_refs.items() if v.get("ts", 0) < cutoff]: + _callback_refs.pop(k, None) + return f"r:{key}" + + +def _resolve_ref(data_str: str): + if not data_str.startswith("r:"): + return None + return _callback_refs.get(data_str[2:]) + + +def _build_connections_keyboard(conns: list, data: dict) -> dict: + """Build inline keyboard where each button = one connection.""" + rows = [] + servers = data.get("servers", []) + for c in conns: + sid = c.get("server_id", 0) + server_name = "Unknown" + if isinstance(sid, int) and sid < len(servers): + srv = servers[sid] + server_name = srv.get("name") or srv.get("host", "Unknown")[:20] + proto = c.get("protocol", "").upper() + name = c.get("name", "Connection") + label = f"🔐 {name} · {proto} · {server_name}" + rows.append([{"text": label, "callback_data": f"cfg:{c['id']}"}]) + rows.append([{"text": "🔄 Refresh list", "callback_data": "refresh"}]) + return {"inline_keyboard": rows} + + +def _connection_lookup(data: dict, server_id: int, proto: str) -> dict: + return { + c.get("client_id"): c + for c in data.get("user_connections", []) + if c.get("server_id") == server_id and c.get("protocol") == proto and c.get("client_id") + } + + +def _client_display_name(client: dict, conn: Optional[dict] = None) -> str: + if conn and conn.get("name"): + return conn.get("name") + user_data = client.get("userData") or {} + return ( + client.get("name") + or client.get("username") + or user_data.get("clientName") + or user_data.get("name") + or str(client.get("clientId") or client.get("client_id") or client.get("id") or "Connection")[:12] + ) + + +def _user_label(user: dict) -> str: + label = user.get("username") or user.get("id", "user") + role = user.get("role") or "user" + suffix = f" · {role}" + if user.get("telegramId"): + suffix += f" · tg:{user.get('telegramId')}" + if user.get("enabled") is False: + suffix += " · disabled" + return f"{label}{suffix}" + + +def _users_keyboard(data: dict, back_callback: str = "adm:menu") -> dict: + rows = [] + for user in data.get("users", [])[:40]: + rows.append([{"text": f"👤 {_user_label(user)}", "callback_data": _ref("user", {"uid": user.get("id")})}]) + rows.append([{"text": "⬅️ Back", "callback_data": back_callback}]) + return {"inline_keyboard": rows} + + +def _assign_user_keyboard(data: dict, server_id: int, proto: str, name: str) -> dict: + rows = [[{"text": "🚫 Do not assign", "callback_data": _ref("create_client", {"sid": server_id, "proto": proto, "name": name, "user_id": None})}]] + for user in data.get("users", [])[:40]: + rows.append([{"text": f"👤 {_user_label(user)}", "callback_data": _ref("create_client", {"sid": server_id, "proto": proto, "name": name, "user_id": user.get("id")})}]) + rows.append([{"text": "❌ Cancel", "callback_data": _ref("clients", {"sid": server_id, "proto": proto})}]) + return {"inline_keyboard": rows} + + +def _admin_main_keyboard() -> dict: + return { + "inline_keyboard": [ + [{"text": "🖥 Servers", "callback_data": "adm:servers"}], + [{"text": "👤 Users", "callback_data": "adm:users"}], + [{"text": "🔐 My connections", "callback_data": "adm:myconns"}], + [{"text": "➕ How to add a server", "callback_data": "adm:addserver_help"}], + ] + } + + +def _server_keyboard(data: dict) -> dict: + rows = [] + for sid, srv in enumerate(data.get("servers", [])): + name = srv.get("name") or srv.get("host") or f"Server {sid + 1}" + rows.append([{"text": f"🖥 {name}", "callback_data": f"srv:{sid}"}]) + rows.append([{"text": "⬅️ Admin menu", "callback_data": "adm:menu"}]) + return {"inline_keyboard": rows} + + +def _protocol_status_icon(info: dict) -> str: + if info.get("status_error"): + return "⚪" + running = info.get("container_running") + if running is True: + return "🟢" + if running is False: + return "🔴" + return "⚪" + + +def _protocol_status_text(info: dict) -> str: + if info.get("status_error"): + return "unknown ⚪" + running = info.get("container_running") + if running is True: + return "running 🟢" + if running is False: + return "stopped 🔴" + return "unknown ⚪" + + +def _protocols_keyboard(server_id: int, server: dict) -> dict: + rows = [] + protocols = server.get("protocols", {}) or {} + for proto, info in protocols.items(): + installed = "✅" if info.get("installed", True) else "⚪" + rows.append([{"text": f"{installed}{_protocol_status_icon(info)} {_protocol_display_name(proto)}", "callback_data": _ref("proto", {"sid": server_id, "proto": proto})}]) + if not rows: + rows.append([{"text": "No installed protocols", "callback_data": f"noop"}]) + rows.append([{"text": "⬅️ Servers", "callback_data": "adm:servers"}]) + return {"inline_keyboard": rows} + + +def _protocol_keyboard(server_id: int, proto: str, proto_info: dict) -> dict: + base = _proto_base(proto) + rows = [] + if base in CLIENT_PROTOCOLS: + rows.append([{"text": "👥 Connections", "callback_data": _ref("clients", {"sid": server_id, "proto": proto})}]) + rows.append([{"text": "➕ Create connection", "callback_data": _ref("add_client", {"sid": server_id, "proto": proto})}]) + is_running = proto_info.get("container_running") is True + rows.append([{"text": "⏹ Stop" if is_running else "▶️ Start", "callback_data": _ref("toggle_proto", {"sid": server_id, "proto": proto, "start": not is_running})}]) + rows.append([{"text": "⬅️ Protocols", "callback_data": f"srv:{server_id}"}]) + return {"inline_keyboard": rows} + + +def _client_keyboard(server_id: int, proto: str, client: dict) -> dict: + client_id = client.get("clientId") or client.get("client_id") or client.get("id") or "" + enabled = client.get("enabled") + if enabled is None: + enabled = client.get("isEnabled") + enabled = bool(enabled) if enabled is not None else True + return { + "inline_keyboard": [ + [{"text": "📄 Config", "callback_data": _ref("client_cfg", {"sid": server_id, "proto": proto, "client_id": client_id, "name": client.get("name") or client.get("username") or "Connection"})}], + [{"text": "🚫 Disable" if enabled else "✅ Enable", "callback_data": _ref("toggle_client", {"sid": server_id, "proto": proto, "client_id": client_id, "enable": not enabled})}], + [{"text": "🗑 Delete", "callback_data": _ref("remove_client", {"sid": server_id, "proto": proto, "client_id": client_id})}], + [{"text": "⬅️ Connections", "callback_data": _ref("clients", {"sid": server_id, "proto": proto})}], + ] + } + + +def _get_ssh_and_manager(server: dict, proto: str): + sys.path.insert(0, os.path.dirname(__file__)) + from managers.ssh_manager import SSHManager + from managers.awg_manager import AWGManager + from managers.xray_manager import XrayManager + from managers.telemt_manager import TelemtManager + from managers.wireguard_manager import WireGuardManager + from managers.dns_manager import DNSManager + from managers.socks5_manager import Socks5Manager + from managers.adguard_manager import AdguardManager + from managers.nginx_manager import NginxManager + + ssh = SSHManager( + server["host"], + server.get("ssh_port", 22), + server["username"], + server.get("password", ""), + server.get("private_key", ""), + ) + base = _proto_base(proto) + if base == "xray": + manager = XrayManager(ssh, proto) + elif base == "telemt": + manager = TelemtManager(ssh, proto) + elif base == "wireguard": + manager = WireGuardManager(ssh) + elif base == "dns": + manager = DNSManager(ssh) + elif base == "socks5": + manager = Socks5Manager(ssh, proto) + elif base == "adguard": + manager = AdguardManager(ssh) + elif base == "nginx": + manager = NginxManager(ssh, proto) + else: + manager = AWGManager(ssh) + return ssh, manager + + +def _manager_call(manager, method_name: str, proto: str, *args, **kwargs): + method = getattr(manager, method_name) + try: + return method(proto, *args, **kwargs) + except TypeError: + return method(*args, **kwargs) + + +def _refresh_server_protocol_statuses(server: dict) -> dict: + """Refresh saved protocol metadata with live Docker status for Telegram admin views.""" + protocols = server.get("protocols", {}) or {} + if not protocols: + return server + + ssh = None + try: + ssh, _ = _get_ssh_and_manager(server, "awg") + ssh.connect() + for proto, info in protocols.items(): + container = info.get("container_name") + if not container: + try: + _, manager = _get_ssh_and_manager(server, proto) + container = getattr(manager, "container_name", None) or getattr(manager, "CONTAINER_NAME", None) + except Exception: + container = None + if not container: + info["status_error"] = "Container name is unknown" + continue + out, err, code = ssh.run_sudo_command( + f"docker inspect -f '{{{{.State.Running}}}}' {shlex.quote(str(container))} 2>/dev/null" + ) + if code == 0: + info["container_running"] = out.strip().lower() == "true" + info["container_exists"] = True + info.pop("status_error", None) + else: + info["container_running"] = False + info["container_exists"] = False + info["status_error"] = (err or out or "container not found").strip() + except Exception as e: + logger.warning("Telegram bot: failed to refresh protocol statuses for %s: %s", server.get("name") or server.get("host"), e) + for info in protocols.values(): + info["status_error"] = str(e) + finally: + if ssh: + try: + ssh.disconnect() + except Exception: + pass + return server + + +async def _refresh_server_protocol_statuses_async(server: dict) -> dict: + return await asyncio.to_thread(_refresh_server_protocol_statuses, server) + + +# ----------------------------------------------------------------------- # +# /start and user connection handlers +# ----------------------------------------------------------------------- # +async def _handle_start(api: TelegramAPI, msg: dict, load_data_fn: Callable): + chat_id = msg["chat"]["id"] + tg_id = str(msg["from"]["id"]) + first_name = msg["from"].get("first_name", "") + + panel_user = _find_user(load_data_fn, tg_id) + + if not panel_user: + await api.send_message( + chat_id, + f"👋 Hi, {_e(first_name)}!\n\n" + "Your Telegram account is not linked to any panel user.\n" + "Please contact your administrator — they need to add your Telegram ID to your profile.\n\n" + f"Your Telegram ID: {_e(tg_id)}", + ) + return + + if _is_admin(panel_user): + await api.send_message( + chat_id, + f"👋 Hi, {_e(first_name)}!\n\n" + f"You are registered as {_e(panel_user.get('username'))} with Admin role.\n" + "Choose an action:", + reply_markup=_admin_main_keyboard(), + ) + return + + await _send_user_connections(api, chat_id, panel_user, load_data_fn, first_name=first_name) + + +async def _send_user_connections(api: TelegramAPI, chat_id: int, panel_user: dict, load_data_fn: Callable, first_name: str = ""): + data = load_data_fn() + conns = [c for c in data.get("user_connections", []) if c.get("user_id") == panel_user.get("id")] + + if not conns: + greeting = f"👋 Hi, {_e(first_name)}!\n\n" if first_name else "" + await api.send_message( + chat_id, + greeting + f"You are registered as {_e(panel_user.get('username'))}.\n\n" + "You have no connections yet. Please contact your administrator.", + ) + return + + kb = _build_connections_keyboard(conns, data) + greeting = f"👋 Hi, {_e(first_name)}!\n\n" if first_name else "" + await api.send_message( + chat_id, + greeting + f"You are registered as {_e(panel_user.get('username'))}.\n\n" + f"Your connections ({len(conns)}) — tap to get config:", + reply_markup=kb, + ) + + +async def _handle_refresh(api: TelegramAPI, chat_id: int, message_id: int, callback_id: str, tg_id: str, load_data_fn: Callable): + await api.answer_callback(callback_id, "Updated!") + panel_user = _find_user(load_data_fn, tg_id) + if not panel_user: + await api.edit_message(chat_id, message_id, "❌ Access denied.") + return + data = load_data_fn() + conns = [c for c in data.get("user_connections", []) if c.get("user_id") == panel_user.get("id")] + if not conns: + await api.edit_message(chat_id, message_id, "You have no connections.") + return + kb = _build_connections_keyboard(conns, data) + await api.edit_message(chat_id, message_id, f"Your connections ({len(conns)}) — tap to get config:", reply_markup=kb) + + +async def _handle_get_config(api: TelegramAPI, chat_id: int, message_id: int, callback_id: str, conn_id: str, tg_id: str, load_data_fn: Callable, generate_vpn_link_fn: Callable): + await api.answer_callback(callback_id, "Fetching config...") + + panel_user = _find_user(load_data_fn, tg_id) + if not panel_user: + await api.send_message(chat_id, "❌ Access denied.") + return + + data = load_data_fn() + conn = next((c for c in data.get("user_connections", []) if c.get("id") == conn_id and (_is_admin(panel_user) or c.get("user_id") == panel_user.get("id"))), None) + if not conn: + await api.send_message(chat_id, "❌ Connection not found.") + return + + servers = data.get("servers", []) + sid = conn.get("server_id") + if not isinstance(sid, int) or sid >= len(servers): + await api.send_message(chat_id, "❌ Server not found.") + return + + await _send_config_by_client(api, chat_id, servers[sid], conn.get("protocol", "awg"), conn.get("client_id"), conn.get("name", "Connection"), generate_vpn_link_fn) + + +async def _send_config_by_client(api: TelegramAPI, chat_id: int, server: dict, proto: str, client_id: str, conn_name: str, generate_vpn_link_fn: Callable): + loading_result = await api.send_message(chat_id, f"⏳ Fetching config for {_e(conn_name)}...") + loading_msg_id = loading_result.get("result", {}).get("message_id") + try: + proto_info = server.get("protocols", {}).get(proto, {}) + port = proto_info.get("port", "55424") + + def _get_cfg(): + ssh, manager = _get_ssh_and_manager(server, proto) + try: + ssh.connect() + return _manager_call(manager, "get_client_config", proto, client_id, server["host"], port) + finally: + ssh.disconnect() + + config = await asyncio.to_thread(_get_cfg) + if not config: + if loading_msg_id: + await api.edit_message(chat_id, loading_msg_id, "❌ Failed to retrieve configuration.") + return + + if loading_msg_id: + await api.call("deleteMessage", chat_id=chat_id, message_id=loading_msg_id) + + server_name = server.get("name") or server.get("host", "Unknown") + await api.send_message(chat_id, f"✅ {_e(conn_name)}\n🌐 Server: {_e(server_name)}\n🔌 Protocol: {_e(proto.upper())}") + + is_link_proto = _proto_base(proto) in ("xray", "telemt") + if is_link_proto: + await api.send_message(chat_id, f"🔗 Connection link (tap to copy):\n{_e(config)}") + else: + MAX_LEN = 4000 + if len(config) <= MAX_LEN: + await api.send_message(chat_id, f"📄 Configuration:\n

{_e(config)}
") + else: + chunks = [config[i:i + MAX_LEN] for i in range(0, len(config), MAX_LEN)] + for i, chunk in enumerate(chunks, 1): + await api.send_message(chat_id, f"📄 Configuration (part {i}/{len(chunks)}):\n
{_e(chunk)}
") + + vpn_link = generate_vpn_link_fn(config) if config else "" + if vpn_link: + await api.send_message(chat_id, f"🔗 VPN Link (tap to copy):\n{_e(vpn_link)}") + filename = f"{str(conn_name).replace(' ', '_')}.conf" + await api.send_document(chat_id, filename=filename, content=config.encode("utf-8"), caption=f"📁 Config file: {conn_name}") + except Exception as e: + logger.exception("Bot: error getting config") + if loading_msg_id: + await api.edit_message(chat_id, loading_msg_id, f"❌ Error: {_e(e)}") + else: + await api.send_message(chat_id, f"❌ Error: {_e(e)}") + + +# ----------------------------------------------------------------------- # +# Admin handlers +# ----------------------------------------------------------------------- # +def _require_admin(load_data_fn: Callable, tg_id: str): + user = _find_user(load_data_fn, tg_id) + if not user or not _is_admin(user): + return None + return user + + +async def _handle_add_server_command(api: TelegramAPI, msg: dict, load_data_fn: Callable, save_data_fn: Optional[Callable]): + chat_id = msg["chat"]["id"] + tg_id = str(msg["from"]["id"]) + if not _require_admin(load_data_fn, tg_id): + await api.send_message(chat_id, "❌ Access denied.") + return + if not save_data_fn: + await api.send_message(chat_id, "❌ Saving is not available for this bot instance.") + return + + text = msg.get("text", "") + parts = text.split(maxsplit=5) + if len(parts) < 4: + await api.send_message( + chat_id, + "Usage:\n" + "/addserver host username password [ssh_port] [name]\n\n" + "Example:\n" + "/addserver 203.0.113.10 root myPassword 22 Prod VPS\n\n" + "⚠️ Telegram messages are not a secrets manager. Prefer adding servers in the web panel if possible.", + ) + return + + host = parts[1] + username = parts[2] + password = parts[3] + ssh_port = 22 + name = host + if len(parts) >= 5: + try: + ssh_port = int(parts[4]) + except Exception: + name = parts[4] + if len(parts) >= 6: + name = parts[5] or host + + data = load_data_fn() + data.setdefault("servers", []).append({ + "name": name, + "host": host, + "ssh_port": ssh_port, + "username": username, + "password": password, + "private_key": "", + "protocols": {}, + "created_at": time.strftime("%Y-%m-%dT%H:%M:%S"), + }) + save_data_fn(data) + await api.send_message(chat_id, f"✅ Server added: {_e(name)}\nHost: {_e(host)}") + + +async def _admin_servers(api: TelegramAPI, chat_id: int, message_id: Optional[int], load_data_fn: Callable): + data = load_data_fn() + servers = data.get("servers", []) + text = f"🖥 Servers ({len(servers)})\n\nChoose a server:" + if message_id: + await api.edit_message(chat_id, message_id, text, reply_markup=_server_keyboard(data)) + else: + await api.send_message(chat_id, text, reply_markup=_server_keyboard(data)) + + +async def _admin_users(api: TelegramAPI, chat_id: int, message_id: int, load_data_fn: Callable): + data = load_data_fn() + users = data.get("users", []) + await api.edit_message(chat_id, message_id, f"👤 Users ({len(users)})\n\nChoose a user:", reply_markup=_users_keyboard(data)) + + +async def _admin_user_detail(api: TelegramAPI, chat_id: int, message_id: int, user_id: str, load_data_fn: Callable): + data = load_data_fn() + user = next((u for u in data.get("users", []) if u.get("id") == user_id), None) + if not user: + await api.edit_message(chat_id, message_id, "❌ User not found.", reply_markup={"inline_keyboard": [[{"text": "⬅️ Users", "callback_data": "adm:users"}]]}) + return + conns = [c for c in data.get("user_connections", []) if c.get("user_id") == user_id] + lines = [ + f"👤 {_e(user.get('username'))}", + f"Role: {_e(user.get('role', 'user'))}", + f"Enabled: {'yes ✅' if user.get('enabled', True) else 'no 🚫'}", + f"Telegram ID: {_e(user.get('telegramId') or '-')}", + f"Email: {_e(user.get('email') or '-')}", + f"Connections: {len(conns)}", + ] + if user.get("description"): + lines.append(f"Description: {_e(user.get('description'))}") + rows = [] + servers = data.get("servers", []) + for c in conns[:20]: + sid = c.get("server_id") + server_name = "Unknown" + if isinstance(sid, int) and sid < len(servers): + server_name = servers[sid].get("name") or servers[sid].get("host") or "Unknown" + rows.append([{"text": f"🔐 {c.get('name', 'Connection')} · {c.get('protocol', '').upper()} · {server_name}", "callback_data": f"cfg:{c.get('id')}"}]) + rows.append([{"text": "⬅️ Users", "callback_data": "adm:users"}]) + rows.append([{"text": "⬅️ Admin menu", "callback_data": "adm:menu"}]) + await api.edit_message(chat_id, message_id, "\n".join(lines), reply_markup={"inline_keyboard": rows}) + + +async def _admin_server_detail(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, load_data_fn: Callable): + data = load_data_fn() + servers = data.get("servers", []) + if server_id < 0 or server_id >= len(servers): + await api.edit_message(chat_id, message_id, "❌ Server not found.") + return + server = await _refresh_server_protocol_statuses_async(servers[server_id]) + protocols = server.get("protocols", {}) or {} + text = ( + f"🖥 {_e(server.get('name') or server.get('host'))}\n" + f"Host: {_e(server.get('host'))}\n" + f"SSH: {_e(server.get('username'))}@{_e(server.get('host'))}:{_e(server.get('ssh_port', 22))}\n\n" + f"Protocols ({len(protocols)}):" + ) + await api.edit_message(chat_id, message_id, text, reply_markup=_protocols_keyboard(server_id, server)) + + +async def _admin_protocol_detail(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, load_data_fn: Callable): + data = load_data_fn() + servers = data.get("servers", []) + if server_id < 0 or server_id >= len(servers): + await api.edit_message(chat_id, message_id, "❌ Server not found.") + return + server = await _refresh_server_protocol_statuses_async(servers[server_id]) + info = (server.get("protocols", {}) or {}).get(proto) + if not info: + await api.edit_message(chat_id, message_id, "❌ Protocol not found.") + return + lines = [ + f"🔌 {_e(_protocol_display_name(proto))}", + f"Server: {_e(server.get('name') or server.get('host'))}", + f"Status: {_protocol_status_text(info)}", + ] + for key in ("port", "container_name", "domain", "site_url", "web_port", "mode"): + if info.get(key) not in (None, ""): + lines.append(f"{_e(key)}: {_e(info.get(key))}") + if info.get("status_error"): + lines.append(f"status_error: {_e(info.get('status_error'))}") + await api.edit_message(chat_id, message_id, "\n".join(lines), reply_markup=_protocol_keyboard(server_id, proto, info)) + + +async def _admin_toggle_protocol(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, start: bool, load_data_fn: Callable): + await api.edit_message(chat_id, message_id, "⏳ Updating protocol container...") + + def _toggle(): + data = load_data_fn() + server = data["servers"][server_id] + ssh, manager = _get_ssh_and_manager(server, proto) + try: + ssh.connect() + container = (server.get("protocols", {}).get(proto, {}) or {}).get("container_name") + if not container: + # fallback: most managers expose CONTAINER_NAME for base/first instances + container = getattr(manager, "CONTAINER_NAME", None) + if not container: + raise RuntimeError("Container name is unknown") + action = "start" if start else "stop" + out, err, code = ssh.run_sudo_command(f"docker {action} {container}") + if code != 0: + raise RuntimeError(err or out or f"docker {action} failed") + return data + finally: + ssh.disconnect() + + try: + await asyncio.to_thread(_toggle) + await _admin_protocol_detail(api, chat_id, message_id, server_id, proto, load_data_fn) + except Exception as e: + logger.exception("Bot admin: protocol toggle failed") + await api.edit_message(chat_id, message_id, f"❌ Error: {_e(e)}", reply_markup={"inline_keyboard": [[{"text": "⬅️ Protocol", "callback_data": _ref("proto", {"sid": server_id, "proto": proto})}]]}) + + +async def _admin_clients(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, load_data_fn: Callable): + await api.edit_message(chat_id, message_id, "⏳ Loading connections...") + + def _load_clients(): + data = load_data_fn() + server = data["servers"][server_id] + ssh, manager = _get_ssh_and_manager(server, proto) + try: + ssh.connect() + return data, _manager_call(manager, "get_clients", proto) + finally: + ssh.disconnect() + + try: + data, clients = await asyncio.to_thread(_load_clients) + if not clients: + await api.edit_message(chat_id, message_id, "👥 No connections.", reply_markup={"inline_keyboard": [[{"text": "➕ Create connection", "callback_data": _ref("add_client", {"sid": server_id, "proto": proto})}], [{"text": "⬅️ Protocol", "callback_data": _ref("proto", {"sid": server_id, "proto": proto})}]]}) + return + rows = [] + conn_by_client = _connection_lookup(data, server_id, proto) + users_by_id = {u.get("id"): u for u in data.get("users", [])} + for c in clients[:40]: + client_id = c.get("clientId") or c.get("client_id") or c.get("id") or "" + conn = conn_by_client.get(client_id) + name = _client_display_name(c, conn) + traffic = "" + user_data = c.get("userData") or {} + if user_data: + total = (user_data.get("dataReceivedBytes") or 0) + (user_data.get("dataSentBytes") or 0) + traffic = f" · {_format_bytes(total)}" + assigned = "" + if conn and conn.get("user_id") in users_by_id: + assigned = f" · @{users_by_id[conn.get('user_id')].get('username')}" + c["name"] = name + c["assigned_user_id"] = conn.get("user_id") if conn else None + rows.append([{"text": f"👤 {name}{assigned}{traffic}", "callback_data": _ref("client", {"sid": server_id, "proto": proto, "client_id": client_id, "name": name, "client": c})}]) + rows.append([{"text": "➕ Create connection", "callback_data": _ref("add_client", {"sid": server_id, "proto": proto})}]) + rows.append([{"text": "⬅️ Protocol", "callback_data": _ref("proto", {"sid": server_id, "proto": proto})}]) + await api.edit_message(chat_id, message_id, f"👥 {_e(_protocol_display_name(proto))} connections ({len(clients)})", reply_markup={"inline_keyboard": rows}) + except Exception as e: + logger.exception("Bot admin: load clients failed") + await api.edit_message(chat_id, message_id, f"❌ Error: {_e(e)}", reply_markup={"inline_keyboard": [[{"text": "⬅️ Protocol", "callback_data": _ref("proto", {"sid": server_id, "proto": proto})}]]}) + + +async def _admin_client_detail(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, client: dict): + client_id = client.get("clientId") or client.get("client_id") or client.get("id") or "" + name = _client_display_name(client) + user_data = client.get("userData") or {} + rx = user_data.get("dataReceivedBytes") or 0 + tx = user_data.get("dataSentBytes") or 0 + enabled = client.get("enabled") + if enabled is None: + enabled = client.get("isEnabled") + enabled_text = "enabled ✅" if (enabled is None or enabled) else "disabled 🚫" + text = ( + f"👤 {_e(name)}\n" + f"Protocol: {_e(_protocol_display_name(proto))}\n" + f"Client ID: {_e(client_id)}\n" + f"Status: {enabled_text}" + ) + if user_data: + text += f"\nTraffic: {_format_bytes(rx + tx)}\nRX: {_format_bytes(rx)} · TX: {_format_bytes(tx)}" + await api.edit_message(chat_id, message_id, text, reply_markup=_client_keyboard(server_id, proto, client)) + + +async def _admin_add_client(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, panel_user: dict, load_data_fn: Callable, save_data_fn: Optional[Callable], generate_vpn_link_fn: Callable): + if not save_data_fn: + await api.edit_message(chat_id, message_id, "❌ Saving is not available for this bot instance.") + return + _pending_inputs[str(chat_id)] = { + "kind": "add_client_name", + "sid": server_id, + "proto": proto, + "admin_user_id": panel_user.get("id"), + "ts": time.time(), + } + await api.edit_message( + chat_id, + message_id, + "➕ Create connection\n\n" + f"Server/protocol: {_e(_protocol_display_name(proto))}\n\n" + "Send the connection name in the next message.\n" + "Example: Ivan iPhone\n\n" + "Send /cancel to cancel.", + reply_markup={"inline_keyboard": [[{"text": "❌ Cancel", "callback_data": _ref("clients", {"sid": server_id, "proto": proto})}]]}, + ) + + +async def _admin_choose_client_user(api: TelegramAPI, chat_id: int, name: str, server_id: int, proto: str, load_data_fn: Callable): + data = load_data_fn() + await api.send_message( + chat_id, + "✅ Connection name: {}\n\n" + "Assign this connection to a panel user?".format(_e(name)), + reply_markup=_assign_user_keyboard(data, server_id, proto, name), + ) + + +async def _admin_create_client(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, name: str, user_id: Optional[str], load_data_fn: Callable, save_data_fn: Optional[Callable], generate_vpn_link_fn: Callable): + if not save_data_fn: + await api.edit_message(chat_id, message_id, "❌ Saving is not available for this bot instance.") + return + await api.edit_message(chat_id, message_id, "⏳ Creating connection...") + + def _create(): + data = load_data_fn() + server = data["servers"][server_id] + proto_info = (server.get("protocols", {}) or {}).get(proto, {}) + port = proto_info.get("port", "55424") + ssh, manager = _get_ssh_and_manager(server, proto) + try: + ssh.connect() + if _proto_base(proto) == "telemt": + result = manager.add_client(proto, name, server["host"], port) + elif _proto_base(proto) == "wireguard": + result = manager.add_client(name, server["host"]) + else: + result = manager.add_client(proto, name, server["host"], port) + finally: + ssh.disconnect() + client_id = result.get("client_id") or result.get("clientId") + assigned_user = None + if user_id: + assigned_user = next((u for u in data.get("users", []) if u.get("id") == user_id), None) + if user_id and client_id: + data.setdefault("user_connections", []).append({ + "id": str(uuid.uuid4()), + "user_id": user_id, + "server_id": server_id, + "protocol": proto, + "client_id": client_id, + "name": name, + "created_at": time.strftime("%Y-%m-%dT%H:%M:%S"), + }) + save_data_fn(data) + return server, result, client_id, assigned_user + + try: + server, result, client_id, assigned_user = await asyncio.to_thread(_create) + assigned_text = f"\nAssigned to: {_e(assigned_user.get('username'))}" if assigned_user else "\nAssigned: not linked" + await api.edit_message(chat_id, message_id, f"✅ Connection created: {_e(name)}{assigned_text}") + config = result.get("config") + if config: + await _send_config_text(api, chat_id, server, proto, name, config, generate_vpn_link_fn) + elif client_id: + await _send_config_by_client(api, chat_id, server, proto, client_id, name, generate_vpn_link_fn) + except Exception as e: + logger.exception("Bot admin: add client failed") + await api.edit_message(chat_id, message_id, f"❌ Error: {_e(e)}", reply_markup={"inline_keyboard": [[{"text": "⬅️ Protocol", "callback_data": _ref("proto", {"sid": server_id, "proto": proto})}]]}) + + +async def _send_config_text(api: TelegramAPI, chat_id: int, server: dict, proto: str, conn_name: str, config: str, generate_vpn_link_fn: Callable): + await api.send_message(chat_id, f"✅ {_e(conn_name)}\n🌐 Server: {_e(server.get('name') or server.get('host'))}\n🔌 Protocol: {_e(proto.upper())}") + if _proto_base(proto) in ("xray", "telemt"): + await api.send_message(chat_id, f"🔗 Connection link:\n{_e(config)}") + else: + await api.send_message(chat_id, f"📄 Configuration:\n
{_e(config)}
") + vpn_link = generate_vpn_link_fn(config) if config else "" + if vpn_link: + await api.send_message(chat_id, f"🔗 VPN Link:\n{_e(vpn_link)}") + await api.send_document(chat_id, filename=f"{conn_name}.conf", content=config.encode("utf-8"), caption=f"📁 Config file: {conn_name}") + + +async def _admin_toggle_client(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, client_id: str, enable: bool, load_data_fn: Callable): + await api.edit_message(chat_id, message_id, "⏳ Updating connection...") + + def _toggle(): + data = load_data_fn() + server = data["servers"][server_id] + ssh, manager = _get_ssh_and_manager(server, proto) + try: + ssh.connect() + return _manager_call(manager, "toggle_client", proto, client_id, enable) + finally: + ssh.disconnect() + + try: + await asyncio.to_thread(_toggle) + await api.edit_message(chat_id, message_id, "✅ Updated.", reply_markup={"inline_keyboard": [[{"text": "⬅️ Connections", "callback_data": _ref("clients", {"sid": server_id, "proto": proto})}]]}) + except Exception as e: + logger.exception("Bot admin: toggle client failed") + await api.edit_message(chat_id, message_id, f"❌ Error: {_e(e)}") + + +async def _admin_remove_client(api: TelegramAPI, chat_id: int, message_id: int, server_id: int, proto: str, client_id: str, load_data_fn: Callable, save_data_fn: Optional[Callable]): + if not save_data_fn: + await api.edit_message(chat_id, message_id, "❌ Saving is not available for this bot instance.") + return + await api.edit_message(chat_id, message_id, "⏳ Removing connection...") + + def _remove(): + data = load_data_fn() + server = data["servers"][server_id] + ssh, manager = _get_ssh_and_manager(server, proto) + try: + ssh.connect() + _manager_call(manager, "remove_client", proto, client_id) + finally: + ssh.disconnect() + data["user_connections"] = [ + c for c in data.get("user_connections", []) + if not (c.get("server_id") == server_id and c.get("protocol") == proto and c.get("client_id") == client_id) + ] + save_data_fn(data) + + try: + await asyncio.to_thread(_remove) + await api.edit_message(chat_id, message_id, "✅ Connection removed.", reply_markup={"inline_keyboard": [[{"text": "⬅️ Connections", "callback_data": _ref("clients", {"sid": server_id, "proto": proto})}]]}) + except Exception as e: + logger.exception("Bot admin: remove client failed") + await api.edit_message(chat_id, message_id, f"❌ Error: {_e(e)}") + + +async def _handle_pending_input(api: TelegramAPI, msg: dict, load_data_fn: Callable, save_data_fn: Optional[Callable], generate_vpn_link_fn: Callable) -> bool: + chat_id = msg["chat"]["id"] + state = _pending_inputs.get(str(chat_id)) + if not state: + return False + + text = (msg.get("text") or "").strip() + if text.lower() in ("/cancel", "cancel"): + _pending_inputs.pop(str(chat_id), None) + await api.send_message(chat_id, "❌ Action cancelled.", reply_markup=_admin_main_keyboard()) + return True + if text.startswith("/"): + _pending_inputs.pop(str(chat_id), None) + return False + + if state.get("kind") == "add_client_name": + panel_user = _require_admin(load_data_fn, str(msg["from"]["id"])) + if not panel_user: + _pending_inputs.pop(str(chat_id), None) + await api.send_message(chat_id, "❌ Access denied.") + return True + name = text[:80].strip() + if not name: + await api.send_message(chat_id, "Name cannot be empty. Send a connection name or /cancel.") + return True + _pending_inputs.pop(str(chat_id), None) + await _admin_choose_client_user(api, chat_id, name, int(state.get("sid", 0)), state.get("proto", "awg"), load_data_fn) + return True + + return False + + +# ----------------------------------------------------------------------- # +# Main polling loop and dispatcher +# ----------------------------------------------------------------------- # +async def _run_bot(token: str, load_data_fn: Callable, generate_vpn_link_fn: Callable, save_data_fn: Optional[Callable] = None): + offset = 0 + logger.info("Telegram bot started (raw httpx polling).") + + async with httpx.AsyncClient() as client: + api = TelegramAPI(token, client) + + me = await api.call("getMe") + if not me.get("ok"): + logger.error(f"Telegram bot: invalid token or API error: {me}") + return + logger.info(f"Telegram bot logged in as @{me['result']['username']}") + + while True: + try: + updates = await api.get_updates(offset=offset, timeout=25) + except asyncio.CancelledError: + logger.info("Telegram bot polling cancelled.") + return + except Exception as e: + logger.warning(f"Telegram bot polling error: {e}") + await asyncio.sleep(5) + continue + + for update in updates: + offset = update["update_id"] + 1 + try: + await _dispatch(api, update, load_data_fn, generate_vpn_link_fn, save_data_fn) + except asyncio.CancelledError: + return + except Exception as e: + logger.exception(f"Telegram bot: error handling update {update['update_id']}: {e}") + + +async def _dispatch(api: TelegramAPI, update: dict, load_data_fn: Callable, generate_vpn_link_fn: Callable, save_data_fn: Optional[Callable] = None): + if "message" in update: + msg = update["message"] + text = msg.get("text", "") + if await _handle_pending_input(api, msg, load_data_fn, save_data_fn, generate_vpn_link_fn): + return + if text.startswith("/start") or text.startswith("/admin"): + await _handle_start(api, msg, load_data_fn) + elif text.startswith("/connections"): + panel_user = _find_user(load_data_fn, str(msg["from"]["id"])) + if not panel_user: + await api.send_message(msg["chat"]["id"], "❌ Access denied.") + else: + await _send_user_connections(api, msg["chat"]["id"], panel_user, load_data_fn) + elif text.startswith("/servers"): + if _require_admin(load_data_fn, str(msg["from"]["id"])): + await _admin_servers(api, msg["chat"]["id"], None, load_data_fn) + else: + await api.send_message(msg["chat"]["id"], "❌ Access denied.") + elif text.startswith("/addserver"): + await _handle_add_server_command(api, msg, load_data_fn, save_data_fn) + + elif "callback_query" in update: + cq = update["callback_query"] + callback_id = cq["id"] + data_str = cq.get("data", "") + chat_id = cq["message"]["chat"]["id"] + message_id = cq["message"]["message_id"] + tg_id = str(cq["from"]["id"]) + + if data_str == "noop": + await api.answer_callback(callback_id) + return + if data_str == "refresh": + await _handle_refresh(api, chat_id, message_id, callback_id, tg_id, load_data_fn) + return + if data_str.startswith("cfg:"): + await _handle_get_config(api, chat_id, message_id, callback_id, data_str[4:], tg_id, load_data_fn, generate_vpn_link_fn) + return + + panel_user = _require_admin(load_data_fn, tg_id) + if not panel_user: + await api.answer_callback(callback_id, "Access denied") + return + + await api.answer_callback(callback_id) + + if data_str == "adm:menu": + await api.edit_message(chat_id, message_id, "Admin menu", reply_markup=_admin_main_keyboard()) + elif data_str == "adm:servers": + await _admin_servers(api, chat_id, message_id, load_data_fn) + elif data_str == "adm:users": + await _admin_users(api, chat_id, message_id, load_data_fn) + elif data_str == "adm:myconns": + await _send_user_connections(api, chat_id, panel_user, load_data_fn) + elif data_str == "adm:addserver_help": + await api.edit_message( + chat_id, + message_id, + "➕ Add server\n\n" + "Use command:\n" + "/addserver host username password [ssh_port] [name]\n\n" + "Example:\n" + "/addserver 203.0.113.10 root myPassword 22 Prod VPS\n\n" + "⚠️ Prefer the web panel for real credentials if possible.", + reply_markup={"inline_keyboard": [[{"text": "⬅️ Admin menu", "callback_data": "adm:menu"}]]}, + ) + elif data_str.startswith("srv:"): + await _admin_server_detail(api, chat_id, message_id, int(data_str.split(":", 1)[1]), load_data_fn) + else: + ref = _resolve_ref(data_str) + if not ref: + await api.edit_message(chat_id, message_id, "❌ Action expired. Use /start again.") + return + action = ref.get("action") + payload = ref.get("payload", {}) + sid = int(payload.get("sid", 0) or 0) + proto = payload.get("proto", "awg") + if action == "user": + await _admin_user_detail(api, chat_id, message_id, payload.get("uid"), load_data_fn) + elif action == "proto": + await _admin_protocol_detail(api, chat_id, message_id, sid, proto, load_data_fn) + elif action == "toggle_proto": + await _admin_toggle_protocol(api, chat_id, message_id, sid, proto, bool(payload.get("start")), load_data_fn) + elif action == "clients": + await _admin_clients(api, chat_id, message_id, sid, proto, load_data_fn) + elif action == "client": + await _admin_client_detail(api, chat_id, message_id, sid, proto, payload.get("client", {})) + elif action == "client_cfg": + data = load_data_fn() + server = data["servers"][sid] + await _send_config_by_client(api, chat_id, server, proto, payload.get("client_id"), payload.get("name", "Connection"), generate_vpn_link_fn) + elif action == "add_client": + await _admin_add_client(api, chat_id, message_id, sid, proto, panel_user, load_data_fn, save_data_fn, generate_vpn_link_fn) + elif action == "create_client": + await _admin_create_client(api, chat_id, message_id, sid, proto, payload.get("name", "Connection"), payload.get("user_id"), load_data_fn, save_data_fn, generate_vpn_link_fn) + elif action == "toggle_client": + await _admin_toggle_client(api, chat_id, message_id, sid, proto, payload.get("client_id"), bool(payload.get("enable")), load_data_fn) + elif action == "remove_client": + await _admin_remove_client(api, chat_id, message_id, sid, proto, payload.get("client_id"), load_data_fn, save_data_fn) diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..695c326 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,269 @@ + + + + + + + + {{ site_settings.title or 'Amnezia Panel' }} {% block title_extra %}{% endblock %} + + + + + {% block head_extra %}{% endblock %} + + + + +
+ +
+
+ + + {% if current_user %} + + + + {% else %} + + {% endif %} +
+ +
+ {% block content %}{% endblock %} +
+
+ + + + + + + {% block scripts %}{% endblock %} + + + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..de0f6c8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,453 @@ +{% extends "base.html" %} + +{% block content %} +
+
+

+ 🖥 + {{ _('nav_servers') }} +

+ +
+ + {% if servers %} +
+ {% for server in servers %} +
+
+
🖥
+
+
+ + {{ server.name }} + +
+
{{ server.host }}:{{ server.ssh_port }}
+
+
+ +
+ {% if server.protocols %} + {% for proto_key, proto_val in server.protocols.items() %} + {% if proto_val.get('installed') %} + + + {{ 'AWG' if proto_key == 'awg' else ('AWG-Legacy' if proto_key == 'awg_legacy' else ('Xray' if + proto_key == 'xray' else proto_key | upper)) }} + + {% endif %} + {% endfor %} + {% else %} + + + {{ _('no_protocols') }} + + {% endif %} +
+ +
+ + {{ _('manage') }} + + + +
+
+ {% endfor %} +
+ {% else %} +
+
🛡
+
{{ _('no_servers') }}
+
+ {{ _('add_server_desc') }} +
+ +
+ {% endif %} +
+ + + + + + +{% endblock %} + +{% block scripts %} + +{% endblock %} \ No newline at end of file diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..268a14d --- /dev/null +++ b/templates/login.html @@ -0,0 +1,285 @@ + + + + + + + {{ site_settings.title or 'Amnezia Panel' }} — {{ _('login') }} + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/my_connections.html b/templates/my_connections.html new file mode 100644 index 0000000..8f6faeb --- /dev/null +++ b/templates/my_connections.html @@ -0,0 +1,162 @@ +{% extends "base.html" %} + +{% block title_extra %} — {{ _('my_connections_title') }}{% endblock %} + +{% block content %} +
+

+ 🔗 + {{ _('my_connections_title') }} +

+ + {% if connections %} +
+ {% for c in connections %} +
+
+
🔗
+
+
{{ c.name or 'VPN Connection' }}
+
+ 🖥 {{ c.server_name }} + + {{ 'AmneziaWG' if c.protocol == 'awg' else ('AmneziaWG 2.0' if c.protocol == 'awg2' else ('AWG Legacy' if c.protocol == 'awg_legacy' else + ('Xray' if c.protocol == 'xray' else c.protocol | upper))) }} + + {% if c.created_at %} + 📅 {{ c.created_at[:10] }} + {% endif %} +
+
+
+
+ +
+
+ {% endfor %} +
+ {% else %} +
+
🔗
+
{{ _('no_connections') }}
+
{{ _('no_connections_user_desc') }}
+
+ {% endif %} +
+ + + +{% endblock %} + +{% block scripts %} + +{% endblock %} \ No newline at end of file diff --git a/templates/server.html b/templates/server.html new file mode 100644 index 0000000..4a06506 --- /dev/null +++ b/templates/server.html @@ -0,0 +1,2347 @@ +{% extends "base.html" %} + +{% block title_extra %} — {{ server.name }}{% endblock %} + +{% block head_extra %} + + + +{% endblock %} + +{% block content %} +{{ _('back_to_servers') }} + + +
+
+
+
🖥
+
+

{{ server.name }}

+
{{ server.host }}:{{ server.ssh_port }} • {{ server.username + }}
+
+
+
+ + +
+
+ +
+ + + +
+
+ {{ _('checking_server') }} +
+ + +
+ +
+
+
+
+
+
AmneziaWG 2.0 NEW +
+
+ {{ _('awg_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
🔮
+
+
+
AmneziaWG
+
+ {{ _('awg_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
📡
+
+
+
AmneziaWG Legacy
+
+ {{ _('awg_legacy_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
+
+
+
Xray (VLESS-Reality)
+
+ {{ _('xray_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
+
+
+
Telemt (Telegram Proxy)
+
+ {{ _('telemt_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
🔒
+
+
+
WireGuard
+
+ {{ _('wireguard_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+ + 🔒 {{ _('coming_soon') }} +
+ +
+
AIVPN
+
{{ _('aivpn_subtitle') }}
+
+ + ⭐ {{ _('promo_star_cta') }} + +
+
+ + +
+
+
🔍
+
+
+
AmneziaDNS
+
+ {{ _('dns_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
🛡️
+
+
+
AdGuard Home
+
+ {{ _('adguard_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+
+
🧦
+
+
+
SOCKS5 Proxy
+
+ {{ _('socks5_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + + +
+
+
🌐
+
+
+
NGINX
+
+ {{ _('nginx_desc') }} +
+
+ {{ _('not_checked') }} +
+ +
+ +
+
+ + +
+ + + 🔒 {{ _('coming_soon') }} +
+ +
+
{{ _('revproxy_title') }}
+
{{ _('revproxy_subtitle') }}
+
+ + ⭐ {{ _('promo_star_cta') }} + +
+
+
+ +
+ + 🔒 Coming soon +
+ +
+
AIVPN
+
AI-driven protocol selection that picks the right tunnel for the moment. Land it sooner — drop a star.
+
+ + ⭐ Star us on GitHub + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{% endblock %} + +{% block scripts %} + + + + + + + + +{% endblock %} diff --git a/templates/settings.html b/templates/settings.html new file mode 100644 index 0000000..29d4b34 --- /dev/null +++ b/templates/settings.html @@ -0,0 +1,1035 @@ +{% extends "base.html" %} + +{% block title_extra %} — {{ _('nav_settings') }}{% endblock %} + +{% block content %} +
+ ⚙️ + {{ _('settings_title') }} +
+ +
+ +
+ +
+

{{ _('appearance') }}

+
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+

{{ _('captcha_title') }}

+
+
+ +
+
+
+ + +
+

{{ _('telegram_bot_title') }}

+
+
+ + +
+
+
+ {{ _('bot_status') }}: + {% if bot_running %} + {{ _('bot_running') }} + {% else %} + {{ _('bot_stopped') }} + {% endif %} +
+ +
+

+ {{ _('bot_hint') }} +

+
+
+ + + + + +
+

🌍 {{ _('tunnels_title') }}

+
+
+
+ {{ _('local_server') }} + {{ _('active') }} +
+
+ {{ request.url.scheme }}://{{ request.url.netloc }} + +
+
+ +
+
+ Cloudflare Quick Tunnel + {{ _('not_installed') }} +
+
{{ _('tunnel_no_public_url') }}
+
+ + + +
+
+ +
+
+ ngrok Tunnel + Authtoken + {{ _('not_installed') }} +
+
+ +
+
{{ _('tunnel_no_public_url') }}
+
+ + + +
+
+ + +
+
+ Cloudflare WARP + {{ _('not_installed') }} +
+
{{ _('warp_status_unknown') }}
+
{{ _('warp_hint') }}
+
+ + +
+
+
+

{{ _('tunnels_hint') }}

+
+ + +
+

🔒 {{ _('ssl_title') }}

+
+
+ +
+
+ + +
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
{{ _('or_paste_text') }}
+ +
+ + +
+
+ + +
+ +

{{ _('ssl_hint') }}

+
+
+
+
+ + +
+ +
+

{{ _('import_users_title') }}

+
+
+ +
+ + + + + +
+
+ +
+
+ + +
+
+ + +
+ +
+ +
+ {{ _('sync_hint') }} +
+
+ + +
+
+ +
+ +
+ +
+
+ + +
+
+ + +
+
+
+
+
+ + +
+

📤 {{ _('backup_title') }}

+
+ +
+
+ + +
+
+
+

+ {{ _('restore_confirm') }} +

+
+ + +
+
+

🔑 {{ _('api_tokens_title') }}

+ +
+

+ {{ _('api_tokens_hint') }} +

+
+
{{ _('api_tokens_empty') }}
+
+
+ + +
+

ℹ️ {{ _('about_title') }}

+
+
+ {{ _('current_version') }} + {{ current_version }} +
+ + + +
+ + +
+
+
+
+
+ +
+ +
+ + + + + + + + +{% endblock %} diff --git a/templates/user_share.html b/templates/user_share.html new file mode 100644 index 0000000..af26f5c --- /dev/null +++ b/templates/user_share.html @@ -0,0 +1,249 @@ +{% extends "base.html" %} + +{% block title_extra %} — {{ _('share_title') }}{% endblock %} + +{% block content %} +
+
+

{{ _('vpn_access') }}

+

{{ _('user_label_share') }}: {{ + share_user.username }} +

+
+ + {% if need_password %} +
+
🔐
+

{{ _('share_protected_desc') }} +

+ +
+
+ +
+ +
+
+ {% else %} +
+
+
+

{{ _('loading_share_conns') }}

+
+ + +
+ {% endif %} +
+ + + + + + + +{% endblock %} \ No newline at end of file diff --git a/templates/users.html b/templates/users.html new file mode 100644 index 0000000..034c8ad --- /dev/null +++ b/templates/users.html @@ -0,0 +1,1084 @@ +{% extends "base.html" %} + +{% block title_extra %} — {{ _('users_title') }}{% endblock %} + +{% block content %} +
+
+

+ 👥 + {{ _('users_title') }} +

+ +
+ + 🔍 +
+ + {% if current_user.role == 'admin' %} + + {% endif %} +
+ + + +
+
+

{{ _('loading_users') }}

+
+ + +
+ + + + + + + + + + + + + + + +{% endblock %} + +{% block scripts %} + + + + + + + +{% endblock %} + diff --git a/translations/en.json b/translations/en.json new file mode 100644 index 0000000..cf10d58 --- /dev/null +++ b/translations/en.json @@ -0,0 +1,423 @@ +{ + "nav_servers": "Servers", + "nav_users": "Users", + "nav_settings": "Settings", + "nav_connections": "Connections", + "nav_logout": "Logout", + "theme_dark": "Dark", + "theme_light": "Light", + "back_to_servers": "← Back to servers", + "server_check": "Check", + "server_checking": "Checking...", + "protocols": "Protocols", + "install": "Install", + "uninstall": "Uninstall", + "run": "Running", + "stop": "Stopped", + "not_installed": "Not installed", + "installed": "Installed", + "add_server": "Add Server", + "no_servers": "No servers added", + "name": "Name", + "host": "Host", + "port": "Port", + "status": "Status", + "actions": "Actions", + "edit": "Edit", + "delete": "Delete", + "save": "Save", + "cancel": "Cancel", + "loading": "Loading...", + "copy": "Copy", + "download": "Download", + "config": "Configuration", + "qr_code": "QR code", + "vpn_key": "VPN key", + "clients": "Clients", + "traffic": "Traffic", + "limit": "Limit", + "manage": "Manage", + "no_protocols": "No protocols", + "add_server_desc": "Add your first VPN server to get started. You'll need SSH credentials to connect.", + "ssh_host": "Host / IP", + "ssh_port": "SSH Port", + "ssh_user": "User", + "ssh_password": "Password", + "ssh_key": "SSH Key", + "ssh_key_placeholder": "Private SSH Key", + "ssh_key_hint": "Paste the content of your id_rsa or id_ed25519 file", + "connect": "Connect", + "connecting": "Connecting...", + "server_added": "Server added successfully", + "server_deleted": "Server deleted", + "delete_confirm": "Are you sure you want to delete this server?", + "success": "Success", + "error": "Error", + "info": "Info", + "login_title": "Login to Panel", + "username": "Username", + "password": "Password", + "captcha": "Captcha", + "captcha_placeholder": "Enter characters from image", + "captcha_hint": "Click to refresh image", + "login": "Login", + "logging_in": "Logging in...", + "login_error": "Login failed", + "check_done": "Check complete", + "check_error": "Connection error", + "ssh_ok": "SSH Connection", + "docker_ok": "Docker", + "docker_not_installed": "Docker not installed", + "awg_desc": "A newer version of the protocol based on awg-go. Supports advanced obfuscation with S3, S4 parameters.", + "awg_legacy_desc": "Original AWG version based on WireGuard kernel. Compatible with older client versions.", + "xray_desc": "Modern protocol that masks traffic as regular web traffic (XTLS-Reality). Resistant to deep packet analysis.", + "wireguard_desc": "Standard and fastest VPN protocol. Supported natively on all modern OS, but easily detected by DPI.", + "not_checked": "Not checked", + "connections": "Connections", + "add": "Add", + "loading_connections": "Loading connections...", + "no_connections": "No connections", + "no_connections_desc": "Add your first connection to generate a VPN configuration", + "install_protocol": "Install protocol", + "port_default_hint": "Default port: 55424. Make sure it's not busy", + "port_xray_hint": "Default port: 443 (recommended for Xray). Make sure it's not taken by another web server.", + "reinstall": "Reinstall", + "uninstall_confirm": "Uninstall {}? All connections and configurations will be lost.", + "stop_container_confirm": "Stop container {}?", + "start_container_confirm": "Start container {}?", + "stopping": "Stopping", + "starting": "Starting", + "stopped": "stopped", + "started": "started", + "server_config": "Server configuration", + "add_connection": "Add connection", + "connection_name": "Connection name", + "connection_name_placeholder": "Example: iPhone, Laptop", + "assign_to_user": "Assign to user (optional)", + "no_assign": "— No assignment —", + "create": "Create", + "creating": "Creating...", + "connection_created": "Connection \"{}\" created", + "delete_connection_confirm": "Delete this connection? The configuration will stop working.", + "connection_deleted": "Connection deleted", + "config_tab": "📄 Config", + "vpn_key_tab": "🔑 VPN-key", + "qr_code_tab": "📱 QR-code", + "copy_config": "📋 Copy", + "download_conf": "⬇ Download .conf", + "copy_key": "📋 Copy key", + "vpn_link_hint": "Paste this link into the AmneziaVPN app for automatic configuration", + "qr_hint": "Scan the QR code in the AmneziaVPN app", + "no_data": "No data", + "start_btn": "▶ Start", + "stop_btn": "⏹ Stop", + "config_btn": "⚙️ Config", + "done": "Done", + "installing": "Installing...", + "start_install": "Starting installation...", + "check_docker": "Checking Docker...", + "prepare_host": "Preparing host...", + "build_container": "Building container...", + "install_success": "Protocol installed successfully!", + "install_error": "Installation error: ", + "qr_error": "Failed to generate QR code", + "users_title": "Users", + "search_placeholder": "Search by name, email or Telegram...", + "add_user": "Add User", + "prev_page": "← Back", + "next_page": "Next →", + "page_info": "Page {} of {}", + "loading_users": "Loading users...", + "nothing_found": "Nothing found", + "search_empty_desc": "Try changing your query or create a new user", + "username_label": "Username", + "password_label": "Password", + "role_label": "Role", + "role_user_desc": "User — view only own connections", + "role_support_desc": "Support — server management", + "role_admin_desc": "Admin — full access", + "tg_id_label": "Telegram ID (opt.)", + "email_label": "Email (opt.)", + "traffic_limit_label": "Traffic limit (GB) (opt., 0 = ∞)", + "expiration_date_label": "Expiration date", + "description_label": "Description (opt.)", + "auto_conn_title": "Automatic connection creation (optional)", + "server_label": "Server", + "no_create_conn": "— Do not create connection —", + "protocol_label": "Protocol", + "edit_user_title": "Edit user: {}", + "edit_user_tg": "Telegram ID (optional)", + "edit_user_email": "Email (optional)", + "edit_user_limit": "Traffic limit (GB) (0 = ∞)", + "new_password_hint": "New password (leave empty if no change needed)", + "op_type_label": "Operation type", + "create_new_conn": "Create new connection", + "link_existing_conn": "Link existing", + "select_existing_conn": "Select existing connection", + "existing_conn_hint": "Only connections not linked to users will be shown", + "conn_name_panel": "Connection name (in panel)", + "user_conns_title": "User connections", + "no_free_conns": "No free connections", + "linking": "Linking...", + "conn_linked": "Connection linked", + "enabling": "Enabling", + "disabling": "Disabling", + "user_enabled": "User enabled", + "user_disabled": "User disabled", + "delete_user_confirm": "Delete user? All their connections will be deleted.", + "share_access": "Share access", + "enable_public_access": "Enable public access", + "share_password_label": "Password (optional)", + "share_password_hint": "If set, user must enter it", + "public_link_label": "Public link", + "disabled": "Disabled", + "out_of": "Of", + "settings_title": "Panel Settings", + "appearance": "🎨 Appearance", + "title_label": "Title", + "logo_label": "Logo (Emoji or symbol)", + "subtitle_label": "Subtitle", + "captcha_title": "🔐 Captcha", + "enable_captcha": "Enable captcha (multicolorcaptcha)", + "telegram_bot_title": "🤖 Telegram Bot", + "bot_token_label": "Bot Token (from @BotFather)", + "bot_status": "Status", + "bot_running": "✅ Running", + "bot_stopped": "⏹ Stopped", + "bot_stop_btn": "⏹ Stop", + "bot_start_btn": "▶️ Start", + "bot_hint": "After changing the token, save the settings — the bot will restart automatically. Users must have a Telegram ID in their profile.", + "api_docs_title": "🔌 API Documentation", + "api_docs_hint": "Use these interfaces to explore the panel's API capabilities", + "tunnels_title": "Tunnels", + "local_server": "Local Server", + "tunnel_install_enable": "Install & Enable", + "tunnel_enable": "Enable Tunnel", + "tunnel_running": "Tunnel running", + "tunnel_stop": "Stop", + "tunnel_stopping": "Stopping...", + "tunnel_stopped": "Tunnel stopped", + "tunnel_delete": "Delete", + "tunnel_deleted": "Tunnel deleted", + "tunnel_delete_confirm": "Stop and delete this panel-managed tunnel binary?", + "tunnel_starting": "Starting tunnel...", + "tunnel_started": "Tunnel started", + "tunnel_waiting_url": "Tunnel started. Waiting for public URL...", + "tunnel_no_public_url": "Public URL will appear here after the tunnel starts.", + "tunnels_hint": "Quick tunnels expose this local panel to the internet. Keep admin credentials strong and share public URLs only with trusted users.", + "ngrok_authtoken_placeholder": "ngrok authtoken (optional for some accounts)", + "import_users_title": "📤 Import Users", + "import_source_label": "Import / Sync Source", + "remnawave_url_label": "Remnawave URL", + "api_key_label": "API Key", + "enable_sync": "Enable synchronization", + "sync_hint": "Users will be created, disabled, and deleted automatically based on Remnawave data", + "sync_now_btn": "🔄 Sync now", + "delete_sync_btn": "🗑 Delete synchronization", + "auto_create_conns": "Create connections automatically", + "sync_server_label": "Server for new connections", + "save_changes": "💾 Save changes", + "sync_success": "Sync completed: {} users", + "sync_deleted": "Deleted {} synced users", + "delete_sync_confirm": "Are you sure you want to delete ALL synced users and their connections? This action is irreversible.", + "settings_saved": "Settings saved successfully", + "bot_started": "Bot started", + "bot_stopped_msg": "Bot stopped", + "sync_running": "Syncing...", + "deleting": "Deleting...", + "my_connections_title": "My Connections", + "show_config": "📄 Show config", + "no_connections_user_desc": "Contact administrator to create a VPN connection", + "share_title": "Connection Access", + "vpn_access": "VPN Access", + "user_label_share": "User", + "share_protected_desc": "This access is password protected. Please enter it to continue.", + "auth_success": "Auth success", + "loading_share_conns": "Loading connections...", + "no_active_conns": "You have no active connections yet.", + "show_settings_btn": "🔑 Show settings", + "copied": "Copied!", + "active": "Active", + "site_description": "Amnezia Web Panel — management of VPN servers and protocols AmneziaWG", + "toggle_theme": "Change theme", + "copied_to_clipboard": "Copied to clipboard", + "share_not_found": "404 Not Found", + "share_not_found_desc": "Either the link is incorrect or access has been disabled.", + "invalid_captcha": "Invalid captcha", + "account_disabled": "Account disabled", + "invalid_login": "Invalid login or password", + "user_exists": "User with this name already exists", + "cannot_delete_self": "You cannot delete yourself", + "wrong_share_password": "Wrong password", + "saving": "Saving...", + "select_lang": "Select Language", + "lang_ru": "Русский", + "lang_en": "English", + "lang_fr": "Français", + "lang_zh": "中文 (Chinese)", + "lang_fa": "فارسی (Persian)", + "backup_title": "Simple Backup", + "download_backup": "Download data.json", + "restore_backup": "Restore from file", + "restore_confirm": "Are you sure? Current data will be overwritten and the application will restart.", + "restore_success": "Restore successful! Restarting...", + "invalid_backup_file": "Invalid backup file or structure", + "config_unavailable": "Configuration unavailable", + "config_unavailable_desc": "This client was created via the native Amnezia app.\\nThe private key is stored only on the user's device and cannot be recovered by the server.", + "client_public_key": "Client public key:", + "telemt_desc": "MTProxy-based Telegram proxy with advanced obfuscation and TLS emulation support.", + "tls_emulation": "TLS Emulation", + "tls_domain": "Masking Domain", + "max_connections_limit": "Max Connections", + "max_connections_hint": "0 for unlimited. Limits total concurrent users.", + "traffic_reset_strategy_label": "Traffic reset strategy", + "traffic_reset_never": "Never reset", + "traffic_reset_daily": "Daily reset", + "traffic_reset_weekly": "Weekly reset", + "traffic_reset_monthly": "Monthly reset", + "traffic_reset_hint": "How often should user traffic be reset", + "traffic_used_total": "Total spent", + "traffic_reset_info": "Next reset: {}", + "services": "Services", + "dns_desc": "Personal DNS server to block ads and protect the privacy of your queries.", + "dns_internal_hint": "The service runs on the internal network (172.29.172.254) without binding to host ports.", + "telemt_port_hint": "Port for the Telegram proxy (typically 443).", + "socks5_desc": "Single-account SOCKS5 proxy (3proxy) with username/password authentication.", + "socks5_username": "Username", + "socks5_password": "Password", + "socks5_password_placeholder": "Leave empty to auto-generate", + "socks5_password_hint": "If left empty, a random 16-character password will be generated.", + "socks5_port_hint": "TCP port the proxy will listen on. The default in the official Amnezia client is 38080.", + "socks5_change_settings": "Change settings", + "socks5_settings_title": "SOCKS5 — Connection settings", + "socks5_port_change_hint": "Changing the port recreates the container; existing sessions will be dropped.", + "socks5_settings_saved": "SOCKS5 settings saved", + "adguard_desc": "AdGuard Home — DNS-based ad blocker with a web admin UI.", + "adguard_mode": "Installation mode", + "adguard_mode_sidebyside": "Side-by-side", + "adguard_mode_sidebyside_hint": "runs alongside AmneziaDNS on a separate internal IP (172.29.172.253)", + "adguard_mode_replace": "Replace AmneziaDNS", + "adguard_mode_replace_hint": "removes amnezia-dns and takes its IP — VPN clients use AdGuard immediately", + "adguard_dns_port": "DNS port (53)", + "adguard_dns_port_hint": "Internal DNS port served to VPN clients via the docker network.", + "adguard_web_port": "Web UI port", + "adguard_dot_port": "DoT port", + "adguard_doh_port": "DoH port", + "adguard_expose_web": "Expose to internet", + "adguard_expose": "Expose to host", + "adguard_install_hint": "Initial AdGuard setup runs through its built-in wizard via the web UI after install.", + "adguard_internal_ip": "Internal IP", + "adguard_web_ui": "Admin URL", + "adguard_open_ui": "Open Web UI", + "edit_server_title": "Edit server", + "edit_keep_credential": "Leave empty to keep the current value", + "server_saved": "Server settings saved", + "servers_reordered": "Servers reordered", + "ping_checking": "Checking connectivity...", + "offline": "offline", + "api_tokens_title": "API tokens", + "api_tokens_hint": "Bearer tokens for external integrations. Send the token in the `Authorization: Bearer ` header. Tokens have admin-equivalent rights and stop working if their owner is disabled or demoted.", + "api_tokens_empty": "No API tokens yet. Create one to integrate the panel with an external service.", + "api_tokens_create": "Create token", + "api_tokens_create_title": "Create API token", + "api_tokens_name_label": "Name", + "api_tokens_name_placeholder": "e.g. Linear integration, CI bot, monitoring", + "api_tokens_name_hint": "Used to identify this token in the list. The token value itself is generated for you.", + "api_tokens_name_required": "Token name is required", + "api_tokens_created_title": "Token created", + "api_tokens_value_label": "Token value", + "api_tokens_warning_title": "This is the only time you'll see this token.", + "api_tokens_warning_body": "Copy it now and store it in your integration's secret manager. The panel keeps only a hash — if you lose this value you'll need to revoke and recreate the token.", + "api_tokens_revoke": "Revoke", + "api_tokens_revoke_confirm": "Revoke token \"{}\"? Any integration using it will stop working.", + "api_tokens_revoked": "Token revoked", + "api_tokens_created": "Created", + "api_tokens_last_used": "Last used", + "api_tokens_owner": "Owner", + "api_tokens_never": "never", + "coming_soon": "Coming soon", + "promo_star_cta": "Star us on GitHub", + "aivpn_subtitle": "AI-driven protocol selection that picks the right tunnel for the moment. Land it sooner — drop a star.", + "revproxy_title": "Reverse Proxy", + "revproxy_subtitle": "High-performance traffic obfuscation: hide your VPN endpoint behind a polished public-facing site, drop the DPI footprint.", + "management": "Management", + "server_management": "Server Management", + "server_management_desc": "Perform system-level actions on your machine.", + "check_server_services": "Check the server services", + "reboot_server": "Reboot server", + "clear_server": "Clear server", + "remove_server": "Remove server from panel", + "ssl_title": "SSL / HTTPS Settings", + "enable_https": "Enable HTTPS", + "panel_port_label": "Panel Port", + "domain_label": "Domain name", + "cert_path_label": "SSL Certificate path (.pem)", + "key_path_label": "Private Key path (.pem)", + "or_paste_text": "OR paste certificate text", + "cert_text_label": "Certificate content (CRT)", + "key_text_label": "Private Key content (KEY)", + "ssl_hint": "After enabling, the panel will be accessible via https:// on the specified domain. Make sure the file paths or text data are correct.", + "about_title": "About & Updates", + "current_version": "Current version", + "check_updates": "Check for updates", + "checking_updates": "Checking...", + "update_available": "New version available", + "download_update": "Download update", + "up_to_date": "You have the latest version", + "warp_hint": "WARP routes this host outbound through Cloudflare. It does not create a public panel URL like Quick Tunnel or ngrok.", + "warp_install_hint": "Install the official Cloudflare WARP client first, then restart the panel.", + "warp_install_required": "Install WARP first", + "warp_connect": "Connect WARP", + "warp_disconnect": "Disconnect", + "warp_connected": "WARP connected", + "warp_disconnected": "WARP disconnected", + "warp_status_unknown": "WARP status is unknown.", + "warp_status_not_installed": "Cloudflare WARP CLI is not installed on this host.", + "warp_status_connected": "Cloudflare WARP is connected.", + "warp_status_connecting": "Cloudflare WARP is connecting.", + "warp_status_disconnected": "Cloudflare WARP is disconnected.", + "warp_status_not_registered": "Cloudflare WARP is installed but not registered yet. Connect will try to register automatically.", + "warp_status_service_unavailable": "Cloudflare WARP service is not available. Make sure warp-svc is running.", + "warp_status_error": "Cloudflare WARP returned an error.", + "install_starting": "Starting installation...", + "server_check_complete": "Check completed", + "server_connection_error": "Connection error", + "connections_load_error": "Error loading connections", + "connection_updated": "Connection updated", + "edit_connection": "Edit connection", + "enable_connection_progress": "Enabling connection...", + "disable_connection_progress": "Disabling connection...", + "connection_enabled": "Connection enabled", + "connection_disabled": "Connection disabled", + "gb": "GB", + "marketplace": "Templates", + "open_marketplace": "Open Templates", + "marketplace_desc": "Install protocol and service templates available for this server.", + "installed_apps": "Installed applications", + "installed_apps_hint": "Only installed protocols and services are shown here. Use Templates to add more.", + "no_installed_apps": "No installed applications yet", + "no_installed_apps_desc": "Open Templates to install protocols or services on this server.", + "install_another": "Install another", + "new_instance": "new instance", + "port_next_instance_hint": "Choose a free UDP port for the additional instance.", + "checking_server": "Checking server services...", + "web_servers": "Web servers", + "nginx_desc": "NGINX web server with Let's Encrypt HTTPS certificate and editable index.html.", + "nginx_domain": "Domain", + "nginx_email": "Let's Encrypt email", + "nginx_port_hint": "HTTPS port exposed on the server. Port 80/TCP must be free and reachable for Let's Encrypt validation.", + "nginx_install_hint": "The domain must already point to this server. Port 80/TCP is used temporarily/permanently for HTTP-01 certificate validation.", + "site": "Site", + "site_editor": "Site editor", + "site_saved": "Site saved", + "nginx_dns_hint": "Create this DNS record before installation:", + "backup": "Backup", + "backups": "Backups", + "backup_desc": "Backups are created on the server and contain valuable protocol files needed to restore or recreate it later.", + "create_backup": "Create backup", + "creating_backup": "Creating backup...", + "backup_created": "Backup created", + "no_backups": "No backups yet", + "no_backups_desc": "Create the first backup for this protocol.", + "refresh": "Refresh" +} diff --git a/translations/fa.json b/translations/fa.json new file mode 100644 index 0000000..fd7096c --- /dev/null +++ b/translations/fa.json @@ -0,0 +1,390 @@ +{ + "nav_servers": "سرورها", + "nav_users": "کاربران", + "nav_settings": "تنظیمات", + "nav_connections": "اتصال‌ها", + "nav_logout": "خروج", + "theme_dark": "تاریک", + "theme_light": "روشن", + "back_to_servers": "← بازگشت به سرورها", + "server_check": "بررسی", + "server_checking": "در حال بررسی...", + "protocols": "پروتکل‌ها", + "install": "نصب", + "uninstall": "حذف نصب", + "run": "در حال اجرا", + "stop": "متوقف شده", + "not_installed": "نصب نشده", + "installed": "نصب شده", + "add_server": "افزودن سرور", + "no_servers": "هیچ سروری اضافه نشده است", + "name": "نام", + "host": "میزبان", + "port": "پورت", + "status": "وضعیت", + "actions": "عملکردها", + "edit": "ویرایش", + "delete": "حذف", + "save": "ذخیره", + "cancel": "لغو", + "loading": "در حال بارگذاری...", + "copy": "کپی", + "download": "دانلود", + "config": "پیکربندی", + "qr_code": "کد QR", + "vpn_key": "کلید VPN", + "clients": "کلاینت‌ها", + "traffic": "ترافیک", + "limit": "محدودیت", + "manage": "مدیریت", + "no_protocols": "بدون پروتکل", + "add_server_desc": "اولین سرور VPN خود را اضافه کنید. برای اتصال به اطلاعات SSH نیاز دارید.", + "ssh_host": "میزبان / IP", + "ssh_port": "پورت SSH", + "ssh_user": "نام کاربری", + "ssh_password": "رمز عبور", + "ssh_key": "کلید SSH", + "ssh_key_placeholder": "کلید خصوصی SSH", + "ssh_key_hint": "محتوای فایل id_rsa یا id_ed25519 خود را اینجا قرار دهید", + "connect": "اتصال", + "connecting": "در حال اتصال...", + "server_added": "سرور با موفقیت اضافه شد", + "server_deleted": "سرور حذف شد", + "delete_confirm": "آیا از حذف این سرور مطمئن هستید؟", + "success": "موفقیت", + "error": "خطا", + "info": "اطلاعات", + "login_title": "ورود به پنل", + "username": "نام کاربری", + "password": "رمز عبور", + "captcha": "کد امنیتی", + "captcha_placeholder": "کاراکترهای تصویر را وارد کنید", + "captcha_hint": "برای نوسازی تصویر کلیک کنید", + "login": "ورود", + "logging_in": "در حال ورود...", + "login_error": "ورود ناموفق بود", + "check_done": "بررسی کامل شد", + "check_error": "خطای اتصال", + "ssh_ok": "اتصال SSH برقرار است", + "docker_ok": "داکر نصب است", + "docker_not_installed": "داکر نصب نیست", + "awg_desc": "نسخه جدید پروتکل بر پایه awg-go. پشتیبانی از مبهم‌سازی پیشرفته (S3, S4).", + "awg_legacy_desc": "نسخه اصلی AWG. سازگار با نسخه‌های قدیمی کلاینت.", + "xray_desc": "تغییر ظاهر ترافیک به ترافیک معمولی وب (XTLS-Reality). مقاوم در برابر فیلترینگ شدید.", + "not_checked": "بررسی نشده", + "connections": "اتصال‌ها", + "add": "افزودن", + "loading_connections": "در حال بارگذاری اتصال‌ها...", + "no_connections": "بدون اتصال", + "no_connections_desc": "اولین اتصال خود را برای ایجاد پیکربندی VPN اضافه کنید", + "install_protocol": "نصب پروتکل", + "port_default_hint": "پورت پیش‌فرض: 55424. مطمئن شوید این پورت آزاد است.", + "port_xray_hint": "پورت پیشنهادی: 443. مطمئن شوید توسط وب‌سرور دیگری اشغال نشده باشد.", + "reinstall": "نصب مجدد", + "uninstall_confirm": "حذف نصب {}؟ تمام اتصال‌ها و پیکربندی‌ها از بین خواهند رفت.", + "stop_container_confirm": "توقف کانتینر {}؟", + "start_container_confirm": "شروع کانتینر {}؟", + "stopping": "در حال توقف", + "starting": "در حال شروع", + "stopped": "متوقف شد", + "started": "شروع شد", + "server_config": "پیکربندی سرور", + "add_connection": "افزودن اتصال", + "connection_name": "نام اتصال", + "connection_name_placeholder": "مثال: iPhone, Laptop", + "assign_to_user": "تخصیص به کاربر (اختیاری)", + "no_assign": "— بدون تخصیص —", + "create": "ایجاد", + "creating": "در حال ایجاد...", + "connection_created": "اتصال \"{}\" ایجاد شد", + "delete_connection_confirm": "این اتصال حذف شود؟ پیکربندی دیگر کار نخواهد کرد.", + "connection_deleted": "اتصال حذف شد", + "config_tab": "📄 فایل", + "vpn_key_tab": "🔑 کلید-VPN", + "qr_code_tab": "📱 کد-QR", + "copy_config": "📋 کپی", + "download_conf": "⬇ دانلود .conf", + "copy_key": "📋 کپی کلید", + "vpn_link_hint": "این لینک را برای تنظیم خودکار در برنامه AmneziaVPN وارد کنید", + "qr_hint": "کد QR را در برنامه AmneziaVPN اسکن کنید", + "no_data": "بدون داده", + "start_btn": "▶ شروع", + "stop_btn": "⏹ توقف", + "config_btn": "⚙️ تنظیم", + "done": "انجام شد", + "installing": "در حال نصب...", + "start_install": "شروع نصب...", + "check_docker": "بررسی داکر...", + "prepare_host": "آماده‌سازی میزبان...", + "build_container": "ساخت کانتینر...", + "install_success": "پروتکل با موفقیت نصب شد!", + "install_error": "خطا در نصب: ", + "qr_error": "ایجاد کد QR ناموفق بود", + "users_title": "کاربران", + "search_placeholder": "جستجو با نام، ایمیل یا تلگرام...", + "add_user": "افزودن کاربر", + "prev_page": "← قبلی", + "next_page": "بعدی →", + "page_info": "صفحه {} از {}", + "loading_users": "در حال بارگذاری کاربران...", + "nothing_found": "چیزی یافت نشد", + "search_empty_desc": "جستجوی دیگری را امتحان کنید یا کاربر جدید بسازید", + "username_label": "نام کاربری", + "password_label": "رمز عبور", + "role_label": "نقش", + "role_user_desc": "User — فقط مشاهده اتصال‌های خود", + "role_support_desc": "Support — مدیریت سرورها", + "role_admin_desc": "Admin — دسترسی کامل", + "tg_id_label": "آیدی تلگرام (اختیاری)", + "email_label": "ایمیل (اختیاری)", + "traffic_limit_label": "محدودیت ترافیک (گیگابایت) (0 = نامحدود)", + "description_label": "توضیحات (اختیاری)", + "auto_conn_title": "ایجاد خودکار اتصال (اختیاری)", + "server_label": "سرور", + "no_create_conn": "— عدم ایجاد اتصال —", + "protocol_label": "پروتکل", + "edit_user_title": "ویرایش کاربر: {}", + "edit_user_tg": "آیدی تلگرام (اختیاری)", + "edit_user_email": "ایمیل (اختیاری)", + "edit_user_limit": "محدودیت ترافیک (گیگابایت) (0 = نامحدود)", + "new_password_hint": "رمز عبور جدید (اگر تغییری نمی‌خواهید خالی بگذارید)", + "op_type_label": "نوع عملیات", + "create_new_conn": "ایجاد اتصال جدید", + "link_existing_conn": "اتصال به موجود", + "select_existing_conn": "انتخاب اتصال موجود", + "existing_conn_hint": "فقط اتصال‌های بدون کاربر نمایش داده می‌شوند", + "conn_name_panel": "نام اتصال (در پنل)", + "user_conns_title": "اتصال‌های کاربر", + "no_free_conns": "اتصال آزاد موجود نیست", + "linking": "در حال اتصال...", + "conn_linked": "اتصال برقرار شد", + "enabling": "در حال فعال‌سازی", + "disabling": "در حال غیرفعال‌سازی", + "user_enabled": "کاربر فعال شد", + "user_disabled": "کاربر غیرفعال شد", + "delete_user_confirm": "کاربر حذف شود؟ تمام اتصال‌های او حذف خواهند شد.", + "share_access": "اشتراک‌گذاری دسترسی", + "enable_public_access": "فعال‌سازی دسترسی عمومی", + "share_password_label": "رمز عبور (اختیاری)", + "share_password_hint": "در صورت تنظیم، کاربر باید آن را وارد کند", + "public_link_label": "لینک عمومی", + "disabled": "غیرفعال", + "out_of": "از", + "settings_title": "تنظیمات پنل", + "appearance": "🎨 ظاهر", + "title_label": "عنوان (Title)", + "logo_label": "لوگو (ایموجی یا نماد)", + "subtitle_label": "زیرعنوان (Subtitle)", + "captcha_title": "🔐 کد امنیتی", + "enable_captcha": "فعال‌سازی کد امنیتی", + "telegram_bot_title": "🤖 ربات تلگرام", + "bot_token_label": "توکن ربات (از @BotFather)", + "bot_status": "وضعیت", + "bot_running": "✅ در حال اجرا", + "bot_stopped": "⏹ متوقف شده", + "bot_stop_btn": "⏹ توقف", + "bot_start_btn": "▶️ شروع", + "bot_hint": "پس از تغییر توکن تنظیمات را ذخیره کنید تا ربات بازراه‌اندازی شود.", + "api_docs_title": "🔌 مستندات API", + "api_docs_hint": "از این رابط‌ها برای بررسی قابلیت‌های API استفاده کنید", + "tunnels_title": "Tunnels", + "local_server": "سرور محلی", + "tunnel_install_enable": "نصب و فعال‌سازی", + "tunnel_enable": "فعال‌سازی تونل", + "tunnel_running": "تونل در حال اجرا است", + "tunnel_stop": "توقف", + "tunnel_stopping": "در حال توقف...", + "tunnel_stopped": "تونل متوقف شد", + "tunnel_delete": "حذف", + "tunnel_deleted": "تونل حذف شد", + "tunnel_delete_confirm": "این فایل اجرایی تونل مدیریت‌شده توسط پنل متوقف و حذف شود؟", + "tunnel_starting": "در حال شروع تونل...", + "tunnel_started": "تونل شروع شد", + "tunnel_waiting_url": "تونل شروع شد. در انتظار آدرس عمومی...", + "tunnel_no_public_url": "آدرس عمومی پس از شروع تونل اینجا نمایش داده می‌شود.", + "tunnels_hint": "تونل‌های سریع این پنل محلی را در اینترنت منتشر می‌کنند. رمز مدیر را قوی نگه دارید و آدرس‌های عمومی را فقط با کاربران مورد اعتماد به اشتراک بگذارید.", + "ngrok_authtoken_placeholder": "ngrok authtoken (برای برخی حساب‌ها اختیاری است)", + "import_users_title": "📤 وارد کردن کاربران", + "import_source_label": "منبع وارد کردن / همگام‌سازی", + "remnawave_url_label": "آدرس Remnawave", + "api_key_label": "کلید API", + "enable_sync": "فعال‌سازی همگام‌سازی", + "sync_hint": "کاربران طبق داده‌های Remnawave به‌طور خودکار مدیریت می‌شوند", + "sync_now_btn": "🔄 همگام‌سازی اکنون", + "delete_sync_btn": "🗑 حذف همگام‌سازی", + "auto_create_conns": "ایجاد خودکار اتصال‌ها", + "sync_server_label": "سرور برای اتصال‌های جدید", + "save_changes": "💾 ذخیره تغییرات", + "sync_success": "همگام‌سازی انجام شد: {} کاربر", + "sync_deleted": "{} کاربر همگام‌سازی شده حذف شدند", + "delete_sync_confirm": "آیا از حذف تمام کاربران همگام‌سازی شده مطمئن هستید؟", + "settings_saved": "تنظیمات با موفقیت ذخیره شد", + "bot_started": "ربات شروع به کار کرد", + "bot_stopped_msg": "ربات متوقف شد", + "sync_running": "در حال همگام‌سازی...", + "deleting": "در حال حذف...", + "my_connections_title": "اتصال‌های من", + "show_config": "📄 نمایش پیکربندی", + "no_connections_user_desc": "برای ایجاد اتصال VPN با مدیر تماس بگیرید", + "share_title": "دسترسی به اتصال", + "vpn_access": "دسترسی VPN", + "user_label_share": "کاربر", + "share_protected_desc": "این دسترسی با رمز عبور محافظت شده است.", + "auth_success": "ورود موفقیت‌آمیز", + "loading_share_conns": "در حال بارگذاری...", + "no_active_conns": "هنوز هیچ اتصال فعالی ندارید.", + "show_settings_btn": "🔑 نمایش تنظیمات", + "copied": "کپی شد!", + "active": "فعال", + "site_description": "پنل وب آمنزیا — مدیریت سرورها و پروتکل‌های AmneziaWG", + "toggle_theme": "تغییر تم", + "copied_to_clipboard": "در حافظه کپی شد", + "share_not_found": "404 یافت نشد", + "share_not_found_desc": "لینک اشتباه است یا دسترسی غیرفعال شده است.", + "invalid_captcha": "کد امنیتی اشتباه است", + "account_disabled": "حساب کاربری غیرفعال است", + "invalid_login": "نام کاربری یا رمز عبور اشتباه است", + "user_exists": "کاربری با این نام قبلاً ثبت شده است", + "cannot_delete_self": "شما نمی‌توانید خودتان را حذف کنید", + "wrong_share_password": "رمز عبور اشتباه است", + "saving": "در حال ذخیره...", + "select_lang": "انتخاب زبان", + "lang_ru": "Русский", + "lang_en": "English", + "lang_fr": "Français", + "lang_zh": "中文 (Chinese)", + "lang_fa": "فارسی (Persian)", + "backup_title": "پشتیبان‌گیری ساده", + "download_backup": "دانلود data.json", + "restore_backup": "بازیابی از فایل", + "restore_confirm": "آیا مطمئن هستید؟ داده‌های فعلی بازنویسی می‌شوند و برنامه دوباره راه‌اندازی خواهد شد.", + "restore_success": "بازیابی موفقیت‌آمیز بود! در حال راه‌اندازی مجدد...", + "invalid_backup_file": "فایل پشتیبان یا ساختار نامعتبر است", + "config_unavailable": "پیکربندی در دسترس نیست", + "config_unavailable_desc": "این کلاینت از طریق اپلیکیشن اصلی Amnezia ایجاد شده است.\\nکلید خصوصی فقط در دستگاه کاربر ذخیره می‌شود و توسط سرور قابل بازیابی نیست.", + "client_public_key": "کلید عمومی کلاینت:", + "management": "مدیریت", + "server_management": "مدیریت سرور", + "server_management_desc": "انجام اقدامات در سطح سیستم روی دستگاه شما.", + "check_server_services": "بررسی سرویس‌های سرور", + "reboot_server": "راه‌اندازی مجدد سرور", + "clear_server": "پاک‌سازی سرور", + "remove_server": "حذف سرور از پنل", + "telemt_desc": "پروکسی تلگرام بر پایه‌ی MTProxy با پوشش‌های پیشرفته.", + "dns_desc": "سرور DNS شخصی برای مسدود کردن تبلیغات و حفظ حریم خصوصی.", + "dns_internal_hint": "The service runs on the internal network (172.29.172.254) without binding to host ports.", + "telemt_port_hint": "Port for the Telegram proxy (typically 443).", + "socks5_desc": "Single-account SOCKS5 proxy (3proxy) with username/password authentication.", + "socks5_username": "Username", + "socks5_password": "Password", + "socks5_password_placeholder": "Leave empty to auto-generate", + "socks5_password_hint": "If left empty, a random 16-character password will be generated.", + "socks5_port_hint": "TCP port the proxy will listen on. The default in the official Amnezia client is 38080.", + "socks5_change_settings": "Change settings", + "socks5_settings_title": "SOCKS5 — Connection settings", + "socks5_port_change_hint": "Changing the port recreates the container; existing sessions will be dropped.", + "socks5_settings_saved": "SOCKS5 settings saved", + "adguard_desc": "AdGuard Home — DNS-based ad blocker with a web admin UI.", + "adguard_mode": "Installation mode", + "adguard_mode_sidebyside": "Side-by-side", + "adguard_mode_sidebyside_hint": "runs alongside AmneziaDNS on a separate internal IP (172.29.172.253)", + "adguard_mode_replace": "Replace AmneziaDNS", + "adguard_mode_replace_hint": "removes amnezia-dns and takes its IP — VPN clients use AdGuard immediately", + "adguard_dns_port": "DNS port (53)", + "adguard_dns_port_hint": "Internal DNS port served to VPN clients via the docker network.", + "adguard_web_port": "Web UI port", + "adguard_dot_port": "DoT port", + "adguard_doh_port": "DoH port", + "adguard_expose_web": "Expose to internet", + "adguard_expose": "Expose to host", + "adguard_install_hint": "Initial AdGuard setup runs through its built-in wizard via the web UI after install.", + "adguard_internal_ip": "Internal IP", + "adguard_web_ui": "Admin URL", + "adguard_open_ui": "Open Web UI", + "edit_server_title": "Edit server", + "edit_keep_credential": "Leave empty to keep the current value", + "server_saved": "Server settings saved", + "servers_reordered": "Servers reordered", + "ping_checking": "Checking connectivity...", + "offline": "offline", + "api_tokens_title": "API tokens", + "api_tokens_hint": "Bearer tokens for external integrations. Send the token in the `Authorization: Bearer ` header. Tokens have admin-equivalent rights and stop working if their owner is disabled or demoted.", + "api_tokens_empty": "No API tokens yet. Create one to integrate the panel with an external service.", + "api_tokens_create": "Create token", + "api_tokens_create_title": "Create API token", + "api_tokens_name_label": "Name", + "api_tokens_name_placeholder": "e.g. Linear integration, CI bot, monitoring", + "api_tokens_name_hint": "Used to identify this token in the list. The token value itself is generated for you.", + "api_tokens_name_required": "Token name is required", + "api_tokens_created_title": "Token created", + "api_tokens_value_label": "Token value", + "api_tokens_warning_title": "This is the only time you'll see this token.", + "api_tokens_warning_body": "Copy it now and store it in your integration's secret manager. The panel keeps only a hash — if you lose this value you'll need to revoke and recreate the token.", + "api_tokens_revoke": "Revoke", + "api_tokens_revoke_confirm": "Revoke token \"{}\"? Any integration using it will stop working.", + "api_tokens_revoked": "Token revoked", + "api_tokens_created": "Created", + "api_tokens_last_used": "Last used", + "api_tokens_owner": "Owner", + "api_tokens_never": "never", + "coming_soon": "Coming soon", + "promo_star_cta": "Star us on GitHub", + "aivpn_subtitle": "AI-driven protocol selection that picks the right tunnel for the moment. Land it sooner — drop a star.", + "revproxy_title": "Reverse Proxy", + "revproxy_subtitle": "High-performance traffic obfuscation: hide your VPN endpoint behind a polished public-facing site, drop the DPI footprint.", + "warp_hint": "WARP routes this host outbound through Cloudflare. It does not create a public panel URL like Quick Tunnel or ngrok.", + "warp_install_hint": "Install the official Cloudflare WARP client first, then restart the panel.", + "warp_install_required": "Install WARP first", + "warp_connect": "Connect WARP", + "warp_disconnect": "Disconnect", + "warp_connected": "WARP connected", + "warp_disconnected": "WARP disconnected", + "warp_status_unknown": "WARP status is unknown.", + "warp_status_not_installed": "Cloudflare WARP CLI is not installed on this host.", + "warp_status_connected": "Cloudflare WARP is connected.", + "warp_status_connecting": "Cloudflare WARP is connecting.", + "warp_status_disconnected": "Cloudflare WARP is disconnected.", + "warp_status_not_registered": "Cloudflare WARP is installed but not registered yet. Connect will try to register automatically.", + "warp_status_service_unavailable": "Cloudflare WARP service is not available. Make sure warp-svc is running.", + "warp_status_error": "Cloudflare WARP returned an error.", + "install_starting": "Starting installation...", + "server_check_complete": "Check completed", + "server_connection_error": "Connection error", + "connections_load_error": "Error loading connections", + "connection_updated": "Connection updated", + "edit_connection": "Edit connection", + "enable_connection_progress": "Enabling connection...", + "disable_connection_progress": "Disabling connection...", + "connection_enabled": "Connection enabled", + "connection_disabled": "Connection disabled", + "gb": "GB", + "marketplace": "Templates", + "open_marketplace": "Open Templates", + "marketplace_desc": "Install protocol and service templates available for this server.", + "installed_apps": "Installed applications", + "installed_apps_hint": "Only installed protocols and services are shown here. Use Templates to add more.", + "no_installed_apps": "No installed applications yet", + "no_installed_apps_desc": "Open Templates to install protocols or services on this server.", + "install_another": "Install another", + "new_instance": "new instance", + "port_next_instance_hint": "Choose a free UDP port for the additional instance.", + "web_servers": "Web servers", + "nginx_desc": "NGINX web server with Let's Encrypt HTTPS certificate and editable index.html.", + "nginx_domain": "Domain", + "nginx_email": "Let's Encrypt email", + "nginx_port_hint": "HTTPS port exposed on the server. Port 80/TCP must be free and reachable for Let's Encrypt validation.", + "nginx_install_hint": "The domain must already point to this server. Port 80/TCP is used for HTTP-01 certificate validation.", + "site": "Site", + "site_editor": "Site editor", + "site_saved": "Site saved", + "nginx_dns_hint": "Create this DNS record before installation:", + "backup": "Backup", + "backups": "Backups", + "backup_desc": "Backups are created on the server and contain valuable protocol files needed to restore or recreate it later.", + "create_backup": "Create backup", + "creating_backup": "Creating backup...", + "backup_created": "Backup created", + "no_backups": "No backups yet", + "no_backups_desc": "Create the first backup for this protocol.", + "refresh": "Refresh" +} diff --git a/translations/fr.json b/translations/fr.json new file mode 100644 index 0000000..4f4bdc3 --- /dev/null +++ b/translations/fr.json @@ -0,0 +1,390 @@ +{ + "nav_servers": "Serveurs", + "nav_users": "Utilisateurs", + "nav_settings": "Paramètres", + "nav_connections": "Connexions", + "nav_logout": "Déconnexion", + "theme_dark": "Sombre", + "theme_light": "Clair", + "back_to_servers": "← Retour aux serveurs", + "server_check": "Vérifier", + "server_checking": "Vérification...", + "protocols": "Protocoles", + "install": "Installer", + "uninstall": "Désinstaller", + "run": "En cours", + "stop": "Arrêté", + "not_installed": "Pas installé", + "installed": "Installé", + "add_server": "Ajouter un serveur", + "no_servers": "Aucun serveur ajouté", + "name": "Nom", + "host": "Hôte", + "port": "Port", + "status": "Statut", + "actions": "Actions", + "edit": "Modifier", + "delete": "Supprimer", + "save": "Enregistrer", + "cancel": "Annuler", + "loading": "Chargement...", + "copy": "Copier", + "download": "Télécharger", + "config": "Configuration", + "qr_code": "Code QR", + "vpn_key": "Clé VPN", + "clients": "Clients", + "traffic": "Trafic", + "limit": "Limite", + "manage": "Gérer", + "no_protocols": "Aucun protocole", + "add_server_desc": "Ajoutez votre premier serveur VPN pour commencer. Identifiants SSH requis.", + "ssh_host": "Hôte / IP", + "ssh_port": "Port SSH", + "ssh_user": "Utilisateur", + "ssh_password": "Mot de passe", + "ssh_key": "Clé SSH", + "ssh_key_placeholder": "Clé SSH privée", + "ssh_key_hint": "Collez le contenu de votre fichier id_rsa ou id_ed25519", + "connect": "Connecter", + "connecting": "Connexion...", + "server_added": "Serveur ajouté avec succès", + "server_deleted": "Serveur supprimé", + "delete_confirm": "Voulez-vous vraiment supprimer ce serveur ?", + "success": "Succès", + "error": "Erreur", + "info": "Info", + "login_title": "Connexion au Panneau", + "username": "Nom d'utilisateur", + "password": "Mot de passe", + "captcha": "Captcha", + "captcha_placeholder": "Entrez les caractères", + "captcha_hint": "Cliquez pour rafraîchir", + "login": "Connexion", + "logging_in": "Connexion...", + "login_error": "Échec de la connexion", + "check_done": "Vérification terminée", + "check_error": "Erreur de connexion", + "ssh_ok": "Connexion SSH", + "docker_ok": "Docker", + "docker_not_installed": "Docker non installé", + "awg_desc": "Version moderne basée sur awg-go. Obfuscation avancée (S3, S4).", + "awg_legacy_desc": "Version AWG originale. Compatible avec les anciens clients.", + "xray_desc": "Masque le trafic en trafic web normal (XTLS-Reality). Résiste au DPI.", + "not_checked": "Non vérifié", + "connections": "Connexions", + "add": "Ajouter", + "loading_connections": "Chargement des connexions...", + "no_connections": "Aucune connexion", + "no_connections_desc": "Ajoutez votre première connexion pour générer un fichier VPN", + "install_protocol": "Installer le protocole", + "port_default_hint": "Port par défaut : 55424. Assurez-vous qu'il est libre.", + "port_xray_hint": "Port recommandé : 443. Assurez-vous qu'il n'est pas utilisé par un serveur web.", + "reinstall": "Réinstaller", + "uninstall_confirm": "Désinstaller {} ? Toutes les données seront perdues.", + "stop_container_confirm": "Arrêter le conteneur {} ?", + "start_container_confirm": "Démarrer le conteneur {} ?", + "stopping": "Arrêt", + "starting": "Démarrage", + "stopped": "arrêté", + "started": "démarré", + "server_config": "Configuration du serveur", + "add_connection": "Ajouter une connexion", + "connection_name": "Nom de la connexion", + "connection_name_placeholder": "Ex: iPhone, Laptop", + "assign_to_user": "Assigner à l'utilisateur (optionnel)", + "no_assign": "— Aucune assignation —", + "create": "Créer", + "creating": "Création...", + "connection_created": "Connexion \"{}\" créée", + "delete_connection_confirm": "Supprimer cette connexion ? Elle cessera de fonctionner.", + "connection_deleted": "Connexion supprimée", + "config_tab": "📄 Config", + "vpn_key_tab": "🔑 Clé-VPN", + "qr_code_tab": "📱 Code-QR", + "copy_config": "📋 Copier", + "download_conf": "⬇ Télécharger .conf", + "copy_key": "📋 Copier la clé", + "vpn_link_hint": "Collez ce lien dans AmneziaVPN pour une config automatique", + "qr_hint": "Scannez le code QR dans l'application AmneziaVPN", + "no_data": "Aucune donnée", + "start_btn": "▶ Start", + "stop_btn": "⏹ Stop", + "config_btn": "⚙️ Config", + "done": "Terminé", + "installing": "Installation...", + "start_install": "Début de l'installation...", + "check_docker": "Vérification de Docker...", + "prepare_host": "Préparation de l'hôte...", + "build_container": "Construction du conteneur...", + "install_success": "Protocole installé avec succès !", + "install_error": "Erreur d'installation : ", + "qr_error": "Échec de génération du QR code", + "users_title": "Utilisateurs", + "search_placeholder": "Recherche par nom, email ou Telegram...", + "add_user": "Ajouter Utilisateur", + "prev_page": "← Retour", + "next_page": "Suivant →", + "page_info": "Page {} sur {}", + "loading_users": "Chargement des utilisateurs...", + "nothing_found": "Rien trouvé", + "search_empty_desc": "Essayez une autre requête ou créez un utilisateur", + "username_label": "Nom d'utilisateur", + "password_label": "Mot de passe", + "role_label": "Rôle", + "role_user_desc": "User — voit ses propres connexions", + "role_support_desc": "Support — gestion des serveurs", + "role_admin_desc": "Admin — accès complet", + "tg_id_label": "ID Telegram (opt.)", + "email_label": "Email (opt.)", + "traffic_limit_label": "Limite trafic (Go) (0 = illimité)", + "description_label": "Description (opt.)", + "auto_conn_title": "Création auto de connexion (optionnel)", + "server_label": "Serveur", + "no_create_conn": "— Ne pas créer —", + "protocol_label": "Protocole", + "edit_user_title": "Modifier utilisateur : {}", + "edit_user_tg": "ID Telegram (optionnel)", + "edit_user_email": "Email (optionnel)", + "edit_user_limit": "Limite trafic (Go) (0 = illimité)", + "new_password_hint": "Nouveau mot de passe (laisser vide si inchangé)", + "op_type_label": "Type d'opération", + "create_new_conn": "Créer nouvelle connexion", + "link_existing_conn": "Lier existante", + "select_existing_conn": "Sélectionner connexion", + "existing_conn_hint": "Seules les connexions libres sont affichées", + "conn_name_panel": "Nom (dans le panneau)", + "user_conns_title": "Connexions utilisateur", + "no_free_conns": "Aucune connexion libre", + "linking": "Liaison...", + "conn_linked": "Connexion liée", + "enabling": "Activation", + "disabling": "Désactivation", + "user_enabled": "Utilisateur activé", + "user_disabled": "Utilisateur désactivé", + "delete_user_confirm": "Supprimer l'utilisateur ? Ses connexions seront supprimées.", + "share_access": "Partager l'accès", + "enable_public_access": "Activer l'accès public", + "share_password_label": "Mot de passe (optionnel)", + "share_password_hint": "Si défini, requis pour l'accès", + "public_link_label": "Lien public", + "disabled": "Désactivé", + "out_of": "sur", + "settings_title": "Paramètres du Panneau", + "appearance": "🎨 Apparence", + "title_label": "Titre", + "logo_label": "Logo (Emoji ou symbole)", + "subtitle_label": "Sous-titre", + "captcha_title": "🔐 Captcha", + "enable_captcha": "Activer captcha", + "telegram_bot_title": "🤖 Bot Telegram", + "bot_token_label": "Bot Token (@BotFather)", + "bot_status": "Statut", + "bot_running": "✅ En cours", + "bot_stopped": "⏹ Arrêté", + "bot_stop_btn": "⏹ Arrêter", + "bot_start_btn": "▶️ Démarrer", + "bot_hint": "Sauvegardez après modification du token. Le bot redémarrera.", + "api_docs_title": "🔌 Documentation API", + "api_docs_hint": "Utilisez ces interfaces pour explorer l'API", + "tunnels_title": "Tunnels", + "local_server": "Serveur local", + "tunnel_install_enable": "Installer et activer", + "tunnel_enable": "Activer le tunnel", + "tunnel_running": "Tunnel en cours", + "tunnel_stop": "Arrêter", + "tunnel_stopping": "Arrêt...", + "tunnel_stopped": "Tunnel arrêté", + "tunnel_delete": "Supprimer", + "tunnel_deleted": "Tunnel supprimé", + "tunnel_delete_confirm": "Arrêter et supprimer ce binaire de tunnel géré par le panneau ?", + "tunnel_starting": "Démarrage du tunnel...", + "tunnel_started": "Tunnel démarré", + "tunnel_waiting_url": "Tunnel démarré. En attente de l'URL publique...", + "tunnel_no_public_url": "L'URL publique apparaîtra ici après le démarrage du tunnel.", + "tunnels_hint": "Les tunnels rapides exposent ce panneau local sur Internet. Gardez des identifiants administrateur robustes et partagez les URL publiques uniquement avec des utilisateurs de confiance.", + "ngrok_authtoken_placeholder": "ngrok authtoken (optionnel pour certains comptes)", + "import_users_title": "📤 Import Utilisateurs", + "import_source_label": "Source Import / Sync", + "remnawave_url_label": "URL Remnawave", + "api_key_label": "Clé API", + "enable_sync": "Activer synchronisation", + "sync_hint": "Synchro automatique avec Remnawave", + "sync_now_btn": "🔄 Sync maintenant", + "delete_sync_btn": "🗑 Supprimer synchro", + "auto_create_conns": "Créer connexions auto", + "sync_server_label": "Serveur pour nouvelles connexions", + "save_changes": "💾 Enregistrer changements", + "sync_success": "Sync terminée : {} utilisateurs", + "sync_deleted": "Supprimé {} utilisateurs sync", + "delete_sync_confirm": "Supprimer TOUS les utilisateurs synchronisés ? Irréversible.", + "settings_saved": "Paramètres enregistrés", + "bot_started": "Bot démarré", + "bot_stopped_msg": "Bot arrêté", + "sync_running": "Synchronisation...", + "deleting": "Suppression...", + "my_connections_title": "Mes Connexions", + "show_config": "📄 Voir config", + "no_connections_user_desc": "Contactez l'admin pour une connexion", + "share_title": "Accès Connexion", + "vpn_access": "Accès VPN", + "user_label_share": "Utilisateur", + "share_protected_desc": "Accès protégé par mot de passe.", + "auth_success": "Succès Auth", + "loading_share_conns": "Chargement...", + "no_active_conns": "Aucune connexion active.", + "show_settings_btn": "🔑 Voir paramètres", + "copied": "Copié !", + "active": "Actif", + "site_description": "Panneau Web Amnezia — gestion serveurs VPN et AmneziaWG", + "toggle_theme": "Changer thème", + "copied_to_clipboard": "Copié dans le presse-papier", + "share_not_found": "404 Introuvable", + "share_not_found_desc": "Lien invalide ou accès désactivé.", + "invalid_captcha": "Captcha invalide", + "account_disabled": "Compte désactivé", + "invalid_login": "Login ou password incorrect", + "user_exists": "L'utilisateur existe déjà", + "cannot_delete_self": "Vous ne pouvez pas vous supprimer", + "wrong_share_password": "Mauvais mot de passe", + "saving": "Enregistrement...", + "select_lang": "Choisir la langue", + "lang_ru": "Русский", + "lang_en": "English", + "lang_fr": "Français", + "lang_zh": "中文 (Chinese)", + "lang_fa": "فارسی (Persian)", + "backup_title": "Sauvegarde Simple", + "download_backup": "Télécharger data.json", + "restore_backup": "Restaurer depuis un fichier", + "restore_confirm": "Êtes-vous sûr ? Les données actuelles seront écrasées et l'application redémarrera.", + "restore_success": "Restauration réussie ! Redémarrage...", + "invalid_backup_file": "Fichier de sauvegarde ou structure invalide", + "config_unavailable": "Configuration indisponible", + "config_unavailable_desc": "Ce client a été créé via l'application native Amnezia.\\nLa clé privée est stockée uniquement sur l'appareil de l'utilisateur et ne peut pas être récupérée par le serveur.", + "client_public_key": "Clé publique du client :", + "management": "Gestion", + "server_management": "Gestion du serveur", + "server_management_desc": "Effectuer des actions au niveau du système sur votre machine.", + "check_server_services": "Vérifier les services du serveur", + "reboot_server": "Redémarrer le serveur", + "clear_server": "Réinitialiser le serveur", + "remove_server": "Retirer le serveur du panneau", + "telemt_desc": "Proxy Telegram basé sur MTProxy avec obfuscation avancée.", + "dns_desc": "Serveur DNS personnel pour bloquer les publicités et protéger la vie privée.", + "dns_internal_hint": "The service runs on the internal network (172.29.172.254) without binding to host ports.", + "telemt_port_hint": "Port for the Telegram proxy (typically 443).", + "socks5_desc": "Single-account SOCKS5 proxy (3proxy) with username/password authentication.", + "socks5_username": "Username", + "socks5_password": "Password", + "socks5_password_placeholder": "Leave empty to auto-generate", + "socks5_password_hint": "If left empty, a random 16-character password will be generated.", + "socks5_port_hint": "TCP port the proxy will listen on. The default in the official Amnezia client is 38080.", + "socks5_change_settings": "Change settings", + "socks5_settings_title": "SOCKS5 — Connection settings", + "socks5_port_change_hint": "Changing the port recreates the container; existing sessions will be dropped.", + "socks5_settings_saved": "SOCKS5 settings saved", + "adguard_desc": "AdGuard Home — DNS-based ad blocker with a web admin UI.", + "adguard_mode": "Installation mode", + "adguard_mode_sidebyside": "Side-by-side", + "adguard_mode_sidebyside_hint": "runs alongside AmneziaDNS on a separate internal IP (172.29.172.253)", + "adguard_mode_replace": "Replace AmneziaDNS", + "adguard_mode_replace_hint": "removes amnezia-dns and takes its IP — VPN clients use AdGuard immediately", + "adguard_dns_port": "DNS port (53)", + "adguard_dns_port_hint": "Internal DNS port served to VPN clients via the docker network.", + "adguard_web_port": "Web UI port", + "adguard_dot_port": "DoT port", + "adguard_doh_port": "DoH port", + "adguard_expose_web": "Expose to internet", + "adguard_expose": "Expose to host", + "adguard_install_hint": "Initial AdGuard setup runs through its built-in wizard via the web UI after install.", + "adguard_internal_ip": "Internal IP", + "adguard_web_ui": "Admin URL", + "adguard_open_ui": "Open Web UI", + "edit_server_title": "Edit server", + "edit_keep_credential": "Leave empty to keep the current value", + "server_saved": "Server settings saved", + "servers_reordered": "Servers reordered", + "ping_checking": "Checking connectivity...", + "offline": "offline", + "api_tokens_title": "API tokens", + "api_tokens_hint": "Bearer tokens for external integrations. Send the token in the `Authorization: Bearer ` header. Tokens have admin-equivalent rights and stop working if their owner is disabled or demoted.", + "api_tokens_empty": "No API tokens yet. Create one to integrate the panel with an external service.", + "api_tokens_create": "Create token", + "api_tokens_create_title": "Create API token", + "api_tokens_name_label": "Name", + "api_tokens_name_placeholder": "e.g. Linear integration, CI bot, monitoring", + "api_tokens_name_hint": "Used to identify this token in the list. The token value itself is generated for you.", + "api_tokens_name_required": "Token name is required", + "api_tokens_created_title": "Token created", + "api_tokens_value_label": "Token value", + "api_tokens_warning_title": "This is the only time you'll see this token.", + "api_tokens_warning_body": "Copy it now and store it in your integration's secret manager. The panel keeps only a hash — if you lose this value you'll need to revoke and recreate the token.", + "api_tokens_revoke": "Revoke", + "api_tokens_revoke_confirm": "Revoke token \"{}\"? Any integration using it will stop working.", + "api_tokens_revoked": "Token revoked", + "api_tokens_created": "Created", + "api_tokens_last_used": "Last used", + "api_tokens_owner": "Owner", + "api_tokens_never": "never", + "coming_soon": "Coming soon", + "promo_star_cta": "Star us on GitHub", + "aivpn_subtitle": "AI-driven protocol selection that picks the right tunnel for the moment. Land it sooner — drop a star.", + "revproxy_title": "Reverse Proxy", + "revproxy_subtitle": "High-performance traffic obfuscation: hide your VPN endpoint behind a polished public-facing site, drop the DPI footprint.", + "warp_hint": "WARP routes this host outbound through Cloudflare. It does not create a public panel URL like Quick Tunnel or ngrok.", + "warp_install_hint": "Install the official Cloudflare WARP client first, then restart the panel.", + "warp_install_required": "Install WARP first", + "warp_connect": "Connect WARP", + "warp_disconnect": "Disconnect", + "warp_connected": "WARP connected", + "warp_disconnected": "WARP disconnected", + "warp_status_unknown": "WARP status is unknown.", + "warp_status_not_installed": "Cloudflare WARP CLI is not installed on this host.", + "warp_status_connected": "Cloudflare WARP is connected.", + "warp_status_connecting": "Cloudflare WARP is connecting.", + "warp_status_disconnected": "Cloudflare WARP is disconnected.", + "warp_status_not_registered": "Cloudflare WARP is installed but not registered yet. Connect will try to register automatically.", + "warp_status_service_unavailable": "Cloudflare WARP service is not available. Make sure warp-svc is running.", + "warp_status_error": "Cloudflare WARP returned an error.", + "install_starting": "Starting installation...", + "server_check_complete": "Check completed", + "server_connection_error": "Connection error", + "connections_load_error": "Error loading connections", + "connection_updated": "Connection updated", + "edit_connection": "Edit connection", + "enable_connection_progress": "Enabling connection...", + "disable_connection_progress": "Disabling connection...", + "connection_enabled": "Connection enabled", + "connection_disabled": "Connection disabled", + "gb": "GB", + "marketplace": "Templates", + "open_marketplace": "Open Templates", + "marketplace_desc": "Install protocol and service templates available for this server.", + "installed_apps": "Installed applications", + "installed_apps_hint": "Only installed protocols and services are shown here. Use Templates to add more.", + "no_installed_apps": "No installed applications yet", + "no_installed_apps_desc": "Open Templates to install protocols or services on this server.", + "install_another": "Install another", + "new_instance": "new instance", + "port_next_instance_hint": "Choose a free UDP port for the additional instance.", + "web_servers": "Serveurs web", + "nginx_desc": "Serveur web NGINX avec certificat HTTPS Let's Encrypt et index.html modifiable.", + "nginx_domain": "Domaine", + "nginx_email": "Email Let's Encrypt", + "nginx_port_hint": "Port HTTPS exposé sur le serveur. Le port 80/TCP doit être libre et accessible pour la validation Let's Encrypt.", + "nginx_install_hint": "Le domaine doit déjà pointer vers ce serveur. Le port 80/TCP est utilisé pour la validation HTTP-01 du certificat.", + "site": "Site", + "site_editor": "Éditeur du site", + "site_saved": "Site enregistré", + "nginx_dns_hint": "Creez cet enregistrement DNS avant l installation :", + "backup": "Backup", + "backups": "Backups", + "backup_desc": "Backups are created on the server and contain valuable protocol files needed to restore or recreate it later.", + "create_backup": "Create backup", + "creating_backup": "Creating backup...", + "backup_created": "Backup created", + "no_backups": "No backups yet", + "no_backups_desc": "Create the first backup for this protocol.", + "refresh": "Refresh" +} diff --git a/translations/ru.json b/translations/ru.json new file mode 100644 index 0000000..e55b9b5 --- /dev/null +++ b/translations/ru.json @@ -0,0 +1,423 @@ +{ + "nav_servers": "Серверы", + "nav_users": "Пользователи", + "nav_settings": "Настройки", + "nav_connections": "Подключения", + "nav_logout": "Выход", + "theme_dark": "Темная", + "theme_light": "Светлая", + "back_to_servers": "← Назад к серверам", + "server_check": "Проверить", + "server_checking": "Проверка...", + "protocols": "Протоколы", + "install": "Установить", + "uninstall": "Удалить", + "run": "Работает", + "stop": "Остановлен", + "not_installed": "Не установлен", + "installed": "Установлен", + "add_server": "Добавить сервер", + "no_servers": "Серверы не добавлены", + "name": "Название", + "host": "Адрес", + "port": "Порт", + "status": "Статус", + "actions": "Действия", + "edit": "Редактировать", + "delete": "Удалить", + "save": "Сохранить", + "cancel": "Отмена", + "loading": "Загрузка...", + "copy": "Копировать", + "download": "Скачать", + "config": "Конфигурация", + "qr_code": "QR-код", + "vpn_key": "VPN-ключ", + "clients": "Клиенты", + "traffic": "Трафик", + "limit": "Limit", + "manage": "Управление", + "no_protocols": "Нет протоколов", + "add_server_desc": "Добавьте свой первый VPN сервер для начала работы. Вам понадобятся SSH-данные для подключения.", + "ssh_host": "Хост / IP", + "ssh_port": "SSH Порт", + "ssh_user": "Пользователь", + "ssh_password": "Пароль", + "ssh_key": "SSH Ключ", + "ssh_key_placeholder": "Приватный SSH ключ", + "ssh_key_hint": "Вставьте содержимое вашего файла id_rsa или id_ed25519", + "connect": "Подключить", + "connecting": "Подключение...", + "server_added": "Сервер успешно добавлен", + "server_deleted": "Сервер удалён", + "delete_confirm": "Вы уверены, что хотите удалить этот сервер?", + "success": "Успешно", + "error": "Ошибка", + "info": "Информация", + "login_title": "Вход в панель", + "username": "Логин", + "password": "Пароль", + "captcha": "Капча", + "captcha_placeholder": "Введите символы с картинки", + "captcha_hint": "Нажмите для обновления картинки", + "login": "Войти", + "logging_in": "Вход...", + "login_error": "Ошибка входа", + "check_done": "Проверка завершена", + "check_error": "Ошибка подключения", + "ssh_ok": "SSH подключение", + "docker_ok": "Docker", + "docker_not_installed": "Docker не установлен", + "awg_desc": "Новая версия протокола на основе awg-go. Поддерживает расширенную обфускацию с параметрами S3, S4.", + "awg_legacy_desc": "Оригинальная версия AWG на базе ядра WireGuard. Совместима с клиентами старых версий.", + "xray_desc": "Современный протокол с маскировкой под обычный веб-трафик (XTLS-Reality). Устойчив к глубокому анализу пакетов.", + "wireguard_desc": "Стандартный и самый быстрый VPN-протокол. Встроен во все современные ОС, но легко блокируется DPI.", + "not_checked": "Не проверено", + "connections": "Подключения", + "add": "Добавить", + "loading_connections": "Загрузка подключений...", + "no_connections": "Нет подключений", + "no_connections_desc": "Добавьте первое подключение для генерации VPN конфигурации", + "install_protocol": "Установить протокол", + "port_default_hint": "Порт по умолчанию: 55424. Убедитесь, что он не занят", + "port_xray_hint": "Порт по умолчанию: 443 (рекомендуется для Xray). Убедитесь, что он не занят другим веб-сервером.", + "reinstall": "Переустановить", + "uninstall_confirm": "Удалить {}? Все подключения и конфигурации будут потеряны.", + "stop_container_confirm": "Остановить контейнер {}?", + "start_container_confirm": "Запустить контейнер {}?", + "stopping": "Остановка", + "starting": "Запуск", + "stopped": "остановлен", + "started": "запущен", + "server_config": "Конфигурация сервера", + "add_connection": "Добавить подключение", + "connection_name": "Имя подключения", + "connection_name_placeholder": "Например: iPhone, Laptop", + "assign_to_user": "Назначить пользователю (опционально)", + "no_assign": "— Без привязки —", + "create": "Создать", + "creating": "Создание...", + "connection_created": "Подключение \"{}\" создано", + "delete_connection_confirm": "Удалить это подключение? Конфигурация перестанет работать.", + "connection_deleted": "Подключение удалено", + "config_tab": "📄 Конфиг", + "vpn_key_tab": "🔑 VPN-ключ", + "qr_code_tab": "📱 QR-код", + "copy_config": "📋 Копировать", + "download_conf": "⬇ Скачать .conf", + "copy_key": "📋 Копировать ключ", + "vpn_link_hint": "Вставьте эту ссылку в приложение AmneziaVPN для автоматической настройки", + "qr_hint": "Отсканируйте QR-код в приложении AmneziaVPN", + "no_data": "Нет данных", + "start_btn": "▶ Старт", + "stop_btn": "⏹ Стоп", + "config_btn": "⚙️ Конфиг", + "done": "Готово", + "installing": "Установка...", + "start_install": "Начинаем установку...", + "check_docker": "Проверка Docker...", + "prepare_host": "Подготовка хоста...", + "build_container": "Сборка контейнера...", + "install_success": "Протокол установлен успешно!", + "install_error": "Ошибка установки: ", + "qr_error": "Не удалось сгенерировать QR-код", + "users_title": "Пользователи", + "search_placeholder": "Поиск по имени, email или Telegram...", + "add_user": "Добавить пользователя", + "prev_page": "← Назад", + "next_page": "Вперёд →", + "page_info": "Страница {} из {}", + "loading_users": "Загрузка пользователей...", + "nothing_found": "Ничего не найдено", + "search_empty_desc": "Попробуйте изменить запрос или создайте нового пользователя", + "username_label": "Имя пользователя", + "password_label": "Пароль", + "role_label": "Роль", + "role_user_desc": "User — только просмотр своих подключений", + "role_support_desc": "Support — управление серверами", + "role_admin_desc": "Admin — полный доступ", + "tg_id_label": "Telegram ID (опц.)", + "email_label": "Email (опц.)", + "traffic_limit_label": "Лимит трафика (ГБ) (опц., 0 = ∞)", + "expiration_date_label": "Срок действия (до)", + "description_label": "Описание (опц.)", + "auto_conn_title": "Автоматическое создание подключения (опционально)", + "server_label": "Сервер", + "no_create_conn": "— Не создавать подключение —", + "protocol_label": "Протокол", + "edit_user_title": "Редактировать пользователя: {}", + "edit_user_tg": "Telegram ID (опционально)", + "edit_user_email": "Email (опционально)", + "edit_user_limit": "Лимит трафика (ГБ) (0 = ∞)", + "new_password_hint": "Новый пароль (оставьте пустым, если не нужно менять)", + "op_type_label": "Тип операции", + "create_new_conn": "Создать новое подключение", + "link_existing_conn": "Привязать существующее", + "select_existing_conn": "Выберите существующее подключение", + "existing_conn_hint": "Будут показаны только не привязанные к пользователям подключения", + "conn_name_panel": "Имя подключения (в панели)", + "user_conns_title": "Подключения пользователя", + "no_free_conns": "Нет свободных подключений", + "linking": "Привязка...", + "conn_linked": "Подключение привязано", + "enabling": "Включение", + "disabling": "Отключение", + "user_enabled": "Пользователь включён", + "user_disabled": "Пользователь отключён", + "delete_user_confirm": "Удалить пользователя? Все его подключения будут удалены.", + "share_access": "Поделиться доступом", + "enable_public_access": "Включить публичный доступ", + "share_password_label": "Пароль (опционально)", + "share_password_hint": "Если установлен, пользователь должен будет его ввести", + "public_link_label": "Публичная ссылка", + "disabled": "Отключён", + "out_of": "Из", + "settings_title": "Настройки панели", + "appearance": "🎨 Внешний вид", + "title_label": "Заголовок (Title)", + "logo_label": "Логотип (Emoji или символ)", + "subtitle_label": "Подзаголовок (Subtitle)", + "captcha_title": "🔐 Капча", + "enable_captcha": "Включить капчу (multicolorcaptcha)", + "telegram_bot_title": "🤖 Telegram Bot", + "bot_token_label": "Bot Token (от @BotFather)", + "bot_status": "Статус", + "bot_running": "✅ Запущен", + "bot_stopped": "⏹ Остановлен", + "bot_stop_btn": "⏹ Остановить", + "bot_start_btn": "▶️ Запустить", + "bot_hint": "После изменения токена сохраните настройки — бот перезапустится автоматически. Пользователи должны иметь Telegram ID в профиле.", + "api_docs_title": "🔌 API Документация", + "api_docs_hint": "Используйте эти интерфейсы для изучения возможностей API панели", + "tunnels_title": "Туннели", + "local_server": "Локальный сервер", + "tunnel_install_enable": "Установить и включить", + "tunnel_enable": "Включить туннель", + "tunnel_running": "Туннель запущен", + "tunnel_stop": "Остановить", + "tunnel_stopping": "Остановка...", + "tunnel_stopped": "Туннель остановлен", + "tunnel_delete": "Удалить", + "tunnel_deleted": "Туннель удалён", + "tunnel_delete_confirm": "Остановить и удалить бинарный файл туннеля, установленный панелью?", + "tunnel_starting": "Запуск туннеля...", + "tunnel_started": "Туннель запущен", + "tunnel_waiting_url": "Туннель запущен. Ждем публичный адрес...", + "tunnel_no_public_url": "Публичный адрес появится здесь после запуска туннеля.", + "tunnels_hint": "Быстрые туннели публикуют локальную панель в интернете. Используйте надежный пароль администратора и передавайте публичные адреса только доверенным пользователям.", + "ngrok_authtoken_placeholder": "ngrok authtoken (для некоторых аккаунтов необязательно)", + "import_users_title": "📤 Импорт пользователей", + "import_source_label": "Источник импорта / Синхронизации", + "remnawave_url_label": "Remnawave URL", + "api_key_label": "API Key", + "enable_sync": "Включить синхронизацию", + "sync_hint": "Пользователи будут создаваться, отключаться и удаляться автоматически на основе данных из Remnawave", + "sync_now_btn": "🔄 Синхронизировать сейчас", + "delete_sync_btn": "🗑 Удалить синхронизацию", + "auto_create_conns": "Создавать подключения автоматически", + "sync_server_label": "Сервер для новых подключений", + "save_changes": "💾 Сохранить изменения", + "sync_success": "Синхронизация завершена: {} пользователей", + "sync_deleted": "Удалено {} синхронизированных пользователей", + "delete_sync_confirm": "Вы уверены, что хотите удалить ВСЕХ синхронизированных пользователей и их подключения? Это действие необратимо.", + "settings_saved": "Настройки успешно сохранены", + "bot_started": "Бот запущен", + "bot_stopped_msg": "Бот остановлен", + "sync_running": "Синхронизация...", + "deleting": "Удаление...", + "my_connections_title": "Мои подключения", + "show_config": "📄 Показать конфиг", + "no_connections_user_desc": "Обратитесь к администратору для создания VPN подключения", + "share_title": "Доступ к подключениям", + "vpn_access": "VPN Доступ", + "user_label_share": "Пользователь", + "share_protected_desc": "Этот доступ защищен паролем. Пожалуйста, введите его для продолжения.", + "auth_success": "Вход выполнен", + "loading_share_conns": "Загрузка подключений...", + "no_active_conns": "У вас пока нет активных подключений.", + "show_settings_btn": "🔑 Показать настройки", + "copied": "Скопировано!", + "active": "Активен", + "site_description": "Amnezia Web Panel — управление VPN серверами и протоколами AmneziaWG", + "toggle_theme": "Сменить тему", + "copied_to_clipboard": "Скопировано в буфер обмена", + "share_not_found": "404 Не Найдено", + "share_not_found_desc": "Либо ссылка неверна, либо доступ был отключен.", + "invalid_captcha": "Неверная капча", + "account_disabled": "Аккаунт отключён", + "invalid_login": "Неверный логин или пароль", + "user_exists": "Пользователь с таким именем уже существует", + "cannot_delete_self": "Нельзя удалить самого себя", + "wrong_share_password": "Неверный пароль", + "saving": "Сохранение...", + "select_lang": "Выберите язык", + "lang_ru": "Русский", + "lang_en": "English", + "lang_fr": "Français", + "lang_zh": "中文 (Chinese)", + "lang_fa": "فارسی (Persian)", + "backup_title": "Резервное копирование", + "download_backup": "Скачать data.json", + "restore_backup": "Восстановить из файла", + "restore_confirm": "Вы уверены? Текущие данные будут перезаписаны, и приложение перезагрузится.", + "restore_success": "Восстановление успешно! Перезагрузка...", + "invalid_backup_file": "Неверный файл резервной копии или структура", + "config_unavailable": "Конфигурация недоступна", + "config_unavailable_desc": "Этот клиент был создан через нативное приложение Amnezia.\\nПриватный ключ хранится только на устройстве пользователя и не может быть восстановлен сервером.", + "client_public_key": "Публичный ключ клиента:", + "telemt_desc": "Прокси для Telegram на базе MTProxy с продвинутой обфускацией и эмуляцией TLS.", + "tls_emulation": "TLS-эмуляция", + "tls_domain": "Домен маскировки", + "max_connections_limit": "Макс. соединений", + "max_connections_hint": "0 — без ограничений. Ограничивает одновременных пользователей.", + "traffic_reset_strategy_label": "Стратегия сброса трафика", + "traffic_reset_never": "Никогда не сбрасывать", + "traffic_reset_daily": "Сброс ежедневно", + "traffic_reset_weekly": "Сброс еженедельно", + "traffic_reset_monthly": "Сброс ежемесячно", + "traffic_reset_hint": "Как часто следует сбрасывать трафик пользователя", + "traffic_used_total": "Всего потрачено", + "traffic_reset_info": "Следующий сброс: {}", + "services": "Сервисы", + "dns_desc": "Персональный DNS-сервер для блокировки рекламы и защиты приватности ваших запросов.", + "dns_internal_hint": "Сервис будет запущен во внутренней сети (172.29.172.254) без привязки к портам хоста.", + "telemt_port_hint": "Порт для Telegram-прокси (обычно 443).", + "socks5_desc": "SOCKS5-прокси (3proxy) с одной учётной записью и аутентификацией по логину/паролю.", + "socks5_username": "Логин", + "socks5_password": "Пароль", + "socks5_password_placeholder": "Оставьте пустым для автогенерации", + "socks5_password_hint": "Если поле пустое, будет сгенерирован случайный пароль на 16 символов.", + "socks5_port_hint": "TCP-порт, на котором будет слушать прокси. В официальном клиенте Amnezia по умолчанию 38080.", + "socks5_change_settings": "Изменить настройки", + "socks5_settings_title": "SOCKS5 — Настройки подключения", + "socks5_port_change_hint": "Смена порта пересоздаёт контейнер — текущие соединения оборвутся.", + "socks5_settings_saved": "Настройки SOCKS5 сохранены", + "adguard_desc": "AdGuard Home — DNS-блокировщик рекламы с веб-интерфейсом администратора.", + "adguard_mode": "Режим установки", + "adguard_mode_sidebyside": "Рядом с AmneziaDNS", + "adguard_mode_sidebyside_hint": "поднимается параллельно AmneziaDNS на отдельном внутреннем IP (172.29.172.253)", + "adguard_mode_replace": "Заменить AmneziaDNS", + "adguard_mode_replace_hint": "удаляет контейнер amnezia-dns и забирает его IP — VPN-клиенты сразу пойдут в AdGuard", + "adguard_dns_port": "DNS-порт (53)", + "adguard_dns_port_hint": "Внутренний DNS-порт, на который ходят VPN-клиенты через docker-сеть.", + "adguard_web_port": "Порт Web UI", + "adguard_dot_port": "Порт DoT", + "adguard_doh_port": "Порт DoH", + "adguard_expose_web": "Опубликовать наружу", + "adguard_expose": "Опубликовать наружу", + "adguard_install_hint": "Первоначальная настройка AdGuard проходит через мастер на веб-интерфейсе после установки.", + "adguard_internal_ip": "Внутренний IP", + "adguard_web_ui": "Адрес панели", + "adguard_open_ui": "Открыть Web UI", + "edit_server_title": "Изменить сервер", + "edit_keep_credential": "Оставьте пустым, чтобы сохранить текущее значение", + "server_saved": "Настройки сервера сохранены", + "servers_reordered": "Порядок серверов изменён", + "ping_checking": "Проверяем соединение...", + "offline": "недоступен", + "api_tokens_title": "API-токены", + "api_tokens_hint": "Bearer-токены для внешних интеграций. Передавайте токен в заголовке `Authorization: Bearer `. Токены имеют права администратора и перестают работать, если их владелец отключён или понижен в роли.", + "api_tokens_empty": "Пока нет ни одного API-токена. Создайте, чтобы подключить панель к внешнему сервису.", + "api_tokens_create": "Создать токен", + "api_tokens_create_title": "Создание API-токена", + "api_tokens_name_label": "Название", + "api_tokens_name_placeholder": "напр. Linear, CI-бот, мониторинг", + "api_tokens_name_hint": "Нужно, чтобы отличать токен в списке. Сам токен сгенерируется автоматически.", + "api_tokens_name_required": "Укажите название токена", + "api_tokens_created_title": "Токен создан", + "api_tokens_value_label": "Значение токена", + "api_tokens_warning_title": "Это единственный раз, когда вы увидите этот токен.", + "api_tokens_warning_body": "Скопируйте его сейчас и сохраните в менеджере секретов вашей интеграции. Панель хранит только хэш — если потеряете значение, токен придётся отозвать и создать заново.", + "api_tokens_revoke": "Отозвать", + "api_tokens_revoke_confirm": "Отозвать токен «{}»? Любая интеграция, использующая его, перестанет работать.", + "api_tokens_revoked": "Токен отозван", + "api_tokens_created": "Создан", + "api_tokens_last_used": "Последнее использование", + "api_tokens_owner": "Владелец", + "api_tokens_never": "никогда", + "coming_soon": "Скоро", + "promo_star_cta": "Поставить звезду на GitHub", + "aivpn_subtitle": "ИИ-подбор протокола, который сам выбирает правильный туннель под текущие условия. Поможете звездой — выйдет быстрее.", + "revproxy_title": "Reverse Proxy", + "revproxy_subtitle": "Высокопроизводительная маскировка трафика: прячем VPN за обычным сайтом, снижаем заметность для DPI.", + "management": "Управление", + "server_management": "Управление сервером", + "server_management_desc": "Выполнение системных действий на вашей машине.", + "check_server_services": "Проверить сервисы сервера", + "reboot_server": "Перезагрузить сервер", + "clear_server": "Очистить сервер", + "remove_server": "Удалить сервер из панели", + "ssl_title": "SSL / HTTPS Настройки", + "enable_https": "Включить HTTPS", + "panel_port_label": "Порт панели", + "domain_label": "Доменное имя", + "cert_path_label": "Путь к SSL сертификату (.pem)", + "key_path_label": "Путь к приватному ключу (.pem)", + "or_paste_text": "ИЛИ вставьте текст сертификатов", + "cert_text_label": "Содержимое сертификата (CRT)", + "key_text_label": "Содержимое ключа (KEY)", + "ssl_hint": "После включения панель будет доступна по https:// на указанном домене. Убедитесь, что пути к файлам или текстовые данные верны.", + "about_title": "О программе и обновления", + "current_version": "Текущая версия", + "check_updates": "Проверить обновления", + "checking_updates": "Проверка...", + "update_available": "Доступна новая версия", + "download_update": "Скачать обновление", + "up_to_date": "У вас установлена последняя версия", + "warp_hint": "WARP направляет исходящий трафик этого хоста через Cloudflare. Он не создаёт публичный URL панели как Quick Tunnel или ngrok.", + "warp_install_hint": "Сначала установите официальный клиент Cloudflare WARP, затем перезапустите панель.", + "warp_install_required": "Сначала установите WARP", + "warp_connect": "Подключить WARP", + "warp_disconnect": "Отключить", + "warp_connected": "WARP подключён", + "warp_disconnected": "WARP отключён", + "warp_status_unknown": "Статус WARP неизвестен.", + "warp_status_not_installed": "Cloudflare WARP CLI не установлен на этом хосте.", + "warp_status_connected": "Cloudflare WARP подключён.", + "warp_status_connecting": "Cloudflare WARP подключается.", + "warp_status_disconnected": "Cloudflare WARP отключён.", + "warp_status_not_registered": "Cloudflare WARP установлен, но ещё не зарегистрирован. Подключение попробует зарегистрировать его автоматически.", + "warp_status_service_unavailable": "Сервис Cloudflare WARP недоступен. Убедитесь, что warp-svc запущен.", + "warp_status_error": "Cloudflare WARP вернул ошибку.", + "install_starting": "Начинаем установку...", + "server_check_complete": "Проверка завершена", + "server_connection_error": "Ошибка подключения", + "connections_load_error": "Ошибка загрузки подключений", + "connection_updated": "Подключение обновлено", + "edit_connection": "Редактировать подключение", + "enable_connection_progress": "Включение подключения...", + "disable_connection_progress": "Отключение подключения...", + "connection_enabled": "Подключение включено", + "connection_disabled": "Подключение отключено", + "gb": "ГБ", + "marketplace": "Шаблоны", + "open_marketplace": "Открыть шаблоны", + "marketplace_desc": "Установите доступные шаблоны протоколов и сервисов для этого сервера.", + "installed_apps": "Установленные приложения", + "installed_apps_hint": "Здесь отображаются только установленные протоколы и сервисы. Чтобы добавить новые, откройте шаблоны.", + "no_installed_apps": "Пока нет установленных приложений", + "no_installed_apps_desc": "Откройте шаблоны, чтобы установить протоколы или сервисы на этот сервер.", + "install_another": "Установить ещё один", + "new_instance": "новый экземпляр", + "port_next_instance_hint": "Выберите свободный UDP-порт для дополнительного экземпляра.", + "checking_server": "Проверяем сервисы сервера...", + "web_servers": "Веб-серверы", + "nginx_desc": "NGINX веб-сервер с HTTPS-сертификатом Let's Encrypt и редактируемым index.html.", + "nginx_domain": "Домен", + "nginx_email": "Email для Let's Encrypt", + "nginx_port_hint": "HTTPS-порт на сервере. Порт 80/TCP должен быть свободен и доступен для проверки Let's Encrypt.", + "nginx_install_hint": "Домен уже должен указывать на этот сервер. Порт 80/TCP используется для HTTP-01 проверки сертификата.", + "site": "Сайт", + "site_editor": "Редактор сайта", + "site_saved": "Сайт сохранён", + "nginx_dns_hint": "Перед установкой создайте DNS-запись:", + "backup": "Backup", + "backups": "Бекапы", + "backup_desc": "Бекапы создаются на сервере и содержат ценные файлы протокола, нужные для восстановления или повторного запуска без потерь.", + "create_backup": "Создать бекап", + "creating_backup": "Создание бекапа...", + "backup_created": "Бекап создан", + "no_backups": "Бекапов пока нет", + "no_backups_desc": "Создайте первый бекап для этого протокола.", + "refresh": "Обновить" +} diff --git a/translations/zh.json b/translations/zh.json new file mode 100644 index 0000000..a611051 --- /dev/null +++ b/translations/zh.json @@ -0,0 +1,390 @@ +{ + "nav_servers": "服务器", + "nav_users": "用户列表", + "nav_settings": "设置", + "nav_connections": "连接管理", + "nav_logout": "登出", + "theme_dark": "深色模式", + "theme_light": "浅色模式", + "back_to_servers": "← 返回服务器列表", + "server_check": "检查状态", + "server_checking": "正在检查...", + "protocols": "协议", + "install": "安装", + "uninstall": "卸载", + "run": "运行中", + "stop": "已停止", + "not_installed": "未安装", + "installed": "已安装", + "add_server": "添加服务器", + "no_servers": "尚未添加服务器", + "name": "名称", + "host": "地址", + "port": "端口", + "status": "状态", + "actions": "操作", + "edit": "编辑", + "delete": "删除", + "save": "保存", + "cancel": "取消", + "loading": "加载中...", + "copy": "复制", + "download": "下载", + "config": "配置", + "qr_code": "二维码", + "vpn_key": "VPN 密钥", + "clients": "客户端", + "traffic": "流量", + "limit": "限制", + "manage": "管理", + "no_protocols": "无协议", + "add_server_desc": "添加您的第一台 VPN 服务器。需要 SSH 凭据进行连接。", + "ssh_host": "主机 / IP", + "ssh_port": "SSH 端口", + "ssh_user": "用户名", + "ssh_password": "密码", + "ssh_key": "SSH 密钥", + "ssh_key_placeholder": "私钥 (Private Key)", + "ssh_key_hint": "粘贴 id_rsa 或 id_ed25519 文件的内容", + "connect": "连接", + "connecting": "正在连接...", + "server_added": "服务器添加成功", + "server_deleted": "服务器已删除", + "delete_confirm": "确定要删除此服务器吗?", + "success": "成功", + "error": "错误", + "info": "信息", + "login_title": "登录管理面板", + "username": "用户名", + "password": "密码", + "captcha": "验证码", + "captcha_placeholder": "输入图中字符", + "captcha_hint": "点击刷新验证码", + "login": "登录", + "logging_in": "登录中...", + "login_error": "登录失败", + "check_done": "检查完成", + "check_error": "连接错误", + "ssh_ok": "SSH 连接正常", + "docker_ok": "Docker 正常", + "docker_not_installed": "Docker 未安装", + "awg_desc": "基于 awg-go 的新版协议。支持 S3, S4 高级混淆。", + "awg_legacy_desc": "原始 AWG 版本。兼容旧版客户端。", + "xray_desc": "将流量伪装成普通网页流量 (XTLS-Reality),抗封锁能力强。", + "not_checked": "未检查", + "connections": "连接", + "add": "添加", + "loading_connections": "正在加载连接...", + "no_connections": "无连接", + "no_connections_desc": "添加首个连接以生成 VPN 配置文件", + "install_protocol": "安装协议", + "port_default_hint": "默认端口: 55424。请确保端口未被占用。", + "port_xray_hint": "推荐端口: 443。请确保未被其他 Web 服务器使用。", + "reinstall": "重新安装", + "uninstall_confirm": "确定卸载 {}?所有连接和配置都将丢失。", + "stop_container_confirm": "停止容器 {}?", + "start_container_confirm": "启动容器 {}?", + "stopping": "停止中", + "starting": "启动中", + "stopped": "已停止", + "started": "已启动", + "server_config": "服务端配置", + "add_connection": "添加连接", + "connection_name": "连接名称", + "connection_name_placeholder": "例如: iPhone, 笔记本电脑", + "assign_to_user": "分配给用户 (可选)", + "no_assign": "— 不分配 —", + "create": "创建", + "creating": "创建中...", + "connection_created": "连接 \"{}\" 已创建", + "delete_connection_confirm": "确定删除此连接?配置将失效。", + "connection_deleted": "连接已删除", + "config_tab": "📄 配置文件", + "vpn_key_tab": "🔑 VPN 密钥", + "qr_code_tab": "📱 二维码", + "copy_config": "📋 复制配置", + "download_conf": "⬇ 下载 .conf 文件", + "copy_key": "📋 复制密钥", + "vpn_link_hint": "将此链接粘贴到 AmneziaVPN 应用中即可自动配置", + "qr_hint": "使用 AmneziaVPN 应用扫描二维码", + "no_data": "无数据", + "start_btn": "▶ 启动", + "stop_btn": "⏹ 停止", + "config_btn": "⚙️ 配置", + "done": "完成", + "installing": "安装中...", + "start_install": "开始安装...", + "check_docker": "检查 Docker...", + "prepare_host": "准备环境...", + "build_container": "构建容器...", + "install_success": "协议安装成功!", + "install_error": "安装失败: ", + "qr_error": "无法生成二维码", + "users_title": "用户管理", + "search_placeholder": "搜索用户名、邮箱或 Telegram ID...", + "add_user": "添加用户", + "prev_page": "← 上一页", + "next_page": "下一页 →", + "page_info": "第 {} 页,共 {} 页", + "loading_users": "正在加载用户...", + "nothing_found": "未找到匹配项", + "search_empty_desc": "请尝试更改查询条件或创建新用户", + "username_label": "用户名", + "password_label": "密码", + "role_label": "角色", + "role_user_desc": "User — 仅查看自己的连接", + "role_support_desc": "Support — 服务器管理权限", + "role_admin_desc": "Admin — 全部权限", + "tg_id_label": "Telegram ID (可选)", + "email_label": "邮箱 (可选)", + "traffic_limit_label": "流量限制 (GB) (0 = 不限制)", + "description_label": "备注 (可选)", + "auto_conn_title": "自动创建连接 (可选)", + "server_label": "服务器", + "no_create_conn": "— 不自动创建 —", + "protocol_label": "协议", + "edit_user_title": "编辑用户: {}", + "edit_user_tg": "Telegram ID (可选)", + "edit_user_email": "邮箱 (可选)", + "edit_user_limit": "流量限制 (GB) (0 = 不限制)", + "new_password_hint": "新密码 (如不修改请留空)", + "op_type_label": "操作类型", + "create_new_conn": "创建新连接", + "link_existing_conn": "关联现有连接", + "select_existing_conn": "选择现有连接", + "existing_conn_hint": "仅显示尚未关联用户的连接", + "conn_name_panel": "连接名称 (面板显示)", + "user_conns_title": "用户连接列表", + "no_free_conns": "无可用空闲连接", + "linking": "关联中...", + "conn_linked": "连接关联成功", + "enabling": "启用中", + "disabling": "禁用中", + "user_enabled": "用户已启用", + "user_disabled": "用户已禁用", + "delete_user_confirm": "确定删除该用户?其所有连接都将被删除。", + "share_access": "分享访问权限", + "enable_public_access": "启用公开访问", + "share_password_label": "密码 (可选)", + "share_password_hint": "如设置,访问者需输入密码", + "public_link_label": "公开链接", + "disabled": "已禁用", + "out_of": "/", + "settings_title": "面板设置", + "appearance": "🎨 外观设置", + "title_label": "页面标题 (Title)", + "logo_label": "图标 (Emoji 或 字符)", + "subtitle_label": "副标题 (Subtitle)", + "captcha_title": "🔐 验证码", + "enable_captcha": "启用登录验证码", + "telegram_bot_title": "🤖 Telegram 机器人", + "bot_token_label": "Bot Token (来自 @BotFather)", + "bot_status": "状态", + "bot_running": "✅ 运行中", + "bot_stopped": "⏹ 已停止", + "bot_stop_btn": "⏹ 停止", + "bot_start_btn": "▶️ 启动", + "bot_hint": "修改 Token 后请保存,机器人将自动重启。用户需在个人资料中填写 Telegram ID。", + "api_docs_title": "🔌 API 文档", + "api_docs_hint": "使用这些接口了解面板功能", + "tunnels_title": "Tunnels", + "local_server": "本地服务器", + "tunnel_install_enable": "安装并启用", + "tunnel_enable": "启用隧道", + "tunnel_running": "隧道运行中", + "tunnel_stop": "停止", + "tunnel_stopping": "正在停止...", + "tunnel_stopped": "隧道已停止", + "tunnel_delete": "删除", + "tunnel_deleted": "隧道已删除", + "tunnel_delete_confirm": "停止并删除由面板管理的隧道二进制文件?", + "tunnel_starting": "正在启动隧道...", + "tunnel_started": "隧道已启动", + "tunnel_waiting_url": "隧道已启动,正在等待公网地址...", + "tunnel_no_public_url": "隧道启动后公网地址会显示在这里。", + "tunnels_hint": "快速隧道会将本地面板暴露到互联网。请使用强管理员密码,并仅与可信用户共享公网地址。", + "ngrok_authtoken_placeholder": "ngrok authtoken(某些账号可选)", + "import_users_title": "📤 导入用户", + "import_source_label": "导入 / 同步源", + "remnawave_url_label": "Remnawave 地址", + "api_key_label": "API 密钥", + "enable_sync": "开启同步", + "sync_hint": "将根据 Remnawave 数据自动创建、禁用和删除用户", + "sync_now_btn": "🔄 立即同步", + "delete_sync_btn": "🗑 删除同步数据", + "auto_create_conns": "自动创建连接", + "sync_server_label": "新连接的服务器", + "save_changes": "💾 保存修改", + "sync_success": "同步完成: {} 个用户已更新", + "sync_deleted": "已删除 {} 个同步用户", + "delete_sync_confirm": "确定要删除所有同步用户及其连接吗?此操作不可逆。", + "settings_saved": "设置已保存", + "bot_started": "机器人已启动", + "bot_stopped_msg": "机器人已停止", + "sync_running": "同步中...", + "deleting": "删除中...", + "my_connections_title": "我的连接", + "show_config": "📄 查看配置", + "no_connections_user_desc": "请联系管理员创建 VPN 连接", + "share_title": "访问连接", + "vpn_access": "VPN 访问", + "user_label_share": "用户", + "share_protected_desc": "此访问受密码保护。请输入密码以继续。", + "auth_success": "身份验证通过", + "loading_share_conns": "正在加载连接...", + "no_active_conns": "您目前没有活跃连接。", + "show_settings_btn": "🔑 显示设置", + "copied": "已复制!", + "active": "活跃", + "site_description": "Amnezia Web Panel — VPN 服务器及 AmneziaWG 协议管理工具", + "toggle_theme": "切换主题", + "copied_to_clipboard": "已复制到剪贴板", + "share_not_found": "404 页面未找到", + "share_not_found_desc": "链接无效或访问已被禁用。", + "invalid_captcha": "验证码错误", + "account_disabled": "账户已被禁用", + "invalid_login": "用户名或密码错误", + "user_exists": "该用户名已存在", + "cannot_delete_self": "您无法删除自己的账户", + "wrong_share_password": "密码错误", + "saving": "正在保存...", + "select_lang": "选择语言", + "lang_ru": "Русский", + "lang_en": "English", + "lang_fr": "Français", + "lang_zh": "中文 (Chinese)", + "lang_fa": "فارسی (Persian)", + "backup_title": "简易备份", + "download_backup": "下载 data.json", + "restore_backup": "从文件恢复", + "restore_confirm": "您确定吗?当前数据将被覆盖,应用程序将重新启动。", + "restore_success": "恢复成功!正在重启...", + "invalid_backup_file": "备份文件无效或结构错误", + "config_unavailable": "配置文件不可用", + "config_unavailable_desc": "此客户端是通过 Amnezia 原生应用创建的。\\n私钥仅存储在用户设备上,服务器无法恢复。", + "client_public_key": "客户端公钥:", + "management": "管理", + "server_management": "服务器管理", + "server_management_desc": "在您的机器上执行系统级别的操作。", + "check_server_services": "检查服务器服务", + "reboot_server": "重启服务器", + "clear_server": "清除服务器", + "remove_server": "从面板移除服务器", + "telemt_desc": "基于 MTProxy 的 Telegram 代理,支持高级混淆。", + "dns_desc": "防止广告和保护隐私的个人 DNS 服务器。", + "dns_internal_hint": "The service runs on the internal network (172.29.172.254) without binding to host ports.", + "telemt_port_hint": "Port for the Telegram proxy (typically 443).", + "socks5_desc": "Single-account SOCKS5 proxy (3proxy) with username/password authentication.", + "socks5_username": "Username", + "socks5_password": "Password", + "socks5_password_placeholder": "Leave empty to auto-generate", + "socks5_password_hint": "If left empty, a random 16-character password will be generated.", + "socks5_port_hint": "TCP port the proxy will listen on. The default in the official Amnezia client is 38080.", + "socks5_change_settings": "Change settings", + "socks5_settings_title": "SOCKS5 — Connection settings", + "socks5_port_change_hint": "Changing the port recreates the container; existing sessions will be dropped.", + "socks5_settings_saved": "SOCKS5 settings saved", + "adguard_desc": "AdGuard Home — DNS-based ad blocker with a web admin UI.", + "adguard_mode": "Installation mode", + "adguard_mode_sidebyside": "Side-by-side", + "adguard_mode_sidebyside_hint": "runs alongside AmneziaDNS on a separate internal IP (172.29.172.253)", + "adguard_mode_replace": "Replace AmneziaDNS", + "adguard_mode_replace_hint": "removes amnezia-dns and takes its IP — VPN clients use AdGuard immediately", + "adguard_dns_port": "DNS port (53)", + "adguard_dns_port_hint": "Internal DNS port served to VPN clients via the docker network.", + "adguard_web_port": "Web UI port", + "adguard_dot_port": "DoT port", + "adguard_doh_port": "DoH port", + "adguard_expose_web": "Expose to internet", + "adguard_expose": "Expose to host", + "adguard_install_hint": "Initial AdGuard setup runs through its built-in wizard via the web UI after install.", + "adguard_internal_ip": "Internal IP", + "adguard_web_ui": "Admin URL", + "adguard_open_ui": "Open Web UI", + "edit_server_title": "Edit server", + "edit_keep_credential": "Leave empty to keep the current value", + "server_saved": "Server settings saved", + "servers_reordered": "Servers reordered", + "ping_checking": "Checking connectivity...", + "offline": "offline", + "api_tokens_title": "API tokens", + "api_tokens_hint": "Bearer tokens for external integrations. Send the token in the `Authorization: Bearer ` header. Tokens have admin-equivalent rights and stop working if their owner is disabled or demoted.", + "api_tokens_empty": "No API tokens yet. Create one to integrate the panel with an external service.", + "api_tokens_create": "Create token", + "api_tokens_create_title": "Create API token", + "api_tokens_name_label": "Name", + "api_tokens_name_placeholder": "e.g. Linear integration, CI bot, monitoring", + "api_tokens_name_hint": "Used to identify this token in the list. The token value itself is generated for you.", + "api_tokens_name_required": "Token name is required", + "api_tokens_created_title": "Token created", + "api_tokens_value_label": "Token value", + "api_tokens_warning_title": "This is the only time you'll see this token.", + "api_tokens_warning_body": "Copy it now and store it in your integration's secret manager. The panel keeps only a hash — if you lose this value you'll need to revoke and recreate the token.", + "api_tokens_revoke": "Revoke", + "api_tokens_revoke_confirm": "Revoke token \"{}\"? Any integration using it will stop working.", + "api_tokens_revoked": "Token revoked", + "api_tokens_created": "Created", + "api_tokens_last_used": "Last used", + "api_tokens_owner": "Owner", + "api_tokens_never": "never", + "coming_soon": "Coming soon", + "promo_star_cta": "Star us on GitHub", + "aivpn_subtitle": "AI-driven protocol selection that picks the right tunnel for the moment. Land it sooner — drop a star.", + "revproxy_title": "Reverse Proxy", + "revproxy_subtitle": "High-performance traffic obfuscation: hide your VPN endpoint behind a polished public-facing site, drop the DPI footprint.", + "warp_hint": "WARP routes this host outbound through Cloudflare. It does not create a public panel URL like Quick Tunnel or ngrok.", + "warp_install_hint": "Install the official Cloudflare WARP client first, then restart the panel.", + "warp_install_required": "Install WARP first", + "warp_connect": "Connect WARP", + "warp_disconnect": "Disconnect", + "warp_connected": "WARP connected", + "warp_disconnected": "WARP disconnected", + "warp_status_unknown": "WARP status is unknown.", + "warp_status_not_installed": "Cloudflare WARP CLI is not installed on this host.", + "warp_status_connected": "Cloudflare WARP is connected.", + "warp_status_connecting": "Cloudflare WARP is connecting.", + "warp_status_disconnected": "Cloudflare WARP is disconnected.", + "warp_status_not_registered": "Cloudflare WARP is installed but not registered yet. Connect will try to register automatically.", + "warp_status_service_unavailable": "Cloudflare WARP service is not available. Make sure warp-svc is running.", + "warp_status_error": "Cloudflare WARP returned an error.", + "install_starting": "Starting installation...", + "server_check_complete": "Check completed", + "server_connection_error": "Connection error", + "connections_load_error": "Error loading connections", + "connection_updated": "Connection updated", + "edit_connection": "Edit connection", + "enable_connection_progress": "Enabling connection...", + "disable_connection_progress": "Disabling connection...", + "connection_enabled": "Connection enabled", + "connection_disabled": "Connection disabled", + "gb": "GB", + "marketplace": "Templates", + "open_marketplace": "Open Templates", + "marketplace_desc": "Install protocol and service templates available for this server.", + "installed_apps": "Installed applications", + "installed_apps_hint": "Only installed protocols and services are shown here. Use Templates to add more.", + "no_installed_apps": "No installed applications yet", + "no_installed_apps_desc": "Open Templates to install protocols or services on this server.", + "install_another": "Install another", + "new_instance": "new instance", + "port_next_instance_hint": "Choose a free UDP port for the additional instance.", + "web_servers": "Web servers", + "nginx_desc": "NGINX web server with Let's Encrypt HTTPS certificate and editable index.html.", + "nginx_domain": "Domain", + "nginx_email": "Let's Encrypt email", + "nginx_port_hint": "HTTPS port exposed on the server. Port 80/TCP must be free and reachable for Let's Encrypt validation.", + "nginx_install_hint": "The domain must already point to this server. Port 80/TCP is used for HTTP-01 certificate validation.", + "site": "Site", + "site_editor": "Site editor", + "site_saved": "Site saved", + "nginx_dns_hint": "Create this DNS record before installation:", + "backup": "Backup", + "backups": "Backups", + "backup_desc": "Backups are created on the server and contain valuable protocol files needed to restore or recreate it later.", + "create_backup": "Create backup", + "creating_backup": "Creating backup...", + "backup_created": "Backup created", + "no_backups": "No backups yet", + "no_backups_desc": "Create the first backup for this protocol.", + "refresh": "Refresh" +}