md-face-engine 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,20 +8,29 @@ Motor reusable para detección facial y aplicación de filtros.
8
8
  npm install md-face-engine
9
9
  ```
10
10
 
11
- ## Uso en frontend
11
+ ## API rápida
12
+
13
+ - `createMdFaceEngineClient({ token, products })`: exige licencia válida.
14
+ - `createMdFaceEngineRuntime({ token, products })`: funciona con o sin licencia (útil para modo demo/watermark).
15
+
16
+ Ambas APIs son `async`.
17
+
18
+ ## Uso recomendado (runtime)
12
19
 
13
20
  ```js
14
- import { createMdFaceEngineClient } from 'md-face-engine/client';
21
+ import { createMdFaceEngineRuntime } from 'md-face-engine/client';
15
22
 
16
- const client = createMdFaceEngineClient({
23
+ const runtime = await createMdFaceEngineRuntime({
17
24
  token: import.meta.env.VITE_MD_FACE_ENGINE_TOKEN,
18
25
  products: []
19
26
  });
27
+
28
+ console.log(runtime.license.active); // true/false
20
29
  ```
21
30
 
22
- El frontend solo necesita un valor:
31
+ ## Tokens
23
32
 
24
- - `VITE_MD_FACE_ENGINE_TOKEN`
33
+ Formato esperado: `mdfe2_...` con firma asimétrica ECDSA.
25
34
 
26
35
  ## Build del paquete
27
36
 
@@ -463,10 +463,10 @@ class FilterConfigManager {
463
463
  return this.exportConfigurations();
464
464
  }
465
465
  }
466
- const filterConfigManager = new FilterConfigManager();
466
+ const coreFilterConfigManager = new FilterConfigManager();
467
467
  function buildWebglConfigForProduct(product) {
468
468
  var _a, _b, _c, _d;
469
- const pc = filterConfigManager.getProductConfig(product.id) || {};
469
+ const pc = coreFilterConfigManager.getProductConfig(product.id) || {};
470
470
  const lockedType = product.filterType || pc.webglConfig && pc.webglConfig.filterType || "wrinkles";
471
471
  const defaults = FILTERS[lockedType] && FILTERS[lockedType].defaults || { intensity: 0.5, sigma: 4, brightness: 0 };
472
472
  const deep = FILTERS[lockedType] && FILTERS[lockedType].deep || {};
@@ -483,25 +483,58 @@ function buildWebglConfigForProduct(product) {
483
483
  const adminCfg = pc.webglConfig || {};
484
484
  return { ...base, ...adminCfg, filterType: lockedType };
485
485
  }
486
- const TOKEN_PREFIX = "mdfe_";
486
+ const TOKEN_PREFIX = "mdfe2_";
487
487
  const PRODUCT_CODE = "md-face-engine";
488
- const LICENSE_SECRET = "md-face-engine-license-v1";
489
- function hashToken(value) {
490
- let hash = 5381;
491
- for (let i = 0; i < value.length; i += 1) {
492
- hash = (hash << 5) + hash + value.charCodeAt(i);
493
- hash &= 4294967295;
494
- }
495
- return (hash >>> 0).toString(16).padStart(8, "0");
496
- }
488
+ const LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
489
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW9CHbTVvVXcm09wZIj6GKGaq8ae1
490
+ XGQAum9LBLgoT3+4q3xPc7W9KSw1z4xgfOByTi8OzdjbjEaF3VrHjzl05w==
491
+ -----END PUBLIC KEY-----`;
492
+ let publicKeyCache = null;
497
493
  function decodeBase64Url(value) {
498
494
  const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
499
- const padding = normalized.length % 4;
500
- const padded = padding ? normalized + "=".repeat(4 - padding) : normalized;
495
+ const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
501
496
  return atob(padded);
502
497
  }
503
- function validateLicenseToken(token, options = {}) {
504
- const { now = Date.now() } = options;
498
+ function decodeBase64UrlToBytes(value) {
499
+ const bin = decodeBase64Url(value);
500
+ const bytes = new Uint8Array(bin.length);
501
+ for (let i = 0; i < bin.length; i += 1) {
502
+ bytes[i] = bin.charCodeAt(i);
503
+ }
504
+ return bytes;
505
+ }
506
+ function pemToArrayBuffer(pem) {
507
+ const b64 = pem.replace(/-----BEGIN PUBLIC KEY-----/g, "").replace(/-----END PUBLIC KEY-----/g, "").replace(/\s+/g, "");
508
+ const raw = atob(b64);
509
+ const bytes = new Uint8Array(raw.length);
510
+ for (let i = 0; i < raw.length; i += 1) {
511
+ bytes[i] = raw.charCodeAt(i);
512
+ }
513
+ return bytes.buffer;
514
+ }
515
+ async function importPublicKey(publicKeyPem = LICENSE_PUBLIC_KEY_PEM) {
516
+ if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM && publicKeyCache) {
517
+ return publicKeyCache;
518
+ }
519
+ const keyData = pemToArrayBuffer(publicKeyPem);
520
+ const key = await crypto.subtle.importKey(
521
+ "spki",
522
+ keyData,
523
+ { name: "ECDSA", namedCurve: "P-256" },
524
+ false,
525
+ ["verify"]
526
+ );
527
+ if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM) {
528
+ publicKeyCache = key;
529
+ }
530
+ return key;
531
+ }
532
+ async function validateLicenseToken(token, options = {}) {
533
+ const {
534
+ now = Date.now(),
535
+ publicKeyPem = LICENSE_PUBLIC_KEY_PEM,
536
+ allowExpired = false
537
+ } = options;
505
538
  if (!token || typeof token !== "string") {
506
539
  return { valid: false, reason: "Token vacío o inválido" };
507
540
  }
@@ -513,22 +546,32 @@ function validateLicenseToken(token, options = {}) {
513
546
  if (parts.length !== 2) {
514
547
  return { valid: false, reason: "Formato de token inválido" };
515
548
  }
516
- const [payloadPart, signature] = parts;
517
- const expected = hashToken(`${payloadPart}.${LICENSE_SECRET}`);
518
- if (signature !== expected) {
519
- return { valid: false, reason: "Firma de licencia inválida" };
520
- }
549
+ const [payloadPart, signaturePart] = parts;
521
550
  let payload;
522
551
  try {
523
552
  payload = JSON.parse(decodeBase64Url(payloadPart));
524
553
  } catch (_err) {
525
554
  return { valid: false, reason: "Payload de licencia inválido" };
526
555
  }
556
+ try {
557
+ const key = await importPublicKey(publicKeyPem);
558
+ const isValid = await crypto.subtle.verify(
559
+ { name: "ECDSA", hash: "SHA-256" },
560
+ key,
561
+ decodeBase64UrlToBytes(signaturePart),
562
+ new TextEncoder().encode(payloadPart)
563
+ );
564
+ if (!isValid) {
565
+ return { valid: false, reason: "Firma de licencia inválida" };
566
+ }
567
+ } catch (_err) {
568
+ return { valid: false, reason: "Error verificando firma de licencia" };
569
+ }
527
570
  if (payload.productCode !== PRODUCT_CODE) {
528
571
  return { valid: false, reason: "Licencia de otro producto" };
529
572
  }
530
- if (typeof payload.exp !== "number" || payload.exp < now) {
531
- return { valid: false, reason: "Licencia vencida" };
573
+ if (!allowExpired && (typeof payload.exp !== "number" || payload.exp < now)) {
574
+ return { valid: false, reason: "Licencia vencida", payload };
532
575
  }
533
576
  return { valid: true, reason: null, payload };
534
577
  }
@@ -537,8 +580,8 @@ class MdFaceEngine {
537
580
  this.license = null;
538
581
  this.activated = false;
539
582
  }
540
- activate(token) {
541
- const result = validateLicenseToken(token);
583
+ async activate(token) {
584
+ const result = await validateLicenseToken(token);
542
585
  if (!result.valid) {
543
586
  this.license = null;
544
587
  this.activated = false;
@@ -577,44 +620,75 @@ class MdFaceEngine {
577
620
  }
578
621
  getFilterConfigManager() {
579
622
  this.assertActivated();
580
- return filterConfigManager;
623
+ return coreFilterConfigManager;
581
624
  }
582
625
  buildWebglConfigForProduct(product) {
583
626
  this.assertActivated();
584
627
  return buildWebglConfigForProduct(product);
585
628
  }
586
629
  }
587
- function createMdFaceEngineClient({ token, products = [] } = {}) {
630
+ async function createMdFaceEngineClient({ token, products = [] } = {}) {
588
631
  if (!token) {
589
632
  throw new Error("Falta token de licencia para activar md-face-engine.");
590
633
  }
591
634
  const engine = new MdFaceEngine();
592
- engine.activate(token);
635
+ await engine.activate(token);
593
636
  engine.assertActivated();
594
- const filterConfigManager2 = engine.getFilterConfigManager();
637
+ const filterConfigManager = engine.getFilterConfigManager();
595
638
  if (Array.isArray(products)) {
596
- filterConfigManager2.setProducts(products);
639
+ filterConfigManager.setProducts(products);
597
640
  }
598
641
  return {
599
642
  engine,
600
643
  FILTERS: engine.getFilterRegistry(),
601
644
  FILTER_ORDER: engine.getFilterOrder(),
602
645
  getFilter: (key) => engine.getFilter(key),
603
- filterConfigManager: filterConfigManager2,
646
+ filterConfigManager,
604
647
  buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)
605
648
  };
606
649
  }
650
+ async function createMdFaceEngineRuntime({ token, products = [] } = {}) {
651
+ let client = null;
652
+ let licenseError = null;
653
+ let isLicenseActive = false;
654
+ if (token) {
655
+ try {
656
+ client = await createMdFaceEngineClient({ token, products });
657
+ isLicenseActive = true;
658
+ } catch (error) {
659
+ licenseError = error;
660
+ isLicenseActive = false;
661
+ }
662
+ }
663
+ if (!client && Array.isArray(products) && typeof (coreFilterConfigManager == null ? void 0 : coreFilterConfigManager.setProducts) === "function") {
664
+ coreFilterConfigManager.setProducts(products);
665
+ }
666
+ return {
667
+ engine: (client == null ? void 0 : client.engine) || null,
668
+ FILTERS: (client == null ? void 0 : client.FILTERS) || FILTERS,
669
+ FILTER_ORDER: (client == null ? void 0 : client.FILTER_ORDER) || FILTER_ORDER,
670
+ getFilter: (client == null ? void 0 : client.getFilter) || getFilter,
671
+ filterConfigManager: (client == null ? void 0 : client.filterConfigManager) || coreFilterConfigManager,
672
+ buildWebglConfigForProduct: (client == null ? void 0 : client.buildWebglConfigForProduct) || buildWebglConfigForProduct,
673
+ license: {
674
+ active: isLicenseActive,
675
+ error: licenseError,
676
+ mode: isLicenseActive ? "licensed" : "unlicensed"
677
+ }
678
+ };
679
+ }
607
680
  export {
608
681
  CATEGORY_PRESETS as C,
609
682
  DEFAULT_FILTER_CONFIG as D,
610
683
  FILTERS as F,
611
684
  MdFaceEngine as M,
612
- FILTER_ORDER as a,
613
- FilterConfigManager as b,
685
+ createMdFaceEngineRuntime as a,
686
+ FILTER_ORDER as b,
614
687
  createMdFaceEngineClient as c,
615
- buildWebglConfigForProduct as d,
616
- filterConfigManager as f,
688
+ coreFilterConfigManager as d,
689
+ FilterConfigManager as e,
690
+ buildWebglConfigForProduct as f,
617
691
  getFilter as g,
618
692
  validateLicenseToken as v
619
693
  };
620
- //# sourceMappingURL=client-BGSZMMvf.js.map
694
+ //# sourceMappingURL=client-B8NLJ0b1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-B8NLJ0b1.js","sources":["../src/core/filters/wrinkles.js","../src/core/filters/brightness.js","../src/core/filters/spots.js","../src/core/filters/acne.js","../src/core/filters/firmness.js","../src/core/filters/index.js","../src/core/config/FilterConfigManager.js","../src/core/webgl/buildWebglConfigForProduct.js","../src/license/token.js","../src/MartidermEngine.js","../src/client.js"],"sourcesContent":["export default {\n key: 'wrinkles',\n label: 'Arrugas',\n defaults: { intensity: 0.5, sigma: 4, brightness: 0 },\n deep: {\n smooth: { enabled: true, radius: 8, passes: 4, opacity: 0.7 },\n brightness: { enabled: true, value: 10 },\n contrast: { enabled: true, value: 1.03 },\n warmth: { enabled: true, rPlus: 8, bMinus: 5, alpha: 0.3 },\n toneUnify: { enabled: true, threshold: 12, mix: 0.4 },\n blemish: { enabled: true, microBlur: 3, alpha: 0.4 },\n contourLift: { enabled: true, lift: 0.06, shade: 0.04, feather: 20 }\n }\n}\n","export default {\n key: 'brightness',\n label: 'Luminosidad',\n defaults: { intensity: 0, sigma: 0, brightness: 0.07 },\n deep: {\n smooth: { enabled: true, radius: 5, passes: 3, opacity: 0.5 },\n brightness: { enabled: true, value: 18 },\n contrast: { enabled: true, value: 1.15 },\n warmth: { enabled: true, rPlus: 12, bMinus: 8, alpha: 0.45 },\n toneUnify: { enabled: true, threshold: 10, mix: 0.3 },\n blemish: { enabled: true, microBlur: 2, alpha: 0.3 },\n contourLift: { enabled: true, lift: 0.12, shade: 0.08, feather: 18 }\n }\n}\n","export default {\n key: 'spots',\n label: 'Manchas/Tono',\n defaults: { intensity: 0.65, sigma: 5, brightness: 0.05 },\n deep: {\n smooth: { enabled: true, radius: 6, passes: 3, opacity: 0.6 },\n brightness: { enabled: true, value: 12 },\n contrast: { enabled: true, value: 1.08 },\n warmth: { enabled: true, rPlus: 7, bMinus: 4, alpha: 0.3 },\n toneUnify: { enabled: true, threshold: 8, mix: 0.6 },\n blemish: { enabled: true, microBlur: 4, alpha: 0.5 },\n contourLift: { enabled: true, lift: 0.08, shade: 0.06, feather: 16 }\n }\n}\n","export default {\n key: 'acne',\n label: 'Acné',\n defaults: { intensity: 0.55, sigma: 3.4, brightness: 0.1 },\n deep: {\n smooth: { enabled: true, radius: 7, passes: 4, opacity: 0.65 },\n brightness: { enabled: true, value: 8 },\n contrast: { enabled: true, value: 1.02 },\n warmth: { enabled: true, rPlus: 6, bMinus: 3, alpha: 0.25 },\n toneUnify: { enabled: true, threshold: 10, mix: 0.5 },\n blemish: { enabled: true, microBlur: 5, alpha: 0.7 },\n contourLift: { enabled: true, lift: 0.06, shade: 0.04, feather: 20 }\n }\n}\n","export default {\n key: 'firmness',\n label: 'Firmeza',\n defaults: { intensity: 0.7, sigma: 2, brightness: 0 },\n deep: {\n smooth: { enabled: true, radius: 3, passes: 2, opacity: 0.3 },\n brightness: { enabled: true, value: 6 },\n contrast: { enabled: true, value: 1.12 },\n warmth: { enabled: true, rPlus: 5, bMinus: 3, alpha: 0.2 },\n toneUnify: { enabled: true, threshold: 18, mix: 0.2 },\n blemish: { enabled: false, microBlur: 1, alpha: 0.1 },\n contourLift: { enabled: true, lift: 0.15, shade: 0.12, feather: 12 }\n }\n}\n","import wrinkles from './wrinkles'\nimport brightness from './brightness'\nimport spots from './spots'\nimport acne from './acne'\nimport firmness from './firmness'\n\nexport const FILTERS = {\n wrinkles,\n brightness,\n spots,\n acne,\n firmness,\n}\n\nexport function getFilter(key) {\n return FILTERS[key] || null\n}\n\nexport const FILTER_ORDER = ['wrinkles','brightness','spots','acne','firmness']\n","/**\n * FilterConfigManager - Servicio para gestionar configuraciones de filtros por producto\n * \n * Funcionalidades:\n * - Almacenamiento persistente de configuraciones de filtros\n * - Gestión de configuraciones por producto\n * - Sistema de autenticación para administradores\n * - Backup y restauración de configuraciones\n * - Valores predeterminados para filtros\n */\n\n// Configuraciones predeterminadas para cada tipo de filtro (alineadas con beautyFilters)\nconst DEFAULT_FILTER_CONFIG = {\n // 1) Arrugas → Suavizado de piel\n smooth: {\n enabled: true,\n intensity: 36, // referencia visual\n radius: 4,\n passes: 2,\n opacity: 0.4\n },\n // 2) Piel apagada → Brillo\n brightness: {\n enabled: true,\n intensity: 91, // referencia visual\n value: 8\n },\n // Ajuste de contraste general\n contrast: {\n enabled: true,\n intensity: 10,\n value: 1.05\n },\n // Tono cálido / glow\n warmth: {\n enabled: true,\n intensity: 20,\n rPlus: 6,\n bMinus: 4,\n alpha: 0.25\n },\n // 2) Manchas → Unificar tono\n toneUnify: {\n enabled: true,\n intensity: 65, // referencia visual\n threshold: 15,\n mix: 0.25\n },\n // 5) Acné → Reducir imperfecciones\n blemish: {\n enabled: true,\n intensity: 35, // referencia visual\n microBlur: 2,\n alpha: 0.25\n },\n // 3) Firmeza → Lifting y contouring\n contourLift: {\n enabled: true,\n intensity: 24, // referencia visual\n lift: 0.08,\n shade: 0.06,\n feather: 15\n },\n // Extras\n highlights: {\n enabled: false,\n intensity: 10\n },\n shadows: {\n enabled: false,\n intensity: 5\n }\n};\n\n// Presets por preocupación de piel\nconst CONCERN_PRESETS = {\n arrugas: {\n smooth: { enabled: true, intensity: 36, radius: 6, passes: 3, opacity: 0.6 },\n contourLift: { enabled: true, intensity: 20, lift: 0.06, shade: 0.05, feather: 18 }\n },\n manchas: {\n toneUnify: { enabled: true, intensity: 65, threshold: 14, mix: 0.35 },\n brightness: { enabled: true, intensity: 20, value: 10 }\n },\n firmeza: {\n contourLift: { enabled: true, intensity: 24, lift: 0.08, shade: 0.06, feather: 20 },\n contrast: { enabled: true, intensity: 12, value: 1.07 }\n },\n luminosidad: {\n brightness: { enabled: true, intensity: 91, value: 12 },\n warmth: { enabled: true, intensity: 25, rPlus: 8, bMinus: 5, alpha: 0.3 }\n },\n acne: {\n blemish: { enabled: true, intensity: 35, microBlur: 3, alpha: 0.35 },\n toneUnify: { enabled: true, intensity: 40, threshold: 16, mix: 0.3 }\n }\n};\n\n// Configuraciones específicas por categoría de producto (usando categorías reales)\nconst CATEGORY_PRESETS = {\n // Antiaging: foco en arrugas y firmeza\n antiaging: {\n smooth: { enabled: true, intensity: 36, radius: 6, passes: 3, opacity: 0.6 },\n contourLift: { enabled: true, intensity: 24, lift: 0.07, shade: 0.05, feather: 18 },\n brightness: { enabled: true, intensity: 20, value: 10 },\n warmth: { enabled: true, intensity: 22, rPlus: 7, bMinus: 5, alpha: 0.28 }\n },\n // Manchas / pigmentación: foco en unificar tono y luminosidad\n manchas: {\n toneUnify: { enabled: true, intensity: 65, threshold: 14, mix: 0.35 },\n brightness: { enabled: true, intensity: 25, value: 10 },\n warmth: { enabled: false }\n },\n // Hidratación: suavizado ligero y glow moderado\n hidratacion: {\n smooth: { enabled: true, intensity: 25, radius: 3, passes: 2, opacity: 0.35 },\n brightness: { enabled: true, intensity: 18, value: 8 },\n warmth: { enabled: true, intensity: 15, rPlus: 5, bMinus: 3, alpha: 0.2 }\n },\n // Acné: foco en reducción de imperfecciones y tono uniforme\n acne: {\n blemish: { enabled: true, intensity: 35, microBlur: 3, alpha: 0.35 },\n toneUnify: { enabled: true, intensity: 40, threshold: 16, mix: 0.3 },\n brightness: { enabled: false }\n }\n};\n\nclass FilterConfigManager {\n constructor(options = {}) {\n this.storageKey = 'martiderm_filter_configs';\n this.authKey = 'martiderm_admin_auth';\n this.backupKey = 'martiderm_config_backup';\n this.products = Array.isArray(options.products) ? options.products : [];\n this.init();\n }\n\n /**\n * Inicializa el gestor de configuraciones\n */\n init() {\n // Verificar si existen configuraciones guardadas\n const savedConfigs = this.loadConfigurations();\n if ((!savedConfigs || Object.keys(savedConfigs).length === 0) && this.products.length > 0) {\n this.initializeDefaultConfigurations();\n }\n }\n\n setProducts(products = []) {\n this.products = Array.isArray(products) ? products : [];\n const savedConfigs = this.loadConfigurations();\n if ((!savedConfigs || Object.keys(savedConfigs).length === 0) && this.products.length > 0) {\n this.initializeDefaultConfigurations();\n }\n }\n\n /**\n * Inicializa configuraciones predeterminadas para todos los productos\n */\n initializeDefaultConfigurations() {\n try {\n const configs = {};\n this.products.forEach(product => {\n configs[product.id] = this.generateProductConfig(product);\n });\n this.saveConfigurations(configs);\n } catch (error) {\n console.error('Error inicializando configuraciones:', error);\n }\n }\n\n /**\n * Genera configuración específica para un producto\n */\n generateProductConfig(product) {\n const baseConfig = { ...DEFAULT_FILTER_CONFIG };\n const categoryPreset = CATEGORY_PRESETS[product.category];\n \n if (categoryPreset) {\n // Aplicar presets específicos de la categoría\n Object.keys(categoryPreset).forEach(filterType => {\n if (baseConfig[filterType]) {\n baseConfig[filterType] = {\n ...baseConfig[filterType],\n ...categoryPreset[filterType]\n };\n }\n });\n }\n\n // Aplicar presets por preocupaciones del producto (si existen)\n if (product.targetConcerns && Array.isArray(product.targetConcerns)) {\n product.targetConcerns.forEach(concern => {\n const preset = CONCERN_PRESETS[concern];\n if (preset) {\n Object.keys(preset).forEach(filterType => {\n if (baseConfig[filterType]) {\n baseConfig[filterType] = {\n ...baseConfig[filterType],\n ...preset[filterType]\n };\n }\n });\n }\n });\n }\n \n return {\n productId: product.id,\n productName: product.name,\n category: product.category,\n filters: baseConfig,\n lastModified: new Date().toISOString(),\n version: '1.0'\n };\n }\n\n /**\n * Obtiene la configuración de filtros para un producto específico\n */\n getProductConfig(productId) {\n const configs = this.loadConfigurations();\n return configs[productId] || null;\n }\n\n /**\n * Guarda la configuración de filtros para un producto\n */\n saveProductConfig(productId, config) {\n const configs = this.loadConfigurations();\n configs[productId] = {\n ...config,\n lastModified: new Date().toISOString()\n };\n this.saveConfigurations(configs);\n return true;\n }\n\n /**\n * Obtiene todas las configuraciones\n */\n getAllConfigurations() {\n return this.loadConfigurations();\n }\n\n /**\n * Carga configuraciones desde localStorage\n */\n loadConfigurations() {\n try {\n const saved = localStorage.getItem(this.storageKey);\n return saved ? JSON.parse(saved) : {};\n } catch (error) {\n console.error('Error cargando configuraciones:', error);\n return {};\n }\n }\n\n /**\n * Guarda configuraciones en localStorage\n */\n saveConfigurations(configs) {\n try {\n localStorage.setItem(this.storageKey, JSON.stringify(configs));\n // Crear backup automático\n this.createBackup(configs);\n return true;\n } catch (error) {\n console.error('Error guardando configuraciones:', error);\n return false;\n }\n }\n\n /**\n * Crea un backup de las configuraciones\n */\n createBackup(configs = null) {\n try {\n const configsToBackup = configs || this.loadConfigurations();\n const backup = {\n timestamp: new Date().toISOString(),\n configurations: configsToBackup,\n version: '1.0'\n };\n localStorage.setItem(this.backupKey, JSON.stringify(backup));\n return true;\n } catch (error) {\n console.error('Error creando backup:', error);\n return false;\n }\n }\n\n /**\n * Restaura configuraciones desde backup\n */\n restoreFromBackup() {\n try {\n const backup = localStorage.getItem(this.backupKey);\n if (backup) {\n const backupData = JSON.parse(backup);\n this.saveConfigurations(backupData.configurations);\n return true;\n }\n return false;\n } catch (error) {\n console.error('Error restaurando backup:', error);\n return false;\n }\n }\n\n /**\n * Exporta configuraciones para descarga\n */\n exportConfigurations() {\n const configs = this.loadConfigurations();\n const exportData = {\n timestamp: new Date().toISOString(),\n configurations: configs,\n version: '1.0'\n };\n return JSON.stringify(exportData, null, 2);\n }\n\n /**\n * Importa configuraciones desde archivo\n */\n importConfigurations(jsonData) {\n try {\n const importData = JSON.parse(jsonData);\n if (importData.configurations) {\n this.saveConfigurations(importData.configurations);\n return true;\n }\n return false;\n } catch (error) {\n console.error('Error importando configuraciones:', error);\n return false;\n }\n }\n\n /**\n * Resetea configuraciones a valores predeterminados\n */\n resetToDefaults() {\n try {\n localStorage.removeItem(this.storageKey);\n this.initializeDefaultConfigurations();\n return true;\n } catch (error) {\n console.error('Error reseteando configuraciones:', error);\n return false;\n }\n }\n\n /**\n * Estado de autenticación del administrador\n */\n isAuthenticated() {\n try {\n const raw = localStorage.getItem(this.authKey);\n if (!raw) return false;\n const data = JSON.parse(raw);\n return !!data?.authenticated;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Autentica al administrador con credenciales simples de demo\n */\n authenticateAdmin(username, password) {\n // Credenciales de prueba visibles en AdminAuth\n const validUser = username === 'admin';\n const validPass = password === 'martiderm2024';\n if (validUser && validPass) {\n const session = {\n authenticated: true,\n username,\n token: `adm-${Date.now()}`,\n lastLogin: new Date().toISOString()\n };\n localStorage.setItem(this.authKey, JSON.stringify(session));\n return { success: true, username };\n }\n return { success: false, error: 'Credenciales inválidas' };\n }\n\n /**\n * Obtiene información del usuario autenticado\n */\n getAuthenticatedUser() {\n try {\n const raw = localStorage.getItem(this.authKey);\n if (!raw) return null;\n const data = JSON.parse(raw);\n if (data?.authenticated) {\n return { username: data.username };\n }\n return null;\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Cierra sesión del administrador\n */\n logout() {\n try {\n localStorage.removeItem(this.authKey);\n return true;\n } catch (e) {\n return false;\n }\n }\n\n /**\n * Compatibilidad: método singular usado por AdminPanel\n */\n exportConfiguration() {\n return this.exportConfigurations();\n }\n}\n\nexport default new FilterConfigManager();\n\n// Exportar también la clase para testing\nexport { FilterConfigManager, DEFAULT_FILTER_CONFIG, CATEGORY_PRESETS };\n","import { FILTERS } from '../filters/index.js';\nimport filterConfigManager from '../config/FilterConfigManager.js';\n\nexport function buildWebglConfigForProduct(product) {\n const pc = filterConfigManager.getProductConfig(product.id) || {};\n const lockedType = product.filterType || (pc.webglConfig && pc.webglConfig.filterType) || 'wrinkles';\n const defaults = (FILTERS[lockedType] && FILTERS[lockedType].defaults) || { intensity: 0.5, sigma: 4, brightness: 0 };\n const deep = (FILTERS[lockedType] && FILTERS[lockedType].deep) || {};\n const base = {\n filterType: lockedType,\n intensity: (product.defaultIntensity !== undefined) ? product.defaultIntensity : defaults.intensity,\n sigma: (product.defaultSigma !== undefined) ? product.defaultSigma : defaults.sigma,\n brightness: (product.defaultBrightness !== undefined) ? product.defaultBrightness : defaults.brightness,\n contrast: typeof deep.contrast?.value === 'number' ? deep.contrast.value : 1.0,\n warmthR: typeof deep.warmth?.rPlus === 'number' ? deep.warmth.rPlus : 0,\n warmthB: typeof deep.warmth?.bMinus === 'number' ? deep.warmth.bMinus : 0,\n warmthA: typeof deep.warmth?.alpha === 'number' ? deep.warmth.alpha : 0,\n };\n const adminCfg = pc.webglConfig || {};\n return { ...base, ...adminCfg, filterType: lockedType };\n}\n\nexport default buildWebglConfigForProduct;\n","const TOKEN_PREFIX = 'mdfe2_';\nconst PRODUCT_CODE = 'md-face-engine';\nconst LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW9CHbTVvVXcm09wZIj6GKGaq8ae1\nXGQAum9LBLgoT3+4q3xPc7W9KSw1z4xgfOByTi8OzdjbjEaF3VrHjzl05w==\n-----END PUBLIC KEY-----`;\n\nlet publicKeyCache = null;\n\nfunction decodeBase64Url(value) {\n const normalized = value.replace(/-/g, '+').replace(/_/g, '/');\n const padded = normalized + '='.repeat((4 - (normalized.length % 4)) % 4);\n return atob(padded);\n}\n\nfunction decodeBase64UrlToBytes(value) {\n const bin = decodeBase64Url(value);\n const bytes = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i += 1) {\n bytes[i] = bin.charCodeAt(i);\n }\n return bytes;\n}\n\nfunction pemToArrayBuffer(pem) {\n const b64 = pem\n .replace(/-----BEGIN PUBLIC KEY-----/g, '')\n .replace(/-----END PUBLIC KEY-----/g, '')\n .replace(/\\s+/g, '');\n const raw = atob(b64);\n const bytes = new Uint8Array(raw.length);\n for (let i = 0; i < raw.length; i += 1) {\n bytes[i] = raw.charCodeAt(i);\n }\n return bytes.buffer;\n}\n\nasync function importPublicKey(publicKeyPem = LICENSE_PUBLIC_KEY_PEM) {\n if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM && publicKeyCache) {\n return publicKeyCache;\n }\n\n const keyData = pemToArrayBuffer(publicKeyPem);\n const key = await crypto.subtle.importKey(\n 'spki',\n keyData,\n { name: 'ECDSA', namedCurve: 'P-256' },\n false,\n ['verify']\n );\n\n if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM) {\n publicKeyCache = key;\n }\n\n return key;\n}\n\nexport async function validateLicenseToken(token, options = {}) {\n const {\n now = Date.now(),\n publicKeyPem = LICENSE_PUBLIC_KEY_PEM,\n allowExpired = false\n } = options;\n\n if (!token || typeof token !== 'string') {\n return { valid: false, reason: 'Token vacío o inválido' };\n }\n\n if (!token.startsWith(TOKEN_PREFIX)) {\n return { valid: false, reason: 'Prefijo de token inválido' };\n }\n\n const raw = token.slice(TOKEN_PREFIX.length);\n const parts = raw.split('.');\n if (parts.length !== 2) {\n return { valid: false, reason: 'Formato de token inválido' };\n }\n\n const [payloadPart, signaturePart] = parts;\n\n let payload;\n try {\n payload = JSON.parse(decodeBase64Url(payloadPart));\n } catch (_err) {\n return { valid: false, reason: 'Payload de licencia inválido' };\n }\n\n try {\n const key = await importPublicKey(publicKeyPem);\n const isValid = await crypto.subtle.verify(\n { name: 'ECDSA', hash: 'SHA-256' },\n key,\n decodeBase64UrlToBytes(signaturePart),\n new TextEncoder().encode(payloadPart)\n );\n\n if (!isValid) {\n return { valid: false, reason: 'Firma de licencia inválida' };\n }\n } catch (_err) {\n return { valid: false, reason: 'Error verificando firma de licencia' };\n }\n\n if (payload.productCode !== PRODUCT_CODE) {\n return { valid: false, reason: 'Licencia de otro producto' };\n }\n\n if (!allowExpired && (typeof payload.exp !== 'number' || payload.exp < now)) {\n return { valid: false, reason: 'Licencia vencida', payload };\n }\n\n return { valid: true, reason: null, payload };\n}\n\nexport { TOKEN_PREFIX, PRODUCT_CODE, LICENSE_PUBLIC_KEY_PEM };\n","import { FILTERS, FILTER_ORDER, getFilter, filterConfigManager, buildWebglConfigForProduct } from './core/index.js';\nimport { validateLicenseToken, PRODUCT_CODE } from './license/token.js';\n\nexport class MdFaceEngine {\n constructor() {\n this.license = null;\n this.activated = false;\n }\n\n async activate(token) {\n const result = await validateLicenseToken(token);\n\n if (!result.valid) {\n this.license = null;\n this.activated = false;\n throw new Error(`Licencia inválida: ${result.reason}`);\n }\n\n this.license = result.payload;\n this.activated = true;\n return result.payload;\n }\n\n isActivated() {\n return this.activated;\n }\n\n assertActivated() {\n if (!this.activated) {\n throw new Error('md-face-engine no está activado. Configura VITE_MD_FACE_ENGINE_TOKEN.');\n }\n }\n\n getLicense() {\n this.assertActivated();\n return this.license;\n }\n\n getProductCode() {\n return PRODUCT_CODE;\n }\n\n getFilterRegistry() {\n this.assertActivated();\n return FILTERS;\n }\n\n getFilterOrder() {\n this.assertActivated();\n return FILTER_ORDER;\n }\n\n getFilter(key) {\n this.assertActivated();\n return getFilter(key);\n }\n\n getFilterConfigManager() {\n this.assertActivated();\n return filterConfigManager;\n }\n\n buildWebglConfigForProduct(product) {\n this.assertActivated();\n return buildWebglConfigForProduct(product);\n }\n}\n\nexport { MdFaceEngine as MartidermEngine };\nexport default MdFaceEngine;\n","import MdFaceEngine from './MartidermEngine.js';\nimport {\n FILTERS as CORE_FILTERS,\n FILTER_ORDER as CORE_FILTER_ORDER,\n getFilter as coreGetFilter,\n filterConfigManager as coreFilterConfigManager,\n buildWebglConfigForProduct as coreBuildWebglConfigForProduct\n} from './core/index.js';\n\nexport async function createMdFaceEngineClient({ token, products = [] } = {}) {\n if (!token) {\n throw new Error('Falta token de licencia para activar md-face-engine.');\n }\n\n const engine = new MdFaceEngine();\n await engine.activate(token);\n engine.assertActivated();\n\n const filterConfigManager = engine.getFilterConfigManager();\n if (Array.isArray(products)) {\n filterConfigManager.setProducts(products);\n }\n\n return {\n engine,\n FILTERS: engine.getFilterRegistry(),\n FILTER_ORDER: engine.getFilterOrder(),\n getFilter: (key) => engine.getFilter(key),\n filterConfigManager,\n buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)\n };\n}\n\nexport async function createMdFaceEngineRuntime({ token, products = [] } = {}) {\n let client = null;\n let licenseError = null;\n let isLicenseActive = false;\n\n if (token) {\n try {\n client = await createMdFaceEngineClient({ token, products });\n isLicenseActive = true;\n } catch (error) {\n licenseError = error;\n isLicenseActive = false;\n }\n }\n\n if (!client && Array.isArray(products) && typeof coreFilterConfigManager?.setProducts === 'function') {\n coreFilterConfigManager.setProducts(products);\n }\n\n return {\n engine: client?.engine || null,\n FILTERS: client?.FILTERS || CORE_FILTERS,\n FILTER_ORDER: client?.FILTER_ORDER || CORE_FILTER_ORDER,\n getFilter: client?.getFilter || coreGetFilter,\n filterConfigManager: client?.filterConfigManager || coreFilterConfigManager,\n buildWebglConfigForProduct: client?.buildWebglConfigForProduct || coreBuildWebglConfigForProduct,\n license: {\n active: isLicenseActive,\n error: licenseError,\n mode: isLicenseActive ? 'licensed' : 'unlicensed'\n }\n };\n}\n"],"names":["filterConfigManager","CORE_FILTERS","CORE_FILTER_ORDER","coreGetFilter","coreBuildWebglConfigForProduct"],"mappings":"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"}
@@ -464,10 +464,10 @@ class FilterConfigManager {
464
464
  return this.exportConfigurations();
465
465
  }
466
466
  }
467
- const filterConfigManager = new FilterConfigManager();
467
+ const coreFilterConfigManager = new FilterConfigManager();
468
468
  function buildWebglConfigForProduct(product) {
469
469
  var _a, _b, _c, _d;
470
- const pc = filterConfigManager.getProductConfig(product.id) || {};
470
+ const pc = coreFilterConfigManager.getProductConfig(product.id) || {};
471
471
  const lockedType = product.filterType || pc.webglConfig && pc.webglConfig.filterType || "wrinkles";
472
472
  const defaults = FILTERS[lockedType] && FILTERS[lockedType].defaults || { intensity: 0.5, sigma: 4, brightness: 0 };
473
473
  const deep = FILTERS[lockedType] && FILTERS[lockedType].deep || {};
@@ -484,25 +484,58 @@ function buildWebglConfigForProduct(product) {
484
484
  const adminCfg = pc.webglConfig || {};
485
485
  return { ...base, ...adminCfg, filterType: lockedType };
486
486
  }
487
- const TOKEN_PREFIX = "mdfe_";
487
+ const TOKEN_PREFIX = "mdfe2_";
488
488
  const PRODUCT_CODE = "md-face-engine";
489
- const LICENSE_SECRET = "md-face-engine-license-v1";
490
- function hashToken(value) {
491
- let hash = 5381;
492
- for (let i = 0; i < value.length; i += 1) {
493
- hash = (hash << 5) + hash + value.charCodeAt(i);
494
- hash &= 4294967295;
495
- }
496
- return (hash >>> 0).toString(16).padStart(8, "0");
497
- }
489
+ const LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
490
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEW9CHbTVvVXcm09wZIj6GKGaq8ae1
491
+ XGQAum9LBLgoT3+4q3xPc7W9KSw1z4xgfOByTi8OzdjbjEaF3VrHjzl05w==
492
+ -----END PUBLIC KEY-----`;
493
+ let publicKeyCache = null;
498
494
  function decodeBase64Url(value) {
499
495
  const normalized = value.replace(/-/g, "+").replace(/_/g, "/");
500
- const padding = normalized.length % 4;
501
- const padded = padding ? normalized + "=".repeat(4 - padding) : normalized;
496
+ const padded = normalized + "=".repeat((4 - normalized.length % 4) % 4);
502
497
  return atob(padded);
503
498
  }
504
- function validateLicenseToken(token, options = {}) {
505
- const { now = Date.now() } = options;
499
+ function decodeBase64UrlToBytes(value) {
500
+ const bin = decodeBase64Url(value);
501
+ const bytes = new Uint8Array(bin.length);
502
+ for (let i = 0; i < bin.length; i += 1) {
503
+ bytes[i] = bin.charCodeAt(i);
504
+ }
505
+ return bytes;
506
+ }
507
+ function pemToArrayBuffer(pem) {
508
+ const b64 = pem.replace(/-----BEGIN PUBLIC KEY-----/g, "").replace(/-----END PUBLIC KEY-----/g, "").replace(/\s+/g, "");
509
+ const raw = atob(b64);
510
+ const bytes = new Uint8Array(raw.length);
511
+ for (let i = 0; i < raw.length; i += 1) {
512
+ bytes[i] = raw.charCodeAt(i);
513
+ }
514
+ return bytes.buffer;
515
+ }
516
+ async function importPublicKey(publicKeyPem = LICENSE_PUBLIC_KEY_PEM) {
517
+ if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM && publicKeyCache) {
518
+ return publicKeyCache;
519
+ }
520
+ const keyData = pemToArrayBuffer(publicKeyPem);
521
+ const key = await crypto.subtle.importKey(
522
+ "spki",
523
+ keyData,
524
+ { name: "ECDSA", namedCurve: "P-256" },
525
+ false,
526
+ ["verify"]
527
+ );
528
+ if (publicKeyPem === LICENSE_PUBLIC_KEY_PEM) {
529
+ publicKeyCache = key;
530
+ }
531
+ return key;
532
+ }
533
+ async function validateLicenseToken(token, options = {}) {
534
+ const {
535
+ now = Date.now(),
536
+ publicKeyPem = LICENSE_PUBLIC_KEY_PEM,
537
+ allowExpired = false
538
+ } = options;
506
539
  if (!token || typeof token !== "string") {
507
540
  return { valid: false, reason: "Token vacío o inválido" };
508
541
  }
@@ -514,22 +547,32 @@ function validateLicenseToken(token, options = {}) {
514
547
  if (parts.length !== 2) {
515
548
  return { valid: false, reason: "Formato de token inválido" };
516
549
  }
517
- const [payloadPart, signature] = parts;
518
- const expected = hashToken(`${payloadPart}.${LICENSE_SECRET}`);
519
- if (signature !== expected) {
520
- return { valid: false, reason: "Firma de licencia inválida" };
521
- }
550
+ const [payloadPart, signaturePart] = parts;
522
551
  let payload;
523
552
  try {
524
553
  payload = JSON.parse(decodeBase64Url(payloadPart));
525
554
  } catch (_err) {
526
555
  return { valid: false, reason: "Payload de licencia inválido" };
527
556
  }
557
+ try {
558
+ const key = await importPublicKey(publicKeyPem);
559
+ const isValid = await crypto.subtle.verify(
560
+ { name: "ECDSA", hash: "SHA-256" },
561
+ key,
562
+ decodeBase64UrlToBytes(signaturePart),
563
+ new TextEncoder().encode(payloadPart)
564
+ );
565
+ if (!isValid) {
566
+ return { valid: false, reason: "Firma de licencia inválida" };
567
+ }
568
+ } catch (_err) {
569
+ return { valid: false, reason: "Error verificando firma de licencia" };
570
+ }
528
571
  if (payload.productCode !== PRODUCT_CODE) {
529
572
  return { valid: false, reason: "Licencia de otro producto" };
530
573
  }
531
- if (typeof payload.exp !== "number" || payload.exp < now) {
532
- return { valid: false, reason: "Licencia vencida" };
574
+ if (!allowExpired && (typeof payload.exp !== "number" || payload.exp < now)) {
575
+ return { valid: false, reason: "Licencia vencida", payload };
533
576
  }
534
577
  return { valid: true, reason: null, payload };
535
578
  }
@@ -538,8 +581,8 @@ class MdFaceEngine {
538
581
  this.license = null;
539
582
  this.activated = false;
540
583
  }
541
- activate(token) {
542
- const result = validateLicenseToken(token);
584
+ async activate(token) {
585
+ const result = await validateLicenseToken(token);
543
586
  if (!result.valid) {
544
587
  this.license = null;
545
588
  this.activated = false;
@@ -578,33 +621,63 @@ class MdFaceEngine {
578
621
  }
579
622
  getFilterConfigManager() {
580
623
  this.assertActivated();
581
- return filterConfigManager;
624
+ return coreFilterConfigManager;
582
625
  }
583
626
  buildWebglConfigForProduct(product) {
584
627
  this.assertActivated();
585
628
  return buildWebglConfigForProduct(product);
586
629
  }
587
630
  }
588
- function createMdFaceEngineClient({ token, products = [] } = {}) {
631
+ async function createMdFaceEngineClient({ token, products = [] } = {}) {
589
632
  if (!token) {
590
633
  throw new Error("Falta token de licencia para activar md-face-engine.");
591
634
  }
592
635
  const engine = new MdFaceEngine();
593
- engine.activate(token);
636
+ await engine.activate(token);
594
637
  engine.assertActivated();
595
- const filterConfigManager2 = engine.getFilterConfigManager();
638
+ const filterConfigManager = engine.getFilterConfigManager();
596
639
  if (Array.isArray(products)) {
597
- filterConfigManager2.setProducts(products);
640
+ filterConfigManager.setProducts(products);
598
641
  }
599
642
  return {
600
643
  engine,
601
644
  FILTERS: engine.getFilterRegistry(),
602
645
  FILTER_ORDER: engine.getFilterOrder(),
603
646
  getFilter: (key) => engine.getFilter(key),
604
- filterConfigManager: filterConfigManager2,
647
+ filterConfigManager,
605
648
  buildWebglConfigForProduct: (product) => engine.buildWebglConfigForProduct(product)
606
649
  };
607
650
  }
651
+ async function createMdFaceEngineRuntime({ token, products = [] } = {}) {
652
+ let client = null;
653
+ let licenseError = null;
654
+ let isLicenseActive = false;
655
+ if (token) {
656
+ try {
657
+ client = await createMdFaceEngineClient({ token, products });
658
+ isLicenseActive = true;
659
+ } catch (error) {
660
+ licenseError = error;
661
+ isLicenseActive = false;
662
+ }
663
+ }
664
+ if (!client && Array.isArray(products) && typeof (coreFilterConfigManager == null ? void 0 : coreFilterConfigManager.setProducts) === "function") {
665
+ coreFilterConfigManager.setProducts(products);
666
+ }
667
+ return {
668
+ engine: (client == null ? void 0 : client.engine) || null,
669
+ FILTERS: (client == null ? void 0 : client.FILTERS) || FILTERS,
670
+ FILTER_ORDER: (client == null ? void 0 : client.FILTER_ORDER) || FILTER_ORDER,
671
+ getFilter: (client == null ? void 0 : client.getFilter) || getFilter,
672
+ filterConfigManager: (client == null ? void 0 : client.filterConfigManager) || coreFilterConfigManager,
673
+ buildWebglConfigForProduct: (client == null ? void 0 : client.buildWebglConfigForProduct) || buildWebglConfigForProduct,
674
+ license: {
675
+ active: isLicenseActive,
676
+ error: licenseError,
677
+ mode: isLicenseActive ? "licensed" : "unlicensed"
678
+ }
679
+ };
680
+ }
608
681
  exports.CATEGORY_PRESETS = CATEGORY_PRESETS;
609
682
  exports.DEFAULT_FILTER_CONFIG = DEFAULT_FILTER_CONFIG;
610
683
  exports.FILTERS = FILTERS;
@@ -612,8 +685,9 @@ exports.FILTER_ORDER = FILTER_ORDER;
612
685
  exports.FilterConfigManager = FilterConfigManager;
613
686
  exports.MdFaceEngine = MdFaceEngine;
614
687
  exports.buildWebglConfigForProduct = buildWebglConfigForProduct;
688
+ exports.coreFilterConfigManager = coreFilterConfigManager;
615
689
  exports.createMdFaceEngineClient = createMdFaceEngineClient;
616
- exports.filterConfigManager = filterConfigManager;
690
+ exports.createMdFaceEngineRuntime = createMdFaceEngineRuntime;
617
691
  exports.getFilter = getFilter;
618
692
  exports.validateLicenseToken = validateLicenseToken;
619
- //# sourceMappingURL=client-DimGdJ4Y.cjs.map
693
+ //# sourceMappingURL=client-Com8umy4.cjs.map