Init repo
This commit is contained in:
parent
5e660e0484
commit
ba48d771bb
16
.gitignore
vendored
16
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
# ---> Python
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
@ -158,5 +158,17 @@ cython_debug/
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
.idea/
|
||||
|
||||
### Python Patch ###
|
||||
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
||||
poetry.toml
|
||||
|
||||
# ruff
|
||||
.ruff_cache/
|
||||
|
||||
# LSP config files
|
||||
pyrightconfig.json
|
||||
|
||||
### DVDFab ###
|
||||
*.htkrules
|
60
CHANGELOG.md
Normal file
60
CHANGELOG.md
Normal file
@ -0,0 +1,60 @@
|
||||
# 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.1.0] - 2024-09-29
|
||||
|
||||
### Added
|
||||
|
||||
- Added PornHub product ID for StreamFab.
|
||||
- Custom ticket builder (type/method/viewer).
|
||||
- Descriptions for each interception rule.
|
||||
- Ability to add to an existing rules file (without overwriting user rules).
|
||||
- Option to save newly created rules in a different location.
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed `.htkrules` dependencies.
|
||||
- Made interception rules more generic.
|
||||
- Clarified debug information.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed detection of the default HTTP Toolkit certificate.
|
||||
- Applied rules to both HTTP and HTTPS.
|
||||
- Enhanced support for generic errors (files/environment, etc.).
|
||||
|
||||
# [1.0.2] - 2024-08-24
|
||||
|
||||
### 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.1.0]: https://cdm-project.com/Download-Tools/DVDFabLifetimeActivation
|
||||
[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
|
18
LICENSE
18
LICENSE
@ -2,8 +2,20 @@ MIT License
|
||||
|
||||
Copyright (c) 2024 hyugogirubato
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
96
README.md
96
README.md
@ -1,2 +1,96 @@
|
||||
# DVDFabLifetimeActivation
|
||||
# DVDFab 365 Lifetime Activation
|
||||
|
||||
**DVDFab 365 Lifetime Activation** is a powerful tool that automates the process of setting up activation rules and licenses for DVDFab, using the HTTP Toolkit for HTTPS interception. This project allows you to manage license tickets for DVDFab, providing seamless lifetime activation through custom rule handling. By leveraging JSON-based rule templates and certificate management, this repository helps in creating and maintaining DVDFab license activations for long-term use.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> For optimal operation (especially for the DRM API), you must have an account with access to the DRM service to bypass restrictions linked to the user/machine/IP.
|
||||
|
||||
## Features
|
||||
|
||||
- **Automated Rule Management**: This tool manages activation rules for DVDFab by loading and updating rule files in JSON format.
|
||||
- **HTTPS Interception**: Utilizes HTTP Toolkit for HTTPS interception, enabling seamless integration with DVDFab.
|
||||
- **Ticket Generation**: Automatically generates DVDFab lifetime activation tickets.
|
||||
- **Certificate Handling**: Updates and injects the correct certificate paths for HTTPS traffic interception, using the system-specific `ca.pem` file.
|
||||
- **Customizable Settings**: Users can provide custom rule paths and output locations via command-line arguments.
|
||||
- **Cross-Platform Support**: Works on Windows, macOS, and Linux by identifying system-specific paths.
|
||||
|
||||
## How It Works
|
||||
|
||||
This project primarily revolves around the **HTTP Toolkit** for intercepting and managing HTTPS requests from DVDFab, and a JSON-based rules file that integrates an activation ticket. The flow includes:
|
||||
|
||||
1. **Loading and Updating Rules**: The tool loads default and custom rules from JSON templates and updates the rule file with a new ticket and certificate path for HTTPS traffic interception.
|
||||
2. **Ticket Management**: It either uses an existing DVDFab ticket or creates a new one that grants a lifetime activation.
|
||||
3. **Saving Updated Rules**: After modifying the rules and inserting the necessary activation details, the updated rules are saved into a new file that is compatible with HTTP Toolkit.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before using the **DVDFab 365 Lifetime Activation** tool, ensure you have the following:
|
||||
|
||||
1. **Python 3.x** installed on your system.
|
||||
2. **HTTP Toolkit** installed for HTTPS interception ([Download HTTP Toolkit](https://httptoolkit.tech/)).
|
||||
3. A valid **DVDFab subscription** or ticket for activation purposes.
|
||||
|
||||
## Installation
|
||||
|
||||
1**Install the Dependencies**:
|
||||
This script doesn't rely on any external Python libraries, so no additional installation is needed. However, ensure that the **HTTP Toolkit** is set up on your system.
|
||||
|
||||
2**Set Up Certificates**:
|
||||
Make sure the **`ca.pem`** certificate from HTTP Toolkit is correctly installed on your system:
|
||||
- **Windows**: Should be located in `C:\Users\<YourUsername>\AppData\Local\httptoolkit\Config\ca.pem`
|
||||
- **macOS/Linux**: Should be located in `~/.config/httptoolkit/ca.pem`
|
||||
|
||||
## Usage
|
||||
|
||||
### Command-line Arguments
|
||||
|
||||
The script accepts several arguments to customize the rule and ticket management process:
|
||||
|
||||
- `--rules`: Path to the rules file (default: `template.json`).
|
||||
- `--ticket`: An existing ticket string to use (optional).
|
||||
- `--output`: Output path for saving the updated rules (default: script directory).
|
||||
|
||||
### Example Usage
|
||||
|
||||
1. **Generate a New Ticket** and Update Rules:
|
||||
```bash
|
||||
python main.py --rules custom_rules.json --output /path/to/save
|
||||
```
|
||||
|
||||
2. **Use an Existing Ticket**:
|
||||
```bash
|
||||
python main.py --rules custom_rules.json --ticket "your-existing-ticket-string" --output /path/to/save
|
||||
```
|
||||
|
||||
This will generate a DVDFab lifetime activation rule set and save it to the specified output path.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `main.py`: The primary script that handles rule management, certificate updates, and ticket processing.
|
||||
- `template.json`: A default JSON rule template that provides the structure for HTTP Toolkit's rules and settings.
|
||||
- `ticket.py`: A module that handles ticket generation and extraction, ensuring proper licensing is injected into the rule file.
|
||||
|
||||
## How the Activation Works
|
||||
|
||||
1. **Default Rules Template**: The `template.json` contains default rules for HTTP Toolkit's interception. It includes placeholders for the certificate and DVDFab ticket data.
|
||||
2. **Certificate Path Update**: The script detects the OS and updates the certificate path in the rules to ensure proper HTTPS interception with DVDFab traffic.
|
||||
3. **Ticket Generation**: A new ticket is generated with the `Ticket` class, including the ticket type (Subscriber) and expiration details (lifetime, 4096 days).
|
||||
4. **DVDFab Group Update**: The `dvdfab-group` rules are updated with the newly generated ticket and inserted at the start of the rules list for priority handling.
|
||||
5. **Save Rules**: The updated rules are saved in a format compatible with HTTP Toolkit to handle DVDFab traffic with lifetime activation enabled.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Certificate Not Found**: Ensure that the `ca.pem` file exists in the correct directory for your operating system. If HTTP Toolkit is installed properly, this file should be automatically generated.
|
||||
- **DVDFab Not Activating**: Double-check the ticket generation process and ensure the ticket type and version are correct. You can manually provide a valid ticket string using the `--ticket` argument.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions! If you have suggestions or find bugs, feel free to open an issue or submit a pull request.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This tool is for educational purposes only. Unauthorized use of software or tools, including attempting to bypass licensing mechanisms, is against the terms of service of most software providers. Always ensure you have the legal right to use the software in question.
|
105
docs/fabcom.crt
Normal file
105
docs/fabcom.crt
Normal file
@ -0,0 +1,105 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGQDCCBSigAwIBAgIQNu/9Js030ZM8qUUtvbuorTANBgkqhkiG9w0BAQsFADCB
|
||||
jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
|
||||
Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB
|
||||
MB4XDTI0MDYwNDAwMDAwMFoXDTI1MDYwNDIzNTk1OVowHjEcMBoGA1UEAxMTd3d3
|
||||
LmR2ZGZhYnN0b3JlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AKzJZZgu6CcY9ZGNVtO4u6Gv6pwWr7c2UBhR5C+saWH5exyIp73tRSWMO24db358
|
||||
P+VInpidzrVV/hHdP1LEF4UEjwoha8oTFAb5e9AZIRtFAYGEHSBCEJrCvcwvROzL
|
||||
Kob4KV2xx0WfGvT6NU9jwZc/cURUkBIHfsgSCeKIhQgRHKxUMHxt/o2PehSem+5/
|
||||
Eu6Umsfa0NWSvwJa3w/G1O7AmhVlBm8E8riF/BrGn+Hq5SOcURPYtYbRSUbr0pTE
|
||||
U68ZDmy1Lm8u5ARsX15Clgz0kCLA8fRektISzkZ5TLJ6/O5u89fx5CUcaZslnIl1
|
||||
/2uzDszEgkxwdZjxnm62Zf8CAwEAAaOCAwYwggMCMB8GA1UdIwQYMBaAFI2MXsRU
|
||||
rYrhd+mb+ZsF4bgBjWHhMB0GA1UdDgQWBBT1hnjQjOqDEubsslh1LxqffL2S+zAO
|
||||
BgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAUBggrBgEFBQcD
|
||||
AQYIKwYBBQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQICBzAlMCMGCCsGAQUF
|
||||
BwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgEwgYQGCCsGAQUF
|
||||
BwEBBHgwdjBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0
|
||||
aWdvUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAjBggrBgEF
|
||||
BQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wLwYDVR0RBCgwJoITd3d3LmR2
|
||||
ZGZhYnN0b3JlLmNvbYIPZHZkZmFic3RvcmUuY29tMIIBfgYKKwYBBAHWeQIEAgSC
|
||||
AW4EggFqAWgAdgDPEVbu1S58r/OHW9lpLpvpGnFnSrAX7KwB0lt3zsw7CAAAAY/h
|
||||
K5aMAAAEAwBHMEUCIHufENt/oKFvU/xUcXGRI59szxl9CnaTjU8AMn4BqTVWAiEA
|
||||
206fHfzMKiQM1GWf91zHmEHYQdg+HjH7UocW9ickjAwAdwCi4wrkRe+9rZt+OO1H
|
||||
Z3dT14JbhJTXK14bLMS5UKRH5wAAAY/hK5YlAAAEAwBIMEYCIQDQ9FDaJs1kdvGr
|
||||
xAqfOllxRHxW5DKXkTyWbWtm5KYIlQIhAOub2+LCC5pbrcYGR0tpbpG7pwM4YgNW
|
||||
+eRtXedz4yjiAHUATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGP
|
||||
4SuWJQAABAMARjBEAiArjJhR95vIOkD2KNAX5Utkq0YOe9tjd+sXHPGHO8BMzwIg
|
||||
SbO2ZStYSgqgCSD5V0ORGVZ601XZS/et1EO6B+jpgmYwDQYJKoZIhvcNAQELBQAD
|
||||
ggEBADnCMwncbylDk/pd5PjX1Zibnp+sbrhekeXMXPFcXcaf9Q2nAMrvpTAmYZBL
|
||||
F9ixRJk0rfxQnPa6BKfspTxP6xAo/FttSS6S7x6kYFwea0jozf8PwsJjpWZ2adlO
|
||||
mEIGXZHtxuWgiRzkmogc6rWAfBVYGNngf2u2B6fiVsY6GcU6EqgUXra5qm9FUWSq
|
||||
ERVodnIjAUDA/hVIZT3YAjfXVBMWWKCgRzt7OXtu/lN8akuhcUqzkZcQA6qhHPFv
|
||||
w6UyWJKKUS1BPKNbqxRO/qZdhUALgQIHnt4s846THt3sjb499CjFPuRRnvE9jpkw
|
||||
mk81gk2B8VzG4SpHz1eA8P7rCZM=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
|
||||
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
|
||||
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
|
||||
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
|
||||
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
|
||||
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
|
||||
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
|
||||
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
|
||||
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
|
||||
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
|
||||
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
|
||||
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
|
||||
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
|
||||
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
|
||||
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
|
||||
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
|
||||
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
|
||||
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
|
||||
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
|
||||
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
|
||||
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
|
||||
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
|
||||
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
|
||||
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
|
||||
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
|
||||
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
|
||||
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
|
||||
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
104
docs/fabnew.crt
Normal file
104
docs/fabnew.crt
Normal file
@ -0,0 +1,104 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGKzCCBROgAwIBAgIRANiQS4APiiZWfW0/nFyT9GowDQYJKoZIhvcNAQELBQAw
|
||||
gY8xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE3MDUGA1UE
|
||||
AxMuU2VjdGlnbyBSU0EgRG9tYWluIFZhbGlkYXRpb24gU2VjdXJlIFNlcnZlciBD
|
||||
QTAeFw0yMzA4MjEwMDAwMDBaFw0yNDA5MjAyMzU5NTlaMBYxFDASBgNVBAMMCyou
|
||||
ZHZkZmFiLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsEKmgKeE
|
||||
dU2VI1AX4q/fVQjUGGzUuPJL3rwWoojWGMqrzN9aYGRRPDY3OTB3jlV9DO9kx1ur
|
||||
OHT2UCFf5xFrq+/Yg2jtjFwatk5UwgNj+VWcsRIW41MELpCcpDVqWH6VY1zWSIuj
|
||||
lSnPKfuW8UVdtjyfAHg2KtjPgcJnckLxl2jrnfKEc1UJcJ4R9J4midZGLvjEyZmI
|
||||
B8l2uvNSV+AmJTNIqY0blPdp0caHvLjoQB9hvPT4TJkdami86CsXJIvsQVeYOS7Q
|
||||
QS+M2HptLaP54huehfq5i7V29t08MnqDofhA7VM7rPSeyuBm7VrAvjHVRaZOHE6G
|
||||
5cbZvUwfSVvAIQIDAQABo4IC+DCCAvQwHwYDVR0jBBgwFoAUjYxexFStiuF36Zv5
|
||||
mwXhuAGNYeEwHQYDVR0OBBYEFFy4rbNIO4JlwuVhG1dKC5xIrBIgMA4GA1UdDwEB
|
||||
/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEF
|
||||
BQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEWF2h0
|
||||
dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEEeDB2
|
||||
ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29SU0FE
|
||||
b21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCMGCCsGAQUFBzABhhdo
|
||||
dHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAhBgNVHREEGjAYggsqLmR2ZGZhYi5jboIJ
|
||||
ZHZkZmFiLmNuMIIBfgYKKwYBBAHWeQIEAgSCAW4EggFqAWgAdgB2/4g/Crb7lVHC
|
||||
Ycz1h7o0tKTNuyncaEIKn+ZnTFo6dAAAAYoWS5ILAAAEAwBHMEUCIBAj38PxL1zL
|
||||
My/YDxD8JWYKqdNtanZbJ9hC1jB+QdDhAiEA1y3WRbjxxBlDmaR1JLUtVWzWBXJv
|
||||
3K5Kx1w+Sh8zKscAdgDatr9rP7W2Ip+bwrtca+hwkXFsu1GEhTS9pD0wSNf7qwAA
|
||||
AYoWS5JdAAAEAwBHMEUCIQDLCAW/LqGRDvHkd45SzTpL7Zjisxq/QlJ9Coiugrlu
|
||||
PQIgCfW5NZuIFBmxvEa11l+MI35j32osRn/X6219rW9+2tkAdgDuzdBk1dsazsVc
|
||||
t520zROiModGfLzs3sNRSFlGcR+1mwAAAYoWS5KEAAAEAwBHMEUCIFwdgul9xtED
|
||||
xem3h+T9V4Vhiom6RUQndOtpGIF1DCc0AiEAoVNMe3txvwm+lTy5vLth0v4cYttG
|
||||
EKtGJvJzMPvPBl8wDQYJKoZIhvcNAQELBQADggEBABWnaaXEti68U9pUFuvZu2Dp
|
||||
N4l/Fef1cKKsPO+JwzdUI4G0vt/ROSGjxFGmHyvCFiXIe7FFW1KO+5VsPMdrJODj
|
||||
aAq4yOa1389QSSvtH55g9fmQuzN4p/KBkzs55A4cOvjL80RGfPVw4UkOZFcmcmHp
|
||||
6+rySKxV0lp4ddGoz98JQ/fiFJiWvw6wNCfnKbCf575jDefa56JosWMnOOGMv78y
|
||||
CJJnu2CWjceA7m536OuD5cK/hoptAAsuzq4lmFnFct32Z+GrEgkvLVLwae4t9YNF
|
||||
KQYwTmVohU1/NVL0Icn5AqQugeFs61k5P4ORjlUTG3MhJZhUmsOWKgoO2hbH5UY=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
|
||||
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
|
||||
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
|
||||
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
|
||||
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
|
||||
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
|
||||
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
|
||||
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
|
||||
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
|
||||
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
|
||||
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
|
||||
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
|
||||
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
|
||||
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
|
||||
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
|
||||
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
|
||||
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
|
||||
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
|
||||
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
|
||||
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
|
||||
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
|
||||
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
|
||||
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
|
||||
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
|
||||
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
|
||||
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
|
||||
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
|
||||
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
BIN
docs/images/favicon.ico
Normal file
BIN
docs/images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 190 KiB |
BIN
docs/images/import_ca.png
Normal file
BIN
docs/images/import_ca.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
BIN
docs/images/mock_requests.png
Normal file
BIN
docs/images/mock_requests.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
BIN
docs/images/mock_rules.png
Normal file
BIN
docs/images/mock_rules.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 KiB |
165
docs/server.py
Normal file
165
docs/server.py
Normal file
@ -0,0 +1,165 @@
|
||||
import re
|
||||
import secrets
|
||||
import string
|
||||
|
||||
import requests
|
||||
import xmltodict
|
||||
|
||||
from flask import Flask, request, Response
|
||||
from requests_toolbelt import MultipartEncoder
|
||||
|
||||
|
||||
# utils.py
|
||||
def parse_boundary(data: str) -> dict:
|
||||
"""
|
||||
Parse the multipart form data to extract fields.
|
||||
|
||||
Parameters:
|
||||
- data (str): The raw multipart form data as a string.
|
||||
|
||||
Returns:
|
||||
- dict: A dictionary with form field names as keys and field values as values.
|
||||
"""
|
||||
fields = {}
|
||||
# Split parts using the boundary (separator) and process each part
|
||||
items = data.split('-' * 26)[1:]
|
||||
for item in items:
|
||||
lines = item.splitlines()
|
||||
if len(lines) < 3:
|
||||
continue
|
||||
# Extract the field name from the Content-Disposition header
|
||||
key = re.match(r'^Content-Disposition:\s*form-data;\s*name="([^"]+)"\s*$', lines[1]).group(1)
|
||||
# Join the remaining lines as the field value
|
||||
fields[key] = '\n'.join(lines[3:])
|
||||
return fields
|
||||
|
||||
|
||||
# session.py
|
||||
class Session:
|
||||
DOMAINS = ['hotmail.com', 'gmail.com', 'yahoo.com', 'outlook.com', 'protonmail.com', 'yandex.com']
|
||||
CHARACTERS = string.ascii_lowercase + string.digits + '.-'
|
||||
|
||||
def __init__(self):
|
||||
self.email = None
|
||||
self.machine_id = None
|
||||
self.usage = 0
|
||||
self.__update()
|
||||
|
||||
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)
|
||||
)
|
||||
|
||||
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}')
|
||||
|
||||
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.
|
||||
|
||||
Parameters:
|
||||
- path (str): The path part of the URL (used for routing).
|
||||
|
||||
Returns:
|
||||
- Response: A Flask Response object with the status and content of the forwarded request.
|
||||
"""
|
||||
is_auth = re.match(r'^auth/trial_disc\.php', path)
|
||||
|
||||
headers = dict(request.headers)
|
||||
del headers['Connection']
|
||||
del headers['Content-Length']
|
||||
|
||||
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=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=content)
|
||||
|
||||
|
||||
# Run the Flask app
|
||||
app.add_url_rule('/', 'catch_all', catch_all, defaults={'path': ''})
|
||||
app.add_url_rule('/<path:path>', 'catch_all', catch_all, defaults={'path': ''})
|
||||
app.run(host='127.0.0.1', port=5000)
|
105
docs/streamfab-us-chain.crt
Normal file
105
docs/streamfab-us-chain.crt
Normal file
@ -0,0 +1,105 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGNTCCBR2gAwIBAgIQW19xjDWCt1zPCZOS4YJiQjANBgkqhkiG9w0BAQsFADCB
|
||||
jzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQD
|
||||
Ey5TZWN0aWdvIFJTQSBEb21haW4gVmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENB
|
||||
MB4XDTI0MDEwOTAwMDAwMFoXDTI1MDEwOTIzNTk1OVowGjEYMBYGA1UEAwwPKi5z
|
||||
dHJlYW1mYWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwBxA
|
||||
5k/xyHsc2idH/N9y+B8zgMNRacIqOxm0zb2MjmYXNM5pZk3NKJoucLLgMMqar8s2
|
||||
E6LYwHrBsDWcmi8UopP5U1pqTWSjSK98GQyaaosLiI0eoSagvBH4mWTkm+qDV3vO
|
||||
rGz5NnXXmoVqXMGVk15/4JaKzv1ksZjOCtN5L7wG8fbuzxNUK8f51+avfDCvB5ZY
|
||||
aBTv5J7NeNMvXxoUe0LGwgEBYeCYxSQCyGzi+2Cmc+j9Qwk9xP/stV6dspJnvEDP
|
||||
HF7CmICib6EYAOYoeovAm4k7SdWhbOIOT3GesREjDsJJgin0xCFpOSI/5fWXf4Ff
|
||||
H7g1WvPFbtWssGuAGQIDAQABo4IC/zCCAvswHwYDVR0jBBgwFoAUjYxexFStiuF3
|
||||
6Zv5mwXhuAGNYeEwHQYDVR0OBBYEFP5TmhConW+mZO6BeKmyF0SHUpzMMA4GA1Ud
|
||||
DwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
|
||||
BgEFBQcDAjBJBgNVHSAEQjBAMDQGCysGAQQBsjEBAgIHMCUwIwYIKwYBBQUHAgEW
|
||||
F2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgGBmeBDAECATCBhAYIKwYBBQUHAQEE
|
||||
eDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29S
|
||||
U0FEb21haW5WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0EuY3J0MCMGCCsGAQUFBzAB
|
||||
hhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTApBgNVHREEIjAggg8qLnN0cmVhbWZh
|
||||
Yi5jb22CDXN0cmVhbWZhYi5jb20wggF9BgorBgEEAdZ5AgQCBIIBbQSCAWkBZwB2
|
||||
AM8RVu7VLnyv84db2Wkum+kacWdKsBfsrAHSW3fOzDsIAAABjOxWztcAAAQDAEcw
|
||||
RQIgUtkTDufYxtIZe2KaY6ISOMITcbTcnIASZi6zYHKHSIkCIQC1eOhczsh0zeTD
|
||||
mi+wXfugyDfyG7aGc5fJ3yvdntywugB2AKLjCuRF772tm3447Udnd1PXgluElNcr
|
||||
XhssxLlQpEfnAAABjOxWztAAAAQDAEcwRQIhAJJM7mrVaxS10+AK9vYIykKBCMrq
|
||||
hoCoaHSxxk8Z00+BAiALNTj+oLrsM0jIQEQwU+cFzh8t7vMK3ZazDDc+gAI9IAB1
|
||||
AE51oydcmhDDOFts1N8/Uusd8OCOG41pwLH6ZLFimjnfAAABjOxWzo8AAAQDAEYw
|
||||
RAIgZ4silEWDt7/mqpiWhUDUu35k3ydsYAFZ6yEpLG4l/aMCIGbAsXAfho3iumKS
|
||||
zZTOCCzm+C/6Lw9zKvWbPl7xCNlCMA0GCSqGSIb3DQEBCwUAA4IBAQBWXnnWtoKn
|
||||
fngd9m2d5FWLMyDg2V2ph5aPW7mfodAwrEHLvqBBxS2jZ8VTtPsEybf8/Va4H52J
|
||||
3Bxx3c/8sfiD7xXC2O2+H8RCv/uKFene3g6uKl0e+odr6v+XrW51fXKqDn1ApfdG
|
||||
faQXdlDbs/vs252IySTLqLiIzvbbZQyVgrMf4Ju7Ao4dzEer02PdLGhS4p8iAEg2
|
||||
sJ4H57yUUeZQ6H4VOvqpGlVzhyjWTZDM31tMVWYdXqYXEI+iDpz7+9GdAEPRHn8Q
|
||||
Sct3iAOzTWhGupyAOn3Y2OKQtWI+05QE+6eUMKF13CqzprgFa/sxiMRMolOTqb9r
|
||||
E0EAYeHAaPdq
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx
|
||||
MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV
|
||||
BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE
|
||||
ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g
|
||||
VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N
|
||||
TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj
|
||||
eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E
|
||||
oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk
|
||||
Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY
|
||||
uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j
|
||||
BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb
|
||||
+ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G
|
||||
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw
|
||||
CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0
|
||||
LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr
|
||||
BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv
|
||||
bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov
|
||||
L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H
|
||||
ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH
|
||||
7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi
|
||||
H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx
|
||||
RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv
|
||||
xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38
|
||||
sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL
|
||||
l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq
|
||||
6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY
|
||||
LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5
|
||||
yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K
|
||||
00u/I5sUKUErmgQfky3xxzlIPK1aEn8=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
5
src/requirements.txt
Normal file
5
src/requirements.txt
Normal 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
|
136
src/rules.py
Normal file
136
src/rules.py
Normal file
@ -0,0 +1,136 @@
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# Importing Ticket and TicketType from the ticket module
|
||||
from ticket import Ticket, TicketType
|
||||
|
||||
# Define paths and defaults
|
||||
PARENT = Path(__file__).parent
|
||||
DEFAULT_RULES_PATH = Path('template.json')
|
||||
|
||||
|
||||
def get_ca_path() -> Path:
|
||||
"""
|
||||
Determine the path to the 'ca.pem' certificate file based on the operating system.
|
||||
The certificate is used by HTTPToolkit for HTTPS interception.
|
||||
|
||||
Returns:
|
||||
Path: The full path to the 'ca.pem' file.
|
||||
"""
|
||||
if os.name == 'nt': # Windows
|
||||
return Path.home() / 'AppData' / 'Local' / 'httptoolkit' / 'Config' / 'ca.pem'
|
||||
else: # Linux/macOS (Unix-like)
|
||||
return Path.home() / '.config' / 'httptoolkit' / 'ca.pem'
|
||||
|
||||
|
||||
def load_rules(rules_path: Path) -> dict:
|
||||
"""
|
||||
Load rules from a specified file path in JSON format.
|
||||
|
||||
Args:
|
||||
rules_path (Path): Path to the rules file.
|
||||
|
||||
Returns:
|
||||
dict: Loaded JSON rules as a Python dictionary.
|
||||
"""
|
||||
return json.loads(rules_path.read_bytes())
|
||||
|
||||
|
||||
def update_certificate_path(rules: dict) -> None:
|
||||
"""
|
||||
Update the 'default-certificate' file path in the rules to point to the system's 'ca.pem' certificate.
|
||||
|
||||
Args:
|
||||
rules (dict): The current rules JSON data to modify.
|
||||
"""
|
||||
try:
|
||||
# Locate the 'default-group' and its 'default-certificate' item
|
||||
group = next(item for item in rules['items'] if item['id'] == 'default-group')
|
||||
certificate = next((item for item in group['items'] if item['id'] == 'default-certificate'), None)
|
||||
|
||||
if certificate:
|
||||
ca_path = get_ca_path() # Get the path to the 'ca.pem' file
|
||||
if ca_path.is_file():
|
||||
certificate['handler']['filePath'] = str(ca_path)
|
||||
print('[+] Updated default certificate path')
|
||||
else:
|
||||
print('[!] CA certificate not found')
|
||||
except StopIteration:
|
||||
print('[!] Could not find default certificate group or item')
|
||||
|
||||
|
||||
def save_rules(rules: dict, output_path: Path) -> None:
|
||||
"""
|
||||
Save the updated rules as a JSON file.
|
||||
|
||||
Args:
|
||||
rules (dict): The modified rules to save.
|
||||
output_path (Path): The path to save the rules file.
|
||||
"""
|
||||
# Ensure output directory exists
|
||||
output_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Define the file name
|
||||
file_path = output_path / 'HTTPToolkit_DVDFab.htkrules'
|
||||
|
||||
# Write the rules to the file in JSON format
|
||||
file_path.write_text(json.dumps(rules, separators=(',', ': ')))
|
||||
|
||||
print(f'[+] Rules saved to {file_path}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Set up argument parsing
|
||||
parser = argparse.ArgumentParser(description='DVDFab-Rules: Manage rules and tickets for HTTPToolkit and DVDFab.')
|
||||
|
||||
# Command-line arguments
|
||||
parser.add_argument('--rules', type=Path, metavar='<path>', default=DEFAULT_RULES_PATH, help='Path to rules file (default: template.json)')
|
||||
parser.add_argument('--ticket', type=str, metavar='<ticket>', help='Existing ticket string (optional)')
|
||||
parser.add_argument('--output', type=Path, metavar='<path>', default=PARENT, help='Output path for saving the updated rules')
|
||||
|
||||
# Parse the command-line arguments
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
# Load default and specified rules
|
||||
default_rules = load_rules(DEFAULT_RULES_PATH)
|
||||
rules = load_rules(args.rules)
|
||||
|
||||
# Update certificate path if the rules match the default template
|
||||
if rules == default_rules:
|
||||
update_certificate_path(rules)
|
||||
|
||||
# Remove any existing 'dvdfab-group' from the rules
|
||||
rules['items'] = [item for item in rules['items'] if item['id'] != 'dvdfab-group']
|
||||
|
||||
# Handle ticket creation or extraction
|
||||
ticket = args.ticket or Ticket.create({
|
||||
'type': TicketType.SUBSCRIBER.name,
|
||||
'version': 6200,
|
||||
'expire': 4096 # Set ticket expiration days
|
||||
}).export()
|
||||
|
||||
# Extract ticket details for display
|
||||
ticket_info = Ticket.extract(ticket)
|
||||
for key, value in ticket_info.items():
|
||||
print(f'[*] {key.capitalize()}: {value}')
|
||||
|
||||
# Add DVDFab group and ticket data to rules
|
||||
dvdfab_group = next(item for item in default_rules['items'] if item['id'] == 'dvdfab-group')
|
||||
auth_item = next(item for item in dvdfab_group['items'] if item['id'] == '6955a688-8bc2-4f63-92cd-141f9debb97a')
|
||||
|
||||
# Insert the ticket data into the auth handler
|
||||
auth_item['handler']['data']['data'] = list(ticket.encode('utf-8'))
|
||||
|
||||
# Add the updated DVDFab group to the start of the rules
|
||||
rules['items'].insert(0, dvdfab_group)
|
||||
print('[+] Added DVDFab rules')
|
||||
|
||||
# Save the updated rules to the output path
|
||||
save_rules(rules, args.output)
|
||||
except Exception as e:
|
||||
# Print any errors that occur during execution
|
||||
print(f'[!] {e}')
|
||||
exit(1)
|
1641
src/template.json
Normal file
1641
src/template.json
Normal file
File diff suppressed because it is too large
Load Diff
388
src/ticket.py
Normal file
388
src/ticket.py
Normal file
@ -0,0 +1,388 @@
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import secrets
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
|
||||
import requests
|
||||
|
||||
from requests_toolbelt import MultipartEncoder
|
||||
|
||||
# Constants for default empty values
|
||||
EMPTY_SERIAL = '00000000000000000000000000000000'
|
||||
EMPTY_MAC = '00-00-00-00-00-00:00-00-00-00-00-00'
|
||||
|
||||
|
||||
# Enum to represent ticket types
|
||||
class TicketType(Enum):
|
||||
SUBSCRIBER = 3
|
||||
LIFETIME = 2
|
||||
FREE = 1
|
||||
NO_LOGIN = 0
|
||||
|
||||
|
||||
# Enum to represent client types (operating systems)
|
||||
class ClientType(Enum):
|
||||
WINDOWS = 94
|
||||
ANDROID = 51
|
||||
MAC = 0 # TODO: Define the Mac Client ID
|
||||
|
||||
|
||||
class Ticket:
|
||||
MAGIC = 1
|
||||
|
||||
# List of valid product IDs (these could represent different software or features)
|
||||
PRODUCTS = [
|
||||
# StreamFab
|
||||
308, 310, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 337, 339, 340, 342, 346, 348,
|
||||
349, 350, 352, 353, 356, 357, 358, 359, 360, 361, 362, 364, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375,
|
||||
376, 377, 378, 379, 380, 381, 500,
|
||||
|
||||
# Others
|
||||
2, 11, 20, 21, 22, 50, 55, 60, 61, 62, 63, 70, 91, 92, 93, 94, 95, 96, 97, 98, 200, 201, 208, 209, 213, 214,
|
||||
215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 300, 301, 302, 303, 304,
|
||||
305, 306, 307, 309, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 336, 338, 341, 347, 351, 354, 355, 363,
|
||||
365, 384, 394, 396, 397, 398, 400, 401, 402, 403, 404, 405, 407, 409, 410, 412, 414, 1002, 1011, 1020, 1021,
|
||||
1022, 1050, 1055, 1060, 1061, 1062, 1070, 1095, 1096, 1097, 1098, 1200, 1201, 1208, 1209, 1213, 1214, 1215,
|
||||
1216, 1217, 1218, 1219, 1221, 1222, 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1300, 1301, 1302,
|
||||
1303, 1304, 1305, 1306, 1307, 1308, 1310, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1322, 1323,
|
||||
1324, 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341,
|
||||
1342, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362,
|
||||
1363, 1364, 1365, 1366, 1367, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378]
|
||||
|
||||
def __init__(self, token: str, data: dict):
|
||||
"""
|
||||
Initialize the ticket with a user token and relevant ticket data.
|
||||
|
||||
Args:
|
||||
token (str): User's unique token.
|
||||
data (dict): Dictionary containing ticket information (type, version, expiration).
|
||||
"""
|
||||
self.token = token
|
||||
self.type = TicketType[data['type']]
|
||||
self.version = data['version']
|
||||
self.expire = 75616 if self.type == TicketType.LIFETIME else data['expire']
|
||||
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Provide string representation for debugging."""
|
||||
return '{name}({items})'.format(
|
||||
name=self.__class__.__name__,
|
||||
items=', '.join([f'{k}={repr(v)}' for k, v in self.__dict__.items()])
|
||||
)
|
||||
|
||||
def export(self) -> str:
|
||||
"""
|
||||
Export the ticket information into a serialized format.
|
||||
|
||||
This method constructs a string representing the ticket data and expiration date.
|
||||
|
||||
Returns:
|
||||
str: A serialized string representation of the ticket, including magic number,
|
||||
product details, and configuration.
|
||||
"""
|
||||
current = datetime.now() # Current date and time
|
||||
expire = current + timedelta(days=self.expire) # Expiration date
|
||||
|
||||
# Determine products that this ticket covers
|
||||
products = self.PRODUCTS if self.type in (TicketType.LIFETIME, TicketType.SUBSCRIBER) else []
|
||||
|
||||
# Ticket configuration based on ticket type
|
||||
config = {
|
||||
'VP': -1, # Validity period (-1 for lifetime/subscription)
|
||||
'VPT': 0, # Validity period time (specific expiration timestamp for non-lifetime tickets)
|
||||
'OV': self.version, # Software version
|
||||
'BV': '', # Base version (reserved for future use)
|
||||
'AD': 1, # Additional field (1 for Subscriber and Lifetime)
|
||||
'SUB': '', # Subscription identifier (if available)
|
||||
'UT': 0, # Usage Type
|
||||
'UL': 1, # User Login required flag
|
||||
'ML': (0, 6, 1), # Machine limits or other codes (used machines, max allowed, currently active)
|
||||
'S': self.token, # User's token
|
||||
'TI': round(current.timestamp()), # Ticket issued timestamp
|
||||
'TM': 0 # Reserved field
|
||||
}
|
||||
|
||||
# Adjust config for different ticket types
|
||||
if self.type == TicketType.NO_LOGIN:
|
||||
# For NO_LOGIN type tickets, certain fields are removed
|
||||
del config['AD']
|
||||
del config['S']
|
||||
else:
|
||||
del config['UL'] # No need for user login in other types
|
||||
config['ML'] = (1, 6, 2) # Adjust machine limits
|
||||
|
||||
if self.type == TicketType.SUBSCRIBER:
|
||||
config['VP'] = self.expire # Set validity period for Subscriber type
|
||||
config['VPT'] = round(expire.timestamp()) # Set the expiration timestamp
|
||||
|
||||
if self.type == TicketType.FREE:
|
||||
config['ML'] = (1, 1, 1) # Restrict machine limits for Free ticket type
|
||||
|
||||
# Convert machine limits to string format
|
||||
config['ML'] = '-'.join(map(str, config['ML']))
|
||||
|
||||
# Construct the ticket export string with MAGIC number and product details
|
||||
items = [self.MAGIC]
|
||||
|
||||
# Add products with expiration timestamps
|
||||
items += [f'{p}:{round(expire.timestamp())}' for p in products]
|
||||
|
||||
# Add configuration key-value pairs
|
||||
items += [f'{k}:{v}' for k, v in config.items()]
|
||||
|
||||
# Return the serialized string
|
||||
return '|'.join(map(str, items))
|
||||
|
||||
@classmethod
|
||||
def from_token(cls, data: dict):
|
||||
"""
|
||||
Create a ticket instance using an existing user token.
|
||||
|
||||
This method validates the token length and initializes a new Ticket instance
|
||||
using the provided token and data.
|
||||
|
||||
Args:
|
||||
data (dict): Dictionary containing token and ticket data.
|
||||
|
||||
Returns:
|
||||
Ticket: An instance of Ticket created using the provided token.
|
||||
"""
|
||||
token = data['token']
|
||||
|
||||
# Token must be 32 characters long
|
||||
assert len(token) == 32, 'Invalid Token Length'
|
||||
|
||||
# Return a new Ticket instance
|
||||
return cls(token, data)
|
||||
|
||||
@classmethod
|
||||
def from_account(cls, data: dict):
|
||||
"""
|
||||
Create a ticket instance using account credentials.
|
||||
|
||||
This method sends a login request to the server and retrieves the token and ticket details.
|
||||
|
||||
Args:
|
||||
data (dict): Dictionary containing account login credentials (email and password).
|
||||
|
||||
Returns:
|
||||
Ticket: An instance of Ticket initialized with the retrieved token and ticket data.
|
||||
"""
|
||||
mp_encoder = MultipartEncoder({
|
||||
'DI': json.dumps({
|
||||
'MAC': data['mac'],
|
||||
'DS': data['DS'],
|
||||
'IS': data['IS'],
|
||||
'BI': data['BI']
|
||||
}, separators=(',', ':')),
|
||||
'H': data['mac'],
|
||||
'V': str(data['version']),
|
||||
'C': str(ClientType[data['client']].value),
|
||||
'S': '',
|
||||
'U': data['email'],
|
||||
'P': hashlib.md5(data['password'].encode('utf-8')).hexdigest(),
|
||||
'T': '0'
|
||||
})
|
||||
|
||||
r = requests.request(
|
||||
method='POST',
|
||||
url='https://www.dvdfabstore.com/auth/v5/',
|
||||
data=mp_encoder,
|
||||
headers={
|
||||
'Accept': '*/*',
|
||||
'Content-Type': mp_encoder.content_type,
|
||||
'User-Agent': 'FabApp/3.0'
|
||||
}
|
||||
)
|
||||
r.raise_for_status()
|
||||
|
||||
# Extract token from response
|
||||
m = re.search(r'S:([a-f0-9]+)', r.text)
|
||||
assert m, 'Invalid Login Credentials'
|
||||
|
||||
# Return a new Ticket instance
|
||||
return cls(m.group(1), data)
|
||||
|
||||
@staticmethod
|
||||
def extract(value: str) -> dict:
|
||||
"""Extract ticket details and return relevant information.
|
||||
|
||||
Args:
|
||||
value (str): The ticket string to extract details from.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the type of ticket, expiration time,
|
||||
number of products, and configuration details.
|
||||
"""
|
||||
items = value.split('|')
|
||||
current = round(datetime.now().timestamp())
|
||||
assert int(items[0]) == Ticket.MAGIC, 'Invalid Magic Ticket'
|
||||
|
||||
config = {}
|
||||
expires = []
|
||||
products = []
|
||||
for item in items[1:]:
|
||||
key, value = item.split(':')
|
||||
|
||||
# Attempt to convert the value to an integer
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if key.isdigit():
|
||||
# Save expiration timestamp
|
||||
expires.append(value)
|
||||
|
||||
# Verify product ID
|
||||
key = int(key)
|
||||
if key not in Ticket.PRODUCTS:
|
||||
print(f'[!] Unknown product: {key}')
|
||||
|
||||
# Add the valid product ID to the list
|
||||
products.append(key)
|
||||
|
||||
# Check if the product has expired
|
||||
if value < current:
|
||||
print(f'[!] Expired product: {key}')
|
||||
else:
|
||||
if key == 'ML':
|
||||
# Extract used device
|
||||
value = tuple(map(int, value.split('-')))
|
||||
|
||||
# Add non-product key-value pairs to config
|
||||
config[key] = value
|
||||
|
||||
# Determine the type of ticket based on the extracted configuration
|
||||
if 'UL' in config:
|
||||
_type = TicketType.NO_LOGIN
|
||||
elif config['VP'] != -1:
|
||||
_type = TicketType.SUBSCRIBER
|
||||
elif config['ML'] == (1, 1, 1):
|
||||
_type = TicketType.FREE
|
||||
else:
|
||||
_type = TicketType.LIFETIME
|
||||
|
||||
# Return a dictionary containing the type, expiration, number of products, and configuration
|
||||
return {
|
||||
'type': _type.name,
|
||||
'expire': timedelta(seconds=max(expires) - current).days if expires else 0,
|
||||
'token': config.get('S'),
|
||||
'products': len(products),
|
||||
'devices': config['ML'],
|
||||
'version': config['OV']
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_ticket(cls, data: dict):
|
||||
"""Create a ticket from a previous ticket.
|
||||
|
||||
Args:
|
||||
data (dict): Dictionary containing ticket data.
|
||||
|
||||
Returns:
|
||||
Ticket: An instance of Ticket created from the given data.
|
||||
"""
|
||||
# Extract details from the ticket
|
||||
extracted = cls.extract(data['ticket'])
|
||||
|
||||
# Retrieve user token from extracted data
|
||||
token = extracted['token']
|
||||
assert token, 'Missing User Token'
|
||||
|
||||
# Update the software version in the provided data
|
||||
data['version'] = extracted['version']
|
||||
|
||||
# Return a new Ticket instance
|
||||
return cls(token, data)
|
||||
|
||||
@classmethod
|
||||
def create(cls, data: dict):
|
||||
"""Generate a new ticket with default values.
|
||||
|
||||
Args:
|
||||
data (dict): Dictionary containing ticket data.
|
||||
|
||||
Returns:
|
||||
Ticket: An instance of Ticket with a newly generated token.
|
||||
"""
|
||||
|
||||
# Generate a secure random token
|
||||
token = secrets.token_hex(16)
|
||||
|
||||
# Return a new Ticket instance with the generated token
|
||||
return cls(token, data)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
"""Main function to parse arguments and handle ticket creation and extraction."""
|
||||
parser = argparse.ArgumentParser(description='DVDFab-Ticket: Manage user tickets for DVDFab software.')
|
||||
|
||||
# Subparsers for account actions
|
||||
subparsers = parser.add_subparsers(dest='action', help='Ticket management actions')
|
||||
|
||||
# Subparser for login
|
||||
login_parser = subparsers.add_parser('login', help='Use account credentials')
|
||||
login_parser.add_argument('email', type=str, metavar='email', help='Email address')
|
||||
login_parser.add_argument('password', type=str, metavar='password', help='Password')
|
||||
login_parser.add_argument('--client', required=False, type=str, choices=[t.name for t in list(ClientType)], default=ClientType.WINDOWS.name, help='Client type')
|
||||
login_parser.add_argument('--mac', required=False, type=str, metavar='<mac>', default=EMPTY_MAC, help='MAC address')
|
||||
login_parser.add_argument('--DS', required=False, type=str, metavar='<DS>', default=EMPTY_SERIAL, help='Device serial')
|
||||
login_parser.add_argument('--IS', required=False, type=str, metavar='<IS>', default=EMPTY_SERIAL, help='Device ID')
|
||||
login_parser.add_argument('--BI', required=False, type=str, metavar='<BI>', default=EMPTY_SERIAL, help='BIOS information')
|
||||
|
||||
# Subparser for token
|
||||
# Allows user to log in using an existing token rather than credentials
|
||||
token_parser = subparsers.add_parser('token', help='Use an existing user token')
|
||||
token_parser.add_argument('token', type=str, metavar='token', help='User token')
|
||||
|
||||
# Subparser for ticket
|
||||
# Allows re-use of a previous ticket
|
||||
ticket_parser = subparsers.add_parser('ticket', help='Use an existing ticket')
|
||||
ticket_parser.add_argument('ticket', type=str, metavar='ticket', help='Old user ticket')
|
||||
|
||||
# Subparser for extracting info
|
||||
# Allows users to extract and view information from an existing ticket string
|
||||
info_parser = subparsers.add_parser('info', help='Extract info from ticket')
|
||||
info_parser.add_argument('ticket', type=str, metavar='ticket', help='Ticket string')
|
||||
|
||||
# Arguments for creating a new ticket
|
||||
# Allow users to customize the ticket type, version, and expiration
|
||||
parser.add_argument('--type', required=False, type=str, choices=[t.name for t in list(TicketType)], default=TicketType.SUBSCRIBER.name, help='Ticket type')
|
||||
parser.add_argument('--version', required=False, type=int, metavar='<version>', default=6200, help='Software version')
|
||||
parser.add_argument('--expire', required=False, type=int, metavar='<expire>', default=365, help='Days until ticket expires (default: 365)')
|
||||
|
||||
# Parse the command-line arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
# Handle ticket information extraction
|
||||
if args.action == 'info':
|
||||
infos = Ticket.extract(args.ticket)
|
||||
for key, value in infos.items():
|
||||
print(f'[*] {str(key).capitalize()}: {value}')
|
||||
else:
|
||||
# Handle ticket creation or loading based on token, login, or ticket
|
||||
if args.action == 'token':
|
||||
# Generate ticket from an existing token
|
||||
ticket = Ticket.from_token(vars(args))
|
||||
elif args.action == 'login':
|
||||
# Generate ticket after logging in
|
||||
ticket = Ticket.from_account(vars(args))
|
||||
elif args.action == 'ticket':
|
||||
# Generate ticket from a previous ticket
|
||||
ticket = Ticket.from_ticket(vars(args))
|
||||
else:
|
||||
# Create a new ticket with default settings
|
||||
ticket = Ticket.create(vars(args))
|
||||
|
||||
# Output the serialized ticket string
|
||||
print(ticket.export())
|
||||
except Exception as e:
|
||||
# Print exception message if an error occurs during ticket creation or processing
|
||||
print(f'[!] {e}')
|
||||
exit(1)
|
Loading…
Reference in New Issue
Block a user