lizenzserver API gedöns
Dieser Commit ist enthalten in:
@@ -2,6 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy.orm import Session
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, Any
|
||||
import uuid
|
||||
|
||||
from app.db.database import get_db
|
||||
from app.models.models import License, Activation, Version
|
||||
@@ -9,7 +10,13 @@ from app.schemas.license import (
|
||||
LicenseActivationRequest,
|
||||
LicenseActivationResponse,
|
||||
LicenseVerificationRequest,
|
||||
LicenseVerificationResponse
|
||||
LicenseVerificationResponse,
|
||||
SessionStartRequest,
|
||||
SessionStartResponse,
|
||||
SessionHeartbeatRequest,
|
||||
SessionHeartbeatResponse,
|
||||
SessionEndRequest,
|
||||
SessionEndResponse
|
||||
)
|
||||
from app.core.security import get_api_key
|
||||
from app.core.config import settings
|
||||
@@ -206,4 +213,185 @@ async def get_license_info(
|
||||
}
|
||||
for a in activations
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@router.post("/session/start", response_model=SessionStartResponse)
|
||||
async def start_session(
|
||||
request: SessionStartRequest,
|
||||
db: Session = Depends(get_db),
|
||||
api_key = Depends(get_api_key)
|
||||
):
|
||||
# Verify API key matches client config
|
||||
from sqlalchemy import text
|
||||
result = db.execute(text("SELECT api_key, current_version, minimum_version FROM client_configs WHERE client_name = 'Account Forger'")).first()
|
||||
|
||||
if not result or result.api_key != api_key:
|
||||
raise HTTPException(status_code=401, detail="Invalid API key")
|
||||
|
||||
# Check if version is supported
|
||||
if request.version < result.minimum_version:
|
||||
return SessionStartResponse(
|
||||
success=False,
|
||||
message=f"Version {request.version} is too old. Minimum required: {result.minimum_version}",
|
||||
session_token=None,
|
||||
requires_update=True,
|
||||
update_url=None,
|
||||
whats_new=None
|
||||
)
|
||||
|
||||
# Verify license exists and is active
|
||||
license = db.query(License).filter(
|
||||
License.license_key == request.license_key,
|
||||
License.is_active == True
|
||||
).first()
|
||||
|
||||
if not license:
|
||||
return SessionStartResponse(
|
||||
success=False,
|
||||
message="Invalid or inactive license key",
|
||||
session_token=None
|
||||
)
|
||||
|
||||
if license.expires_at and license.expires_at < datetime.utcnow():
|
||||
return SessionStartResponse(
|
||||
success=False,
|
||||
message="License has expired",
|
||||
session_token=None
|
||||
)
|
||||
|
||||
# Check for existing active session
|
||||
existing_session_result = db.execute(
|
||||
text("SELECT session_token, hardware_id FROM license_sessions WHERE license_id = :license_id"),
|
||||
{"license_id": license.id}
|
||||
).first()
|
||||
|
||||
if existing_session_result:
|
||||
if existing_session_result.hardware_id == request.hardware_id:
|
||||
# Same device, update heartbeat
|
||||
db.execute(
|
||||
text("UPDATE license_sessions SET last_heartbeat = CURRENT_TIMESTAMP WHERE session_token = :token"),
|
||||
{"token": existing_session_result.session_token}
|
||||
)
|
||||
db.commit()
|
||||
|
||||
return SessionStartResponse(
|
||||
success=True,
|
||||
message="Existing session resumed",
|
||||
session_token=existing_session_result.session_token,
|
||||
requires_update=request.version < result.current_version,
|
||||
update_url=None,
|
||||
whats_new=None
|
||||
)
|
||||
else:
|
||||
return SessionStartResponse(
|
||||
success=False,
|
||||
message="Es ist nur eine Sitzung erlaubt, stelle sicher, dass nirgendwo sonst das Programm läuft",
|
||||
session_token=None
|
||||
)
|
||||
|
||||
# Create new session
|
||||
session_token = str(uuid.uuid4())
|
||||
|
||||
db.execute(
|
||||
text("""
|
||||
INSERT INTO license_sessions (license_id, hardware_id, ip_address, client_version, session_token)
|
||||
VALUES (:license_id, :hardware_id, :ip_address, :version, :token)
|
||||
"""),
|
||||
{
|
||||
"license_id": license.id,
|
||||
"hardware_id": request.hardware_id,
|
||||
"ip_address": request.ip_address,
|
||||
"version": request.version,
|
||||
"token": session_token
|
||||
}
|
||||
)
|
||||
db.commit()
|
||||
|
||||
return SessionStartResponse(
|
||||
success=True,
|
||||
message="Session started successfully",
|
||||
session_token=session_token,
|
||||
requires_update=request.version < result.current_version,
|
||||
update_url=None,
|
||||
whats_new=None
|
||||
)
|
||||
|
||||
@router.post("/session/heartbeat", response_model=SessionHeartbeatResponse)
|
||||
async def session_heartbeat(
|
||||
request: SessionHeartbeatRequest,
|
||||
db: Session = Depends(get_db),
|
||||
api_key = Depends(get_api_key)
|
||||
):
|
||||
# Update heartbeat
|
||||
result = db.execute(
|
||||
text("""
|
||||
UPDATE license_sessions
|
||||
SET last_heartbeat = CURRENT_TIMESTAMP
|
||||
WHERE session_token = :token
|
||||
RETURNING id
|
||||
"""),
|
||||
{"token": request.session_token}
|
||||
).first()
|
||||
|
||||
if not result:
|
||||
return SessionHeartbeatResponse(
|
||||
success=False,
|
||||
message="Invalid or expired session"
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
return SessionHeartbeatResponse(
|
||||
success=True,
|
||||
message="Heartbeat received"
|
||||
)
|
||||
|
||||
@router.post("/session/end", response_model=SessionEndResponse)
|
||||
async def end_session(
|
||||
request: SessionEndRequest,
|
||||
db: Session = Depends(get_db),
|
||||
api_key = Depends(get_api_key)
|
||||
):
|
||||
# Get session info before deleting
|
||||
session_info = db.execute(
|
||||
text("""
|
||||
SELECT license_id, hardware_id, ip_address, client_version, started_at
|
||||
FROM license_sessions
|
||||
WHERE session_token = :token
|
||||
"""),
|
||||
{"token": request.session_token}
|
||||
).first()
|
||||
|
||||
if not session_info:
|
||||
return SessionEndResponse(
|
||||
success=False,
|
||||
message="Session not found"
|
||||
)
|
||||
|
||||
# Log to session history
|
||||
db.execute(
|
||||
text("""
|
||||
INSERT INTO session_history (license_id, hardware_id, ip_address, client_version, started_at, ended_at, end_reason)
|
||||
VALUES (:license_id, :hardware_id, :ip_address, :version, :started, CURRENT_TIMESTAMP, 'normal')
|
||||
"""),
|
||||
{
|
||||
"license_id": session_info.license_id,
|
||||
"hardware_id": session_info.hardware_id,
|
||||
"ip_address": session_info.ip_address,
|
||||
"version": session_info.client_version,
|
||||
"started": session_info.started_at
|
||||
}
|
||||
)
|
||||
|
||||
# Delete the session
|
||||
db.execute(
|
||||
text("DELETE FROM license_sessions WHERE session_token = :token"),
|
||||
{"token": request.session_token}
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
return SessionEndResponse(
|
||||
success=True,
|
||||
message="Session ended"
|
||||
)
|
||||
@@ -40,4 +40,35 @@ class VersionCheckResponse(BaseModel):
|
||||
update_available: bool
|
||||
is_mandatory: bool
|
||||
download_url: Optional[str] = None
|
||||
release_notes: Optional[str] = None
|
||||
release_notes: Optional[str] = None
|
||||
|
||||
class SessionStartRequest(BaseModel):
|
||||
license_key: str
|
||||
machine_id: str
|
||||
hardware_id: str
|
||||
hardware_hash: str
|
||||
version: str
|
||||
ip_address: Optional[str] = None
|
||||
|
||||
class SessionStartResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
session_token: Optional[str] = None
|
||||
requires_update: bool = False
|
||||
update_url: Optional[str] = None
|
||||
whats_new: Optional[str] = None
|
||||
|
||||
class SessionHeartbeatRequest(BaseModel):
|
||||
session_token: str
|
||||
license_key: str
|
||||
|
||||
class SessionHeartbeatResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
|
||||
class SessionEndRequest(BaseModel):
|
||||
session_token: str
|
||||
|
||||
class SessionEndResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren