diff --git a/CHANGELOG.md b/CHANGELOG.md
index 603bb4c..4459b30 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,240 @@ All notable changes to this project are documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [1.2.0] - Unreleased
+## [1.3.0] - 2026-09-26
+
+Row-Template now installs on **PasarGuard** and **Rebecca** as well as 3X-UI,
+and ships two more designs. A minor release: nothing changes for an existing
+3X-UI install except what is listed below, and Row stays the default design.
+It also carries every fix prepared for 1.2.1, which was not released on its
+own.
+
+### Added
+
+- **PasarGuard support.** PasarGuard is supported from this release: detect,
+ install, activate, verify, back up, restore and uninstall, on the official
+ Docker install and on a source install (`pasarguard.service`). The page is
+ placed at `/var/lib/pasarguard/templates/row-template/index.html` (or inside
+ your own `CUSTOM_TEMPLATES_DIRECTORY`) and selected by one marked block
+ appended to `/opt/pasarguard/.env`; a running panel is restarted once. None
+ of your own `.env` lines is edited, and uninstall returns the file to its
+ exact previous bytes. `row-template verify` also reports the two panel
+ settings that still take precedence over the page: an admin's own
+ `sub_template`, and `disable_sub_template`.
+- **Rebecca support.** Rebecca 1.x — the Go edition, which Rebecca publishes for
+ its binary install — is supported from this release, with the same seven
+ operations. The page is placed at
+ `/var/lib/rebecca/templates/row-template/index.html` (or inside your own
+ custom templates directory) and selected in the newest
+ `subscription_settings` row, which Rebecca reads on every request — so
+ nothing is ever restarted. Activation is automatic with the default SQLite
+ database and `sqlite3`; with MySQL/MariaDB the page is still placed and the
+ installer prints the two values to enter in the dashboard. `NULL`, empty and
+ a set templates directory are each restored exactly.
+- **Panel detection and choice.** The installer finds the panel on the server
+ and installs for it (`/etc/3x-ui/sub_templates/row-template` for 3X-UI,
+ `/etc/row-template` for PasarGuard and Rebecca). A panel counts only when two
+ independent signals agree; a half-installed panel is refused, not guessed at.
+ On a server with more than one panel it asks, or reads
+ `RT_PANEL=3xui|pasarguard|rebecca` in a script.
+- **Transactional activation on PasarGuard and Rebecca.** The panel's state is
+ snapshotted, changed and verified; if any step fails it is restored exactly,
+ and the installer says so — and shows the real cause.
+- **Two new designs: Meter and Notebook.** Meter is a calm instrument
+ dashboard of rounded cards with a segmented traffic meter; Notebook is a
+ page from a dotted notebook, hand-inked. Both were contributed by the
+ project's author, ported onto the shared runtime, and held to the same
+ contract as the other fifteen — seventeen designs in all, on every panel.
+- **Every design, for every panel.** Each release now carries a PasarGuard
+ (Jinja2) and a Rebecca (pongo2) page for every design, under `shells/`,
+ checksum-verified like the 3X-UI pages.
+
+### Fixed
+
+- **Rolling back to a backup taken under 1.1.0 works.** 1.2.x refused it with
+ "backup artifact matches no installed template". A backup that names its
+ design is restored as that design; one whose page is none of this release's
+ designs (1.1.0's) is restored as this release's Row, so `verify`, design
+ switching and updates keep working afterwards.
+- **A successful rollback is reported as a success.** The transaction engine
+ checked, after restoring the panel, that the panel was still pointing at
+ Row-Template's directory — which is exactly the state a correct rollback has
+ just undone. Every rollback therefore ended in "the rollback failed" even
+ when the panel had been restored perfectly. The engine no longer asks that
+ question: the restore verifies itself. Each panel adapter now re-reads the
+ panel's own setting after restoring and confirms it matches the value it
+ recorded before changing anything, and a restore that does not land is
+ reported as a failed rollback with the real cause. A regression test pins
+ this: the engine must never re-run the forward check after a restore.
+- **The manual PasarGuard instructions are complete.** When activation cannot
+ be done automatically, the installer printed only `SUBSCRIPTION_PAGE_TEMPLATE`
+ and told you to edit `.env` — but the page had not been copied anywhere the
+ panel could read. It now prints both the copy and the two `.env` values
+ (`CUSTOM_TEMPLATES_DIRECTORY` and `SUBSCRIPTION_PAGE_TEMPLATE`), and says to
+ keep your own templates directory if you already have one.
+- **A rollback right after a change undoes that change.** Backup names have
+ one-second resolution, and two backups made in the same second — a design
+ switch followed at once by `row-template rollback --auto`, which snapshots
+ the current state first — shared one directory. The newer snapshot
+ overwrote the older one, so the rollback re-applied the state it was meant
+ to undo. A backup now waits for the next second rather than reuse a name.
+- **The live check after `config`, `update` and `rollback` runs on 3X-UI.**
+ It always said "skipped (no test URL available without sqlite3)", even with
+ `sqlite3` installed, because those commands had not located the panel
+ database. And the check made right after activation no longer warns "could
+ not reach the subscription endpoint" while 3X-UI is still restarting.
+- **A page change that cannot reach PasarGuard or Rebecca changes nothing.**
+ Regenerating the page (a rebrand, a design switch, an update) replaced
+ `sub.html` before copying it into the panel; if that copy failed, `sub.html`
+ was left newer than the page the panel serves. It is now put back.
+- **A valid page is never refused under load.** The structural check before
+ every install, update and design switch read the page through
+ `head | grep -q`. On a busy server `grep -q` could stop reading before `head`
+ finished writing, and the shell then reported the match as a failure —
+ "generated template does not begin with " for a perfectly
+ valid page, about once in 150 checks. Every such check is now written so
+ that it cannot be cut short.
+- All fixes prepared for 1.2.1 (below): one `row-template update` is enough to
+ move from 1.1.0, misplaced designs are moved back, branding works on an
+ install the 1.1.0 updater left incomplete, and `verify` names missing and
+ damaged designs.
+
+### Security
+
+- **Every value is escaped on every panel.** PasarGuard renders pages with a
+ non-sandboxed Jinja2 whose autoescaping is off. Every PasarGuard and Rebecca
+ page therefore wraps its body in an explicit autoescape block, and is tested
+ with the panels' real engines against hostile usernames, notes, links and
+ malformed data.
+- **Branding can never open a template tag.** `{` and `}` in your service name,
+ support link or logo are written as `{` and `}`, so no branding
+ value can start a Jinja2 or pongo2 expression.
+- **Panel secrets stay where they are.** PasarGuard's `.env` and Rebecca's
+ database URL are read only for the keys the installer needs, never printed,
+ and never copied into a backup. A MySQL/MariaDB password is never asked for
+ or read.
+- **Backups record their panel** and are never restored onto another one.
+
+### Changed
+
+- `row-template version` shows the panel it serves; on 3X-UI it still shows the
+ minimum-supported and detected versions.
+- `row-template uninstall` returns each panel to the page it had before
+ Row-Template, and leaves a page you chose afterwards alone.
+- The `on_hold` state on PasarGuard and Rebecca is shown as active: with its
+ "starts on first connection" duration on PasarGuard, and with an unknown
+ expiry on Rebecca, which does not give the page that duration
+ (`docs/design/PANEL-ON-HOLD-DECISION.md`).
+
+### Known limitations
+
+- On PasarGuard and Rebecca the page shows the values as of when it was opened;
+ live refresh (`?format=info`) is 3X-UI only, because both panels serve live
+ status on a path suffix.
+- PasarGuard's page title (`subTitle`) and Clash templates are not produced.
+- Rebecca on MySQL/MariaDB needs its one setting entered in the dashboard.
+- Rebecca's Docker image (`rebeccapanel/rebecca` on Docker Hub) is still the
+ 0.0.x Python edition, which cannot render this page. The installer
+ identifies it and refuses before changing anything; Rebecca's own
+ `rebecca migrate-binary` moves a Docker install to 1.x.
+
+### Documentation
+
+- The compatibility page, installation, configuration and troubleshooting
+ cover all three panels, in English, Persian and Arabic; the READMEs in all
+ five languages describe PasarGuard and Rebecca as supported.
+- `docs/design/PASARGUARD-INSTALLER-AUDIT.md` and
+ `docs/design/REBECCA-INSTALLER-AUDIT.md` record, from each panel's source,
+ what activation is and how the installer follows it.
+
+### Development
+
+- The test suite renders the PasarGuard and Rebecca pages with the real
+ engines, and needs Python 3 with Jinja2 as well as Go; a missing engine is a
+ failure, never a skip.
+- `tools/make-release.sh` writes checksums in the text form on every platform.
+
+### Upgrading
+
+- From **1.2.0** or **1.1.0** on 3X-UI: run `row-template update`. From 1.1.0,
+ the next `row-template`, `row-template config` or `row-template verify`
+ completes the install. Your design, branding and panel wiring are kept.
+- On **PasarGuard** or **Rebecca**: run the installer. Earlier releases did not
+ install on these panels. Rebecca must be 1.x (its binary install); a Docker
+ Rebecca is 0.0.x and is refused until it is moved to 1.x.
+- **Rolling back after the update.** `row-template update` backs up the version
+ it replaces, and `row-template rollback --to ` returns to its page
+ and branding. A rollback restores the page and the recorded version, not the
+ manager itself: `row-template` stays 1.3.0 and reports the version it rolled
+ back to, and the next `row-template update` returns to 1.3.0. Only the two
+ newest backups are kept, so the pre-update backup is replaced after two
+ further changes (a design switch, an update or a rollback each make one).
+
+## [1.2.1] - Unreleased (shipped in 1.3.0)
+
+Fixes the update from 1.1.0, which could leave the manager with no designs to
+choose from. 3X-UI (>= 3.6.0) stays the only supported panel.
+
+### Fixed
+
+- **One `row-template update` is enough to move from 1.1.0.** 1.1.0's own
+ updater installs the new version but copies only four files, so in 1.2.0 the
+ designs were missing until a second update, and **Reconfigure branding →
+ Template** said "No templates are installed". Now the first time you open
+ `row-template`, or run `row-template config` or `row-template verify` as
+ root, after the update, it downloads the rest of the same release — every
+ design and the remaining installer files, checksum-verified — before doing
+ anything else. It downloads the version you have installed, never a newer
+ one, and changes nothing else: the live page, branding, selected design and
+ backups stay as they are. If the release cannot be reached, it says so and
+ tries again the next time the manager opens.
+- **Designs found outside their folder are moved back.** The designs belong in
+ `dist/templates/`. A copy at the install root's `templates/` — where a copied
+ or extracted release leaves it — is now moved into place automatically by
+ `install`, `update` and `verify`. Each design is checked against its own
+ checksum first; one that fails is reported and left where it is, and files
+ Row-Template does not recognise are never removed.
+- **Changing branding works on an install the 1.1.0 updater left incomplete.**
+ `row-template config` and the manager's branding editors refused with "the
+ template selection could not be reconciled" until a second update; they now
+ complete the install first.
+- **`row-template verify` names missing and damaged designs.** A design that
+ fails its checksum is reported by name as a failure; missing designs are a
+ warning that names them. It previously reported a failing store without
+ saying which design, and did not report missing ones at all.
+
+### Changed
+
+- `row-template verify` is no longer strictly read-only. Run as root, it first
+ repairs the template store — moving misplaced designs back into place and
+ downloading any the installed version is missing, from that same release —
+ and then checks it. It makes no other change, and none at all when run
+ without root.
+
+### Documentation
+
+- The compatibility page lists, per panel, what the installer can do today:
+ detection, install, activation, verification, and backup and rollback. For
+ PasarGuard and Rebecca the answer is none of them — only the page shells are
+ built and packaged — so both stay **research targets, not supported panels**.
+ A test checks every README and compatibility page against the installer.
+
+### Known issues
+
+- Rolling back from 1.2.x to a backup taken under 1.1.0 fails with "backup
+ artifact matches no installed template": 1.1.0's page is not one of the
+ current release's designs. The rollback stops before changing anything, so
+ the running page stays as it was. Rolling back to a backup taken under 1.2.x
+ is not affected.
+
+### Upgrading
+
+- From **1.1.0**: run `row-template update`. The next `row-template`,
+ `row-template config` or `row-template verify` completes the install.
+- From **1.2.0**: run `row-template update`. This also completes a 1.2.0
+ install that the 1.1.0 updater left without its designs.
+
+## [1.2.0] - 2026-09-24
Turns Row-Template from one page into a collection of designs. A minor release:
Row stays the default design, and 3X-UI (>= 3.6.0) stays the only supported
@@ -84,7 +317,8 @@ panel.
page updates and your branding is kept — but copies only the library and
the command, so only Row is available. The second, carried out by 1.2.0,
installs every design and the remaining installer files. `row-template
- verify` reports whether the second run is still needed.
+ verify` reports whether the second run is still needed. (Fixed in 1.2.1,
+ which needs one run.)
## [1.1.0] - 2026-08-30
@@ -162,6 +396,8 @@ First stable release.
- Requires 3X-UI (MHSanaei) **>= 3.6.0**; validated against stock 3.7.0.
- Recommended operating system: Ubuntu 24.04 LTS (x86_64).
-[1.2.0]: https://github.com/iitzSeriZdev/Row-Template/compare/v1.1.0...main
+[1.3.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.3.0
+[1.2.1]: https://github.com/iitzSeriZdev/Row-Template/compare/v1.2.0...v1.3.0
+[1.2.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.2.0
[1.1.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.1.0
[1.0.0]: https://github.com/iitzSeriZdev/Row-Template/releases/tag/v1.0.0
diff --git a/PROVENANCE.md b/PROVENANCE.md
index 58d6a7a..532c405 100644
--- a/PROVENANCE.md
+++ b/PROVENANCE.md
@@ -13,7 +13,7 @@ Every release published on GitHub carries these assets:
| ----- | ------- |
| `row-template-.tar.gz` | The runtime payload — see below. |
| `SHA256SUMS` | The SHA-256 checksum of the tarball above. |
-| `manifest.txt` | Plain-text metadata (`name`, `version`, `artifact`, `min_xui`, `created`), parsed as data — never executed. |
+| `manifest.txt` | Plain-text metadata (`name`, `version`, `artifact`, `min_xui`, `created`), parsed as data — never executed. `min_xui` applies to 3X-UI only. |
| `install.sh` | The bootstrap used by the one-command installer. |
The tarball expands to a single `row-template-/` directory:
@@ -21,12 +21,21 @@ The tarball expands to a single `row-template-/` directory:
| Path | Contents |
| ---- | -------- |
| `template.html` | The Row design, the page an older installed version updates against. |
-| `templates//template.html` (+ `.sha256`) | Every selectable design, each with its own checksum. |
-| `shells///shell.html` (+ `.sha256`) | Each design's page shell per panel, packaged for research; the installer does not place them. |
+| `templates//template.html` (+ `.sha256`) | Every selectable design for 3X-UI, each with its own checksum. |
+| `shells///shell.html` (+ `.sha256`) | Every design for every panel, each with its own checksum. On PasarGuard (Jinja2) and Rebecca 1.x (pongo2) the installer places the one you select, and refuses a page built for another panel or by a release before 1.3.0. `shells/3xui/` is byte-identical to `templates/`, which is what 3X-UI installs use. |
| `VERSION`, `install.sh`, `lib/`, `bin/` | The version, the installer and the `row-template` manager. |
-| `panels/` | The panel interface layer the manager loads; installed next to `lib/`. |
+| `panels/` | The panel interface and one adapter per panel (`3xui.sh`, `pasarguard.sh`, `rebecca.sh`); installed next to `lib/`. |
| `SHA256SUMS` | The checksum of every payload file, so the contents can be checked after extraction as well. |
+Every design is built from this repository's own sources (`src/`). Meter and
+Notebook (1.3.0) were contributed by the project's author and ported onto the
+shared runtime; like every other design they contain no third-party code beyond
+the bundled QR generator and font listed in the README's License section. The
+PasarGuard and Rebecca pages contain no code from either panel: both panels are
+AGPL-3.0, so the preludes and the test harnesses that render them with the
+panels' real engines are independent implementations, written from the source
+audits in `docs/design/`.
+
The build is deterministic: the same sources always produce a byte-identical
`row-template-.tar.gz`. Anyone can rebuild it from a checkout with
`tools/make-release.sh` (which needs Node.js to build the designs) and compare
diff --git a/README.ar.md b/README.ar.md
index 82f6533..7964c42 100644
--- a/README.ar.md
+++ b/README.ar.md
@@ -6,7 +6,7 @@
- صفحة اشتراك مصقولة ومكتفية ذاتيًا للوحات 3X-UI — خمسة عشر تصميمًا، كلٌّ منها ملف HTML واحد، قابلة لإعادة التسمية بالكامل (white-label)، ودون أي طلبات إلى أطراف ثالثة من الصفحة التي يفتحها مشتركوك.
+ صفحة اشتراك مصقولة ومكتفية ذاتيًا للوحات 3X-UI وPasarGuard وRebecca — سبعة عشر تصميمًا، كلٌّ منها ملف HTML واحد، قابلة لإعادة التسمية بالكامل (white-label)، ودون أي طلبات إلى أطراف ثالثة من الصفحة التي يفتحها مشتركوك.
@@ -16,7 +16,7 @@
-
+
@@ -33,21 +33,21 @@
## ما هو Row-Template؟
-يستطيع 3X-UI أن يعرض على المشتركين صفحة مخصّصة بدلًا من صفحته المدمجة. وRow-Template هو تلك الصفحة: يفتح المشترك رابط اشتراكه فيرى باقته واستهلاكه وتاريخ انتهاء اشتراكه، مع طرق لإضافة الاشتراك بلمسة واحدة إلى التطبيق الذي يستخدمه.
+تستطيع كلٌّ من 3X-UI وPasarGuard وRebecca أن تعرض على المشتركين صفحة مخصّصة بدلًا من صفحتها المدمجة. وRow-Template هو تلك الصفحة: يفتح المشترك رابط اشتراكه فيرى باقته واستهلاكه وتاريخ انتهاء اشتراكه، مع طرق لإضافة الاشتراك بلمسة واحدة إلى التطبيق الذي يستخدمه.
-يُقدَّم كل تصميم في ملف HTML واحد مكتفٍ ذاتيًا، تُضمَّن فيه جميع الأنماط والسكربتات والخطوط ومولّد رمز QR. يثبّته أمر واحد بجوار لوحتك، ويوجّه اللوحة إليه، ويمنحك المدير `row-template` لإدارة العلامة التجارية والتحديثات والتراجع.
+يُقدَّم كل تصميم في ملف HTML واحد مكتفٍ ذاتيًا، تُضمَّن فيه جميع الأنماط والسكربتات والخطوط ومولّد رمز QR، ومعه نسخة من كل تصميم بلغة قوالب كل لوحة. يكتشف أمر واحد لوحتك، ويثبّت الصفحة بجوارها، ويوجّه اللوحة إليها، ويمنحك المدير `row-template` لإدارة العلامة التجارية والتحديثات والتراجع.
## لماذا Row-Template؟
- **الخصوصية في صميم التصميم.** الصفحة التي يفتحها مشتركوك لا ترسل أي طلبات إلى أطراف ثالثة. تُولَّد رموز QR داخل الصفحة نفسها، وتُحقن علامتك التجارية كنص — لا تُنفَّذ أبدًا ولا تُرسل إلى أي مكان.
- **إعادة تسمية حقيقية بالكامل.** اسم خدمتك، ورابط الدعم الخاص بك، وشعارك. لا شيء في الصفحة المعروضة يشير إلى Row-Template.
-- **خمسة عشر تصميمًا، كلٌّ في ملف واحد.** اختر المظهر الذي يناسب خدمتك. جميع التصاميم تتشارك المزايا واللغات وفحوص الأمان نفسها.
+- **سبعة عشر تصميمًا، كلٌّ في ملف واحد.** اختر المظهر الذي يناسب خدمتك. جميع التصاميم تتشارك المزايا واللغات وفحوص الأمان نفسها — على كل لوحة مدعومة.
- **مصمَّم لمشتركيك.** عرض حيّ للاستهلاك وتاريخ الانتهاء، واستيراد بلمسة واحدة إلى التطبيقات الشائعة، وقائمة قابلة للبحث بالإعدادات الفردية لإضافة خادم واحد يدويًا.
-- **آمن في التشغيل.** إصدارات يُتحقَّق من مجموعها الاختباري، وتفعيل ذرّي، وتراجع بأمر واحد. لا يعدّل 3X-UI أبدًا: الإعداد الوحيد الذي يغيّره في اللوحة هو مجلد صفحة الاشتراك (`subThemeDir`).
+- **آمن في التشغيل.** إصدارات يُتحقَّق من مجموعها الاختباري، وتفعيل على هيئة معاملة يعيد اللوحة إلى حالتها بدقة إن فشلت أي خطوة، وتراجع بأمر واحد. لا يعدّل لوحتك أبدًا: في 3X-UI يغيّر إعدادًا واحدًا (`subThemeDir`)، وفي PasarGuard يضيف كتلة معلَّمة واحدة إلى `.env`، وفي Rebecca يضبط حقلين من إعدادات الاشتراك.
## التصاميم
-يأتي Row-Template 1.2.0 بخمسة عشر تصميمًا، والتصميم الافتراضي هو Row.
+يأتي Row-Template 1.3.0 بسبعة عشر تصميمًا، والتصميم الافتراضي هو Row.
@@ -71,6 +71,10 @@
 Terminal Nova |
 Arcade Nova |
+
+  Meter |
+  Notebook |
+
المعاينات مولَّدة من بيانات المشروع النموذجية. معاينات سطح المكتب والهاتف لكل تصميم موجودة في معرض القوالب.
@@ -81,7 +85,7 @@
**لمشتركيك**
-- **حالة حيّة.** حالة الباقة، والبيانات المستهلكة والمتبقية، وتاريخ الانتهاء، تُحدَّث من لوحتك طالما كانت الصفحة ظاهرة.
+- **حالة حيّة.** حالة الباقة، والبيانات المستهلكة والمتبقية، وتاريخ الانتهاء، تُحدَّث من لوحتك طالما كانت الصفحة ظاهرة (في 3X-UI؛ أما في PasarGuard وRebecca فتعرض الصفحة القيم لحظة فتحها).
- **استيراد بلمسة واحدة** إلى التطبيقات الشائعة، مرتّبة حسب المنصة: v2rayNG وHapp وsing-box على Android؛ وStreisand وV2Box وShadowrocket على iOS؛ وClash Verge Rev وMihomo Party وv2rayN على Windows؛ وClash Verge Rev وStreisand وV2Box على macOS.
- **النسخ ورمز QR.** انسخ رابط الاشتراك أو امسحه كرمز QR يُولَّد داخل الصفحة.
- **مستكشف الإعدادات.** كل خادم في صف خاص به، مع علم الدولة أو شارة بالأحرف الأولى (monogram) ووسم البروتوكول (VLESS وVMess وTrojan وShadowsocks وHysteria/Hysteria2 وWireGuard وAmneziaWG وTelegram MTProto)، مع رمز QR ونسخ لكل إعداد، وبحث في القوائم الطويلة.
@@ -98,17 +102,17 @@
- **لا طلبات إلى أطراف ثالثة** من الصفحة المعروضة: لا شبكات CDN، ولا خدمات خارجية لرموز QR أو تحديد الموقع، ولا قياس عن بُعد (telemetry). تأتي الحالة الحيّة من لوحتك أنت.
- **تحقق SHA-256 إلزامي** لكل تنزيل لإصدار، دون أي خيار لتجاوزه.
- **تفعيل ذرّي.** تُولَّد الصفحة الجديدة ويُتحقَّق منها قبل أن تحل محل الصفحة الحالية، فلا تترك خطوة فاشلة صفحة معطوبة قيد العمل.
-- **كشف حذر للوحة.** إذا لم تكن قاعدة بيانات اللوحة التي يعثر عليها Row-Template قاعدة بيانات SQLite صالحة، فإنه يرفض استخدامها بدلًا من تخمين قاعدة بيانات أخرى.
+- **كشف حذر للوحة.** لا تُعدّ اللوحة مثبّتة إلا حين تتفق إشارات مستقلة؛ واللوحة المثبّتة جزئيًا، أو قاعدة بيانات اللوحة التي ليست قاعدة بيانات SQLite صالحة، تُرفض بدلًا من التخمين.
## اللوحات المدعومة
| اللوحة | الحالة | ملاحظات |
| ----- | ------ | ----- |
| [3X-UI](https://github.com/MHSanaei/3x-ui) (MHSanaei) | ✅ مدعومة | تتطلب الإصدار **>= 3.6.0** |
-| [PasarGuard](https://github.com/PasarGuard/panel) | 🔬 قيد البحث | غير مدعومة؛ لا يوجد مسار تثبيت |
-| [Rebecca](https://github.com/rebeccapanel/Rebecca) | 🔬 قيد البحث | غير مدعومة؛ لا يوجد مسار تثبيت |
+| [PasarGuard](https://github.com/PasarGuard/panel) | ✅ مدعومة منذ 1.3.0 | التثبيت الرسمي عبر Docker أو التثبيت من المصدر (`pasarguard.service`) |
+| [Rebecca](https://github.com/rebeccapanel/Rebecca) | ✅ مدعومة منذ 1.3.0 | Rebecca الإصدار **1.x**، إصدار Go (التثبيت الثنائي لـ Rebecca). تفعيل تلقائي مع SQLite و`sqlite3`؛ ومع MySQL/MariaDB إعداد واحد يُدخَل في لوحة التحكم. صورة Docker ما زالت 0.0.x وتُرفض |
-3X-UI هي اللوحة الوحيدة المدعومة. تستخدم PasarGuard وRebecca محرّكَي قوالب مختلفين (Jinja2 وpongo2)؛ يُبنى هيكل صفحة كل تصميم لهما ويُحزَم في الإصدار لأغراض الدراسة، لكن المثبّت لا يضعه في مكانه ولا توجد تعليمات تثبيت لهما. راجع [التوافق](https://iitzseridev.github.io/Row-Template/ar/compatibility/) للاطلاع على نتائج البحث.
+تستخدم اللوحات الثلاث ثلاثة محرّكات قوالب مختلفة — `html/template` في Go وJinja2 وpongo2 — لذا يُبنى كل تصميم مرة لكل لوحة، ويُختبر كل إصدار منه بعرضه بمحرّك تلك اللوحة الحقيقي. يكتشف المثبّت اللوحة الموجودة على الخادم؛ وعلى خادم فيه أكثر من لوحة يسألك (أو يقرأ `RT_PANEL`). **مدعومة** تعني توفّر القدرات السبع كلها على تلك اللوحة — الاكتشاف والتثبيت والتفعيل والتحقق والنسخ الاحتياطي والاستعادة وإلغاء التثبيت — ويختبر كلًّا منها مجموعة الاختبارات. راجع [التوافق](https://iitzseridev.github.io/Row-Template/ar/compatibility/) لتفاصيل كل لوحة.
## البنية
@@ -116,14 +120,14 @@
flowchart TB
subgraph build ["Build and release"]
direction LR
- SRC["src/
runtime, styles, locales,
15 design layouts"] --> BUILD["tools/build.mjs"]
- BUILD --> ART["One self-contained
HTML file per design"]
+ SRC["src/
runtime, styles, locales,
17 design layouts"] --> BUILD["tools/build.mjs"]
+ BUILD --> ART["One self-contained
HTML file per design,
per panel"]
ART --> REL["tools/make-release.sh
tarball + SHA256SUMS"]
end
- subgraph host ["Your 3X-UI server"]
+ subgraph host ["Your panel server"]
direction LR
- INST["install.sh / row-template
verify checksum, stage, validate,
back up, activate"] --> DIR["/etc/3x-ui/
sub_templates/row-template"]
- DIR -- "subThemeDir" --> XUI["3X-UI renders the page
with the subscriber's data"]
+ INST["install.sh / row-template
verify checksum, detect panel,
back up, activate, verify"] --> DIR["3X-UI: subThemeDir
PasarGuard: .env block
Rebecca: subscription settings"]
+ DIR --> XUI["The panel renders the page
with the subscriber's data"]
end
build -- "GitHub Releases" --> host
host -- "serves the page" --> BROWSER["Subscriber's browser"]
@@ -131,15 +135,15 @@ flowchart TB
```
- **ملف واحد لكل تصميم.** يضمّن `tools/build.mjs` الشيفرة المشتركة والترجمات والخطوط ومولّد QR داخل تخطيط كل تصميم، ويرفض أي تخطيط ينقصه أيٌّ من نقاط الربط (hooks) التي تحتاجها الشيفرة. ثم يرفض `tools/verify.mjs` أي ملف يحمّل شيئًا من مصدر بعيد أو يحتوي على بنية محظورة.
-- **اللوحة هي من تعرض الصفحة.** الصفحة قالب: يملأ 3X-UI بيانات المشترك فيها عند تقديمها، ثم تحدّث الصفحة حالتها من اللوحة نفسها.
-- **لا يعدّل المثبّت 3X-UI أبدًا.** يكتب في مجلده الخاص ويغيّر إعدادًا واحدًا في اللوحة، هو `subThemeDir`، ليشير إليه.
+- **اللوحة هي من تعرض الصفحة.** الصفحة قالب: تملأ اللوحة بيانات المشترك فيها عند تقديمها. في PasarGuard (Jinja2) وRebecca (pongo2) يُغلَّف كل تصميم بمقدّمة صغيرة تربط بيانات اللوحة نفسها بالصفحة وتهرّب (escape) كل قيمة.
+- **لا يعدّل المثبّت لوحتك أبدًا.** في 3X-UI يوجّه `subThemeDir` إلى مجلده الخاص؛ وفي PasarGuard يضع الصفحة في مجلد القوالب ويُلحق كتلة معلَّمة واحدة بـ`.env`؛ وفي Rebecca يضع الصفحة ويضبط حقلَي الصفحة والمجلد في إعدادات الاشتراك. تُلتقط لقطة لكل تغيير قبل إجرائه، ويُستعاد بدقة إن فشل أي شيء.
| المسار | المحتوى |
| ---- | ---------------- |
| `src/` | شيفرة الصفحة وأنماطها وترجماتها؛ كل تصميم في `src/templates//` |
| `template/index.html` | صفحة Row المبنية، وهي مُضمَّنة في المستودع |
| `tools/` | البناء والتحقق والإصدار وعارض الـ fixtures المكتوب بـ Go |
-| `installer/` | `install.sh` والأمر `row-template` ومكتبته الإدارية |
+| `installer/` | `install.sh` والأمر `row-template` ومكتبته الإدارية، ومحوّل لكل لوحة في `installer/panels/` |
| `tests/` | مجموعات الاختبارات |
| `docs/` | موقع التوثيق؛ سجلات التصميم في [`docs/design/`](docs/design/README.md) |
@@ -147,9 +151,9 @@ flowchart TB
> **نظام التشغيل المُوصى به: Ubuntu 24.04 LTS (x86_64).** قد تعمل توزيعات Linux الحديثة الأخرى لكنها لم تحظَ بالمستوى نفسه من تغطية التحقق.
-**المتطلبات:** خادم يشغّل 3X-UI **>= 3.6.0**، وصلاحية root عليه، و`curl` و`tar` و`sha256sum` (متوفرة على جميع أنظمة Linux تقريبًا). ويحتاج التفعيل التلقائي أيضًا إلى `sqlite3`.
+**المتطلبات:** خادم يشغّل 3X-UI **>= 3.6.0** أو PasarGuard أو Rebecca **1.x**؛ وصلاحية root عليه؛ و`curl` و`tar` و`sha256sum` (متوفرة على جميع أنظمة Linux تقريبًا). ويحتاج التفعيل التلقائي في 3X-UI وRebecca أيضًا إلى `sqlite3`.
-شغّل الأمر بصلاحية **root** على الخادم الذي يستضيف لوحة 3X-UI:
+شغّل الأمر بصلاحية **root** على الخادم الذي يستضيف لوحتك:
```bash
bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
@@ -159,7 +163,7 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
1. ينزّل أحدث إصدار مستقر من GitHub.
2. يتحقق من مجموعه الاختباري SHA-256 (إلزامي — دون إمكانية التجاوز).
-3. يستخرجه بأمان ويثبّته في `/etc/3x-ui/sub_templates/row-template`.
+3. يكتشف لوحتك، ويستخرج الإصدار بأمان ويثبّته في `/etc/3x-ui/sub_templates/row-template` (3X-UI) أو `/etc/row-template` (PasarGuard وRebecca).
4. في التثبيت الجديد، يعرض أداة اختيار التصميم (يُبقي Enter على Row).
5. يطلب بيانات علامتك التجارية (اسم الخدمة، رابط الدعم، الشعار — وكلها اختيارية).
6. يولّد الصفحة ويتحقق منها، ثم يفعّلها في اللوحة حيثما أمكن.
@@ -170,6 +174,12 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
RT_TEMPLATE=editorial bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
```
+على خادم يشغّل أكثر من لوحة مدعومة، يسألك المثبّت عن اللوحة التي يخدمها؛ وفي سكربت، سمِّها عبر `RT_PANEL` (`3xui` أو `pasarguard` أو `rebecca`):
+
+```bash
+RT_PANEL=pasarguard bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
+```
+
إن كنت تفضّل عدم تمرير السكربت مباشرة من الشبكة، فنزّل ملفات الإصدار الأربعة (`install.sh`، `manifest.txt`، `SHA256SUMS`، `row-template-.tar.gz`) من [صفحة الإصدارات](https://github.com/iitzSeriZdev/Row-Template/releases/latest) إلى مجلد واحد، وتحقق من المجموع الاختباري بنفسك كما يشرح [PROVENANCE.md](PROVENANCE.md)، ثم وجّه المثبّت إلى ذلك المجلد:
```bash
@@ -178,19 +188,39 @@ RT_RELEASE_DIR=/root/row-template-release bash /root/row-template-release/instal
### التفعيل
-يُثبَّت Row-Template في مجلد تقدّمه اللوحة كصفحة اشتراك:
+يعرض التثبيت التفاعلي ما سيغيّره التفعيل ويسألك أولًا. في PasarGuard وRebecca يجري التفعيل على هيئة معاملة: تُلتقط لقطة لحالة اللوحة، ثم يُطبَّق التغيير ويُتحقق منه، وإن فشلت أي خطوة تُستعاد اللوحة بدقة.
+
+**3X-UI.** يُثبَّت Row-Template في مجلد تقدّمه اللوحة كصفحة اشتراك:
```
/etc/3x-ui/sub_templates/row-template
```
-- **تلقائيًا:** عند توفر `sqlite3`، يضبطه Row-Template نيابةً عنك. يوقف خدمة اللوحة لفترة وجيزة، ويكتب الإعداد، ثم يشغّل الخدمة من جديد ويتحقق من القيمة. في التثبيت التفاعلي يعرض الإعداد الحالي ويسألك أولًا.
+- **تلقائيًا:** عند توفر `sqlite3`، يضبطه Row-Template نيابةً عنك. يوقف خدمة اللوحة لفترة وجيزة، ويكتب الإعداد، ثم يشغّل الخدمة من جديد ويتحقق من القيمة.
- **يدويًا:** خلاف ذلك، افتح **Panel Settings → Subscription → Profile → Sub Theme Directory** وأدخل القيمة التالية حرفيًا:
```
/etc/3x-ui/sub_templates/row-template
```
+**PasarGuard.** توضع الصفحة في `/var/lib/pasarguard/templates/row-template/index.html` (أو داخل `CUSTOM_TEMPLATES_DIRECTORY` الخاص بك إن كنت قد ضبطته)، وتُلحق كتلة معلَّمة بـ`/opt/pasarguard/.env`:
+
+```
+# >>> row-template (managed by Row-Template; do not edit) nl=0 >>>
+CUSTOM_TEMPLATES_DIRECTORY = "/var/lib/pasarguard/templates"
+SUBSCRIPTION_PAGE_TEMPLATE = "row-template/index.html"
+# <<< row-template <<<
+```
+
+تقرأ PasarGuard ملف `.env` عند الإقلاع، لذا تُعاد تشغيل اللوحة العاملة مرة واحدة. لا يُعدَّل أي سطر من أسطرك؛ ويزيل إلغاء التثبيت الكتلة ويعيد `.env` إلى بايتاته السابقة بدقة. يبقى للمشرف الذي له قالب اشتراك خاص، أو لإعداد **disable subscription template**، الأولوية — ويخبرك `row-template verify` إن انطبق أيٌّ منهما.
+
+يدعم Row-Template الإصدار **1.x** من Rebecca، أي إصدار Go الذي تنشره Rebecca لتثبيتها الثنائي (`rebecca-binary.sh`). أما صورة `rebeccapanel/rebecca` على Docker Hub فما زالت إصدار 0.0.x المكتوب بـ Python، الذي لا يستطيع عرض هذه الصفحة؛ لذا يرفضها المثبّت ولا يغيّر شيئًا، والأمر `rebecca migrate-binary` الخاص بـ Rebecca ينقل تثبيت Docker إلى 1.x.
+
+**Rebecca.** توضع الصفحة في `/var/lib/rebecca/templates/row-template/index.html` (أو داخل مجلد القوالب المخصّص الخاص بك)، وتُضبط إعدادات الاشتراك في Rebecca على `row-template/index.html`. تقرأ Rebecca هذه الإعدادات مع كل طلب، فلا حاجة إلى إعادة التشغيل.
+
+- **تلقائيًا** مع قاعدة بيانات SQLite الافتراضية وتثبيت `sqlite3`.
+- **يدويًا** مع MySQL/MariaDB (أو دون `sqlite3`): تبقى الصفحة موضوعة في مكانها؛ في لوحة تحكم Rebecca افتح **Settings → Subscription → Templates** واضبط **Subscription page template** على `row-template/index.html` و**Custom templates directory** على `/var/lib/rebecca/templates`.
+
## الاستخدام
شغّل المدير دون أي وسائط في الطرفية لفتح القائمة التفاعلية:
@@ -206,23 +236,24 @@ row-template
| `row-template config` | تغيير اسم الخدمة أو رابط الدعم أو الشعار، ثم إعادة توليد الصفحة |
| `row-template update` | تنزيل أحدث إصدار مستقر والتحقق منه وتفعيله (التحقق من المجموع الاختباري إلزامي) |
| `row-template rollback` | استعادة إصدار سابق (`--auto` أو `--to `) |
-| `row-template verify` | فحص التثبيت وربط اللوحة والصفحة الحالية (للقراءة فقط) |
-| `row-template version` | عرض الإصدار المثبّت والحد الأدنى المدعوم وإصدار 3X-UI المكتشف |
-| `row-template uninstall` | إزالة Row-Template وإعادة اللوحة إلى صفحتها المدمجة |
+| `row-template verify` | فحص التثبيت وربط اللوحة والصفحة الحالية (وبصلاحيات root يعيد أيضًا التصاميم المفقودة أو الموضوعة في غير مكانها) |
+| `row-template version` | عرض الإصدار المثبّت واللوحة التي يخدمها (وفي 3X-UI أيضًا الحد الأدنى المدعوم والإصدار المكتشف) |
+| `row-template uninstall` | إزالة Row-Template وإعادة اللوحة إلى الصفحة التي كانت لديها من قبل |
| `row-template help` | عرض طريقة الاستخدام |
يجب تشغيل الأوامر التي تغيّر النظام (`config` و`update` و`rollback` و`uninstall`) بصلاحية root.
- **العلامة التجارية** تُخزَّن كبيانات، ولا تُنفَّذ أبدًا، وتُحقن في الصفحة كنص. اترك أي حقل فارغًا للحصول على صفحة بلا علامة تجارية. لا يقبل رابط الدعم إلا البروتوكولات التي ينبغي للمتصفح فتحها، مثل `https://…` أو `tg://…` أو `mailto:…`.
- **التحديثات** تأتي من قناة الإصدارات المستقرة العامة. يطبّق `row-template update` دائمًا أحدث إصدار مستقر، حتى لو كان هو الإصدار المثبّت لديك؛ أما خيار **Update** في المدير فيقارن الإصدارات أولًا ويسأل قبل أي تغيير. إذا تعذّر الوصول إلى مصدر الإصدارات، لا يتغيّر شيء ولا يُعامَل تثبيتك أبدًا على أنه تالف.
-- **التراجع** يستعيد إصدارًا سابقًا من نسخة احتياطية جرى التحقق منها. تُلتقط لقطة (snapshot) للإصدار الحالي أولًا، بحيث يمكن التعافي من تراجع فاشل، وتُحفَظ علامتك التجارية.
-- **إلغاء التثبيت** يزيل ملفات Row-Template. ولا يمسح `subThemeDir` في اللوحة إلا إذا كان يشير إلى Row-Template، فتعود اللوحة إلى صفحتها المدمجة؛ ولا يمسّ الواردات (inbounds) أو العملاء أو الشهادات.
+- **التحديث من 1.1.0 أو 1.2.x** يكفيه تشغيل `row-template update` مرة واحدة. ينسخ مُحدِّث 1.1.0 نفسه جزءًا فقط من الإصدار الجديد، لذا فإن التشغيل التالي لـ`row-template` أو `row-template config` أو `row-template verify` بصلاحيات root ينزّل أولًا بقية الإصدار نفسه — كل التصاميم، مع التحقق من checksum. ويُحفَظ تصميمك وعلامتك التجارية وربط اللوحة.
+- **التراجع** يستعيد إصدارًا سابقًا من نسخة احتياطية جرى التحقق منها. تُلتقط لقطة (snapshot) للإصدار الحالي أولًا، بحيث يمكن التعافي من تراجع فاشل، وتُحفَظ علامتك التجارية. تسجّل النسخ الاحتياطية اللوحة التي أُنشئت عليها ولا تُستعاد أبدًا على لوحة أخرى؛ والنسخة الاحتياطية من إصدار أقدم لا تسجّل اسم تصميمها تُستعاد على أنها Row.
+- **إلغاء التثبيت** يزيل ملفات Row-Template ويعيد اللوحة إلى الصفحة التي كانت لديها من قبل: في 3X-UI لا يمسح `subThemeDir` إلا إذا كان يشير إلى Row-Template؛ وفي PasarGuard يزيل كتلته من `.env` وصفحته؛ وفي Rebecca يستعيد إعدادَي الاشتراك اللذين غيّرهما (ويتركهما إن كنت قد اخترت صفحة أخرى منذ ذلك الحين). ولا يمسّ المستخدمين أو الواردات (inbounds) أو العملاء أو العُقد أو الشهادات.
يغطي [التوثيق](https://iitzseridev.github.io/Row-Template/ar/) الإعداد والعلامة التجارية واستكشاف الأخطاء بمزيد من التفصيل.
## التطوير
-تُبنى الصفحات من مصادر مقروءة في `src/`. تحتاج إلى Node.js 22 أو أحدث، وإلى Go 1.22 أو أحدث لتشغيل الاختبارات.
+تُبنى الصفحات من مصادر مقروءة في `src/`. تحتاج إلى Node.js 22 أو أحدث؛ ولتشغيل الاختبارات أيضًا إلى Go 1.22 أو أحدث وPython 3 مع Jinja2 (`pip install jinja2`)، اللذين يعرضان صفحات PasarGuard وRebecca بمحرّكَي هاتين اللوحتين الحقيقيين.
```bash
npm run build # regenerate template/index.html from src/
@@ -237,7 +268,7 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
## الاختبار
-- **`npm test`** يولّد أولًا صفحات الـ fixtures لكل التصاميم باستخدام العارض المكتوب بـ Go، ثم يشغّل مجموعات الاختبارات: سكربتات الصفحة، والبناء، والملف النهائي لكل تصميم، وحمولة الإصدار، والمثبّت — الذي تُشغَّل مكتبته الـ shell المنشورة في `bash` حقيقي على fixtures مؤقتة.
+- **`npm test`** يولّد أولًا صفحات الـ fixtures لكل التصاميم باستخدام العارض المكتوب بـ Go، ثم يشغّل مجموعات الاختبارات: سكربتات الصفحة، والبناء، والملف النهائي لكل تصميم، وصفحات PasarGuard وRebecca معروضةً بـ Jinja2 وpongo2 الحقيقيين (بما في ذلك مع بيانات عدائية ومشوّهة)، وحمولة الإصدار، والمثبّت — الذي تُشغَّل مكتبته الـ shell المنشورة ومحوّل كل لوحة في `bash` حقيقي على خوادم مؤقتة مرتّبة كتثبيت كل لوحة الرسمي.
- **`npm run verify`** يفحص صفحة مبنية وفق بوابات الأمان الخاصة بها، ومنها: مستند كامل، واستبدال كل علامات البناء، وتضمين كل شيء، وعدم وجود مراجع بعيدة، وعدم وجود بُنى محظورة، وسلامة الترجمات، وخلوّ المصادر من المحارف غير المرئية.
- **`npm run lint:sh`** يفشل عند أي خطأ من ShellCheck؛ ويعرض `npm run lint:sh -- -S warning` التقرير الكامل.
- **سير عمل Docs** يبني موقع التوثيق في كل طلب دمج (pull request) يغيّره.
@@ -246,18 +277,17 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
توجّه، لا وعود:
-- **Row-Template 1.2.0** — التصاميم الخمسة عشر وأداة اختيار التصميم الموصوفة أعلاه.
-- **PasarGuard وRebecca** — قيد البحث. هيكل الصفحة مبنيّ لكليهما؛ وتحتاج الحالة الحيّة إلى تغيير صغير في الشيفرة أو إلى وكيل عكسي (reverse proxy)، وقد أُرجئ هذا القرار. راجع [التوافق](https://iitzseridev.github.io/Row-Template/ar/compatibility/).
-- **التثبيت على أكثر من لوحة** — البنية التحتية للمثبّت (واجهة للوحات، ومحرّك معاملات، ومحوّل لـ 3X-UI، وصيغة نسخ احتياطي جديدة) موجودة، لكن لا يستخدمها أي أمر بعد.
+- **Row-Template 1.3.0** — دعم PasarGuard وRebecca، وتصميما Meter وNotebook، الموصوفة أعلاه.
+- **الحالة الحيّة في PasarGuard وRebecca** — تقدّمها كلتاهما على لاحقة مسار لا على `?format=info`؛ ويحتاج ربطها إلى تغيير صغير في الشيفرة، وقد أُرجئ هذا القرار. راجع [التوافق](https://iitzseridev.github.io/Row-Template/ar/compatibility/).
- **القوالب المخصّصة** — مقترح لإضافة تصميمك الخاص: [`docs/design/CUSTOM-TEMPLATES-PROPOSAL.md`](docs/design/CUSTOM-TEMPLATES-PROPOSAL.md).
## المساهمة
نرحّب كثيرًا بتقارير الأخطاء والترجمات وتصحيحات التوثيق. اقرأ [CONTRIBUTING.md](CONTRIBUTING.md) قبل فتح طلب دمج، والتزم بـ[مدونة السلوك](CODE_OF_CONDUCT.md).
-**الإبلاغ عن الأخطاء:** افتح تذكرة (issue) على . أدرِج إصدار Row-Template لديك (`row-template version`)، وإصدار 3X-UI، ونظام التشغيل وإصداره، ومعمارية المعالج، ومخرجات `row-template verify`، وخطوات واضحة لإعادة إنتاج المشكلة.
+**الإبلاغ عن الأخطاء:** افتح تذكرة (issue) على . أدرِج إصدار Row-Template لديك (`row-template version`)، ولوحتك وإصدارها، ونظام التشغيل وإصداره، ومعمارية المعالج، ومخرجات `row-template verify`، وخطوات واضحة لإعادة إنتاج المشكلة.
-> **لا تُدرِج أي أسرار.** لا تلصق إطلاقًا روابط الاشتراك، أو قيم `subId`، أو معرّفات UUID الخاصة بالعملاء، أو أسماء مستخدمي اللوحة أو كلمات مرورها، أو ملفات تعريف الارتباط (cookies)، أو الرموز (tokens)، أو `webBasePath` الخاص باللوحة، أو مفاتيح TLS، أو عناوين الخوادم الحقيقية. ونقِّح السجلات قبل مشاركتها.
+> **لا تُدرِج أي أسرار.** لا تلصق إطلاقًا روابط الاشتراك، أو قيم `subId`، أو معرّفات UUID الخاصة بالعملاء، أو أسماء مستخدمي اللوحة أو كلمات مرورها، أو ملفات تعريف الارتباط (cookies)، أو الرموز (tokens)، أو `webBasePath` الخاص باللوحة، أو محتوى `.env`، أو روابط قواعد البيانات، أو مفاتيح TLS، أو عناوين الخوادم الحقيقية. ونقِّح السجلات قبل مشاركتها.
## الأمان
diff --git a/README.fa.md b/README.fa.md
index 997222f..ba324b3 100644
--- a/README.fa.md
+++ b/README.fa.md
@@ -7,7 +7,7 @@
- یک صفحهٔ اشتراک شکیل و خودبسنده برای پنل های 3X-UI — پانزده طرح که هر کدام یک فایل HTML است، کاملاً وایت لیبل، و بدون هیچ درخواستی به شخص ثالث از صفحه ای که مشترکان شما باز می کنند.
+ یک صفحهٔ اشتراک شکیل و خودبسنده برای پنل های 3X-UI، PasarGuard و Rebecca — هفده طرح که هر کدام یک فایل HTML است، کاملاً وایت لیبل، و بدون هیچ درخواستی به شخص ثالث از صفحه ای که مشترکان شما باز می کنند.
@@ -17,7 +17,7 @@
-
+
@@ -34,21 +34,21 @@
## Row-Template چیست؟
-3X-UI می تواند به جای صفحهٔ داخلی خود، یک صفحهٔ سفارشی به مشترکان نشان دهد. Row-Template همان صفحه است: مشترک پیوند اشتراک خود را باز می کند و پلن، میزان مصرف و تاریخ انقضای خود را می بیند، به همراه راه هایی برای افزودن اشتراک با یک لمس به برنامه ای که استفاده می کند.
+3X-UI، PasarGuard و Rebecca هر کدام می توانند به جای صفحهٔ داخلی خود، یک صفحهٔ سفارشی به مشترکان نشان دهند. Row-Template همان صفحه است: مشترک پیوند اشتراک خود را باز می کند و پلن، میزان مصرف و تاریخ انقضای خود را می بیند، به همراه راه هایی برای افزودن اشتراک با یک لمس به برنامه ای که استفاده می کند.
-برای هر طرح یک فایل HTML خودبسنده عرضه می شود که همهٔ استایل ها، اسکریپت ها، فونت ها و مولد کد QR درون آن گنجانده شده اند. یک دستور آن را کنار پنل شما نصب می کند، پنل را به آن اشاره می دهد و ابزار مدیریتی `row-template` را برای برندسازی، به روزرسانی و بازگردانی در اختیار شما می گذارد.
+برای هر طرح یک فایل HTML خودبسنده عرضه می شود که همهٔ استایل ها، اسکریپت ها، فونت ها و مولد کد QR درون آن گنجانده شده اند، و از هر طرح نسخه ای به زبان قالب خود هر پنل. یک دستور پنل شما را شناسایی می کند، صفحه را کنار آن نصب می کند، پنل را به آن اشاره می دهد و ابزار مدیریتی `row-template` را برای برندسازی، به روزرسانی و بازگردانی در اختیار شما می گذارد.
## چرا Row-Template؟
- **محرمانه از پایه.** صفحه ای که مشترکان شما باز می کنند هیچ درخواستی به شخص ثالث نمی فرستد. کدهای QR روی خود صفحه تولید می شوند و اطلاعات برندسازی شما به صورت متن تزریق می شود — هرگز اجرا نمی شود و هرگز به هیچ جایی فرستاده نمی شود.
- **واقعاً وایت لیبل.** نام سرویس، پیوند پشتیبانی و لوگوی خودتان. هیچ چیزی روی صفحهٔ ارائه شده معرف Row-Template نیست.
-- **پانزده طرح، هر کدام یک فایل.** ظاهری را انتخاب کنید که به سرویس شما می آید. همهٔ طرح ها ویژگی ها، زبان ها و بررسی های ایمنی یکسانی دارند.
+- **هفده طرح، هر کدام یک فایل.** ظاهری را انتخاب کنید که به سرویس شما می آید. همهٔ طرح ها ویژگی ها، زبان ها و بررسی های ایمنی یکسانی دارند — روی هر پنل پشتیبانی شده.
- **ساخته شده برای مشترکان شما.** نمای زندهٔ مصرف و انقضا، ورود (import) با یک لمس به برنامه های پرکاربرد، و فهرستی قابل جستجو از پیکربندی های جداگانه برای افزودن دستی یک سرور.
-- **ایمن برای بهره برداری.** نسخه هایی که مجموع کنترلی آن ها بررسی می شود، فعال سازی اتمی و بازگردانی تک دستوری. هرگز 3X-UI را وصله نمی کند: تنها تنظیمی از پنل که تغییر می دهد، دایرکتوری صفحهٔ اشتراک (`subThemeDir`) است.
+- **ایمن برای بهره برداری.** نسخه هایی که مجموع کنترلی آن ها بررسی می شود، فعال سازی تراکنشی که اگر گامی شکست بخورد پنل را دقیقاً به حالت قبل برمی گرداند، و بازگردانی تک دستوری. هرگز پنل شما را وصله نمی کند: در 3X-UI یک تنظیم (`subThemeDir`) را تغییر می دهد، در PasarGuard یک بلوک نشان دار به `.env` می افزاید، و در Rebecca دو فیلد از تنظیمات اشتراک را مقدار می دهد.
## طرح ها
-Row-Template 1.2.0 با پانزده طرح عرضه می شود. طرح پیش فرض Row است.
+Row-Template 1.3.0 با هفده طرح عرضه می شود. طرح پیش فرض Row است.
@@ -72,6 +72,10 @@ Row-Template 1.2.0 با پانزده طرح عرضه می شود. طرح پیش
 Terminal Nova |
 Arcade Nova |
+
+  Meter |
+  Notebook |
+
پیش نمایش ها با داده های نمونهٔ خود پروژه ساخته شده اند. پیش نمایش دسکتاپ و موبایل همهٔ طرح ها در گالری طرح ها موجود است.
@@ -82,7 +86,7 @@ Row-Template 1.2.0 با پانزده طرح عرضه می شود. طرح پیش
**برای مشترکان شما**
-- **وضعیت زنده.** وضعیت پلن، ترافیک مصرف شده و باقی مانده و تاریخ انقضا، که تا وقتی صفحه دیده می شود از پنل شما به روز می شود.
+- **وضعیت زنده.** وضعیت پلن، ترافیک مصرف شده و باقی مانده و تاریخ انقضا، که تا وقتی صفحه دیده می شود از پنل شما به روز می شود (در 3X-UI؛ در PasarGuard و Rebecca صفحه مقادیر لحظهٔ باز شدن را نشان می دهد).
- **ورود با یک لمس** به برنامه های پرکاربرد، بر اساس پلتفرم: v2rayNG، Happ و sing-box در Android؛ Streisand، V2Box و Shadowrocket در iOS؛ Clash Verge Rev، Mihomo Party و v2rayN در Windows؛ Clash Verge Rev، Streisand و V2Box در macOS.
- **کپی و QR.** پیوند اشتراک را کپی کنید یا آن را به صورت کد QR که روی خود صفحه ساخته می شود اسکن کنید.
- **کاوشگر پیکربندی ها.** هر سرور در یک ردیف جداگانه، با پرچم کشور یا نشان حروف (monogram) و برچسب پروتکل (VLESS، VMess، Trojan، Shadowsocks، Hysteria/Hysteria2، WireGuard، AmneziaWG، Telegram MTProto)، به همراه QR و کپی برای هر پیکربندی و جستجو برای فهرست های طولانی.
@@ -99,17 +103,17 @@ Row-Template 1.2.0 با پانزده طرح عرضه می شود. طرح پیش
- **بدون درخواست به شخص ثالث** از صفحهٔ ارائه شده: بدون CDN، بدون جستجوی بیرونی QR یا موقعیت جغرافیایی، بدون تله متری. وضعیت زنده از پنل خود شما می آید.
- **SHA-256 الزامی** برای هر دانلود نسخه، بدون هیچ گزینه ای برای رد کردن آن.
- **فعال سازی اتمی.** صفحهٔ جدید پیش از جایگزینی صفحهٔ فعال ساخته و اعتبارسنجی می شود، بنابراین یک گام ناموفق هرگز صفحه ای خراب را فعال باقی نمی گذارد.
-- **شناسایی محتاطانهٔ پنل.** اگر پایگاه دادهٔ پنلی که Row-Template پیدا می کند یک پایگاه دادهٔ SQLite معتبر نباشد، به جای حدس زدن پایگاه دادهٔ دیگری، از به کار بردن آن خودداری می کند.
+- **شناسایی محتاطانهٔ پنل.** یک پنل تنها وقتی نصب شده به حساب می آید که نشانه های مستقل با هم بخوانند؛ پنلی که نیمه نصب شده، یا پایگاه دادهٔ پنلی که یک پایگاه دادهٔ SQLite معتبر نیست، به جای حدس زدن رد می شود.
## پنل های پشتیبانی شده
| پنل | وضعیت | یادداشت ها |
| ----- | ------ | ----- |
| [3X-UI](https://github.com/MHSanaei/3x-ui) (MHSanaei) | ✅ پشتیبانی شده | نیازمند نسخهٔ **>= 3.6.0** |
-| [PasarGuard](https://github.com/PasarGuard/panel) | 🔬 در حال پژوهش | پشتیبانی نمی شود؛ مسیر نصبی ندارد |
-| [Rebecca](https://github.com/rebeccapanel/Rebecca) | 🔬 در حال پژوهش | پشتیبانی نمی شود؛ مسیر نصبی ندارد |
+| [PasarGuard](https://github.com/PasarGuard/panel) | ✅ پشتیبانی شده از 1.3.0 | نصب رسمی Docker یا نصب از سورس (`pasarguard.service`) |
+| [Rebecca](https://github.com/rebeccapanel/Rebecca) | ✅ پشتیبانی شده از 1.3.0 | Rebecca نسخهٔ **1.x**، نسخهٔ Go (نصب باینری Rebecca). فعال سازی خودکار با SQLite و `sqlite3`؛ با MySQL/MariaDB یک تنظیم که باید در داشبورد وارد شود. ایمیج Docker هنوز 0.0.x است و رد می شود |
-تنها پنل پشتیبانی شده 3X-UI است. PasarGuard و Rebecca از موتورهای قالب متفاوتی (Jinja2 و pongo2) استفاده می کنند؛ پوستهٔ صفحهٔ هر طرح برای آن ها ساخته و برای بررسی در نسخه بسته بندی می شود، اما نصب کننده آن را جایگذاری نمی کند و هیچ دستورالعمل نصبی برای آن ها وجود ندارد. برای یافته های پژوهشی، [سازگاری](https://iitzseridev.github.io/Row-Template/fa/compatibility/) را ببینید.
+این سه پنل از سه موتور قالب متفاوت استفاده می کنند — `html/template` زبان Go، Jinja2 و pongo2 — پس هر طرح برای هر پنل یک بار ساخته می شود و هر نسخه با رندر شدن توسط موتور واقعی همان پنل آزموده می شود. نصب کننده تشخیص می دهد کدام پنل روی سرور است؛ روی سروری با بیش از یک پنل، از شما می پرسد (یا `RT_PANEL` را می خواند). **پشتیبانیشده** یعنی هر هفت توانایی روی آن پنل موجود است — تشخیص، نصب، فعالسازی، بررسی، پشتیبانگیری، بازگردانی و حذف نصب — و هر کدام توسط مجموعهٔ آزمون آزموده می شود. برای جزئیات هر پنل، [سازگاری](https://iitzseridev.github.io/Row-Template/fa/compatibility/) را ببینید.
## معماری
@@ -117,14 +121,14 @@ Row-Template 1.2.0 با پانزده طرح عرضه می شود. طرح پیش
flowchart TB
subgraph build ["Build and release"]
direction LR
- SRC["src/
runtime, styles, locales,
15 design layouts"] --> BUILD["tools/build.mjs"]
- BUILD --> ART["One self-contained
HTML file per design"]
+ SRC["src/
runtime, styles, locales,
17 design layouts"] --> BUILD["tools/build.mjs"]
+ BUILD --> ART["One self-contained
HTML file per design,
per panel"]
ART --> REL["tools/make-release.sh
tarball + SHA256SUMS"]
end
- subgraph host ["Your 3X-UI server"]
+ subgraph host ["Your panel server"]
direction LR
- INST["install.sh / row-template
verify checksum, stage, validate,
back up, activate"] --> DIR["/etc/3x-ui/
sub_templates/row-template"]
- DIR -- "subThemeDir" --> XUI["3X-UI renders the page
with the subscriber's data"]
+ INST["install.sh / row-template
verify checksum, detect panel,
back up, activate, verify"] --> DIR["3X-UI: subThemeDir
PasarGuard: .env block
Rebecca: subscription settings"]
+ DIR --> XUI["The panel renders the page
with the subscriber's data"]
end
build -- "GitHub Releases" --> host
host -- "serves the page" --> BROWSER["Subscriber's browser"]
@@ -132,15 +136,15 @@ flowchart TB
```
- **یک فایل برای هر طرح.** `tools/build.mjs` کد اجرایی مشترک، ترجمه ها، فونت ها و مولد QR را درون چیدمان هر طرح می گنجاند و چیدمانی را که هر یک از قلاب های (hook) مورد نیاز کد اجرایی را نداشته باشد رد می کند. سپس `tools/verify.mjs` هر فایلی را که چیزی را از راه دور بارگذاری کند یا ساختاری ممنوع داشته باشد رد می کند.
-- **رندر را پنل انجام می دهد.** صفحه یک قالب است: 3X-UI هنگام ارائهٔ آن داده های مشترک را در آن قرار می دهد و سپس صفحه وضعیت خود را از همان پنل به روز می کند.
-- **نصب کننده هرگز 3X-UI را ویرایش نمی کند.** دایرکتوری خودش را می نویسد و تنها یک تنظیم پنل، `subThemeDir`، را تغییر می دهد تا به آن اشاره کند.
+- **رندر را پنل انجام می دهد.** صفحه یک قالب است: پنل هنگام ارائهٔ آن داده های مشترک را در آن قرار می دهد. برای PasarGuard (Jinja2) و Rebecca (pongo2) هر طرح درون یک پیش درآمد کوچک قرار می گیرد که داده های خود پنل را به صفحه نگاشت می کند و هر مقدار را escape می کند.
+- **نصب کننده هرگز پنل شما را وصله نمی کند.** در 3X-UI، `subThemeDir` را به دایرکتوری خودش اشاره می دهد؛ در PasarGuard صفحه را در دایرکتوری قالب ها می گذارد و یک بلوک نشان دار به انتهای `.env` می افزاید؛ در Rebecca صفحه را می گذارد و فیلدهای صفحه و دایرکتوری تنظیمات اشتراک را مقدار می دهد. از هر تغییر پیش از انجام یک snapshot گرفته می شود و اگر چیزی شکست بخورد دقیقاً بازگردانده می شود.
| مسیر | محتوا |
| ---- | ---------------- |
| `src/` | کد اجرایی، استایل ها و ترجمه های صفحه؛ هر طرح در `src/templates//` |
| `template/index.html` | صفحهٔ ساخته شدهٔ Row، که commit شده است |
| `tools/` | ساخت، اعتبارسنجی، انتشار و رندرکنندهٔ Go برای fixtureها |
-| `installer/` | `install.sh`، دستور `row-template` و کتابخانهٔ مدیریتی آن |
+| `installer/` | `install.sh`، دستور `row-template`، کتابخانهٔ مدیریتی آن و یک آداپتور برای هر پنل در `installer/panels/` |
| `tests/` | مجموعه های آزمون |
| `docs/` | سایت مستندات؛ سوابق طراحی در [`docs/design/`](docs/design/README.md) |
@@ -148,9 +152,9 @@ flowchart TB
> **سیستم عامل پیشنهادی: Ubuntu 24.04 LTS (x86_64).** دیگر توزیع های امروزی لینوکس نیز ممکن است کار کنند، اما پوشش اعتبارسنجی یکسانی نداشته اند.
-**پیش نیازها:** سروری با 3X-UI **>= 3.6.0**، دسترسی root به آن، و `curl`، `tar` و `sha256sum` (که تقریباً روی همهٔ سیستم های لینوکس موجود است). فعال سازی خودکار به `sqlite3` هم نیاز دارد.
+**پیش نیازها:** سروری با 3X-UI **>= 3.6.0**، PasarGuard یا Rebecca **1.x**؛ دسترسی root به آن؛ و `curl`، `tar` و `sha256sum` (که تقریباً روی همهٔ سیستم های لینوکس موجود است). فعال سازی خودکار در 3X-UI و Rebecca به `sqlite3` هم نیاز دارد.
-با کاربر **root** روی سروری که پنل 3X-UI شما را میزبانی می کند اجرا کنید:
+با کاربر **root** روی سروری که پنل شما را میزبانی می کند اجرا کنید:
```bash
bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
@@ -160,7 +164,7 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
1. آخرین نسخهٔ پایدار را از GitHub دانلود می کند.
2. مجموع کنترلی SHA-256 آن را بررسی می کند (الزامی — بدون امکان دور زدن).
-3. آن را به شکل ایمن استخراج می کند و در `/etc/3x-ui/sub_templates/row-template` نصب می کند.
+3. پنل شما را شناسایی می کند، نسخه را به شکل ایمن استخراج می کند و در `/etc/3x-ui/sub_templates/row-template` (3X-UI) یا `/etc/row-template` (PasarGuard، Rebecca) نصب می کند.
4. در نصب تازه، انتخابگر طرح را نشان می دهد (Enter طرح Row را نگه می دارد).
5. برای برندسازی شما درخواست ورودی می دهد (نام سرویس، پیوند پشتیبانی، لوگو — همگی اختیاری).
6. صفحه را تولید و اعتبارسنجی می کند و سپس در صورت امکان آن را در پنل فعال می کند.
@@ -171,6 +175,12 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
RT_TEMPLATE=editorial bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
```
+روی سروری که بیش از یک پنل پشتیبانی شده دارد، نصب کننده می پرسد کدام را سرویس دهد؛ در یک اسکریپت، آن را با `RT_PANEL` (`3xui`، `pasarguard` یا `rebecca`) مشخص کنید:
+
+```bash
+RT_PANEL=pasarguard bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
+```
+
اگر ترجیح می دهید از طریق شبکه به صورت pipe عمل نکنید، چهار فایل نسخه (`install.sh`، `manifest.txt`، `SHA256SUMS` و `row-template-.tar.gz`) را از [صفحهٔ Releases](https://github.com/iitzSeriZdev/Row-Template/releases/latest) در یک پوشه دانلود کنید، مجموع کنترلی را خودتان همان گونه که در [PROVENANCE.md](PROVENANCE.md) توضیح داده شده بررسی کنید و نصب کننده را به آن پوشه ارجاع دهید:
```bash
@@ -179,19 +189,39 @@ RT_RELEASE_DIR=/root/row-template-release bash /root/row-template-release/instal
### فعال سازی
-Row-Template در دایرکتوری ای نصب می شود که پنل آن را به عنوان صفحهٔ اشتراک ارائه می دهد:
+نصب تعاملی ابتدا نشان می دهد فعال سازی چه چیزی را تغییر می دهد و پیش از تغییر از شما می پرسد. در PasarGuard و Rebecca فعال سازی به صورت یک تراکنش اجرا می شود: از وضعیت پنل snapshot گرفته می شود، تغییر اعمال و بررسی می شود، و اگر گامی شکست بخورد، پنل دقیقاً به حالت قبل بازگردانده می شود.
+
+**3X-UI.** Row-Template در دایرکتوری ای نصب می شود که پنل آن را به عنوان صفحهٔ اشتراک ارائه می دهد:
```
/etc/3x-ui/sub_templates/row-template
```
-- **خودکار:** هنگامی که `sqlite3` در دسترس باشد، Row-Template آن را برای شما تنظیم می کند. سرویس پنل را برای مدت کوتاهی متوقف می کند، تنظیم را می نویسد، سرویس را دوباره راه اندازی می کند و مقدار را بررسی می کند. نصب تعاملی ابتدا تنظیم فعلی را نشان می دهد و پیش از تغییر از شما می پرسد.
+- **خودکار:** هنگامی که `sqlite3` در دسترس باشد، Row-Template آن را برای شما تنظیم می کند. سرویس پنل را برای مدت کوتاهی متوقف می کند، تنظیم را می نویسد، سرویس را دوباره راه اندازی می کند و مقدار را بررسی می کند.
- **دستی:** در غیر این صورت، **Panel Settings → Subscription → Profile → Sub Theme Directory** را باز کنید و دقیقاً این را وارد کنید:
```
/etc/3x-ui/sub_templates/row-template
```
+**PasarGuard.** صفحه در `/var/lib/pasarguard/templates/row-template/index.html` قرار می گیرد (یا درون `CUSTOM_TEMPLATES_DIRECTORY` خودتان، اگر تنظیمش کرده باشید)، و یک بلوک نشان دار به انتهای `/opt/pasarguard/.env` افزوده می شود:
+
+```
+# >>> row-template (managed by Row-Template; do not edit) nl=0 >>>
+CUSTOM_TEMPLATES_DIRECTORY = "/var/lib/pasarguard/templates"
+SUBSCRIPTION_PAGE_TEMPLATE = "row-template/index.html"
+# <<< row-template <<<
+```
+
+PasarGuard فایل `.env` را هنگام راه اندازی می خواند، پس پنلی که در حال اجراست یک بار راه اندازی مجدد می شود. هیچ یک از خط های خودتان ویرایش نمی شود؛ حذف نصب بلوک را برمی دارد و `.env` را دقیقاً به بایت های قبلی اش بازمی گرداند. ادمینی که قالب اشتراک خودش را دارد، یا تنظیم **disable subscription template**، همچنان مقدم است — `row-template verify` به شما می گوید اگر یکی از آن ها برقرار باشد.
+
+Row-Template از Rebecca نسخهٔ **1.x** پشتیبانی می کند، یعنی نسخهٔ Go که Rebecca برای نصب باینری خود (`rebecca-binary.sh`) منتشر می کند. ایمیج `rebeccapanel/rebecca` در Docker Hub هنوز نسخهٔ 0.0.x پایتونی است که نمی تواند این صفحه را رندر کند؛ نصب کننده آن را رد می کند و چیزی را تغییر نمی دهد، و دستور `rebecca migrate-binary` خود Rebecca یک نصب Docker را به 1.x منتقل می کند.
+
+**Rebecca.** صفحه در `/var/lib/rebecca/templates/row-template/index.html` قرار می گیرد (یا درون دایرکتوری قالب های سفارشی خودتان)، و تنظیمات اشتراک Rebecca روی `row-template/index.html` تنظیم می شود. Rebecca این تنظیمات را در هر درخواست می خواند، پس نیازی به راه اندازی مجدد نیست.
+
+- **خودکار** با پایگاه دادهٔ پیش فرض SQLite و نصب بودن `sqlite3`.
+- **دستی** با MySQL/MariaDB (یا بدون `sqlite3`): صفحه همچنان جایگذاری می شود؛ در داشبورد Rebecca، **Settings → Subscription → Templates** را باز کنید و **Subscription page template** را `row-template/index.html` و **Custom templates directory** را `/var/lib/rebecca/templates` قرار دهید.
+
## استفاده
مدیر را بدون هیچ آرگومانی در ترمینال اجرا کنید تا منوی تعاملی باز شود:
@@ -207,23 +237,24 @@ row-template
| `row-template config` | تغییر نام سرویس، پیوند پشتیبانی یا لوگو و سپس بازسازی صفحه |
| `row-template update` | دانلود، بررسی و فعال سازی آخرین نسخهٔ پایدار (بررسی مجموع کنترلی الزامی) |
| `row-template rollback` | بازگردانی یک نسخهٔ پیشین (`--auto` یا `--to `) |
-| `row-template verify` | بررسی نصب، اتصال به پنل و صفحهٔ فعال (فقط خواندنی) |
-| `row-template version` | نمایش نسخهٔ نصب شده، حداقل نسخهٔ پشتیبانی شده و نسخهٔ شناسایی شدهٔ 3X-UI |
-| `row-template uninstall` | حذف Row-Template و بازگرداندن پنل به صفحهٔ داخلی خودش |
+| `row-template verify` | بررسی نصب، اتصال به پنل و صفحهٔ فعال (با دسترسی root، طرح های گم شده یا جابه جا شده را هم به جای خود برمی گرداند) |
+| `row-template version` | نمایش نسخهٔ نصب شده و پنلی که به آن سرویس می دهد (در 3X-UI، حداقل نسخهٔ پشتیبانی شده و نسخهٔ شناسایی شده را هم) |
+| `row-template uninstall` | حذف Row-Template و بازگرداندن پنل به صفحه ای که پیش تر داشت |
| `row-template help` | نمایش راهنمای استفاده |
دستورهایی که سیستم را تغییر می دهند (`config`، `update`، `rollback`، `uninstall`) باید با root اجرا شوند.
- **برندسازی** به عنوان داده ذخیره می شود، هرگز اجرا نمی شود و به صورت متن در صفحه تزریق می گردد. برای یک صفحهٔ بدون برند، فیلدی را خالی بگذارید. پیوند پشتیبانی تنها پروتکل هایی را می پذیرد که مرورگر باید باز کند، مانند `https://…`، `tg://…` یا `mailto:…`.
- **به روزرسانی ها** از کانال عمومی نسخه های پایدار می آیند. `row-template update` همیشه آخرین نسخهٔ پایدار را اعمال می کند، حتی اگر همان نسخه را داشته باشید؛ گزینهٔ **Update** در منوی مدیریت ابتدا نسخه ها را مقایسه می کند و پیش از هر تغییری می پرسد. اگر منبع انتشار در دسترس نباشد، چیزی تغییر نمی کند و نصب شما هرگز آسیب دیده تلقی نمی شود.
-- **بازگردانی** یک نسخهٔ پیشین را از یک پشتیبان اعتبارسنجی شده بازیابی می کند. ابتدا از نسخهٔ فعلی یک عکس فوری (snapshot) گرفته می شود تا یک بازگردانی ناموفق قابل جبران باشد، و برندسازی شما حفظ می شود.
-- **حذف نصب** فایل های Row-Template را حذف می کند. `subThemeDir` پنل را تنها در صورتی پاک می کند که به Row-Template اشاره کند، تا پنل به صفحهٔ داخلی خود بازگردد؛ به inboundها، کلاینت ها و گواهی های شما دست زده نمی شود.
+- **به روزرسانی از 1.1.0 یا 1.2.x** با یک بار اجرای `row-template update` انجام می شود. به روزرسان خود 1.1.0 فقط بخشی از نسخهٔ جدید را کپی می کند، برای همین اجرای بعدی `row-template`، `row-template config` یا `row-template verify` با دسترسی root، ابتدا بقیهٔ همان نسخه را دریافت می کند — همهٔ طرح ها، با بررسی checksum. طرح، برندسازی و اتصال پنل شما حفظ می شوند.
+- **بازگردانی** یک نسخهٔ پیشین را از یک پشتیبان اعتبارسنجی شده بازیابی می کند. ابتدا از نسخهٔ فعلی یک عکس فوری (snapshot) گرفته می شود تا یک بازگردانی ناموفق قابل جبران باشد، و برندسازی شما حفظ می شود. پشتیبان ها پنلی را که روی آن ساخته شده اند ثبت می کنند و هرگز روی پنل دیگری بازگردانده نمی شوند؛ پشتیبانی از یک نسخهٔ قدیمی تر که نام طرحش را ثبت نکرده، به صورت Row بازگردانده می شود.
+- **حذف نصب** فایل های Row-Template را حذف می کند و پنل را به صفحه ای که پیش تر داشت بازمی گرداند: در 3X-UI، `subThemeDir` را تنها در صورتی پاک می کند که به Row-Template اشاره کند؛ در PasarGuard بلوک `.env` و صفحهٔ خودش را برمی دارد؛ در Rebecca دو تنظیم اشتراکی را که تغییر داده بازمی گرداند (و اگر از آن پس صفحهٔ دیگری انتخاب کرده باشید، به آن ها دست نمی زند). به کاربران، inboundها، کلاینت ها، نودها و گواهی های شما دست زده نمی شود.
[مستندات](https://iitzseridev.github.io/Row-Template/fa/) پیکربندی، برندسازی و رفع اشکال را با جزئیات بیشتری پوشش می دهد.
## توسعه
-صفحه ها از منابع خوانای موجود در `src/` ساخته می شوند. به Node.js نسخهٔ 22 یا بالاتر، و برای اجرای آزمون ها به Go نسخهٔ 1.22 یا بالاتر نیاز دارید.
+صفحه ها از منابع خوانای موجود در `src/` ساخته می شوند. به Node.js نسخهٔ 22 یا بالاتر نیاز دارید؛ برای اجرای آزمون ها همچنین به Go نسخهٔ 1.22 یا بالاتر و Python 3 همراه Jinja2 (`pip install jinja2`) که صفحه های PasarGuard و Rebecca را با موتورهای واقعی همان پنل ها رندر می کنند.
```bash
npm run build # regenerate template/index.html from src/
@@ -238,7 +269,7 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
## آزمون
-- **`npm test`** ابتدا صفحه های fixture همهٔ طرح ها را با رندرکنندهٔ Go می سازد و سپس مجموعه های آزمون را اجرا می کند: اسکریپت های صفحه، فرآیند ساخت، فایل نهایی هر طرح، محتوای بستهٔ انتشار و نصب کننده — که کتابخانهٔ shell منتشرشده را در یک `bash` واقعی روی fixtureهای موقت اجرا می کند.
+- **`npm test`** ابتدا صفحه های fixture همهٔ طرح ها را با رندرکنندهٔ Go می سازد و سپس مجموعه های آزمون را اجرا می کند: اسکریپت های صفحه، فرآیند ساخت، فایل نهایی هر طرح، صفحه های PasarGuard و Rebecca که با Jinja2 و pongo2 واقعی رندر می شوند (از جمله با داده های مخرب و ناقص)، محتوای بستهٔ انتشار و نصب کننده — که کتابخانهٔ shell منتشرشده و آداپتور هر پنل را در یک `bash` واقعی روی میزبان های موقتی اجرا می کند که مانند نصب رسمی هر پنل چیده شده اند.
- **`npm run verify`** یک صفحهٔ ساخته شده را با دروازه های ایمنی آن می سنجد، از جمله: سند کامل، جایگزینی همهٔ نشانگرهای ساخت، گنجاندن همه چیز در فایل، نبود ارجاع راه دور، نبود ساختارهای ممنوع، سالم بودن ترجمه ها و نبود نویسه های نامرئی در منابع.
- **`npm run lint:sh`** با هر خطای ShellCheck شکست می خورد؛ `npm run lint:sh -- -S warning` گزارش کامل را نشان می دهد.
- **گردش کار Docs** سایت مستندات را در هر pull request که آن را تغییر دهد می سازد.
@@ -247,18 +278,17 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
جهت گیری، نه وعده:
-- **Row-Template 1.2.0** — پانزده طرح و انتخابگر طرح که در بالا توضیح داده شد.
-- **PasarGuard و Rebecca** — در حال پژوهش. پوستهٔ صفحه برای هر دو ساخته شده است؛ وضعیت زنده به یک تغییر کوچک در کد اجرایی یا یک reverse proxy نیاز دارد و این تصمیم به تعویق افتاده است. [سازگاری](https://iitzseridev.github.io/Row-Template/fa/compatibility/) را ببینید.
-- **نصب روی بیش از یک پنل** — زیرساخت نصب کننده (یک رابط پنل، یک موتور تراکنش، یک آداپتور 3X-UI و یک قالب پشتیبان گیری جدید) آماده است، اما هنوز هیچ دستوری از آن استفاده نمی کند.
+- **Row-Template 1.3.0** — پشتیبانی از PasarGuard و Rebecca، و طرح های Meter و Notebook، که در بالا توضیح داده شد.
+- **وضعیت زنده در PasarGuard و Rebecca** — هر دو آن را روی یک پسوند مسیر ارائه می دهند نه `?format=info`؛ اتصال آن به یک تغییر کوچک در کد اجرایی نیاز دارد و این تصمیم به تعویق افتاده است. [سازگاری](https://iitzseridev.github.io/Row-Template/fa/compatibility/) را ببینید.
- **قالب های سفارشی** — پیشنهادی برای افزودن طرح خودتان: [`docs/design/CUSTOM-TEMPLATES-PROPOSAL.md`](docs/design/CUSTOM-TEMPLATES-PROPOSAL.md).
## مشارکت
گزارش اشکال، ترجمه و اصلاح مستندات بسیار استقبال می شود. پیش از باز کردن pull request، [CONTRIBUTING.md](CONTRIBUTING.md) را بخوانید و از [آیین نامهٔ رفتاری](CODE_OF_CONDUCT.md) پیروی کنید.
-**گزارش اشکال:** یک issue در باز کنید. نسخهٔ Row-Template خود (`row-template version`)، نسخهٔ 3X-UI، سیستم عامل و نسخهٔ آن، معماری پردازنده، خروجی `row-template verify` و گام های روشن برای بازتولید مشکل را ذکر کنید.
+**گزارش اشکال:** یک issue در باز کنید. نسخهٔ Row-Template خود (`row-template version`)، پنل شما و نسخهٔ آن، سیستم عامل و نسخهٔ آن، معماری پردازنده، خروجی `row-template verify` و گام های روشن برای بازتولید مشکل را ذکر کنید.
-> **هیچ گونه اطلاعات محرمانه درج نکنید.** هرگز URLهای اشتراک، مقادیر `subId`، UUIDهای کلاینت، نام کاربری یا گذرواژهٔ پنل، کوکی ها، توکن ها، `webBasePath` پنل، کلیدهای TLS یا نشانی های واقعی سرور را وارد نکنید. پیش از اشتراک گذاری لاگ ها، آن ها را ویرایش و پاک سازی کنید.
+> **هیچ گونه اطلاعات محرمانه درج نکنید.** هرگز URLهای اشتراک، مقادیر `subId`، UUIDهای کلاینت، نام کاربری یا گذرواژهٔ پنل، کوکی ها، توکن ها، `webBasePath` پنل، محتوای `.env`، URLهای پایگاه داده، کلیدهای TLS یا نشانی های واقعی سرور را وارد نکنید. پیش از اشتراک گذاری لاگ ها، آن ها را ویرایش و پاک سازی کنید.
## امنیت
diff --git a/README.md b/README.md
index f94c223..feb54c0 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
- A polished, self-contained subscription page for 3X-UI panels — fifteen designs, each a single HTML file, fully white-label, with no third-party requests from the page your subscribers open.
+ A polished, self-contained subscription page for 3X-UI, PasarGuard and Rebecca panels — seventeen designs, each a single HTML file, fully white-label, with no third-party requests from the page your subscribers open.
@@ -17,7 +17,7 @@
-
+
@@ -34,21 +34,21 @@
## What it is
-3X-UI can serve a custom page to subscribers instead of its built-in one. Row-Template is that page: a subscriber opens their subscription link and sees their plan, their usage, their expiry date, and one-tap ways to add the subscription to the app they use.
+3X-UI, PasarGuard and Rebecca can each serve a custom page to subscribers instead of their built-in one. Row-Template is that page: a subscriber opens their subscription link and sees their plan, their usage, their expiry date, and one-tap ways to add the subscription to the app they use.
-It ships as one self-contained HTML file per design, with every style, script, font, and the QR code generator inlined. A single command installs it next to your panel, points the panel at it, and gives you a `row-template` manager for branding, updates, and rollback.
+It ships as one self-contained HTML file per design, with every style, script, font, and the QR code generator inlined, and a version of each design in every panel's own template language. A single command detects your panel, installs the page next to it, points the panel at it, and gives you a `row-template` manager for branding, updates, and rollback.
## Why Row-Template?
- **Private by design.** The page your subscribers open makes no third-party requests. QR codes are generated on the page, and your branding is injected as text — never executed, never sent anywhere.
- **Genuinely white-label.** Your service name, your support link, your logo. Nothing on the served page identifies Row-Template.
-- **Fifteen designs, one file each.** Pick the look that fits your service. Every design shares the same features, languages, and safety checks.
+- **Seventeen designs, one file each.** Pick the look that fits your service. Every design shares the same features, languages, and safety checks — on every supported panel.
- **Made for your subscribers.** Live usage and expiry, one-tap import into popular apps, and a searchable list of individual configurations for adding a single server by hand.
-- **Safe to operate.** Checksum-verified releases, atomic activation, and one-command rollback. It never patches 3X-UI: the only panel setting it changes is the subscription page directory (`subThemeDir`).
+- **Safe to operate.** Checksum-verified releases, transactional activation that restores the panel exactly if any step fails, and one-command rollback. It never patches your panel: on 3X-UI it changes one setting (`subThemeDir`), on PasarGuard it adds one marked block to `.env`, and on Rebecca it sets two fields of its subscription settings.
## Designs
-Row-Template 1.2.0 ships fifteen designs. Row is the default.
+Row-Template 1.3.0 ships seventeen designs. Row is the default.
@@ -72,6 +72,10 @@ Row-Template 1.2.0 ships fifteen designs. Row is the default.
 Terminal Nova |
 Arcade Nova |
+
+  Meter |
+  Notebook |
+
Previews are rendered from the project's own placeholder data. Desktop and mobile previews of every design are in the template gallery.
@@ -82,7 +86,7 @@ Choose a design during a fresh interactive install, set `RT_TEMPLATE` for a scri
**For your subscribers**
-- **Live status.** Plan state, traffic used and remaining, and expiry, refreshed from your panel while the page is visible.
+- **Live status.** Plan state, traffic used and remaining, and expiry, refreshed from your panel while the page is visible (3X-UI; on PasarGuard and Rebecca the page shows the values as of when it was opened).
- **One-tap import** into popular apps, grouped by platform: v2rayNG, Happ and sing-box on Android; Streisand, V2Box and Shadowrocket on iOS; Clash Verge Rev, Mihomo Party and v2rayN on Windows; Clash Verge Rev, Streisand and V2Box on macOS.
- **Copy and QR.** Copy the subscription link or scan it as a QR code generated on the page.
- **Configuration Explorer.** Every server on its own row, with a country flag or monogram and a protocol label (VLESS, VMess, Trojan, Shadowsocks, Hysteria/Hysteria2, WireGuard, AmneziaWG, Telegram MTProto), plus per-configuration QR and copy, and search for long lists.
@@ -99,17 +103,17 @@ Choose a design during a fresh interactive install, set `RT_TEMPLATE` for a scri
- **No third-party requests** from the served page: no CDNs, no external QR or geolocation lookups, no telemetry. Live status comes from your own panel.
- **Mandatory SHA-256** verification of every release download, with no option to skip it.
- **Atomic activation.** A new page is generated and validated before it replaces the live one, so a failed step never leaves a broken page live.
-- **Fail-closed panel detection.** If the panel database Row-Template finds is not a valid SQLite database, it refuses to use it rather than guessing another one.
+- **Fail-closed panel detection.** A panel counts as installed only when independent signals agree; a half-installed panel, or a panel database that is not a valid SQLite database, is refused rather than guessed at.
## Supported panels
| Panel | Status | Notes |
| ----- | ------ | ----- |
| [3X-UI](https://github.com/MHSanaei/3x-ui) (MHSanaei) | ✅ Supported | Requires version **>= 3.6.0** |
-| [PasarGuard](https://github.com/PasarGuard/panel) | 🔬 Research | Not supported; no installation path |
-| [Rebecca](https://github.com/rebeccapanel/Rebecca) | 🔬 Research | Not supported; no installation path |
+| [PasarGuard](https://github.com/PasarGuard/panel) | ✅ Supported since 1.3.0 | The official Docker install or a source install (`pasarguard.service`) |
+| [Rebecca](https://github.com/rebeccapanel/Rebecca) | ✅ Supported since 1.3.0 | Rebecca **1.x**, the Go edition (Rebecca's binary install). Automatic activation with SQLite and `sqlite3`; with MySQL/MariaDB, one setting to enter in the dashboard. The Docker image is still 0.0.x and is refused |
-3X-UI is the only supported panel. PasarGuard and Rebecca use different template engines (Jinja2 and pongo2); each design's page shell is built for them and packaged in the release for study, but the installer does not place it and there are no installation instructions for them. See [Compatibility](https://iitzseridev.github.io/Row-Template/compatibility/) for the research findings.
+The three panels use three different template engines — Go `html/template`, Jinja2 and pongo2 — so every design is built once per panel, and each version is tested by rendering it with that panel's real engine. The installer detects which panel is on the server; on a server with more than one, it asks (or reads `RT_PANEL`). **Supported** means all seven capabilities are present on that panel — detect, install, activate, verify, backup, restore and uninstall — and each one is exercised by the test suite. See [Compatibility](https://iitzseridev.github.io/Row-Template/compatibility/) for the details of each panel.
## Architecture
@@ -117,14 +121,14 @@ Choose a design during a fresh interactive install, set `RT_TEMPLATE` for a scri
flowchart TB
subgraph build ["Build and release"]
direction LR
- SRC["src/
runtime, styles, locales,
15 design layouts"] --> BUILD["tools/build.mjs"]
- BUILD --> ART["One self-contained
HTML file per design"]
+ SRC["src/
runtime, styles, locales,
17 design layouts"] --> BUILD["tools/build.mjs"]
+ BUILD --> ART["One self-contained
HTML file per design,
per panel"]
ART --> REL["tools/make-release.sh
tarball + SHA256SUMS"]
end
- subgraph host ["Your 3X-UI server"]
+ subgraph host ["Your panel server"]
direction LR
- INST["install.sh / row-template
verify checksum, stage, validate,
back up, activate"] --> DIR["/etc/3x-ui/
sub_templates/row-template"]
- DIR -- "subThemeDir" --> XUI["3X-UI renders the page
with the subscriber's data"]
+ INST["install.sh / row-template
verify checksum, detect panel,
back up, activate, verify"] --> DIR["3X-UI: subThemeDir
PasarGuard: .env block
Rebecca: subscription settings"]
+ DIR --> XUI["The panel renders the page
with the subscriber's data"]
end
build -- "GitHub Releases" --> host
host -- "serves the page" --> BROWSER["Subscriber's browser"]
@@ -132,15 +136,15 @@ flowchart TB
```
- **One file per design.** `tools/build.mjs` inlines the shared runtime, the translations, the fonts, and the QR generator into a design's layout, and refuses a layout that is missing any hook the runtime needs. `tools/verify.mjs` then rejects an artifact that loads anything remote or carries a forbidden construct.
-- **The panel does the rendering.** The page is a template: 3X-UI fills in the subscriber's data when it serves it, and the page then refreshes its status from the same panel.
-- **The installer never edits 3X-UI.** It writes its own directory and changes one panel setting, `subThemeDir`, to point at it.
+- **The panel does the rendering.** The page is a template: the panel fills in the subscriber's data when it serves it. For PasarGuard (Jinja2) and Rebecca (pongo2) each design is wrapped in a small prelude that maps the panel's own data onto the page and escapes every value.
+- **The installer never patches your panel.** On 3X-UI it points `subThemeDir` at its own directory; on PasarGuard it places the page in the templates directory and appends one marked block to `.env`; on Rebecca it places the page and sets the page and directory fields of its subscription settings. Each change is snapshotted first and restored exactly if anything fails.
| Path | What lives there |
| ---- | ---------------- |
| `src/` | The page's runtime, styles, and translations; each design in `src/templates//` |
| `template/index.html` | The built Row page, committed |
| `tools/` | Build, verification, release, and the Go fixture renderer |
-| `installer/` | `install.sh`, the `row-template` command, and its management library |
+| `installer/` | `install.sh`, the `row-template` command, its management library, and one adapter per panel in `installer/panels/` |
| `tests/` | The test suites |
| `docs/` | The documentation site; design records in [`docs/design/`](docs/design/README.md) |
@@ -148,9 +152,9 @@ flowchart TB
> **Recommended OS: Ubuntu 24.04 LTS (x86_64).** Other modern Linux distributions may work but have not had the same validation coverage.
-**Requirements:** a server running 3X-UI **>= 3.6.0**, root access to it, and `curl`, `tar`, and `sha256sum` (present on virtually all Linux systems). Automatic activation also needs `sqlite3`.
+**Requirements:** a server running 3X-UI **>= 3.6.0**, PasarGuard, or Rebecca **1.x**; root access to it; and `curl`, `tar`, and `sha256sum` (present on virtually all Linux systems). Automatic activation on 3X-UI and Rebecca also needs `sqlite3`.
-Run as **root** on the server that hosts your 3X-UI panel:
+Run as **root** on the server that hosts your panel:
```bash
bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
@@ -160,7 +164,7 @@ The installer:
1. Downloads the latest stable release from GitHub.
2. Verifies its SHA-256 checksum (mandatory — no bypass).
-3. Extracts it safely and installs to `/etc/3x-ui/sub_templates/row-template`.
+3. Detects your panel, extracts the release safely and installs to `/etc/3x-ui/sub_templates/row-template` (3X-UI) or `/etc/row-template` (PasarGuard, Rebecca).
4. On a fresh install, offers the design chooser (Enter keeps Row).
5. Prompts for your branding (service name, support link, logo — all optional).
6. Generates and validates the page, then activates it in the panel where possible.
@@ -171,6 +175,12 @@ To choose a design without the chooser, for example in a script:
RT_TEMPLATE=editorial bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
```
+On a server that runs more than one supported panel, the installer asks which one to serve; in a script, name it with `RT_PANEL` (`3xui`, `pasarguard` or `rebecca`):
+
+```bash
+RT_PANEL=pasarguard bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
+```
+
If you prefer not to pipe from the network, download the four release assets (`install.sh`, `manifest.txt`, `SHA256SUMS`, and `row-template-.tar.gz`) from the [Releases page](https://github.com/iitzSeriZdev/Row-Template/releases/latest) into one folder, verify the checksum yourself as described in [PROVENANCE.md](PROVENANCE.md), and point the installer at that folder:
```bash
@@ -179,19 +189,39 @@ RT_RELEASE_DIR=/root/row-template-release bash /root/row-template-release/instal
### Activation
-Row-Template installs to a directory that the panel serves as its subscription page:
+An interactive install shows what activation will change and asks first. On PasarGuard and Rebecca, activation runs as a transaction: the panel's state is snapshotted, changed, verified, and — if any step fails — restored exactly.
+
+**3X-UI.** Row-Template installs to a directory that the panel serves as its subscription page:
```
/etc/3x-ui/sub_templates/row-template
```
-- **Automatic:** when `sqlite3` is available, Row-Template sets it for you. It briefly stops the panel service, writes the setting, starts the service again, and checks the value. An interactive install shows the current setting and asks first.
+- **Automatic:** when `sqlite3` is available, Row-Template sets it for you. It briefly stops the panel service, writes the setting, starts the service again, and checks the value.
- **Manual:** otherwise, open **Panel Settings → Subscription → Profile → Sub Theme Directory** and enter exactly:
```
/etc/3x-ui/sub_templates/row-template
```
+**PasarGuard.** The page is placed at `/var/lib/pasarguard/templates/row-template/index.html` (or inside your own `CUSTOM_TEMPLATES_DIRECTORY`, if you set one), and a marked block is appended to `/opt/pasarguard/.env`:
+
+```
+# >>> row-template (managed by Row-Template; do not edit) nl=0 >>>
+CUSTOM_TEMPLATES_DIRECTORY = "/var/lib/pasarguard/templates"
+SUBSCRIPTION_PAGE_TEMPLATE = "row-template/index.html"
+# <<< row-template <<<
+```
+
+PasarGuard reads `.env` at start-up, so a running panel is restarted once. None of your own lines are edited; uninstall removes the block and returns `.env` to its exact previous bytes. An admin with their own subscription template, or the **disable subscription template** setting, still takes precedence — `row-template verify` tells you when either applies.
+
+Row-Template supports Rebecca **1.x**, the Go edition, which Rebecca publishes for its binary install (`rebecca-binary.sh`). Docker Hub's `rebeccapanel/rebecca` image is still the 0.0.x Python edition, which cannot render this page; the installer refuses it and changes nothing, and Rebecca's own `rebecca migrate-binary` moves a Docker install to 1.x.
+
+**Rebecca.** The page is placed at `/var/lib/rebecca/templates/row-template/index.html` (or inside your own custom templates directory), and Rebecca's subscription settings are set to `row-template/index.html`. Rebecca reads them on every request, so no restart is needed.
+
+- **Automatic** with the default SQLite database and `sqlite3` installed.
+- **Manual** with MySQL/MariaDB (or without `sqlite3`): the page is still placed; in the Rebecca dashboard open **Settings → Subscription → Templates** and set **Subscription page template** to `row-template/index.html` and **Custom templates directory** to `/var/lib/rebecca/templates`.
+
## Usage
Run the manager with no arguments in a terminal to open the interactive menu:
@@ -207,23 +237,24 @@ Or use a command directly:
| `row-template config` | Change the service name, support link, or logo, then regenerate the page |
| `row-template update` | Download, verify, and activate the latest stable release (checksum enforced) |
| `row-template rollback` | Restore a previous version (`--auto` or `--to `) |
-| `row-template verify` | Check the install, the panel wiring, and the live page (read-only) |
-| `row-template version` | Show the installed, minimum-supported, and detected 3X-UI versions |
-| `row-template uninstall` | Remove Row-Template and revert the panel to its built-in page |
+| `row-template verify` | Check the install, the panel wiring, and the live page (as root, it also puts back missing or misplaced designs) |
+| `row-template version` | Show the installed version and the panel it serves (on 3X-UI, also the minimum-supported and detected versions) |
+| `row-template uninstall` | Remove Row-Template and return the panel to the page it had before |
| `row-template help` | Show usage |
Commands that change the system (`config`, `update`, `rollback`, `uninstall`) must run as root.
- **Branding** is stored as data, never executed, and injected into the page as text. Leave a field blank for an unbranded page. The support link accepts only schemes a browser should open, such as `https://…`, `tg://…`, or `mailto:…`.
- **Updates** come from the public stable channel. `row-template update` always applies the latest stable release, even the version you already run; the manager's **Update** compares versions first and asks before changing anything. If the release source is unreachable, nothing is changed and your installation is never treated as damaged.
-- **Rollback** restores a previous version from a validated backup. The current version is snapshotted first, so a failed rollback can be recovered, and your branding is preserved.
-- **Uninstall** removes Row-Template's files. It clears the panel's `subThemeDir` only if it points at Row-Template, so the panel falls back to its built-in page; your inbounds, clients, and certificates are not touched.
+- **Updating from 1.1.0 or 1.2.x** takes one `row-template update`. 1.1.0's own updater copies only part of the new release, so the next `row-template`, `row-template config`, or `row-template verify` run as root first downloads the rest of that same release — every design, checksum-verified. Your design, branding, and panel wiring are kept.
+- **Rollback** restores a previous version from a validated backup. The current version is snapshotted first, so a failed rollback can be recovered, and your branding is preserved. Backups record the panel they were made on and are never restored onto another; a backup from an older release that does not name its design restores as Row.
+- **Uninstall** removes Row-Template's files and returns the panel to the page it had before: on 3X-UI it clears `subThemeDir` only if it points at Row-Template; on PasarGuard it removes its `.env` block and its page; on Rebecca it restores the two subscription settings it changed (leaving them alone if you have since chosen another page). Your users, inbounds, clients, nodes, and certificates are not touched.
The [documentation](https://iitzseridev.github.io/Row-Template/) covers configuration, branding, and troubleshooting in more depth.
## Development
-The pages are built from readable sources in `src/`. You need Node.js 22 or newer, and Go 1.22 or newer to run the tests.
+The pages are built from readable sources in `src/`. You need Node.js 22 or newer; to run the tests, also Go 1.22 or newer and Python 3 with Jinja2 (`pip install jinja2`), which render the PasarGuard and Rebecca pages with those panels' real engines.
```bash
npm run build # regenerate template/index.html from src/
@@ -238,7 +269,7 @@ The build is deterministic — the same sources always produce a byte-identical
## Testing
-- **`npm test`** renders every design's fixture pages with the Go renderer, then runs the suites: the page's scripts, the build, every design's artifact, the release payload, and the installer — which runs the shipped shell library in real `bash` against throwaway fixtures.
+- **`npm test`** renders every design's fixture pages with the Go renderer, then runs the suites: the page's scripts, the build, every design's artifact, the PasarGuard and Rebecca pages rendered by real Jinja2 and pongo2 (including hostile and malformed data), the release payload, and the installer — which runs the shipped shell library and every panel adapter in real `bash` against throwaway hosts laid out like each panel's official install.
- **`npm run verify`** checks a built page against its safety gates, including: a whole document, every build marker substituted, everything inlined, no remote references, no forbidden constructs, intact translations, and no invisible characters in the sources.
- **`npm run lint:sh`** fails on any ShellCheck error; `npm run lint:sh -- -S warning` shows the full report.
- **The Docs workflow** builds the documentation site on every pull request that changes it.
@@ -247,18 +278,17 @@ The build is deterministic — the same sources always produce a byte-identical
Direction, not promises:
-- **Row-Template 1.2.0** — the fifteen designs and the design chooser described above.
-- **PasarGuard and Rebecca** — research. Page shells are built for both; live status needs a small runtime change or a reverse proxy, and that decision is deferred. See [Compatibility](https://iitzseridev.github.io/Row-Template/compatibility/).
-- **Installing on more than one panel** — the installer groundwork (a panel interface, a transaction engine, a 3X-UI adapter, and a new backup format) is in place but not yet used by any command.
+- **Row-Template 1.3.0** — PasarGuard and Rebecca support, and the Meter and Notebook designs, described above.
+- **Live status on PasarGuard and Rebecca** — both serve it on a path suffix rather than `?format=info`; wiring it up needs a small runtime change, and that decision is deferred. See [Compatibility](https://iitzseridev.github.io/Row-Template/compatibility/).
- **Custom templates** — a proposal for adding your own design: [`docs/design/CUSTOM-TEMPLATES-PROPOSAL.md`](docs/design/CUSTOM-TEMPLATES-PROPOSAL.md).
## Contributing
Bug reports, translations, and documentation fixes are very welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) before opening a pull request, and follow the [Code of Conduct](CODE_OF_CONDUCT.md).
-**Bug reports:** open an issue at . Include your Row-Template version (`row-template version`), 3X-UI version, operating system and version, CPU architecture, the output of `row-template verify`, and clear steps to reproduce.
+**Bug reports:** open an issue at . Include your Row-Template version (`row-template version`), your panel and its version, operating system and version, CPU architecture, the output of `row-template verify`, and clear steps to reproduce.
-> **Do not include secrets.** Never paste subscription URLs, `subId` values, client UUIDs, panel usernames or passwords, cookies, tokens, the panel `webBasePath`, TLS keys, or real server addresses. Redact logs before sharing them.
+> **Do not include secrets.** Never paste subscription URLs, `subId` values, client UUIDs, panel usernames or passwords, cookies, tokens, the panel `webBasePath`, the contents of `.env`, database URLs, TLS keys, or real server addresses. Redact logs before sharing them.
## Security
diff --git a/README.ru.md b/README.ru.md
index 6603a7b..9c8e6b2 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -7,7 +7,7 @@
- Аккуратная автономная страница подписки для панелей 3X-UI — пятнадцать дизайнов, каждый в одном HTML-файле, полностью white-label и без сторонних запросов со страницы, которую открывают ваши подписчики.
+ Аккуратная автономная страница подписки для панелей 3X-UI, PasarGuard и Rebecca — семнадцать дизайнов, каждый в одном HTML-файле, полностью white-label и без сторонних запросов со страницы, которую открывают ваши подписчики.
@@ -17,7 +17,7 @@
-
+
@@ -34,21 +34,21 @@
## Что это такое
-3X-UI умеет показывать подписчикам собственную страницу вместо встроенной. Row-Template — такая страница: подписчик открывает ссылку на подписку и видит свой тариф, расход трафика, дату окончания и способы добавить подписку в своё приложение в одно касание.
+3X-UI, PasarGuard и Rebecca умеют показывать подписчикам собственную страницу вместо встроенной. Row-Template — такая страница: подписчик открывает ссылку на подписку и видит свой тариф, расход трафика, дату окончания и способы добавить подписку в своё приложение в одно касание.
-Каждый дизайн поставляется одним автономным HTML-файлом, в который встроены все стили, скрипты, шрифты и генератор QR-кодов. Одна команда устанавливает его рядом с панелью, направляет на него панель и даёт вам менеджер `row-template` для оформления, обновлений и отката.
+Каждый дизайн поставляется одним автономным HTML-файлом, в который встроены все стили, скрипты, шрифты и генератор QR-кодов, а также версией на языке шаблонов каждой панели. Одна команда определяет вашу панель, устанавливает страницу рядом с ней, направляет на неё панель и даёт вам менеджер `row-template` для оформления, обновлений и отката.
## Почему Row-Template?
- **Приватность по умолчанию.** Страница, которую открывают подписчики, не делает сторонних запросов. QR-коды генерируются прямо на странице, а ваше оформление вставляется как текст — никогда не выполняется и никуда не отправляется.
- **Настоящий white-label.** Ваше название сервиса, ваша ссылка на поддержку, ваш логотип. Ничто на странице не указывает на Row-Template.
-- **Пятнадцать дизайнов, каждый в одном файле.** Выберите вид, который подходит вашему сервису. У всех дизайнов одинаковые возможности, языки и проверки безопасности.
+- **Семнадцать дизайнов, каждый в одном файле.** Выберите вид, который подходит вашему сервису. У всех дизайнов одинаковые возможности, языки и проверки безопасности — на каждой поддерживаемой панели.
- **Сделано для ваших подписчиков.** Расход и срок действия в реальном времени, импорт в популярные приложения в одно касание и список отдельных конфигураций с поиском, чтобы добавить один сервер вручную.
-- **Безопасен в эксплуатации.** Релизы с проверкой контрольной суммы, атомарная активация и откат одной командой. Row-Template никогда не патчит 3X-UI: единственная настройка панели, которую он меняет, — каталог страницы подписки (`subThemeDir`).
+- **Безопасен в эксплуатации.** Релизы с проверкой контрольной суммы, транзакционная активация, которая точно восстанавливает панель при сбое любого шага, и откат одной командой. Row-Template никогда не патчит вашу панель: в 3X-UI он меняет одну настройку (`subThemeDir`), в PasarGuard добавляет один помеченный блок в `.env`, а в Rebecca задаёт два поля настроек подписки.
## Дизайны
-Row-Template 1.2.0 поставляется с пятнадцатью дизайнами. Дизайн по умолчанию — Row.
+Row-Template 1.3.0 поставляется с семнадцатью дизайнами. Дизайн по умолчанию — Row.
@@ -72,6 +72,10 @@ Row-Template 1.2.0 поставляется с пятнадцатью дизай
 Terminal Nova |
 Arcade Nova |
+
+  Meter |
+  Notebook |
+
Превью построены на демонстрационных данных самого проекта. Превью каждого дизайна для компьютера и телефона — в галерее шаблонов.
@@ -82,7 +86,7 @@ Row-Template 1.2.0 поставляется с пятнадцатью дизай
**Для ваших подписчиков**
-- **Статус в реальном времени.** Состояние тарифа, израсходованный и оставшийся трафик и срок действия, которые обновляются из вашей панели, пока страница открыта на экране.
+- **Статус в реальном времени.** Состояние тарифа, израсходованный и оставшийся трафик и срок действия, которые обновляются из вашей панели, пока страница открыта на экране (в 3X-UI; в PasarGuard и Rebecca страница показывает значения на момент открытия).
- **Импорт в одно касание** в популярные приложения, сгруппированные по платформам: v2rayNG, Happ и sing-box на Android; Streisand, V2Box и Shadowrocket на iOS; Clash Verge Rev, Mihomo Party и v2rayN на Windows; Clash Verge Rev, Streisand и V2Box на macOS.
- **Копирование и QR.** Скопируйте ссылку на подписку или отсканируйте её как QR-код, созданный на самой странице.
- **Обозреватель конфигураций.** Каждый сервер в отдельной строке — с флагом страны или монограммой и меткой протокола (VLESS, VMess, Trojan, Shadowsocks, Hysteria/Hysteria2, WireGuard, AmneziaWG, Telegram MTProto), с QR-кодом и копированием для каждой конфигурации и поиском по длинным спискам.
@@ -99,17 +103,17 @@ Row-Template 1.2.0 поставляется с пятнадцатью дизай
- **Никаких сторонних запросов** со страницы: без CDN, без внешних сервисов QR и геолокации, без телеметрии. Статус в реальном времени приходит из вашей же панели.
- **Обязательная проверка SHA-256** для каждой загрузки релиза, без возможности её пропустить.
- **Атомарная активация.** Новая страница создаётся и проверяется до того, как заменит работающую, поэтому неудачный шаг никогда не оставляет сломанную страницу.
-- **Осторожное обнаружение панели.** Если найденная база данных панели не является корректной базой SQLite, Row-Template отказывается её использовать, а не пытается угадать другую.
+- **Осторожное обнаружение панели.** Панель считается установленной, только когда совпадают независимые признаки; частично установленная панель или база данных панели, не являющаяся корректной базой SQLite, отвергается, а не угадывается.
## Поддерживаемые панели
| Панель | Статус | Примечания |
| ----- | ------ | ----- |
| [3X-UI](https://github.com/MHSanaei/3x-ui) (MHSanaei) | ✅ Поддерживается | Требуется версия **>= 3.6.0** |
-| [PasarGuard](https://github.com/PasarGuard/panel) | 🔬 Исследование | Не поддерживается; установка не предусмотрена |
-| [Rebecca](https://github.com/rebeccapanel/Rebecca) | 🔬 Исследование | Не поддерживается; установка не предусмотрена |
+| [PasarGuard](https://github.com/PasarGuard/panel) | ✅ Поддерживается с 1.3.0 | Официальная установка в Docker или установка из исходников (`pasarguard.service`) |
+| [Rebecca](https://github.com/rebeccapanel/Rebecca) | ✅ Поддерживается с 1.3.0 | Rebecca **1.x**, версия на Go (бинарная установка Rebecca). Автоматическая активация с SQLite и `sqlite3`; с MySQL/MariaDB — одна настройка в панели управления. Образ Docker всё ещё 0.0.x и отклоняется |
-3X-UI — единственная поддерживаемая панель. PasarGuard и Rebecca используют другие шаблонизаторы (Jinja2 и pongo2); оболочка страницы каждого дизайна собирается для них и упаковывается в релиз для изучения, но установщик её не размещает, и инструкций по установке для них нет. Результаты исследования — в разделе [Совместимость](https://iitzseridev.github.io/Row-Template/compatibility/).
+Три панели используют три разных шаблонизатора — Go `html/template`, Jinja2 и pongo2, — поэтому каждый дизайн собирается отдельно для каждой панели, и каждая версия проверяется отрисовкой настоящим движком этой панели. Установщик определяет, какая панель стоит на сервере; если их несколько, он спрашивает (или читает `RT_PANEL`). **Поддерживается** означает, что для этой панели есть все семь возможностей — обнаружение, установка, активация, проверка, резервная копия, восстановление и удаление, — и каждая из них покрыта тестами. Подробности по каждой панели — в разделе [Совместимость](https://iitzseridev.github.io/Row-Template/compatibility/).
## Архитектура
@@ -117,14 +121,14 @@ Row-Template 1.2.0 поставляется с пятнадцатью дизай
flowchart TB
subgraph build ["Build and release"]
direction LR
- SRC["src/
runtime, styles, locales,
15 design layouts"] --> BUILD["tools/build.mjs"]
- BUILD --> ART["One self-contained
HTML file per design"]
+ SRC["src/
runtime, styles, locales,
17 design layouts"] --> BUILD["tools/build.mjs"]
+ BUILD --> ART["One self-contained
HTML file per design,
per panel"]
ART --> REL["tools/make-release.sh
tarball + SHA256SUMS"]
end
- subgraph host ["Your 3X-UI server"]
+ subgraph host ["Your panel server"]
direction LR
- INST["install.sh / row-template
verify checksum, stage, validate,
back up, activate"] --> DIR["/etc/3x-ui/
sub_templates/row-template"]
- DIR -- "subThemeDir" --> XUI["3X-UI renders the page
with the subscriber's data"]
+ INST["install.sh / row-template
verify checksum, detect panel,
back up, activate, verify"] --> DIR["3X-UI: subThemeDir
PasarGuard: .env block
Rebecca: subscription settings"]
+ DIR --> XUI["The panel renders the page
with the subscriber's data"]
end
build -- "GitHub Releases" --> host
host -- "serves the page" --> BROWSER["Subscriber's browser"]
@@ -132,15 +136,15 @@ flowchart TB
```
- **Один файл на дизайн.** `tools/build.mjs` встраивает общий код, переводы, шрифты и генератор QR в макет дизайна и отклоняет макет, в котором нет хотя бы одной нужной коду точки привязки (hook). Затем `tools/verify.mjs` отклоняет файл, который загружает что-либо извне или содержит запрещённую конструкцию.
-- **Страницу отрисовывает панель.** Страница — это шаблон: 3X-UI подставляет данные подписчика при выдаче, а затем страница обновляет свой статус из той же панели.
-- **Установщик никогда не редактирует 3X-UI.** Он пишет в собственный каталог и меняет одну настройку панели, `subThemeDir`, чтобы она указывала на него.
+- **Страницу отрисовывает панель.** Страница — это шаблон: панель подставляет данные подписчика при выдаче. Для PasarGuard (Jinja2) и Rebecca (pongo2) каждый дизайн обёрнут в небольшую преамбулу, которая сопоставляет собственные данные панели полям страницы и экранирует каждое значение.
+- **Установщик никогда не патчит вашу панель.** В 3X-UI он направляет `subThemeDir` на свой каталог; в PasarGuard кладёт страницу в каталог шаблонов и дописывает в `.env` один помеченный блок; в Rebecca кладёт страницу и задаёт поля страницы и каталога в настройках подписки. Перед каждым изменением делается снимок, и при любом сбое всё точно восстанавливается.
| Путь | Содержимое |
| ---- | ---------------- |
| `src/` | Код, стили и переводы страницы; каждый дизайн — в `src/templates//` |
| `template/index.html` | Собранная страница Row, хранится в репозитории |
| `tools/` | Сборка, проверка, релизы и рендерер фикстур на Go |
-| `installer/` | `install.sh`, команда `row-template` и её библиотека управления |
+| `installer/` | `install.sh`, команда `row-template`, её библиотека управления и по одному адаптеру на панель в `installer/panels/` |
| `tests/` | Наборы тестов |
| `docs/` | Сайт документации; проектные записи — в [`docs/design/`](docs/design/README.md) |
@@ -148,9 +152,9 @@ flowchart TB
> **Рекомендуемая ОС: Ubuntu 24.04 LTS (x86_64).** Другие современные дистрибутивы Linux могут работать, но не проходили такого же объёма проверок.
-**Требования:** сервер с 3X-UI **>= 3.6.0**, root-доступ к нему и `curl`, `tar` и `sha256sum` (есть практически в любой системе Linux). Для автоматической активации также нужен `sqlite3`.
+**Требования:** сервер с 3X-UI **>= 3.6.0**, PasarGuard или Rebecca **1.x**; root-доступ к нему; `curl`, `tar` и `sha256sum` (есть практически в любой системе Linux). Для автоматической активации в 3X-UI и Rebecca также нужен `sqlite3`.
-Запустите от имени **root** на сервере, где работает ваша панель 3X-UI:
+Запустите от имени **root** на сервере, где работает ваша панель:
```bash
bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
@@ -160,7 +164,7 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
1. Скачивает последний стабильный релиз с GitHub.
2. Проверяет его контрольную сумму SHA-256 (обязательно — без возможности обойти).
-3. Безопасно распаковывает его и устанавливает в `/etc/3x-ui/sub_templates/row-template`.
+3. Определяет вашу панель, безопасно распаковывает релиз и устанавливает его в `/etc/3x-ui/sub_templates/row-template` (3X-UI) или `/etc/row-template` (PasarGuard, Rebecca).
4. При новой установке предлагает выбрать дизайн (Enter оставляет Row).
5. Запрашивает ваше оформление (название сервиса, ссылка на поддержку, логотип — всё необязательно).
6. Создаёт и проверяет страницу, а затем, если возможно, активирует её в панели.
@@ -171,6 +175,12 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
RT_TEMPLATE=editorial bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
```
+На сервере, где работает несколько поддерживаемых панелей, установщик спрашивает, какую обслуживать; в скрипте укажите её через `RT_PANEL` (`3xui`, `pasarguard` или `rebecca`):
+
+```bash
+RT_PANEL=pasarguard bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
+```
+
Если вы не хотите запускать скрипт прямо из сети, скачайте четыре файла релиза (`install.sh`, `manifest.txt`, `SHA256SUMS` и `row-template-.tar.gz`) со [страницы релизов](https://github.com/iitzSeriZdev/Row-Template/releases/latest) в одну папку, проверьте контрольную сумму самостоятельно, как описано в [PROVENANCE.md](PROVENANCE.md), и укажите установщику эту папку:
```bash
@@ -179,19 +189,39 @@ RT_RELEASE_DIR=/root/row-template-release bash /root/row-template-release/instal
### Активация
-Row-Template устанавливается в каталог, который панель отдаёт как страницу подписки:
+Интерактивная установка сначала показывает, что изменит активация, и спрашивает разрешения. В PasarGuard и Rebecca активация выполняется как транзакция: состояние панели сохраняется в снимок, изменение применяется и проверяется, а при сбое любого шага панель точно восстанавливается.
+
+**3X-UI.** Row-Template устанавливается в каталог, который панель отдаёт как страницу подписки:
```
/etc/3x-ui/sub_templates/row-template
```
-- **Автоматически:** если доступен `sqlite3`, Row-Template настраивает это за вас. Он ненадолго останавливает службу панели, записывает настройку, снова запускает службу и проверяет значение. Интерактивная установка сначала показывает текущее значение и спрашивает разрешения.
+- **Автоматически:** если доступен `sqlite3`, Row-Template настраивает это за вас. Он ненадолго останавливает службу панели, записывает настройку, снова запускает службу и проверяет значение.
- **Вручную:** иначе откройте **Panel Settings → Subscription → Profile → Sub Theme Directory** и введите в точности:
```
/etc/3x-ui/sub_templates/row-template
```
+**PasarGuard.** Страница размещается в `/var/lib/pasarguard/templates/row-template/index.html` (или в вашем `CUSTOM_TEMPLATES_DIRECTORY`, если он задан), а в `/opt/pasarguard/.env` дописывается помеченный блок:
+
+```
+# >>> row-template (managed by Row-Template; do not edit) nl=0 >>>
+CUSTOM_TEMPLATES_DIRECTORY = "/var/lib/pasarguard/templates"
+SUBSCRIPTION_PAGE_TEMPLATE = "row-template/index.html"
+# <<< row-template <<<
+```
+
+PasarGuard читает `.env` при запуске, поэтому работающая панель перезапускается один раз. Ни одна ваша строка не редактируется; удаление убирает блок и возвращает `.env` точно к прежним байтам. Администратор с собственным шаблоном подписки или настройка **disable subscription template** по-прежнему имеют приоритет — `row-template verify` сообщит, если действует что-то из этого.
+
+Row-Template поддерживает Rebecca **1.x** — версию на Go, которую Rebecca публикует для бинарной установки (`rebecca-binary.sh`). Образ `rebeccapanel/rebecca` на Docker Hub всё ещё версии 0.0.x на Python, которая не может отрисовать эту страницу; установщик отклоняет её и ничего не меняет, а собственная команда Rebecca `rebecca migrate-binary` переводит установку Docker на 1.x.
+
+**Rebecca.** Страница размещается в `/var/lib/rebecca/templates/row-template/index.html` (или в вашем собственном каталоге шаблонов), а в настройках подписки Rebecca выбирается `row-template/index.html`. Rebecca читает эти настройки при каждом запросе, поэтому перезапуск не нужен.
+
+- **Автоматически** — с базой SQLite по умолчанию и установленным `sqlite3`.
+- **Вручную** — с MySQL/MariaDB (или без `sqlite3`): страница всё равно размещается; в панели управления Rebecca откройте **Settings → Subscription → Templates** и задайте **Subscription page template** = `row-template/index.html` и **Custom templates directory** = `/var/lib/rebecca/templates`.
+
## Использование
Запустите менеджер без аргументов в терминале, чтобы открыть интерактивное меню:
@@ -207,23 +237,24 @@ row-template
| `row-template config` | Меняет название сервиса, ссылку на поддержку или логотип и заново создаёт страницу |
| `row-template update` | Скачивает, проверяет и активирует последний стабильный релиз (проверка контрольной суммы обязательна) |
| `row-template rollback` | Восстанавливает предыдущую версию (`--auto` или `--to `) |
-| `row-template verify` | Проверяет установку, связь с панелью и работающую страницу (только чтение) |
-| `row-template version` | Показывает установленную, минимально поддерживаемую и обнаруженную версии 3X-UI |
-| `row-template uninstall` | Удаляет Row-Template и возвращает панели встроенную страницу |
+| `row-template verify` | Проверяет установку, связь с панелью и работающую страницу (от root также возвращает на место отсутствующие или перемещённые дизайны) |
+| `row-template version` | Показывает установленную версию и обслуживаемую панель (в 3X-UI — также минимально поддерживаемую и обнаруженную версии) |
+| `row-template uninstall` | Удаляет Row-Template и возвращает панели страницу, которая была до него |
| `row-template help` | Показывает справку |
Команды, изменяющие систему (`config`, `update`, `rollback`, `uninstall`), нужно запускать от имени root.
- **Оформление** хранится как данные, никогда не выполняется и вставляется в страницу как текст. Оставьте поле пустым, чтобы получить страницу без брендинга. Ссылка на поддержку принимает только схемы, которые браузер должен открывать, например `https://…`, `tg://…` или `mailto:…`.
- **Обновления** берутся из публичного стабильного канала. `row-template update` всегда применяет последний стабильный релиз, даже если он уже установлен; пункт **Update** в менеджере сначала сравнивает версии и спрашивает перед любым изменением. Если источник релизов недоступен, ничего не меняется, и установка никогда не считается повреждённой.
-- **Откат** восстанавливает предыдущую версию из проверенной резервной копии. Сначала делается снимок (snapshot) текущей версии, поэтому неудачный откат можно исправить, а ваше оформление сохраняется.
-- **Удаление** стирает файлы Row-Template. Настройку `subThemeDir` панели оно очищает, только если та указывает на Row-Template, и панель возвращается к встроенной странице; ваши inbound'ы, клиенты и сертификаты не затрагиваются.
+- **Обновление с 1.1.0 или 1.2.x** выполняется одним запуском `row-template update`. Механизм обновления самой версии 1.1.0 копирует лишь часть нового релиза, поэтому следующий запуск `row-template`, `row-template config` или `row-template verify` от root сначала загружает остальную часть того же релиза — все дизайны, с проверкой контрольных сумм. Ваш дизайн, оформление и подключение к панели сохраняются.
+- **Откат** восстанавливает предыдущую версию из проверенной резервной копии. Сначала делается снимок (snapshot) текущей версии, поэтому неудачный откат можно исправить, а ваше оформление сохраняется. Резервные копии запоминают панель, на которой созданы, и никогда не восстанавливаются на другую; копия из старого релиза, в которой не записан дизайн, восстанавливается как Row.
+- **Удаление** стирает файлы Row-Template и возвращает панели страницу, которая была до него: в 3X-UI очищает `subThemeDir`, только если та указывает на Row-Template; в PasarGuard убирает свой блок из `.env` и свою страницу; в Rebecca восстанавливает две изменённые настройки подписки (и не трогает их, если вы с тех пор выбрали другую страницу). Ваши пользователи, inbound'ы, клиенты, ноды и сертификаты не затрагиваются.
[Документация](https://iitzseridev.github.io/Row-Template/) подробнее описывает настройку, оформление и устранение неполадок.
## Разработка
-Страницы собираются из читаемых исходников в `src/`. Нужен Node.js 22 или новее, а для запуска тестов — Go 1.22 или новее.
+Страницы собираются из читаемых исходников в `src/`. Нужен Node.js 22 или новее; для запуска тестов — также Go 1.22 или новее и Python 3 с Jinja2 (`pip install jinja2`), которые отрисовывают страницы PasarGuard и Rebecca настоящими движками этих панелей.
```bash
npm run build # regenerate template/index.html from src/
@@ -238,7 +269,7 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
## Тестирование
-- **`npm test`** сначала создаёт страницы фикстур всех дизайнов рендерером на Go, а затем запускает наборы тестов: скрипты страницы, сборку, итоговый файл каждого дизайна, содержимое релиза и установщик — его опубликованная shell-библиотека выполняется в настоящем `bash` на временных фикстурах.
+- **`npm test`** сначала создаёт страницы фикстур всех дизайнов рендерером на Go, а затем запускает наборы тестов: скрипты страницы, сборку, итоговый файл каждого дизайна, страницы PasarGuard и Rebecca, отрисованные настоящими Jinja2 и pongo2 (в том числе с враждебными и повреждёнными данными), содержимое релиза и установщик — его опубликованная shell-библиотека и адаптер каждой панели выполняются в настоящем `bash` на временных хостах, устроенных как официальная установка каждой панели.
- **`npm run verify`** проверяет собранную страницу по её правилам безопасности, в том числе: цельный документ, замена всех маркеров сборки, всё встроено, нет внешних ссылок, нет запрещённых конструкций, целые переводы и отсутствие невидимых символов в исходниках.
- **`npm run lint:sh`** завершается ошибкой при любой ошибке ShellCheck; `npm run lint:sh -- -S warning` показывает полный отчёт.
- **Workflow Docs** собирает сайт документации в каждом pull request, который его меняет.
@@ -247,18 +278,17 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
Направление, а не обещания:
-- **Row-Template 1.2.0** — пятнадцать дизайнов и выбор дизайна, описанные выше.
-- **PasarGuard и Rebecca** — исследование. Оболочки страниц для обеих собраны; для статуса в реальном времени нужно небольшое изменение в коде или обратный прокси (reverse proxy), и это решение отложено. См. [Совместимость](https://iitzseridev.github.io/Row-Template/compatibility/).
-- **Установка на несколько панелей** — основа установщика (интерфейс панели, движок транзакций, адаптер 3X-UI и новый формат резервных копий) готова, но пока не используется ни одной командой.
+- **Row-Template 1.3.0** — поддержка PasarGuard и Rebecca и дизайны Meter и Notebook, описанные выше.
+- **Статус в реальном времени в PasarGuard и Rebecca** — обе отдают его по суффиксу пути, а не через `?format=info`; для подключения нужно небольшое изменение в коде, и это решение отложено. См. [Совместимость](https://iitzseridev.github.io/Row-Template/compatibility/).
- **Собственные шаблоны** — предложение о добавлении своего дизайна: [`docs/design/CUSTOM-TEMPLATES-PROPOSAL.md`](docs/design/CUSTOM-TEMPLATES-PROPOSAL.md).
## Участие в проекте
Сообщения об ошибках, переводы и исправления документации очень приветствуются. Прочитайте [CONTRIBUTING.md](CONTRIBUTING.md), прежде чем открывать pull request, и соблюдайте [Кодекс поведения](CODE_OF_CONDUCT.md).
-**Сообщения об ошибках:** создайте issue на . Укажите версию Row-Template (`row-template version`), версию 3X-UI, операционную систему и её версию, архитектуру процессора, вывод `row-template verify` и чёткие шаги для воспроизведения.
+**Сообщения об ошибках:** создайте issue на . Укажите версию Row-Template (`row-template version`), вашу панель и её версию, операционную систему и её версию, архитектуру процессора, вывод `row-template verify` и чёткие шаги для воспроизведения.
-> **Не указывайте секретные данные.** Никогда не вставляйте URL подписок, значения `subId`, UUID клиентов, имена пользователей и пароли панели, cookie, токены, панельный `webBasePath`, ключи TLS или реальные адреса серверов. Скрывайте конфиденциальные данные в логах перед тем, как ими делиться.
+> **Не указывайте секретные данные.** Никогда не вставляйте URL подписок, значения `subId`, UUID клиентов, имена пользователей и пароли панели, cookie, токены, панельный `webBasePath`, содержимое `.env`, URL баз данных, ключи TLS или реальные адреса серверов. Скрывайте конфиденциальные данные в логах перед тем, как ими делиться.
## Безопасность
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 5506851..865597d 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -6,7 +6,7 @@
- 为 3X-UI 面板打造的精致、自包含的订阅页面 —— 十五种设计,每种都是一个 HTML 文件,完全白标(white-label),订阅者打开的页面不会向任何第三方发出请求。
+ 为 3X-UI、PasarGuard 和 Rebecca 面板打造的精致、自包含的订阅页面 —— 十七种设计,每种都是一个 HTML 文件,完全白标(white-label),订阅者打开的页面不会向任何第三方发出请求。
@@ -16,7 +16,7 @@
-
+
@@ -33,21 +33,21 @@
## 这是什么
-3X-UI 可以向订阅者展示自定义页面来代替内置页面。Row-Template 就是这样一个页面:订阅者打开订阅链接,就能看到自己的套餐、用量和到期日期,以及一键把订阅添加到所用应用的方式。
+3X-UI、PasarGuard 和 Rebecca 都可以向订阅者展示自定义页面来代替内置页面。Row-Template 就是这样一个页面:订阅者打开订阅链接,就能看到自己的套餐、用量和到期日期,以及一键把订阅添加到所用应用的方式。
-每种设计都以一个自包含的 HTML 文件提供,所有样式、脚本、字体和二维码生成器都已内联其中。一条命令即可把它安装到面板旁边、让面板指向它,并为你提供 `row-template` 管理器,用于品牌设置、更新和回滚。
+每种设计都以一个自包含的 HTML 文件提供,所有样式、脚本、字体和二维码生成器都已内联其中,并为每个面板提供一个使用该面板自身模板语言的版本。一条命令即可检测你的面板、把页面安装到面板旁边、让面板指向它,并为你提供 `row-template` 管理器,用于品牌设置、更新和回滚。
## 为什么选择 Row-Template?
- **隐私优先。** 订阅者打开的页面不会向任何第三方发出请求。二维码在页面内生成,你的品牌信息以文本形式注入 —— 从不执行,也从不发送到任何地方。
- **真正的白标。** 你的服务名称、你的支持链接、你的徽标。所呈现的页面上没有任何内容标明 Row-Template。
-- **十五种设计,每种一个文件。** 选择适合你服务的外观。所有设计共享相同的功能、语言和安全检查。
+- **十七种设计,每种一个文件。** 选择适合你服务的外观。所有设计在每个受支持的面板上都共享相同的功能、语言和安全检查。
- **为你的订阅者而设计。** 实时显示用量和到期时间,一键导入常用应用,以及可搜索的单独配置列表,便于手动添加单个服务器。
-- **运维安全。** 经校验和验证的发布、原子化激活以及一条命令即可回滚。它从不修补 3X-UI:它唯一会修改的面板设置是订阅页面目录(`subThemeDir`)。
+- **运维安全。** 经校验和验证的发布、任何一步失败都会把面板精确恢复原状的事务式激活,以及一条命令即可回滚。它从不修补你的面板:在 3X-UI 上只修改一项设置(`subThemeDir`),在 PasarGuard 上向 `.env` 追加一个带标记的块,在 Rebecca 上设置订阅设置中的两个字段。
## 设计
-Row-Template 1.2.0 提供十五种设计,默认设计为 Row。
+Row-Template 1.3.0 提供十七种设计,默认设计为 Row。
@@ -71,6 +71,10 @@ Row-Template 1.2.0 提供十五种设计,默认设计为 Row。
 Terminal Nova |
 Arcade Nova |
+
+  Meter |
+  Notebook |
+
预览图使用项目自带的示例数据渲染。每种设计的桌面端和移动端预览见模板画廊。
@@ -81,7 +85,7 @@ Row-Template 1.2.0 提供十五种设计,默认设计为 Row。
**面向你的订阅者**
-- **实时状态。** 套餐状态、已用和剩余流量以及到期时间,在页面可见期间从你的面板刷新。
+- **实时状态。** 套餐状态、已用和剩余流量以及到期时间,在页面可见期间从你的面板刷新(3X-UI;在 PasarGuard 和 Rebecca 上,页面显示打开时的数值)。
- **一键导入**常用应用,按平台分组:Android 上的 v2rayNG、Happ 和 sing-box;iOS 上的 Streisand、V2Box 和 Shadowrocket;Windows 上的 Clash Verge Rev、Mihomo Party 和 v2rayN;macOS 上的 Clash Verge Rev、Streisand 和 V2Box。
- **复制与二维码。** 复制订阅链接,或扫描在页面内生成的二维码。
- **配置浏览器。** 每个服务器单独一行,带有国家旗帜或首字母徽章(monogram)以及协议标签(VLESS、VMess、Trojan、Shadowsocks、Hysteria/Hysteria2、WireGuard、AmneziaWG、Telegram MTProto),每个配置都可查看二维码和复制,长列表支持搜索。
@@ -98,17 +102,17 @@ Row-Template 1.2.0 提供十五种设计,默认设计为 Row。
- 所呈现的页面**不向第三方发出任何请求**:没有 CDN,没有外部二维码或地理定位服务,没有遥测。实时状态来自你自己的面板。
- 每次下载发布版本都**强制进行 SHA-256 校验**,且没有跳过的选项。
- **原子化激活。** 新页面在替换当前页面之前先生成并通过验证,因此失败的步骤绝不会让损坏的页面上线。
-- **谨慎的面板检测。** 如果 Row-Template 找到的面板数据库不是有效的 SQLite 数据库,它会拒绝使用,而不是去猜测另一个数据库。
+- **谨慎的面板检测。** 只有在多个独立迹象一致时才认为面板已安装;只安装了一半的面板,或不是有效 SQLite 数据库的面板数据库,都会被拒绝,而不是去猜测。
## 支持的面板
| 面板 | 状态 | 说明 |
| ----- | ------ | ----- |
| [3X-UI](https://github.com/MHSanaei/3x-ui) (MHSanaei) | ✅ 已支持 | 需要 **>= 3.6.0** 版本 |
-| [PasarGuard](https://github.com/PasarGuard/panel) | 🔬 研究中 | 不受支持;没有安装途径 |
-| [Rebecca](https://github.com/rebeccapanel/Rebecca) | 🔬 研究中 | 不受支持;没有安装途径 |
+| [PasarGuard](https://github.com/PasarGuard/panel) | ✅ 自 1.3.0 起支持 | 官方 Docker 安装或源码安装(`pasarguard.service`) |
+| [Rebecca](https://github.com/rebeccapanel/Rebecca) | ✅ 自 1.3.0 起支持 | Rebecca **1.x**,即 Go 版本(Rebecca 的二进制安装)。使用 SQLite 和 `sqlite3` 时自动激活;使用 MySQL/MariaDB 时需在控制台中填写一项设置。Docker 镜像仍是 0.0.x,会被拒绝 |
-3X-UI 是唯一受支持的面板。PasarGuard 和 Rebecca 使用不同的模板引擎(Jinja2 和 pongo2);每种设计都会为它们构建页面外壳并打包进发布版本以供研究,但安装程序不会部署它,也没有针对它们的安装说明。研究结果见[兼容性](https://iitzseridev.github.io/Row-Template/compatibility/)。
+三个面板使用三种不同的模板引擎 —— Go `html/template`、Jinja2 和 pongo2 —— 因此每种设计都会为每个面板分别构建,并用该面板真实的引擎渲染来测试每个版本。安装程序会检测服务器上是哪一个面板;如果有多个,它会询问你(或读取 `RT_PANEL`)。**支持**意味着该面板具备全部七项能力 —— 检测、安装、激活、校验、备份、还原和卸载 —— 并且每一项都由测试套件覆盖。各面板的详细信息见[兼容性](https://iitzseridev.github.io/Row-Template/compatibility/)。
## 架构
@@ -116,14 +120,14 @@ Row-Template 1.2.0 提供十五种设计,默认设计为 Row。
flowchart TB
subgraph build ["Build and release"]
direction LR
- SRC["src/
runtime, styles, locales,
15 design layouts"] --> BUILD["tools/build.mjs"]
- BUILD --> ART["One self-contained
HTML file per design"]
+ SRC["src/
runtime, styles, locales,
17 design layouts"] --> BUILD["tools/build.mjs"]
+ BUILD --> ART["One self-contained
HTML file per design,
per panel"]
ART --> REL["tools/make-release.sh
tarball + SHA256SUMS"]
end
- subgraph host ["Your 3X-UI server"]
+ subgraph host ["Your panel server"]
direction LR
- INST["install.sh / row-template
verify checksum, stage, validate,
back up, activate"] --> DIR["/etc/3x-ui/
sub_templates/row-template"]
- DIR -- "subThemeDir" --> XUI["3X-UI renders the page
with the subscriber's data"]
+ INST["install.sh / row-template
verify checksum, detect panel,
back up, activate, verify"] --> DIR["3X-UI: subThemeDir
PasarGuard: .env block
Rebecca: subscription settings"]
+ DIR --> XUI["The panel renders the page
with the subscriber's data"]
end
build -- "GitHub Releases" --> host
host -- "serves the page" --> BROWSER["Subscriber's browser"]
@@ -131,15 +135,15 @@ flowchart TB
```
- **每种设计一个文件。** `tools/build.mjs` 将共享的运行时代码、翻译、字体和二维码生成器内联到设计的布局中,并拒绝缺少任何运行时所需钩子(hook)的布局。随后 `tools/verify.mjs` 会拒绝任何加载远程资源或包含禁用结构的文件。
-- **由面板负责渲染。** 页面是一个模板:3X-UI 在提供页面时填入订阅者的数据,之后页面再从同一面板刷新状态。
-- **安装程序从不修改 3X-UI。** 它只写入自己的目录,并修改一项面板设置 `subThemeDir`,使其指向该目录。
+- **由面板负责渲染。** 页面是一个模板:面板在提供页面时填入订阅者的数据。对于 PasarGuard(Jinja2)和 Rebecca(pongo2),每种设计都包在一段小的前导代码中,它把面板自身的数据映射到页面字段并对每个值进行转义。
+- **安装程序从不修补你的面板。** 在 3X-UI 上,它让 `subThemeDir` 指向自己的目录;在 PasarGuard 上,它把页面放入模板目录,并向 `.env` 追加一个带标记的块;在 Rebecca 上,它放置页面并设置订阅设置中的页面和目录字段。每次修改前都会先做快照,任何一步失败都会精确恢复。
| 路径 | 内容 |
| ---- | ---------------- |
| `src/` | 页面的运行时代码、样式和翻译;每种设计位于 `src/templates//` |
| `template/index.html` | 构建好的 Row 页面,已提交到仓库 |
| `tools/` | 构建、验证、发布以及 Go 编写的 fixture 渲染器 |
-| `installer/` | `install.sh`、`row-template` 命令及其管理库 |
+| `installer/` | `install.sh`、`row-template` 命令、其管理库,以及 `installer/panels/` 中每个面板各一个的适配器 |
| `tests/` | 测试套件 |
| `docs/` | 文档站点;设计记录位于 [`docs/design/`](docs/design/README.md) |
@@ -147,9 +151,9 @@ flowchart TB
> **推荐操作系统:Ubuntu 24.04 LTS (x86_64)。** 其他较新的 Linux 发行版或许也能运行,但未经过同等程度的验证覆盖。
-**环境要求:** 运行 3X-UI **>= 3.6.0** 的服务器、该服务器的 root 权限,以及 `curl`、`tar` 和 `sha256sum`(几乎所有 Linux 系统都自带)。自动激活还需要 `sqlite3`。
+**环境要求:** 运行 3X-UI **>= 3.6.0**、PasarGuard 或 Rebecca **1.x** 的服务器;该服务器的 root 权限;以及 `curl`、`tar` 和 `sha256sum`(几乎所有 Linux 系统都自带)。在 3X-UI 和 Rebecca 上自动激活还需要 `sqlite3`。
-在托管 3X-UI 面板的服务器上以 **root** 身份运行:
+在托管你的面板的服务器上以 **root** 身份运行:
```bash
bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
@@ -159,7 +163,7 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
1. 从 GitHub 下载最新的稳定版本。
2. 校验其 SHA-256 校验和(强制 —— 无法绕过)。
-3. 安全地解压并安装到 `/etc/3x-ui/sub_templates/row-template`。
+3. 检测你的面板,安全地解压发布包并安装到 `/etc/3x-ui/sub_templates/row-template`(3X-UI)或 `/etc/row-template`(PasarGuard、Rebecca)。
4. 全新安装时显示设计选择器(按 Enter 保留 Row)。
5. 提示你设置品牌信息(服务名称、支持链接、徽标 —— 均为可选)。
6. 生成并验证页面,然后在可能的情况下在面板中激活它。
@@ -170,6 +174,12 @@ bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/d
RT_TEMPLATE=editorial bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
```
+在运行多个受支持面板的服务器上,安装程序会询问要为哪一个提供页面;在脚本中,可用 `RT_PANEL`(`3xui`、`pasarguard` 或 `rebecca`)指定:
+
+```bash
+RT_PANEL=pasarguard bash <(curl -fsSL https://github.com/iitzSeriZdev/Row-Template/releases/latest/download/install.sh)
+```
+
如果你不希望直接从网络通过管道执行,可以从 [Releases 页面](https://github.com/iitzSeriZdev/Row-Template/releases/latest)将四个发布文件(`install.sh`、`manifest.txt`、`SHA256SUMS` 和 `row-template-.tar.gz`)下载到同一个文件夹,按照 [PROVENANCE.md](PROVENANCE.md) 中的说明自行校验校验和,然后让安装程序使用该文件夹:
```bash
@@ -178,19 +188,39 @@ RT_RELEASE_DIR=/root/row-template-release bash /root/row-template-release/instal
### 激活
-Row-Template 安装在一个由面板作为订阅页面提供的目录中:
+交互式安装会先说明激活将修改什么,并征求你的同意。在 PasarGuard 和 Rebecca 上,激活以事务方式进行:先为面板状态做快照,再应用并验证修改;任何一步失败,面板都会被精确恢复。
+
+**3X-UI。** Row-Template 安装在一个由面板作为订阅页面提供的目录中:
```
/etc/3x-ui/sub_templates/row-template
```
-- **自动:** 当 `sqlite3` 可用时,Row-Template 会替你完成设置。它会短暂停止面板服务、写入设置、重新启动服务并核对该值。交互式安装会先显示当前设置并征求你的同意。
+- **自动:** 当 `sqlite3` 可用时,Row-Template 会替你完成设置。它会短暂停止面板服务、写入设置、重新启动服务并核对该值。
- **手动:** 否则,请打开 **Panel Settings → Subscription → Profile → Sub Theme Directory** 并准确输入:
```
/etc/3x-ui/sub_templates/row-template
```
+**PasarGuard。** 页面放在 `/var/lib/pasarguard/templates/row-template/index.html`(如果你设置了自己的 `CUSTOM_TEMPLATES_DIRECTORY`,则放在其中),并向 `/opt/pasarguard/.env` 追加一个带标记的块:
+
+```
+# >>> row-template (managed by Row-Template; do not edit) nl=0 >>>
+CUSTOM_TEMPLATES_DIRECTORY = "/var/lib/pasarguard/templates"
+SUBSCRIPTION_PAGE_TEMPLATE = "row-template/index.html"
+# <<< row-template <<<
+```
+
+PasarGuard 在启动时读取 `.env`,因此正在运行的面板会重启一次。你自己的任何一行都不会被修改;卸载会删除该块,并把 `.env` 精确恢复为之前的字节。拥有自己订阅模板的管理员,或 **disable subscription template** 设置,仍然优先 —— 如果其中之一生效,`row-template verify` 会告诉你。
+
+Row-Template 支持 Rebecca **1.x**,即 Rebecca 为其二进制安装(`rebecca-binary.sh`)发布的 Go 版本。Docker Hub 上的 `rebeccapanel/rebecca` 镜像仍是 0.0.x 的 Python 版本,无法渲染此页面;安装程序会拒绝它且不做任何更改,而 Rebecca 自带的 `rebecca migrate-binary` 可以把 Docker 安装迁移到 1.x。
+
+**Rebecca。** 页面放在 `/var/lib/rebecca/templates/row-template/index.html`(或你自己的自定义模板目录中),并把 Rebecca 的订阅设置设为 `row-template/index.html`。Rebecca 在每次请求时读取这些设置,因此无需重启。
+
+- **自动:** 使用默认的 SQLite 数据库并已安装 `sqlite3` 时。
+- **手动:** 使用 MySQL/MariaDB(或没有 `sqlite3`)时:页面仍会放好;在 Rebecca 控制台中打开 **Settings → Subscription → Templates**,把 **Subscription page template** 设为 `row-template/index.html`,把 **Custom templates directory** 设为 `/var/lib/rebecca/templates`。
+
## 使用
在终端中不带参数运行管理器以打开交互式菜单:
@@ -206,23 +236,24 @@ row-template
| `row-template config` | 更改服务名称、支持链接或徽标,然后重新生成页面 |
| `row-template update` | 下载、校验并激活最新的稳定版本(强制校验校验和) |
| `row-template rollback` | 恢复到之前的版本(`--auto` 或 `--to `) |
-| `row-template verify` | 检查安装、面板连接和当前页面(只读) |
-| `row-template version` | 显示已安装版本、最低支持版本以及检测到的 3X-UI 版本 |
-| `row-template uninstall` | 移除 Row-Template 并让面板恢复其内置页面 |
+| `row-template verify` | 检查安装、面板连接和当前页面(以 root 运行时还会补回缺失或放错位置的设计) |
+| `row-template version` | 显示已安装版本及其服务的面板(在 3X-UI 上还显示最低支持版本和检测到的版本) |
+| `row-template uninstall` | 移除 Row-Template 并让面板恢复之前使用的页面 |
| `row-template help` | 显示用法 |
会修改系统的命令(`config`、`update`、`rollback`、`uninstall`)必须以 root 身份运行。
- **品牌信息**以数据形式存储,从不执行,并以文本形式注入页面。将某个字段留空即可得到无品牌的页面。支持链接只接受浏览器应当打开的协议,例如 `https://…`、`tg://…` 或 `mailto:…`。
- **更新**来自公共稳定通道。`row-template update` 总是应用最新的稳定版本,即使你已安装的就是该版本;管理器中的 **Update** 会先比较版本,并在做出任何更改前询问。如果无法访问发布源,则不会做任何更改,你的安装也绝不会因此被视为已损坏。
-- **回滚**会从经过验证的备份中恢复之前的版本。系统会先为当前版本创建快照(snapshot),因此失败的回滚也可以恢复,且你的品牌配置会被保留。
-- **卸载**会移除 Row-Template 的文件。只有当面板的 `subThemeDir` 指向 Row-Template 时才会将其清除,使面板恢复内置页面;你的入站(inbound)、客户端和证书都不会受到影响。
+- **从 1.1.0 或 1.2.x 更新**只需运行一次 `row-template update`。1.1.0 自带的更新程序只会复制新版本的一部分,因此下一次以 root 运行 `row-template`、`row-template config` 或 `row-template verify` 时,会先下载同一版本的其余部分——所有设计,并校验 checksum。你的设计、品牌配置和面板连接都会保留。
+- **回滚**会从经过验证的备份中恢复之前的版本。系统会先为当前版本创建快照(snapshot),因此失败的回滚也可以恢复,且你的品牌配置会被保留。备份会记录其所在的面板,绝不会恢复到另一个面板上;来自旧版本、未记录设计名称的备份会按 Row 恢复。
+- **卸载**会移除 Row-Template 的文件,并让面板恢复之前使用的页面:在 3X-UI 上,只有当 `subThemeDir` 指向 Row-Template 时才会将其清除;在 PasarGuard 上,删除它在 `.env` 中的块和它的页面;在 Rebecca 上,恢复它修改过的两项订阅设置(如果你此后已选择了其他页面,则不做改动)。你的用户、入站(inbound)、客户端、节点和证书都不会受到影响。
[文档](https://iitzseridev.github.io/Row-Template/)更详细地介绍了配置、品牌设置和故障排查。
## 开发
-页面由 `src/` 中可读的源代码构建而成。你需要 Node.js 22 或更高版本,运行测试还需要 Go 1.22 或更高版本。
+页面由 `src/` 中可读的源代码构建而成。你需要 Node.js 22 或更高版本;运行测试还需要 Go 1.22 或更高版本,以及带 Jinja2 的 Python 3(`pip install jinja2`),它们用这两个面板真实的引擎渲染 PasarGuard 和 Rebecca 页面。
```bash
npm run build # regenerate template/index.html from src/
@@ -237,7 +268,7 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
## 测试
-- **`npm test`** 先用 Go 渲染器生成所有设计的 fixture 页面,然后运行各测试套件:页面脚本、构建、每种设计的最终文件、发布包内容以及安装程序 —— 其发布的 shell 库会在真实的 `bash` 中针对临时 fixture 运行。
+- **`npm test`** 先用 Go 渲染器生成所有设计的 fixture 页面,然后运行各测试套件:页面脚本、构建、每种设计的最终文件、由真实 Jinja2 和 pongo2 渲染的 PasarGuard 和 Rebecca 页面(包括恶意和畸形数据)、发布包内容以及安装程序 —— 其发布的 shell 库和每个面板的适配器会在真实的 `bash` 中,针对按各面板官方安装方式布置的临时主机运行。
- **`npm run verify`** 按照安全关卡检查构建好的页面,包括:完整的文档、所有构建标记均已替换、所有内容均已内联、没有远程引用、没有禁用结构、翻译完整,以及源代码中没有不可见字符。
- **`npm run lint:sh`** 遇到任何 ShellCheck 错误即失败;`npm run lint:sh -- -S warning` 会显示完整报告。
- **Docs 工作流**会在每个修改文档站点的 pull request 中构建该站点。
@@ -246,18 +277,17 @@ npm run preview # preview the fixture pages at http://127.0.0.1:8787
这是方向,而非承诺:
-- **Row-Template 1.2.0** —— 上文介绍的十五种设计和设计选择器。
-- **PasarGuard 和 Rebecca** —— 研究中。两者的页面外壳均已构建;实时状态需要对运行时代码做一处小改动或使用反向代理(reverse proxy),这一决定已推迟。参见[兼容性](https://iitzseridev.github.io/Row-Template/compatibility/)。
-- **在多个面板上安装** —— 安装程序的基础设施(面板接口、事务引擎、3X-UI 适配器和新的备份格式)已经就绪,但尚未被任何命令使用。
+- **Row-Template 1.3.0** —— 上文介绍的 PasarGuard 和 Rebecca 支持,以及 Meter 和 Notebook 设计。
+- **PasarGuard 和 Rebecca 上的实时状态** —— 两者都通过路径后缀而不是 `?format=info` 提供它;接入需要对运行时代码做一处小改动,这一决定已推迟。参见[兼容性](https://iitzseridev.github.io/Row-Template/compatibility/)。
- **自定义模板** —— 关于添加你自己设计的提案:[`docs/design/CUSTOM-TEMPLATES-PROPOSAL.md`](docs/design/CUSTOM-TEMPLATES-PROPOSAL.md)。
## 参与贡献
非常欢迎问题反馈、翻译和文档修正。在提交 pull request 之前请阅读 [CONTRIBUTING.md](CONTRIBUTING.md),并遵守[行为准则](CODE_OF_CONDUCT.md)。
-**问题反馈:** 请在 提交 issue。请附上你的 Row-Template 版本(`row-template version`)、3X-UI 版本、操作系统及其版本、CPU 架构、`row-template verify` 的输出,以及清晰的复现步骤。
+**问题反馈:** 请在 提交 issue。请附上你的 Row-Template 版本(`row-template version`)、你的面板及其版本、操作系统及其版本、CPU 架构、`row-template verify` 的输出,以及清晰的复现步骤。
-> **请勿包含机密信息。** 切勿粘贴订阅 URL、`subId` 值、客户端 UUID、面板用户名或密码、Cookie、令牌、面板的 `webBasePath`、TLS 密钥或真实的服务器地址。分享日志前请先对其做脱敏处理。
+> **请勿包含机密信息。** 切勿粘贴订阅 URL、`subId` 值、客户端 UUID、面板用户名或密码、Cookie、令牌、面板的 `webBasePath`、`.env` 的内容、数据库 URL、TLS 密钥或真实的服务器地址。分享日志前请先对其做脱敏处理。
## 安全
diff --git a/VERSION b/VERSION
index 26aaba0..f0bb29e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.2.0
+1.3.0
diff --git a/docs/design/CUSTOM-TEMPLATE-GUIDELINES.md b/docs/design/CUSTOM-TEMPLATE-GUIDELINES.md
index b68aa61..7fcba4b 100644
--- a/docs/design/CUSTOM-TEMPLATE-GUIDELINES.md
+++ b/docs/design/CUSTOM-TEMPLATE-GUIDELINES.md
@@ -1,7 +1,7 @@
# Custom Template Guidelines
**Status:** binding contract for every future custom template.
-**Applies to:** any template added to this repository that is not one of the fifteen
+**Applies to:** any template added to this repository that is not one of the seventeen
frozen core designs.
**Companion documents:** `CUSTOM-TEMPLATES-PROPOSAL.md` (the design rationale and
phased plan), `CONTRIBUTING.md` (the general contribution process),
@@ -85,14 +85,14 @@ behaviour and defaults a custom entry to unlocked"*.
The gap between 15 and 200 is intentional: it leaves room for future core designs
without a renumbering, and makes the two tiers distinguishable at a glance.
-**Checked by:** `tests/registry.test.mjs` — *"core templates keep order 1..15 and a
+**Checked by:** `tests/registry.test.mjs` — *"core templates keep order 1..17 and a
custom template must use order >= 200"*, *"the selectable set is sorted by order…"*.
### 1.5 The frozen set
The frozen set is **core-only**. `FROZEN_ARTIFACTS` in `tests/build.test.mjs` holds
-eleven of the fifteen; `row`, `editorial`, `canvas` and `pulsenova` hold individual
-lock tests. The union is exactly the fifteen core templates.
+thirteen of the seventeen; `row`, `editorial`, `canvas` and `pulsenova` hold individual
+lock tests. The union is exactly the seventeen core templates.
> **A custom template MUST NOT appear in the frozen set.**
@@ -101,7 +101,7 @@ and the build reads only `styles` and `emitDataTemplate` off a registry entry, s
entry can add itself to the frozen set. The test that pins this fails if a
`tier: 'custom'` id ever appears there.
-**Checked by:** `tests/build.test.mjs` — *"the frozen set is exactly the fifteen core
+**Checked by:** `tests/build.test.mjs` — *"the frozen set is exactly the seventeen core
templates, and a custom template can never enter it"*.
---
@@ -109,7 +109,7 @@ templates, and a custom template can never enter it"*.
## 2. Mandatory Runtime Contract
Every custom template MUST satisfy the following. These are the same requirements
-the fifteen core templates satisfy; there is no reduced contract for custom work.
+the seventeen core templates satisfy; there is no reduced contract for custom work.
| # | requirement | how it is checked |
|---|---|---|
@@ -142,7 +142,7 @@ The artifact carries three ` can never form in
# the injected branding block). Control chars must be rejected by the caller.
# LC_ALL=C keeps sed byte-oriented; UTF-8 trail bytes (>=0x80) never collide
- # with the ASCII bytes \ " < being rewritten.
- printf '%s' "$1" | LC_ALL=C sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\\u003c/g'
+ # with the ASCII bytes \ " < { } being rewritten.
+ #
+ # '{' and '}' are escaped too ({, } -- the same string to
+ # JavaScript). The page is itself a TEMPLATE on every panel: Go's
+ # html/template on 3X-UI, Jinja2 on PasarGuard, pongo2 on Rebecca, and all of
+ # them parse the branding block along with the rest of the file. A service
+ # name such as "{{ config }}" or "{% endautoescape %}" must never become a
+ # template delimiter -- on PasarGuard's unsandboxed Jinja2 that would be code
+ # execution on the panel -- and with no brace left, none can form.
+ printf '%s' "$1" | LC_ALL=C sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/\\u003c/g' \
+ -e 's/{/\\u007b/g' -e 's/}/\\u007d/g'
+}
+
+rt_dotenv_get() {
+ # rt_dotenv_get FILE KEY [SKIP_OPEN SKIP_CLOSE]
+ #
+ # Echo KEY's value from a dotenv FILE the way dotenv readers take it
+ # (python-dotenv, Docker Compose): the LAST assignment wins; `export` and
+ # spaces around `=` are allowed; a quoted value ends at its closing quote;
+ # an unquoted one ends at ` #`. Lines between a line starting with
+ # SKIP_OPEN and a line equal to SKIP_CLOSE are ignored, when given.
+ #
+ # Read as DATA: nothing is sourced or evaluated, and nothing is printed but
+ # the one value. Exit 0 with the value (possibly empty) when KEY is assigned,
+ # 3 when it is not, 1 when FILE cannot be read.
+ local file="$1" key="$2"
+ [ -f "$file" ] && [ -r "$file" ] || return 1
+ RT_K="$key" RT_BO="${3:-}" RT_BC="${4:-}" LC_ALL=C awk '
+ BEGIN { want = ENVIRON["RT_K"]; bo = ENVIRON["RT_BO"]; bc = ENVIRON["RT_BC"]; inb = 0; found = 0 }
+ {
+ line = $0; sub(/\r$/, "", line)
+ if (bo != "" && index(line, bo) == 1) { inb = 1; next }
+ if (bc != "" && line == bc) { inb = 0; next }
+ if (inb) next
+ s = line; sub(/^[ \t]+/, "", s)
+ if (s == "" || substr(s, 1, 1) == "#") next
+ if (substr(s, 1, 7) == "export ") { s = substr(s, 8); sub(/^[ \t]+/, "", s) }
+ eq = index(s, "="); if (eq == 0) next
+ k = substr(s, 1, eq - 1); sub(/[ \t]+$/, "", k)
+ if (k != want) next
+ v = substr(s, eq + 1); sub(/^[ \t]+/, "", v)
+ q = substr(v, 1, 1)
+ if (q == "\"" || q == "\047") {
+ rest = substr(v, 2); e = index(rest, q)
+ v = (e > 0) ? substr(rest, 1, e - 1) : rest
+ } else {
+ c = index(v, " #"); if (c > 0) v = substr(v, 1, c - 1)
+ sub(/[ \t]+$/, "", v)
+ }
+ val = v; found = 1
+ }
+ END { if (found) { printf "%s", val; exit 0 } exit 3 }
+ ' "$file"
}
# --- input validation --------------------------------------------------------
@@ -237,7 +318,7 @@ rt_config_write() {
# The selectable ids of this release, in catalogue order. Row is first and is
# the default.
-RT_TEMPLATES_AVAILABLE="row editorial canvas prism terminal pulse brutal arcade sketch signature saffron pulsenova prismnova terminalnova arcadenova"
+RT_TEMPLATES_AVAILABLE="row editorial canvas prism terminal pulse brutal arcade sketch signature saffron pulsenova prismnova terminalnova arcadenova meter notebook"
rt_template_allowed() {
local id
@@ -264,6 +345,8 @@ rt_template_display_name() {
prismnova) printf 'Prism Nova' ;;
terminalnova) printf 'Terminal Nova' ;;
arcadenova) printf 'Arcade Nova' ;;
+ meter) printf 'Meter' ;;
+ notebook) printf 'Notebook' ;;
*) printf '%s' "$1" ;;
esac
}
@@ -431,26 +514,180 @@ rt_stage_template_store() {
# anything is staged. A payload without a templates/ directory (an older
# release) simply carries no store; that is the caller's signal to fall back
# to the top-level artifact.
- local payload="$1" dir id want
- [ -d "$payload/templates" ] || return 0
- for dir in "$payload"/templates/*/; do
+ #
+ # The designs come from the payload subtree of the panel this install serves
+ # (rt_payload_store): templates//template.html for 3X-UI, and
+ # shells///shell.html for PasarGuard and Rebecca. Either way they
+ # land in the store under the same name, so everything after staging is
+ # panel-agnostic. Every artifact must also fit the panel
+ # (rt_artifact_fits_panel) -- a store must never hold a page the panel
+ # cannot render safely.
+ local payload="$1" dir id want spec sub name sidecar
+ spec="$(rt_payload_store)"; sub="${spec%%|*}"; name="${spec#*|}"
+ [ -d "$payload/$sub" ] || return 0
+ for dir in "$payload/$sub"/*/; do
[ -d "$dir" ] || continue
id="$(basename "$dir")"
case "$id" in
*[!a-z0-9]*|"") rt_warn "payload template directory is not a plain id: $id (skipped)"; continue ;;
esac
- [ -f "$dir/template.html" ] || { rt_warn "payload template $id has no template.html (skipped)"; continue; }
- [ -f "$dir/template.html.sha256" ] || { rt_err "payload template $id has no checksum sidecar"; return 1; }
- want="$(LC_ALL=C awk '{print $1; exit}' "$dir/template.html.sha256")"
- rt_verify_sha256 "$dir/template.html" "$want" || { rt_err "payload template $id failed its checksum"; return 1; }
- rt_validate_template "$dir/template.html" || { rt_err "payload template $id failed structural validation"; return 1; }
+ [ -f "$dir/$name" ] || { rt_warn "payload template $id has no $name (skipped)"; continue; }
+ sidecar="$dir/$name.sha256"
+ [ -f "$sidecar" ] || { rt_err "payload template $id has no checksum sidecar"; return 1; }
+ want="$(LC_ALL=C awk '{print $1; exit}' "$sidecar")"
+ rt_verify_sha256 "$dir/$name" "$want" || { rt_err "payload template $id failed its checksum"; return 1; }
+ rt_validate_template "$dir/$name" || { rt_err "payload template $id failed structural validation"; return 1; }
+ rt_artifact_fits_panel "$dir/$name" \
+ || { rt_err "payload template $id is not a $(rt_panel_label "$(rt_panel_current)") page"; return 1; }
+ rt_assert_not_symlink "$RT_TEMPLATE_STORE/$id" || return 1
mkdir -p "$RT_TEMPLATE_STORE/$id" || return 1
- rt_atomic_install "$dir/template.html" "$RT_TEMPLATE_STORE/$id/template.html" 644 || return 1
- rt_atomic_install "$dir/template.html.sha256" "$RT_TEMPLATE_STORE/$id/template.html.sha256" 644 || return 1
+ rt_atomic_install "$dir/$name" "$RT_TEMPLATE_STORE/$id/template.html" 644 || return 1
+ rt_atomic_install "$sidecar" "$RT_TEMPLATE_STORE/$id/template.html.sha256" 644 || return 1
done
return 0
}
+# --- template store self-healing ---------------------------------------------
+# Every reader above looks in ONE place, RT_TEMPLATE_STORE. A store anywhere
+# else is invisible, and the manager then reports that no design is installed
+# while the files sit one directory away. Two states lead there on real hosts:
+#
+# ABSENT v1.1.0's updater installs this library but copies only four
+# files, so no design arrives with it (rt_complete_install).
+# MISPLACED a release payload lays its designs out at templates//; a
+# payload copied or extracted over the install root leaves them
+# at $RT_ROOT/templates, beside dist/ instead of inside it.
+#
+# rt_repair_template_store heals from what the host already has; install,
+# update and verify all run it, so a path mistake is repaired by whichever
+# command meets it first and no operator has to move a file by hand.
+
+# Where a store has been found outside its home, relative to RT_ROOT. A closed
+# list of fixed paths inside the install root, never derived from input.
+RT_TEMPLATE_STORE_MISPLACED="templates"
+
+rt_template_entry_ok() {
+ # 0 when DIR holds a design whose artifact matches its own sidecar. No
+ # symlinks: a linked directory or file could hand over bytes from outside the
+ # install root. Silent; callers report.
+ local d="$1" want
+ [ -d "$d" ] && [ ! -L "$d" ] || return 1
+ [ -f "$d/template.html" ] && [ ! -L "$d/template.html" ] || return 1
+ [ -f "$d/template.html.sha256" ] && [ ! -L "$d/template.html.sha256" ] || return 1
+ want="$(LC_ALL=C awk '{print $1; exit}' "$d/template.html.sha256" 2>/dev/null)"
+ rt_verify_sha256 "$d/template.html" "$want" >/dev/null 2>&1
+}
+
+rt_template_store_status() {
+ # echo ok | missing | corrupt for registry ID in the installed store.
+ # "missing" is a design with neither file; anything else short of a
+ # verifying pair (one file alone, a checksum mismatch, a symlink) is corrupt.
+ local id="$1" d
+ rt_template_allowed "$id" || return 1
+ d="$RT_TEMPLATE_STORE/$id"
+ if rt_template_entry_ok "$d"; then printf 'ok'; return 0; fi
+ if [ ! -e "$d/template.html" ] && [ ! -e "$d/template.html.sha256" ] && [ ! -L "$d" ]; then
+ printf 'missing'
+ else
+ printf 'corrupt'
+ fi
+}
+
+rt_template_store_missing() {
+ # echo the registry ids the store cannot supply (missing or corrupt), one per
+ # line, in catalogue order. Empty output means the store is complete.
+ local id
+ for id in $RT_TEMPLATES_AVAILABLE; do
+ [ "$(rt_template_store_status "$id")" = "ok" ] || printf '%s\n' "$id"
+ done
+ return 0
+}
+
+rt_template_store_retire() {
+ # remove a misplaced store's copy of every design the canonical store now
+ # supplies. Only the two files a design consists of are removed, only for
+ # registry ids, and only through real directories; a directory is then
+ # removed only if that left it empty. Anything else -- a foreign file, an
+ # unknown id, a copy of a design the store still lacks -- stays where it is.
+ local src="$1" id
+ for id in $RT_TEMPLATES_AVAILABLE; do
+ [ -d "$src/$id" ] && [ ! -L "$src/$id" ] || continue
+ [ "$(rt_template_store_status "$id")" = "ok" ] || continue
+ rm -f -- "$src/$id/template.html" "$src/$id/template.html.sha256"
+ rmdir -- "$src/$id" 2>/dev/null || true
+ done
+ rmdir -- "$src" 2>/dev/null || true
+}
+
+rt_repair_template_store() {
+ # Make RT_TEMPLATE_STORE hold a verified copy of every design this release
+ # offers, from the sources on hand, in order of authority:
+ #
+ # 1. PAYLOAD's templates/, when given: a release that already passed its
+ # checksum. rt_stage_template_store verifies and installs every design.
+ # 2. a misplaced store inside the install root: a design the store cannot
+ # supply is taken from it only when that copy matches its own checksum
+ # and passes the structural gate; a copy that does not is reported and
+ # left in place.
+ #
+ # A misplaced copy is retired once the store covers its design, so the tree
+ # is left with one store, not two. Backups, config.env, the canonical
+ # artifact and the live page are never touched: this only fills the store.
+ #
+ # Returns 0 when the store is complete, 2 when designs are still missing (the
+ # caller decides whether that matters: an older payload carries no store at
+ # all), and 1 when the payload fails verification or a write fails.
+ local payload="${1:-}" rel src id moved warned
+ if [ -L "$RT_TEMPLATE_STORE" ] || [ -L "$(dirname "$RT_TEMPLATE_STORE")" ]; then
+ rt_err "the template store path is a symlink; refusing to repair it: $RT_TEMPLATE_STORE"
+ return 1
+ fi
+ if [ -e "$RT_TEMPLATE_STORE" ] && [ ! -d "$RT_TEMPLATE_STORE" ]; then
+ rt_err "the template store path is not a directory: $RT_TEMPLATE_STORE"
+ return 1
+ fi
+
+ if [ -n "$payload" ]; then
+ rt_stage_template_store "$payload" || return 1
+ fi
+
+ for rel in $RT_TEMPLATE_STORE_MISPLACED; do
+ src="$RT_ROOT/$rel"
+ [ -e "$src" ] || [ -L "$src" ] || continue
+ if [ -L "$src" ] || [ ! -d "$src" ]; then
+ rt_warn "not reading templates from $src: it is not a plain directory."
+ continue
+ fi
+ moved=0; warned=0
+ for id in $RT_TEMPLATES_AVAILABLE; do
+ [ -e "$src/$id" ] || [ -L "$src/$id" ] || continue
+ [ "$(rt_template_store_status "$id")" = "ok" ] && continue
+ if ! rt_template_entry_ok "$src/$id" \
+ || ! rt_validate_template "$src/$id/template.html" >/dev/null 2>&1 \
+ || ! rt_artifact_fits_panel "$src/$id/template.html"; then
+ rt_warn "the copy of design '$id' in $src fails its checksum or structural check; it was not moved."
+ warned=1
+ continue
+ fi
+ rt_assert_not_symlink "$RT_TEMPLATE_STORE/$id" || return 1
+ mkdir -p "$RT_TEMPLATE_STORE/$id" || return 1
+ rt_atomic_install "$src/$id/template.html" "$RT_TEMPLATE_STORE/$id/template.html" 644 || return 1
+ rt_atomic_install "$src/$id/template.html.sha256" "$RT_TEMPLATE_STORE/$id/template.html.sha256" 644 || return 1
+ moved=$((moved + 1))
+ done
+ rt_template_store_retire "$src"
+ if [ "$moved" -gt 0 ]; then
+ rt_ok "Template store: moved $moved design(s) from $src to $RT_TEMPLATE_STORE."
+ fi
+ if [ -e "$src" ] && [ "$warned" -eq 0 ]; then
+ rt_warn "left $src in place: it holds files Row-Template does not recognise."
+ fi
+ done
+
+ [ -z "$(rt_template_store_missing)" ] && return 0
+ return 2
+}
+
rt_switch_template() {
# switch the active template as one transaction. Ordered so that nothing on
# disk changes until the candidate has passed every check, and so that any
@@ -624,9 +861,17 @@ rt_validate_template() {
size="$(rt_file_size "$f")" || { rt_err "cannot size generated template"; return 1; }
[ "$size" -ge $((40 * 1024)) ] \
|| { rt_err "generated template implausibly small (${size} bytes)"; return 1; }
- LC_ALL=C head -c 512 "$f" | LC_ALL=C grep -qi '' \
+ # No `head | grep -q` here. Under pipefail, grep -q exits on its first match,
+ # head can die of SIGPIPE writing the rest, and pipefail reports the match as
+ # a failure: measured on a loaded Linux host (1.3.0) at ~0.7% of calls, which
+ # made install, update and design switching refuse a perfectly valid page.
+ # tr reads its whole input, so nothing in these pipelines can be cut short.
+ local lead trail
+ lead="$(LC_ALL=C head -c 512 "$f" 2>/dev/null | LC_ALL=C tr -d '\000' | LC_ALL=C tr '[:upper:]' '[:lower:]')"
+ [[ "$lead" == *''* ]] \
|| { rt_err "generated template does not begin with "; return 1; }
- LC_ALL=C tail -c 64 "$f" | LC_ALL=C grep -q '