En esta lección se amplía el ejemplo de la lección anterior para controlar el acceso a una app.
Puedes probar el ejemplo en https://srvaut.rf.gd/.
Prueba con los siguientes usarios y contraseñas:
Este ejmplo se puede complementar usando reCaptcha..
Este ejemplo usa sesión en el navegador, que es un archivo en el servidor que permite guardar la información del usuario. Este mecanismo está cayendo en desuso, porque limita la veocidad del servidor y lo expone a fallas de seguridad.
Hoy en día se prefiere usar servidores de OAuth 2 para autenticar usuarios. Los principales servidores para este tipo de autenticación son Google, Facebook y Microsoft.
Algunos navegadores web bloquean las interfaces que muestran etiquetas como
contraseña
, usuario
, id
, email
, etcétera,
suponiendo que es un
intento de engañar al usuario; para evitar este problema, al campo con el
nombre de usuario se le llama cue
y a la conreaseña match
.
Prueba el ejemplo en https://srvaut.rf.gd/.
Descarga el archivo /src/srvaut.zip y descompáctalo.
Crea una cuenta de email pqra ti, por ejemplo, pepito@google.com. Si ya tienes un email, omite este paso.
Crea una cuenta de GitHub usando el email anterior y selecciona el nombre de usuario unsando la parte inicial del correo electrónico, por ejemplo pepito. Si ya tienes una cuenta, omite este paso.
Crea un repositorio nuevo. En el nombre del repositorio debes poner el nombre de tu sitio; por ejemplo devuelvejson
Edita los archivos que desees.
Prueba tu sitio localmente.
Necesitas un hosting. En este ejemplo se muestra como usar el hosting. https://infinityfree.com/ Si no lo has usado, lo primero que tienes que hacer es entrar a registrar tu email con el botón Registrar. Si ya tienes tu email registrado, omite este paso.
Crea una cuenta. Si ya tienes cuenta, entra a ella y crea un nuevo domino. En este ejemplo no se crean los archivos directamente en el hosting.
Sube tus archivos a GitHub. En este ejemplo no hay archivo sw.js ni necesitas esperar 11 o más minutos.
Prueba el ejemplo en https://srvaut.rf.gd/.
Descarga el archivo /src/srvaut.zip y descompáctalo.
Crea tu proyecto en GitHub:
Crea una cuenta de email para tí, por ejemplo, pepito@google.com. Si ya tienes un email, omite este paso.
Crea una cuenta de GitHub usando el email anterior y selecciona el nombre de usuario unsando la parte inicial del correo electrónico, por ejemplo pepito. Si ya tienes una cuenta, omite este paso.
Crea un repositorio nuevo. En la página principal de GitHub cliquea 📘 New.
En la página Create a new repository introduce los siguientes datos:
Proporciona el nombre de tu repositorio debajo de donde dice Repository name *.
Mantén la selección Public para que otros usuarios puedan ver tu proyecto.
Verifica la casilla Add a README file. En este archivo se muestra información sobre tu proyecto.
Cliquea License: None. y selecciona la licencia que consideres más adecuada para tu proyecto.
Cliquea Create repository.
Importa el proyecto en GitHub:
En la página principal de tu proyecto en GitHub, en la pestaña < > Code, cliquea < > Code y en la sección Branches y copia la dirección que está en HTTPS, debajo de Clone.
En Visual Studio Code, usa el botón de la izquierda para Source Control.
Cliquea el botón Clone Repository.
Pega la url que copiaste anteriormente hasta arriba, donde dice algo como Provide repository URL y presiona la teclea Intro.
Selecciona la carpeta donde se guardará la carpeta del proyecto.
Abre la carpeta del proyecto importado.
Añade el contenido de la carpeta descompactada que contiene el código del ejemplo.
Edita los archivos que desees.
Haz clic derecho en index.html
, selecciona
PHP Server: serve project y se abre el navegador para que puedas
probar localmente el ejemplo.
Para depurar paso a paso haz lo siguiente:
En el navegador, haz clic derecho en la página que deseas depurar y selecciona inspeccionar.
Recarga la página, de preferencia haciendo clic derecho en el ícono de
volver a cargar la página
y
seleccionando vaciar caché y volver a cargar de manera forzada (o
algo parecido). Si no aparece un menú emergente, simplemente cliquea
volver a cargar la página
.
Revisa que no aparezca ningún error ni en la pestañas Consola, ni
en Red.
Selecciona la pestaña Fuentes (o Sources si tu navegador está en Inglés).
Selecciona el archivo donde vas a empezar a depurar.
Haz clic en el número de la línea donde vas a empezar a depurar.
En Visual Studio Code, abre el archivo de PHP donde vas a empezar a depurar.
Haz clic en Run and Debug
.
Si no está configurada la depuración, haz clic en create a launch json file.
Haz clic en la flechita RUN AND DEBUG, al lado de la cual debe
decir Listen for Xdebug
.
Aparece un cuadro con los controles de depuración
Selecciona otra vez el archivo de PHP y haz clic en el número de la línea donde vas a empezar a depurar.
Regresa al navegador, recarga la página y empieza a usarla.
Si se ejecuta alguna de las líneas de código seleccionadas, aparece resaltada en la pestaña de fuentes. Usa los controles de depuración para avanzar, como se muestra en este video.
Sube el proyecto al hosting que elijas.
Crea una nueva carpeta para crear un nuevo proyecto que estará conectado directamente al servidor web por ftp.
Abre la nueva carpeta con Visual Studio Code.
Tecle al mismo Mayúsculas+Control+P y selecciona SFTP: Config. Aparece un archivo de configuración de FTP. Llena los datos con la configuración de FTP de tu servidor, excepto la contraseña.
Cliquea el botón de SFTP y luego haz clic en la URL de tu servidos. En la barra superior te pide la contraseña y ENTER.
Pásate a la parte de archivos y coloca tus archivos.
Cliquea con el botón derecho en la sección de archivos y selecciona Sync: Local -> Remote.
Abre un navegador y prueba el proyecto en tu hosting.
En el hosting InfinityFree, la primera vez que corres la página, puede marcar un mensaje de error, pero al recargar funciona correctamente. Puedes evitar este problema usando un dominio propio.
Para subir el código a GitHub, en la sección de SOURCE CONTROL, en Message introduce un mensaje sobre los cambios que hiciste, por ejemplo index.html corregido, selecciona v y luego Commit & Push.
Haz clic en los triángulos para expandir las carpetas
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Autenticación</title> |
| 10 | |
| 11 | <link rel="stylesheet" href="css/estilos.css"> |
| 12 | <script src="dompurify/purify.min.js"></script> |
| 13 | <script type="module" src="libclienteweb/manejaErrores.js"></script> |
| 14 | <script type="module" src="js/custom/mi-nav.js"></script> |
| 15 | |
| 16 | </head> |
| 17 | |
| 18 | <body> |
| 19 | |
| 20 | <mi-nav></mi-nav> |
| 21 | |
| 22 | <h1>Autenticación</h1> |
| 23 | |
| 24 | <p>Bienvenid@.</p> |
| 25 | |
| 26 | <script type="module" src="js/index.js"></script> |
| 27 | |
| 28 | </body> |
| 29 | |
| 30 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Perfil</title> |
| 10 | |
| 11 | <link rel="stylesheet" href="css/estilos.css"> |
| 12 | <script src="dompurify/purify.min.js"></script> |
| 13 | <script type="module" src="libclienteweb/manejaErrores.js"></script> |
| 14 | <script type="module" src="js/custom/mi-nav.js"></script> |
| 15 | |
| 16 | |
| 17 | </head> |
| 18 | |
| 19 | <body> |
| 20 | |
| 21 | <mi-nav></mi-nav> |
| 22 | |
| 23 | <h1>Perfil</h1> |
| 24 | |
| 25 | <p> |
| 26 | <output id="outputSan"> |
| 27 | <progress max="100">Cargando…</progress> |
| 28 | </output> |
| 29 | </p> |
| 30 | |
| 31 | <p> |
| 32 | <output id="outputRoles"></output> |
| 33 | </p> |
| 34 | |
| 35 | <p> |
| 36 | |
| 37 | <a id="login" hidden href="login.html">Iniciar sesión</a> |
| 38 | |
| 39 | <button id="botonLogout" type="button" hidden> |
| 40 | Terminar sesión |
| 41 | </button> |
| 42 | |
| 43 | </p> |
| 44 | |
| 45 | <script type="module" src="js/perfil.js"></script> |
| 46 | |
| 47 | </body> |
| 48 | |
| 49 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Iniciar sesión</title> |
| 10 | |
| 11 | <link rel="stylesheet" href="css/estilos.css"> |
| 12 | <script src="dompurify/purify.min.js"></script> |
| 13 | <script type="module" src="libclienteweb/manejaErrores.js"></script> |
| 14 | |
| 15 | </head> |
| 16 | |
| 17 | <body> |
| 18 | |
| 19 | <progress id="ocupado" max="100">Cargando…</progress> |
| 20 | |
| 21 | <form id="formulario" hidden> |
| 22 | |
| 23 | <h1>Iniciar Sesión</h1> |
| 24 | |
| 25 | <p><a href="perfil.html">Cancelar</a></p> |
| 26 | |
| 27 | <p> |
| 28 | <label> |
| 29 | San |
| 30 | <input name="san"> |
| 31 | </label> |
| 32 | </p> |
| 33 | |
| 34 | <p> |
| 35 | <label> |
| 36 | Sen |
| 37 | <input type="password" name="sen"> |
| 38 | </label> |
| 39 | </p> |
| 40 | |
| 41 | <p><button type="submit">Iniciar sesión</button></p> |
| 42 | |
| 43 | </form> |
| 44 | |
| 45 | <script type="module" src="js/login.js"></script> |
| 46 | |
| 47 | </body> |
| 48 | |
| 49 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Solo Administradores</title> |
| 10 | |
| 11 | <link rel="stylesheet" href="css/estilos.css"> |
| 12 | <script src="dompurify/purify.min.js"></script> |
| 13 | <script type="module" src="libclienteweb/manejaErrores.js"></script> |
| 14 | <script type="module" src="js/custom/mi-nav.js"></script> |
| 15 | |
| 16 | </head> |
| 17 | |
| 18 | <body> |
| 19 | |
| 20 | <mi-nav></mi-nav> |
| 21 | |
| 22 | <main id="main" hidden> |
| 23 | |
| 24 | <h1>Solo Administradores</h1> |
| 25 | |
| 26 | <p>Hola.</p> |
| 27 | |
| 28 | <p> |
| 29 | <button id="botonSaludo"> |
| 30 | Ejecuta servicio |
| 31 | </button> |
| 32 | </p> |
| 33 | |
| 34 | </main> |
| 35 | |
| 36 | <script type="module" src="js/administrador.js"></script> |
| 37 | |
| 38 | </body> |
| 39 | |
| 40 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Solo Clientes</title> |
| 10 | |
| 11 | <link rel="stylesheet" href="css/estilos.css"> |
| 12 | <script src="dompurify/purify.min.js"></script> |
| 13 | <script type="module" src="libclienteweb/manejaErrores.js"></script> |
| 14 | <script type="module" src="js/custom/mi-nav.js"></script> |
| 15 | |
| 16 | </head> |
| 17 | |
| 18 | <body> |
| 19 | |
| 20 | <mi-nav></mi-nav> |
| 21 | |
| 22 | <main id="main" hidden> |
| 23 | |
| 24 | <h1>Solo Clientes</h1> |
| 25 | |
| 26 | <p>Hola.</p> |
| 27 | |
| 28 | <p> |
| 29 | <button id="botonSaludo"> |
| 30 | Ejecuta servicio |
| 31 | </button> |
| 32 | </p> |
| 33 | |
| 34 | </main> |
| 35 | |
| 36 | <script type="module" src="js/cliente.js"></script> |
| 37 | |
| 38 | </body> |
| 39 | |
| 40 | </html> |
Este archivo configura las respuestas del servidor..
Lo utilizan principalmente servidores como Apache o Nginx.
Configura el mime type para el archivo de manifiesto y sedhabilita el uso de la cache general de http..
| 1 | AddType application/manifest+json .webmanifest |
| 2 | |
| 3 | ExpiresActive On |
| 4 | |
| 5 | Header set Cache-Control "max-age=1, must-revalidate" |
| 6 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/ROL_ID_CLIENTE.php"; |
| 4 | require_once __DIR__ . "/ROL_ID_ADMINISTRADOR.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/rolBusca.php"; |
| 6 | require_once __DIR__ . "/../libservidorphp/rolAgrega.php"; |
| 7 | require_once __DIR__ . "/../libservidorphp/usuRolAgrega.php"; |
| 8 | require_once __DIR__ . "/usuarioBuscaSan.php"; |
| 9 | |
| 10 | class Bd |
| 11 | { |
| 12 | |
| 13 | private static ?PDO $pdo = null; |
| 14 | |
| 15 | static function pdo(): PDO |
| 16 | { |
| 17 | if (self::$pdo === null) { |
| 18 | |
| 19 | self::$pdo = new PDO( |
| 20 | // cadena de conexión |
| 21 | "sqlite:" . __DIR__ . "/srvaut.db", |
| 22 | // usuario |
| 23 | null, |
| 24 | // contraseña |
| 25 | null, |
| 26 | // Opciones: pdos no persistentes y lanza excepciones. |
| 27 | [PDO::ATTR_PERSISTENT => false, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] |
| 28 | ); |
| 29 | |
| 30 | self::$pdo->exec( |
| 31 | 'CREATE TABLE IF NOT EXISTS USUARIO ( |
| 32 | USU_ID INTEGER, |
| 33 | USU_SAN TEXT NOT NULL, |
| 34 | USU_SEN TEXT NOT NULL, |
| 35 | CONSTRAINT USU_PK |
| 36 | PRIMARY KEY(USU_ID), |
| 37 | CONSTRAINT USU_SAN_UNQ |
| 38 | UNIQUE(USU_SAN), |
| 39 | CONSTRAINT USU_SAN_NV |
| 40 | CHECK(LENGTH(USU_SAN) > 0) |
| 41 | )' |
| 42 | ); |
| 43 | self::$pdo->exec( |
| 44 | 'CREATE TABLE IF NOT EXISTS ROL ( |
| 45 | ROL_ID TEXT NOT NULL, |
| 46 | ROL_DESCRIPCION TEXT NOT NULL, |
| 47 | CONSTRAINT ROL_PK |
| 48 | PRIMARY KEY(ROL_ID), |
| 49 | CONSTRAINT ROL_ID_NV |
| 50 | CHECK(LENGTH(ROL_ID) > 0), |
| 51 | CONSTRAINT ROL_DESCR_UNQ |
| 52 | UNIQUE(ROL_DESCRIPCION), |
| 53 | CONSTRAINT ROL_DESCR_NV |
| 54 | CHECK(LENGTH(ROL_DESCRIPCION) > 0) |
| 55 | )' |
| 56 | ); |
| 57 | self::$pdo->exec( |
| 58 | 'CREATE TABLE IF NOT EXISTS USU_ROL ( |
| 59 | USU_ID INTEGER NOT NULL, |
| 60 | ROL_ID TEXT NOT NULL, |
| 61 | CONSTRAINT USU_ROL_PK |
| 62 | PRIMARY KEY(USU_ID, ROL_ID), |
| 63 | CONSTRAINT USU_ROL_USU_FK |
| 64 | FOREIGN KEY (USU_ID) REFERENCES USUARIO(USU_ID), |
| 65 | CONSTRAINT USU_ROL_ROL_FK |
| 66 | FOREIGN KEY (ROL_ID) REFERENCES ROL(ROL_ID) |
| 67 | )' |
| 68 | ); |
| 69 | |
| 70 | self::$pdo->beginTransaction(); |
| 71 | |
| 72 | if (rolBusca(self::$pdo, "Administrador") === false) { |
| 73 | rolAgrega( |
| 74 | bd: self::$pdo, |
| 75 | id: "Administrador", |
| 76 | descripcion: "Administra el sistema." |
| 77 | ); |
| 78 | } |
| 79 | |
| 80 | if (rolBusca(self::$pdo, "Cliente") === false) { |
| 81 | rolAgrega( |
| 82 | bd: self::$pdo, |
| 83 | id: "Cliente", |
| 84 | descripcion: "Realiza compras." |
| 85 | ); |
| 86 | } |
| 87 | |
| 88 | $usuarioAgrega = self::$pdo->prepare( |
| 89 | "INSERT INTO USUARIO ( |
| 90 | USU_SAN, USU_SEN |
| 91 | ) VALUES ( |
| 92 | :USU_SAN, :USU_SEN |
| 93 | )" |
| 94 | ); |
| 95 | |
| 96 | if (usuarioBuscaSan(self::$pdo, "pepito") === false) { |
| 97 | $usuarioAgrega->execute([ |
| 98 | ":USU_SAN" => "pepito", |
| 99 | ":USU_SEN" => password_hash("cuentos", PASSWORD_DEFAULT), |
| 100 | ]); |
| 101 | $usuId = self::$pdo->lastInsertId(); |
| 102 | usuRolAgrega(self::$pdo, $usuId, [ROL_ID_CLIENTE]); |
| 103 | } |
| 104 | |
| 105 | if (usuarioBuscaSan(self::$pdo, "susana") === false) { |
| 106 | $usuarioAgrega->execute([ |
| 107 | ":USU_SAN" => "susana", |
| 108 | ":USU_SEN" => password_hash("alegria", PASSWORD_DEFAULT), |
| 109 | ]); |
| 110 | $usuId = self::$pdo->lastInsertId(); |
| 111 | usuRolAgrega(self::$pdo, $usuId, [ROL_ID_ADMINISTRADOR]); |
| 112 | } |
| 113 | |
| 114 | if (usuarioBuscaSan(self::$pdo, "bebe") === false) { |
| 115 | $usuarioAgrega->execute([ |
| 116 | ":USU_SAN" => "bebe", |
| 117 | ":USU_SEN" => password_hash("saurio", PASSWORD_DEFAULT), |
| 118 | ]); |
| 119 | $usuId = self::$pdo->lastInsertId(); |
| 120 | usuRolAgrega(self::$pdo, $usuId, [ROL_ID_CLIENTE,ROL_ID_ADMINISTRADOR]); |
| 121 | } |
| 122 | |
| 123 | self::$pdo->commit(); |
| 124 | } |
| 125 | |
| 126 | return self::$pdo; |
| 127 | } |
| 128 | } |
| 129 |
| 1 | <?php |
| 2 | |
| 3 | function jsonMiNav(string $san, array $rolIds) |
| 4 | { |
| 5 | $json = [ |
| 6 | "ocupado" => ["hidden" => true], |
| 7 | "aAdmin" => [ |
| 8 | "hidden" => array_search(ROL_ID_ADMINISTRADOR, $rolIds, true) === false |
| 9 | ], |
| 10 | "aCliente" => [ |
| 11 | "hidden" => array_search(ROL_ID_CLIENTE, $rolIds, true) === false |
| 12 | ], |
| 13 | "san" => ["hidden" => $san === "", "textContent" => $san], |
| 14 | ]; |
| 15 | |
| 16 | return $json; |
| 17 | } |
| 18 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/../libservidorphp/BAD_REQUEST.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/recibeTextoObligatorio.php"; |
| 6 | require_once __DIR__ . "/../libservidorphp/recibeTexto.php"; |
| 7 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 8 | require_once __DIR__ . "/../libservidorphp/rolIdsParaUsuId.php"; |
| 9 | require_once __DIR__ . "/SAN.php"; |
| 10 | require_once __DIR__ . "/USU_ID.php"; |
| 11 | require_once __DIR__ . "/ROL_IDS.php"; |
| 12 | require_once __DIR__ . "/Bd.php"; |
| 13 | require_once __DIR__ . "/protegeLogin.php"; |
| 14 | require_once __DIR__ . "/usuarioBuscaSan.php"; |
| 15 | |
| 16 | protegeLogin([]); |
| 17 | |
| 18 | $san = recibeTextoObligatorio("san"); |
| 19 | $sen = recibeTexto("sen"); |
| 20 | |
| 21 | $bd = Bd::pdo(); |
| 22 | |
| 23 | $usuario = usuarioBuscaSan($bd, $san); |
| 24 | |
| 25 | if ( |
| 26 | $usuario === false |
| 27 | || !password_verify( |
| 28 | ($sen === false || $sen === null) ? "" : $sen, |
| 29 | $usuario["USU_SEN"] |
| 30 | ) |
| 31 | ) |
| 32 | throw new ProblemDetailsException([ |
| 33 | "status" => BAD_REQUEST, |
| 34 | "type" => "/errors/datosincorrectos.html", |
| 35 | "title" => "Datos incorrectos.", |
| 36 | "detail" => "El san y/o el sen proporcionados son incorrectos.", |
| 37 | ]); |
| 38 | |
| 39 | $_SESSION[SAN] = $san; |
| 40 | $_SESSION[USU_ID] = $usuario[USU_ID]; |
| 41 | |
| 42 | devuelveJson([ |
| 43 | SAN => $san, |
| 44 | ROL_IDS => rolIdsParaUsuId($bd, $usuario[USU_ID]) |
| 45 | ]); |
| 46 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/../libservidorphp/devuelveNoContent.php"; |
| 5 | require_once __DIR__ . "/SAN.php"; |
| 6 | require_once __DIR__ . "/ROL_IDS.php"; |
| 7 | |
| 8 | session_start(); |
| 9 | |
| 10 | if (isset($_SESSION[SAN])) { |
| 11 | unset($_SESSION[SAN]); |
| 12 | } |
| 13 | if (isset($_SESSION[ROL_IDS])) { |
| 14 | unset($_SESSION[ROL_IDS]); |
| 15 | } |
| 16 | |
| 17 | session_destroy(); |
| 18 | |
| 19 | devuelveNoContent(); |
| 20 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/NO_AUTORIZADO.php"; |
| 4 | require_once __DIR__ . "/../libservidorphp/PROHIBIDO.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/ProblemDetailsException.php"; |
| 6 | require_once __DIR__ . "/../libservidorphp/rolIdsParaUsuId.php"; |
| 7 | require_once __DIR__ . "/SAN.php"; |
| 8 | require_once __DIR__ . "/USU_ID.php"; |
| 9 | require_once __DIR__ . "/Bd.php"; |
| 10 | |
| 11 | function protege(array $rolIdsPermitidos) |
| 12 | { |
| 13 | |
| 14 | session_start(); |
| 15 | |
| 16 | $san = isset($_SESSION[SAN]) ? $_SESSION[SAN] : ""; |
| 17 | $usuId = isset($_SESSION[USU_ID]) ? $_SESSION[USU_ID] : -1; |
| 18 | $rolIds = rolIdsParaUsuId(Bd::pdo(), $usuId); |
| 19 | |
| 20 | if (count($rolIdsPermitidos) === 0) { |
| 21 | |
| 22 | return [$san, $rolIds, $usuId]; |
| 23 | } else { |
| 24 | |
| 25 | if ($san === "") |
| 26 | throw new ProblemDetailsException([ |
| 27 | "status" => NO_AUTORIZADO, |
| 28 | "type" => "/errors/noautorizado.html", |
| 29 | "title" => "No autorizado.", |
| 30 | "detail" => "Necesitas iniciar sesión.", |
| 31 | ]); |
| 32 | |
| 33 | foreach ($rolIdsPermitidos as $rolId) { |
| 34 | if (array_search($rolId, $rolIds, true) !== false) { |
| 35 | return [$san, $rolIds, $usuId]; |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | throw new ProblemDetailsException([ |
| 40 | "status" => PROHIBIDO, |
| 41 | "type" => "/errors/prohibido.html", |
| 42 | "title" => "Prohibido.", |
| 43 | "detail" => "No tienes roles para usar este recurso.", |
| 44 | ]); |
| 45 | } |
| 46 | } |
| 47 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/PROHIBIDO.php"; |
| 4 | require_once __DIR__ . "/../libservidorphp/ProblemDetailsException.php"; |
| 5 | require_once __DIR__ . "/protege.php"; |
| 6 | |
| 7 | function protegeLogin(array $rolIdsPermitidos) |
| 8 | { |
| 9 | |
| 10 | list($san, $rolIds, $usuId) = protege($rolIdsPermitidos); |
| 11 | |
| 12 | if ($san !== "") |
| 13 | throw new ProblemDetailsException([ |
| 14 | "status" => PROHIBIDO, |
| 15 | "type" => "/errors/sesioniniciada.html", |
| 16 | "title" => "Sesión iniciada.", |
| 17 | "detail" => "La sesión ya está iniciada.", |
| 18 | ]); |
| 19 | |
| 20 | return [$san, $rolIds, $usuId]; |
| 21 | } |
| 22 |
| 1 | <?php |
| 2 | |
| 3 | const ROL_IDS = "rolIds"; |
| 1 | <?php |
| 2 | |
| 3 | const ROL_ID_ADMINISTRADOR = "Administrador"; |
| 4 |
| 1 | <?php |
| 2 | |
| 3 | const ROL_ID_CLIENTE = "Cliente"; |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 5 | require_once __DIR__ . "/ROL_ID_CLIENTE.php"; |
| 6 | require_once __DIR__ . "/protege.php"; |
| 7 | |
| 8 | list($san) = protege([ROL_ID_CLIENTE]); |
| 9 | |
| 10 | devuelveJson("Hola $san."); |
| 11 |
| 1 | <?php |
| 2 | |
| 3 | const SAN = "san"; |
| 1 | <?php |
| 2 | |
| 3 | function usuarioBuscaSan(\PDO $bd, string $san) |
| 4 | { |
| 5 | $usuarioBusca = $bd->prepare("SELECT * FROM USUARIO WHERE USU_SAN = :USU_SAN"); |
| 6 | $usuarioBusca->execute([":USU_SAN" => $san]); |
| 7 | $usuario = $usuarioBusca->fetch(PDO::FETCH_ASSOC); |
| 8 | return $usuario; |
| 9 | } |
| 10 |
| 1 | <?php |
| 2 | |
| 3 | const USU_ID = "USU_ID"; |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/protege.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 6 | require_once __DIR__ . "/ROL_ID_ADMINISTRADOR.php"; |
| 7 | require_once __DIR__ . "/jsonMiNav.php"; |
| 8 | |
| 9 | list($san, $rolIds) = protege([ROL_ID_ADMINISTRADOR]); |
| 10 | devuelveJson([ |
| 11 | ...jsonMiNav($san, $rolIds), |
| 12 | "main" => ["hidden" => false], |
| 13 | ]); |
| 14 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/protege.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 6 | require_once __DIR__ . "/ROL_ID_CLIENTE.php"; |
| 7 | require_once __DIR__ . "/jsonMiNav.php"; |
| 8 | |
| 9 | list($san, $rolIds) = protege([ROL_ID_CLIENTE]); |
| 10 | |
| 11 | devuelveJson([ |
| 12 | ...jsonMiNav($san, $rolIds), |
| 13 | "main" => ["hidden" => false], |
| 14 | ]); |
| 15 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/protege.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 6 | require_once __DIR__ . "/jsonMiNav.php"; |
| 7 | |
| 8 | list($san, $rolIds) = protege([]); |
| 9 | |
| 10 | devuelveJson(jsonMiNav($san, $rolIds)); |
| 11 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 5 | require_once __DIR__ . "/protegeLogin.php"; |
| 6 | |
| 7 | protegeLogin([]); |
| 8 | |
| 9 | devuelveJson([ |
| 10 | "ocupado" => ["hidden" => true], |
| 11 | "formulario" => ["hidden" => false], |
| 12 | ]); |
| 13 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/../libservidorphp/manejaErrores.php"; |
| 4 | require_once __DIR__ . "/protege.php"; |
| 5 | require_once __DIR__ . "/../libservidorphp/devuelveJson.php"; |
| 6 | require_once __DIR__ . "/jsonMiNav.php"; |
| 7 | |
| 8 | list($san, $rolIds) = protege([]); |
| 9 | |
| 10 | if ($san === "") { |
| 11 | devuelveJson([ |
| 12 | ...jsonMiNav($san, $rolIds), |
| 13 | "login" => ["hidden" => false], |
| 14 | "outputSan" => ["value" => "No has iniciado sesión."], |
| 15 | "outputRoles" => ["value" => ""], |
| 16 | ]); |
| 17 | } else { |
| 18 | devuelveJson([ |
| 19 | ...jsonMiNav($san, $rolIds), |
| 20 | "botonLogout" => ["hidden" => false], |
| 21 | "outputSan" => ["value" => $san], |
| 22 | "outputRoles" => [ |
| 23 | "value" => count($rolIds) === 0 |
| 24 | ? "Sin roles." |
| 25 | : implode(", ", $rolIds), |
| 26 | ], |
| 27 | ]); |
| 28 | } |
| 29 |
| 1 | html { |
| 2 | color-scheme: light dark; |
| 3 | font-family: system-ui; |
| 4 | display: flex; |
| 5 | align-items: center; |
| 6 | justify-content: center; |
| 7 | overflow: auto; |
| 8 | } |
| 9 | |
| 10 | mi-nav nav ul { |
| 11 | display: flex; |
| 12 | flex-wrap: wrap; |
| 13 | padding: 0; |
| 14 | gap: 0.5em; |
| 15 | list-style-type: none |
| 16 | } |
| 1 | import { consume } from "../libclienteweb/consume.js" |
| 2 | import { descargaVista } from "../libclienteweb/descargaVista.js" |
| 3 | import { recibeJson } from "../libclienteweb/recibeJson.js" |
| 4 | |
| 5 | descargaDatos() |
| 6 | |
| 7 | async function descargaDatos() { |
| 8 | await descargaVista("api/vista-administrador.php") |
| 9 | const botonSaludo = document.querySelector("#botonSaludo") |
| 10 | if (botonSaludo) { |
| 11 | botonSaludo.addEventListener("click", saludo) |
| 12 | } |
| 13 | } |
| 14 | |
| 15 | async function saludo() { |
| 16 | const respuesta = await consume(recibeJson('api/saludo-cliente.php')) |
| 17 | const json = await respuesta.json() |
| 18 | alert(json) |
| 19 | } |
| 20 |
| 1 | import { consume } from "../libclienteweb/consume.js" |
| 2 | import { descargaVista } from "../libclienteweb/descargaVista.js" |
| 3 | import { recibeJson } from "../libclienteweb/recibeJson.js" |
| 4 | |
| 5 | descargaDatos() |
| 6 | |
| 7 | async function descargaDatos() { |
| 8 | await descargaVista("api/vista-cliente.php") |
| 9 | const botonSaludo = document.querySelector("#botonSaludo") |
| 10 | if (botonSaludo) { |
| 11 | botonSaludo.addEventListener("click", saludo) |
| 12 | } |
| 13 | } |
| 14 | |
| 15 | async function saludo() { |
| 16 | const respuesta = await consume(recibeJson('api/saludo-cliente.php')) |
| 17 | const json = await respuesta.json() |
| 18 | alert(json) |
| 19 | } |
| 20 |
| 1 | import { descargaVista } from "../libclienteweb/descargaVista.js" |
| 2 | |
| 3 | descargaVista("api/vista-index.php") |
| 1 | import { |
| 2 | configuraSubmitAccion |
| 3 | } from "../libclienteweb/configuraSubmitAccion.js" |
| 4 | import { descargaVista } from "../libclienteweb/descargaVista.js" |
| 5 | |
| 6 | descargaDatos() |
| 7 | |
| 8 | async function descargaDatos() { |
| 9 | await descargaVista("api/vista-login.php") |
| 10 | const formulario = document.querySelector("form") |
| 11 | if (formulario) { |
| 12 | configuraSubmitAccion("api/login.php", formulario, "perfil.html") |
| 13 | } |
| 14 | } |
| 1 | import { consume } from "../libclienteweb/consume.js" |
| 2 | import { descargaVista } from "../libclienteweb/descargaVista.js" |
| 3 | import { recibeJson } from "../libclienteweb/recibeJson.js" |
| 4 | |
| 5 | descargaDatos() |
| 6 | |
| 7 | async function descargaDatos() { |
| 8 | await descargaVista("api/vista-perfil.php") |
| 9 | const botonLogout = document.querySelector("#botonLogout") |
| 10 | if (botonLogout) { |
| 11 | botonLogout.addEventListener("click", logout) |
| 12 | } |
| 13 | } |
| 14 | |
| 15 | async function logout() { |
| 16 | await consume(recibeJson('api/logout.php')) |
| 17 | location.reload() |
| 18 | } |
| 1 | export class MiNav extends HTMLElement { |
| 2 | |
| 3 | constructor() { |
| 4 | super() |
| 5 | this.cargado = false |
| 6 | } |
| 7 | |
| 8 | connectedCallback() { |
| 9 | |
| 10 | this.style.display = "block" |
| 11 | |
| 12 | if (this.cargado === false) { |
| 13 | this.innerHTML = /* html */ |
| 14 | `<nav> |
| 15 | <ul> |
| 16 | <li><a href="index.html">Inicio</a></li> |
| 17 | <li id="ocupado"><progress max="100">Cargando…</progress></li> |
| 18 | <li id="aAdmin" hidden> |
| 19 | <a href="administrador.html">Para administradores</a> |
| 20 | </li> |
| 21 | <li id="aCliente" hidden><a href="cliente.html">Para clientes</a></li> |
| 22 | <li id="san" hidden></li> |
| 23 | <li id="aPerfil"><a href="perfil.html">Perfil</a></li> |
| 24 | </ul> |
| 25 | </nav>` |
| 26 | |
| 27 | this.cargado = true |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | } |
| 32 | |
| 33 | customElements.define("mi-nav", MiNav) |
| 1 | import { consume } from "./consume.js" |
| 2 | import { submitFormRecibeJson } from "./submitFormRecibeJson.js" |
| 3 | |
| 4 | /** |
| 5 | * @param {string} url |
| 6 | * @param {HTMLFormElement} formulario |
| 7 | * @param {string} nuevaVista |
| 8 | */ |
| 9 | export function configuraSubmitAccion(url, formulario, nuevaVista) { |
| 10 | formulario.addEventListener( |
| 11 | "submit", |
| 12 | async event => { |
| 13 | event.preventDefault() |
| 14 | await consume(submitFormRecibeJson(url, formulario)) |
| 15 | location.href = nuevaVista |
| 16 | } |
| 17 | ) |
| 18 | } |
| 1 | import { ProblemDetailsError } from "./ProblemDetailsError.js" |
| 2 | |
| 3 | /** |
| 4 | * Espera a que la promesa de un fetch termine. Si |
| 5 | * hay error, lanza una excepción. |
| 6 | * |
| 7 | * @param {Promise<Response> } servicio |
| 8 | */ |
| 9 | export async function consume(servicio) { |
| 10 | const respuesta = await servicio |
| 11 | if (respuesta.ok) { |
| 12 | return respuesta |
| 13 | } else { |
| 14 | const contentType = respuesta.headers.get("Content-Type") |
| 15 | if ( |
| 16 | contentType !== null && contentType.startsWith("application/problem+json") |
| 17 | ) |
| 18 | throw new ProblemDetailsError(await respuesta.json()) |
| 19 | else |
| 20 | throw new Error(respuesta.statusText) |
| 21 | } |
| 22 | } |
| 1 | import { consume } from "./consume.js" |
| 2 | import { muestraObjeto } from "./muestraObjeto.js" |
| 3 | import { recibeJson } from "./recibeJson.js" |
| 4 | |
| 5 | /** |
| 6 | * @param {string} url |
| 7 | * @param { "GET" | "POST"| "PUT" | "PATCH" | "DELETE" | "TRACE" | "OPTIONS" |
| 8 | * | "CONNECT" | "HEAD" } metodoHttp |
| 9 | */ |
| 10 | export async function descargaVista(url, metodoHttp = "GET") { |
| 11 | const respuesta = await consume(recibeJson(url, metodoHttp)) |
| 12 | const json = await respuesta.json() |
| 13 | muestraObjeto(document, json) |
| 14 | return json |
| 15 | } |
| 1 | import { muestraError } from "./muestraError.js" |
| 2 | |
| 3 | /** |
| 4 | * Intercepta Response.prototype.json para capturar errores de parseo |
| 5 | * y asegurar que se reporten correctamente en navegadores Chromium. |
| 6 | */ |
| 7 | { |
| 8 | const originalJson = Response.prototype.json |
| 9 | |
| 10 | Response.prototype.json = function () { |
| 11 | // Llamamos al método original usando el contexto (this) de la respuesta |
| 12 | return originalJson.call(this) |
| 13 | .catch((/** @type {any} */ error) => { |
| 14 | // Corrige un error de Chrome que evita el manejo correcto de errores. |
| 15 | throw new Error(error) |
| 16 | }) |
| 17 | } |
| 18 | } |
| 19 | |
| 20 | window.onerror = function ( |
| 21 | /** @type {Event | string} */ _event, |
| 22 | /** @type {string | undefined} */ _fuente, |
| 23 | /** @type {number | undefined} */ _numeroDeLinea, |
| 24 | /** @type {number | undefined} */ _numeroDeColumna, |
| 25 | /** @type {Error | undefined} */ error |
| 26 | ) { |
| 27 | muestraError(error) |
| 28 | return true |
| 29 | } |
| 30 | |
| 31 | window.addEventListener('unhandledrejection', event => { |
| 32 | muestraError(event.reason) |
| 33 | event.preventDefault() |
| 34 | }) |
| 1 | import { ProblemDetailsError } from "./ProblemDetailsError.js" |
| 2 | |
| 3 | /** |
| 4 | * Muestra los datos de una Error en la consola y en un cuadro de alerta. |
| 5 | * @param { unknown } error descripción del error. |
| 6 | */ |
| 7 | export function muestraError(error) { |
| 8 | |
| 9 | if (error instanceof ProblemDetailsError) { |
| 10 | |
| 11 | const problemDetails = error.problemDetails |
| 12 | |
| 13 | let mensaje = |
| 14 | typeof problemDetails["title"] === "string" ? problemDetails["title"] : "" |
| 15 | if (typeof problemDetails["detail"] === "string") { |
| 16 | if (mensaje !== "") { |
| 17 | mensaje += "\n" |
| 18 | } |
| 19 | mensaje += problemDetails["detail"] |
| 20 | } |
| 21 | if (mensaje === "") { |
| 22 | mensaje = "Error" |
| 23 | } |
| 24 | console.error(error, problemDetails) |
| 25 | alert(mensaje) |
| 26 | |
| 27 | } else if ( |
| 28 | typeof error === "object" && error !== null && "message" in error |
| 29 | ) { |
| 30 | |
| 31 | console.error(error) |
| 32 | alert(error.message) |
| 33 | |
| 34 | } else { |
| 35 | |
| 36 | console.error("Error", error) |
| 37 | alert("Error") |
| 38 | |
| 39 | } |
| 40 | |
| 41 | } |
| 1 | /** |
| 2 | * @param {Document | HTMLElement | ShadowRoot} raizHtml |
| 3 | * @param { any } objeto |
| 4 | */ |
| 5 | export function muestraObjeto(raizHtml, objeto) { |
| 6 | for (const [nombre, definiciones] of Object.entries(objeto)) { |
| 7 | if (Array.isArray(definiciones)) { |
| 8 | muestraArray(raizHtml, nombre, definiciones) |
| 9 | } else if (definiciones !== undefined && definiciones !== null) { |
| 10 | muestraElementos(raizHtml, nombre, definiciones) |
| 11 | } |
| 12 | } |
| 13 | } |
| 14 | |
| 15 | /** |
| 16 | * @param { string } nombre |
| 17 | */ |
| 18 | export function selectorDeNombre(nombre) { |
| 19 | return `[id="${ nombre }"],[name="${ nombre }"],[data-name="${ nombre }"]` |
| 20 | } |
| 21 | |
| 22 | /** |
| 23 | * @param { Document | HTMLElement | ShadowRoot } raizHtml |
| 24 | * @param { string } propiedad |
| 25 | * @param {any[]} valores |
| 26 | */ |
| 27 | function muestraArray(raizHtml, propiedad, valores) { |
| 28 | const conjunto = new Set(valores) |
| 29 | const elementos = raizHtml.querySelectorAll(selectorDeNombre(propiedad)) |
| 30 | if (elementos.length === 1 && elementos[0] instanceof HTMLSelectElement) { |
| 31 | muestraOptions(elementos[0], conjunto) |
| 32 | } else { |
| 33 | muestraInputs(elementos, conjunto) |
| 34 | } |
| 35 | |
| 36 | } |
| 37 | |
| 38 | /** |
| 39 | * @param {HTMLSelectElement} select |
| 40 | * @param {Set<any>} conjunto |
| 41 | */ |
| 42 | function muestraOptions(select, conjunto) { |
| 43 | for (let i = 0, options = select.options, len = options.length; i < len; i++) { |
| 44 | const option = options[i] |
| 45 | option.selected = conjunto.has(option.value) |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | /** |
| 50 | * @param {NodeListOf<Element>} elementos |
| 51 | * @param {Set<any>} conjunto |
| 52 | */ |
| 53 | function muestraInputs(elementos, conjunto) { |
| 54 | for (let i = 0, len = elementos.length; i < len; i++) { |
| 55 | const elemento = elementos[i] |
| 56 | if (elemento instanceof HTMLInputElement) { |
| 57 | elemento.checked = conjunto.has(elemento.value) |
| 58 | } |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | const data_ = "data-" |
| 63 | const data_Length = data_.length |
| 64 | |
| 65 | /** |
| 66 | * @param {Document | HTMLElement | ShadowRoot} raizHtml |
| 67 | * @param {string} nombre |
| 68 | * @param {{ [s: string]: any; } } definiciones |
| 69 | */ |
| 70 | function muestraElementos(raizHtml, nombre, definiciones) { |
| 71 | const elementos = raizHtml.querySelectorAll(selectorDeNombre(nombre)) |
| 72 | for (let i = 0, len = elementos.length; i < len; i++) { |
| 73 | /** |
| 74 | * @type {any} |
| 75 | */ |
| 76 | const elemento = elementos[i] |
| 77 | if (elemento !== null) { |
| 78 | for (const [propiedad, valor] of Object.entries(definiciones)) { |
| 79 | if (propiedad in elemento) { |
| 80 | if (propiedad === "innerHTML") { |
| 81 | // @ts-ignore |
| 82 | elemento["innerHTML"] = DOMPurify.sanitize(valor) |
| 83 | } else { |
| 84 | elemento[propiedad] = valor |
| 85 | } |
| 86 | } else if ( |
| 87 | propiedad.length > data_Length |
| 88 | && propiedad.startsWith(data_) |
| 89 | && elemento instanceof HTMLElement |
| 90 | ) { |
| 91 | elemento.dataset[propiedad.substring(data_Length)] = valor |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | } |
| 1 | export class ProblemDetailsError extends Error { |
| 2 | |
| 3 | /** |
| 4 | * Detalle de los errores devueltos por un servicio. |
| 5 | * Crea una instancia de ProblemDetailsError. |
| 6 | * @param {any} problemDetails Objeto con la descripcipon del error. |
| 7 | */ |
| 8 | constructor(problemDetails) { |
| 9 | |
| 10 | super( |
| 11 | typeof problemDetails["detail"] === "string" |
| 12 | ? problemDetails["detail"] |
| 13 | : ( |
| 14 | typeof problemDetails["title"] === "string" |
| 15 | ? problemDetails["title"] |
| 16 | : "Error" |
| 17 | ) |
| 18 | ) |
| 19 | |
| 20 | this.problemDetails = problemDetails |
| 21 | |
| 22 | } |
| 23 | |
| 24 | } |
| 1 | |
| 2 | /** |
| 3 | * @param {string} url |
| 4 | * @param { "GET" | "POST"| "PUT" | "PATCH" | "DELETE" | "TRACE" | "OPTIONS" |
| 5 | * | "CONNECT" | "HEAD" } metodoHttp |
| 6 | */ |
| 7 | export async function recibeJson(url, metodoHttp = "GET") { |
| 8 | return fetch( |
| 9 | url, |
| 10 | { |
| 11 | method: metodoHttp, |
| 12 | headers: { "Accept": "application/json, application/problem+json" } |
| 13 | } |
| 14 | ) |
| 15 | } |
| 1 | /** |
| 2 | * Envía los datos de un formolario a la url usando la codificación |
| 3 | * multipart/form-data. |
| 4 | * @param {string} url |
| 5 | * @param {HTMLFormElement | FormData} formulario |
| 6 | * @param { "GET" | "POST"| "PUT" | "PATCH" | "DELETE" | "TRACE" | "OPTIONS" |
| 7 | * | "CONNECT" | "HEAD" } metodoHttp |
| 8 | */ |
| 9 | export function submitFormRecibeJson(url, formulario, metodoHttp = "POST") { |
| 10 | |
| 11 | const formData = |
| 12 | formulario instanceof FormData ? formulario : new FormData(formulario) |
| 13 | |
| 14 | if (tieneArchivos(formData)) { |
| 15 | |
| 16 | return fetch( |
| 17 | url, |
| 18 | { |
| 19 | method: metodoHttp, |
| 20 | headers: { "Accept": "application/json, application/problem+json" }, |
| 21 | body: formData |
| 22 | } |
| 23 | ) |
| 24 | |
| 25 | } else { |
| 26 | |
| 27 | // @ts-ignore |
| 28 | const params = new URLSearchParams(formData) |
| 29 | const queryString = params.toString() |
| 30 | |
| 31 | return fetch( |
| 32 | url, |
| 33 | { |
| 34 | method: metodoHttp, |
| 35 | headers: { |
| 36 | 'Content-Type': 'application/x-www-form-urlencoded', |
| 37 | "Accept": "application/json, application/problem+json" |
| 38 | }, |
| 39 | body: queryString |
| 40 | } |
| 41 | ) |
| 42 | |
| 43 | } |
| 44 | |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * @param {FormData} formData |
| 49 | */ |
| 50 | function tieneArchivos(formData) { |
| 51 | for (const value of formData.values()) { |
| 52 | if (value instanceof File) { |
| 53 | return true |
| 54 | } |
| 55 | } |
| 56 | return false |
| 57 | } |
| 1 | <?php |
| 2 | |
| 3 | const BAD_REQUEST = 400; |
| 4 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/devuelveResultadoNoJson.php"; |
| 4 | |
| 5 | function devuelveJson($resultado) |
| 6 | { |
| 7 | $json = json_encode($resultado); |
| 8 | if ($json === false) { |
| 9 | devuelveResultadoNoJson(); |
| 10 | } else { |
| 11 | header("Content-Type: application/json; charset=utf-8"); |
| 12 | echo $json; |
| 13 | } |
| 14 | exit(); |
| 15 | } |
| 16 |
| 1 | <?php |
| 2 | |
| 3 | function devuelveNoContent() |
| 4 | { |
| 5 | http_response_code(204); |
| 6 | } |
| 7 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php"; |
| 4 | |
| 5 | function devuelveResultadoNoJson() |
| 6 | { |
| 7 | http_response_code(INTERNAL_SERVER_ERROR); |
| 8 | header("Content-Type: application/problem+json; charset=utf-8"); |
| 9 | |
| 10 | echo '{' . |
| 11 | "status: " . INTERNAL_SERVER_ERROR . |
| 12 | '"title": "El resultado no puede representarse como JSON."' . |
| 13 | '"type": "/errors/resultadonojson.html"' . |
| 14 | '}'; |
| 15 | } |
| 16 |
| 1 | <?php |
| 2 | |
| 3 | const INTERNAL_SERVER_ERROR = 500; |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php"; |
| 4 | require_once __DIR__ . "/ProblemDetailsException.php"; |
| 5 | |
| 6 | // Hace que se lance una excepción automáticamente cuando se genere un error. |
| 7 | set_error_handler(function ($severity, $message, $file, $line) { |
| 8 | throw new ErrorException($message, 0, $severity, $file, $line); |
| 9 | }); |
| 10 | |
| 11 | // Código cuando una excepción no es atrapada. |
| 12 | set_exception_handler(function (Throwable $excepcion) { |
| 13 | if ($excepcion instanceof ProblemDetailsException) { |
| 14 | devuelveProblemDetails($excepcion->problemDetails); |
| 15 | } else { |
| 16 | devuelveProblemDetails([ |
| 17 | "status" => INTERNAL_SERVER_ERROR, |
| 18 | "title" => "Error interno del servidor", |
| 19 | "detail" => $excepcion->getMessage(), |
| 20 | "type" => "/errors/errorinterno.html", |
| 21 | ]); |
| 22 | } |
| 23 | exit(); |
| 24 | }); |
| 25 | |
| 26 | function devuelveProblemDetails(array $array) |
| 27 | { |
| 28 | $json = json_encode($array); |
| 29 | if ($json === false) { |
| 30 | devuelveResultadoNoJson(); |
| 31 | } else { |
| 32 | http_response_code(isset($array["status"]) ? $array["status"] : 500); |
| 33 | header("Content-Type: application/problem+json; charset=utf-8"); |
| 34 | echo $json; |
| 35 | } |
| 36 | } |
| 37 |
| 1 | <?php |
| 2 | |
| 3 | const NO_AUTORIZADO = 401; |
| 4 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/INTERNAL_SERVER_ERROR.php"; |
| 4 | |
| 5 | /** |
| 6 | * Detalle de los errores devueltos por un servicio. |
| 7 | */ |
| 8 | class ProblemDetailsException extends Exception |
| 9 | { |
| 10 | |
| 11 | public array $problemDetails; |
| 12 | |
| 13 | public function __construct( |
| 14 | array $problemDetails, |
| 15 | ) { |
| 16 | |
| 17 | parent::__construct( |
| 18 | isset($problemDetails["detail"]) |
| 19 | ? $problemDetails["detail"] |
| 20 | : (isset($problemDetails["title"]) |
| 21 | ? $problemDetails["title"] |
| 22 | : "Error"), |
| 23 | $problemDetails["status"] |
| 24 | ? $problemDetails["status"] |
| 25 | : INTERNAL_SERVER_ERROR |
| 26 | ); |
| 27 | |
| 28 | $this->problemDetails = $problemDetails; |
| 29 | } |
| 30 | } |
| 31 |
| 1 | <?php |
| 2 | |
| 3 | const PROHIBIDO = 403; |
| 4 |
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Devuelve el texto de un parámetro enviado al |
| 5 | * servidor por medio de GET, POST o cookie. |
| 6 | * |
| 7 | * Si el parámetro no se recibe, devuelve false. |
| 8 | */ |
| 9 | function recibeTexto(string $parametro): false|string |
| 10 | { |
| 11 | /* Si el parámetro está asignado en $_REQUEST, |
| 12 | * devuelve su valor; de lo contrario, devuelve false. |
| 13 | */ |
| 14 | $valor = isset($_REQUEST[$parametro]) |
| 15 | ? $_REQUEST[$parametro] |
| 16 | : false; |
| 17 | return $valor; |
| 18 | } |
| 19 |
| 1 | <?php |
| 2 | |
| 3 | require_once __DIR__ . "/BAD_REQUEST.php"; |
| 4 | require_once __DIR__ . "/recibeTexto.php"; |
| 5 | require_once __DIR__ . "/ProblemDetailsException.php"; |
| 6 | |
| 7 | function recibeTextoObligatorio(string $parametro) |
| 8 | { |
| 9 | $texto = recibeTexto($parametro); |
| 10 | |
| 11 | if ($texto === false) |
| 12 | throw new ProblemDetailsException([ |
| 13 | "status" => BAD_REQUEST, |
| 14 | "title" => "Falta el valor $parametro.", |
| 15 | "type" => "/errors/faltavalor.html", |
| 16 | "detail" => "La solicitud no tiene el valor de $parametro." |
| 17 | ]); |
| 18 | |
| 19 | $trimTexto = trim($texto); |
| 20 | |
| 21 | if ($trimTexto === "") |
| 22 | throw new ProblemDetailsException([ |
| 23 | "status" => BAD_REQUEST, |
| 24 | "title" => "Campo $parametro en blanco.", |
| 25 | "type" => "/errors/campoenblanco.html", |
| 26 | "detail" => "Pon texto en el campo $parametro." |
| 27 | ]); |
| 28 | |
| 29 | return $trimTexto; |
| 30 | } |
| 31 |
| 1 | <?php |
| 2 | |
| 3 | function rolAgrega(\PDO $bd, string $id, string $descripcion) |
| 4 | { |
| 5 | $rolAgrega = $bd->prepare( |
| 6 | "INSERT INTO ROL ( |
| 7 | ROL_ID, ROL_DESCRIPCION |
| 8 | ) VALUES ( |
| 9 | :ROL_ID, :ROL_DESCRIPCION |
| 10 | )" |
| 11 | ); |
| 12 | $rolAgrega->execute([ |
| 13 | ":ROL_ID" => $id, |
| 14 | ":ROL_DESCRIPCION" => $descripcion, |
| 15 | ]); |
| 16 | } |
| 17 |
| 1 | <?php |
| 2 | |
| 3 | function rolBusca(\PDO $bd, string $id) |
| 4 | { |
| 5 | $rolBusca = $bd->prepare("SELECT * FROM ROL WHERE ROL_ID = :ROL_ID"); |
| 6 | $rolBusca->execute([":ROL_ID" => $id]); |
| 7 | $rol = $rolBusca->fetch(PDO::FETCH_ASSOC); |
| 8 | return $rol; |
| 9 | } |
| 10 |
| 1 | <?php |
| 2 | |
| 3 | function rolIdsParaUsuId(\PDO $bd, int $usuId) |
| 4 | { |
| 5 | $stmt = $bd->prepare( |
| 6 | "SELECT ROL_ID |
| 7 | FROM USU_ROL |
| 8 | WHERE USU_ID = :USU_ID |
| 9 | ORDER BY USU_ID" |
| 10 | ); |
| 11 | $stmt->execute([":USU_ID" => $usuId]); |
| 12 | $rolIds = $stmt->fetchAll(PDO::FETCH_COLUMN, 0); |
| 13 | return $rolIds; |
| 14 | } |
| 15 |
| 1 | <?php |
| 2 | |
| 3 | function usuRolAgrega(\PDO $bd, string $usuId, array $rolIds) |
| 4 | { |
| 5 | $usuRolAgrega = $bd->prepare( |
| 6 | "INSERT INTO USU_ROL (USU_ID, ROL_ID) values (:USU_ID, :ROL_ID)" |
| 7 | ); |
| 8 | foreach ($rolIds as $rolId) { |
| 9 | $usuRolAgrega->execute([ |
| 10 | ":USU_ID" => $usuId, |
| 11 | ":ROL_ID" => $rolId, |
| 12 | ]); |
| 13 | } |
| 14 | } |
| 15 |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Campo en blanco</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>Campo en blanco</h1> |
| 16 | |
| 17 | <p>Pon texto en el campo obligatorio que está en blanco.</p> |
| 18 | |
| 19 | </body> |
| 20 | |
| 21 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Datos incorrectos</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>Datos incorrectos</h1> |
| 16 | |
| 17 | <p>El san y/o el sen proporcionados son incorrectos.</p> |
| 18 | </body> |
| 19 | |
| 20 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Error interno del servidor</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>Error interno del servidor</h1> |
| 16 | |
| 17 | <p>Se presentó de forma inesperada un error interno del servidor.</p> |
| 18 | |
| 19 | </body> |
| 20 | |
| 21 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Falta un valor</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>Falta un valor</h1> |
| 16 | |
| 17 | <p>La solicitud no tiene un valor obligatorio.</p> |
| 18 | |
| 19 | </body> |
| 20 | |
| 21 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>No autorizado</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>No autorizado</h1> |
| 16 | |
| 17 | <p>Necesitas iniciar sesión.</p> |
| 18 | |
| 19 | </body> |
| 20 | |
| 21 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Prohibido</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>Prohibido</h1> |
| 16 | |
| 17 | <p>No tienes roles para usar este recurso.</p> |
| 18 | |
| 19 | </body> |
| 20 | |
| 21 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>El resultado no puede representarse como JSON</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>El resultado no puede representarse como JSON</h1> |
| 16 | |
| 17 | <p> |
| 18 | Debido a un error interno del servidor, el resultado generado, no se puede |
| 19 | recuperar. |
| 20 | </p> |
| 21 | |
| 22 | </body> |
| 23 | |
| 24 | </html> |
| 1 | <!DOCTYPE html> |
| 2 | <html lang="es"> |
| 3 | |
| 4 | <head> |
| 5 | |
| 6 | <meta charset="UTF-8"> |
| 7 | <meta name="viewport" content="width=device-width"> |
| 8 | |
| 9 | <title>Sesión iniciada</title> |
| 10 | |
| 11 | </head> |
| 12 | |
| 13 | <body> |
| 14 | |
| 15 | <h1>Sesión iniciada</h1> |
| 16 | |
| 17 | <p>La sesión ya está iniciada.</p> |
| 18 | |
| 19 | </body> |
| 20 | |
| 21 | </html> |
Este archivo ayuda a detectar errores en los archivos del proyecto.
Lo utiliza principalmente Visual Studio Code.
No se explica aquí su estructura, pero puede encontrarse la explicación de todo en la documentación del sitio de Visual Studio Code.
| 1 |
{
|
| 2 |
"compilerOptions": {
|
| 3 |
"checkJs": true, |
| 4 |
"strictNullChecks": true, |
| 5 |
"target": "ES6", |
| 6 |
"module": "Node16", |
| 7 |
"moduleResolution": "Node16", |
| 8 |
"lib": [
|
| 9 |
"ES2017",
|
| 10 |
"WebWorker",
|
| 11 |
"DOM"
|
| 12 |
] |
| 18 |
} |
| 1 | /*! @license DOMPurify 3.4.1 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.1/LICENSE */ |
| 2 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t){for(var n=arguments.length,o=new Array(n>2?n-2:0),r=2;r<n;r++)o[r-2]=arguments[r];return e.apply(t,o)}),s||(s=function(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),o=1;o<t;o++)n[o-1]=arguments[o];return new e(...n)});const u=L(Array.prototype.forEach),m=L(Array.prototype.lastIndexOf),f=L(Array.prototype.pop),p=L(Array.prototype.push),d=L(Array.prototype.splice),h=Array.isArray,T=L(String.prototype.toLowerCase),g=L(String.prototype.toString),y=L(String.prototype.match),A=L(String.prototype.replace),E=L(String.prototype.indexOf),_=L(String.prototype.trim),S=L(Number.prototype.toString),b=L(Boolean.prototype.toString),N="undefined"==typeof BigInt?null:L(BigInt.prototype.toString),R="undefined"==typeof Symbol?null:L(Symbol.prototype.toString),D=L(Object.prototype.hasOwnProperty),O=L(Object.prototype.toString),I=L(RegExp.prototype.test),w=(C=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return s(C,t)});var C;function L(e){return function(t){t instanceof RegExp&&(t.lastIndex=0);for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r<n;r++)o[r-1]=arguments[r];return c(e,t,o)}}function k(e,o){let r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:T;if(t&&t(e,null),!h(o))return e;let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function x(e){for(let t=0;t<e.length;t++){D(e,t)||(e[t]=null)}return e}function v(t){const n=l(null);for(const[o,r]of e(t)){D(t,o)&&(h(r)?n[o]=x(r):r&&"object"==typeof r&&r.constructor===Object?n[o]=v(r):n[o]=r)}return n}function M(e,t){for(;null!==e;){const n=r(e,t);if(n){if(n.get)return L(n.get);if("function"==typeof n.value)return L(n.value)}e=o(e)}return function(){return null}}const P=i(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","search","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),U=i(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","enterkeyhint","exportparts","filter","font","g","glyph","glyphref","hkern","image","inputmode","line","lineargradient","marker","mask","metadata","mpath","part","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),z=i(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),F=i(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),H=i(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),B=i(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),G=i(["#text"]),W=i(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","exportparts","face","for","headers","height","hidden","high","href","hreflang","id","inert","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","part","pattern","placeholder","playsinline","popover","popovertarget","popovertargetaction","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","slot","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","wrap","xmlns"]),j=i(["accent-height","accumulate","additive","alignment-baseline","amplitude","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","exponent","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","intercept","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","mask-type","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","slope","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","tablevalues","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),Y=i(["accent","accentunder","align","bevelled","close","columnalign","columnlines","columnspacing","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lquote","lspace","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),X=i(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),q=a(/\{\{[\w\W]*|[\w\W]*\}\}/gm),$=a(/<%[\w\W]*|[\w\W]*%>/gm),K=a(/\$\{[\w\W]*/gm),V=a(/^data-[\-\w.\u00B7-\uFFFF]+$/),Z=a(/^aria-[\-\w]+$/),J=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Q=a(/^(?:\w+script|data):/i),ee=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),te=a(/^html$/i),ne=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var oe=Object.freeze({__proto__:null,ARIA_ATTR:Z,ATTR_WHITESPACE:ee,CUSTOM_ELEMENT:ne,DATA_ATTR:V,DOCTYPE_NAME:te,ERB_EXPR:$,IS_ALLOWED_URI:J,IS_SCRIPT_OR_DATA:Q,MUSTACHE_EXPR:q,TMPLIT_EXPR:K});const re=1,ie=3,ae=7,le=8,ce=9,se=function(){return"undefined"==typeof window?null:window};var ue=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:se();const o=e=>t(e);if(o.version="3.4.1",o.removed=[],!n||!n.document||n.document.nodeType!==ce||!n.Element)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:C,Node:L,Element:x,NodeFilter:q,NamedNodeMap:$=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:K,DOMParser:V,trustedTypes:Z}=n,Q=x.prototype,ee=M(Q,"cloneNode"),ne=M(Q,"remove"),ue=M(Q,"nextSibling"),me=M(Q,"childNodes"),fe=M(Q,"parentNode");if("function"==typeof C){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let pe,de="";const{implementation:he,createNodeIterator:Te,createDocumentFragment:ge,getElementsByTagName:ye}=r,{importNode:Ae}=a;let Ee={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]};o.isSupported="function"==typeof e&&"function"==typeof fe&&he&&void 0!==he.createHTMLDocument;const{MUSTACHE_EXPR:_e,ERB_EXPR:Se,TMPLIT_EXPR:be,DATA_ATTR:Ne,ARIA_ATTR:Re,IS_SCRIPT_OR_DATA:De,ATTR_WHITESPACE:Oe,CUSTOM_ELEMENT:Ie}=oe;let{IS_ALLOWED_URI:we}=oe,Ce=null;const Le=k({},[...P,...U,...z,...H,...G]);let ke=null;const xe=k({},[...W,...j,...Y,...X]);let ve=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Me=null,Pe=null;const Ue=Object.seal(l(null,{tagCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeCheck:{writable:!0,configurable:!1,enumerable:!0,value:null}}));let ze=!0,Fe=!0,He=!1,Be=!0,Ge=!1,We=!0,je=!1,Ye=!1,Xe=!1,qe=!1,$e=!1,Ke=!1,Ve=!0,Ze=!1;const Je="user-content-";let Qe=!0,et=!1,tt={},nt=null;const ot=k({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let rt=null;const it=k({},["audio","video","img","source","image","track"]);let at=null;const lt=k({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),ct="http://www.w3.org/1998/Math/MathML",st="http://www.w3.org/2000/svg",ut="http://www.w3.org/1999/xhtml";let mt=ut,ft=!1,pt=null;const dt=k({},[ct,st,ut],g);let ht=k({},["mi","mo","mn","ms","mtext"]),Tt=k({},["annotation-xml"]);const gt=k({},["title","style","font","a","script"]);let yt=null;const At=["application/xhtml+xml","text/html"];let Et=null,_t=null;const St=r.createElement("form"),bt=function(e){return e instanceof RegExp||e instanceof Function},Nt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(_t&&_t===e)return;e&&"object"==typeof e||(e={}),e=v(e),yt=-1===At.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,Et="application/xhtml+xml"===yt?g:T,Ce=D(e,"ALLOWED_TAGS")&&h(e.ALLOWED_TAGS)?k({},e.ALLOWED_TAGS,Et):Le,ke=D(e,"ALLOWED_ATTR")&&h(e.ALLOWED_ATTR)?k({},e.ALLOWED_ATTR,Et):xe,pt=D(e,"ALLOWED_NAMESPACES")&&h(e.ALLOWED_NAMESPACES)?k({},e.ALLOWED_NAMESPACES,g):dt,at=D(e,"ADD_URI_SAFE_ATTR")&&h(e.ADD_URI_SAFE_ATTR)?k(v(lt),e.ADD_URI_SAFE_ATTR,Et):lt,rt=D(e,"ADD_DATA_URI_TAGS")&&h(e.ADD_DATA_URI_TAGS)?k(v(it),e.ADD_DATA_URI_TAGS,Et):it,nt=D(e,"FORBID_CONTENTS")&&h(e.FORBID_CONTENTS)?k({},e.FORBID_CONTENTS,Et):ot,Me=D(e,"FORBID_TAGS")&&h(e.FORBID_TAGS)?k({},e.FORBID_TAGS,Et):v({}),Pe=D(e,"FORBID_ATTR")&&h(e.FORBID_ATTR)?k({},e.FORBID_ATTR,Et):v({}),tt=!!D(e,"USE_PROFILES")&&(e.USE_PROFILES&&"object"==typeof e.USE_PROFILES?v(e.USE_PROFILES):e.USE_PROFILES),ze=!1!==e.ALLOW_ARIA_ATTR,Fe=!1!==e.ALLOW_DATA_ATTR,He=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Be=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,Ge=e.SAFE_FOR_TEMPLATES||!1,We=!1!==e.SAFE_FOR_XML,je=e.WHOLE_DOCUMENT||!1,qe=e.RETURN_DOM||!1,$e=e.RETURN_DOM_FRAGMENT||!1,Ke=e.RETURN_TRUSTED_TYPE||!1,Xe=e.FORCE_BODY||!1,Ve=!1!==e.SANITIZE_DOM,Ze=e.SANITIZE_NAMED_PROPS||!1,Qe=!1!==e.KEEP_CONTENT,et=e.IN_PLACE||!1,we=function(e){try{return I(e,""),!0}catch(e){return!1}}(e.ALLOWED_URI_REGEXP)?e.ALLOWED_URI_REGEXP:J,mt="string"==typeof e.NAMESPACE?e.NAMESPACE:ut,ht=D(e,"MATHML_TEXT_INTEGRATION_POINTS")&&e.MATHML_TEXT_INTEGRATION_POINTS&&"object"==typeof e.MATHML_TEXT_INTEGRATION_POINTS?v(e.MATHML_TEXT_INTEGRATION_POINTS):k({},["mi","mo","mn","ms","mtext"]),Tt=D(e,"HTML_INTEGRATION_POINTS")&&e.HTML_INTEGRATION_POINTS&&"object"==typeof e.HTML_INTEGRATION_POINTS?v(e.HTML_INTEGRATION_POINTS):k({},["annotation-xml"]);const t=D(e,"CUSTOM_ELEMENT_HANDLING")&&e.CUSTOM_ELEMENT_HANDLING&&"object"==typeof e.CUSTOM_ELEMENT_HANDLING?v(e.CUSTOM_ELEMENT_HANDLING):l(null);if(ve=l(null),D(t,"tagNameCheck")&&bt(t.tagNameCheck)&&(ve.tagNameCheck=t.tagNameCheck),D(t,"attributeNameCheck")&&bt(t.attributeNameCheck)&&(ve.attributeNameCheck=t.attributeNameCheck),D(t,"allowCustomizedBuiltInElements")&&"boolean"==typeof t.allowCustomizedBuiltInElements&&(ve.allowCustomizedBuiltInElements=t.allowCustomizedBuiltInElements),Ge&&(Fe=!1),$e&&(qe=!0),tt&&(Ce=k({},G),ke=l(null),!0===tt.html&&(k(Ce,P),k(ke,W)),!0===tt.svg&&(k(Ce,U),k(ke,j),k(ke,X)),!0===tt.svgFilters&&(k(Ce,z),k(ke,j),k(ke,X)),!0===tt.mathMl&&(k(Ce,H),k(ke,Y),k(ke,X))),Ue.tagCheck=null,Ue.attributeCheck=null,D(e,"ADD_TAGS")&&("function"==typeof e.ADD_TAGS?Ue.tagCheck=e.ADD_TAGS:h(e.ADD_TAGS)&&(Ce===Le&&(Ce=v(Ce)),k(Ce,e.ADD_TAGS,Et))),D(e,"ADD_ATTR")&&("function"==typeof e.ADD_ATTR?Ue.attributeCheck=e.ADD_ATTR:h(e.ADD_ATTR)&&(ke===xe&&(ke=v(ke)),k(ke,e.ADD_ATTR,Et))),D(e,"ADD_URI_SAFE_ATTR")&&h(e.ADD_URI_SAFE_ATTR)&&k(at,e.ADD_URI_SAFE_ATTR,Et),D(e,"FORBID_CONTENTS")&&h(e.FORBID_CONTENTS)&&(nt===ot&&(nt=v(nt)),k(nt,e.FORBID_CONTENTS,Et)),D(e,"ADD_FORBID_CONTENTS")&&h(e.ADD_FORBID_CONTENTS)&&(nt===ot&&(nt=v(nt)),k(nt,e.ADD_FORBID_CONTENTS,Et)),Qe&&(Ce["#text"]=!0),je&&k(Ce,["html","head","body"]),Ce.table&&(k(Ce,["tbody"]),delete Me.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw w('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw w('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');pe=e.TRUSTED_TYPES_POLICY,de=pe.createHTML("")}else void 0===pe&&(pe=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(Z,c)),null!==pe&&"string"==typeof de&&(de=pe.createHTML(""));i&&i(e),_t=e},Rt=k({},[...U,...z,...F]),Dt=k({},[...H,...B]),Ot=function(e){p(o.removed,{element:e});try{fe(e).removeChild(e)}catch(t){ne(e)}},It=function(e,t){try{p(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e)if(qe||$e)try{Ot(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},wt=function(e){let t=null,n=null;if(Xe)e="<remove></remove>"+e;else{const t=y(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===yt&&mt===ut&&(e='<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>'+e+"</body></html>");const o=pe?pe.createHTML(e):e;if(mt===ut)try{t=(new V).parseFromString(o,yt)}catch(e){}if(!t||!t.documentElement){t=he.createDocument(mt,"template",null);try{t.documentElement.innerHTML=ft?de:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),mt===ut?ye.call(t,je?"html":"body")[0]:je?t.documentElement:i},Ct=function(e){return Te.call(e.ownerDocument||e,e,q.SHOW_ELEMENT|q.SHOW_COMMENT|q.SHOW_TEXT|q.SHOW_PROCESSING_INSTRUCTION|q.SHOW_CDATA_SECTION,null)},Lt=function(e){return e instanceof K&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof $)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},kt=function(e){return"function"==typeof L&&e instanceof L};function xt(e,t,n){u(e,e=>{e.call(o,t,n,_t)})}const vt=function(e){let t=null;if(xt(Ee.beforeSanitizeElements,e,null),Lt(e))return Ot(e),!0;const n=Et(e.nodeName);if(xt(Ee.uponSanitizeElement,e,{tagName:n,allowedTags:Ce}),We&&e.hasChildNodes()&&!kt(e.firstElementChild)&&I(/<[/\w!]/g,e.innerHTML)&&I(/<[/\w!]/g,e.textContent))return Ot(e),!0;if(We&&e.namespaceURI===ut&&"style"===n&&kt(e.firstElementChild))return Ot(e),!0;if(e.nodeType===ae)return Ot(e),!0;if(We&&e.nodeType===le&&I(/<[/\w]/g,e.data))return Ot(e),!0;if(Me[n]||!(Ue.tagCheck instanceof Function&&Ue.tagCheck(n))&&!Ce[n]){if(!Me[n]&&Ut(n)){if(ve.tagNameCheck instanceof RegExp&&I(ve.tagNameCheck,n))return!1;if(ve.tagNameCheck instanceof Function&&ve.tagNameCheck(n))return!1}if(Qe&&!nt[n]){const t=fe(e)||e.parentNode,n=me(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=ee(n[o],!0);t.insertBefore(r,ue(e))}}}return Ot(e),!0}return e instanceof x&&!function(e){let t=fe(e);t&&t.tagName||(t={namespaceURI:mt,tagName:"template"});const n=T(e.tagName),o=T(t.tagName);return!!pt[e.namespaceURI]&&(e.namespaceURI===st?t.namespaceURI===ut?"svg"===n:t.namespaceURI===ct?"svg"===n&&("annotation-xml"===o||ht[o]):Boolean(Rt[n]):e.namespaceURI===ct?t.namespaceURI===ut?"math"===n:t.namespaceURI===st?"math"===n&&Tt[o]:Boolean(Dt[n]):e.namespaceURI===ut?!(t.namespaceURI===st&&!Tt[o])&&!(t.namespaceURI===ct&&!ht[o])&&!Dt[n]&&(gt[n]||!Rt[n]):!("application/xhtml+xml"!==yt||!pt[e.namespaceURI]))}(e)?(Ot(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!I(/<\/no(script|embed|frames)/i,e.innerHTML)?(Ge&&e.nodeType===ie&&(t=e.textContent,u([_e,Se,be],e=>{t=A(t,e," ")}),e.textContent!==t&&(p(o.removed,{element:e.cloneNode()}),e.textContent=t)),xt(Ee.afterSanitizeElements,e,null),!1):(Ot(e),!0)},Mt=function(e,t,n){if(Pe[t])return!1;if(Ve&&("id"===t||"name"===t)&&(n in r||n in St))return!1;if(Fe&&!Pe[t]&&I(Ne,t));else if(ze&&I(Re,t));else if(Ue.attributeCheck instanceof Function&&Ue.attributeCheck(t,e));else if(!ke[t]||Pe[t]){if(!(Ut(e)&&(ve.tagNameCheck instanceof RegExp&&I(ve.tagNameCheck,e)||ve.tagNameCheck instanceof Function&&ve.tagNameCheck(e))&&(ve.attributeNameCheck instanceof RegExp&&I(ve.attributeNameCheck,t)||ve.attributeNameCheck instanceof Function&&ve.attributeNameCheck(t,e))||"is"===t&&ve.allowCustomizedBuiltInElements&&(ve.tagNameCheck instanceof RegExp&&I(ve.tagNameCheck,n)||ve.tagNameCheck instanceof Function&&ve.tagNameCheck(n))))return!1}else if(at[t]);else if(I(we,A(n,Oe,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==E(n,"data:")||!rt[e]){if(He&&!I(De,A(n,Oe,"")));else if(n)return!1}else;return!0},Pt=k({},["annotation-xml","color-profile","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","missing-glyph"]),Ut=function(e){return!Pt[T(e)]&&I(Ie,e)},zt=function(e){xt(Ee.beforeSanitizeAttributes,e,null);const{attributes:t}=e;if(!t||Lt(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:ke,forceKeepAttr:void 0};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=Et(a),m=c;let p="value"===a?m:_(m);if(n.attrName=s,n.attrValue=p,n.keepAttr=!0,n.forceKeepAttr=void 0,xt(Ee.uponSanitizeAttribute,e,n),p=n.attrValue,!Ze||"id"!==s&&"name"!==s||0===E(p,Je)||(It(a,e),p=Je+p),We&&I(/((--!?|])>)|<\/(style|script|title|xmp|textarea|noscript|iframe|noembed|noframes)/i,p)){It(a,e);continue}if("attributename"===s&&y(p,"href")){It(a,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){It(a,e);continue}if(!Be&&I(/\/>/i,p)){It(a,e);continue}Ge&&u([_e,Se,be],e=>{p=A(p,e," ")});const d=Et(e.nodeName);if(Mt(d,s,p)){if(pe&&"object"==typeof Z&&"function"==typeof Z.getAttributeType)if(l);else switch(Z.getAttributeType(d,s)){case"TrustedHTML":p=pe.createHTML(p);break;case"TrustedScriptURL":p=pe.createScriptURL(p)}if(p!==m)try{l?e.setAttributeNS(l,a,p):e.setAttribute(a,p),Lt(e)?Ot(e):f(o.removed)}catch(t){It(a,e)}}else It(a,e)}xt(Ee.afterSanitizeAttributes,e,null)},Ft=function(e){let t=null;const n=Ct(e);for(xt(Ee.beforeSanitizeShadowDOM,e,null);t=n.nextNode();)xt(Ee.uponSanitizeShadowNode,t,null),vt(t),zt(t),t.content instanceof s&&Ft(t.content);xt(Ee.afterSanitizeShadowDOM,e,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(ft=!e,ft&&(e="\x3c!--\x3e"),"string"!=typeof e&&!kt(e)&&"string"!=typeof(e=function(e){switch(typeof e){case"string":return e;case"number":return S(e);case"boolean":return b(e);case"bigint":return N?N(e):"0";case"symbol":return R?R(e):"Symbol()";case"undefined":default:return O(e);case"function":case"object":{if(null===e)return O(e);const t=e,n=M(t,"toString");if("function"==typeof n){const e=n(t);return"string"==typeof e?e:O(e)}return O(e)}}}(e)))throw w("dirty is not a string, aborting");if(!o.isSupported)return e;if(Ye||Nt(t),o.removed=[],"string"==typeof e&&(et=!1),et){const t=e.nodeName;if("string"==typeof t){const e=Et(t);if(!Ce[e]||Me[e])throw w("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof L)n=wt("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===re&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!qe&&!Ge&&!je&&-1===e.indexOf("<"))return pe&&Ke?pe.createHTML(e):e;if(n=wt(e),!n)return qe?null:Ke?de:""}n&&Xe&&Ot(n.firstChild);const c=Ct(et?e:n);for(;i=c.nextNode();)vt(i),zt(i),i.content instanceof s&&Ft(i.content);if(et)return e;if(qe){if(Ge){n.normalize();let e=n.innerHTML;u([_e,Se,be],t=>{e=A(e,t," ")}),n.innerHTML=e}if($e)for(l=ge.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(ke.shadowroot||ke.shadowrootmode)&&(l=Ae.call(a,l,!0)),l}let m=je?n.outerHTML:n.innerHTML;return je&&Ce["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&I(te,n.ownerDocument.doctype.name)&&(m="<!DOCTYPE "+n.ownerDocument.doctype.name+">\n"+m),Ge&&u([_e,Se,be],e=>{m=A(m,e," ")}),pe&&Ke?pe.createHTML(m):m},o.setConfig=function(){Nt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Ye=!0},o.clearConfig=function(){_t=null,Ye=!1},o.isValidAttribute=function(e,t,n){_t||Nt({});const o=Et(e),r=Et(t);return Mt(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&p(Ee[e],t)},o.removeHook=function(e,t){if(void 0!==t){const n=m(Ee[e],t);return-1===n?void 0:d(Ee[e],n,1)[0]}return f(Ee[e])},o.removeHooks=function(e){Ee[e]=[]},o.removeAllHooks=function(){Ee={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},o}();return ue}); |
| 3 | //# sourceMappingURL=purify.min.js.map |
| 4 |
| 1 | {"version":3,"file":"purify.min.js","sources":["../src/utils.ts","../src/tags.ts","../src/attrs.ts","../src/regexp.ts","../src/purify.ts"],"sourcesContent":[null,null,null,null,null],"names":["entries","setPrototypeOf","isFrozen","getPrototypeOf","getOwnPropertyDescriptor","Object","freeze","seal","create","apply","construct","Reflect","x","func","thisArg","_len","arguments","length","args","Array","_key","Func","_len2","_key2","arrayForEach","unapply","prototype","forEach","arrayLastIndexOf","lastIndexOf","arrayPop","pop","arrayPush","push","arraySplice","splice","arrayIsArray","isArray","stringToLowerCase","String","toLowerCase","stringToString","toString","stringMatch","match","stringReplace","replace","stringIndexOf","indexOf","stringTrim","trim","numberToString","Number","booleanToString","Boolean","bigintToString","BigInt","symbolToString","Symbol","objectHasOwnProperty","hasOwnProperty","objectToString","regExpTest","RegExp","test","typeErrorCreate","TypeError","_len4","_key4","lastIndex","_len3","_key3","addToSet","set","array","transformCaseFunc","l","element","lcElement","cleanArray","index","clone","object","newObject","property","value","constructor","lookupGetter","prop","desc","get","html","svg","svgFilters","svgDisallowed","mathMl","mathMlDisallowed","text","xml","MUSTACHE_EXPR","ERB_EXPR","TMPLIT_EXPR","DATA_ATTR","ARIA_ATTR","IS_ALLOWED_URI","IS_SCRIPT_OR_DATA","ATTR_WHITESPACE","DOCTYPE_NAME","CUSTOM_ELEMENT","NODE_TYPE","getGlobal","window","purify","createDOMPurify","undefined","DOMPurify","root","version","VERSION","removed","document","nodeType","Element","isSupported","originalDocument","currentScript","DocumentFragment","HTMLTemplateElement","Node","NodeFilter","NamedNodeMap","MozNamedAttrMap","HTMLFormElement","DOMParser","trustedTypes","ElementPrototype","cloneNode","remove","getNextSibling","getChildNodes","getParentNode","template","createElement","content","ownerDocument","trustedTypesPolicy","emptyHTML","implementation","createNodeIterator","createDocumentFragment","getElementsByTagName","importNode","hooks","afterSanitizeAttributes","afterSanitizeElements","afterSanitizeShadowDOM","beforeSanitizeAttributes","beforeSanitizeElements","beforeSanitizeShadowDOM","uponSanitizeAttribute","uponSanitizeElement","uponSanitizeShadowNode","createHTMLDocument","EXPRESSIONS","ALLOWED_TAGS","DEFAULT_ALLOWED_TAGS","TAGS","ALLOWED_ATTR","DEFAULT_ALLOWED_ATTR","ATTRS","CUSTOM_ELEMENT_HANDLING","tagNameCheck","writable","configurable","enumerable","attributeNameCheck","allowCustomizedBuiltInElements","FORBID_TAGS","FORBID_ATTR","EXTRA_ELEMENT_HANDLING","tagCheck","attributeCheck","ALLOW_ARIA_ATTR","ALLOW_DATA_ATTR","ALLOW_UNKNOWN_PROTOCOLS","ALLOW_SELF_CLOSE_IN_ATTR","SAFE_FOR_TEMPLATES","SAFE_FOR_XML","WHOLE_DOCUMENT","SET_CONFIG","FORCE_BODY","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","SANITIZE_DOM","SANITIZE_NAMED_PROPS","SANITIZE_NAMED_PROPS_PREFIX","KEEP_CONTENT","IN_PLACE","USE_PROFILES","FORBID_CONTENTS","DEFAULT_FORBID_CONTENTS","DATA_URI_TAGS","DEFAULT_DATA_URI_TAGS","URI_SAFE_ATTRIBUTES","DEFAULT_URI_SAFE_ATTRIBUTES","MATHML_NAMESPACE","SVG_NAMESPACE","HTML_NAMESPACE","NAMESPACE","IS_EMPTY_INPUT","ALLOWED_NAMESPACES","DEFAULT_ALLOWED_NAMESPACES","MATHML_TEXT_INTEGRATION_POINTS","HTML_INTEGRATION_POINTS","COMMON_SVG_AND_HTML_ELEMENTS","PARSER_MEDIA_TYPE","SUPPORTED_PARSER_MEDIA_TYPES","CONFIG","formElement","isRegexOrFunction","testValue","Function","_parseConfig","cfg","ADD_URI_SAFE_ATTR","ADD_DATA_URI_TAGS","_unused","isRegex","ALLOWED_URI_REGEXP","customElementHandling","ADD_TAGS","ADD_ATTR","ADD_FORBID_CONTENTS","table","tbody","TRUSTED_TYPES_POLICY","createHTML","createScriptURL","purifyHostElement","createPolicy","suffix","ATTR_NAME","hasAttribute","getAttribute","policyName","scriptUrl","_","console","warn","_createTrustedTypesPolicy","ALL_SVG_TAGS","ALL_MATHML_TAGS","_forceRemove","node","removeChild","_removeAttribute","name","attribute","getAttributeNode","from","removeAttribute","setAttribute","_initDocument","dirty","doc","leadingWhitespace","matches","dirtyPayload","parseFromString","documentElement","createDocument","innerHTML","body","insertBefore","createTextNode","childNodes","call","_createNodeIterator","SHOW_ELEMENT","SHOW_COMMENT","SHOW_TEXT","SHOW_PROCESSING_INSTRUCTION","SHOW_CDATA_SECTION","_isClobbered","nodeName","textContent","attributes","namespaceURI","hasChildNodes","_isNode","_executeHooks","currentNode","data","hook","_sanitizeElements","tagName","allowedTags","firstElementChild","_isBasicCustomElement","parentNode","i","childClone","parent","parentTagName","_checkValidNamespace","expr","_isValidAttribute","lcTag","lcName","RESERVED_CUSTOM_ELEMENT_NAMES","_sanitizeAttributes","hookEvent","attrName","attrValue","keepAttr","allowedAttributes","forceKeepAttr","attr","initValue","getAttributeType","setAttributeNS","_sanitizeShadowDOM","fragment","shadowNode","shadowIterator","nextNode","sanitize","importedNode","returnNode","valueAsRecord","valueToString","stringified","stringifyValue","nn","appendChild","firstChild","nodeIterator","normalize","shadowroot","shadowrootmode","serializedHTML","outerHTML","doctype","setConfig","clearConfig","isValidAttribute","tag","addHook","entryPoint","hookFunction","removeHook","removeHooks","removeAllHooks"],"mappings":"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PL,EACAM,GAEA,KAAkB,OAAXN,GAAiB,CACtB,MAAMO,EAAOrF,EAAyB8E,EAAQM,GAE9C,GAAIC,EAAM,CACR,GAAIA,EAAKC,IACP,OAAOjE,EAAQgE,EAAKC,KAGtB,GAA0B,mBAAfD,EAAKJ,MACd,OAAO5D,EAAQgE,EAAKJ,MAExB,CAEAH,EAAS/E,EAAe+E,EAC1B,CAMA,OAJA,WACE,OAAO,IACT,CAGF,CC1RO,MAAMS,EAAOrF,EAAO,CACzB,IACA,OACA,UACA,UACA,OACA,UACA,QACA,QACA,IACA,MACA,MACA,MACA,QACA,aACA,OACA,KACA,SACA,SACA,UACA,SACA,OACA,OACA,MACA,WACA,UACA,OACA,WACA,KACA,YACA,MACA,UACA,MACA,SACA,MACA,MACA,KACA,KACA,UACA,KACA,WACA,aACA,SACA,OACA,SACA,OACA,KACA,KACA,KACA,KACA,KACA,KACA,OACA,SACA,SACA,KACA,OACA,IACA,MACA,QACA,MACA,MACA,QACA,SACA,KACA,OACA,MACA,OACA,UACA,OACA,WACA,QACA,MACA,OACA,KACA,WACA,SACA,SACA,IACA,UACA,MACA,WACA,IACA,KACA,KACA,OACA,IACA,OACA,SACA,UACA,SACA,SACA,OACA,QACA,SACA,SACA,OACA,SACA,SACA,QACA,MACA,UACA,MACA,QACA,QACA,KACA,WACA,WACA,QACA,KACA,QACA,OACA,KACA,QACA,KACA,IACA,KACA,MACA,QACA,QAGWsF,EAAMtF,EAAO,CACxB,MACA,IACA,WACA,cACA,eACA,eACA,gBACA,mBACA,SACA,WACA,OACA,OACA,UACA,eACA,cACA,SACA,OACA,IACA,QACA,WACA,QACA,QACA,YACA,OACA,iBACA,SACA,OACA,WACA,QACA,OACA,OACA,UACA,UACA,WACA,iBACA,OACA,OACA,QACA,SACA,SACA,OACA,WACA,QACA,OACA,QACA,OACA,UAGWuF,EAAavF,EAAO,CAC/B,UACA,gBACA,sBACA,cACA,mBACA,oBACA,oBACA,iBACA,eACA,UACA,UACA,UACA,UACA,UACA,iBACA,UACA,UACA,cACA,eACA,WACA,eACA,qBACA,cACA,SACA,iBAOWwF,EAAgBxF,EAAO,CAClC,UACA,gBACA,SACA,UACA,YACA,mBACA,iBACA,gBACA,gBACA,gBACA,QACA,YACA,OACA,eACA,YACA,UACA,gBACA,SACA,MACA,aACA,UACA,QAGWyF,EAASzF,EAAO,CAC3B,OACA,WACA,SACA,UACA,QACA,SACA,KACA,aACA,gBACA,KACA,KACA,QACA,UACA,WACA,QACA,OACA,KACA,SACA,QACA,SACA,OACA,OACA,UACA,SACA,MACA,QACA,MACA,SACA,aACA,gBAKW0F,EAAmB1F,EAAO,CACrC,UACA,cACA,aACA,WACA,YACA,UACA,UACA,SACA,SACA,QACA,YACA,aACA,iBACA,cACA,SAGW2F,EAAO3F,EAAO,CAAC,UC1RfqF,EAAOrF,EAAO,CACzB,SACA,SACA,QACA,MACA,iBACA,eACA,uBACA,WACA,aACA,UACA,SACA,UACA,cACA,cACA,UACA,OACA,QACA,QACA,QACA,OACA,UACA,WACA,eACA,SACA,cACA,WACA,WACA,UACA,MACA,WACA,0BACA,wBACA,WACA,YACA,UACA,eACA,cACA,OACA,MACA,UACA,SACA,SACA,OACA,OACA,WACA,KACA,QACA,YACA,YACA,QACA,OACA,QACA,OACA,OACA,UACA,OACA,MACA,MACA,YACA,QACA,SACA,MACA,YACA,WACA,QACA,OACA,QACA,UACA,aACA,SACA,OACA,UACA,OACA,UACA,cACA,cACA,UACA,gBACA,sBACA,SACA,UACA,UACA,aACA,WACA,MACA,WACA,MACA,WACA,OACA,OACA,UACA,aACA,QACA,WACA,QACA,OACA,QACA,OACA,OACA,UACA,QACA,MACA,SACA,OACA,QACA,UACA,WACA,QACA,YACA,OACA,SACA,SACA,QACA,QACA,OACA,UAGWsF,EAAMtF,EAAO,CACxB,gBACA,aACA,WACA,qBACA,YACA,SACA,gBACA,gBACA,UACA,gBACA,iBACA,QACA,OACA,KACA,QACA,OACA,gBACA,YACA,YACA,QACA,sBACA,8BACA,gBACA,kBACA,KACA,KACA,IACA,KACA,KACA,kBACA,YACA,UACA,UACA,MACA,WACA,YACA,MACA,WACA,OACA,eACA,YACA,SACA,cACA,cACA,gBACA,cACA,YACA,mBACA,eACA,aACA,eACA,cACA,KACA,KACA,KACA,KACA,aACA,WACA,gBACA,oBACA,SACA,OACA,KACA,kBACA,KACA,MACA,YACA,IACA,KACA,KACA,KACA,KACA,UACA,YACA,aACA,WACA,OACA,eACA,iBACA,eACA,mBACA,iBACA,QACA,aACA,aACA,eACA,eACA,cACA,cACA,mBACA,YACA,MACA,OACA,YACA,QACA,SACA,OACA,MACA,OACA,aACA,SACA,WACA,UACA,QACA,SACA,cACA,SACA,WACA,cACA,OACA,aACA,sBACA,mBACA,eACA,SACA,gBACA,sBACA,iBACA,IACA,KACA,KACA,SACA,OACA,OACA,cACA,YACA,UACA,SACA,SACA,QACA,OACA,kBACA,QACA,mBACA,mBACA,eACA,cACA,eACA,cACA,aACA,eACA,mBACA,oBACA,iBACA,kBACA,oBACA,iBACA,SACA,eACA,QACA,eACA,iBACA,WACA,cACA,UACA,UACA,YACA,mBACA,cACA,kBACA,iBACA,aACA,OACA,KACA,KACA,UACA,SACA,UACA,aACA,UACA,aACA,gBACA,gBACA,QACA,eACA,OACA,eACA,mBACA,mBACA,IACA,KACA,KACA,QACA,IACA,KACA,KACA,IACA,eAGWyF,EAASzF,EAAO,CAC3B,SACA,cACA,QACA,WACA,QACA,cACA,cACA,gBACA,aACA,aACA,QACA,MACA,UACA,eACA,WACA,QACA,QACA,SACA,OACA,KACA,UACA,SACA,gBACA,SACA,SACA,iBACA,YACA,WACA,cACA,UACA,UACA,gBACA,WACA,WACA,OACA,WACA,WACA,aACA,UACA,SACA,SACA,cACA,gBACA,uBACA,YACA,YACA,aACA,WACA,iBACA,iBACA,YACA,UA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"} |
En esta lección se amplió el ejemplo de la lección anterior para controlar el acceso a una app.