diff --git a/license_validation.obfuscated.js b/license_validation.obfuscated.js new file mode 100644 index 00000000..84795ac9 --- /dev/null +++ b/license_validation.obfuscated.js @@ -0,0 +1,972 @@ + +// Git Pusher License Module v2.1 +// (c) 2026 - Proprietary Software + +function _d(a,k){return a.map(function(c){return String.fromCharCode(c^k)}).join('')} + +var _mPGDWTSS='5EhVno1UAlInMxiRRohAIoQQXfvB5uNK'; +var _AbhxrBXu='gh4wJsfEj6bKKDBda6siGkXTl24SqzID'; +var _DJpxscIp='7WxQZbX3mWsPniP6NAiN8qeT2bvpROlK'; +var _xjUlAsbu='yhMeseZvgVte3xFkHtb9LRwzAgyDJ49o'; +var _rpAdgQzl='24ftvYKeAuUjQ9zSK4LZWAhDMggyOpbi'; +var _YQfoMflT='3Fr9X68WaQ8khf867cwWm9wtkIqLC6eI'; +var _EnDSfcIg='Hi5iVFTBTae4bvZQdgXRIm5ckqHPJdlO'; +var _cdjGrlDP='ySXg3RdRh14CdF39X7oe6WGAtWTRpYPr'; +var _bGgNTsaK='owKsysl909KDZFlDoig3EPxwJUN5HBhU'; +var _zdElVfsf='qyF0pBuWqaAvCCQfonA8ma4Xee3Zd1Ue'; + +function _xTojmKRE(a,b){ +var c=a^b;var d=c.toString(16); +return d.split('').reverse().join(''); +} + + +function _yXcfkjTR(a,b){ +var c=a^b;var d=c.toString(16); +return d.split('').reverse().join(''); +} + + +function _CDFMlkgT(a,b){ +var c=a^b;var d=c.toString(16); +return d.split('').reverse().join(''); +} + + +function _jyPgmVGM(a,b){ +var c=a^b;var d=c.toString(16); +return d.split('').reverse().join(''); +} + + +function _OBxihZbO(a,b){ +var c=a^b;var d=c.toString(16); +return d.split('').reverse().join(''); +} + +var _jBABccsO=_d([57,57,57,57,57,86,81,83,93,90,52,68,65,86,88,93,87,52,95,81,77,57,57,57,57,57,30],20); +var _ZePwpkAM=_d([22,18,18,24,18,49,26,21,25,60,48,42,51,48,50,28,98,44,107,25,26,10,30,29,26,26,20,24,26,60,99,26,22,18,18,24,24,60,16,24,26,60,30,26,40,60,44,26,40,51,109,49,53,42,35,110,12,11,33,22,47],91); +var _oCVFKZwd=_d([78,118,4,100,4,68,121,119,0,68,93,93,112,94,2,90,103,78,99,69,124,93,102,98,100,31,13,102,71,125,71,102,109,67,70,6,92,67,78,81,0,3,100,100,31,95,12,64,64,78,117,82,108,68,103,83,70,108,100,76,100],52); +var _RuPMmnZX=_d([62,101,106,37,52,16,47,24,105,23,57,106,111,22,21,14,56,41,36,36,9,105,55,63,23,4,11,53,104,9,24,105,48,119,27,44,55,48,24,12,46,18,12,42,9,45,62,10,37,101,62,57,104,107,59,109,52,22,14,110,6],92); +var _KeXFGBIN=_d([213,244,207,196,193,219,136,231,144,246,226,233,154,239,201,231,247,193,193,210,214,229,150,226,144,140,250,213,231,226,228,237,145,140,239,215,228,192,217,244,192,146,243,249,230,226,234,196,237,151,218,208,231,209,201,229,226,214,197,250,242],163); +var _cFGuqfbG=_d([134,138,167,155,228,190,135,146,135,138,229,178,177,135,132,154,255,153,229,189,138,151,131,156,183,190,146,145,136,146,157,225,132,180,185,147,149,227,134,154,183,160,129,156,150,164,177,179,233,153,157,164,135,232,170,188,188,161,146,186,180],208); +var _fwSTdFnn=_d([218,223,190,226,231,255,198,191,239,254,186,253,249,230,227,197,239,219,184,190,253,231,188,252,226,207,253,239,232,202,200,253,238,207,238,184,205,249,228,233,209,211,188,221,228,249,197,194,199,187,189,220,210,160,206,233,200,238,207,196,198],139); +var _VverwbJj=_d([44,62,13,8,30,105,24,26,12,26,56,29,25,35,18,107,33,60,15,52,19,51,19,14,19,43,14,49,51,14,45,44,29,51,33,106,40,107,30,108,61,41,60,1,99,1,24,13,61,16,22,24,51,57,49,8,34,34,57,3,45],91); +var _PwjApxIz=_d([150,174,190,162,144,175,247,180,237,168,187,139,182,172,150,179,128,140,190,172,159,130,224,160,183,235,182,186,148,129,183,171,175,238,159,175,155,176,239,181,162,187,146,157,191,150,157,236,182,247,176,238,175,224,149,150,159,170,143,187,187],216); +var _lJhcfbph=_d([135,231,144,230,144,183,134,166,175,254,176,185,228,191,165,191,153,172,186,148,166,165,160,185,175,141,228,227,150,191,143,164,143,128,175,157,134,156,166,254,162,184,228,144,135,173,146,133,191,161,160,254,178,190,155,172,161,224,144,147,187],213); +var _hYaCbGFk=_d([31,122,121,69,66,111,76,64,117,2,122,121,119,66,76,90,122,88,69,65,88,85,127,117,72,79,21,103,71,98,67,68,121,100,67,21,104,108,108,106,90,20,68,24,27,75,76,125,79,123,72,75,89,117,27,85,122,102,120,103,125],45); +var _oOQkhkZF=_d([141,162,129,155,164,144,136,136,139,144,254,163,176,240,157,158,185,171,230,144,132,190,226,241,144,138,176,174,226,248,253,156,190,176,185,154,168,143,162,131,160,241,252,249,187,145,251,163,157,153,147,144,165,136,177,160,177,255,240,226,139],201); +var _YwznZUaO=_d([145,246,237,215,227,244,254,143,217,237,248,131,251,220,241,253,221,255,145,255,139,137,217,202,232,145,221,234,205,248,232,242,235,140,192,205,145,245,131,222,130,247,215,240,142,192,138,235,212,253,211,136,238,208,200,209,249,251,205,255,251,251,235,135,135],186); +var _xYjhhgWk=_d([150,177,177,177,177,177,217,210,216,188,204,201,222,208,213,223,188,215,217,197,177,177,177,177,177],156); +var _wHaMhGny=_jBABccsO+_ZePwpkAM+_oCVFKZwd+_RuPMmnZX+_KeXFGBIN+_cFGuqfbG+_fwSTdFnn+_VverwbJj+_PwjApxIz+_lJhcfbph+_hYaCbGFk+_oOQkhkZF+_YwznZUaO+_xYjhhgWk; +var PUBLIC_KEY_PEM=_wHaMhGny; + +const DEFAULT_APP_CONFIG = { + api: { + url: '', + port: 9999, + useProxy: true + } +}; +function loadAppConfigForLicense() { + try { + const stored = localStorage.getItem('git_pusher_config'); + if (stored) { + return JSON.parse(stored); + } + } catch (e) { + console.warn('Erreur chargement config localStorage:', e); + } + return DEFAULT_APP_CONFIG; +} +function getLicenseServerUrl() { + const config = loadAppConfigForLicense(); + const hostname = window.location.hostname; + const protocol = window.location.protocol; + if (config.api && config.api.url) { + let url = config.api.url; + if (!config.api.useProxy && config.api.port) { + url = url.replace(/\/$/, '') + ':' + config.api.port; + } + return url; + } + if (hostname === 'myprivspldev.jp-engineering.fr') { + return protocol + '//myprivspldev-api.jp-engineering.fr'; + } + if (hostname === 'myprivspldev-api.jp-engineering.fr') { + return protocol + '//' + hostname; + } + if (/^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) || hostname === 'localhost') { + return protocol + '//' + hostname + ':9999'; + } + return protocol + '//' + hostname + ':9999'; +} +const LICENSE_CONFIG = { + storageKey: 'git_pusher_license', + usageKey: 'git_pusher_usage', + version: '2.1.0', + serverUrl: getLicenseServerUrl() +}; +function pemToArrayBuffer(pem) { + const b64 = pem + .replace(/-----BEGIN PUBLIC KEY-----/, '') + .replace(/-----END PUBLIC KEY-----/, '') + .replace(/\s/g, ''); + const binary = atob(b64); + const bytes = new Uint8Array(binary.length); + for (let i = 0; i < binary.length; i++) { + bytes[i] = binary.charCodeAt(i); + } + return bytes.buffer; +} +async function importPublicKey() { + try { + const keyData = pemToArrayBuffer(PUBLIC_KEY_PEM); + const key = await crypto.subtle.importKey( + 'spki', + keyData, + { + name: 'RSASSA-PKCS1-v1_5', + hash: 'SHA-256' + }, + false, + ['verify'] + ); + return key; + } catch (error) { + console.error('Erreur import clé publique:', error); + return null; + } +} +async function verifySignature(data, signatureB64, publicKey) { + try { + const signature = Uint8Array.from(atob(signatureB64), c => c.charCodeAt(0)); + const dataBuffer = new TextEncoder().encode(data); + const isValid = await crypto.subtle.verify( + 'RSASSA-PKCS1-v1_5', + publicKey, + signature, + dataBuffer + ); + return isValid; + } catch (error) { + console.error('Erreur vérification signature:', error); + return false; + } +} +function base64Decode(str) { + try { + return decodeURIComponent(atob(str).split('').map(function(c) { + return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); + }).join('')); + } catch (e) { + return atob(str); + } +} +function getCurrentHostname() { + return window.location.hostname.toLowerCase(); +} +async function getSplunkHostname() { + try { + const response = await fetch('/en-US/splunkd/__raw/services/server/info?output_mode=json', { + credentials: 'include' + }); + if (response.ok) { + const data = await response.json(); + const serverName = data.entry?.[0]?.content?.serverName; + if (serverName) { + console.log('Hostname Splunk (server/info):', serverName); + return serverName.toLowerCase(); + } + } + } catch (e) { + console.log('Méthode server/info échouée:', e); + } + try { + const response2 = await fetch('/en-US/splunkd/__raw/services/server/settings?output_mode=json', { + credentials: 'include' + }); + if (response2.ok) { + const data2 = await response2.json(); + const serverName = data2.entry?.[0]?.content?.serverName; + if (serverName) { + console.log('Hostname Splunk (server/settings):', serverName); + return serverName.toLowerCase(); + } + } + } catch (e) { + console.log('Méthode server/settings échouée:', e); + } + console.warn('Impossible de récupérer le hostname Splunk, utilisation URL:', getCurrentHostname()); + return getCurrentHostname(); +} +function daysRemaining(expiryDate) { + const expiry = new Date(expiryDate); + const now = new Date(); + const diff = expiry - now; + return Math.ceil(diff / (1000 * 60 * 60 * 24)); +} +function parseLicenseFile(content) { + try { + const lines = content.trim().split('\n'); + let payloadB64 = null; + for (const line of lines) { + const trimmed = line.trim(); + if (trimmed && !trimmed.startsWith('#')) { + payloadB64 = trimmed; + break; + } + } + if (!payloadB64) { + return { error: 'Payload non trouvé dans le fichier' }; + } + const payloadJson = base64Decode(payloadB64); + const payload = JSON.parse(payloadJson); + if (!payload.license || !payload.signature) { + return { error: 'Format de licence invalide' }; + } + const licenseJson = base64Decode(payload.license); + const licenseData = JSON.parse(licenseJson); + return { + success: true, + licenseJson: licenseJson, + licenseData: licenseData, + signatureB64: payload.signature, + rawPayload: payloadB64 + }; + } catch (error) { + console.error('Erreur parsing licence:', error); + return { error: 'Erreur de lecture du fichier de licence' }; + } +} +async function validateLicense(licenseContent = null) { + try { + let parsed; + if (licenseContent) { + parsed = parseLicenseFile(licenseContent); + } else { + const stored = localStorage.getItem(LICENSE_CONFIG.storageKey); + if (!stored) { + return { + valid: false, + error: 'Aucune licence installée', + error_code: 'NO_LICENSE' + }; + } + parsed = JSON.parse(stored); + } + if (parsed.error) { + return { + valid: false, + error: parsed.error, + error_code: 'PARSE_ERROR' + }; + } + const { licenseJson, licenseData, signatureB64 } = parsed; + console.log('=== DEBUG VALIDATION LICENCE ==='); + console.log('License JSON:', licenseJson); + console.log('License JSON length:', licenseJson.length); + console.log('Signature B64:', signatureB64.substring(0, 50) + '...'); + console.log('Signature B64 length:', signatureB64.length); + console.log('Vérification de la signature RSA...'); + const publicKey = await importPublicKey(); + if (!publicKey) { + console.error('Échec import clé publique'); + return { + valid: false, + error: 'Impossible de charger la clé publique', + error_code: 'KEY_ERROR' + }; + } + console.log('Clé publique importée avec succès'); + const signatureValid = await verifySignature(licenseJson, signatureB64, publicKey); + console.log('Résultat vérification signature:', signatureValid); + if (!signatureValid) { + return { + valid: false, + error: 'Signature de licence invalide', + error_code: 'INVALID_SIGNATURE' + }; + } + console.log('✓ Signature RSA valide'); + const expectedHostname = (licenseData.hostname || '').toLowerCase(); + const currentHostname = await getSplunkHostname(); + console.log(`Hostname attendu: "${expectedHostname}", actuel: "${currentHostname}"`); + if (expectedHostname && expectedHostname !== currentHostname) { + if (!currentHostname.includes(expectedHostname) && !expectedHostname.includes(currentHostname)) { + return { + valid: false, + error: `Licence non valide pour ce serveur. Attendu: ${expectedHostname}, Actuel: ${currentHostname}`, + error_code: 'HOSTNAME_MISMATCH', + expected_hostname: expectedHostname, + current_hostname: currentHostname + }; + } + console.log('✓ Hostname valide (correspondance partielle)'); + } else { + console.log('✓ Hostname valide (exact)'); + } + const expiryDate = licenseData.expires; + if (expiryDate) { + const days = daysRemaining(expiryDate); + if (days < 0) { + return { + valid: false, + error: `Licence expirée le ${expiryDate}`, + error_code: 'LICENSE_EXPIRED', + expires: expiryDate + }; + } + console.log(`✓ Licence valide (${days} jours restants)`); + } + return { + valid: true, + license_id: licenseData.license_id, + type: licenseData.type, + type_name: licenseData.type_name, + customer: licenseData.customer, + hostname: expectedHostname, + issued: licenseData.issued, + expires: expiryDate, + days_remaining: daysRemaining(expiryDate), + limits: licenseData.limits || {}, + features: licenseData.features || [] + }; + } catch (error) { + console.error('Erreur validation licence:', error); + return { + valid: false, + error: error.message, + error_code: 'VALIDATION_ERROR' + }; + } +} +async function hasFeature(featureName) { + const validation = await validateLicense(); + if (!validation.valid) return false; + return validation.features.includes(featureName); +} +async function saveLicense(licenseContent) { + try { + const parsed = parseLicenseFile(licenseContent); + if (parsed.error) { + return { + success: false, + error: parsed.error + }; + } + const validation = await validateLicense(licenseContent); + if (!validation.valid) { + return { + success: false, + error: validation.error, + error_code: validation.error_code + }; + } + localStorage.setItem(LICENSE_CONFIG.storageKey, JSON.stringify(parsed)); + console.log('✓ Licence sauvegardée dans localStorage'); + try { + const response = await fetch(`${LICENSE_CONFIG.serverUrl}/license/save`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + license_content: licenseContent + }) + }); + const serverResult = await response.json(); + if (serverResult.success) { + console.log('✓ Licence sauvegardée sur le serveur'); + } else { + console.warn('⚠ Échec sauvegarde serveur:', serverResult.error); + } + } catch (serverError) { + console.warn('⚠ Impossible de sauvegarder sur le serveur:', serverError); + } + return { + success: true, + license: validation + }; + } catch (error) { + console.error('Erreur sauvegarde licence:', error); + return { + success: false, + error: error.message + }; + } +} +async function loadLicenseFromServer() { + try { + const response = await fetch(`${LICENSE_CONFIG.serverUrl}/license/file`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }); + const result = await response.json(); + if (result.success && result.content) { + console.log('Licence trouvée sur le serveur, validation en cours...'); + const parsed = parseLicenseFile(result.content); + if (parsed.error) { + console.warn('Erreur parsing licence serveur:', parsed.error); + return false; + } + const validation = await validateLicense(result.content); + if (validation.valid) { + localStorage.setItem(LICENSE_CONFIG.storageKey, JSON.stringify(parsed)); + console.log('✓ Licence chargée depuis le serveur et stockée localement'); + return true; + } else { + console.warn('Licence serveur invalide:', validation.error); + return false; + } + } else { + console.log('Aucune licence sur le serveur'); + return false; + } + } catch (error) { + console.log('Impossible de charger la licence depuis le serveur:', error.message); + return false; + } +} +async function removeLicense() { + localStorage.removeItem(LICENSE_CONFIG.storageKey); + localStorage.removeItem(LICENSE_CONFIG.usageKey); + try { + await fetch(`${LICENSE_CONFIG.serverUrl}/license/delete`, { + method: 'POST' + }); + console.log('Licence supprimée du serveur'); + } catch (e) { + console.warn('Impossible de supprimer la licence du serveur:', e); + } + console.log('Licence supprimée'); +} +function getLicenseInfo() { + try { + const stored = localStorage.getItem(LICENSE_CONFIG.storageKey); + if (!stored) return null; + const parsed = JSON.parse(stored); + return parsed.licenseData; + } catch { + return null; + } +} +function getUsageStats() { + try { + const stored = localStorage.getItem(LICENSE_CONFIG.usageKey); + if (stored) { + return JSON.parse(stored); + } + } catch {} + return { + total_pushes: 0, + pushes_today: 0, + last_push_date: null + }; +} +function incrementUsage() { + const stats = getUsageStats(); + const today = new Date().toISOString().split('T')[0]; + if (stats.last_push_date !== today) { + stats.pushes_today = 0; + stats.last_push_date = today; + } + stats.total_pushes = (stats.total_pushes || 0) + 1; + stats.pushes_today = (stats.pushes_today || 0) + 1; + localStorage.setItem(LICENSE_CONFIG.usageKey, JSON.stringify(stats)); + return stats; +} +async function checkLimits() { + const validation = await validateLicense(); + if (!validation.valid) { + return { + allowed: false, + error: validation.error, + error_code: validation.error_code + }; + } + const limits = validation.limits || {}; + const maxPushes = limits.max_pushes_per_day || -1; + if (maxPushes > 0) { + const stats = getUsageStats(); + const today = new Date().toISOString().split('T')[0]; + let pushesToday = stats.pushes_today || 0; + if (stats.last_push_date !== today) { + pushesToday = 0; + } + if (pushesToday >= maxPushes) { + return { + allowed: false, + error: `Limite quotidienne atteinte (${maxPushes} pushes/jour)`, + error_code: 'DAILY_LIMIT_REACHED' + }; + } + } + return { + allowed: true, + license_type: validation.type_name, + remaining_today: maxPushes > 0 ? maxPushes - getUsageStats().pushes_today : -1 + }; +} +async function updateLicenseBadge() { + const container = document.getElementById('license-badge-container'); + if (!container) return; + const validation = await validateLicense(); + let badgeHtml = ''; + if (validation.valid) { + const daysLeft = validation.days_remaining; + let badgeClass = 'license-badge-valid'; + let icon = '✓'; + if (daysLeft <= 7) { + badgeClass = 'license-badge-expiring'; + icon = '⚠️'; + } else if (daysLeft <= 30) { + badgeClass = 'license-badge-warning'; + icon = '⏳'; + } + badgeHtml = ` +
+ ${icon} + ${validation.type_name} + ${daysLeft}j +
+ `; + } else { + badgeHtml = ` +
+ 🔐 + Activer +
+ `; + } + container.innerHTML = badgeHtml; +} +function showLicenseModal(message = null, errorCode = null) { + const existingModal = document.getElementById('license-modal'); + if (existingModal) existingModal.remove(); + const modal = document.createElement('div'); + modal.id = 'license-modal'; + modal.className = 'license-modal-overlay'; + let errorMessage = ''; + if (message) { + errorMessage = `
${message}
`; + } + modal.innerHTML = ` +
+
+

🔐 Activation de Licence

+ +
+
+ ${errorMessage} +
+
📄
+
+ Glissez-déposez votre fichier .lic ici +
ou cliquez pour sélectionner +
+ +
+
+ Hostname du serveur: + Chargement... +
Communiquez ce hostname pour obtenir votre licence +
+
+
+ +
+ `; + document.body.appendChild(modal); + getSplunkHostname().then(hostname => { + const hostnameDisplay = document.getElementById('current-hostname-display'); + if (hostnameDisplay) { + hostnameDisplay.textContent = hostname; + } + }); + setupLicenseUpload(); +} +function setupLicenseUpload() { + const dropZone = document.getElementById('license-upload-zone'); + const fileInput = document.getElementById('license-file-input'); + if (!dropZone || !fileInput) return; + dropZone.addEventListener('click', () => fileInput.click()); + dropZone.addEventListener('dragover', (e) => { + e.preventDefault(); + dropZone.classList.add('dragover'); + }); + dropZone.addEventListener('dragleave', () => { + dropZone.classList.remove('dragover'); + }); + dropZone.addEventListener('drop', (e) => { + e.preventDefault(); + dropZone.classList.remove('dragover'); + const files = e.dataTransfer.files; + if (files.length > 0) { + handleLicenseFile(files[0]); + } + }); + fileInput.addEventListener('change', (e) => { + if (e.target.files.length > 0) { + handleLicenseFile(e.target.files[0]); + } + }); +} +async function handleLicenseFile(file) { + const resultDiv = document.getElementById('license-validation-result'); + if (!resultDiv) return; + if (!file.name.endsWith('.lic')) { + resultDiv.innerHTML = ` +
+ ❌ Le fichier doit avoir l'extension .lic +
+ `; + return; + } + resultDiv.innerHTML = ` +
+ ⏳ Validation en cours... +
+ `; + try { + const content = await file.text(); + const result = await saveLicense(content); + if (result.success) { + const license = result.license; + resultDiv.innerHTML = ` +
+
+
+ Licence activée avec succès !
+ Type: ${license.type_name}
+ Expire: ${license.expires} (${license.days_remaining} jours)
+ Client: ${license.customer?.name || 'N/A'} +
+
+ `; + updateLicenseBadge(); + setTimeout(() => { + closeLicenseModal(); + }, 3000); + } else { + resultDiv.innerHTML = ` +
+ ❌ ${result.error} +
+ `; + } + } catch (error) { + resultDiv.innerHTML = ` +
+ ❌ Erreur: ${error.message} +
+ `; + } +} +function closeLicenseModal() { + const modal = document.getElementById('license-modal'); + if (modal) modal.remove(); +} +async function showLicenseDetails() { + const validation = await validateLicense(); + if (!validation.valid) { + showLicenseModal(validation.error, validation.error_code); + return; + } + const existingModal = document.getElementById('license-details-modal'); + if (existingModal) existingModal.remove(); + const modal = document.createElement('div'); + modal.id = 'license-details-modal'; + modal.className = 'license-modal-overlay'; + const features = validation.features.map(f => `${f}`).join(' '); + const limits = validation.limits; + const maxApps = limits.max_apps === -1 ? '∞' : limits.max_apps; + const maxPushes = limits.max_pushes_per_day === -1 ? '∞' : limits.max_pushes_per_day; + const usage = getUsageStats(); + modal.innerHTML = ` +
+
+

📋 Détails de la Licence

+ +
+
+ + + + + + + + + + + +
ID${validation.license_id}
Type${validation.type_name}
Client${validation.customer?.name || 'N/A'}
Email${validation.customer?.email || 'N/A'}
Hostname${validation.hostname}
Émise le${validation.issued}
Expire le${validation.expires}
Jours restants${validation.days_remaining}
Apps max${maxApps}
Pushes/jour${maxPushes}
+
+ Fonctionnalités:
+
${features}
+
+
+ Utilisation:
+ Total pushes: ${usage.total_pushes} | Aujourd'hui: ${usage.pushes_today} +
+
+ +
+ `; + document.body.appendChild(modal); +} +function confirmRemoveLicense() { + if (confirm('Êtes-vous sûr de vouloir supprimer cette licence ?')) { + removeLicense(); + const detailsModal = document.getElementById('license-details-modal'); + if (detailsModal) detailsModal.remove(); + updateLicenseBadge(); + alert('Licence supprimée.'); + } +} +async function checkLicenseBeforePush() { + const result = await checkLimits(); + if (!result.allowed) { + showLicenseModal(result.error, result.error_code); + return false; + } + return true; +} +const licenseStyles = ` + +`; +async function initializeLicense() { + console.log('Git Pusher License System v' + LICENSE_CONFIG.version + ' (RSA)'); + if (!document.getElementById('license-styles')) { + const styleEl = document.createElement('div'); + styleEl.id = 'license-styles'; + styleEl.innerHTML = licenseStyles; + document.head.appendChild(styleEl); + } + const stored = localStorage.getItem(LICENSE_CONFIG.storageKey); + if (!stored) { + console.log('Aucune licence en cache, tentative de chargement depuis le serveur...'); + const loadedFromServer = await loadLicenseFromServer(); + if (loadedFromServer) { + console.log('✓ Licence restaurée depuis le serveur'); + } else { + console.log('Aucune licence disponible'); + } + } else { + console.log('Licence trouvée dans le cache local'); + } + updateLicenseBadge(); +} +window.initializeLicense = initializeLicense; +window.validateLicense = validateLicense; +window.saveLicense = saveLicense; +window.removeLicense = removeLicense; +window.loadLicenseFromServer = loadLicenseFromServer; +window.checkLicenseBeforePush = checkLicenseBeforePush; +window.showLicenseModal = showLicenseModal; +window.closeLicenseModal = closeLicenseModal; +window.showLicenseDetails = showLicenseDetails; +window.confirmRemoveLicense = confirmRemoveLicense; +window.updateLicenseBadge = updateLicenseBadge; +window.hasFeature = hasFeature; +window.incrementUsage = incrementUsage; +window.getUsageStats = getUsageStats; +window.getLicenseInfo = getLicenseInfo; +if (document.readyState === 'complete') { + setTimeout(initializeLicense, 100); +} else { + window.addEventListener('load', function() { + setTimeout(initializeLicense, 100); + }); +} \ No newline at end of file