├── app ├── dashboard │ ├── example.env │ ├── .prettierrc.json │ ├── src │ │ ├── types │ │ │ ├── ProxyHosts.ts │ │ │ └── User.ts │ │ ├── vite-env.d.ts │ │ ├── constants │ │ │ ├── Project.ts │ │ │ ├── ProxyHosts.tsx │ │ │ └── UserSettings.tsx │ │ ├── utils │ │ │ ├── authStorage.ts │ │ │ ├── dateFormatter.ts │ │ │ └── formatByte.tsx │ │ ├── App.tsx │ │ ├── service │ │ │ └── http.ts │ │ ├── components │ │ │ ├── Footer.tsx │ │ │ ├── modules │ │ │ │ └── Router.tsx │ │ │ ├── Icon.tsx │ │ │ ├── UserBadge.tsx │ │ │ └── DeleteUserModal.tsx │ │ ├── index.tsx │ │ ├── index.scss │ │ ├── pages │ │ │ └── Dashboard.tsx │ │ └── assets │ │ │ └── logo.svg │ ├── build │ │ ├── favicon │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-150x150.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── browserconfig.xml │ │ │ ├── site.webmanifest │ │ │ └── safari-pinned-tab.svg │ │ ├── assets │ │ │ ├── ajax-loader.e7b44c86.gif │ │ │ ├── slick.12459f22.svg │ │ │ └── logo.2507bd68.svg │ │ ├── 404.html │ │ └── index.html │ ├── public │ │ └── favicon │ │ │ ├── favicon.ico │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-150x150.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── browserconfig.xml │ │ │ ├── site.webmanifest │ │ │ └── safari-pinned-tab.svg │ ├── tsconfig.node.json │ ├── .gitignore │ ├── vite.config.ts │ ├── tsconfig.json │ ├── index.html │ ├── README.md │ ├── __init__.py │ └── package.json ├── db │ ├── migrations │ │ ├── README │ │ ├── versions │ │ │ ├── ece13c4c6f65_.py │ │ │ ├── b15eba6e5867_add_host_sni.py │ │ │ ├── 7cbe9d91ac11_proxyhost_security_added.py │ │ │ ├── 9d5a518ae432_init_jwt_table.py │ │ │ ├── 9b60be6cd0a2_add_created_at_field_to_users_table.py │ │ │ ├── b3378dc6de01_hosts.py │ │ │ ├── 3cf36a5fde73_init_system_table.py │ │ │ ├── e91236993f1a_inbounds_table_excluded_inbounds.py │ │ │ ├── d02dcfbf1517_add_userusageresetlogs_model_and_data_.py │ │ │ ├── 94a5cc12c0d6_init_user_table.py │ │ │ ├── 671621870b02_init_admin.py │ │ │ ├── 5b84d88804a1_fix.py │ │ │ └── fad8b1997c3a_case_insensitive_username.py │ │ ├── script.py.mako │ │ └── env.py │ ├── base.py │ └── __init__.py ├── views │ ├── __init__.py │ └── subscription.py ├── models │ ├── system.py │ └── admin.py ├── jobs │ ├── 0_start_xray.py │ ├── __init__.py │ ├── reset_user_data_usage.py │ ├── review_users.py │ └── record_usages.py ├── xray │ └── __init__.py ├── utils │ ├── system.py │ ├── xray.py │ ├── jwt.py │ └── store.py ├── telegram │ ├── __init__.py │ └── user.py └── __init__.py ├── .dockerignore ├── xray_api ├── types │ ├── __init__.py │ ├── message.py │ └── account.py ├── proto │ ├── core │ │ └── config_pb2_grpc.py │ ├── app │ │ ├── dns │ │ │ ├── config_pb2_grpc.py │ │ │ └── fakedns │ │ │ │ ├── fakedns_pb2_grpc.py │ │ │ │ └── fakedns_pb2.py │ │ ├── log │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── stats │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── commander │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── dispatcher │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── metrics │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── policy │ │ │ └── config_pb2_grpc.py │ │ ├── proxyman │ │ │ └── config_pb2_grpc.py │ │ ├── reverse │ │ │ └── config_pb2_grpc.py │ │ ├── router │ │ │ └── config_pb2_grpc.py │ │ └── observatory │ │ │ └── config_pb2_grpc.py │ ├── common │ │ ├── log │ │ │ ├── log_pb2_grpc.py │ │ │ └── log_pb2.py │ │ ├── net │ │ │ ├── port_pb2_grpc.py │ │ │ ├── address_pb2_grpc.py │ │ │ ├── network_pb2_grpc.py │ │ │ ├── destination_pb2_grpc.py │ │ │ ├── address_pb2.py │ │ │ ├── destination_pb2.py │ │ │ ├── port_pb2.py │ │ │ └── network_pb2.py │ │ ├── protocol │ │ │ ├── user_pb2_grpc.py │ │ │ ├── headers_pb2_grpc.py │ │ │ ├── server_spec_pb2_grpc.py │ │ │ ├── user_pb2.py │ │ │ ├── server_spec_pb2.py │ │ │ └── headers_pb2.py │ │ └── serial │ │ │ ├── typed_message_pb2_grpc.py │ │ │ └── typed_message_pb2.py │ ├── proxy │ │ ├── dns │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── dokodemo │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── freedom │ │ │ └── config_pb2_grpc.py │ │ ├── http │ │ │ └── config_pb2_grpc.py │ │ ├── loopback │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── mtproto │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── socks │ │ │ └── config_pb2_grpc.py │ │ ├── trojan │ │ │ └── config_pb2_grpc.py │ │ ├── vless │ │ │ ├── account_pb2_grpc.py │ │ │ ├── inbound │ │ │ │ ├── config_pb2_grpc.py │ │ │ │ └── config_pb2.py │ │ │ ├── encoding │ │ │ │ ├── addons_pb2_grpc.py │ │ │ │ └── addons_pb2.py │ │ │ ├── outbound │ │ │ │ ├── config_pb2_grpc.py │ │ │ │ └── config_pb2.py │ │ │ └── account_pb2.py │ │ ├── vmess │ │ │ ├── account_pb2_grpc.py │ │ │ ├── inbound │ │ │ │ └── config_pb2_grpc.py │ │ │ ├── outbound │ │ │ │ ├── config_pb2_grpc.py │ │ │ │ └── config_pb2.py │ │ │ └── account_pb2.py │ │ ├── blackhole │ │ │ ├── config_pb2_grpc.py │ │ │ └── config_pb2.py │ │ ├── shadowsocks │ │ │ └── config_pb2_grpc.py │ │ └── shadowsocks_2022 │ │ │ └── config_pb2_grpc.py │ └── transport │ │ ├── global │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ └── internet │ │ ├── config_pb2_grpc.py │ │ ├── grpc │ │ ├── config_pb2_grpc.py │ │ ├── config_pb2.py │ │ └── encoding │ │ │ └── stream_pb2.py │ │ ├── http │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── kcp │ │ └── config_pb2_grpc.py │ │ ├── quic │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── tcp │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── tls │ │ └── config_pb2_grpc.py │ │ ├── udp │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── xtls │ │ └── config_pb2_grpc.py │ │ ├── websocket │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── domainsocket │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ └── headers │ │ ├── http │ │ └── config_pb2_grpc.py │ │ ├── noop │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── srtp │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── tls │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── utp │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ ├── wechat │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py │ │ └── wireguard │ │ ├── config_pb2_grpc.py │ │ └── config_pb2.py ├── base.py ├── __init__.py └── exceptions.py ├── .env.example ├── Dockerfile ├── .github ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── build.yml │ └── build-dev.yml ├── main.py ├── requirements.txt └── config.py /app/dashboard/example.env: -------------------------------------------------------------------------------- 1 | VITE_BASE_API= 2 | -------------------------------------------------------------------------------- /app/db/migrations/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /app/dashboard/.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80 3 | } 4 | -------------------------------------------------------------------------------- /app/dashboard/src/types/ProxyHosts.ts: -------------------------------------------------------------------------------- 1 | export type ProxyHostSecurity = "inbound_default" | "none" | "tls" 2 | -------------------------------------------------------------------------------- /app/dashboard/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /app/dashboard/build/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/favicon.ico -------------------------------------------------------------------------------- /app/dashboard/public/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/favicon.ico -------------------------------------------------------------------------------- /app/dashboard/build/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /app/dashboard/build/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /app/dashboard/build/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /app/dashboard/public/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /app/dashboard/public/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /app/dashboard/build/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /app/dashboard/public/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /app/dashboard/build/assets/ajax-loader.e7b44c86.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/assets/ajax-loader.e7b44c86.gif -------------------------------------------------------------------------------- /app/dashboard/public/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /app/dashboard/build/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /app/dashboard/build/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/build/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /app/dashboard/public/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /app/dashboard/public/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Musixal/Marzban/HEAD/app/dashboard/public/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | __pycache__ 3 | *.pyc 4 | *.pyo 5 | *.pyd 6 | .env* 7 | db.sqlite3 8 | db.sqlite3-journal 9 | *.log 10 | v2ray-core 11 | xray-core -------------------------------------------------------------------------------- /xray_api/types/__init__.py: -------------------------------------------------------------------------------- 1 | from .account import (Account, ShadowsocksAccount, TrojanAccount, VLESSAccount, 2 | VMessAccount) 3 | from .message import Message, TypedMessage 4 | -------------------------------------------------------------------------------- /xray_api/proto/core/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/dns/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/log/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/stats/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/log/log_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/net/port_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/dns/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/commander/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/dispatcher/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/metrics/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/policy/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/proxyman/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/reverse/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/router/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/net/address_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/net/network_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/protocol/user_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/dokodemo/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/freedom/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/http/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/loopback/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/mtproto/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/socks/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/trojan/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vless/account_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vmess/account_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/dns/fakedns/fakedns_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/app/observatory/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/net/destination_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/protocol/headers_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/blackhole/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/shadowsocks/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vless/inbound/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vmess/inbound/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/global/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/protocol/server_spec_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/common/serial/typed_message_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/shadowsocks_2022/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vless/encoding/addons_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vless/outbound/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/proxy/vmess/outbound/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/grpc/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/http/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/kcp/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/quic/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/tcp/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/tls/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/udp/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/xtls/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/websocket/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/domainsocket/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/http/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/noop/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/srtp/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/tls/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/utp/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/wechat/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /app/views/__init__.py: -------------------------------------------------------------------------------- 1 | from app import app 2 | 3 | from .admin import * 4 | from .system import * 5 | from .user import * 6 | from .subscription import * 7 | 8 | 9 | @app.get("/", status_code=204) 10 | def base(): 11 | return 12 | -------------------------------------------------------------------------------- /xray_api/base.py: -------------------------------------------------------------------------------- 1 | import grpc 2 | 3 | 4 | class XRayBase(object): 5 | def __init__(self, address, port): 6 | self.address = address 7 | self.port = port 8 | self._channel = grpc.insecure_channel(f"{address}:{port}") 9 | -------------------------------------------------------------------------------- /xray_api/proto/transport/internet/headers/wireguard/config_pb2_grpc.py: -------------------------------------------------------------------------------- 1 | # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! 2 | """Client and server classes corresponding to protobuf-defined services.""" 3 | import grpc 4 | 5 | -------------------------------------------------------------------------------- /app/dashboard/src/constants/Project.ts: -------------------------------------------------------------------------------- 1 | export const REPO_URL = "https://github.com/Gozargah/Marzban"; 2 | export const ORGANIZATION_URL = "https://github.com/Gozargah"; 3 | export const DONATION_URL = "https://github.com/Gozargah/Marzban#donation"; 4 | -------------------------------------------------------------------------------- /app/dashboard/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /app/models/system.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SystemStats(BaseModel): 5 | mem_total: int 6 | mem_used: int 7 | total_user: int 8 | users_active: int 9 | incoming_bandwidth: int 10 | outgoing_bandwidth: int 11 | -------------------------------------------------------------------------------- /xray_api/types/message.py: -------------------------------------------------------------------------------- 1 | from ..proto.common.serial.typed_message_pb2 import TypedMessage 2 | 3 | 4 | class Message: 5 | def __new__(cls, message) -> TypedMessage: 6 | return TypedMessage( 7 | type=message.DESCRIPTOR.full_name, 8 | value=message.SerializeToString() 9 | ) 10 | -------------------------------------------------------------------------------- /app/dashboard/build/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/dashboard/public/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/dashboard/src/utils/authStorage.ts: -------------------------------------------------------------------------------- 1 | export const getAuthToken = () => { 2 | return localStorage.getItem("token"); 3 | }; 4 | 5 | export const setAuthToken = (token: string) => { 6 | localStorage.setItem("token", token); 7 | }; 8 | 9 | export const removeAuthToken = () => { 10 | localStorage.removeItem("token"); 11 | }; 12 | -------------------------------------------------------------------------------- /xray_api/__init__.py: -------------------------------------------------------------------------------- 1 | from . import exceptions 2 | from . import exceptions as exc 3 | from . import types 4 | from .proxyman import Proxyman 5 | from .stats import Stats 6 | 7 | 8 | class XRay(Proxyman, Stats): 9 | pass 10 | 11 | 12 | __all__ = [ 13 | "XRay", 14 | "exceptions", 15 | "exc", 16 | "types" 17 | ] 18 | -------------------------------------------------------------------------------- /app/jobs/0_start_xray.py: -------------------------------------------------------------------------------- 1 | from app import app, xray 2 | from app.utils.xray import xray_config_include_db_clients 3 | 4 | 5 | @app.on_event("startup") 6 | def app_startup(): 7 | xray.core.start( 8 | xray_config_include_db_clients(xray.config) 9 | ) 10 | 11 | 12 | @app.on_event("shutdown") 13 | def app_shutdown(): 14 | xray.core.stop() 15 | -------------------------------------------------------------------------------- /app/dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | *.local 12 | 13 | # Editor directories and files 14 | .vscode/* 15 | !.vscode/extensions.json 16 | .idea 17 | .DS_Store 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | 24 | .env 25 | 26 | stats.html 27 | -------------------------------------------------------------------------------- /app/dashboard/src/App.tsx: -------------------------------------------------------------------------------- 1 | import "react-datepicker/dist/react-datepicker.css"; 2 | import "react-loading-skeleton/dist/skeleton.css"; 3 | import { RouterProvider } from "react-router-dom"; 4 | import { router } from "./components/modules/Router"; 5 | 6 | function App() { 7 | return ( 8 |
9 | 10 |
11 | ); 12 | } 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | SUDO_USERNAME = "admin" 2 | SUDO_PASSWORD = "admin" 3 | 4 | UVICORN_HOST = "0.0.0.0" 5 | UVICORN_PORT = 8000 6 | 7 | XRAY_JSON = "xray.json" 8 | XRAY_EXECUTABLE_PATH = "/usr/local/bin/xray" 9 | XRAY_ASSETS_PATH = "/usr/local/share/xray" 10 | 11 | 12 | # XRAY_SUBSCRIPTION_URL_PREFIX = "http://example.com" 13 | 14 | # TELEGRAM_API_TOKEN = 123456789:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 15 | # TELEGRAM_ADMIN_ID = 987654321 -------------------------------------------------------------------------------- /app/dashboard/src/constants/ProxyHosts.tsx: -------------------------------------------------------------------------------- 1 | import { ProxyHostSecurity } from "types/ProxyHosts"; 2 | 3 | export const proxyHostSecurity: {title: string, value: ProxyHostSecurity}[] = [ 4 | { 5 | "title": "Inbound's default", 6 | "value": "inbound_default" 7 | }, 8 | { 9 | "title": "TLS", 10 | "value": "tls" 11 | }, 12 | { 13 | "title": "None", 14 | "value": "none" 15 | } 16 | ] -------------------------------------------------------------------------------- /app/jobs/__init__.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import importlib.util 3 | from os.path import basename, dirname, join 4 | 5 | modules = glob.glob(join(dirname(__file__), "*.py")) 6 | 7 | for file in modules: 8 | name = basename(file).replace('.py', '') 9 | if name.startswith('_'): 10 | continue 11 | 12 | spec = importlib.util.spec_from_file_location(name, file) 13 | spec.loader.exec_module(importlib.util.module_from_spec(spec)) 14 | -------------------------------------------------------------------------------- /app/db/base.py: -------------------------------------------------------------------------------- 1 | from config import SQLALCHEMY_DATABASE_URL 2 | from sqlalchemy import create_engine 3 | from sqlalchemy.ext.declarative import declarative_base 4 | from sqlalchemy.orm import sessionmaker 5 | 6 | engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args=( 7 | {"check_same_thread": False} if SQLALCHEMY_DATABASE_URL.startswith('sqlite') else {} 8 | )) 9 | SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) 10 | Base = declarative_base() 11 | -------------------------------------------------------------------------------- /app/dashboard/src/utils/dateFormatter.ts: -------------------------------------------------------------------------------- 1 | import dayjs from "dayjs"; 2 | 3 | export const relativeExpiryDate = (expiryDate: number | null | undefined) => { 4 | let date = ""; 5 | if (expiryDate) { 6 | if ( 7 | dayjs(expiryDate * 1000) 8 | .utc() 9 | .isAfter(dayjs().utc()) 10 | ) { 11 | date = "Expires " + dayjs().to(dayjs(expiryDate * 1000).utc()); 12 | } else { 13 | date = "Expired " + dayjs().to(dayjs(expiryDate * 1000).utc()); 14 | } 15 | } 16 | return date; 17 | }; 18 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim 2 | 3 | ENV PYTHONUNBUFFERED 1 4 | 5 | WORKDIR /code 6 | 7 | RUN apt-get update \ 8 | && apt-get install -y curl unzip gcc python3-dev \ 9 | && rm -rf /var/lib/apt/lists/* 10 | 11 | RUN curl -L https://github.com/Gozargah/Marzban-scripts/raw/master/install_latest_xray.sh | bash 12 | 13 | COPY . /code 14 | 15 | RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt 16 | 17 | RUN apt-get remove -y curl unzip gcc python3-dev 18 | 19 | CMD ["bash", "-c", "alembic upgrade head; python main.py"] -------------------------------------------------------------------------------- /app/db/migrations/versions/ece13c4c6f65_.py: -------------------------------------------------------------------------------- 1 | """empty message 2 | 3 | Revision ID: ece13c4c6f65 4 | Revises: d02dcfbf1517, b3378dc6de01 5 | Create Date: 2023-02-23 14:55:19.953972 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = 'ece13c4c6f65' 14 | down_revision = ('d02dcfbf1517', 'b3378dc6de01') 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | pass 21 | 22 | 23 | def downgrade() -> None: 24 | pass 25 | -------------------------------------------------------------------------------- /app/dashboard/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react"; 2 | import { defineConfig, splitVendorChunkPlugin } from "vite"; 3 | import svgr from "vite-plugin-svgr"; 4 | import { visualizer } from "rollup-plugin-visualizer"; 5 | import tsconfigPaths from "vite-tsconfig-paths"; 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [ 10 | tsconfigPaths(), 11 | react({ 12 | include: "**/*.tsx", 13 | }), 14 | svgr(), 15 | visualizer(), 16 | splitVendorChunkPlugin(), 17 | ], 18 | }); 19 | -------------------------------------------------------------------------------- /app/dashboard/build/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/favicon/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/favicon/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /app/dashboard/public/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/favicon/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/favicon/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /app/dashboard/src/service/http.ts: -------------------------------------------------------------------------------- 1 | import { $fetch as ohMyFetch, FetchOptions } from "ohmyfetch"; 2 | import { getAuthToken } from "utils/authStorage"; 3 | 4 | export const $fetch = ohMyFetch.create({ 5 | baseURL: import.meta.env.VITE_BASE_API, 6 | }); 7 | 8 | export const fetcher = (url: string, ops: FetchOptions<"json"> = {}) => { 9 | const token = getAuthToken(); 10 | if (token) { 11 | ops["headers"] = { 12 | ...(ops?.headers || {}), 13 | Authorization: `Bearer ${getAuthToken()}`, 14 | }; 15 | } 16 | return $fetch(url, ops); 17 | }; 18 | 19 | export const fetch = fetcher; 20 | -------------------------------------------------------------------------------- /app/db/migrations/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | ${imports if imports else ""} 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = ${repr(up_revision)} 14 | down_revision = ${repr(down_revision)} 15 | branch_labels = ${repr(branch_labels)} 16 | depends_on = ${repr(depends_on)} 17 | 18 | 19 | def upgrade() -> None: 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade() -> None: 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /app/dashboard/src/utils/formatByte.tsx: -------------------------------------------------------------------------------- 1 | export function formatBytes(bytes: number, decimals = 2, asArray = false) { 2 | if (!+bytes) return "0 B"; 3 | 4 | const k = 1024; 5 | const dm = decimals < 0 ? 0 : decimals; 6 | const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; 7 | 8 | const i = Math.floor(Math.log(bytes) / Math.log(k)); 9 | if (!asArray) 10 | return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`; 11 | else return [parseFloat((bytes / Math.pow(k, i)).toFixed(dm)), sizes[i]]; 12 | } 13 | 14 | export const numberWithCommas = (x: number) => { 15 | if (x !== null) return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 16 | }; 17 | -------------------------------------------------------------------------------- /app/dashboard/src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { BoxProps, HStack, Link, Text } from "@chakra-ui/react"; 2 | import { ORGANIZATION_URL } from "constants/Project"; 3 | import { FC } from "react"; 4 | 5 | export const Footer: FC = (props) => { 6 | return ( 7 | 8 | 15 | Made with ❤️ in{" "} 16 | 17 | Gozargah 18 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: Feature title 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /app/dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": [ 6 | "DOM", 7 | "DOM.Iterable", 8 | "ESNext" 9 | ], 10 | "allowJs": false, 11 | "skipLibCheck": true, 12 | "esModuleInterop": false, 13 | "allowSyntheticDefaultImports": true, 14 | "strict": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "module": "ESNext", 17 | "moduleResolution": "Node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx", 22 | "baseUrl": "./src" 23 | }, 24 | "include": [ 25 | "src" 26 | ], 27 | "references": [ 28 | { 29 | "path": "./tsconfig.node.json" 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /app/db/migrations/versions/b15eba6e5867_add_host_sni.py: -------------------------------------------------------------------------------- 1 | """add host and sni columns to hosts table 2 | 3 | Revision ID: b15eba6e5867 4 | Revises: ece13c4c6f65 5 | Create Date: 2023-02-28 18:34:19.100255 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "b15eba6e5867" 14 | down_revision = "ece13c4c6f65" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | op.add_column("hosts", sa.Column("sni", sa.String(256), nullable=True)) 21 | op.add_column("hosts", sa.Column("host", sa.String(256), nullable=True)) 22 | 23 | 24 | def downgrade() -> None: 25 | op.drop_column("hosts", "host") 26 | op.drop_column("hosts", "sni") 27 | -------------------------------------------------------------------------------- /app/dashboard/src/components/modules/Router.tsx: -------------------------------------------------------------------------------- 1 | import { createBrowserRouter, createHashRouter } from "react-router-dom"; 2 | import { Dashboard } from "../../pages/Dashboard"; 3 | import { Login } from "../../pages/Login"; 4 | import { fetch } from "../../service/http"; 5 | import { getAuthToken } from "../../utils/authStorage"; 6 | 7 | const fetchAdminLoader = () => { 8 | return fetch("/admin", { 9 | headers: { 10 | Authorization: `Bearer ${getAuthToken()}`, 11 | }, 12 | }); 13 | }; 14 | 15 | export const router = createBrowserRouter( 16 | [ 17 | { 18 | path: "/", 19 | element: , 20 | errorElement: , 21 | loader: fetchAdminLoader, 22 | }, 23 | { 24 | path: "/login/", 25 | element: , 26 | }, 27 | ], 28 | { basename: import.meta.env.BASE_URL } 29 | ); 30 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from app import app 3 | from config import ( 4 | DEBUG, 5 | UVICORN_HOST, 6 | UVICORN_PORT, 7 | UVICORN_UDS, 8 | UVICORN_SSL_CERTFILE, 9 | UVICORN_SSL_KEYFILE 10 | ) 11 | 12 | 13 | if __name__ == "__main__": 14 | # Do NOT change workers count for now 15 | # multi-workers support isn't implemented yet for APScheduler and XRay module 16 | try: 17 | uvicorn.run( 18 | "main:app", 19 | host=('127.0.0.1' if DEBUG else UVICORN_HOST), 20 | port=UVICORN_PORT, 21 | uds=(None if DEBUG else UVICORN_UDS), 22 | ssl_certfile=UVICORN_SSL_CERTFILE, 23 | ssl_keyfile=UVICORN_SSL_KEYFILE, 24 | workers=1, 25 | reload=DEBUG 26 | ) 27 | except FileNotFoundError: # to prevent error on removing unix sock 28 | pass 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: Bug title 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Machine details (please complete the following information):** 27 | - OS: [e.g. ubuntu 20] 28 | - Python version: [e.g 3.8] 29 | - Nodejs version: [e.g 16.17] 30 | - Browser [e.g. chrome, safari] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /app/xray/__init__.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | 3 | from app.utils.system import check_port 4 | from app.xray.config import XRayConfig 5 | from app.xray.core import XRayCore 6 | from xray_api import XRay 7 | from xray_api import exceptions 8 | from xray_api import exceptions as exc 9 | from xray_api import types 10 | 11 | from config import XRAY_ASSETS_PATH, XRAY_EXECUTABLE_PATH, XRAY_JSON 12 | 13 | # Search for a free API port 14 | try: 15 | for api_port in range(randint(10000, 60000), 65536): 16 | if not check_port(api_port): 17 | break 18 | finally: 19 | config = XRayConfig(XRAY_JSON, api_port=api_port) 20 | del api_port 21 | 22 | 23 | core = XRayCore(XRAY_EXECUTABLE_PATH, XRAY_ASSETS_PATH) 24 | api = XRay(config.api_host, config.api_port) 25 | 26 | 27 | __all__ = [ 28 | "config", 29 | "core", 30 | "api", 31 | "exceptions", 32 | "exc", 33 | "types" 34 | ] 35 | -------------------------------------------------------------------------------- /app/db/migrations/versions/7cbe9d91ac11_proxyhost_security_added.py: -------------------------------------------------------------------------------- 1 | """ProxyHost: security added 2 | 3 | Revision ID: 7cbe9d91ac11 4 | Revises: b15eba6e5867 5 | Create Date: 2023-03-07 23:30:49.678157 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = "7cbe9d91ac11" 14 | down_revision = "e3f0e888a563" 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.add_column( 22 | "hosts", 23 | sa.Column( 24 | "security", 25 | sa.Enum("inbound_default", "none", "tls", name="proxyhostsecurity"), 26 | nullable=False, 27 | server_default="inbound_default" 28 | ), 29 | ) 30 | 31 | # ### end Alembic commands ### 32 | 33 | 34 | def downgrade() -> None: 35 | # ### commands auto generated by Alembic - please adjust! ### 36 | op.drop_column("hosts", "security") 37 | # ### end Alembic commands ### 38 | -------------------------------------------------------------------------------- /app/dashboard/src/constants/UserSettings.tsx: -------------------------------------------------------------------------------- 1 | import { DataLimitResetStrategy } from "types/User"; 2 | 3 | export const resetStrategy: { title: string; value: DataLimitResetStrategy }[] = 4 | [ 5 | { 6 | title: "No", 7 | value: "no_reset", 8 | }, 9 | { 10 | title: "Daily", 11 | value: "day", 12 | }, 13 | { 14 | title: "Weekly", 15 | value: "week", 16 | }, 17 | { 18 | title: "Monthly", 19 | value: "month", 20 | }, 21 | { 22 | title: "Annually", 23 | value: "year", 24 | }, 25 | ]; 26 | 27 | export const statusColors: { 28 | [key: string]: { 29 | statusColor: string; 30 | bandWidthColor: string; 31 | }; 32 | } = { 33 | active: { 34 | statusColor: "green", 35 | bandWidthColor: "primary", 36 | }, 37 | disabled: { 38 | statusColor: "gray", 39 | bandWidthColor: "gray", 40 | }, 41 | expired: { 42 | statusColor: "orange", 43 | bandWidthColor: "orange", 44 | }, 45 | limited: { 46 | statusColor: "red", 47 | bandWidthColor: "red", 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /app/db/migrations/versions/9d5a518ae432_init_jwt_table.py: -------------------------------------------------------------------------------- 1 | """init jwt table 2 | 3 | Revision ID: 9d5a518ae432 4 | Revises: 3cf36a5fde73 5 | Create Date: 2022-11-24 21:02:44.278773 6 | 7 | """ 8 | import os 9 | from alembic import op 10 | import sqlalchemy as sa 11 | 12 | 13 | # revision identifiers, used by Alembic. 14 | revision = '9d5a518ae432' 15 | down_revision = '3cf36a5fde73' 16 | branch_labels = None 17 | depends_on = None 18 | 19 | 20 | def upgrade() -> None: 21 | # ### commands auto generated by Alembic - please adjust! ### 22 | table = op.create_table('jwt', 23 | sa.Column('id', sa.Integer(), nullable=False), 24 | sa.Column('secret_key', sa.String(length=64), nullable=False), 25 | sa.PrimaryKeyConstraint('id') 26 | ) 27 | 28 | # INSERT DEFAULT ROW 29 | op.bulk_insert(table, [{"id": 1, "secret_key": os.urandom(32).hex()}]) 30 | 31 | # ### end Alembic commands ### 32 | 33 | 34 | def downgrade() -> None: 35 | # ### commands auto generated by Alembic - please adjust! ### 36 | op.drop_table('jwt') 37 | # ### end Alembic commands ### 38 | -------------------------------------------------------------------------------- /app/db/migrations/versions/9b60be6cd0a2_add_created_at_field_to_users_table.py: -------------------------------------------------------------------------------- 1 | """add created_at field to users table 2 | 3 | Revision ID: 9b60be6cd0a2 4 | Revises: 9d5a518ae432 5 | Create Date: 2022-12-25 18:45:46.743506 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '9b60be6cd0a2' 14 | down_revision = '9d5a518ae432' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | with op.batch_alter_table('users') as batch_op: 22 | batch_op.add_column(sa.Column( 23 | 'created_at', sa.DateTime(), 24 | nullable=False, 25 | server_default=sa.func.current_timestamp())) 26 | # ### end Alembic commands ### 27 | 28 | 29 | def downgrade() -> None: 30 | # ### commands auto generated by Alembic - please adjust! ### 31 | with op.batch_alter_table('users') as batch_op: 32 | batch_op.drop_column('created_at') 33 | # ### end Alembic commands ### 34 | -------------------------------------------------------------------------------- /app/dashboard/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProvider } from "@chakra-ui/react"; 2 | import React from "react"; 3 | import ReactDOM from "react-dom/client"; 4 | import { SWRConfig } from "swr"; 5 | import { theme } from "../chakra.config"; 6 | import App from "./App"; 7 | import "index.scss"; 8 | import { fetcher } from "service/http"; 9 | import dayjs from "dayjs"; 10 | import LocalizedFormat from "dayjs/plugin/localizedFormat"; 11 | import Timezone from "dayjs/plugin/timezone"; 12 | import utc from "dayjs/plugin/utc"; 13 | import RelativeTime from "dayjs/plugin/relativeTime"; 14 | 15 | dayjs.extend(Timezone); 16 | dayjs.extend(LocalizedFormat); 17 | dayjs.extend(utc); 18 | dayjs.extend(RelativeTime); 19 | 20 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( 21 | 22 | 23 | 31 | 32 | 33 | 34 | 35 | ); 36 | -------------------------------------------------------------------------------- /app/db/migrations/versions/b3378dc6de01_hosts.py: -------------------------------------------------------------------------------- 1 | """hosts 2 | 3 | Revision ID: b3378dc6de01 4 | Revises: e91236993f1a 5 | Create Date: 2023-02-14 18:22:26.791353 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = 'b3378dc6de01' 14 | down_revision = 'e91236993f1a' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | op.create_table('hosts', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('remark', sa.String(256), nullable=False), 24 | sa.Column('address', sa.String(256), nullable=False), 25 | sa.Column('port', sa.Integer(), nullable=True), 26 | sa.Column('inbound_tag', sa.String(256), nullable=False), 27 | sa.ForeignKeyConstraint(['inbound_tag'], ['inbounds.tag'], ), 28 | sa.PrimaryKeyConstraint('id') 29 | ) 30 | # ### end Alembic commands ### 31 | 32 | 33 | def downgrade() -> None: 34 | # ### commands auto generated by Alembic - please adjust! ### 35 | op.drop_table('hosts') 36 | # ### end Alembic commands ### 37 | -------------------------------------------------------------------------------- /app/dashboard/src/types/User.ts: -------------------------------------------------------------------------------- 1 | export type UserStatus = "active" | "disabled" | "limited" | "expired"; 2 | export type ProxyKeys = ("vmess" | "vless" | "trojan" | "shadowsocks")[]; 3 | export type ProxyType = { 4 | vmess?: { 5 | id?: string; 6 | }; 7 | vless?: { 8 | id?: string; 9 | }; 10 | trojan?: { password?: string }; 11 | shadowsocks?: { 12 | password?: string; 13 | }; 14 | }; 15 | 16 | export type DataLimitResetStrategy = 17 | | "no_reset" 18 | | "day" 19 | | "week" 20 | | "month" 21 | | "year"; 22 | 23 | export type UserInbounds = { 24 | [key: string]: string[]; 25 | }; 26 | export type User = { 27 | proxies: ProxyType; 28 | expire: number | null; 29 | data_limit: number | null; 30 | data_limit_reset_strategy: DataLimitResetStrategy; 31 | lifetime_used_traffic: number; 32 | username: string; 33 | used_traffic: number; 34 | status: UserStatus; 35 | links: string[]; 36 | subscription_url: string; 37 | inbounds: UserInbounds; 38 | }; 39 | 40 | export type UserCreate = Pick< 41 | User, 42 | | "inbounds" 43 | | "proxies" 44 | | "expire" 45 | | "data_limit" 46 | | "data_limit_reset_strategy" 47 | | "username" 48 | | "status" 49 | >; 50 | -------------------------------------------------------------------------------- /app/utils/system.py: -------------------------------------------------------------------------------- 1 | import math 2 | import secrets 3 | import socket 4 | from dataclasses import dataclass 5 | 6 | import psutil 7 | 8 | 9 | @dataclass 10 | class MemoryStat(): 11 | total: int 12 | used: int 13 | free: int 14 | 15 | 16 | @dataclass 17 | class CPUStat(): 18 | cores: int 19 | percent: int 20 | 21 | 22 | def cpu_usage() -> CPUStat: 23 | return CPUStat(cores=psutil.cpu_count(), percent=psutil.cpu_percent()) 24 | 25 | 26 | def memory_usage() -> MemoryStat: 27 | mem = psutil.virtual_memory() 28 | return MemoryStat(total=mem.total, used=mem.used, free=mem.available) 29 | 30 | 31 | def random_password() -> str: 32 | return secrets.token_urlsafe(16) 33 | 34 | 35 | def check_port(port: int) -> bool: 36 | s = socket.socket() 37 | try: 38 | s.connect(('127.0.0.1', port)) 39 | return True 40 | except socket.error: 41 | return False 42 | finally: 43 | s.close() 44 | 45 | 46 | def readable_size(size_bytes): 47 | if size_bytes == 0: 48 | return "0B" 49 | size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB") 50 | i = int(math.floor(math.log(size_bytes, 1024))) 51 | p = math.pow(1024, i) 52 | s = round(size_bytes / p, 2) 53 | return f'{s} {size_name[i]}' 54 | -------------------------------------------------------------------------------- /app/dashboard/src/index.scss: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap"); 2 | 3 | .bg-blue-animate { 4 | animation: blur-animate 200ms ease-in; 5 | backdrop-filter: blur(10px); 6 | } 7 | 8 | @keyframes blur-animate { 9 | from { 10 | backdrop-filter: blur(1px); 11 | } 12 | to { 13 | backdrop-filter: blur(10px); 14 | } 15 | } 16 | 17 | .animate-spin { 18 | animation: spin 1s linear infinite; 19 | } 20 | 21 | @keyframes spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | table thead { 31 | th:first-of-type { 32 | border-top-left-radius: 8px; 33 | } 34 | th:last-of-type { 35 | border-top-right-radius: 8px; 36 | } 37 | } 38 | 39 | .last-row { 40 | td:first-of-type { 41 | border-bottom-left-radius: 8px; 42 | } 43 | td:last-of-type { 44 | border-bottom-right-radius: 8px; 45 | } 46 | } 47 | 48 | .slick-prev { 49 | left: -40px; 50 | } 51 | .slick-next { 52 | right: -40px; 53 | } 54 | .slick-prev, 55 | .slick-next { 56 | z-index: 100; 57 | } 58 | .chakra-popover__popper { 59 | z-index: 9999 !important; 60 | } 61 | .inbound-item .chakra-checkbox__label { 62 | max-width: 100%; 63 | width: 100%; 64 | } 65 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | alembic==1.8.1 2 | anyio==3.6.2 3 | APScheduler==3.9.1.post1 4 | async-timeout==4.0.2 5 | backports.zoneinfo==0.2.1;python_version<"3.9" 6 | bcrypt==4.0.1 7 | certifi==2022.12.7 8 | cffi==1.15.1 9 | charset-normalizer==2.1.1 10 | click==8.1.3 11 | cryptography==39.0.1 12 | Deprecated==1.2.13 13 | ecdsa==0.18.0 14 | fastapi==0.92.0 15 | fastapi-responses==0.2.1 16 | greenlet==2.0.1 17 | grpcio==1.50.0 18 | grpcio-tools==1.44.0 19 | h11==0.14.0 20 | httptools==0.5.0 21 | idna==3.4 22 | importlib-metadata==5.1.0 23 | importlib-resources==5.10.0 24 | Mako==1.2.4 25 | MarkupSafe==2.1.1 26 | packaging==21.3 27 | passlib==1.7.4 28 | protobuf==3.20.3 29 | psutil==5.9.4 30 | pyasn1==0.4.8 31 | pycparser==2.21 32 | pydantic==1.10.2 33 | pyparsing==3.0.9 34 | pyTelegramBotAPI==4.9.0 35 | python-decouple==3.6 36 | python-dotenv==0.21.0 37 | python-jose==3.3.0 38 | python-multipart==0.0.5 39 | pytz==2022.6 40 | pytz-deprecation-shim==0.1.0.post0 41 | PyYAML==6.0 42 | redis==4.3.5 43 | requests==2.28.1 44 | rsa==4.9 45 | six==1.16.0 46 | sniffio==1.3.0 47 | SQLAlchemy==1.4.44 48 | starlette==0.25.0 49 | typing_extensions==4.4.0 50 | tzdata==2022.6 51 | tzlocal==4.2 52 | urllib3==1.26.12 53 | uvicorn==0.19.0 54 | uvloop==0.17.0 55 | watchfiles==0.18.1 56 | websockets==10.4 57 | wrapt==1.14.1 58 | zipp==3.10.0 59 | python-dateutil==2.8.2 -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | build-docker-image: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v3 14 | 15 | - name: Set up QEMU 16 | uses: docker/setup-qemu-action@v2 17 | 18 | - name: Set up Docker Buildx 19 | uses: docker/setup-buildx-action@v2 20 | 21 | - name: Login to Docker Hub 22 | uses: docker/login-action@v2 23 | with: 24 | username: ${{ secrets.DOCKERHUB_USERNAME }} 25 | password: ${{ secrets.DOCKERHUB_TOKEN }} 26 | 27 | - name: Login to GitHub Container Registry 28 | uses: docker/login-action@v2 29 | with: 30 | registry: ghcr.io 31 | username: ${{ github.repository_owner }} 32 | password: ${{ secrets.GITHUB_TOKEN }} 33 | 34 | - name: Build and push 35 | uses: docker/build-push-action@v3 36 | with: 37 | context: . 38 | platforms: linux/amd64,linux/arm64 39 | push: true 40 | tags: | 41 | gozargah/marzban:latest 42 | gozargah/marzban:${{github.ref_name}} 43 | ghcr.io/gozargah/marzban:latest 44 | ghcr.io/gozargah/marzban:${{github.ref_name}} 45 | -------------------------------------------------------------------------------- /app/dashboard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Marzban 7 | 12 | 18 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/telegram/__init__.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import importlib.util 3 | from os.path import basename, dirname, join 4 | from threading import Thread 5 | from config import TELEGRAM_API_TOKEN, TELEGRAM_PROXY_URL 6 | from app import app 7 | from telebot import TeleBot, apihelper 8 | 9 | 10 | bot = None 11 | if TELEGRAM_API_TOKEN: 12 | apihelper.proxy = {'http': TELEGRAM_PROXY_URL, 'https': TELEGRAM_PROXY_URL} 13 | bot = TeleBot(TELEGRAM_API_TOKEN) 14 | 15 | 16 | @app.on_event("startup") 17 | def start_bot(): 18 | if bot: 19 | handler = glob.glob(join(dirname(__file__), "*.py")) 20 | for file in handler: 21 | name = basename(file).replace('.py', '') 22 | if name.startswith('_'): 23 | continue 24 | spec = importlib.util.spec_from_file_location(name, file) 25 | spec.loader.exec_module(importlib.util.module_from_spec(spec)) 26 | 27 | thread = Thread(target=bot.infinity_polling, daemon=True) 28 | thread.start() 29 | 30 | 31 | from .report import ( # noqa 32 | report, 33 | report_new_user, 34 | report_user_modification, 35 | report_user_deletion, 36 | report_status_change 37 | ) 38 | 39 | __all__ = [ 40 | "bot", 41 | "report", 42 | "report_new_user", 43 | "report_user_modification", 44 | "report_user_deletion", 45 | "report_status_change" 46 | ] 47 | -------------------------------------------------------------------------------- /app/dashboard/README.md: -------------------------------------------------------------------------------- 1 | # Dashboard UI for marzban 2 | 3 | ## Requirements 4 | 5 | For development, you will only need Node.js installed on your environement. 6 | 7 | ### Node 8 | 9 | [Node](http://nodejs.org/) is really easy to install & now include [NPM](https://npmjs.org/). 10 | This project has been developed on the Nodejs v16.17.0 so if you faced any issue during installation that may related to the node version, install Node with version >= v16.17.0. 11 | 12 | ## Install 13 | 14 | git clone https://github.com/gozargah/marz-manager.git 15 | cd marz-manager 16 | yarn install 17 | 18 | ### Configure app 19 | 20 | Copy `example.env` to `.env` then set the backend api address: 21 | 22 | VITE_BASE_API=https://somewhere.com/ 23 | 24 | #### Environment variables 25 | 26 | | Name | Description | 27 | | ------------- | ------------------------------------------------------------------------------------ | 28 | | VITE_BASE_API | The api url of the deployed backend ([Marzban](https://github.com/gozargah/Marzban)) | 29 | 30 | ## Start development server 31 | 32 | yarn dev 33 | 34 | ## Simple build for production 35 | 36 | yarn build 37 | 38 | ## Contribution 39 | 40 | Feel free to contribute. Go on and fork the project. After commiting the changes, make a PR. It means a lot to us. 41 | -------------------------------------------------------------------------------- /app/db/migrations/versions/3cf36a5fde73_init_system_table.py: -------------------------------------------------------------------------------- 1 | """init system table 2 | 3 | Revision ID: 3cf36a5fde73 4 | Revises: 94a5cc12c0d6 5 | Create Date: 2022-11-22 04:48:55.227490 6 | 7 | """ 8 | from alembic import op 9 | import sqlalchemy as sa 10 | 11 | 12 | # revision identifiers, used by Alembic. 13 | revision = '3cf36a5fde73' 14 | down_revision = '94a5cc12c0d6' 15 | branch_labels = None 16 | depends_on = None 17 | 18 | 19 | def upgrade() -> None: 20 | # ### commands auto generated by Alembic - please adjust! ### 21 | table = op.create_table('system', 22 | sa.Column('id', sa.Integer(), nullable=False), 23 | sa.Column('uplink', sa.BigInteger(), nullable=True), 24 | sa.Column('downlink', sa.BigInteger(), nullable=True), 25 | sa.PrimaryKeyConstraint('id') 26 | ) 27 | op.create_index(op.f('ix_system_id'), 'system', ['id'], unique=False) 28 | 29 | # INSERT DEFAULT ROW 30 | op.bulk_insert(table, [{"id": 1, "uplink": 0, "downlink": 0}]) 31 | 32 | # ### end Alembic commands ### 33 | 34 | 35 | def downgrade() -> None: 36 | # ### commands auto generated by Alembic - please adjust! ### 37 | op.drop_index(op.f('ix_system_id'), table_name='system') 38 | op.drop_table('system') 39 | # ### end Alembic commands ### 40 | -------------------------------------------------------------------------------- /app/dashboard/src/pages/Dashboard.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Button, VStack } from "@chakra-ui/react"; 2 | import { Statistics } from "../components/Statistics"; 3 | import { FC, useEffect } from "react"; 4 | import { Footer } from "components/Footer"; 5 | import { Header } from "components/Header"; 6 | import { UsersTable } from "components/UsersTable"; 7 | import { Filters } from "components/Filters"; 8 | import { fetchInbounds, useDashboard } from "contexts/DashboardContext"; 9 | import { UserDialog } from "components/UserDialog"; 10 | import { DeleteUserModal } from "components/DeleteUserModal"; 11 | import { QRCodeDialog } from "components/QRCodeDialog"; 12 | import { HostsDialog } from "components/HostsDialog"; 13 | import { ResetUserUsageModal } from "components/ResetUserUsageModal"; 14 | 15 | export const Dashboard: FC = () => { 16 | useEffect(() => { 17 | useDashboard.getState().refetchUsers(); 18 | fetchInbounds(); 19 | }, []); 20 | return ( 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |