From 81ddc973d9e213fb9d49b8b2e9aedbaaa1219633 Mon Sep 17 00:00:00 2001 From: GamerNoTitle Date: Sun, 22 Sep 2024 18:14:36 +0800 Subject: [PATCH] init --- .gitignore | 2 + README.md | 68 +++++++++++++++++++++++++++++ app/__init__.py | 0 app/main.py | 94 ++++++++++++++++++++++++++++++++++++++++ app/static/scripts.js | 7 +++ app/static/styles.css | 69 +++++++++++++++++++++++++++++ app/templates/index.html | 67 ++++++++++++++++++++++++++++ requirements.txt | 5 +++ 8 files changed, 312 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 app/__init__.py create mode 100644 app/main.py create mode 100644 app/static/scripts.js create mode 100644 app/static/styles.css create mode 100644 app/templates/index.html create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d75edea --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +venv +__pycache__ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9ad8750 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# JetbrainsLSAvaliableChecker + +Check a Jetbrains License Server is avaliable or not. + +## Quick Start + +- Install Python + +- ```bash + $ pip install -r requirements.txt + ``` + +- ```bash + $ uvicorn app.main:app --reload + ``` + +## API Usage + +- Path: `/api/fetch` + +- Methods: `GET` or `POST` + +- params: + + - `server`: The server url of the license server + +- Return: + + - ```json + { + "available": bool, + "message": str, + "data": { + "release_ticket_data": { + "action": str, + "confirmation_stamp": str, + "lease_signature": str, + "response_code": str, + "salt": str, + "server_lease": str, + "server_uid": str, + "validation_deadline_period": str, + "validation_period": str + }, + "obtain_ticket_data": { + "action": str, + "confirmation_stamp": str, + "lease_signature": str, + "message": str, + "prolongation_period": str, + "response_code": str, + "salt": str, + "server_lease": str, + "server_uid": str, + "validation_deadline_period": str, + "validation_period": str + } + } + } + ``` + +## Disclaimer + +This program and its related documentation are provided for general informational purposes only. While we strive to ensure the accuracy and completeness of the information, we make no representations or warranties of any kind, express or implied, regarding the accuracy, reliability, or completeness of the content. You use this program at your own risk. + +We shall not be liable for any direct, indirect, incidental, special, or consequential damages arising from the use or inability to use this program, including but not limited to loss of data or profits, even if we have been advised of the possibility of such damages. + +The use of this program may be subject to certain legal and regulatory requirements, and users are responsible for understanding and complying with applicable laws and regulations. We reserve the right to modify this disclaimer at any time without notice. diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/main.py b/app/main.py new file mode 100644 index 0000000..c53b809 --- /dev/null +++ b/app/main.py @@ -0,0 +1,94 @@ +from fastapi import FastAPI, Form, Request +from fastapi.responses import HTMLResponse, JSONResponse +from fastapi.templating import Jinja2Templates +from fastapi.staticfiles import StaticFiles +import httpx +import uuid +import string +import random +import xml.etree.ElementTree as ET + +app = FastAPI() + +templates = Jinja2Templates(directory="app/templates") + +ascii_list = list(string.ascii_letters + string.digits) +DESKTOP_NAME = "DESKTOP-" + "".join(random.sample(ascii_list, 7)).upper() +MACHINE_ID = uuid.uuid4() +USERNAME = "".join(random.sample(ascii_list, 7)).upper() +VERSION = 2024100 +BUILD_NUMBER = "2024.1.4+Build+CL-241.18034.45" + +# 配置静态文件 +app.mount("/static", StaticFiles(directory="app/static"), name="static") + +# 获取并解析 XML 响应 +def get_xml_data(server: str, ticket_path: str): + client = httpx.Client(verify=False) + try: + response = client.get(server + ticket_path, timeout=3) # 设置超时为10秒 + response.raise_for_status() # 检查响应状态 + root = ET.fromstring(response.text) + + return { + "action": root.find("action").text, + "confirmation_stamp": root.find("confirmationStamp").text, + "lease_signature": root.find("leaseSignature").text, + "response_code": root.find("responseCode").text, + "salt": root.find("salt").text, + "server_lease": root.find("serverLease").text, + "server_uid": root.find("serverUid").text, + "validation_deadline_period": root.find("validationDeadlinePeriod").text, + "validation_period": root.find("validationPeriod").text, + "message": root.find("message").text + } + except httpx.ReadTimeout: + return {"error": "Timeout: Please try again later."} + except Exception as e: + return {"error": f"An unexpected error occurred: {str(e)}. It seems that this server is not avaliable or you can try again later."} + +@app.get("/", response_class=HTMLResponse) +async def index(request: Request): + return templates.TemplateResponse("index.html", {"request": request}) + +@app.post("/fetch", response_class=HTMLResponse) +async def fetch_data(request: Request, server: str = Form(...)): + RELEASE_TICKET_PATH = f"/rpc/releaseTicket.action?buildNumber={BUILD_NUMBER}&clientVersion=16&hostName={DESKTOP_NAME}&machineId={MACHINE_ID}&productCode=cfc7082d-ae43-4978-a2a2-46feb1679405&productFamilyId=cfc7082d-ae43-4978-a2a2-46feb1679405&salt=1726973268812&secure=false&ticketId=rsoaehfbbg&userName={USERNAME}" + OBTAIN_TICKET_PATH = f"/rpc/obtainTicket.action?buildDate=20240409&{BUILD_NUMBER}&clientVersion=16&hostName={DESKTOP_NAME}&machineId={MACHINE_ID}&productCode=cfc7082d-ae43-4978-a2a2-46feb1679405&productFamilyId=cfc7082d-ae43-4978-a2a2-46feb1679405&salt=1726973269845&secure=false&userName={USERNAME}&version={VERSION}&versionNumber={VERSION}" + + release_ticket_data = get_xml_data(server, RELEASE_TICKET_PATH) + obtain_ticket_data = get_xml_data(server, OBTAIN_TICKET_PATH) + + return templates.TemplateResponse("index.html", { + "request": request, + "release_data": release_ticket_data, + "obtain_data": obtain_ticket_data, + "server": server + }) + +@app.get("/api/fetch") +@app.post("/api/fetch") +async def api_fetch(server: str = Form(...)): + return await handle_fetch(server) + +async def handle_fetch(server: str): + RELEASE_TICKET_PATH = f"/rpc/releaseTicket.action?buildNumber={BUILD_NUMBER}&clientVersion=16&hostName={DESKTOP_NAME}&machineId={MACHINE_ID}&productCode=cfc7082d-ae43-4978-a2a2-46feb1679405&productFamilyId=cfc7082d-ae43-4978-a2a2-46feb1679405&salt=1726973268812&secure=false&ticketId=rsoaehfbbg&userName={USERNAME}" + OBTAIN_TICKET_PATH = f"/rpc/obtainTicket.action?buildDate=20240409&{BUILD_NUMBER}&clientVersion=16&hostName={DESKTOP_NAME}&machineId={MACHINE_ID}&productCode=cfc7082d-ae43-4978-a2a2-46feb1679405&productFamilyId=cfc7082d-ae43-4978-a2a2-46feb1679405&salt=1726973269845&secure=false&userName={USERNAME}&version={VERSION}&versionNumber={VERSION}" + + release_ticket_data = get_xml_data(server, RELEASE_TICKET_PATH) + obtain_ticket_data = get_xml_data(server, OBTAIN_TICKET_PATH) + + available = False + if obtain_ticket_data.get("response_code") == "OK": + available = True + elif obtain_ticket_data.get("response_code") == "Error": + available = False + + return JSONResponse(content={ + "available": available, + "message": obtain_ticket_data.get("message", ""), + "data": { + "release_ticket_data": release_ticket_data, + "obtain_ticket_data": obtain_ticket_data, + } + }) \ No newline at end of file diff --git a/app/static/scripts.js b/app/static/scripts.js new file mode 100644 index 0000000..258bf06 --- /dev/null +++ b/app/static/scripts.js @@ -0,0 +1,7 @@ +document.getElementById('server-form').addEventListener('submit', function(e) { + const serverInput = document.getElementById('server').value; + if (!serverInput.startsWith('https://') && !serverInput.startsWith('http://')) { + e.preventDefault(); + alert('Please enter a valid server URL starting with https:// or http://'); + } +}); diff --git a/app/static/styles.css b/app/static/styles.css new file mode 100644 index 0000000..6cf558c --- /dev/null +++ b/app/static/styles.css @@ -0,0 +1,69 @@ +body { + font-family: Arial, sans-serif; + margin: 20px; + background-color: #f4f4f4; + color: #333; +} + +h1 { + color: #007bff; + text-align: center; +} + +form { + margin-bottom: 20px; + text-align: center; +} + +input[type="text"] { + padding: 10px; + margin-right: 10px; + width: 300px; +} + +button { + padding: 10px 15px; + background-color: #007bff; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; +} + +button:hover { + background-color: #0056b3; +} + +hr { + margin: 40px 0; +} + +#results { + margin-top: 20px; +} + +form { + margin-bottom: 20px; +} + +table { + width: 1200px; + border-collapse: collapse; + margin-bottom: 30px; +} + +th, td { + border: 1px solid #ddd; + padding: 8px; + text-align: left; + word-wrap: break-word; /* 允许单词换行 */ + max-width: 300px; /* 设置最大宽度 */ +} + +th { + background-color: #f2f2f2; +} + +tr:hover { + background-color: #f1f1f1; +} \ No newline at end of file diff --git a/app/templates/index.html b/app/templates/index.html new file mode 100644 index 0000000..fcd2837 --- /dev/null +++ b/app/templates/index.html @@ -0,0 +1,67 @@ + + + + + + License Server Information + + + +

JetBrains License Server Info Fetcher

+ +
+ + + +
+
+
+ {% if obtain_data.response_code == "" %} +

Please input your server to check.

+ {% elif obtain_data.error %} +

{{ obtain_data.error }}

+ {% elif obtain_data.response_code == "OK" %} +

This server is available.

+ {% else %} +

This server is not available: {{ obtain_data.message }}

+ {% endif %} +
+
+ +
+ {% if release_data and obtain_data %} +

Release Ticket Data

+ + + + + + + + + + + +
FieldValue
Action{{ release_data.action }}
Confirmation Stamp{{ release_data.confirmation_stamp }}
Lease Signature{{ release_data.lease_signature }}
Response Code{{ release_data.response_code }}
Salt{{ release_data.salt }}
Server Lease{{ release_data.server_lease }}
Server UID{{ release_data.server_uid }}
Validation Deadline Period{{ release_data.validation_deadline_period }}
Validation Period{{ release_data.validation_period }}
+ +

Obtain Ticket Data

+ + + + + + + + + + + + + +
FieldValue
Action{{ obtain_data.action }}
Confirmation Stamp{{ obtain_data.confirmation_stamp }}
Lease Signature{{ obtain_data.lease_signature }}
Message{{ obtain_data.message }}
Prolongation Period{{ obtain_data.prolongation_period }}
Response Code{{ obtain_data.response_code }}
Salt{{ obtain_data.salt }}
Server Lease{{ obtain_data.server_lease }}
Server UID{{ obtain_data.server_uid }}
Validation Deadline Period{{ obtain_data.validation_deadline_period }}
Validation Period{{ obtain_data.validation_period }}
+ {% endif %} +
+ + + + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f2ff9ef --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +fastapi +uvicorn +httpx +jinja2 +python-multipart \ No newline at end of file