UAForge 1.1.0__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.
@@ -0,0 +1,411 @@
1
+ import datetime
2
+ from typing import Dict, List, Tuple, Any
3
+
4
+ from .database import Database
5
+ from .version_fetcher import VersionFetcher
6
+ import random
7
+
8
+ class VersionUpdater:
9
+ def __init__(self, db_path: str = None):
10
+ self.db = Database(db_path)
11
+ self.fetcher = VersionFetcher()
12
+
13
+ self.windows_versions = [
14
+ "Windows NT 6.0", # Vista
15
+ "Windows NT 6.1", # 7
16
+ "Windows NT 6.2", # 8
17
+ "Windows NT 6.3", # 8.1
18
+ "Windows NT 10.0" # 10/11
19
+ ]
20
+
21
+ self.linux_versions = [
22
+ "X11; Linux",
23
+ "X11; Ubuntu; Linux"
24
+ ]
25
+
26
+ self.version_types = {
27
+ "Windows": ["Win64; x64", "WOW64"],
28
+ "Linux": ["i686", "x86_64", "i686 on x86_64"],
29
+ "Mac": [""],
30
+ "Android": ["armv7l", "armv8l"]
31
+ }
32
+
33
+ self.platforms = {
34
+ "Windows": self.windows_versions,
35
+ "Linux": self.linux_versions,
36
+ "Mac": self._generate_mac_systems(),
37
+ "Android": self._generate_android_systems()
38
+ }
39
+
40
+ def _generate_mac_systems(self) -> List[str]:
41
+ """
42
+ Generates a list of macOS system strings for various Apple devices and OS versions.
43
+ Returns:
44
+ List[str]: A list of strings representing different combinations of Apple devices
45
+ (iPhone, iPad, Macintosh) and macOS versions, formatted as
46
+ "<Device>; Intel Mac OS X <version>".
47
+ """
48
+ devices = ["iPhone", "iPad", "Macintosh"]
49
+ versions = ["10_15_7", "11_6", "12_0", "13_0", "14_0"]
50
+ systems = []
51
+
52
+ for device in devices:
53
+ for version in versions:
54
+ systems.append(f"{device}; Intel Mac OS X {version}")
55
+
56
+ return systems
57
+
58
+ def _generate_android_systems(self) -> List[str]:
59
+ devices = [
60
+ "Linux; Android 10",
61
+ "Linux; Android 11",
62
+ "Linux; Android 12",
63
+ "Linux; Android 13",
64
+ "Linux; Android 14"
65
+ ]
66
+ return devices
67
+
68
+ def update_chrome(self) -> Tuple[int, int]:
69
+ """
70
+ Updates the Chrome version information in the database by comparing fetched web data with current records.
71
+ Fetches the latest Chrome version data using the fetcher, compares it with the versions stored in the database,
72
+ and determines which versions need to be added or updated. If there are new or updated versions, it updates the
73
+ database accordingly.
74
+ Returns:
75
+ Tuple[int, int]: A tuple containing the number of versions added and the number of versions updated.
76
+ Exceptions:
77
+ Catches all exceptions, prints an error message, and returns (0, 0) in case of failure.
78
+ """
79
+ try:
80
+ web_data = self.fetcher.fetch_chrome_versions()
81
+ current_versions, current_data = self.db.get_chrome_vers()
82
+
83
+ dt_add = []
84
+ dt_update = []
85
+ now = datetime.datetime.now().isoformat()
86
+
87
+ for version, date in web_data["Version_dict"].items():
88
+ chrome_version = f"Chrome/{version.strip()}"
89
+
90
+ if chrome_version in current_versions:
91
+ idx = current_versions.index(chrome_version)
92
+ original_date = current_data[idx][1]
93
+
94
+ if date != original_date:
95
+ dt_update.append((chrome_version, date, now))
96
+ else:
97
+ dt_add.append((chrome_version, date, now))
98
+
99
+ if dt_add or dt_update:
100
+ self.db.add_chrome_versions(dt_add, dt_update)
101
+
102
+ return len(dt_add), len(dt_update)
103
+
104
+ except Exception as e:
105
+ print(f"Chrome update error: {e}")
106
+ return 0, 0
107
+
108
+ def update_firefox(self) -> Tuple[int, int]:
109
+ """
110
+ Updates the Firefox version information in the database by comparing fetched web data with current records.
111
+ Fetches the latest Firefox version data from the web, compares it with the versions stored in the database,
112
+ and determines which versions need to be added or updated based on their release dates. If there are new or
113
+ updated versions, it updates the database accordingly.
114
+ Returns:
115
+ Tuple[int, int]: A tuple containing the number of versions added and the number of versions updated.
116
+ Exceptions:
117
+ Catches all exceptions, prints an error message, and returns (0, 0) in case of failure.
118
+ """
119
+ try:
120
+ web_data = self.fetcher.fetch_firefox_versions()
121
+ current_versions, current_data = self.db.get_firefox_vers()
122
+
123
+ dt_add = []
124
+ dt_update = []
125
+ now = datetime.datetime.now().isoformat()
126
+ for version, date in web_data["Version_dict"].items():
127
+ if version in current_versions:
128
+ pass
129
+ else:
130
+ dt_add.append((version, date.isoformat() if hasattr(date, 'isoformat') else str(date), now))
131
+
132
+ if dt_add or dt_update:
133
+ self.db.add_firefox_versions(dt_add, dt_update)
134
+
135
+ return len(dt_add), len(dt_update)
136
+
137
+ except Exception as e:
138
+ print(f"Firefox update error: {e}")
139
+ return 0, 0
140
+
141
+ def update_opera(self) -> Tuple[int, int]:
142
+ """
143
+ Updates the Opera browser version information in the database by comparing fetched web data with current records.
144
+ Fetches the latest Opera versions and their release dates from an external source, compares them with the versions stored in the database, and determines which versions need to be added or updated. New or updated versions are then written to the database.
145
+ Returns:
146
+ Tuple[int, int]: A tuple containing the number of new versions added and the number of existing versions updated.
147
+ Exceptions:
148
+ Catches and logs any exceptions that occur during the update process, returning (0, 0) in case of error.
149
+ """
150
+ try :
151
+ web_data = self.fetcher.fetch_opera_versions()
152
+ current_versions, current_data = self.db.get_opera_vers()
153
+
154
+ dt_add = []
155
+ dt_update = []
156
+ now = datetime.datetime.now().isoformat()
157
+ for version, date in web_data["Version_dict"].items():
158
+ if version in current_versions:
159
+ idx = current_versions.index(version)
160
+ original_date = current_data[idx][1]
161
+
162
+ if isinstance(original_date, str) and date != original_date:
163
+ dt_update.append((version, date.isoformat() if hasattr(date, 'isoformat') else str(date), now))
164
+ else:
165
+ dt_add.append((version, date.isoformat() if hasattr(date, 'isoformat') else str(date), now))
166
+
167
+ if dt_add or dt_update:
168
+ self.db.add_opera_versions(dt_add, dt_update)
169
+
170
+ return len(dt_add), len(dt_update)
171
+
172
+ except Exception as e:
173
+ print(f"Opera update error: {e}")
174
+ return 0, 0
175
+
176
+ def update_android(self) -> Tuple[int, int]:
177
+ """
178
+ Update Android versions in the database with the latest data from the web.
179
+ Fetches the latest Android versions from the web, compares them with the
180
+ current versions stored in the database, and updates or adds new versions
181
+ as needed.
182
+ Returns:
183
+ Tuple[int, int]: A tuple containing:
184
+ - Number of new Android versions added (int)
185
+ - Number of existing Android versions updated (int)
186
+ Note:
187
+ If an exception occurs during the update process, the method returns (0, 0)
188
+ and prints an error message to the console.
189
+ """
190
+ try:
191
+ web_data = self.fetcher.fetch_android_versions()
192
+ current_versions, current_data = self.db.get_android_vers()
193
+
194
+ dt_add = []
195
+ dt_update = []
196
+ now = datetime.datetime.now().isoformat()
197
+ for version, date in web_data["Version_dict"].items():
198
+ if version in current_versions:
199
+ pass
200
+ else:
201
+ dt_add.append((version, date.isoformat() if hasattr(date, 'isoformat') else str(date), now))
202
+
203
+ if dt_add or dt_update:
204
+ self.db.add_android_versions(dt_add, dt_update)
205
+
206
+ return len(dt_add), len(dt_update)
207
+
208
+ except Exception as e:
209
+ print(f"Android update error: {e}")
210
+ return 0, 0
211
+
212
+ def update_platforms(self):
213
+ """
214
+ Updates the platforms in the database with the current platforms and systems.
215
+ Iterates over the platforms and their associated systems, prepares the data,
216
+ and adds it to the database using the `add_platforms` method. Handles exceptions
217
+ by printing an error message and returning False.
218
+ Returns:
219
+ bool: True if the platforms were updated successfully, False otherwise.
220
+ """
221
+ try:
222
+ platforms_data = []
223
+ for platform, systems in self.platforms.items():
224
+ for system in systems:
225
+ platforms_data.append((platform, system))
226
+
227
+ self.db.add_platforms(platforms_data)
228
+
229
+ return True
230
+
231
+ except Exception as e:
232
+ print(f"Platform update error: {e}")
233
+ return False
234
+
235
+ def update_version_types(self):
236
+ """
237
+ Updates the version types in the database.
238
+ Iterates over the `version_types` attribute, which is expected to be a dictionary
239
+ mapping platforms to lists of version type strings. Collects all (platform, type)
240
+ pairs and adds them to the database using the `add_version_types` method.
241
+ Returns:
242
+ bool: True if the update was successful, False otherwise.
243
+ Exceptions:
244
+ Catches all exceptions, prints an error message, and returns False if an error occurs.
245
+ """
246
+ try:
247
+ version_types_data = []
248
+ for platform, types in self.version_types.items():
249
+ for type_str in types:
250
+ version_types_data.append((platform, type_str))
251
+
252
+ self.db.add_version_types(version_types_data)
253
+
254
+ return True
255
+
256
+ except Exception as e:
257
+ print(f"Version type update error: {e}")
258
+ return False
259
+
260
+ def update_windows(self) -> Tuple[int, int]:
261
+ """
262
+ Updates the Windows versions in the database by adding any new versions not already present.
263
+ Returns:
264
+ Tuple[int, int]: A tuple where the first element is the number of new versions added,
265
+ and the second element is always 0. If an exception occurs, returns (0, 0).
266
+ Exceptions:
267
+ Catches all exceptions, prints an error message, and returns (0, 0).
268
+ """
269
+ try:
270
+ dt_add = []
271
+ now = datetime.datetime.now().isoformat()
272
+ getting_current_versions = self.db.get_windows_vers()
273
+
274
+ for version in self.windows_versions:
275
+ if version not in getting_current_versions[0]:
276
+ dt_add.append((version, now, now))
277
+
278
+ if dt_add:
279
+ self.db.add_windows_versions(dt_add)
280
+
281
+ return len(dt_add), 0
282
+
283
+ except Exception as e:
284
+ print(f"Windows update error: {e}")
285
+ return 0, 0
286
+
287
+ def update_linux(self) -> Tuple[int, int]:
288
+ try:
289
+ return 0, 0
290
+ except Exception as e:
291
+ print(f"Linux update error: {e}")
292
+ return 0, 0
293
+
294
+ def update_mac(self) -> Tuple[int, int]:
295
+ """
296
+ Updates the local database with new macOS versions fetched from an external source.
297
+ Fetches the latest macOS version information using the fetcher, compares it with the
298
+ versions currently stored in the database, and adds any new versions that are not already present.
299
+ The method records the current timestamp for each new entry. If there are new or updated versions,
300
+ they are added to the database.
301
+ Returns:
302
+ Tuple[int, int]: A tuple containing the number of new versions added and the number of versions updated.
303
+ Exceptions:
304
+ Catches all exceptions, prints an error message, and returns (0, 0) in case of failure.
305
+ """
306
+ try:
307
+ web_data = self.fetcher.fetch_macos_versions()
308
+ current_versions, current_data = self.db.get_macos_vers()
309
+
310
+ dt_add = []
311
+ dt_update = []
312
+ now = datetime.datetime.now().isoformat()
313
+
314
+ for version, date in web_data["Version_dict"].items():
315
+ if version in current_versions:
316
+ pass
317
+ else:
318
+ dt_add.append((version, date.isoformat() if hasattr(date, 'isoformat') else str(date), now))
319
+
320
+ if dt_add or dt_update:
321
+ self.db.add_macos_versions(dt_add, dt_update)
322
+
323
+ return len(dt_add), len(dt_update)
324
+
325
+ except Exception as e:
326
+ print(f"Mac update error: {e}")
327
+ return 0, 0
328
+
329
+ def update_all(self):
330
+ print("All versions are being updated...")
331
+
332
+ self.update_platforms()
333
+ self.update_version_types()
334
+
335
+ results = {}
336
+
337
+ results['Chrome'] = self.update_chrome()
338
+ results['Firefox'] = self.update_firefox()
339
+ results['Opera'] = self.update_opera()
340
+
341
+ results['Android'] = self.update_android()
342
+ results["Mac"] = self.update_mac()
343
+ results['Windows'] = self.update_windows()
344
+ results['Linux'] = self.update_linux()
345
+
346
+ print("\nUpdate Results:")
347
+ print("-" * 40)
348
+ total_added = 0
349
+ total_updated = 0
350
+
351
+ for name, (added, updated) in results.items():
352
+ print(f" {name}: +{added} added, {updated} updated")
353
+ total_added += added
354
+ total_updated += updated
355
+
356
+ print("-" * 40)
357
+ print(f" Total: +{total_added} added, {total_updated} updated")
358
+
359
+ return results
360
+
361
+ def initialize_database(self):
362
+ print("The database is being populated with initial data...")
363
+
364
+ chrome_versions = [
365
+ ("Chrome/120.0.0.0", "2023-12-01", datetime.datetime.now().isoformat()),
366
+ ("Chrome/119.0.0.0", "2023-11-01", datetime.datetime.now().isoformat()),
367
+ ("Chrome/118.0.0.0", "2023-10-01", datetime.datetime.now().isoformat()),
368
+ ]
369
+
370
+ firefox_versions = [
371
+ ("Firefox/121.0", "2023-12-01", datetime.datetime.now().isoformat()),
372
+ ("Firefox/120.0", "2023-11-01", datetime.datetime.now().isoformat()),
373
+ ("Firefox/119.0", "2023-10-01", datetime.datetime.now().isoformat()),
374
+ ]
375
+
376
+ android_versions = [
377
+ ("Linux; Android 14", "2023-10-01", datetime.datetime.now().isoformat()),
378
+ ("Linux; Android 13", "2022-10-01", datetime.datetime.now().isoformat()),
379
+ ("Linux; Android 12", "2021-10-01", datetime.datetime.now().isoformat()),
380
+ ]
381
+
382
+ windows_versions = [
383
+ ("Windows NT 10.0", datetime.datetime.now().isoformat(), datetime.datetime.now().isoformat()),
384
+ ("Windows NT 6.3", datetime.datetime.now().isoformat(), datetime.datetime.now().isoformat()),
385
+ ("Windows NT 6.1", datetime.datetime.now().isoformat(), datetime.datetime.now().isoformat()),
386
+ ]
387
+
388
+ try:
389
+ self.db.add_chrome_versions(chrome_versions)
390
+ self.db.add_firefox_versions(firefox_versions)
391
+ self.db.add_android_versions(android_versions)
392
+ self.db.add_windows_versions(windows_versions)
393
+
394
+ self.update_platforms()
395
+
396
+ self.update_version_types()
397
+
398
+ print("Database successfully started!")
399
+ print(" - Chrome: 3 Version")
400
+ print(" - Firefox: 3 Version")
401
+ print(" - Android: 3 Version")
402
+ print(" - Platforms: 4 platform")
403
+ print(" - Version types: 4 version type")
404
+
405
+ return True
406
+
407
+ except Exception as e:
408
+ print(f"Database initialization error: {e}")
409
+ import traceback
410
+ traceback.print_exc()
411
+ return False
Binary file
uaforge/utils.py ADDED
@@ -0,0 +1,31 @@
1
+ import string
2
+ import random
3
+ from typing import List
4
+
5
+ def save_useragents_to_file(useragents: List[str], filename: str = None):
6
+ """
7
+ Save a list of user agents to a text file.
8
+ Args:
9
+ useragents (List[str]): A list of user agent strings to save.
10
+ filename (str, optional): The name of the file to save to. If None, a random filename
11
+ with format "user_agent_<12_digits>.txt" will be generated.
12
+ Defaults to None.
13
+ Returns:
14
+ str: The filename where the user agents were saved.
15
+ Example:
16
+ >>> uas = ["Mozilla/5.0...", "Chrome/91.0..."]
17
+ >>> save_useragents_to_file(uas)
18
+ 'user_agent_123456789012.txt'
19
+ >>> save_useragents_to_file(uas, "my_agents.txt")
20
+ 'my_agents.txt'
21
+ """
22
+
23
+ if filename is None:
24
+ random_str = ''.join(random.choices(string.digits, k=12))
25
+ filename = f"user_agent_{random_str}.txt"
26
+
27
+ with open(filename, "w", encoding="UTF-8") as file:
28
+ for ua in useragents:
29
+ file.write(f"{ua}\n")
30
+
31
+ return filename