This commit is contained in:
TPD94
2024-08-07 12:23:30 -04:00
parent 910e335084
commit 4454aa1db9
7 changed files with 349 additions and 599 deletions

37
CHANGELOG.md Normal file
View File

@@ -0,0 +1,37 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
# [1.0.2] - 2024-00-00
### Fixed
- Corrected the regex for patching MAC IDs.
- Added a missing dependency to the requirements.
# [1.0.1] - 2024-08-04
### Added
- Added a feature to bypass XML detection, enhancing compatibility with newer DVDFab versions.
- Implemented a block for usage limit requests when the user is not connected, removing restrictions on non-connected sessions.
- Removed recommendation ads, providing a cleaner and more focused user experience.
- Added a compiled executable (`.exe`) for Windows in the `dist` directory, facilitating easier deployment on Windows systems.
### Changed
- Improved the reuse of session identifiers, ensuring smoother transitions and fewer disruptions during repeated use.
### Fixed
- Fixed an error where email replacement was not functioning correctly, ensuring that all email-related operations are handled properly.
## [1.0.0] - 2024-08-01
- Initial release of the project, laying the foundation for future enhancements and features.
[1.0.2]: https://cdm-project.com/Download-Tools/DVDFabLifetimeActivation
[1.0.1]: https://cdm-project.com/Download-Tools/DVDFabLifetimeActivation
[1.0.0]: https://cdm-project.com/Download-Tools/DVDFabLifetimeActivation

View File

@@ -17,6 +17,11 @@ A method to activate DVDFab products using a proxy approach that does not impact
1. **HTTP Toolkit**: Download and install from [httptoolkit.com](https://httptoolkit.com/)
2. **DVDFab Product**: Ensure you have the DVDFab product (e.g., StreamFab) installed on your system.
3. **Python**: Ensure you have Python installed on your system.
4. **Required Python Packages**: Install the required packages using pip:
````shell
pip install -r requirements.txt
````
## Installation & Usage
@@ -61,13 +66,23 @@ In case you encounter errors related to MAC detection:
### Step 6: Enabling Additional Rules in HTTP Toolkit (If Needed)
1. **Access HTTP Toolkit Configuration:**
1. **Access HTTP Toolkit Configuration**:
- Go to the `Mock` tab where you imported the `HTTPToolkit_DVDFab.htkrules` file.
2. **Enable Additional Rules:**
2. **Enable Additional Rules**:
- In the rules configuration, locate the index `2` section. This rule is disabled by default.
- Enable this rule to apply additional patches required for your specific configuration.
### Step 7: Enjoy Activated Features
### Step 7: Disabling XML Check (Optional)
If you encounter issues related to XML checks, you can disable this check by enabling a specific rule in HTTP Toolkit:
1. **Access HTTP Toolkit Configuration:**
- Go to the Mock tab where you imported the HTTPToolkit_DVDFab.htkrules file.
2. **Enable XML Check Disabling Rule:**
- In the rules configuration, locate the index `3` section. This rule is disabled by default.
- Enable this rule to disable the XML check.
### Step 8: Enjoy Activated Features
1. The requests are now patched, and you can enjoy all functionalities.
![Mock Requests](docs/images/mock_requests.png)

BIN
docs/images/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

5
src/requirements.txt Normal file
View File

@@ -0,0 +1,5 @@
pathlib~=1.0.1
requests~=2.31.0
xmltodict~=0.13.0
Flask~=3.0.3
requests-toolbelt~=1.0.0

View File

@@ -36,7 +36,7 @@ if __name__ == '__main__':
print('Expiration Date:', expire.isoformat())
# Additional details
version = 6191
version = 6192
adds = True
token = secrets.token_hex(16) # Generate a random token
@@ -49,7 +49,7 @@ if __name__ == '__main__':
ticket.append(f'AD:{int(adds)}') # Adds flag
ticket.append('SUB:') # Placeholder for subscription details
ticket.append('UT:0') # User type
ticket.append('ML:1-11-1') # Machine limits or other codes
ticket.append('ML:1-11-1') # Machine limits or other codes (current/total/used)
ticket.append(f'S:{token}') # Security token
ticket.append(f'TI:{int(current.timestamp())}') # Ticket issuance time
ticket.append('TM:0') # Placeholder for additional time management

View File

@@ -1,20 +1,15 @@
import re
import secrets
from random import SystemRandom
import string
import requests
import xmltodict
from flask import Flask, request, Response
from requests_toolbelt import MultipartEncoder
app = Flask(__name__)
app.config.update(
DEBUG=True,
SECRET_KEY=secrets.token_hex(16),
ALLOWED_HOSTS=['127.0.0.1', 'localhost']
)
# utils.py
def parse_boundary(data: str) -> dict:
"""
Parse the multipart form data to extract fields.
@@ -39,39 +34,83 @@ def parse_boundary(data: str) -> dict:
return fields
def patch_boundary(data: dict) -> dict:
"""
Modify specific fields in the data dictionary based on predefined rules.
# session.py
class Session:
DOMAINS = ['hotmail.com', 'gmail.com', 'yahoo.com', 'outlook.com', 'protonmail.com', 'yandex.com']
CHARACTERS = string.ascii_lowercase + string.digits + '.-'
Parameters:
- data (dict): A dictionary containing form field names and values.
def __init__(self):
self.email = None
self.machine_id = None
self.usage = 0
self.__update()
Returns:
- dict: The modified dictionary with updated field values.
"""
# Generate a new machine ID
machine_id = [''.join(SystemRandom().choice('abcdef0123456789') for _ in range(2)) for _ in range(12)]
machine_id = ':'.join(['-'.join(machine_id[:6]), '-'.join(machine_id[6:])])
def __update(self) -> None:
"""
Update the session with a new random email and machine ID.
"""
length = secrets.choice(range(5, 15))
self.email = '{local}@{domain}'.format(
local=''.join(secrets.choice(self.CHARACTERS) for _ in range(length)),
domain=secrets.choice(Session.DOMAINS)
)
# Update fields based on rules
for key, value in data.items():
if key in ('TK', 'PW', 'D', 'F') and re.match(r'[0-9a-f]{32}', value):
data[key] = value # '' # Replace token
if re.match(r'^([0-9a-f]{2}-){5}[0-9a-f]{2}:([0-9a-f]{2}-){5}[0-9a-f]{2}', value):
data[key] = machine_id # Replace MAC
elif re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', value):
fake_email_user = ''.join(SystemRandom().choice('abcdefghijklmnopqrstuvwxyz.-0123456789') for _ in range(SystemRandom().randint(8, 16)))
fake_email_provider = SystemRandom().choice(["@gmail.com", "@hotmail.com", "@yahoo.com"])
data[key] = fake_email_user + fake_email_provider # Replace email
elif re.match(r'^365$', value):
data[key] = 'trial' # Replace subscription
self.machine_id = ':'.join([
'-'.join(f'{b:02x}' for b in secrets.token_bytes(6)),
'-'.join(f'{b:02x}' for b in secrets.token_bytes(6))
])
print(f'Email: {self.email}')
print(f'Machine ID: {self.machine_id}')
return data
def __repr__(self) -> str:
return '{name}({items})'.format(
name=self.__class__.__name__,
items=', '.join([f'{k}={repr(v)}' for k, v in self.__dict__.items()])
)
def patch_boundary(self, data: dict) -> dict:
"""
Modify specific fields in the data dictionary based on predefined rules.
Parameters:
- data (dict): A dictionary containing form field names and values.
Returns:
- dict: The modified dictionary with updated field values.
"""
if self.usage == 3:
self.usage = 0
self.__update()
# Update fields based on rules
for key, value in data.items():
if key in ('TK', 'PW', 'D', 'F') and re.match(r'[0-9a-f]{32}', value):
data[key] = value # '' # Replace token
if re.match(r'^([0-9a-f]{2}-){5}[0-9a-f]{2}(:([0-9a-f]{2}-){5}[0-9a-f]{2})?', value):
data[key] = self.machine_id # Replace MAC
elif re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', value):
data[key] = self.email # Replace email
elif re.match(r'^365$', value):
data[key] = 'trial' # Replace subscription
self.usage += 1
return data
# app.py
session = Session()
app = Flask(__name__)
app.config.update(
DEBUG=True,
SECRET_KEY=secrets.token_hex(16),
ALLOWED_HOSTS=['127.0.0.1', 'localhost']
)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['POST'])
def catch_all(path: str) -> Response:
global session
"""
Handle all POST requests, modify the data, and forward it to the same URL over HTTPS.
@@ -81,34 +120,43 @@ def catch_all(path: str) -> Response:
Returns:
- Response: A Flask Response object with the status and content of the forwarded request.
"""
# Get the raw request data
body = request.get_data().decode('utf-8')
is_auth = re.match(r'^auth/trial_disc\.php', path)
# Parse the multipart form data and modify it
boundary = parse_boundary(body)
patched = patch_boundary(boundary)
# Create a MultipartEncoder with the modified data
mp_encoder = MultipartEncoder(patched)
# Prepare headers for the forwarded request
headers = dict(request.headers)
del headers['Connection']
del headers['Content-Length']
headers['Content-Type'] = mp_encoder.content_type
body = request.get_data()
if not is_auth:
boundary = parse_boundary(body.decode('utf-8'))
patched = session.patch_boundary(boundary)
mp_encoder = MultipartEncoder(patched)
headers['Content-Type'] = mp_encoder.content_type
body = mp_encoder.read()
# Forward the request to the same URL over HTTPS
r = requests.request(
method=request.method,
url=request.url.replace('http://', 'https://'),
params=request.args.to_dict(),
data=mp_encoder,
data=body,
headers=headers,
cookies=request.cookies
)
content = r.content
if is_auth:
data = xmltodict.parse(content)
if data.get('TrialOpenDiscInfo', {}).get('@MacID'):
data['TrialOpenDiscInfo']['@MacID'] = session.machine_id
if data.get('TrialOpenDiscInfo', {}).get('DiscInfo'):
del data['TrialOpenDiscInfo']['DiscInfo']
content = xmltodict.unparse(data, pretty=False, full_document=False)
# Return the response from the forwarded request
return Response(status=r.status_code, response=r.content)
return Response(status=r.status_code, response=content)
# Run the Flask app

View File

@@ -22,7 +22,24 @@
"handler": {
"data": {
"type": "Buffer",
"data": null
"data": [
89,
79,
85,
82,
95,
65,
85,
84,
72,
95,
84,
73,
67,
75,
69,
84
]
},
"status": 200,
"headers": {
@@ -50,9 +67,6 @@
"regexFlags": ""
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"uiType": "forward-to-host",
"type": "passthrough",
@@ -60,6 +74,122 @@
"targetHost": "http://127.0.0.1:5000",
"updateHostHeader": false
}
},
"completionChecker": {
"type": "always"
}
},
{
"id": "21f9f6b0-a1d3-4c81-993b-d573ac224158",
"type": "http",
"activated": false,
"matchers": [
{
"method": 1,
"type": "method",
"uiType": "POST"
},
{
"type": "regex-path",
"regexSource": "http:\\/\\/ssl\\.dvdfab\\.cn\\/auth\\/trial_disc.php",
"regexFlags": ""
},
{
"type": "query",
"queryObject": {
"Mode": "Download"
}
}
],
"handler": {
"uiType": "forward-to-host",
"type": "passthrough",
"forwarding": {
"targetHost": "http://127.0.0.1:5000",
"updateHostHeader": false
}
},
"completionChecker": {
"type": "always"
}
},
{
"id": "ca9eadc4-1fad-43b5-907a-d128f6806cdd",
"type": "http",
"activated": true,
"matchers": [
{
"method": 1,
"type": "method",
"uiType": "POST"
},
{
"path": "https://ssl.dvdfab.cn/update/recommend.php",
"type": "simple-path"
}
],
"handler": {
"data": {
"type": "Buffer",
"data": [
123,
34,
99,
115,
99,
111,
100,
101,
34,
58,
48,
44,
34,
118,
101,
114,
115,
105,
111,
110,
34,
58,
49,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
116,
114,
117,
101,
44,
34,
100,
97,
116,
97,
34,
58,
91,
93,
125
]
},
"status": 200,
"headers": {
"content-type": "text/html"
},
"type": "simple"
},
"completionChecker": {
"type": "always"
}
},
{
@@ -77,9 +207,6 @@
"type": "simple-path"
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"data": {
"type": "Buffer",
@@ -100,6 +227,9 @@
"content-type": "text/html; charset=UTF-8"
},
"type": "simple"
},
"completionChecker": {
"type": "always"
}
},
{
@@ -117,11 +247,51 @@
"type": "simple-path"
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"type": "close-connection"
},
"completionChecker": {
"type": "always"
}
},
{
"id": "73edc756-fee2-46bf-ba9a-c8085e2d6f79",
"type": "http",
"activated": true,
"matchers": [
{
"method": 1,
"type": "method",
"uiType": "POST"
},
{
"type": "regex-path",
"regexSource": "http:\\/\\/ssl\\.dvdfab\\.cn\\/auth\\/trial_disc\\.php",
"regexFlags": ""
},
{
"type": "query",
"queryObject": {
"Mode": "Upload"
}
}
],
"handler": {
"data": {
"type": "Buffer",
"data": [
79,
75
]
},
"status": 200,
"headers": {
"content-type": "text/html"
},
"type": "simple"
},
"completionChecker": {
"type": "always"
}
},
{
@@ -136,13 +306,10 @@
},
{
"type": "regex-path",
"regexSource": "https:\\/\\/servo-slave-[0-9]+\\.dvdfab\\.cn\\/recommend\\/client\\/best\\/list",
"regexSource": "https:\\/\\/servo-slave-.+\\.dvdfab\\.cn\\/recommend\\/client\\/best\\/list",
"regexFlags": ""
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"data": {
"type": "Buffer",
@@ -196,6 +363,9 @@
"content-type": "application/json"
},
"type": "simple"
},
"completionChecker": {
"type": "always"
}
},
{
@@ -214,9 +384,6 @@
"regexFlags": ""
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"data": {
"type": "Buffer",
@@ -264,531 +431,6 @@
34,
58,
91,
123,
34,
112,
111,
115,
95,
105,
100,
34,
58,
49,
44,
34,
105,
100,
34,
58,
45,
49,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
102,
97,
108,
115,
101,
44,
34,
112,
111,
115,
34,
58,
34,
65,
100,
32,
119,
104,
101,
110,
32,
97,
112,
112,
32,
115,
116,
97,
114,
116,
34,
44,
34,
114,
101,
99,
111,
109,
109,
101,
110,
100,
95,
100,
97,
116,
97,
34,
58,
34,
34,
125,
44,
123,
34,
112,
111,
115,
95,
105,
100,
34,
58,
50,
44,
34,
105,
100,
34,
58,
53,
48,
48,
50,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
116,
114,
117,
101,
44,
34,
112,
111,
115,
34,
58,
34,
78,
101,
119,
32,
112,
114,
111,
100,
117,
99,
116,
32,
97,
100,
32,
119,
104,
101,
110,
32,
97,
112,
112,
32,
115,
116,
97,
114,
116,
34,
44,
34,
114,
101,
99,
111,
109,
109,
101,
110,
100,
95,
100,
97,
116,
97,
34,
58,
34,
34,
125,
44,
123,
34,
112,
111,
115,
95,
105,
100,
34,
58,
53,
44,
34,
105,
100,
34,
58,
53,
48,
48,
48,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
116,
114,
117,
101,
44,
34,
112,
111,
115,
34,
58,
34,
65,
100,
32,
97,
116,
32,
98,
111,
116,
116,
111,
109,
32,
111,
102,
32,
117,
105,
34,
44,
34,
114,
101,
99,
111,
109,
109,
101,
110,
100,
95,
100,
97,
116,
97,
34,
58,
34,
34,
125,
44,
123,
34,
112,
111,
115,
95,
105,
100,
34,
58,
54,
44,
34,
105,
100,
34,
58,
45,
49,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
102,
97,
108,
115,
101,
44,
34,
112,
111,
115,
34,
58,
34,
65,
100,
32,
97,
116,
32,
108,
101,
102,
116,
32,
98,
111,
116,
116,
111,
109,
32,
99,
111,
114,
110,
101,
114,
34,
44,
34,
114,
101,
99,
111,
109,
109,
101,
110,
100,
95,
100,
97,
116,
97,
34,
58,
34,
34,
125,
44,
123,
34,
112,
111,
115,
95,
105,
100,
34,
58,
50,
48,
48,
48,
44,
34,
105,
100,
34,
58,
49,
49,
48,
50,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
116,
114,
117,
101,
44,
34,
112,
111,
115,
34,
58,
34,
65,
100,
32,
105,
110,
32,
108,
105,
118,
101,
117,
112,
100,
97,
116,
101,
32,
100,
105,
97,
108,
111,
103,
34,
44,
34,
114,
101,
99,
111,
109,
109,
101,
110,
100,
95,
100,
97,
116,
97,
34,
58,
34,
34,
125,
44,
123,
34,
112,
111,
115,
95,
105,
100,
34,
58,
56,
44,
34,
105,
100,
34,
58,
53,
49,
48,
51,
44,
34,
101,
110,
97,
98,
108,
101,
34,
58,
116,
114,
117,
101,
44,
34,
112,
111,
115,
34,
58,
34,
65,
100,
32,
97,
116,
32,
108,
105,
99,
101,
110,
115,
101,
32,
105,
110,
102,
111,
34,
44,
34,
114,
101,
99,
111,
109,
109,
101,
110,
100,
95,
100,
97,
116,
97,
34,
58,
34,
34,
125,
93,
125,
125
@@ -799,6 +441,9 @@
"content-type": "text/html; charset=UTF-8"
},
"type": "simple"
},
"completionChecker": {
"type": "always"
}
},
{
@@ -952,9 +597,6 @@
"regexFlags": ""
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"data": {
"type": "Buffer",
@@ -991,6 +633,9 @@
"content-type": "text/html; charset=UTF-8"
},
"type": "simple"
},
"completionChecker": {
"type": "always"
}
},
{
@@ -1009,9 +654,6 @@
"regexFlags": ""
}
],
"completionChecker": {
"type": "always"
},
"handler": {
"uiType": "forward-to-host",
"type": "passthrough",
@@ -1019,6 +661,9 @@
"targetHost": "http://127.0.0.1:5000",
"updateHostHeader": false
}
},
"completionChecker": {
"type": "always"
}
},
{
@@ -1103,7 +748,7 @@
],
"handler": {
"status": 200,
"filePath": null,
"filePath": "C:\\Users\\hyugogirubato\\AppData\\Local\\httptoolkit\\Config\\ca.pem",
"headers": {
"content-type": "application/x-x509-ca-cert"
},