nopoh22 commited on
Commit
cdb1269
·
verified ·
1 Parent(s): 1308519

Update renewer.py

Browse files
Files changed (1) hide show
  1. renewer.py +96 -53
renewer.py CHANGED
@@ -11,19 +11,93 @@ logging.basicConfig(
11
  )
12
  logger = logging.getLogger(__name__)
13
 
14
- ACCOUNTS_FILE = "accounts.json"
15
 
16
 
17
- def load_accounts():
18
- if os.path.exists(ACCOUNTS_FILE):
19
- with open(ACCOUNTS_FILE, "r") as f:
20
  return json.load(f)
21
- return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
 
24
  def save_accounts(accounts):
25
- with open(ACCOUNTS_FILE, "w") as f:
26
- json.dump(accounts, f, indent=2)
 
 
 
 
 
 
 
 
27
 
28
 
29
  def get_host(username, token):
@@ -45,7 +119,6 @@ def extend_webapp(username, password, host="www.pythonanywhere.com"):
45
  session = requests.Session()
46
  results = []
47
 
48
- # headers تحاكي المتصفح تماماً
49
  session.headers.update({
50
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
51
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
@@ -53,44 +126,33 @@ def extend_webapp(username, password, host="www.pythonanywhere.com"):
53
  })
54
 
55
  try:
56
- # ── الخطوة 1: فتح صفحة تسجيل الدخول ──
57
  login_url = f"https://{host}/login/"
58
  login_page = session.get(login_url, timeout=15)
59
  logger.info(f"[{username}] صفحة الدخول: {login_page.status_code}")
60
 
61
  soup = BeautifulSoup(login_page.text, "html.parser")
62
-
63
- # اجلب كل حقول الـ form تلقائياً
64
  form = soup.find("form")
65
  if not form:
66
- logger.error(f"[{username}] لم يتم العثور على form في صفحة الدخول")
67
  return []
68
 
69
- # ابدأ بكل الحقول الموجودة في الـ form (hidden fields)
70
  form_data = {}
71
  for inp in form.find_all("input"):
72
- name = inp.get("name")
73
- value = inp.get("value", "")
74
  if name:
75
- form_data[name] = value
76
-
77
- logger.info(f"[{username}] حقول الـ form: {list(form_data.keys())}")
78
 
79
- # أضف ب��انات الدخول
80
  form_data["auth-username"] = username
81
  form_data["auth-password"] = password
82
-
83
- # بعض إصدارات الموقع تحتاج هذا الحقل
84
  if "login_view-current_step" not in form_data:
85
  form_data["login_view-current_step"] = "auth"
86
 
87
- # ── الخطوة 2: إرسال بيانات الدخول ──
88
  form_action = form.get("action") or login_url
89
  if not form_action.startswith("http"):
90
  form_action = f"https://{host}{form_action}"
91
 
92
- logger.info(f"[{username}] إرسال الدخول إلى: {form_action}")
93
-
94
  login_resp = session.post(
95
  form_action,
96
  data=form_data,
@@ -102,41 +164,26 @@ def extend_webapp(username, password, host="www.pythonanywhere.com"):
102
  timeout=15,
103
  allow_redirects=True
104
  )
105
- logger.info(f"[{username}] نتيجة الدخول: {login_resp.status_code} | URL: {login_resp.url}")
106
 
107
- # ── التحقق من نجاح تسجيل الدخول ──
108
- cookies = session.cookies.get_dict()
109
- logger.info(f"[{username}] الكوكيز: {list(cookies.keys())}")
110
-
111
- if "sessionid" not in cookies:
112
- logger.error(f"[{username}] لم يتم إنشاء sessionid — فشل تسجيل الدخول")
113
  return []
114
 
115
- if "login" in login_resp.url.lower() and login_resp.status_code != 200:
116
- logger.error(f"[{username}] ما زال على صفحة login — فشل")
117
- return []
118
 
119
- logger.info(f"[{username}] ✅ تم تسجيل الدخول بنجاح")
120
-
121
- # ── الخطوة 3: فتح صفحة الويب آب وجلب CSRF جديد ──
122
  webapps_url = f"https://{host}/user/{username}/webapps/"
123
  page = session.get(webapps_url, timeout=15)
124
- logger.info(f"[{username}] صفحة الويب آب: {page.status_code}")
125
 
126
  soup = BeautifulSoup(page.text, "html.parser")
127
  csrf_input = soup.find("input", {"name": "csrfmiddlewaretoken"})
128
- if not csrf_input:
129
- meta = soup.find("meta", {"name": "csrf-token"})
130
- csrf = meta.get("content", "") if meta else ""
131
- else:
132
- csrf = csrf_input["value"]
133
-
134
  if not csrf:
135
- logger.error(f"[{username}] لم يتم العثور على CSRF في صفحة الويب آب")
136
  return []
137
- logger.info(f"[{username}] CSRF الويب آب: {csrf[:10]}...")
138
 
139
- # ── الخطوة 4: اكتشاف النطاقات ──
140
  domains = []
141
  for link in soup.find_all("a", href=True):
142
  href = link["href"]
@@ -147,11 +194,8 @@ def extend_webapp(username, password, host="www.pythonanywhere.com"):
147
 
148
  if not domains:
149
  domains = [f"{username}.pythonanywhere.com"]
150
- logger.warning(f"[{username}] النطاق الافتراضي: {domains[0]}")
151
- else:
152
- logger.info(f"[{username}] النطاقات: {domains}")
153
 
154
- # ── الخطوة 5: إرسال طلب التمديد ──
155
  for domain in domains:
156
  extend_url = f"https://{host}/user/{username}/webapps/{domain}/extend"
157
  resp = session.post(
@@ -165,7 +209,6 @@ def extend_webapp(username, password, host="www.pythonanywhere.com"):
165
  timeout=15
166
  )
167
  logger.info(f"[{username}] Extend {domain}: HTTP {resp.status_code}")
168
-
169
  status = "✅ تم التمديد" if resp.status_code in (200, 302) else f"❌ فشل ({resp.status_code})"
170
  results.append({"domain": domain, "status": status})
171
 
@@ -198,7 +241,7 @@ def renew_account(account):
198
  def run_renewals():
199
  accounts = load_accounts()
200
  if not accounts:
201
- logger.info("لا توجد حسابات.")
202
  return
203
 
204
  now = datetime.utcnow()
 
11
  )
12
  logger = logging.getLogger(__name__)
13
 
14
+ STATE_FILE = "renewal_state.json"
15
 
16
 
17
+ def load_state():
18
+ if os.path.exists(STATE_FILE):
19
+ with open(STATE_FILE, "r") as f:
20
  return json.load(f)
21
+ return {}
22
+
23
+
24
+ def save_state(state):
25
+ with open(STATE_FILE, "w") as f:
26
+ json.dump(state, f, indent=2)
27
+
28
+
29
+ def load_accounts():
30
+ """
31
+ يقرأ الحسابات من Environment Variables بأي من الصيغ التالية:
32
+
33
+ الصيغة 1 — متغيرات مرقّمة (الموصى بها):
34
+ ACCOUNTS_1 = username1:password1
35
+ ACCOUNTS_2 = username2:password2
36
+ ACCOUNTS_3 = username3:password3
37
+
38
+ الصيغة 2 — متغير واحد يحتوي الكل (مفصولة بفاصلة):
39
+ ACCOUNTS = username1:password1,username2:password2
40
+
41
+ يمكن الجمع بين الصيغتين — سيتم دمج الكل بدون تكرار.
42
+ """
43
+ state = load_state()
44
+ accounts = []
45
+ seen = set()
46
+
47
+ def add_account(username, password):
48
+ if not username or not password or username in seen:
49
+ return
50
+ seen.add(username)
51
+ user_state = state.get(username, {})
52
+ accounts.append({
53
+ "username": username,
54
+ "password": password,
55
+ "host": user_state.get("host", "www.pythonanywhere.com"),
56
+ "last_renewed": user_state.get("last_renewed"),
57
+ "next_renewal": user_state.get("next_renewal"),
58
+ "last_results": user_state.get("last_results", []),
59
+ })
60
+
61
+ def parse_entry(entry):
62
+ entry = entry.strip()
63
+ if ":" in entry:
64
+ username, password = entry.split(":", 1)
65
+ add_account(username.strip(), password.strip())
66
+
67
+ # ── الصيغة 1: ACCOUNTS_1, ACCOUNTS_2, ACCOUNTS_3 ... ──
68
+ i = 1
69
+ while True:
70
+ entry = os.environ.get(f"ACCOUNTS_{i}", "").strip()
71
+ if not entry:
72
+ break
73
+ parse_entry(entry)
74
+ i += 1
75
+
76
+ # ── الصيغة 2: ACCOUNTS = user1:pass1,user2:pass2 ──
77
+ accounts_env = os.environ.get("ACCOUNTS", "").strip()
78
+ if accounts_env:
79
+ for entry in accounts_env.split(","):
80
+ parse_entry(entry)
81
+
82
+ if accounts:
83
+ logger.info(f"تم تحميل {len(accounts)} حساب: {[a['username'] for a in accounts]}")
84
+ else:
85
+ logger.warning("لم يتم العثور على حسابات — أضف ACCOUNTS_1 أو ACCOUNTS في Secrets")
86
+
87
+ return accounts
88
 
89
 
90
  def save_accounts(accounts):
91
+ """يحفظ حالة التجديد فقط — كلمات المرور تبقى في Secrets"""
92
+ state = {}
93
+ for a in accounts:
94
+ state[a["username"]] = {
95
+ "host": a.get("host", "www.pythonanywhere.com"),
96
+ "last_renewed": a.get("last_renewed"),
97
+ "next_renewal": a.get("next_renewal"),
98
+ "last_results": a.get("last_results", []),
99
+ }
100
+ save_state(state)
101
 
102
 
103
  def get_host(username, token):
 
119
  session = requests.Session()
120
  results = []
121
 
 
122
  session.headers.update({
123
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
124
  "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
 
126
  })
127
 
128
  try:
129
+ # الخطوة 1: صفحة الدخول
130
  login_url = f"https://{host}/login/"
131
  login_page = session.get(login_url, timeout=15)
132
  logger.info(f"[{username}] صفحة الدخول: {login_page.status_code}")
133
 
134
  soup = BeautifulSoup(login_page.text, "html.parser")
 
 
135
  form = soup.find("form")
136
  if not form:
137
+ logger.error(f"[{username}] لم يتم العثور على form")
138
  return []
139
 
 
140
  form_data = {}
141
  for inp in form.find_all("input"):
142
+ name = inp.get("name")
 
143
  if name:
144
+ form_data[name] = inp.get("value", "")
 
 
145
 
 
146
  form_data["auth-username"] = username
147
  form_data["auth-password"] = password
 
 
148
  if "login_view-current_step" not in form_data:
149
  form_data["login_view-current_step"] = "auth"
150
 
151
+ # الخطوة 2: تسجيل الدخول
152
  form_action = form.get("action") or login_url
153
  if not form_action.startswith("http"):
154
  form_action = f"https://{host}{form_action}"
155
 
 
 
156
  login_resp = session.post(
157
  form_action,
158
  data=form_data,
 
164
  timeout=15,
165
  allow_redirects=True
166
  )
167
+ logger.info(f"[{username}] نتيجة الدخول: {login_resp.status_code} | {login_resp.url}")
168
 
169
+ if "sessionid" not in session.cookies.get_dict():
170
+ logger.error(f"[{username}] فشل تسجيل الدخول — لا يوجد sessionid")
 
 
 
 
171
  return []
172
 
173
+ logger.info(f"[{username}] ✅ تم تسجيل الدخول")
 
 
174
 
175
+ # الخطوة 3: صفحة الويب آب
 
 
176
  webapps_url = f"https://{host}/user/{username}/webapps/"
177
  page = session.get(webapps_url, timeout=15)
 
178
 
179
  soup = BeautifulSoup(page.text, "html.parser")
180
  csrf_input = soup.find("input", {"name": "csrfmiddlewaretoken"})
181
+ csrf = csrf_input["value"] if csrf_input else ""
 
 
 
 
 
182
  if not csrf:
183
+ logger.error(f"[{username}] لم يتم العثور على CSRF")
184
  return []
 
185
 
186
+ # الخطوة 4: اكتشاف النطاقات
187
  domains = []
188
  for link in soup.find_all("a", href=True):
189
  href = link["href"]
 
194
 
195
  if not domains:
196
  domains = [f"{username}.pythonanywhere.com"]
 
 
 
197
 
198
+ # الخطوة 5: التمديد
199
  for domain in domains:
200
  extend_url = f"https://{host}/user/{username}/webapps/{domain}/extend"
201
  resp = session.post(
 
209
  timeout=15
210
  )
211
  logger.info(f"[{username}] Extend {domain}: HTTP {resp.status_code}")
 
212
  status = "✅ تم التمديد" if resp.status_code in (200, 302) else f"❌ فشل ({resp.status_code})"
213
  results.append({"domain": domain, "status": status})
214
 
 
241
  def run_renewals():
242
  accounts = load_accounts()
243
  if not accounts:
244
+ logger.info("لا توجد حسابات — أضف ACCOUNTS_1 أو ACCOUNTS في Secrets.")
245
  return
246
 
247
  now = datetime.utcnow()