import base64 import secrets import subprocess # noqa: S404 import tempfile import uuid from datetime import UTC, datetime from pathlib import Path from typing import Any from urllib.parse import urlencode from apps.esia.scopes import SCOPES from core.config import settings ACCESS_TYPE = 'online' RESPONSE_CODE = 'code' def csp_sign(data: str): with tempfile.TemporaryDirectory() as tmp_dir: tmp_file_name = secrets.token_hex(8) source_path = Path(tmp_dir) / f'{tmp_file_name}.txt' destination_path = source_path.with_suffix('.txt.sgn') with open(source_path, 'w', encoding='utf-8') as f: f.write(data) cmd = [ 'cryptcp', '-signf', '-norev', '-nochain', '-der', '-strict', '-cert', '-detached', '-thumbprint', settings.ESIA_CONTAINER_THUMBPRINT, '-pin', settings.ESIA_CONTAINER_PASSWORD, '-dir', tmp_dir, str(source_path), ] subprocess.run( # noqa: S603 cmd, input=b'y\n', capture_output=True, check=True, text=False ) signed_message = destination_path.read_bytes() return signed_message def sign_params(params: dict[str, Any]): plaintext = ( params.get('scope', '') + params.get('timestamp', '') + params.get('client_id', '') + params.get('state', '') ) client_secret = csp_sign(plaintext) return base64.urlsafe_b64encode(client_secret).decode('utf-8') def get_url(): timestamp = datetime.now(UTC).strftime('%Y.%m.%d %H:%M:%S %z').strip() state = str(uuid.uuid4()) params = { 'client_id': settings.ESIA_CLIENT_ID, 'client_secret': '', 'redirect_uri': settings.ESIA_REDIRECT_URI, 'response_type': RESPONSE_CODE, 'state': state, 'timestamp': timestamp, 'access_type': ACCESS_TYPE, 'scope': ' '.join(SCOPES), } params['client_secret'] = sign_params(params) return f'{settings.ESIA_BASE_URL}/aas/oauth2/ac?{urlencode(params)}'