Extensions
/
ManageMyVpn
Manage My VPN 2.3.0
Adds account controls to the VPN shop: pause and resume, revoke the credentials, move an account to another server in the same plan group, and keep a note on it. Customers act on their own accounts from /myvpn; admins on any account by its code.
You are looking at 2.3.0. The current release is 2.6.0.
Install
Install it
php bin/console ext:install ManageMyVpn --version=2.3.0
Update it later
php bin/console ext:update ManageMyVpn
Remove it
php bin/console ext:remove ManageMyVpn
Add --dry-run to any of these to see exactly which files
would change before anything is written.
Readme
Manage My VPN
Adds the controls to an account that the shop deliberately leaves out:
pause and resume, revoke, change location, and a note.
Customers reach them from /myvpn; admins reach the same screens for any
account by searching its code in /admin → فروش VPN → *🔎 جستجوی سرویس با
کد*. Every screen is in Persian.
Requires the VPN Shop
This extension is an addition to [Vpn](../Vpn/README.md) 2.3.0 or newer,
and says so in its extension.json:
```json
"requires": { "extensions": { "Vpn": ">=2.3.0" } }
```
Core enforces that: ext:install and ext:enable refuse while the shop is
missing, disabled, or older, and refuse to disable or remove the shop while
this is enabled (--force overrides). If the shop's files disappear anyway,
this extension contributes nothing rather than crashing the bot.
It adds no tables to the shop and no commands of its own. The one button it
adds to /myvpn arrives through the shop's AccountAddon hook, so nothing
in the shop mentions this extension by name.
Install
```bash
php bin/console ext:install ManageMyVpn
```
Nothing to configure — every control is on by default. What it does add is
a ⚙️ مدیریت سرویس button under each account.
What each control does
⏸ خاموش / ▶️ روشن — pauses the account on the panel and leaves
everything else alone: expiry keeps running, usage is kept, the link stays
valid. 3x-ui gets its client's enable flag flipped; PasarGuard gets
status: disabled. An expired or drained account cannot be resumed —
renewing is the answer, and it says so.
🔑 ابطال — rotates what the account connects with, so anybody holding
the old configs loses access. On 3x-ui both the client id and the
subscription id change, because rotating only the uuid leaves a shared
subscription link handing out the new one. On PasarGuard it is one
revoke_sub call. The new link and QR are sent to the owner immediately;
the old ones stop working the moment the panel answers.
🌍 تغییر لوکیشن — moves the account to another server. Offered only for
servers that
- sell the same plan group — that is what makes the plan mean the same
thing on the other side, and it is the rule the shop already uses to
decide what a server sells;
- are enabled; and
- have capacity left, counted the same way the shop counts it when
selling — both limits: the service count, and the traffic allowance,
which the account's own allowance lands on when it arrives. A server
with free slots can still be too full on traffic to take it.
The remaining days and the remaining traffic move with the account: the
expiry date does not change, and the new account is created with what was
left rather than the plan's full allowance, because usage starts at zero on
the new panel. An account that has run out of traffic or time cannot be
moved — it would arrive unlimited or expired — so renewal comes first.
The order is create → switch the row over → delete the old one. If the new
panel refuses, nothing has changed. If the old panel refuses the delete,
the customer is fine and an admin is told that a leftover account needs
removing by hand.
📝 یادداشت — one line kept on the account, shown to both the customer
and any admin looking it up. HTML is stripped when it is stored, not
escaped when it is shown.
Who may do what
| | Customer | Admin |
| --- | --- | --- |
| Their own account | yes, subject to the allow_* settings and the cooldowns | — |
| Anyone else's account | never | yes, ignoring allow_* and the cooldowns |
Ownership is re-checked on every press rather than trusted because a
button was drawn: an account code is eight characters, and a message can be
forwarded. An account that is not yours and one that does not exist give the
same answer, so a guess cannot tell the difference.
An admin acting on their own account is treated as a customer — same screen,
same rules — which is also how the settings below can be tried out without a
second account.
Whenever an admin changes somebody's account, the owner is told (see
notify_owner), and for a revoke or a move they are sent the new link and
QR straight away rather than left to discover it.
When something fails
A refusal — a panel that says no, a cooldown, an expired account — arrives
as a Telegram alert: a popup that has to be dismissed, not a toast that
fades on its own. The same sentence is also left on the account's screen,
because an alert is gone the moment it is tapped away and the customer
still needs to know what happened.
That means the button keeps spinning while the panel is being talked to:
Telegram accepts one answer per press, so answering early to stop the
spinner would spend the only chance to say why something failed.
Panel refusals are logged as well as shown. The customer's screen is the
wrong place for an operator to learn that their panel is misconfigured.
Settings
```bash
php bin/console ext:settings ManageMyVpn
php bin/console ext:set ManageMyVpn allow_move false
```
| Key | Default | Meaning |
| --- | --- | --- |
| allow_toggle | true | Customers may pause and resume |
| allow_revoke | true | Customers may revoke |
| allow_move | true | Customers may change location |
| allow_note | true | Customers may set a note |
| move_cooldown_hours | 24 | Wait between a customer's moves; 0 is no wait |
| revoke_cooldown_hours | 1 | Wait between a customer's revokes; 0 is no wait |
| note_max_length | 120 | Characters |
| notify_owner | true | Tell the owner when an admin changes their account |
| history_lines | 5 | How much history the admin screen shows; 0 hides it |
The four allow_* switches apply to customers only. Turning all four off
leaves the account screen exactly as the shop draws it — the button is not
shown to a customer with nothing behind it — while admins keep everything.
The cooldowns exist for the panels' sake: a revoke and a move are both
writes to somebody else's server. They are counted from that customer's own
last action, so an admin fixing something for them does not start their
clock.
Tables
managemyvpn_notes — one note per account.
managemyvpn_events — what was done, when, by whom, and whether that was an
admin. It is the history on the admin screen and the clock the cooldowns are
read from, so it is not optional bookkeeping.
ext:remove ManageMyVpn drops both. Accounts are left exactly as they are:
one that was paused stays paused, one that was moved stays where it went.
Removing the controls is not a decision to undo what was done with them.
Known limits
- A paused account still occupies its server's capacity in the shop's
count, and it is meant to: it still exists on the panel. What frees a
slot is deleting the account, which nothing here does.
- Moving an account does not charge for it and does not touch the plan.
The account keeps the plan it was renewed onto, which is valid on the new
server because both sell the same group.
- The location change is create-then-delete, not a panel-to-panel
migration: usage counters start again at zero on the new server, which is
why the new limit is what was left rather than the whole plan.
- The 3x-ui revoke needs the client id the shop stored when the account was
sold. An account created outside the bot, or restored from a backup taken
before that column existed, cannot be revoked and says so.
Releases
| Version | Published | Size | Files |
|---|---|---|---|
| 2.6.0 current | 2 Oct 2026 | 37.8 KB | 20 |
| 2.5.0 | 23 Sep 2026 | 37.5 KB | 20 |
| 2.4.1 | 20 Sep 2026 | 36.8 KB | 20 |
| 2.4.0 | 20 Sep 2026 | 36.2 KB | 20 |
| 2.3.0 | 20 Sep 2026 | 35.6 KB | 20 |
| 2.2.0 | 15 Sep 2026 | 35.3 KB | 20 |
| 2.1.0 | 14 Sep 2026 | 35.4 KB | 20 |
| 2.0.0 | 14 Sep 2026 | 35.4 KB | 20 |
| 1.3.0 | 14 Sep 2026 | 34.6 KB | 20 |
| 1.2.0 | 14 Sep 2026 | 34.7 KB | 20 |
| 1.1.0 | 13 Sep 2026 | 34.6 KB | 20 |
| 1.0.0 | 10 Sep 2026 | 34.6 KB | 20 |