hiddifypanel 10.12.1__py3-none-any.whl → 10.15.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +2 -2
  3. hiddifypanel/auth.py +15 -4
  4. hiddifypanel/base.py +58 -50
  5. hiddifypanel/cache.py +43 -25
  6. hiddifypanel/database.py +9 -0
  7. hiddifypanel/drivers/abstract_driver.py +2 -0
  8. hiddifypanel/drivers/singbox_api.py +17 -15
  9. hiddifypanel/drivers/ssh_liberty_bridge_api.py +2 -0
  10. hiddifypanel/drivers/user_driver.py +12 -6
  11. hiddifypanel/drivers/wireguard_api.py +2 -0
  12. hiddifypanel/drivers/xray_api.py +14 -9
  13. hiddifypanel/hutils/__init__.py +1 -0
  14. hiddifypanel/hutils/convert.py +13 -2
  15. hiddifypanel/hutils/crypto.py +21 -2
  16. hiddifypanel/hutils/flask.py +19 -5
  17. hiddifypanel/hutils/importer/xui.py +5 -2
  18. hiddifypanel/hutils/node/__init__.py +3 -0
  19. hiddifypanel/hutils/node/api_client.py +76 -0
  20. hiddifypanel/hutils/node/child.py +147 -0
  21. hiddifypanel/hutils/node/parent.py +100 -0
  22. hiddifypanel/hutils/node/shared.py +65 -0
  23. hiddifypanel/hutils/proxy/shared.py +15 -3
  24. hiddifypanel/models/__init__.py +2 -2
  25. hiddifypanel/models/admin.py +14 -2
  26. hiddifypanel/models/base_account.py +3 -3
  27. hiddifypanel/models/child.py +30 -16
  28. hiddifypanel/models/config.py +39 -15
  29. hiddifypanel/models/config_enum.py +55 -8
  30. hiddifypanel/models/domain.py +28 -20
  31. hiddifypanel/models/parent_domain.py +2 -2
  32. hiddifypanel/models/proxy.py +13 -4
  33. hiddifypanel/models/report.py +2 -3
  34. hiddifypanel/models/usage.py +2 -2
  35. hiddifypanel/models/user.py +18 -9
  36. hiddifypanel/panel/admin/Actions.py +4 -6
  37. hiddifypanel/panel/admin/AdminstratorAdmin.py +13 -2
  38. hiddifypanel/panel/admin/Dashboard.py +5 -10
  39. hiddifypanel/panel/admin/DomainAdmin.py +12 -11
  40. hiddifypanel/panel/admin/NodeAdmin.py +6 -2
  41. hiddifypanel/panel/admin/ProxyAdmin.py +4 -3
  42. hiddifypanel/panel/admin/SettingAdmin.py +60 -21
  43. hiddifypanel/panel/admin/UserAdmin.py +10 -2
  44. hiddifypanel/panel/admin/templates/index.html +1 -1
  45. hiddifypanel/panel/admin/templates/parent_dash.html +2 -4
  46. hiddifypanel/panel/cli.py +16 -16
  47. hiddifypanel/panel/commercial/ProxyDetailsAdmin.py +10 -5
  48. hiddifypanel/panel/commercial/__init__.py +7 -5
  49. hiddifypanel/panel/commercial/restapi/v2/admin/__init__.py +0 -5
  50. hiddifypanel/panel/commercial/restapi/v2/admin/admin_info_api.py +2 -2
  51. hiddifypanel/panel/commercial/restapi/v2/admin/admin_log_api.py +4 -5
  52. hiddifypanel/panel/commercial/restapi/v2/admin/admin_user_api.py +8 -35
  53. hiddifypanel/panel/commercial/restapi/v2/admin/admin_users_api.py +4 -4
  54. hiddifypanel/panel/commercial/restapi/v2/admin/schema.py +157 -0
  55. hiddifypanel/panel/commercial/restapi/v2/admin/server_status_api.py +3 -3
  56. hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +9 -73
  57. hiddifypanel/panel/commercial/restapi/v2/admin/users_api.py +1 -1
  58. hiddifypanel/panel/commercial/restapi/v2/child/__init__.py +18 -0
  59. hiddifypanel/panel/commercial/restapi/v2/child/actions.py +63 -0
  60. hiddifypanel/panel/commercial/restapi/v2/child/register_parent_api.py +34 -0
  61. hiddifypanel/panel/commercial/restapi/v2/child/schema.py +7 -0
  62. hiddifypanel/panel/commercial/restapi/v2/child/sync_parent_api.py +21 -0
  63. hiddifypanel/panel/commercial/restapi/v2/panel/__init__.py +13 -0
  64. hiddifypanel/panel/commercial/restapi/v2/panel/info.py +18 -0
  65. hiddifypanel/panel/commercial/restapi/v2/panel/ping_pong.py +23 -0
  66. hiddifypanel/panel/commercial/restapi/v2/panel/schema.py +7 -0
  67. hiddifypanel/panel/commercial/restapi/v2/parent/__init__.py +16 -0
  68. hiddifypanel/panel/commercial/restapi/v2/parent/register_api.py +65 -0
  69. hiddifypanel/panel/commercial/restapi/v2/parent/schema.py +115 -0
  70. hiddifypanel/panel/commercial/restapi/v2/parent/status_api.py +26 -0
  71. hiddifypanel/panel/commercial/restapi/v2/parent/sync_api.py +53 -0
  72. hiddifypanel/panel/commercial/restapi/v2/parent/usage_api.py +57 -0
  73. hiddifypanel/panel/commercial/telegrambot/admin.py +1 -2
  74. hiddifypanel/panel/common.py +21 -6
  75. hiddifypanel/panel/hiddify.py +9 -80
  76. hiddifypanel/panel/init_db.py +84 -38
  77. hiddifypanel/panel/usage.py +33 -18
  78. hiddifypanel/panel/user/templates/home/usage.html +1 -1
  79. hiddifypanel/panel/user/templates/new.html +2 -2
  80. hiddifypanel/static/css/custom.css +13 -0
  81. hiddifypanel/static/images/hiddify.png +0 -0
  82. hiddifypanel/static/images/hiddify2.png +0 -0
  83. hiddifypanel/static/new/assets/hiddify-logo-7617d937.png +0 -0
  84. hiddifypanel/static/new/assets/{index-4510b616.js → index-ccb9873c.js} +2 -2
  85. hiddifypanel/static/new/assets/index-fa00de9a.css +1 -0
  86. hiddifypanel/static/new/i18n/en.json +6 -6
  87. hiddifypanel/static/new/i18n/fa.json +1 -1
  88. hiddifypanel/templates/admin-layout.html +24 -40
  89. hiddifypanel/templates/fake.html +22 -0
  90. hiddifypanel/templates/master.html +24 -42
  91. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  92. hiddifypanel/translations/en/LC_MESSAGES/messages.po +95 -5
  93. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  94. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +96 -4
  95. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  96. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +98 -6
  97. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  98. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +91 -1
  99. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  100. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +92 -2
  101. hiddifypanel/translations.i18n/en.json +61 -5
  102. hiddifypanel/translations.i18n/fa.json +60 -4
  103. hiddifypanel/translations.i18n/pt.json +63 -7
  104. hiddifypanel/translations.i18n/ru.json +57 -1
  105. hiddifypanel/translations.i18n/zh.json +58 -2
  106. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/METADATA +47 -47
  107. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/RECORD +112 -94
  108. hiddifypanel/panel/commercial/restapi/v2/DTO.py +0 -9
  109. hiddifypanel/panel/commercial/restapi/v2/hello/__init__.py +0 -16
  110. hiddifypanel/panel/commercial/restapi/v2/hello/hello.py +0 -32
  111. hiddifypanel/static/new/assets/hiddify-logo-7617d937_old.png +0 -0
  112. hiddifypanel/static/new/assets/index-669b32c8.css +0 -1
  113. /hiddifypanel/static/images/{hiddify1.png → hiddify-old.png} +0 -0
  114. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/LICENSE.md +0 -0
  115. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/WHEEL +0 -0
  116. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/entry_points.txt +0 -0
  117. {hiddifypanel-10.12.1.dist-info → hiddifypanel-10.15.0.dev0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,115 @@
1
+ from apiflask import fields, Schema
2
+ from marshmallow import ValidationError
3
+
4
+ from hiddifypanel.models import DomainType, ProxyProto, ProxyL3, ProxyTransport, ProxyCDN, ConfigEnum, ChildMode
5
+ from hiddifypanel.panel.commercial.restapi.v2.admin.schema import UserSchema, AdminSchema
6
+
7
+
8
+ def hconfig_key_validator(value):
9
+ if value not in [c.name for c in ConfigEnum]:
10
+ raise ValidationError(f"{value} is not a valid hconfig key.")
11
+ return value
12
+
13
+
14
+ class DomainSchema(Schema):
15
+ child_unique_id = fields.String(description="The child's unique id")
16
+ domain = fields.String(required=True, description="The domain name")
17
+ alias = fields.String(description="The domain alias", allow_none=True)
18
+ sub_link_only = fields.Boolean(required=True, description="Is the domain sub link only")
19
+ mode = fields.Enum(DomainType, required=True, description="The domain type")
20
+ cdn_ip = fields.String(description="The cdn ip", allow_none=True)
21
+ grpc = fields.Boolean(required=True, description="Is the domain grpc")
22
+ servernames = fields.String(description="The servernames", allow_none=True)
23
+ show_domains = fields.List(fields.String(), desciption="The list of domains to show")
24
+
25
+
26
+ class ProxySchema(Schema):
27
+ child_unique_id = fields.String(description="The child's unique id")
28
+ name = fields.String(required=True, description="The proxy name")
29
+ enable = fields.Boolean(required=True, description="Is the proxy enabled")
30
+ proto = fields.Enum(ProxyProto, required=True, description="The proxy protocol")
31
+ l3 = fields.Enum(ProxyL3, required=True, description="The proxy l3")
32
+ transport = fields.Enum(ProxyTransport, required=True, description="The proxy transport")
33
+ cdn = fields.Enum(ProxyCDN, required=True, description="The proxy cdn")
34
+
35
+
36
+ class StringOrBooleanField(fields.Field):
37
+ def _deserialize(self, value, attr, data, **kwargs):
38
+ if isinstance(value, (str, bool)):
39
+ return str(value)
40
+ else:
41
+ raise ValidationError("Value must be a string or a boolean.")
42
+
43
+ def _serialize(self, value, attr, obj, **kwargs):
44
+ return value
45
+
46
+
47
+ class HConfigSchema(Schema):
48
+ child_unique_id = fields.String(description="The child's unique id")
49
+ key = fields.String(required=True, description="The config key", validate=hconfig_key_validator) # type: ignore
50
+ value = StringOrBooleanField(required=True, description="The config value")
51
+
52
+
53
+ # region usage
54
+ class UsageData(Schema):
55
+ uuid = fields.UUID(required=True, desciption="The user uuid")
56
+ usage = fields.Integer(required=True, description="The user usage in bytes")
57
+ devices = fields.List(fields.String(required=True, description="The user connected devices"))
58
+
59
+
60
+ class UsageInputOutputSchema(Schema):
61
+ usages = fields.List(fields.Nested(UsageData), required=True, description="The list of usages")
62
+ # endregion
63
+
64
+
65
+ # region sync
66
+ class SyncInputSchema(Schema):
67
+ # users = fields.List(fields.Nested(UserSchema),required=True,description="The list of users")
68
+ domains = fields.List(fields.Nested(DomainSchema), required=True, description="The list of domains")
69
+ proxies = fields.List(fields.Nested(ProxySchema), required=True, description="The list of proxies")
70
+ # parent_domains = fields.List(fields.Nested(ParentDomainSchema),required=True,description="The list of parent domains")
71
+ # admin_users = fields.List(fields.Nested(AdminSchema),required=True,description="The list of admin users")
72
+ hconfigs = fields.List(fields.Nested(HConfigSchema), required=True, description="The list of configs")
73
+
74
+
75
+ class SyncOutputSchema(Schema):
76
+ users = fields.List(fields.Nested(UserSchema), required=True, description="The list of users")
77
+ admin_users = fields.List(fields.Nested(AdminSchema), required=True, description="The list of admin users")
78
+
79
+ # endregion
80
+
81
+
82
+ # region child status
83
+ class ChildStatusInputSchema(Schema):
84
+ child_unique_id = fields.String(required=True, description="The child's unique id")
85
+
86
+
87
+ class ChildStatusOutputSchema(Schema):
88
+ existance = fields.Boolean(required=True, description="Whether child exists")
89
+
90
+ # end region
91
+
92
+
93
+ # region register
94
+
95
+ class RegisterDataSchema(Schema):
96
+ users = fields.List(fields.Nested(UserSchema), required=True, description="The list of users")
97
+ domains = fields.List(fields.Nested(DomainSchema), required=True, description="The list of domains")
98
+ proxies = fields.List(fields.Nested(ProxySchema), required=True, description="The list of proxies")
99
+ admin_users = fields.List(fields.Nested(AdminSchema), required=True, description="The list of admin users")
100
+ hconfigs = fields.List(fields.Nested(HConfigSchema), required=True, description="The list of configs")
101
+
102
+
103
+ class RegisterInputSchema(Schema):
104
+ panel_data = fields.Nested(RegisterDataSchema, required=True, description="The child's data")
105
+ unique_id = fields.String(required=True, description="The child's unique id")
106
+ name = fields.String(required=True, description="The child's name")
107
+ mode = fields.Enum(ChildMode, required=True, description="The child's mode")
108
+
109
+
110
+ class RegisterOutputSchema(Schema):
111
+ parent_unique_id = fields.String(description="The parent's unique id")
112
+ users = fields.List(fields.Nested(UserSchema), required=True, description="The list of users")
113
+ admin_users = fields.List(fields.Nested(AdminSchema), required=True, description="The list of admin users")
114
+
115
+ # endregion
@@ -0,0 +1,26 @@
1
+ from flask.views import MethodView
2
+ from flask import current_app as app
3
+ from loguru import logger
4
+
5
+ from hiddifypanel.models import Child, Role
6
+ from hiddifypanel.auth import login_required
7
+
8
+ from .schema import ChildStatusInputSchema, ChildStatusOutputSchema
9
+
10
+
11
+ class StatusApi(MethodView):
12
+ decorators = [login_required(node_auth=True)]
13
+
14
+ @app.input(ChildStatusInputSchema, arg_name='data') # type: ignore
15
+ @app.output(ChildStatusOutputSchema) # type: ignore
16
+ def post(self, data):
17
+ logger.info(f"Checking the existence of child with unique_id: {data['child_unique_id']}")
18
+ res = ChildStatusOutputSchema()
19
+ res.existance = False # type: ignore
20
+
21
+ child = Child.query.filter(Child.unique_id == data['child_unique_id']).first()
22
+ if child:
23
+ logger.info(f"Child with unique_id: {data['child_unique_id']} exists")
24
+ res.existance = True # type: ignore
25
+
26
+ return res
@@ -0,0 +1,53 @@
1
+
2
+ from flask.views import MethodView
3
+ from flask import current_app as app
4
+ from flask import g
5
+ from apiflask import abort
6
+
7
+ from hiddifypanel.models.user import User
8
+ from hiddifypanel.database import db
9
+ from hiddifypanel.models.child import Child
10
+ from loguru import logger
11
+ from hiddifypanel.models import *
12
+ from hiddifypanel.auth import login_required
13
+ from .schema import SyncInputSchema, SyncOutputSchema
14
+
15
+
16
+ class SyncApi(MethodView):
17
+ decorators = [login_required(node_auth=True)]
18
+
19
+ @app.input(SyncInputSchema, arg_name='data') # type: ignore
20
+ @app.output(SyncOutputSchema) # type: ignore
21
+ def put(self, data):
22
+ from hiddifypanel import hutils
23
+ unique_id = Child.node.unique_id
24
+
25
+ logger.info(f"Sync child with unique_id: {unique_id}")
26
+ if not hutils.node.is_parent():
27
+ logger.error("Not a parent")
28
+ abort(400, "Not a parent")
29
+
30
+ child = Child.query.filter(Child.unique_id == unique_id).first()
31
+ if not child:
32
+ logger.error("The child does not exist")
33
+ abort(404, "The child does not exist")
34
+
35
+ try:
36
+ logger.info("Syncing domains...")
37
+ bulk_register_domains(data['domains'], commit=False, force_child_unique_id=child.unique_id)
38
+ logger.info("Syncing hconfigs...")
39
+ bulk_register_configs(data['hconfigs'], commit=False, froce_child_unique_id=child.unique_id)
40
+ logger.info("Syncing proxies...")
41
+ Proxy.bulk_register(data['proxies'], commit=False, force_child_unique_id=child.unique_id)
42
+ db.session.commit() # type: ignore
43
+ except Exception as err:
44
+ with logger.contextualize(error=err):
45
+ logger.error(f"Error while syncing data")
46
+ abort(400, str(err))
47
+
48
+ res = SyncOutputSchema()
49
+ res.users = [u.to_schema() for u in User.query.all()] # type: ignore
50
+ res.admin_users = [a.to_schema() for a in AdminUser.query.all()] # type: ignore
51
+
52
+ logger.info("Returning sync output")
53
+ return res
@@ -0,0 +1,57 @@
1
+ from apiflask import abort
2
+ from flask.views import MethodView
3
+ from flask import current_app as app
4
+ from flask import g
5
+ from loguru import logger
6
+
7
+ from hiddifypanel.models import Child
8
+ from hiddifypanel.panel.usage import add_users_usage_uuid
9
+ from hiddifypanel.auth import login_required
10
+
11
+ from .schema import UsageInputOutputSchema
12
+
13
+
14
+ class UsageApi(MethodView):
15
+ decorators = [login_required(node_auth=True)]
16
+
17
+ @app.input(UsageInputOutputSchema, arg_name='data') # type: ignore
18
+ @app.output(UsageInputOutputSchema) # type: ignore
19
+ def put(self, data):
20
+ from hiddifypanel import hutils
21
+ child = Child.query.filter(Child.unique_id == Child.node.unique_id).first()
22
+ if not child:
23
+ logger.error("The child does not exist")
24
+ abort(400, "The child does not exist")
25
+
26
+ # parse request data
27
+ logger.debug(f"Received Usage data from child: {data}")
28
+ child_usages_data = hutils.node.convert_usage_api_response_to_dict(data)
29
+
30
+ # get current usage
31
+ logger.debug("Getting current usage data from parent")
32
+ parent_current_usages_data = hutils.node.convert_usage_api_response_to_dict(UsageInputOutputSchema().dump(hutils.node.get_users_usage_data_for_api())) # type: ignore
33
+
34
+ # calculate usages
35
+ logger.debug("Calculating increased usages")
36
+ increased_usages = self.__calculate_parent_increased_usages(child_usages_data, parent_current_usages_data)
37
+ logger.debug(f"Increased usages: {increased_usages}")
38
+
39
+ # add users usage
40
+ if increased_usages:
41
+ logger.info(f"Adding increased usages to parent: {increased_usages}")
42
+ add_users_usage_uuid(increased_usages, child.id)
43
+
44
+ return hutils.node.get_users_usage_data_for_api()
45
+
46
+ def __calculate_parent_increased_usages(self, child_usages_data: dict, parent_usages_data: dict) -> dict:
47
+ res = {}
48
+ for p_uuid, p_usage in parent_usages_data.items():
49
+ if child_usage := child_usages_data.get(p_uuid):
50
+ if child_usage['usage'] > 0:
51
+ usage_data = {
52
+ 'usage': child_usage['usage'] - p_usage['usage'],
53
+ 'devices': child_usage['devices'],
54
+ }
55
+ if usage_data['usage'] > 0:
56
+ res[p_uuid] = usage_data
57
+ return res
@@ -138,8 +138,7 @@ def create_package(call): # <- passes a CallbackQuery type object to your funct
138
138
  domain = int(splt[4])
139
139
  new_text = _("Please Wait...")
140
140
  bot.edit_message_text(new_text, call.message.chat.id, call.message.message_id, reply_markup=None)
141
- DT = (ParentDomain if hconfig(ConfigEnum.is_parent) else Domain)
142
- domain = DT.query.filter(DT.id == domain).first()
141
+ domain = Domain.query.filter(Domain.id == domain).first()
143
142
  from . import Usage
144
143
  admin_id = admin.id
145
144
  admin_name = admin.name
@@ -18,6 +18,8 @@ def init_app(app: APIFlask):
18
18
  app.jinja_env.globals['UserMode'] = UserMode
19
19
  app.jinja_env.globals['hconfig'] = hconfig
20
20
  app.jinja_env.globals['g'] = g
21
+ app.jinja_env.globals['hutils'] = hutils
22
+ app.jinja_env.globals['hiddify'] = hiddify
21
23
  app.jinja_env.globals['version'] = hiddifypanel.__version__
22
24
  app.jinja_env.globals['static_url_for'] = hutils.flask.static_url_for
23
25
  app.jinja_env.globals['hurl_for'] = hutils.flask.hurl_for
@@ -34,6 +36,12 @@ def init_app(app: APIFlask):
34
36
 
35
37
  @app.errorhandler(Exception)
36
38
  def internal_server_error(e):
39
+ if isinstance(e, Exception):
40
+ if hutils.flask.is_api_call(request.path):
41
+ return {
42
+ 'msg': str(e),
43
+ }, 500
44
+
37
45
  if hasattr(e, 'code') and e.code == 404:
38
46
  return jsonify({
39
47
  'message': 'Not Found',
@@ -68,6 +76,7 @@ def init_app(app: APIFlask):
68
76
  # print(request.headers)
69
77
  if not request.accept_mimetypes.accept_html:
70
78
  return app.error_callback(e)
79
+ # if it's interval server error
71
80
  if e.status_code == 500:
72
81
  trace = traceback.format_exc()
73
82
 
@@ -81,9 +90,17 @@ def init_app(app: APIFlask):
81
90
  has_update = "dev" not in hiddifypanel.__version__ and f'{last_version}' != hiddifypanel.__version__
82
91
 
83
92
  return render_template('500.html', error=e, trace=trace, has_update=has_update, last_version=last_version, issue_link=issue_link), 500
93
+
94
+ # if it's access denied error
84
95
  # if e.status_code in [400,401,403]:
85
96
  # return render_template('access-denied.html',error=e), e.status_code
86
97
 
98
+ # if it's api error
99
+ if hutils.flask.is_api_call(request.path):
100
+ return {
101
+ 'msg': e.message,
102
+ }, e.status_code
103
+
87
104
  return render_template('error.html', error=e), e.status_code
88
105
 
89
106
  @app.url_defaults
@@ -133,12 +150,6 @@ def init_app(app: APIFlask):
133
150
  g.child = Child.by_id(g.__child_id) or abort(404, "Child not found")
134
151
  g.account = current_account
135
152
 
136
- @app.before_first_request
137
- def first_request():
138
- import hiddifypanel.panel.commercial.telegrambot as telegrambot
139
- if (not telegrambot.bot) or (not telegrambot.bot.username): # type: ignore
140
- telegrambot.register_bot(set_hook=True)
141
-
142
153
  @app.before_request
143
154
  def base_middleware():
144
155
  if request.endpoint == 'static' or request.endpoint == "videos":
@@ -174,3 +185,7 @@ def init_app(app: APIFlask):
174
185
  return auth_before
175
186
 
176
187
  app.jinja_env.globals['generate_github_issue_link_for_admin_sidebar'] = hutils.github_issue.generate_github_issue_link_for_admin_sidebar
188
+ with app.app_context():
189
+ import hiddifypanel.panel.commercial.telegrambot as telegrambot
190
+ if (not telegrambot.bot) or (not telegrambot.bot.username): # type: ignore
191
+ telegrambot.register_bot(set_hook=True)
@@ -1,22 +1,16 @@
1
- import glob
2
1
  import re
3
- import json
4
2
  import subprocess
5
3
 
6
4
  from datetime import datetime
7
5
  from typing import Tuple
8
- from cryptography.hazmat.primitives import serialization
9
- from cryptography.hazmat.primitives.asymmetric import x25519
10
6
  from flask import current_app, g
11
7
  from flask_babel import lazy_gettext as _
12
- from flask_babel import gettext as __
13
8
  from datetime import timedelta
14
9
 
15
10
  from hiddifypanel.cache import cache
16
11
  from hiddifypanel.models import *
17
12
  from hiddifypanel.database import db
18
13
  from hiddifypanel.hutils.utils import *
19
- from hiddifypanel.Events import domain_changed
20
14
  from hiddifypanel import hutils
21
15
  from hiddifypanel.panel.run_commander import commander, Command
22
16
  import subprocess
@@ -69,23 +63,9 @@ def exec_command(cmd, cwd=None):
69
63
 
70
64
 
71
65
  def quick_apply_users():
72
- if hconfig(ConfigEnum.is_parent):
73
- return
74
- # from hiddifypanel.panel import usage
75
- # usage.update_local_usage()
76
- # return
77
- # for user in User.query.all():
78
- # if user.is_active:
79
- # xray_api.add_client(user.uuid)
80
- # else:
81
- # xray_api.remove_client(user.uuid)
82
-
83
- # exec_command("sudo /opt/hiddify-manager/install.sh apply_users --no-gui")
84
-
85
66
  # run install.sh apply_users
86
67
  commander(Command.apply_users)
87
68
 
88
- # time.sleep(1)
89
69
  return {"status": 'success'}
90
70
 
91
71
 
@@ -145,11 +125,12 @@ def check_need_reset(old_configs, do=False):
145
125
 
146
126
 
147
127
  def get_child(unique_id):
148
- child_id = Child.current.id
128
+ child_id = Child.current().id
149
129
  if unique_id is None or unique_id in ["self", "default", str(hconfig(ConfigEnum.unique_id))]:
150
130
  child_id = 0
151
131
  else:
152
132
  child = Child.query.filter(Child.unique_id == str(unique_id)).first()
133
+ # TODO: this doesn't work because name and mode fields are nullable
153
134
  if not child:
154
135
  child = Child(unique_id=str(unique_id))
155
136
  db.session.add(child)
@@ -164,7 +145,7 @@ def dump_db_to_dict():
164
145
  "users": [u.to_dict() for u in User.query.all()],
165
146
  "domains": [u.to_dict() for u in Domain.query.all()],
166
147
  "proxies": [u.to_dict() for u in Proxy.query.all()],
167
- "parent_domains": [] if not hconfig(ConfigEnum.license) else [u.to_dict() for u in ParentDomain.query.all()],
148
+ # "parent_domains": [] if not hconfig(ConfigEnum.license) else [u.to_dict() for u in ParentDomain.query.all()],
168
149
  'admin_users': [d.to_dict() for d in AdminUser.query.all()],
169
150
  "hconfigs": [*[u.to_dict() for u in BoolConfig.query.all()],
170
151
  *[u.to_dict() for u in StrConfig.query.all()]]
@@ -195,7 +176,7 @@ def set_db_from_json(json_data, override_child_unique_id=True, set_users=True, s
195
176
  # override root child unique id
196
177
  if override_child_unique_id:
197
178
  backup_child_unique_id = get_backup_child_unique_id(json_data)
198
- replace_backup_child_unique_id(json_data, backup_child_unique_id, Child.current.unique_id)
179
+ replace_backup_child_unique_id(json_data, backup_child_unique_id, Child.current().unique_id)
199
180
 
200
181
  # restore childs
201
182
  if set_child and 'childs' in json_data:
@@ -243,13 +224,12 @@ def set_db_from_json(json_data, override_child_unique_id=True, set_users=True, s
243
224
  if set_users and 'users' in json_data:
244
225
  User.bulk_register(json_data['users'], commit=False, remove=remove_users)
245
226
  if set_domains and 'domains' in json_data:
246
- bulk_register_domains(json_data['domains'], commit=False, remove=remove_domains, override_child_unique_id=override_child_unique_id)
247
- # if set_domains and 'parent_domains' in json_data:
248
- # ParentDomain.bulk_register(json_data['parent_domains'], commit=False, remove=remove_domains)
227
+ bulk_register_domains(json_data['domains'], commit=False, remove=remove_domains)
228
+
249
229
  if set_settings and 'hconfigs' in json_data:
250
- bulk_register_configs(json_data["hconfigs"], commit=True, override_child_unique_id=override_child_unique_id, override_unique_id=override_unique_id)
230
+ bulk_register_configs(json_data["hconfigs"], commit=True, override_unique_id=override_unique_id)
251
231
  if 'proxies' in json_data:
252
- Proxy.bulk_register(json_data['proxies'], commit=False, override_child_unique_id=override_child_unique_id)
232
+ Proxy.bulk_register(json_data['proxies'], commit=False)
253
233
 
254
234
  ids_without_parent = get_ids_without_parent({u.id: u.to_dict() for u in AdminUser.query.all()})
255
235
  owner = AdminUser.get_super_admin()
@@ -276,49 +256,13 @@ def get_domain_btn_link(domain):
276
256
  return res
277
257
 
278
258
 
279
- def debug_flash_if_not_in_the_same_asn(domain):
280
- from hiddifypanel.hutils.network.auto_ip_selector import IPASN
281
- ipv4 = hutils.network.get_ip_str(4)
282
- dip = hutils.network.get_domain_ip(domain)
283
- try:
284
- if IPASN:
285
- asn_ipv4 = IPASN.get(ipv4)
286
- asn_dip = IPASN.get(dip)
287
- # country_ipv4= ipcountry.get(ipv4)
288
- # country_dip= ipcountry.get(dip)
289
- if asn_ipv4.get('autonomous_system_organization') != asn_dip.get('autonomous_system_organization'):
290
- hutils.flask.flash(_("selected domain for REALITY is not in the same ASN. To better use of the protocol, it is better to find a domain in the same ASN.") +
291
- f"<br> Server ASN={asn_ipv4.get('autonomous_system_organization','unknown')}<br>{domain}_ASN={asn_dip.get('autonomous_system_organization','unknown')}", "warning")
292
- except BaseException:
293
- pass
294
-
295
-
296
- def generate_x25519_keys():
297
- priv = x25519.X25519PrivateKey.generate()
298
- pub = priv.public_key()
299
- priv_bytes = priv.private_bytes(
300
- encoding=serialization.Encoding.Raw,
301
- format=serialization.PrivateFormat.Raw,
302
- encryption_algorithm=serialization.NoEncryption()
303
- )
304
- pub_bytes = pub.public_bytes(
305
- encoding=serialization.Encoding.Raw,
306
- format=serialization.PublicFormat.Raw
307
- )
308
- import base64
309
- pub_str = base64.urlsafe_b64encode(pub_bytes).decode()[:-1]
310
- priv_str = base64.urlsafe_b64encode(priv_bytes).decode()[:-1]
311
-
312
- return {'private_key': priv_str, 'public_key': pub_str}
313
-
314
-
315
259
  def get_ssh_client_version(user):
316
260
  return 'SSH-2.0-OpenSSH_7.4p1'
317
261
 
318
262
 
319
263
  def get_account_panel_link(account: BaseAccount, host: str, is_https: bool = True, prefere_path_only: bool = False, child_id=None):
320
264
  if child_id is None:
321
- child_id = Child.current.id
265
+ child_id = Child.current().id
322
266
  is_admin = isinstance(account, AdminUser)
323
267
  basic_auth = False # is_admin #because safri does not support it.
324
268
 
@@ -363,11 +307,8 @@ def clone_model(model):
363
307
  for k in table.columns.keys():
364
308
  if k == "id":
365
309
  continue
366
- # if k in table.primary_key:
367
- # continue
368
310
  setattr(new_model, f'{k}', getattr(model, k))
369
311
 
370
- # data.pop('id')
371
312
  return new_model
372
313
 
373
314
 
@@ -392,18 +333,6 @@ def get_backup_child_unique_id(backupdata: dict) -> str:
392
333
  return "self"
393
334
  return backupdata['childs'][0]['unique_id']
394
335
 
395
- # for k, v in backupdata.items():
396
- # if k == 'admin_users' or k == 'users':
397
- # continue
398
- # if k == 'childs':
399
- # if len(v) < 1:
400
- # continue
401
- # return v[0]['unique_id']
402
- # else:
403
- # for item in v:
404
- # return item['child_unique_id']
405
- # return 'self'
406
-
407
336
 
408
337
  def is_hiddify_next_version(major_v: int = 0, minor_v: int = 0, patch_v: int = 0) -> bool:
409
338
  '''If the user agent version be equals or higher than parameters returns True'''