Compare commits
16 Commits
2c16bea045
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| f47b280634 | |||
| 67db5c7a11 | |||
| 4a75e30671 | |||
| 68649ba214 | |||
| b052e82358 | |||
| 667d3c205a | |||
| adbf40240c | |||
| 6232b79ffa | |||
| 043526229e | |||
| 98e0f594df | |||
| 2be258380f | |||
| c6a8d7c804 | |||
| 06f0e5eb86 | |||
| 5402524456 | |||
| ced142e044 | |||
| 13ec20a19f |
4
.gitattributes
vendored
4
.gitattributes
vendored
@@ -119,8 +119,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.html linguist-language=HTML
|
||||
*.css linguist-language=CSS
|
||||
*.js linguist-language=JavaScript
|
||||
*.json linguist-language=JSON
|
||||
*.md linguist-language=Markdown
|
||||
#*.json linguist-language=JSON
|
||||
#*.md linguist-language=Markdown
|
||||
*.yml linguist-language=YAML
|
||||
*.yaml linguist-language=YAML
|
||||
*.c linguist-language=C
|
||||
|
||||
43
.gitea/workflows/ci.yaml
Normal file
43
.gitea/workflows/ci.yaml
Normal file
@@ -0,0 +1,43 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r backend/requirements.txt
|
||||
|
||||
- name: Lint backend
|
||||
run: |
|
||||
pip install flake8
|
||||
flake8 backend
|
||||
|
||||
frontend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check frontend files
|
||||
run: |
|
||||
test -f frontend/templates/index.html
|
||||
test -f frontend/css/style.css
|
||||
test -f frontend/js/main.js
|
||||
@@ -3,6 +3,7 @@ from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class Config:
|
||||
"""
|
||||
Конфигурация FastAPI приложения.
|
||||
|
||||
@@ -4,11 +4,12 @@ from fastapi.responses import FileResponse
|
||||
from pathlib import Path
|
||||
|
||||
# Импорт роутера
|
||||
from .routes.license_routes import router as license_router # Изменено: один dot вместо двух
|
||||
from .routes.license_routes import router as license_router
|
||||
|
||||
# Путь к корню проекта
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
|
||||
|
||||
def create_app() -> FastAPI:
|
||||
"""
|
||||
Создание и конфигурация FastAPI приложения.
|
||||
@@ -24,9 +25,21 @@ def create_app() -> FastAPI:
|
||||
apps.include_router(license_router, prefix="/api")
|
||||
|
||||
# Монтируем статические папки фронтенда
|
||||
apps.mount("/static/css", StaticFiles(directory=BASE_DIR.parent / "frontend" / "css"), name="css")
|
||||
apps.mount("/static/js", StaticFiles(directory=BASE_DIR.parent / "frontend" / "js"), name="js")
|
||||
apps.mount("/static/assets", StaticFiles(directory=BASE_DIR.parent / "frontend" / "assets"), name="assets")
|
||||
apps.mount(
|
||||
"/static/css",
|
||||
StaticFiles(directory=BASE_DIR.parent / "frontend" / "css"),
|
||||
name="css"
|
||||
)
|
||||
apps.mount(
|
||||
"/static/js",
|
||||
StaticFiles(directory=BASE_DIR.parent / "frontend" / "js"),
|
||||
name="js"
|
||||
)
|
||||
apps.mount(
|
||||
"/static/assets",
|
||||
StaticFiles(directory=BASE_DIR.parent / "frontend" / "assets"),
|
||||
name="assets"
|
||||
)
|
||||
|
||||
# Отдача главной страницы
|
||||
@apps.get("/", include_in_schema=False)
|
||||
@@ -34,8 +47,11 @@ def create_app() -> FastAPI:
|
||||
"""
|
||||
Отдает главную страницу сайта (index.html)
|
||||
"""
|
||||
return FileResponse(BASE_DIR.parent / "frontend" / "templates" / "index.html")
|
||||
index_file = BASE_DIR.parent / "frontend" / "templates" / "index.html"
|
||||
return FileResponse(index_file)
|
||||
|
||||
return apps
|
||||
|
||||
|
||||
# Экземпляр приложения
|
||||
app: FastAPI = create_app()
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from .license_routes import *
|
||||
|
||||
@@ -5,6 +5,7 @@ from ..services.license_service import generate_license_file
|
||||
|
||||
router: APIRouter = APIRouter()
|
||||
|
||||
|
||||
@router.post("/generate", response_class=FileResponse)
|
||||
async def generate_license(
|
||||
background_tasks: BackgroundTasks,
|
||||
@@ -20,17 +21,27 @@ async def generate_license(
|
||||
- FileResponse: сгенерированный ZIP файл с именем Custom.mxtpro
|
||||
"""
|
||||
if not name.strip() or not version.strip():
|
||||
raise HTTPException(status_code=400, detail="NAME и VERSION обязательны.")
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="NAME и VERSION обязательны."
|
||||
)
|
||||
try:
|
||||
# Создаём временный файл на сервере
|
||||
filepath, temp_dir = generate_license_file(name, version)
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Ошибка генерации лицензии: {e}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Ошибка генерации лицензии: {e}"
|
||||
)
|
||||
|
||||
# Удаляем директорию (и файл внутри) после отправки пользователю
|
||||
background_tasks.add_task(temp_dir.cleanup)
|
||||
|
||||
# Отправляем с фиксированным именем Custom.mxtpro
|
||||
return FileResponse(
|
||||
filepath,
|
||||
media_type="application/octet-stream",
|
||||
headers={"Content-Disposition": 'attachment; filename="Custom.mxtpro"'}
|
||||
headers={
|
||||
"Content-Disposition": 'attachment; filename="Custom.mxtpro"'
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from .license_service import *
|
||||
|
||||
@@ -4,11 +4,13 @@ from pathlib import Path
|
||||
from ..utils.encoding import variant_base64_encode
|
||||
from ..utils.crypto import encrypt_bytes
|
||||
|
||||
|
||||
class LicenseType:
|
||||
Professional: int = 1
|
||||
Educational: int = 3
|
||||
Personal: int = 4
|
||||
|
||||
|
||||
def generate_license_file(
|
||||
user_name: str,
|
||||
version: str,
|
||||
@@ -26,11 +28,13 @@ def generate_license_file(
|
||||
minor_version: int = int(minor_str)
|
||||
except Exception as e:
|
||||
raise ValueError(f"Неверный формат версии: {version}") from e
|
||||
# Формирование строки лицензии (исправлено: убрали лишний #, интегрировали цифры в один блок)
|
||||
|
||||
# Формирование строки лицензии
|
||||
license_str: str = (
|
||||
f"{lic_type}#{user_name}|{major_version}{minor_version}"
|
||||
f"#{count}#{major_version}3{minor_version}6{minor_version}#0#0#0#"
|
||||
)
|
||||
|
||||
# Шифрование и кодирование
|
||||
encrypted: bytes = encrypt_bytes(0x0787, license_str.encode("utf-8"))
|
||||
encoded: str = variant_base64_encode(encrypted).decode("ascii")
|
||||
@@ -40,4 +44,5 @@ def generate_license_file(
|
||||
filepath = Path(temp_dir.name) / "Custom.mxtpro"
|
||||
with ZipFile(filepath, "w") as zf:
|
||||
zf.writestr("Pro.key", encoded)
|
||||
|
||||
return str(filepath), temp_dir
|
||||
@@ -1,2 +0,0 @@
|
||||
from .crypto import *
|
||||
from .encoding import *
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
from typing import Dict
|
||||
|
||||
# Таблица Base64-подобного варианта
|
||||
VariantBase64Table: str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||
VariantBase64Dict: Dict[int, str] = {i: VariantBase64Table[i] for i in range(len(VariantBase64Table))}
|
||||
VariantBase64ReverseDict: Dict[str, int] = {VariantBase64Table[i]: i for i in range(len(VariantBase64Table))}
|
||||
VariantBase64Table: str = (
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||
)
|
||||
VariantBase64Dict: Dict[int, str] = {
|
||||
i: VariantBase64Table[i] for i in range(len(VariantBase64Table))
|
||||
}
|
||||
VariantBase64ReverseDict: Dict[str, int] = {
|
||||
VariantBase64Table[i]: i for i in range(len(VariantBase64Table))
|
||||
}
|
||||
|
||||
|
||||
def variant_base64_encode(bs: bytes) -> bytes:
|
||||
@@ -24,7 +30,8 @@ def variant_base64_encode(bs: bytes) -> bytes:
|
||||
b: bytes = bs[3*i:3*i+3]
|
||||
coding_int: int = int.from_bytes(b, "little")
|
||||
block: str = "".join(
|
||||
VariantBase64Dict[(coding_int >> shift) & 0x3F] for shift in (0, 6, 12, 18)
|
||||
VariantBase64Dict[(coding_int >> shift) & 0x3F]
|
||||
for shift in (0, 6, 12, 18)
|
||||
)
|
||||
result.extend(block.encode("ascii"))
|
||||
|
||||
@@ -33,7 +40,8 @@ def variant_base64_encode(bs: bytes) -> bytes:
|
||||
b: bytes = bs[-left_bytes:]
|
||||
coding_int: int = int.from_bytes(b, "little")
|
||||
block: str = "".join(
|
||||
VariantBase64Dict[(coding_int >> shift) & 0x3F] for shift in range(0, left_bytes*8 + 1, 6)
|
||||
VariantBase64Dict[(coding_int >> shift) & 0x3F]
|
||||
for shift in range(0, left_bytes * 8 + 1, 6)
|
||||
)
|
||||
result.extend(block.encode("ascii"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user