# TP-Generator
<p align="center">
<a href="https://github.com/truocphan/TP-Generator/releases/"><img src="https://img.shields.io/github/release/truocphan/TP-Generator" height=30></a>
<a href="#"><img src="https://img.shields.io/github/downloads/truocphan/TP-Generator/total" height=30></a>
<a href="#"><img src="https://img.shields.io/github/stars/truocphan/TP-Generator" height=30></a>
<a href="#"><img src="https://img.shields.io/github/forks/truocphan/TP-Generator" height=30></a>
<a href="https://github.com/truocphan/TP-Generator/issues?q=is%3Aopen+is%3Aissue"><img src="https://img.shields.io/github/issues/truocphan/TP-Generator" height=30></a>
<a href="https://github.com/truocphan/TP-Generator/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed/truocphan/TP-Generator" height=30></a>
<br>
<a href="#"><img src="https://img.shields.io/pypi/v/TP-Generator" height=30></a>
<a href="#"><img src="https://img.shields.io/pypi/dm/TP-Generator" height=30></a>
</p>
## Installation
#### From PyPI:
```console
pip install TP-Generator
```
#### From Source:
```console
git clone https://github.com/truocphan/TP-Generator.git --branch <Branch/Tag>
cd TP-Generator
python setup.py build
python setup.py install
```
## Basic Usage
### Utils
```
from TP_Generator import Utils
Utils.timestamp(10)
# OUTPUT: 1733597189
Utils.uuid(1)
# OUTPUT: '9daeab4b-b4cb-11ef-b79b-00a554ba203d'
Utils.RandomNumber(0, 1000)
# OUTPUT: 931
Utils.RandomString(10)
# OUTPUT: 'Wz<:1<.YSC'
Utils.toUTF16('TPCyberSec')
# OUTPUT: 'VABQAEMAeQBiAGUAcgBTAGUAYwA='
Utils.toUTF32('TPCyberSec')
# OUTPUT: 'VAAAAFAAAABDAAAAeQAAAGIAAABlAAAAcgAAAFMAAABlAAAAYwAAAA=='
Utils.Str2Hex('TPCyberSec')
# OUTPUT: '54504379626572536563'
Utils.Hex2Str('54504379626572536563')
# OUTPUT: 'TPCyberSec'
Utils.base64Encode('TPCyberSec')
# OUTPUT: 'VFBDeWJlclNlYw=='
Utils.base64Decode('VFBDeWJlclNlYw==')
# OUTPUT: 'TPCyberSec'
Utils.base64UrlEncode('TPCyberSec')
# OUTPUT: 'VFBDeWJlclNlYw'
Utils.base64UrlDecode('VFBDeWJlclNlYw')
# OUTPUT: 'TPCyberSec'
Utils.UrlEncode('TP Cyber Security')
# OUTPUT: 'TP%20Cyber%20Security'
Utils.UrlDecode('TP%20Cyber%20Security')
# OUTPUT: 'TP Cyber Security'
```
#### Generating testcases for the Sniper attack
```
from TP_Generator import AttackTypes
InjectionPoints = [
"RequestBody||id",
"RequestBody||name"
]
Payloads = [
[
"' AND '1'='1",
"' AND '1'='0"
]
]
for testcases in AttackTypes.Sniper(InjectionPoints, Payloads):
print(testcases)
# OUTPUT:
# {'RequestBody||id': "' AND '1'='1"}
# {'RequestBody||id': "' AND '1'='0"}
# {'RequestBody||name': "' AND '1'='1"}
# {'RequestBody||name': "' AND '1'='0"}
```
#### Generating testcases for the Batteringram attack
```
from TP_Generator import AttackTypes
InjectionPoints = [
"RequestBody||id",
"RequestBody||name"
]
Payloads = [
[
"' AND '1'='1",
"' AND '1'='0"
]
]
for testcases in AttackTypes.Batteringram(InjectionPoints, Payloads):
print(testcases)
# OUTPUT:
# {'RequestBody||id': "' AND '1'='1", 'RequestBody||name': "' AND '1'='1"}
# {'RequestBody||id': "' AND '1'='0", 'RequestBody||name': "' AND '1'='0"}
```
#### Generating testcases for the Pitchfork attack
```
from TP_Generator import AttackTypes
InjectionPoints = [
"RequestBody||id",
"RequestBody||name"
]
Payloads = [
[
"' AND '1'='1",
"' AND '1'='0"
],
[
"' OR '1'='1",
"' OR '1'='0"
]
]
for testcases in AttackTypes.Pitchfork(InjectionPoints, Payloads):
print(testcases)
# OUTPUT:
# {'RequestBody||id': "' AND '1'='1", 'RequestBody||name': "' OR '1'='1"}
# {'RequestBody||id': "' AND '1'='0", 'RequestBody||name': "' OR '1'='0"}
```
#### Generating testcases for the Clusterbomb attack
```
from TP_Generator import AttackTypes
InjectionPoints = [
"RequestBody||id",
"RequestBody||name"
]
Payloads = [
[
"' AND '1'='1",
"' AND '1'='0",
"' && '1'='1"
],
[
"' OR '1'='1",
"' OR '1'='0",
]
]
for testcases in AttackTypes.Clusterbomb(InjectionPoints, Payloads):
print(testcases)
# OUTPUT:
# {'RequestBody||id': "' AND '1'='1", 'RequestBody||name': "' OR '1'='1"}
# {'RequestBody||id': "' AND '1'='1", 'RequestBody||name': "' OR '1'='0"}
# {'RequestBody||id': "' AND '1'='0", 'RequestBody||name': "' OR '1'='1"}
# {'RequestBody||id': "' AND '1'='0", 'RequestBody||name': "' OR '1'='0"}
# {'RequestBody||id': "' && '1'='1", 'RequestBody||name': "' OR '1'='1"}
# {'RequestBody||id': "' && '1'='1", 'RequestBody||name': "' OR '1'='0"}
```
#### Generating the TOTP, HOTP code
```
from TP_Generator import MFA_Generator
print(MFA_Generator.TOTP("JBSWY3DPEHPK3PXP"))
# OUTPUT: 862642
print(MFA_Generator.HOTP("JBSWY3DPEHPK3PXP", 1))
# OUTPUT: 996554
```
#### Generating the WordPress Nonce for unauthenticated users with wp-rest action
```
from TP_Generator import Nonce_Generator
action = "wp-rest"
NONCE_KEY = "Y9(H0]_u8BA:^or^<^4>AM@EkgnAm`{Mpsq*H!Z-?8 OHe6ITmPY6kQSai)y3w{}"
NONCE_SALT = "xV&%-Ji<,`Clp+|bqt9<c%JrGpq!EiMy///`z0+<D1F<E%H14mha9Csm<TH;~TfH"
print(Nonce_Generator.WordPress_Nonce(nonce_action=action, WORDPRESS_NONCE_KEY=NONCE_KEY, WORDPRESS_NONCE_SALT=NONCE_SALT))
# OUTPUT: ac06630f78
```
#### (Un)parsing QR Code
```
from TP_Generator import QR_Generator
QR_String = "00020101021230340009nbcb@devb01090000001230204DEVB520459995303840540115802KH5912Coffee Klang6010Phnom Penh62300314Coffe Klang0010708A60086679917001316418876882756304CE7C"
QRObj = QR_Generator.initQR("KHQR_Corporate").parse(QR_String)
print(QRObj.dumps())
# OUTPUT: {"PayloadFormatIndicator": "01", "PointOfInitiationMethod": "12", "MerchantAccountInformation": {"BakongAccountID": "nbcb@devb", "MerchantID": "000000123", "AcquiringBank": "DEVB"}, "MerchantCategoryCode": "5999", "TransactionCurrency": "840", "TransactionAmount": "1", "CountryCode": "KH", "MerchantName": "Coffee Klang", "MerchantCity": "Phnom Penh", "AdditionalDataFieldTemplate": {"StoreLabel": "Coffe Klang001", "TerminalLabel": "A6008667"}, "CRC": "CE7C", "Timestamp": {"timestamp": "1641887688275"}}
QRObj.update("TransactionAmount", "1000")
print(QR_Generator.initQR("KHQR_Corporate").unparse(QRObj))
# OUTPUT: 00020101021230340009nbcb@devb01090000001230204DEVB520459995303840540410005802KH5912Coffee Klang6010Phnom Penh62300314Coffe Klang0010708A600866799170013164188768827563043ECD
```
## CHANGELOG
#### [TP-Generator v2025.1.1](https://github.com/truocphan/TP-Generator/tree/2025.1.1)
- **New**: _Utils_: **toUTF16**, **toUTF32**
- **New**: _QR_Generator_: **VNPAYQR**
#### [TP-Generator v2024.12.12](https://github.com/truocphan/TP-Generator/tree/2024.12.12)
- **New**: _Utils_ module
- **New**: _QR_Generator_: Parse/Unparse QR code types: **VietQR**, **MoMo**, **KHQR_Individual**, **KHQR_Corporate**
#### [TP-Generator v2024.8.10](https://github.com/truocphan/TP-Generator/tree/2024.8.10)
- **Updated**: _AttackTypes_: **Sniper**, **Batteringram**, **Pitchfork**, **Pitchfork**
- **New**: _Nonce_Generator_: Generate the WordPress Nonce
#### [TP-Generator v2024.6.13](https://github.com/truocphan/TP-Generator/tree/2024.6.13)
- **Updated**: _MFA_Generator_: Fixed error generating **TOTP**, **HOTP** from jython
#### [TP-Generator v2024.4.5](https://github.com/truocphan/TP-Generator/tree/2024.4.5)
- **New**: _Bruteforcer_List_: **UUID1**
#### [TP-Generator v2024.3.3](https://github.com/truocphan/TP-Generator/tree/2024.3.3)
- **New**: _MFA_Generator_: **TOTP** (Time-based One-Time Password) and **HOTP** (HMAC-based One-Time Password)
#### [TP-Generator v2024.3.1](https://github.com/truocphan/TP-Generator/tree/2024.3.1)
- **New**: Generate test cases for attack types: **_Sniper_**, **_Battering Ram_**, **_Pitchfork_**, **_Cluster Bomb_**
Raw data
{
"_id": null,
"home_page": "https://github.com/truocphan/TP-Generator",
"name": "TP-Generator",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "TPCyberSec, TP-Generator",
"author": "TP Cyber Security",
"author_email": "tpcybersec2023@gmail.com",
"download_url": null,
"platform": null,
"description": "# TP-Generator\n\n<p align=\"center\">\n\t<a href=\"https://github.com/truocphan/TP-Generator/releases/\"><img src=\"https://img.shields.io/github/release/truocphan/TP-Generator\" height=30></a>\n\t<a href=\"#\"><img src=\"https://img.shields.io/github/downloads/truocphan/TP-Generator/total\" height=30></a>\n\t<a href=\"#\"><img src=\"https://img.shields.io/github/stars/truocphan/TP-Generator\" height=30></a>\n\t<a href=\"#\"><img src=\"https://img.shields.io/github/forks/truocphan/TP-Generator\" height=30></a>\n\t<a href=\"https://github.com/truocphan/TP-Generator/issues?q=is%3Aopen+is%3Aissue\"><img src=\"https://img.shields.io/github/issues/truocphan/TP-Generator\" height=30></a>\n\t<a href=\"https://github.com/truocphan/TP-Generator/issues?q=is%3Aissue+is%3Aclosed\"><img src=\"https://img.shields.io/github/issues-closed/truocphan/TP-Generator\" height=30></a>\n\t<br>\n\t<a href=\"#\"><img src=\"https://img.shields.io/pypi/v/TP-Generator\" height=30></a>\n\t<a href=\"#\"><img src=\"https://img.shields.io/pypi/dm/TP-Generator\" height=30></a>\n</p>\n\n## Installation\n#### From PyPI:\n```console\npip install TP-Generator\n```\n#### From Source:\n```console\ngit clone https://github.com/truocphan/TP-Generator.git --branch <Branch/Tag>\ncd TP-Generator\npython setup.py build\npython setup.py install\n```\n\n## Basic Usage\n### Utils\n```\nfrom TP_Generator import Utils\n\nUtils.timestamp(10)\n# OUTPUT: 1733597189\n\nUtils.uuid(1)\n# OUTPUT: '9daeab4b-b4cb-11ef-b79b-00a554ba203d'\n\nUtils.RandomNumber(0, 1000)\n# OUTPUT: 931\n\nUtils.RandomString(10)\n# OUTPUT: 'Wz<:1<.YSC'\n\nUtils.toUTF16('TPCyberSec')\n# OUTPUT: 'VABQAEMAeQBiAGUAcgBTAGUAYwA='\n\nUtils.toUTF32('TPCyberSec')\n# OUTPUT: 'VAAAAFAAAABDAAAAeQAAAGIAAABlAAAAcgAAAFMAAABlAAAAYwAAAA=='\n\nUtils.Str2Hex('TPCyberSec')\n# OUTPUT: '54504379626572536563'\n\nUtils.Hex2Str('54504379626572536563')\n# OUTPUT: 'TPCyberSec'\n\nUtils.base64Encode('TPCyberSec')\n# OUTPUT: 'VFBDeWJlclNlYw=='\n\nUtils.base64Decode('VFBDeWJlclNlYw==')\n# OUTPUT: 'TPCyberSec'\n\nUtils.base64UrlEncode('TPCyberSec')\n# OUTPUT: 'VFBDeWJlclNlYw'\n\nUtils.base64UrlDecode('VFBDeWJlclNlYw')\n# OUTPUT: 'TPCyberSec'\n\nUtils.UrlEncode('TP Cyber Security')\n# OUTPUT: 'TP%20Cyber%20Security'\n\nUtils.UrlDecode('TP%20Cyber%20Security')\n# OUTPUT: 'TP Cyber Security'\n\n```\n\n#### Generating testcases for the Sniper attack\n```\nfrom TP_Generator import AttackTypes\n\nInjectionPoints = [\n\t\"RequestBody||id\",\n\t\"RequestBody||name\"\n]\n\nPayloads = [\n\t[\n\t\t\"' AND '1'='1\",\n\t\t\"' AND '1'='0\"\n\t]\n]\n\nfor testcases in AttackTypes.Sniper(InjectionPoints, Payloads):\n\tprint(testcases)\n\n# OUTPUT:\n# {'RequestBody||id': \"' AND '1'='1\"}\n# {'RequestBody||id': \"' AND '1'='0\"}\n# {'RequestBody||name': \"' AND '1'='1\"}\n# {'RequestBody||name': \"' AND '1'='0\"}\n```\n\n#### Generating testcases for the Batteringram attack\n```\nfrom TP_Generator import AttackTypes\n\nInjectionPoints = [\n\t\"RequestBody||id\",\n\t\"RequestBody||name\"\n]\n\nPayloads = [\n\t[\n\t\t\"' AND '1'='1\",\n\t\t\"' AND '1'='0\"\n\t]\n]\n\nfor testcases in AttackTypes.Batteringram(InjectionPoints, Payloads):\n\tprint(testcases)\n\n# OUTPUT:\n# {'RequestBody||id': \"' AND '1'='1\", 'RequestBody||name': \"' AND '1'='1\"}\n# {'RequestBody||id': \"' AND '1'='0\", 'RequestBody||name': \"' AND '1'='0\"}\n```\n\n#### Generating testcases for the Pitchfork attack\n```\nfrom TP_Generator import AttackTypes\n\nInjectionPoints = [\n\t\"RequestBody||id\",\n\t\"RequestBody||name\"\n]\n\nPayloads = [\n\t[\n\t\t\"' AND '1'='1\",\n\t\t\"' AND '1'='0\"\n\t],\n\t[\n\t\t\"' OR '1'='1\",\n\t\t\"' OR '1'='0\"\n\t]\n]\n\nfor testcases in AttackTypes.Pitchfork(InjectionPoints, Payloads):\n\tprint(testcases)\n\n# OUTPUT:\n# {'RequestBody||id': \"' AND '1'='1\", 'RequestBody||name': \"' OR '1'='1\"}\n# {'RequestBody||id': \"' AND '1'='0\", 'RequestBody||name': \"' OR '1'='0\"}\n```\n\n#### Generating testcases for the Clusterbomb attack\n```\nfrom TP_Generator import AttackTypes\n\nInjectionPoints = [\n\t\"RequestBody||id\",\n\t\"RequestBody||name\"\n]\n\nPayloads = [\n\t[\n\t\t\"' AND '1'='1\",\n\t\t\"' AND '1'='0\",\n\t\t\"' && '1'='1\"\n\t],\n\t[\n\t\t\"' OR '1'='1\",\n\t\t\"' OR '1'='0\",\n\t]\n]\n\nfor testcases in AttackTypes.Clusterbomb(InjectionPoints, Payloads):\n\tprint(testcases)\n\n# OUTPUT:\n# {'RequestBody||id': \"' AND '1'='1\", 'RequestBody||name': \"' OR '1'='1\"}\n# {'RequestBody||id': \"' AND '1'='1\", 'RequestBody||name': \"' OR '1'='0\"}\n# {'RequestBody||id': \"' AND '1'='0\", 'RequestBody||name': \"' OR '1'='1\"}\n# {'RequestBody||id': \"' AND '1'='0\", 'RequestBody||name': \"' OR '1'='0\"}\n# {'RequestBody||id': \"' && '1'='1\", 'RequestBody||name': \"' OR '1'='1\"}\n# {'RequestBody||id': \"' && '1'='1\", 'RequestBody||name': \"' OR '1'='0\"}\n```\n\n#### Generating the TOTP, HOTP code\n```\nfrom TP_Generator import MFA_Generator\n\nprint(MFA_Generator.TOTP(\"JBSWY3DPEHPK3PXP\"))\n# OUTPUT: 862642\n\nprint(MFA_Generator.HOTP(\"JBSWY3DPEHPK3PXP\", 1))\n# OUTPUT: 996554\n```\n\n#### Generating the WordPress Nonce for unauthenticated users with wp-rest action\n```\nfrom TP_Generator import Nonce_Generator\n\naction = \"wp-rest\"\nNONCE_KEY = \"Y9(H0]_u8BA:^or^<^4>AM@EkgnAm`{Mpsq*H!Z-?8 OHe6ITmPY6kQSai)y3w{}\"\nNONCE_SALT = \"xV&%-Ji<,`Clp+|bqt9<c%JrGpq!EiMy///`z0+<D1F<E%H14mha9Csm<TH;~TfH\"\n\nprint(Nonce_Generator.WordPress_Nonce(nonce_action=action, WORDPRESS_NONCE_KEY=NONCE_KEY, WORDPRESS_NONCE_SALT=NONCE_SALT))\n# OUTPUT: ac06630f78\n```\n\n#### (Un)parsing QR Code\n```\nfrom TP_Generator import QR_Generator\n\nQR_String = \"00020101021230340009nbcb@devb01090000001230204DEVB520459995303840540115802KH5912Coffee Klang6010Phnom Penh62300314Coffe Klang0010708A60086679917001316418876882756304CE7C\"\n\nQRObj = QR_Generator.initQR(\"KHQR_Corporate\").parse(QR_String)\nprint(QRObj.dumps())\n# OUTPUT: {\"PayloadFormatIndicator\": \"01\", \"PointOfInitiationMethod\": \"12\", \"MerchantAccountInformation\": {\"BakongAccountID\": \"nbcb@devb\", \"MerchantID\": \"000000123\", \"AcquiringBank\": \"DEVB\"}, \"MerchantCategoryCode\": \"5999\", \"TransactionCurrency\": \"840\", \"TransactionAmount\": \"1\", \"CountryCode\": \"KH\", \"MerchantName\": \"Coffee Klang\", \"MerchantCity\": \"Phnom Penh\", \"AdditionalDataFieldTemplate\": {\"StoreLabel\": \"Coffe Klang001\", \"TerminalLabel\": \"A6008667\"}, \"CRC\": \"CE7C\", \"Timestamp\": {\"timestamp\": \"1641887688275\"}}\n\nQRObj.update(\"TransactionAmount\", \"1000\")\nprint(QR_Generator.initQR(\"KHQR_Corporate\").unparse(QRObj))\n# OUTPUT: 00020101021230340009nbcb@devb01090000001230204DEVB520459995303840540410005802KH5912Coffee Klang6010Phnom Penh62300314Coffe Klang0010708A600866799170013164188768827563043ECD\n```\n\n\n## CHANGELOG\n#### [TP-Generator v2025.1.1](https://github.com/truocphan/TP-Generator/tree/2025.1.1)\n- **New**: _Utils_: **toUTF16**, **toUTF32**\n- **New**: _QR_Generator_: **VNPAYQR**\n\n#### [TP-Generator v2024.12.12](https://github.com/truocphan/TP-Generator/tree/2024.12.12)\n- **New**: _Utils_ module\n- **New**: _QR_Generator_: Parse/Unparse QR code types: **VietQR**, **MoMo**, **KHQR_Individual**, **KHQR_Corporate**\n\n#### [TP-Generator v2024.8.10](https://github.com/truocphan/TP-Generator/tree/2024.8.10)\n- **Updated**: _AttackTypes_: **Sniper**, **Batteringram**, **Pitchfork**, **Pitchfork**\n- **New**: _Nonce_Generator_: Generate the WordPress Nonce\n\n#### [TP-Generator v2024.6.13](https://github.com/truocphan/TP-Generator/tree/2024.6.13)\n- **Updated**: _MFA_Generator_: Fixed error generating **TOTP**, **HOTP** from jython\n\n#### [TP-Generator v2024.4.5](https://github.com/truocphan/TP-Generator/tree/2024.4.5)\n- **New**: _Bruteforcer_List_: **UUID1**\n\n#### [TP-Generator v2024.3.3](https://github.com/truocphan/TP-Generator/tree/2024.3.3)\n- **New**: _MFA_Generator_: **TOTP** (Time-based One-Time Password) and **HOTP** (HMAC-based One-Time Password)\n\n#### [TP-Generator v2024.3.1](https://github.com/truocphan/TP-Generator/tree/2024.3.1)\n- **New**: Generate test cases for attack types: **_Sniper_**, **_Battering Ram_**, **_Pitchfork_**, **_Cluster Bomb_**\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": null,
"version": "2025.1.1",
"project_urls": {
"Homepage": "https://github.com/truocphan/TP-Generator"
},
"split_keywords": [
"tpcybersec",
" tp-generator"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "3db92b18978816de2c564113c021caa89973909019b464f07ce4c9374f30fdd1",
"md5": "07075cf8287296219beedb9be5110033",
"sha256": "6d8eb57d90248403d02f3c324d3d0ef389ad26d6b7079304ed574d579017cbda"
},
"downloads": -1,
"filename": "TP_Generator-2025.1.1-py2-none-any.whl",
"has_sig": false,
"md5_digest": "07075cf8287296219beedb9be5110033",
"packagetype": "bdist_wheel",
"python_version": "py2",
"requires_python": null,
"size": 11536,
"upload_time": "2025-01-01T15:28:48",
"upload_time_iso_8601": "2025-01-01T15:28:48.517734Z",
"url": "https://files.pythonhosted.org/packages/3d/b9/2b18978816de2c564113c021caa89973909019b464f07ce4c9374f30fdd1/TP_Generator-2025.1.1-py2-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "83b1ec5f0b82756b4fea88308880ad31ffad77f2fd109ae76d2fbb7ef688f3d8",
"md5": "a5ccdb1e7bb2d7542b6a3c70eeab2681",
"sha256": "acf16432fcfa633f165210b6b7d1a8ff447902e3cb8c7cea6075e2f9318534c5"
},
"downloads": -1,
"filename": "TP_Generator-2025.1.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "a5ccdb1e7bb2d7542b6a3c70eeab2681",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 11553,
"upload_time": "2025-01-01T15:28:50",
"upload_time_iso_8601": "2025-01-01T15:28:50.849293Z",
"url": "https://files.pythonhosted.org/packages/83/b1/ec5f0b82756b4fea88308880ad31ffad77f2fd109ae76d2fbb7ef688f3d8/TP_Generator-2025.1.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-01-01 15:28:48",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "truocphan",
"github_project": "TP-Generator",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "json-duplicate-keys",
"specs": [
[
">=",
"2024.12.12"
]
]
}
],
"lcname": "tp-generator"
}